Compare commits
5 commits
69e1aca041
...
f283144658
Author | SHA1 | Date | |
---|---|---|---|
|
f283144658 | ||
|
833158c0b7 | ||
|
fc3a7f4529 | ||
|
74ea24233c | ||
|
8332b4dd07 |
13 changed files with 426 additions and 193 deletions
|
@ -1817,6 +1817,15 @@ the files in the current directory as well as the available disk
|
|||
space. If you set this to @code{nil}, the available disk space
|
||||
information will not be displayed at all.
|
||||
|
||||
@vindex dired-check-symlinks
|
||||
Dired fontifies the items in the Dired buffer. If the
|
||||
@code{default-directory} of that buffer is remote, this might be
|
||||
extensive for symbolic links, because their @code{file-truename} is
|
||||
evaluated. Set user option @code{dired-check-symlinks} to @code{nil}
|
||||
for remote directories, which suffer from a slow connection. It can be
|
||||
declared as connection-local variable to match how a remote system is
|
||||
connectable (@pxref{Connection Variables}).
|
||||
|
||||
@kindex + @r{(Dired)}
|
||||
@findex dired-create-directory
|
||||
The command @kbd{+} (@code{dired-create-directory}) reads a
|
||||
|
|
|
@ -2353,6 +2353,12 @@ buffers (@pxref{Window History}) of all windows (including dead windows
|
|||
that are only referenced by window configurations) and remove any
|
||||
@code{quit-restore} or @code{quit-restore-prev} parameters
|
||||
(@pxref{Window Parameters}) referencing that buffer.
|
||||
|
||||
This function does not replace the buffer specified by
|
||||
@var{buffer-or-name} in any minibuffer window showing it, nor does it
|
||||
delete minibuffer windows or minibuffer frames. It removes, however,
|
||||
that buffer from the lists of previous and next buffers of all
|
||||
minibuffer windows.
|
||||
@end deffn
|
||||
|
||||
By default, @code{replace-buffer-in-windows} deletes only windows
|
||||
|
|
|
@ -489,15 +489,17 @@ compares three files simultaneously).
|
|||
@item a
|
||||
@kindex a
|
||||
@emph{In comparison sessions:}
|
||||
Copies the current difference region (or the region specified as the prefix
|
||||
to this command) from buffer A to buffer B@.
|
||||
Ediff saves the old contents of buffer B's region; it can
|
||||
be restored via the command @kbd{rb}, which see.
|
||||
Copies the current difference region (or the region specified as the
|
||||
numerical prefix to this command, or @emph{all} regions with @kbd{C-u}
|
||||
prefix) from buffer A to buffer B@. Ediff saves the old contents of
|
||||
buffer B's region; it can be restored via the command @kbd{rb}, which
|
||||
see.
|
||||
|
||||
@emph{In merge sessions:}
|
||||
Copies the current difference region (or the region specified as the prefix
|
||||
to this command) from buffer A to the merge buffer. The old contents of
|
||||
this region in buffer C can be restored via the command @kbd{r}.
|
||||
Copies the current difference region (or the region specified as the
|
||||
numerical prefix to this command, or @emph{all} regions with @kbd{C-u}
|
||||
prefix) from buffer A to the merge buffer. The old contents of this
|
||||
region in buffer C can be restored via the command @kbd{r}.
|
||||
|
||||
@item b
|
||||
@kindex b
|
||||
|
@ -511,11 +513,12 @@ be reinstated via the command @kbd{ra} in comparison sessions and
|
|||
|
||||
@item ab
|
||||
@kindex ab
|
||||
Copies the current difference region (or the region specified as the prefix
|
||||
to this command) from buffer A to buffer B@. This (and the next five)
|
||||
command is enabled only in sessions that compare three files
|
||||
simultaneously. The old region in buffer B is saved and can be restored
|
||||
via the command @kbd{rb}.
|
||||
Copies the current difference region (or the region specified as the
|
||||
numerical prefix to this command, or @emph{all} regions with @kbd{C-u}
|
||||
prefix) from buffer A to buffer B@. This (and the next five) command is
|
||||
enabled only in sessions that compare three files simultaneously. The
|
||||
old region in buffer B is saved and can be restored via the command
|
||||
@kbd{rb}.
|
||||
@item ac
|
||||
@kindex ac
|
||||
Copies the difference region from buffer A to buffer C@.
|
||||
|
|
|
@ -5292,6 +5292,31 @@ connections, apply the following code.
|
|||
@end group
|
||||
@end lisp
|
||||
|
||||
@vindex dired-check-symlinks
|
||||
@item
|
||||
Disable check for symbolic link validity in @code{dired} buffers.
|
||||
Emacs fontifies symbolic links in @code{dired} buffers using the
|
||||
@code{file-truename} operation. This can be slow. Since @w{Emacs
|
||||
31}, there is a user option which suppresses this. It can be set
|
||||
connection-local.
|
||||
@ifinfo
|
||||
@xref{Connection Variables, , , emacs}.
|
||||
@end ifinfo
|
||||
|
||||
@lisp
|
||||
@group
|
||||
(connection-local-set-profile-variables
|
||||
'my-dired-profile
|
||||
'((dired-check-symlinks . nil)))
|
||||
@end group
|
||||
|
||||
@group
|
||||
(connection-local-set-profiles
|
||||
'(:application tramp :machine "remotehost")
|
||||
'my-dired-profile)
|
||||
@end group
|
||||
@end lisp
|
||||
|
||||
@item
|
||||
Use direct asynchronous processes if possible.
|
||||
|
||||
|
|
48
etc/NEWS
48
etc/NEWS
|
@ -111,7 +111,7 @@ This hook allows you to control which tab-bar tabs are auto-resized.
|
|||
** Project
|
||||
|
||||
---
|
||||
*** New command `project-find-file-in-root`.
|
||||
*** New command 'project-find-file-in-root'.
|
||||
It is equivalent to running ‘project-any-command’ with ‘find-file’.
|
||||
|
||||
|
||||
|
@ -139,6 +139,14 @@ exactly below the text after the prefix on the first line.
|
|||
If 'whitespace-style' includes 'missing-newline-at-eof' (which is the
|
||||
default), the 'whitespace-cleanup' function will now add the newline.
|
||||
|
||||
** Gnus
|
||||
|
||||
---
|
||||
*** Replying to icalendar events now supports specifying a comment.
|
||||
When called with a prefix argument, accepting, declining, or tentatively
|
||||
accepting an icalendar event will prompt for a comment to add to the
|
||||
response.
|
||||
|
||||
** Eshell
|
||||
|
||||
---
|
||||
|
@ -283,13 +291,39 @@ command attempts to look up and copy the text in-between the hunks.
|
|||
** php-ts-mode
|
||||
|
||||
---
|
||||
*** 'php-ts-mode-run-php-webserver' can now accept a custom php.ini file.
|
||||
*** 'php-ts-mode-run-php-webserver' can now accept a custom "php.ini" file.
|
||||
You can use the new optional argument CONFIG when calling
|
||||
'php-ts-mode-run-php-webserver' to pass an alternative php.ini file to
|
||||
'php-ts-mode-run-php-webserver' to pass an alternative "php.ini" file to
|
||||
the built-in Web server. Interactively, when invoked with a prefix
|
||||
argument, 'php-ts-mode-run-php-webserver' prompts for the config file as
|
||||
well as for other connection parameters.
|
||||
|
||||
** Ediff
|
||||
|
||||
+++
|
||||
*** Ediff's copy commands now apply to all changes with 'C-u' prefix.
|
||||
The Ediff copy commands, bound to 'a', 'b', 'ab', etc., now copy all
|
||||
changes when supplied with a universal prefix argument via 'C-u':
|
||||
|
||||
- 'C-u a' copies all changes from buffer A to buffer B (in 2-way diff)
|
||||
or to buffer C (in 3-way diff or merge).
|
||||
- 'C-u b' copies all changes from buffer B to buffer A (in 2-way diff)
|
||||
or to buffer C (in 3-way diff or merge).
|
||||
- 'C-u a b' copies all changes from buffer A to buffer B.
|
||||
- 'C-u b a' copies all changes from buffer B to buffer A.
|
||||
- 'C-u a c' copies all changes from buffer A to buffer C.
|
||||
- 'C-u b c' copies all changes from buffer B to buffer C.
|
||||
- 'C-u c a' copies all changes from buffer C to buffer A.
|
||||
- 'C-u c b' copies all changes from buffer C to buffer B.
|
||||
|
||||
** Dired
|
||||
|
||||
+++
|
||||
*** Dired allows to disable checks for symbolic link validity.
|
||||
Dired fontifies symbolic links in Dired buffers using the
|
||||
'file-truename' operation. This can be slow for remote directories.
|
||||
Setting user option 'dired-check-symlinks' to nil disables these checks.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 31.1
|
||||
|
||||
|
@ -338,11 +372,11 @@ If supplied, 'string-pixel-width' will use any face remappings from
|
|||
BUFFER when computing the string's width.
|
||||
|
||||
---
|
||||
*** New macro 'with-work-buffer'.
|
||||
This macro is similar to the already existing macro `with-temp-buffer',
|
||||
** New macro 'with-work-buffer'.
|
||||
This macro is similar to the already existing macro 'with-temp-buffer',
|
||||
except that it does not allocate a new temporary buffer on each call,
|
||||
but tries to reuse those previously allocated (up to a number defined by
|
||||
the new variable `work-buffer-limit', which defaults to 10).
|
||||
the new variable 'work-buffer-limit', which defaults to 10).
|
||||
|
||||
+++
|
||||
** 'date-to-time' now defaults to local time.
|
||||
|
@ -379,7 +413,7 @@ where a userspace executable loader is required, has been optimized on
|
|||
systems featuring Linux 3.5.0 and above.
|
||||
|
||||
---
|
||||
** NSSpeechRecognitionUsageDescription now included in Info.plist (macOS).
|
||||
** 'NSSpeechRecognitionUsageDescription' now included in "Info.plist" (macOS).
|
||||
Should Emacs (or any built-in shell) invoke a process using macOS speech
|
||||
recognition APIs, the relevant permission dialog is now displayed, thus
|
||||
allowing Emacs users access to speech recognition utilities.
|
||||
|
|
|
@ -1059,49 +1059,50 @@ the `left' or `right' when one of the standard modes is used."
|
|||
(defun calculator-update-display (&optional force)
|
||||
"Update the display.
|
||||
If optional argument FORCE is non-nil, don't use the cached string."
|
||||
(set-buffer calculator-buffer)
|
||||
;; update calculator-stack-display
|
||||
(when (or force (not (eq (car calculator-stack-display)
|
||||
calculator-stack)))
|
||||
(setq calculator-stack-display
|
||||
(cons calculator-stack
|
||||
(if calculator-stack
|
||||
(concat
|
||||
(let ((calculator-displayer
|
||||
(if (and calculator-displayers
|
||||
(= 1 (length calculator-stack)))
|
||||
;; customizable display for a single value
|
||||
(caar calculator-displayers)
|
||||
calculator-displayer)))
|
||||
(mapconcat 'calculator-number-to-string
|
||||
(reverse calculator-stack)
|
||||
" "))
|
||||
" "
|
||||
(and calculator-display-fragile
|
||||
calculator-saved-list
|
||||
;; Hack: use `eq' to compare the number: it's a
|
||||
;; flonum, so `eq' means that its the actual
|
||||
;; number rather than a computation that had an
|
||||
;; equal result (eg, enter 1,3,2, use "v" to see
|
||||
;; the average -- it now shows "2" instead of
|
||||
;; "2 [3]").
|
||||
(eq (car calculator-stack)
|
||||
(nth calculator-saved-ptr
|
||||
calculator-saved-list))
|
||||
(if (= 0 calculator-saved-ptr)
|
||||
(format "[%s]" (length calculator-saved-list))
|
||||
(format "[%s/%s]"
|
||||
(- (length calculator-saved-list)
|
||||
calculator-saved-ptr)
|
||||
(length calculator-saved-list)))))
|
||||
""))))
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(insert (calculator-get-display)))
|
||||
(set-buffer-modified-p nil)
|
||||
(goto-char (if calculator-display-fragile
|
||||
(1+ (length calculator-prompt))
|
||||
(1- (point)))))
|
||||
(when (buffer-live-p calculator-buffer)
|
||||
(set-buffer calculator-buffer)
|
||||
;; update calculator-stack-display
|
||||
(when (or force (not (eq (car calculator-stack-display)
|
||||
calculator-stack)))
|
||||
(setq calculator-stack-display
|
||||
(cons calculator-stack
|
||||
(if calculator-stack
|
||||
(concat
|
||||
(let ((calculator-displayer
|
||||
(if (and calculator-displayers
|
||||
(= 1 (length calculator-stack)))
|
||||
;; customizable display for a single value
|
||||
(caar calculator-displayers)
|
||||
calculator-displayer)))
|
||||
(mapconcat 'calculator-number-to-string
|
||||
(reverse calculator-stack)
|
||||
" "))
|
||||
" "
|
||||
(and calculator-display-fragile
|
||||
calculator-saved-list
|
||||
;; Hack: use `eq' to compare the number: it's a
|
||||
;; flonum, so `eq' means that its the actual
|
||||
;; number rather than a computation that had an
|
||||
;; equal result (eg, enter 1,3,2, use "v" to see
|
||||
;; the average -- it now shows "2" instead of
|
||||
;; "2 [3]").
|
||||
(eq (car calculator-stack)
|
||||
(nth calculator-saved-ptr
|
||||
calculator-saved-list))
|
||||
(if (= 0 calculator-saved-ptr)
|
||||
(format "[%s]" (length calculator-saved-list))
|
||||
(format "[%s/%s]"
|
||||
(- (length calculator-saved-list)
|
||||
calculator-saved-ptr)
|
||||
(length calculator-saved-list)))))
|
||||
""))))
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer)
|
||||
(insert (calculator-get-display)))
|
||||
(set-buffer-modified-p nil)
|
||||
(goto-char (if calculator-display-fragile
|
||||
(1+ (length calculator-prompt))
|
||||
(1- (point))))))
|
||||
|
||||
;;;---------------------------------------------------------------------
|
||||
;;; Stack computations
|
||||
|
@ -1553,17 +1554,18 @@ a multiplication."
|
|||
(defun calculator-quit ()
|
||||
"Quit calculator."
|
||||
(interactive)
|
||||
(set-buffer calculator-buffer)
|
||||
(let ((inhibit-read-only t)) (erase-buffer))
|
||||
(unless calculator-electric-mode
|
||||
(ignore-errors
|
||||
(while (get-buffer-window calculator-buffer)
|
||||
(delete-window (get-buffer-window calculator-buffer)))))
|
||||
(kill-buffer calculator-buffer)
|
||||
(message "Calculator done.")
|
||||
(if calculator-electric-mode
|
||||
(throw 'calculator-done nil) ; will kill the buffer
|
||||
(setq calculator-buffer nil)))
|
||||
(when (buffer-live-p calculator-buffer)
|
||||
(set-buffer calculator-buffer)
|
||||
(let ((inhibit-read-only t)) (erase-buffer))
|
||||
(unless calculator-electric-mode
|
||||
(ignore-errors
|
||||
(while (get-buffer-window calculator-buffer)
|
||||
(delete-window (get-buffer-window calculator-buffer)))))
|
||||
(kill-buffer calculator-buffer)
|
||||
(message "Calculator done.")
|
||||
(if calculator-electric-mode
|
||||
(throw 'calculator-done nil) ; will kill the buffer
|
||||
(setq calculator-buffer nil))))
|
||||
|
||||
(defun calculator-save-and-quit ()
|
||||
"Quit the calculator, saving the result on the `kill-ring'."
|
||||
|
|
|
@ -738,6 +738,13 @@ Subexpression 2 must end right before the \\n.")
|
|||
|
||||
;;; Font-lock
|
||||
|
||||
(defcustom dired-check-symlinks t
|
||||
"Whether symlinks are checked for validity.
|
||||
Set it to nil for remote directories, which suffer from a slow connection."
|
||||
:type 'boolean
|
||||
:group 'dired
|
||||
:version "31.1")
|
||||
|
||||
(defvar dired-font-lock-keywords
|
||||
(list
|
||||
;;
|
||||
|
@ -815,11 +822,13 @@ Subexpression 2 must end right before the \\n.")
|
|||
;; Broken Symbolic link.
|
||||
(list dired-re-sym
|
||||
(list (lambda (end)
|
||||
(let* ((file (dired-file-name-at-point))
|
||||
(truename (ignore-errors (file-truename file))))
|
||||
;; either not existent target or circular link
|
||||
(and (not (and truename (file-exists-p truename)))
|
||||
(search-forward-regexp "\\(.+\\) \\(->\\) ?\\(.+\\)" end t))))
|
||||
(when (connection-local-value dired-check-symlinks)
|
||||
(let* ((file (dired-file-name-at-point))
|
||||
(truename (ignore-errors (file-truename file))))
|
||||
;; either not existent target or circular link
|
||||
(and (not (and truename (file-exists-p truename)))
|
||||
(search-forward-regexp
|
||||
"\\(.+\\) \\(->\\) ?\\(.+\\)" end t)))))
|
||||
'(dired-move-to-filename)
|
||||
nil
|
||||
'(1 'dired-broken-symlink)
|
||||
|
@ -829,24 +838,29 @@ Subexpression 2 must end right before the \\n.")
|
|||
;; Symbolic link to a directory.
|
||||
(list dired-re-sym
|
||||
(list (lambda (end)
|
||||
(when-let* ((file (dired-file-name-at-point))
|
||||
(truename (ignore-errors (file-truename file))))
|
||||
(and (file-directory-p truename)
|
||||
(search-forward-regexp "\\(.+-> ?\\)\\(.+\\)" end t))))
|
||||
(when (connection-local-value dired-check-symlinks)
|
||||
(when-let* ((file (dired-file-name-at-point))
|
||||
(truename (ignore-errors (file-truename file))))
|
||||
(and (file-directory-p truename)
|
||||
(search-forward-regexp
|
||||
"\\(.+-> ?\\)\\(.+\\)" end t)))))
|
||||
'(dired-move-to-filename)
|
||||
nil
|
||||
'(1 dired-symlink-face)
|
||||
'(2 `(face ,dired-directory-face dired-symlink-filename t))))
|
||||
;;
|
||||
;; Symbolic link to a non-directory.
|
||||
;; Symbolic link to a non-directory. Or no check at all.
|
||||
(list dired-re-sym
|
||||
(list (lambda (end)
|
||||
(when-let ((file (dired-file-name-at-point)))
|
||||
(let ((truename (ignore-errors (file-truename file))))
|
||||
(and (or (not truename)
|
||||
(not (file-directory-p truename)))
|
||||
(search-forward-regexp "\\(.+-> ?\\)\\(.+\\)"
|
||||
end t)))))
|
||||
(if (not (connection-local-value dired-check-symlinks))
|
||||
(search-forward-regexp
|
||||
"\\(.+-> ?\\)\\(.+\\)" end t)
|
||||
(when-let ((file (dired-file-name-at-point)))
|
||||
(let ((truename (ignore-errors (file-truename file))))
|
||||
(and (or (not truename)
|
||||
(not (file-directory-p truename)))
|
||||
(search-forward-regexp
|
||||
"\\(.+-> ?\\)\\(.+\\)" end t))))))
|
||||
'(dired-move-to-filename)
|
||||
nil
|
||||
'(1 dired-symlink-face)
|
||||
|
|
|
@ -309,7 +309,7 @@ status will be retrieved from the first matching attendee record."
|
|||
;;; gnus-icalendar-event-reply
|
||||
;;;
|
||||
|
||||
(defun gnus-icalendar-event--build-reply-event-body (ical-request status identities)
|
||||
(defun gnus-icalendar-event--build-reply-event-body (ical-request status identities &optional comment)
|
||||
(let ((summary-status (capitalize (symbol-name status)))
|
||||
(attendee-status (upcase (symbol-name status)))
|
||||
reply-event-lines)
|
||||
|
@ -319,6 +319,10 @@ status will be retrieved from the first matching attendee record."
|
|||
(if (string-match "^[^:]+:" line)
|
||||
(replace-match (format "\\&%s: " summary-status) t nil line)
|
||||
line))
|
||||
(update-comment
|
||||
(line)
|
||||
(if comment (format "COMMENT:%s" comment)
|
||||
line))
|
||||
(update-dtstamp ()
|
||||
(format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t))
|
||||
(attendee-matches-identity
|
||||
|
@ -341,6 +345,7 @@ status will be retrieved from the first matching attendee record."
|
|||
(cond
|
||||
((string= key "ATTENDEE") (update-attendee-status line))
|
||||
((string= key "SUMMARY") (update-summary line))
|
||||
((string= key "COMMENT") (update-comment line))
|
||||
((string= key "DTSTAMP") (update-dtstamp))
|
||||
((member key '("ORGANIZER" "DTSTART" "DTEND"
|
||||
"LOCATION" "DURATION" "SEQUENCE"
|
||||
|
@ -363,16 +368,27 @@ status will be retrieved from the first matching attendee record."
|
|||
attendee-status user-full-name user-mail-address)
|
||||
reply-event-lines))
|
||||
|
||||
;; add comment line if not existing
|
||||
(when (and comment
|
||||
(not (gnus-icalendar-find-if
|
||||
(lambda (x)
|
||||
(string-match "^COMMENT" x))
|
||||
reply-event-lines)))
|
||||
(push (format "COMMENT:%s" comment) reply-event-lines))
|
||||
|
||||
(mapconcat #'identity `("BEGIN:VEVENT"
|
||||
,@(nreverse reply-event-lines)
|
||||
"END:VEVENT")
|
||||
"\n"))))
|
||||
|
||||
(defun gnus-icalendar-event-reply-from-buffer (buf status identities)
|
||||
(defun gnus-icalendar-event-reply-from-buffer (buf status identities &optional comment)
|
||||
"Build a calendar event reply for request contained in BUF.
|
||||
The reply will have STATUS (`accepted', `tentative' or `declined').
|
||||
The reply will be composed for attendees matching any entry
|
||||
on the IDENTITIES list."
|
||||
on the IDENTITIES list.
|
||||
Optional argument COMMENT will be placed in the comment field of the
|
||||
reply.
|
||||
"
|
||||
(cl-labels
|
||||
((extract-block
|
||||
(blockname)
|
||||
|
@ -396,7 +412,7 @@ on the IDENTITIES list."
|
|||
"PRODID:Gnus"
|
||||
"VERSION:2.0"
|
||||
zone
|
||||
(gnus-icalendar-event--build-reply-event-body event status identities)
|
||||
(gnus-icalendar-event--build-reply-event-body event status identities comment)
|
||||
"END:VCALENDAR")))
|
||||
|
||||
(mapconcat #'identity (delq nil contents) "\n"))))))
|
||||
|
@ -878,13 +894,13 @@ These will be used to retrieve the RSVP information from ical events."
|
|||
(insert "Subject: " subject)
|
||||
(message-send-and-exit))))
|
||||
|
||||
(defun gnus-icalendar-reply (data)
|
||||
(defun gnus-icalendar-reply (data &optional comment)
|
||||
(let* ((handle (car data))
|
||||
(status (cadr data))
|
||||
(event (caddr data))
|
||||
(reply (gnus-icalendar-with-decoded-handle handle
|
||||
(gnus-icalendar-event-reply-from-buffer
|
||||
(current-buffer) status (gnus-icalendar-identities))))
|
||||
(current-buffer) status (gnus-icalendar-identities) comment)))
|
||||
(organizer (gnus-icalendar-event:organizer event)))
|
||||
|
||||
(when reply
|
||||
|
@ -1009,25 +1025,37 @@ These will be used to retrieve the RSVP information from ical events."
|
|||
(when data
|
||||
(gnus-icalendar-save-part data))))
|
||||
|
||||
(defun gnus-icalendar-reply-accept ()
|
||||
"Accept invitation in the current article."
|
||||
(interactive nil gnus-article-mode gnus-summary-mode)
|
||||
(defun gnus-icalendar-reply-accept (&optional comment-p)
|
||||
"Accept invitation in the current article.
|
||||
|
||||
Optional argument COMMENT-P non-nil (interactively `\\[universal-argument]')
|
||||
means prompt for a comment to include in the reply."
|
||||
(interactive "P" gnus-article-mode gnus-summary-mode)
|
||||
(with-current-buffer gnus-article-buffer
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'accepted gnus-icalendar-event))
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'accepted gnus-icalendar-event)
|
||||
(when comment-p (read-string "Comment: ")))
|
||||
(setq-local gnus-icalendar-reply-status 'accepted)))
|
||||
|
||||
(defun gnus-icalendar-reply-tentative ()
|
||||
"Send tentative response to invitation in the current article."
|
||||
(interactive nil gnus-article-mode gnus-summary-mode)
|
||||
(defun gnus-icalendar-reply-tentative (&optional comment-p)
|
||||
"Send tentative response to invitation in the current article.
|
||||
|
||||
Optional argument COMMENT-P non-nil (interactively `\\[universal-argument]')
|
||||
means prompt for a comment to include in the reply."
|
||||
(interactive "P" gnus-article-mode gnus-summary-mode)
|
||||
(with-current-buffer gnus-article-buffer
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'tentative gnus-icalendar-event))
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'tentative gnus-icalendar-event)
|
||||
(when comment-p (read-string "Comment: ")))
|
||||
(setq-local gnus-icalendar-reply-status 'tentative)))
|
||||
|
||||
(defun gnus-icalendar-reply-decline ()
|
||||
"Decline invitation in the current article."
|
||||
(interactive nil gnus-article-mode gnus-summary-mode)
|
||||
(defun gnus-icalendar-reply-decline (&optional comment-p)
|
||||
"Decline invitation in the current article.
|
||||
|
||||
Optional argument COMMENT-P non-nil (interactively `\\[universal-argument]')
|
||||
means prompt for a comment to include in the reply."
|
||||
(interactive "P" gnus-article-mode gnus-summary-mode)
|
||||
(with-current-buffer gnus-article-buffer
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'declined gnus-icalendar-event))
|
||||
(gnus-icalendar-reply (list gnus-icalendar-handle 'declined gnus-icalendar-event)
|
||||
(when comment-p (read-string "Comment: ")))
|
||||
(setq-local gnus-icalendar-reply-status 'declined)))
|
||||
|
||||
(defun gnus-icalendar-event-export ()
|
||||
|
|
|
@ -1890,8 +1890,8 @@ current point position in the specified buffer."
|
|||
|
||||
(defun ediff-diff-to-diff (arg &optional keys)
|
||||
"Copy buffer-X'th difference region to buffer Y (X,Y are A, B, or C).
|
||||
With numerical prefix argument ARG, copy the difference specified
|
||||
in the arg.
|
||||
With numerical prefix argument ARG, copy the difference specified in the
|
||||
arg. With prefix `\\[universal-argument]', copy all differences.
|
||||
Otherwise, copy the difference given by `ediff-current-difference'.
|
||||
This command assumes it is bound to a 2-character key sequence, `ab', `ba',
|
||||
`ac', etc., which is used to determine the types of buffers to be used for
|
||||
|
@ -1904,17 +1904,23 @@ command keys."
|
|||
(interactive "P")
|
||||
(ediff-barf-if-not-control-buffer)
|
||||
(or keys (setq keys (this-command-keys)))
|
||||
(if (eq arg '-) (setq arg -1)) ; translate neg arg to -1
|
||||
(if (numberp arg) (ediff-jump-to-difference arg))
|
||||
(if (equal arg '(4))
|
||||
;; copy all differences with `C-u' prefix
|
||||
(let ((n 0))
|
||||
(while (ediff-valid-difference-p n)
|
||||
(ediff-diff-to-diff (1+ n) keys)
|
||||
(setq n (1+ n))))
|
||||
(if (eq arg '-) (setq arg -1)) ; translate neg arg to -1
|
||||
(if (numberp arg) (ediff-jump-to-difference arg))
|
||||
|
||||
(let* ((char1 (aref keys 0))
|
||||
(char2 (aref keys 1))
|
||||
ediff-verbose-p)
|
||||
(ediff-copy-diff ediff-current-difference
|
||||
(ediff-char-to-buftype char1)
|
||||
(ediff-char-to-buftype char2))
|
||||
;; recenter with rehighlighting, but no messages
|
||||
(ediff-recenter)))
|
||||
(let* ((char1 (aref keys 0))
|
||||
(char2 (aref keys 1))
|
||||
ediff-verbose-p)
|
||||
(ediff-copy-diff ediff-current-difference
|
||||
(ediff-char-to-buftype char1)
|
||||
(ediff-char-to-buftype char2))
|
||||
;; recenter with rehighlighting, but no messages
|
||||
(ediff-recenter))))
|
||||
|
||||
(defun ediff-copy-A-to-B (arg)
|
||||
"Copy ARGth difference region from buffer A to B.
|
||||
|
|
152
lisp/window.el
152
lisp/window.el
|
@ -4469,75 +4469,86 @@ This may be a useful alternative binding for \\[delete-other-windows]
|
|||
|
||||
;;; Windows and buffers.
|
||||
|
||||
;; `prev-buffers' and `next-buffers' are two reserved window slots used
|
||||
;; 'prev-buffers' and 'next-buffers' are two reserved window slots used
|
||||
;; for (1) determining which buffer to show in the window when its
|
||||
;; buffer shall be buried or killed and (2) which buffer to show for
|
||||
;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
|
||||
;; 'switch-to-prev-buffer' and 'switch-to-next-buffer'.
|
||||
|
||||
;; `prev-buffers' consists of <buffer, window-start, window-point>
|
||||
;; 'prev-buffers' consists of <buffer, window-start, window-point>
|
||||
;; triples. The entries on this list are ordered by the time their
|
||||
;; buffer has been removed from the window, the most recently removed
|
||||
;; buffer's entry being first. The window-start and window-point
|
||||
;; components are `window-start' and `window-point' at the time the
|
||||
;; components are 'window-start' and 'window-point' at the time the
|
||||
;; buffer was removed from the window which implies that the entry must
|
||||
;; be added when `set-window-buffer' removes the buffer from the window.
|
||||
;; be added when 'set-window-buffer' removes the buffer from the window.
|
||||
|
||||
;; `next-buffers' is the list of buffers that have been replaced
|
||||
;; recently by `switch-to-prev-buffer'. These buffers are the least
|
||||
;; preferred candidates of `switch-to-prev-buffer' and the preferred
|
||||
;; candidates of `switch-to-next-buffer' to switch to. This list is
|
||||
;; 'next-buffers' is the list of buffers that have been replaced
|
||||
;; recently by 'switch-to-prev-buffer'. These buffers are the least
|
||||
;; preferred candidates of 'switch-to-prev-buffer' and the preferred
|
||||
;; candidates of 'switch-to-next-buffer' to switch to. This list is
|
||||
;; reset to nil by any action changing the window's buffer with the
|
||||
;; exception of `switch-to-prev-buffer' and `switch-to-next-buffer'.
|
||||
;; `switch-to-prev-buffer' pushes the buffer it just replaced on it,
|
||||
;; `switch-to-next-buffer' pops the last pushed buffer from it.
|
||||
|
||||
;; Both `prev-buffers' and `next-buffers' may reference killed buffers
|
||||
;; if such a buffer was killed while the window was hidden within a
|
||||
;; window configuration. Such killed buffers get removed whenever
|
||||
;; `switch-to-prev-buffer' or `switch-to-next-buffer' encounter them.
|
||||
|
||||
;; The following function is called by `set-window-buffer' _before_ it
|
||||
;; replaces the buffer of the argument window with the new buffer.
|
||||
(defun push-window-buffer-onto-prev (&optional window)
|
||||
"Push entry for WINDOW's buffer onto WINDOW's prev-buffers list.
|
||||
WINDOW must be a live window and defaults to the selected one.
|
||||
|
||||
Any duplicate entries for the buffer in the list are removed."
|
||||
(let* ((window (window-normalize-window window t))
|
||||
(buffer (window-buffer window))
|
||||
(w-list (window-prev-buffers window))
|
||||
(entry (assq buffer w-list)))
|
||||
(when entry
|
||||
(setq w-list (assq-delete-all buffer w-list)))
|
||||
(let ((start (window-start window))
|
||||
(point (window-point window)))
|
||||
(setq entry
|
||||
(cons buffer
|
||||
(with-current-buffer buffer
|
||||
(if entry
|
||||
;; We have an entry, update marker positions.
|
||||
(list (set-marker (nth 1 entry) start)
|
||||
(set-marker (nth 2 entry) point))
|
||||
(list (copy-marker start)
|
||||
(copy-marker
|
||||
;; Preserve window-point-insertion-type
|
||||
;; (Bug#12855)
|
||||
point window-point-insertion-type))))))
|
||||
(set-window-prev-buffers window (cons entry w-list)))))
|
||||
;; exception of 'switch-to-prev-buffer' and 'switch-to-next-buffer'.
|
||||
;; 'switch-to-prev-buffer' pushes the buffer it just replaced on it,
|
||||
;; 'switch-to-next-buffer' pops the last pushed buffer from it.
|
||||
|
||||
;; The following function is called by 'set-window-buffer' _before_ it
|
||||
;; replaces the buffer of the argument window with the new buffer. It
|
||||
;; does not record a non-minibuffer buffer (like the one created by
|
||||
;; 'calculator' in Electric mode) in a minibuffer window since the code
|
||||
;; in minibuf.c cannot handle that. The minibuf.c code calls this
|
||||
;; function exclusively to arrange minibuffers shown in minibuffer
|
||||
;; windows.
|
||||
(defun record-window-buffer (&optional window)
|
||||
"Record WINDOW's buffer.
|
||||
WINDOW must be a live window and defaults to the selected one."
|
||||
Add the buffer currently shown in WINDOW to the list of WINDOW's
|
||||
previous buffers. WINDOW must be a live window and defaults to the
|
||||
selected one.
|
||||
|
||||
If WINDOW is not a minibuffer window, do not record insignificant
|
||||
buffers (buffers whose name starts with a space). If WINDOW is a
|
||||
minibuffer window, record its buffer if and only if that buffer is a
|
||||
live minibuffer (`minibufferp' with LIVE argument non-nil must return
|
||||
non-nil for it).
|
||||
|
||||
Run `buffer-list-update-hook' if and only if WINDOW is not a minibuffer
|
||||
window."
|
||||
(let* ((window (window-normalize-window window t))
|
||||
(buffer (window-buffer window)))
|
||||
(mini (window-minibuffer-p window))
|
||||
(buffer (window-buffer window))
|
||||
(prev-buffers (window-prev-buffers window))
|
||||
(entry (assq buffer prev-buffers)))
|
||||
(when entry
|
||||
(setq prev-buffers (assq-delete-all buffer prev-buffers)))
|
||||
|
||||
;; Reset WINDOW's next buffers. If needed, they are resurrected by
|
||||
;; `switch-to-prev-buffer' and `switch-to-next-buffer'.
|
||||
(set-window-next-buffers window nil)
|
||||
|
||||
;; Don't record insignificant buffers.
|
||||
(when (not (eq (aref (buffer-name buffer) 0) ?\s))
|
||||
(push-window-buffer-onto-prev window)
|
||||
(run-hooks 'buffer-list-update-hook))))
|
||||
;; For minibuffer windows record live minibuffers only. For normal
|
||||
;; windows do not record insignificant buffers.
|
||||
(when (if mini
|
||||
(minibufferp buffer t)
|
||||
(not (eq (aref (buffer-name buffer) 0) ?\s)))
|
||||
(let ((start (window-start window))
|
||||
(point (window-point window)))
|
||||
(setq entry
|
||||
(cons buffer
|
||||
(with-current-buffer buffer
|
||||
(if entry
|
||||
;; We have an entry, update marker positions.
|
||||
(list (set-marker (nth 1 entry) start)
|
||||
(set-marker (nth 2 entry) point))
|
||||
(list (copy-marker start)
|
||||
(copy-marker
|
||||
;; Preserve window-point-insertion-type
|
||||
;; (Bug#12855)
|
||||
point window-point-insertion-type))))))
|
||||
(set-window-prev-buffers window (cons entry prev-buffers))
|
||||
|
||||
(unless mini
|
||||
(run-hooks 'buffer-list-update-hook))))))
|
||||
|
||||
(defalias 'push-window-buffer-onto-prev 'record-window-buffer)
|
||||
|
||||
(defun unrecord-window-buffer (&optional window buffer all)
|
||||
"Unrecord BUFFER in WINDOW.
|
||||
|
@ -5160,10 +5171,19 @@ parameters naming it."
|
|||
;; If a window doesn't show BUFFER, unrecord BUFFER in it.
|
||||
(unrecord-window-buffer window buffer t)))))
|
||||
|
||||
;; Conceptually, 'replace-buffer-in-windows' would not have to touch the
|
||||
;; list of previous buffers of a minibuffer window: As a rule,
|
||||
;; minibuffers are never deleted and any other buffers shown in a
|
||||
;; minibuffer window are not recorded by 'record-window'. To be on the
|
||||
;; safe side, 'replace-buffer-in-windows' now scans minibuffer windows
|
||||
;; too to make sure that any killed buffer gets removed from all lists
|
||||
;; of previous and next buffers. 'replace-buffer-in-windows' still does
|
||||
;; _not_ replace the buffer itself in any minibuffer window showing it.
|
||||
;; That case is still handled only in 'kill-buffer' itself.
|
||||
(defun replace-buffer-in-windows (&optional buffer-or-name)
|
||||
"Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
|
||||
BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
|
||||
defaults to the current buffer. Minibuffer windows are not considered.
|
||||
defaults to the current buffer.
|
||||
|
||||
If the option `kill-buffer-quit-windows' is nil, behave as follows: With
|
||||
the exception of side windows, when a window showing BUFFER-OR-NAME is
|
||||
|
@ -5180,21 +5200,29 @@ In either case, remove the buffer denoted by BUFFER-OR-NAME from the
|
|||
lists of previous and next buffers of all windows and remove any
|
||||
`quit-restore' or `quit-restore-prev' parameters mentioning it.
|
||||
|
||||
This function does not replace the buffer specified by BUFFER-OR-NAME in
|
||||
any minibuffer window showing it, nor does it delete minibuffer windows
|
||||
or minibuffer frames. It removes, however, that buffer from the lists
|
||||
of previous and next buffers of all minibuffer windows.
|
||||
|
||||
If, for any window showing BUFFER-OR-NAME running the abnormal hook
|
||||
`window-deletable-functions' returns nil, do not delete that window but
|
||||
show some other buffer in that window.
|
||||
|
||||
This function is called by `kill-buffer' which kills the buffer
|
||||
specified by `buffer-or-name' afterwards. It never kills a buffer by
|
||||
itself."
|
||||
This function is called by `kill-buffer' which effectively kills the
|
||||
buffer specified by `buffer-or-name' afterwards. It never kills a
|
||||
buffer by itself."
|
||||
(interactive "bBuffer to replace: ")
|
||||
(let ((buffer (window-normalize-buffer buffer-or-name)))
|
||||
;; Scan all windows. We have to unrecord BUFFER-OR-NAME in those
|
||||
;; not showing it.
|
||||
(dolist (window (window-list-1 nil nil t))
|
||||
;; Scan all windows including minibuffer windows. We have to
|
||||
;; unrecord BUFFER-OR-NAME even in those not showing it.
|
||||
(dolist (window (window-list-1 nil t t))
|
||||
(when (eq (window-buffer window) buffer)
|
||||
(if kill-buffer-quit-windows
|
||||
(quit-restore-window window 'killing)
|
||||
(cond
|
||||
((window-minibuffer-p window))
|
||||
(kill-buffer-quit-windows
|
||||
(quit-restore-window window 'killing))
|
||||
(t
|
||||
(let ((dedicated-side (eq (window-dedicated-p window) 'side)))
|
||||
(when (or dedicated-side (not (window--delete window t 'kill)))
|
||||
;; Switch to another buffer in that window.
|
||||
|
@ -5212,7 +5240,7 @@ itself."
|
|||
;; element of the parameter, 'quit-restore-window' cannot
|
||||
;; possibly show BUFFER instead; so this parameter becomes
|
||||
;; useless too.
|
||||
(unrecord-window-buffer window buffer t)))))
|
||||
(unrecord-window-buffer window buffer t))))))
|
||||
|
||||
(defcustom quit-window-hook nil
|
||||
"Hook run before performing any other actions in the `quit-window' command."
|
||||
|
|
|
@ -160,16 +160,15 @@ zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window)
|
|||
set_window_buffer (dest_window, sw->contents, 0, 0);
|
||||
Fset_window_start (dest_window, Fwindow_start (source_window), Qnil);
|
||||
Fset_window_point (dest_window, Fwindow_point (source_window));
|
||||
dw->prev_buffers = sw->prev_buffers;
|
||||
wset_prev_buffers (dw, sw->prev_buffers);
|
||||
set_window_buffer (source_window, nth_minibuffer (0), 0, 0);
|
||||
sw->prev_buffers = Qnil;
|
||||
wset_prev_buffers (sw, Qnil);
|
||||
return;
|
||||
}
|
||||
|
||||
if (live_minibuffer_p (dw->contents))
|
||||
call1 (Qpush_window_buffer_onto_prev, dest_window);
|
||||
if (live_minibuffer_p (sw->contents))
|
||||
call1 (Qpush_window_buffer_onto_prev, source_window);
|
||||
call1 (Qrecord_window_buffer, dest_window);
|
||||
call1 (Qrecord_window_buffer, source_window);
|
||||
|
||||
acc = merge_c (dw->prev_buffers, sw->prev_buffers, minibuffer_ent_greater);
|
||||
|
||||
if (!NILP (acc))
|
||||
|
@ -180,8 +179,9 @@ zip_minibuffer_stacks (Lisp_Object dest_window, Lisp_Object source_window)
|
|||
Fset_window_start (dest_window, Fcar (Fcdr (d_ent)), Qnil);
|
||||
Fset_window_point (dest_window, Fcar (Fcdr (Fcdr (d_ent))));
|
||||
}
|
||||
dw->prev_buffers = acc;
|
||||
sw->prev_buffers = Qnil;
|
||||
|
||||
wset_prev_buffers (dw, acc);
|
||||
wset_prev_buffers (sw, Qnil);
|
||||
set_window_buffer (source_window, nth_minibuffer (0), 0, 0);
|
||||
}
|
||||
|
||||
|
@ -688,8 +688,8 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
|
|||
Fframe_first_window (MB_frame), Qnil);
|
||||
}
|
||||
MB_frame = XWINDOW (XFRAME (selected_frame)->minibuffer_window)->frame;
|
||||
if (live_minibuffer_p (XWINDOW (minibuf_window)->contents))
|
||||
call1 (Qpush_window_buffer_onto_prev, minibuf_window);
|
||||
|
||||
call1 (Qrecord_window_buffer, minibuf_window);
|
||||
|
||||
record_unwind_protect_void (minibuffer_unwind);
|
||||
if (read_minibuffer_restore_windows)
|
||||
|
|
12
src/window.c
12
src/window.c
|
@ -3647,9 +3647,17 @@ replace_buffer_in_windows (Lisp_Object buffer)
|
|||
call1 (Qreplace_buffer_in_windows, buffer);
|
||||
}
|
||||
|
||||
/* If BUFFER is shown in a window, safely replace it with some other
|
||||
buffer in all windows of all frames, even those on other keyboards. */
|
||||
/** If BUFFER is shown in any window, safely replace it with some other
|
||||
buffer in all windows of all frames, even those on other keyboards.
|
||||
Do not delete any window.
|
||||
|
||||
This function is called by Fkill_buffer when it detects that
|
||||
replacing BUFFER in some window showing BUFFER has failed. It
|
||||
assumes that ‘replace-buffer-in-windows’ has removed any entry
|
||||
referencing BUFFER from any window's lists of previous and next
|
||||
buffers and that window's ‘quit-restore’ and 'quit-restore-prev'
|
||||
parameters.
|
||||
*/
|
||||
void
|
||||
replace_buffer_in_windows_safely (Lisp_Object buffer)
|
||||
{
|
||||
|
|
|
@ -255,5 +255,75 @@ END:VCALENDAR" (list "participant@anoncompany.com"))))
|
|||
<2020-09-21 14:00-14:30 +1w>")))
|
||||
(setenv "TZ" tz))))
|
||||
|
||||
(ert-deftest gnus-icalendar-accept-with-comment ()
|
||||
""
|
||||
(let ((event "\
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20200915T140000
|
||||
DTEND;TZID=Europe/Berlin:20200915T143000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
|
||||
DTSTAMP:20200915T120627Z
|
||||
ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
|
||||
UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
|
||||
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;RSVP=TRUE
|
||||
;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
|
||||
CREATED:20200325T095723Z
|
||||
DESCRIPTION:Coffee talk
|
||||
LAST-MODIFIED:20200915T120623Z
|
||||
LOCATION:
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
SUMMARY:Casual coffee talk
|
||||
TRANSP:OPAQUE
|
||||
END:VEVENT")
|
||||
(icalendar-identities '("participant@anoncompany.com")))
|
||||
(let* ((reply (with-temp-buffer
|
||||
(insert event)
|
||||
(gnus-icalendar-event-reply-from-buffer
|
||||
(current-buffer)
|
||||
'accepted
|
||||
icalendar-identities
|
||||
"Can not stay long."))))
|
||||
(should (string-match "^ATTENDEE;.*?\\(PARTSTAT=[^;]+\\)" reply))
|
||||
(should (string-equal (match-string 1 reply) "PARTSTAT=ACCEPTED"))
|
||||
(should (string-match "^COMMENT:\\(.*\\)$" reply))
|
||||
(should (string-equal (match-string 1 reply) "Can not stay long.")))))
|
||||
|
||||
(ert-deftest gnus-icalendar-decline-without-changing-comment ()
|
||||
""
|
||||
(let ((event "\
|
||||
BEGIN:VEVENT
|
||||
DTSTART;TZID=Europe/Berlin:20200915T140000
|
||||
DTEND;TZID=Europe/Berlin:20200915T143000
|
||||
RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
|
||||
DTSTAMP:20200915T120627Z
|
||||
ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
|
||||
UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
|
||||
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;RSVP=TRUE
|
||||
;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
|
||||
CREATED:20200325T095723Z
|
||||
DESCRIPTION:Coffee talk
|
||||
LAST-MODIFIED:20200915T120623Z
|
||||
COMMENT:Only available at 2pm
|
||||
LOCATION:
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
SUMMARY:Casual coffee talk
|
||||
TRANSP:OPAQUE
|
||||
END:VEVENT")
|
||||
(icalendar-identities '("participant@anoncompany.com")))
|
||||
(let* ((reply (with-temp-buffer
|
||||
(insert event)
|
||||
(gnus-icalendar-event-reply-from-buffer
|
||||
(current-buffer)
|
||||
'declined
|
||||
icalendar-identities
|
||||
nil))))
|
||||
(should (string-match "^ATTENDEE;.*?\\(PARTSTAT=[^;]+\\)" reply))
|
||||
(should (string-equal (match-string 1 reply) "PARTSTAT=DECLINED"))
|
||||
(should (string-match "^COMMENT:\\(.*\\)$" reply))
|
||||
(should (string-equal (match-string 1 reply) "Only available at 2pm"))
|
||||
)))
|
||||
|
||||
(provide 'gnus-icalendar-tests)
|
||||
;;; gnus-icalendar-tests.el ends here
|
||||
|
|
Loading…
Reference in a new issue