From 1976ca1634d8c53a980299cb08778830cc7d90cf Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 21 Feb 2023 15:20:56 +0100 Subject: [PATCH 01/27] Make 'emacs-news-cycle-tag' work at all levels * lisp/textmodes/emacs-news-mode.el (emacs-news-cycle-tag): Search for a heading starting with 2 or more '*' rather than exactly 3. * test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts (Point-Char): Add tests for 2 and 4 '*' levels. --- lisp/textmodes/emacs-news-mode.el | 4 +- .../emacs-news-mode-resources/cycle-tag.erts | 89 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/lisp/textmodes/emacs-news-mode.el b/lisp/textmodes/emacs-news-mode.el index c5e7b8f4bc6..773b07764aa 100644 --- a/lisp/textmodes/emacs-news-mode.el +++ b/lisp/textmodes/emacs-news-mode.el @@ -195,7 +195,9 @@ untagged NEWS entry." (goto-char (line-beginning-position)) (cond ((or (looking-at (rx bol (or "---" "+++") eol))) (forward-line 2)) - ((or (looking-at (rx bol "*** "))) + ((or (looking-at (rx bol "**" + (zero-or-more "*") + " "))) (forward-line 1))) (outline-previous-visible-heading 1) (forward-line -1) diff --git a/test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts b/test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts index 63c3b1b7d8a..c3d32f6f05c 100644 --- a/test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts +++ b/test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts @@ -129,3 +129,92 @@ The corresponding key "% Y" is now bound by default in Dired. Before, that binding was only available if the 'dired-x' package was loaded. =-=-= + +Name: tag7-2level +Point-Char: | + +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +|+++ +** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +|** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-=-= + +Name: tag8-2level +Point-Char: | + +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + ++++ +|** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +|** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-=-= + +Name: tag9-2level-notag +Point-Char: | + +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +|** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-= ++++ +** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +--- +|** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-=-= + + +Name: tag10-4level +Point-Char: | + +=-= ++++ +**** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +|**** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-= ++++ +**** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key "% Y" is now bound by default in Dired. + +--- +|**** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the 'dired-x' package was +loaded. +=-=-= From 06ba9484166a57bf7f307d6e847e1c0bd725950f Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 21 Feb 2023 16:35:25 +0100 Subject: [PATCH 02/27] Improve text about deleting windows * doc/emacs/windows.texi (Change Window): Improve grammar around 'delete-window-choose-selected'. --- doc/emacs/windows.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi index 239b5b2956b..e4abdef76be 100644 --- a/doc/emacs/windows.texi +++ b/doc/emacs/windows.texi @@ -310,8 +310,8 @@ the space that it occupied is given to an adjacent window (but not the minibuffer window, even if that is active at the time). Deleting the window has no effect on the buffer it used to display; the buffer continues to exist, and you can still switch to it with @kbd{C-x b}. -The option @code{delete-window-choose-selected} allows to choose which -window becomes the new selected window instead (@pxref{Deleting +The option @code{delete-window-choose-selected} controls which +window is chosen as the new selected window instead (@pxref{Deleting Windows,,, elisp, The Emacs Lisp Reference Manual}). @findex kill-buffer-and-window From 68df9e5953c881d390fdb14fc774c3cd45060ba4 Mon Sep 17 00:00:00 2001 From: Andrea Corallo Date: Tue, 21 Feb 2023 14:58:28 +0100 Subject: [PATCH 03/27] * lisp/emacs-lisp/comp.el (comp--trampoline-abs-filename): Improve 5d0b45cd67b --- lisp/emacs-lisp/comp.el | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index a0b18ea864f..046d169f00f 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -3812,10 +3812,8 @@ Return the trampoline if found or nil otherwise." ;; Default to some temporary directory if no better option was ;; found. finally (cl-return - (expand-file-name - (make-temp-file (file-name-sans-extension rel-filename) 0 ".eln" - nil) - temporary-file-directory)))) + (make-temp-file (file-name-sans-extension rel-filename) nil ".eln" + nil)))) (defun comp-trampoline-compile (subr-name) "Synthesize compile and return a trampoline for SUBR-NAME." From cf53e62a791a7585fe83e1752f205317a037df4c Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 21 Feb 2023 16:45:21 +0100 Subject: [PATCH 04/27] Add 'process-status' to process shortdoc * lisp/emacs-lisp/shortdoc.el (process): Add 'process-status'. --- lisp/emacs-lisp/shortdoc.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index ed4e205d204..c49960c2ee6 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -1167,6 +1167,9 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), :eg-result-string "#") (processp :eval (processp t)) + (process-status + :no-eval (process-status process) + :eg-result exit) (delete-process :no-value (delete-process process)) (kill-process From ef38774c02c3dd0fde6cc67e2105fb2d86f6a49c Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 21 Feb 2023 16:55:21 +0100 Subject: [PATCH 05/27] Improve dnd-direct-save-remote-files docstring * lisp/dnd.el (dnd-direct-save-remote-files): Reword. --- lisp/dnd.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/dnd.el b/lisp/dnd.el index 3abb108a4a7..67907ec403e 100644 --- a/lisp/dnd.el +++ b/lisp/dnd.el @@ -108,11 +108,11 @@ program." (defcustom dnd-direct-save-remote-files 'x "Whether or not to perform a direct save of remote files. -This is compatible with less programs, but means dropped files +This is compatible with fewer programs, but means dropped files will be saved with their actual file names, and not a temporary file name provided by TRAMP. -This defaults to `x', which means only to drop that way on X +This defaults to `x', which means to save that way only on X Windows." :type '(choice (const :tag "Only use direct save on X Windows" x) (const :tag "Use direct save everywhere" t) From f1c838980601f05479bf29502c04fc5c38339c97 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 21 Feb 2023 18:15:35 +0200 Subject: [PATCH 06/27] Fix build --without-xdbe * src/xterm.c (x_end_cr_clip, handle_one_xevent): Condition double-buffering code on HAVE_XDBE. (Bug#61667) --- src/xterm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xterm.c b/src/xterm.c index 6a4b84babe4..14c7f89b6ec 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5830,8 +5830,10 @@ void x_end_cr_clip (struct frame *f) { cairo_restore (FRAME_CR_CONTEXT (f)); +#ifdef HAVE_XDBE if (FRAME_X_DOUBLE_BUFFERED_P (f)) x_mark_frame_dirty (f); +#endif } void @@ -20900,8 +20902,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_flush (WINDOW_XFRAME (XWINDOW (bar->window))); } +#ifdef HAVE_XDBE if (f && FRAME_X_DOUBLE_BUFFERED_P (f)) x_drop_xrender_surfaces (f); +#endif goto OTHER; } From 4dc1f2b9a01e35633acb7d01ec177e896b3b49c6 Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 21 Feb 2023 18:05:32 +0100 Subject: [PATCH 07/27] ; * src/xterm.c (x_update_end): Condition on HAVE_XDBE --- src/xterm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xterm.c b/src/xterm.c index 14c7f89b6ec..e981a36fa9c 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -7360,8 +7360,10 @@ x_update_end (struct frame *f) MOUSE_HL_INFO (f)->mouse_face_defer = false; #ifdef USE_CAIRO +# ifdef HAVE_XDBE if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f)) cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f))); +# endif #endif /* If double buffering is disabled, finish the update here. From 48c9a50771383f08593ddc41db4f42bc633a7e56 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Tue, 21 Feb 2023 18:49:04 +0100 Subject: [PATCH 08/27] * etc/NEWS: Mention new buffer display action alist entries --- etc/NEWS | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 0106953c1e0..48f743fc9da 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1175,6 +1175,33 @@ For example, a 'display-buffer-alist' entry of will make the body of the chosen window 40 columns wide. For the height use 'window-height' and 'body-lines', respectively. ++++ +*** 'display-buffer' provides more options for using an existing window. +The display buffer action functions 'display-buffer-use-window' and +'display-buffer-use-least-recent-window' now honor the action alist +entry 'window-min-height' as well as the entries listed below to make +the display of several buffers in a row more amenable. + ++++ +*** New buffer display action alist entry 'lru-frames'. +This allows to specify which frames 'display-buffer' should consider +when using a window that shows another buffer. + ++++ +*** New buffer display action alist entry 'lru-time'. +'display-buffer' will ignore windows with a use time higher than that +when using a window that shows another buffer. + ++++ +*** New buffer display action alist entry 'bump-use-time'. +This has 'display-buffer' bump the use time of any window it returns, +making it a less likely candidate for displaying another buffer. + ++++ +*** New buffer display action alist entry 'window-min-width'. +This allows to specify a minimum width of the window used to display a +buffer. + --- *** You can customize on which window 'scroll-other-window' operates. This is controlled by the new 'other-window-scroll-default' variable. From fb5dbf6de73fa034338448f1029c55f85d1078b4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 21 Feb 2023 22:06:30 +0200 Subject: [PATCH 09/27] ; Fix documentation of 'icon-title-format'. --- doc/lispref/frames.texi | 5 +++-- etc/NEWS | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 638b759ff13..e0766ad0b43 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -2653,8 +2653,9 @@ like that of @code{frame-title-format}. The value can also be avoids problems with some window managers and desktop environments, where a change in a frame's title (when a frame is iconified) is interpreted as a request to raise the frame and/or give it input -focus. The default is a string identical to the default value of -@code{frame-title-format}. +focus. It is also useful if you want the frame's title to be the same +no matter if the frame is iconified or not. The default value is a +string identical to the default value of @code{frame-title-format}. @end defvar @defvar multiple-frames diff --git a/etc/NEWS b/etc/NEWS index 48f743fc9da..8e406128357 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1221,7 +1221,8 @@ the corresponding deleted frame. That value means to use 'frame-title-format' for iconified frames. This is useful with some window managers and desktop environments which treat changes in frame's title as requests to raise the frame -and/or give it input focus. +and/or give it input focus, or if you want the frame's title to be the +same no matter if the frame is iconified or not. ** Tab Bars and Tab Lines From ba91a76659b911f90914a61a2f2d5c0073a8890a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 22 Feb 2023 14:55:05 +0200 Subject: [PATCH 10/27] Avoid division by zero in get_narrowed_* functions * src/xdisp.c (get_narrowed_width, get_narrowed_len): Return at least 1 as the value. (Bug#61704) --- src/xdisp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index f5d54974b13..b64f1d35cbc 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3498,18 +3498,18 @@ init_iterator (struct it *it, struct window *w, static int get_narrowed_width (struct window *w) { - int fact; /* In a character-only terminal, only one font size is used, so we can use a smaller factor. */ - fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3; - return fact * window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS); + int fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3; + int width = window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS); + return fact * max (1, width); } static int get_narrowed_len (struct window *w) { - return get_narrowed_width (w) * - window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS); + int height = window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS); + return get_narrowed_width (w) * max (1, height); } ptrdiff_t From 003759a6dca730df6fae6c9bc8d4a47761b10014 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 22 Feb 2023 15:16:25 +0200 Subject: [PATCH 11/27] Explain effect of variable-pitch fonts on fill-column * doc/emacs/text.texi (Fill Commands): * doc/emacs/display.texi (Displaying Boundaries): * lisp/display-fill-column-indicator.el (display-fill-column-indicator-mode): Document caveats of using variable-pitch fonts with 'fill-column' and its indicator. (Bug#61677) --- doc/emacs/display.texi | 6 +++++- doc/emacs/text.texi | 7 ++++++- lisp/display-fill-column-indicator.el | 3 +++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index a86c12a0db7..7ec843180b8 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi @@ -1402,7 +1402,11 @@ right-to-left paragraphs. functionality especially in @code{prog-mode} and its descendants (@pxref{Major Modes}) to indicate the position of a specific column that has some special meaning for formatting the source code of a -program. +program. This assumes the buffer uses a fixed-pitch font, where all +the characters (with the possible exception of double-width +characters) have the same width on display. If the buffer uses +variable-pitch fonts, the fill-column indicators on different lines +might appear unaligned. To activate the fill-column indication display, use the minor modes @code{display-fill-@-column-indicator-mode} and diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 3cc5f10582a..7037c8c943a 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -619,7 +619,12 @@ variable @code{fill-column}. The default value (@pxref{Locals}) is is to use the command @kbd{C-x f} (@code{set-fill-column}). With a numeric argument, it uses that as the new fill column. With just @kbd{C-u} as argument, it sets @code{fill-column} to the current -horizontal position of point. +horizontal position of point. Note that, by its very nature, +@code{fill-column} is measured in column units; the actual position of +that column on a graphical display depends on the font being used. In +particular, using variable-pitch fonts will cause the +@code{fill-column} occupy different horizontal positions on display in +different lines. @cindex centering @findex center-line diff --git a/lisp/display-fill-column-indicator.el b/lisp/display-fill-column-indicator.el index 7ad09de0765..45bdca2f5a5 100644 --- a/lisp/display-fill-column-indicator.el +++ b/lisp/display-fill-column-indicator.el @@ -53,6 +53,9 @@ customize `display-fill-column-indicator-column'. You can change the character for the indicator setting `display-fill-column-indicator-character'. The globalized version is `global-display-fill-column-indicator-mode', which see. +This minor mode assumes the buffer uses a fixed-pitch font; if you +use variable-pitch fonts, the indicators on different lines might +not appear aligned. See Info node `Displaying Boundaries' for details." :lighter nil (if display-fill-column-indicator-mode From 1f4886fdb09ad6eba5b24bc5032fa650da3a7fcd Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Sun, 19 Feb 2023 21:03:57 +0100 Subject: [PATCH 12/27] Do not error out on non image file (bug#61639) * lisp/image/image-dired.el (image-dired-display-thumbs): Do not insert non image file and do not display image-dired buffer if it is empty. --- lisp/image/image-dired.el | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lisp/image/image-dired.el b/lisp/image/image-dired.el index 11632e7f28e..8e2a75a418f 100644 --- a/lisp/image/image-dired.el +++ b/lisp/image/image-dired.el @@ -585,13 +585,15 @@ thumbnail buffer to be selected." (erase-buffer)) (goto-char (point-max))) (dolist (file files) - (let ((thumb (image-dired--get-create-thumbnail-file file))) + (when (string-match-p (image-dired--file-name-regexp) file) (image-dired-insert-thumbnail - thumb file dired-buf + (image-dired--get-create-thumbnail-file file) file dired-buf (cl-incf image-dired--number-of-thumbnails))))) - (if do-not-pop - (display-buffer buf) - (pop-to-buffer buf)) + (if (> image-dired--number-of-thumbnails 0) + (if do-not-pop + (display-buffer buf) + (pop-to-buffer buf)) + (message "No images selected")) (image-dired--line-up-with-method) (image-dired--update-header-line)))) From d816429e2f26731b790be77b8a8a5ce5261832ed Mon Sep 17 00:00:00 2001 From: Augusto Stoffel Date: Mon, 20 Feb 2023 10:49:22 +0100 Subject: [PATCH 13/27] * lisp/progmodes/python.el (python--import-sources): Fix regexp (bug#61648) --- lisp/progmodes/python.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 0d714c31e9e..eab5e70af33 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -6376,7 +6376,7 @@ for key in sorted(result): "List files containing Python imports that may be useful in the current buffer." (if-let (((featurep 'project)) ;For compatibility with Emacs < 26 (proj (project-current))) - (seq-filter (lambda (s) (string-match-p "\\.py[ciw]?\\'" s)) + (seq-filter (lambda (s) (string-match-p "\\.py[iwx]?\\'" s)) (project-files proj)) (list default-directory))) From a6be0be1db64fc5ab5863ffaf4a37fe2bcc6fe98 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 22 Feb 2023 15:40:26 +0200 Subject: [PATCH 14/27] ; Clarify "kill files" in Gnus manual * doc/misc/gnus.texi (Scoring): Make the reference to kill files less vague. (Bug#61325) --- doc/misc/gnus.texi | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index 486171a080a..d513726979b 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -19808,10 +19808,11 @@ locally stored articles. @chapter Scoring @cindex scoring -Other people use @dfn{kill files}, but we here at Gnus Towers like -scoring better than killing, so we'd rather switch than fight. They do -something completely different as well, so sit up straight and pay -attention! +Other people use @dfn{kill files} (@pxref{Kill Files}, but we here at +Gnus Towers like scoring better than killing, so we'd rather switch +than fight. Scoring and score files processing are more powerful and +faster than processing of kill files. Scoring also does something +completely different as well, so sit up straight and pay attention! @vindex gnus-summary-mark-below All articles have a default score (@code{gnus-summary-default-score}), From db21c84bc9458a1ebaf93a4ff5d289ff96ddd33d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 22 Feb 2023 16:24:59 +0200 Subject: [PATCH 15/27] ; Improve doc string of 'C-q' * lisp/simple.el (read-quoted-char-radix, quoted-insert): Doc fix. --- lisp/simple.el | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lisp/simple.el b/lisp/simple.el index 5f23910efc6..b6efb06fc27 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -937,7 +937,7 @@ column specified by the function `current-left-margin'." (defcustom read-quoted-char-radix 8 "Radix for \\[quoted-insert] and other uses of `read-quoted-char'. -Legitimate radix values are 8, 10 and 16." +Supported radix values are 8, 10 and 16." :type '(choice (const 8) (const 10) (const 16)) :group 'editing-basics) @@ -1012,21 +1012,25 @@ any other non-digit terminates the character code and is then used as input.")) This is useful for inserting control characters. With argument, insert ARG copies of the character. -If the first character you type after this command is an octal digit, -you should type a sequence of octal digits that specify a character code. -Any nondigit terminates the sequence. If the terminator is a RET, -it is discarded; any other terminator is used itself as input. +If the first character you type is an octal digit, the sequence of +one or more octal digits you type is interpreted to specify a +character code. Any character that is not an octal digit terminates +the sequence. If the terminator is a RET, it is discarded; any +other terminator is used itself as input and is inserted. + The variable `read-quoted-char-radix' specifies the radix for this feature; -set it to 10 or 16 to use decimal or hex instead of octal. +set it to 10 or 16 to use decimal or hex instead of octal. If you change +the radix, the characters interpreted as specifying a character code +change accordingly: 0 to 9 for decimal, 0 to F for hex. In overwrite mode, this function inserts the character anyway, and -does not handle octal digits specially. This means that if you use -overwrite as your normal editing mode, you can use this function to -insert characters when necessary. +does not handle octal (or decimal or hex) digits specially. This means +that if you use overwrite mode as your normal editing mode, you can use +this function to insert characters when necessary. In binary overwrite mode, this function does overwrite, and octal -digits are interpreted as a character code. This is intended to be -useful for editing binary files." +(or decimal or hex) digits are interpreted as a character code. This +is intended to be useful for editing binary files." (interactive "*p") (let* ((char ;; Avoid "obsolete" warnings for translation-table-for-input. From db7096a532ca031687f9411df621900e869e9e98 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Wed, 22 Feb 2023 06:24:17 -0800 Subject: [PATCH 16/27] Yield to erc-move-to-prompt before unhiding prompt * lisp/erc/erc-backend.el (erc--hide-prompt): Change hook depth from 0 to 91 to allow the `move-to-prompt' module to do its thing. This feature was added by bug#54826 and first appeared in Emacs 29. * lisp/erc/erc-common.el (erc-server-user): Remove erroneous comment. The `buffers' field is a list of buffers. * test/lisp/erc/erc-tests.el (erc-hide-prompt): Use `erc--target' instead of `erc-default-recipients' because this is new code. --- lisp/erc/erc-backend.el | 34 ++++++++++++++++------------------ lisp/erc/erc-common.el | 3 --- test/lisp/erc/erc-tests.el | 4 ++-- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index cf0b734bd28..567443f5329 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -883,24 +883,22 @@ Conditionally try to reconnect and take appropriate action." (erc--unhide-prompt))) (defun erc--hide-prompt (proc) - (erc-with-all-buffers-of-server - proc nil ; sorta wish this was indent 2 - (when (and erc-hide-prompt - (or (eq erc-hide-prompt t) - ;; FIXME use `erc--target' after bug#48598 - (memq (if (erc-default-target) - (if (erc-channel-p (car erc-default-recipients)) - 'channel - 'query) - 'server) - erc-hide-prompt)) - (marker-position erc-insert-marker) - (marker-position erc-input-marker) - (get-text-property erc-insert-marker 'erc-prompt)) - (with-silent-modifications - (add-text-properties erc-insert-marker (1- erc-input-marker) - `(display ,erc-prompt-hidden))) - (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 0 t)))) + (erc-with-all-buffers-of-server proc nil + (when (and erc-hide-prompt + (or (eq erc-hide-prompt t) + (memq (if erc--target + (if (erc--target-channel-p erc--target) + 'channel + 'query) + 'server) + erc-hide-prompt)) + (marker-position erc-insert-marker) + (marker-position erc-input-marker) + (get-text-property erc-insert-marker 'erc-prompt)) + (with-silent-modifications + (add-text-properties erc-insert-marker (1- erc-input-marker) + `(display ,erc-prompt-hidden))) + (add-hook 'pre-command-hook #'erc--unhide-prompt-on-self-insert 91 t)))) (defun erc-process-sentinel (cproc event) "Sentinel function for ERC process." diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 994555acecf..0279b0a0bc4 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -48,9 +48,6 @@ ;; User data nickname host login full-name info ;; Buffers - ;; - ;; This is an alist of the form (BUFFER . CHANNEL-DATA), where - ;; CHANNEL-DATA is either nil or an erc-channel-user struct. (buffers nil)) (cl-defstruct (erc-channel-user (:type vector) :named) diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 40a2d2de657..d6c63934163 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -147,7 +147,7 @@ (should (looking-at-p (regexp-quote erc-prompt))) (setq erc-server-process (buffer-local-value 'erc-server-process (get-buffer "ServNet")) - erc-default-recipients '("#chan"))) + erc--target (erc--target-from-string "#chan"))) (with-current-buffer (get-buffer-create "bob") (erc-tests--send-prep) @@ -155,7 +155,7 @@ (should (looking-at-p (regexp-quote erc-prompt))) (setq erc-server-process (buffer-local-value 'erc-server-process (get-buffer "ServNet")) - erc-default-recipients '("bob"))) + erc--target (erc--target-from-string "bob"))) (ert-info ("Value: t (default)") (should (eq erc-hide-prompt t)) From 177d0cf2a9a4467c8106426e3f80395cc02d8ab5 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Wed, 22 Feb 2023 15:35:03 +0100 Subject: [PATCH 17/27] ; * etc/NEWS: Fix typos. --- etc/NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 8e406128357..72f46a6ce59 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1177,7 +1177,7 @@ height use 'window-height' and 'body-lines', respectively. +++ *** 'display-buffer' provides more options for using an existing window. -The display buffer action functions 'display-buffer-use-window' and +The display buffer action functions 'display-buffer-reuse-window' and 'display-buffer-use-least-recent-window' now honor the action alist entry 'window-min-height' as well as the entries listed below to make the display of several buffers in a row more amenable. From 43c4dd6f962df22507c41ea0ad20b58b5644becd Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 22 Feb 2023 17:40:00 +0200 Subject: [PATCH 18/27] ; * doc/emacs/anti.texi (Antinews): Adjust to latest changes. --- doc/emacs/anti.texi | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/emacs/anti.texi b/doc/emacs/anti.texi index c46110a530d..b25d8a8e3cc 100644 --- a/doc/emacs/anti.texi +++ b/doc/emacs/anti.texi @@ -69,13 +69,14 @@ idea anyway. @item In line with simplifying and eventually removing the native-compilation option, we've deleted the -@code{inhibit-automatic-native-compilation} variable and its support -code. This greatly simplifies how native compilation works and makes -your configure-time decision regarding native compilation in Emacs -clear-cut: either Emacs always compiles Lisp to native code before -using it, or it never does so; no more half measures and special -exceptions. For similar reasons, @code{native-compile-prune-cache} -and @code{startup-redirect-eln-cache} features are no longer part of +@option{--with-native-compilation=aot} configure-time option. This +greatly simplifies how native compilation works and makes your +configure-time decision regarding native compilation in Emacs +clear-cut: either Emacs compiles non-preloaded Lisp packages to native +code only before using it, or it never uses native compilation at all; +no more half measures and special exceptions. For similar reasons, +@code{native-compile-prune-cache} and +@code{startup-redirect-eln-cache} features are no longer part of Emacs. @item From a0b67252346c64ee188eec909a653dbc14cb5652 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 22 Feb 2023 10:10:04 -0700 Subject: [PATCH 19/27] ; * doc/emacs/vc1-xtra.texi (Preparing Patches): Wording tweaks. --- doc/emacs/vc1-xtra.texi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/emacs/vc1-xtra.texi b/doc/emacs/vc1-xtra.texi index 22b415613cb..3785e565676 100644 --- a/doc/emacs/vc1-xtra.texi +++ b/doc/emacs/vc1-xtra.texi @@ -288,16 +288,16 @@ is about to run. @findex vc-prepare-patch When collaborating on projects it is common to send patches via email, -to share changes. If you wish to do this using VC, you can use the +to share changes. You can do this using VC with the @code{vc-prepare-patch} command. This will prompt you for the revisions you wish to share, and which destination email address(es) -to use. The revisions are separated using commas (or whatever was -configured by @var{crm-separator}). The command will then prepare +to use. Separate the revisions using the value of +@var{crm-separator}, commas by default. The command will then prepare those revisions using your @abbr{MUA, Mail User Agent} for you to review and send. When invoked interactively in a Log View buffer with marked revisions, -these revisions will be used. +those marked revisions will be used. @vindex vc-prepare-patches-separately Depending on the value of the user option From d411b4d1fd368bfe9dc72db7864d4c7d99babb18 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 22 Feb 2023 10:17:08 -0700 Subject: [PATCH 20/27] ; * etc/NEWS (C-x v !): Additional text. --- etc/NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 72f46a6ce59..4511f8e20f8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2168,6 +2168,10 @@ before execution. For example, in a Git repository, you can produce a log of more than one branch by typing 'C-x v ! C-x v b l' and then appending additional branch names to the 'git log' command. +The intention is that this command can be used to access a wide +variety of version control system-specific functionality from VC +without complexifying either the VC command set or the backend API. + --- *** 'C-x v v' in a diffs buffer allows to commit only some of the changes. This command is intended to allow you to commit only some of the From 6016f1982d34a88f626c9fcbeef51040d39d5f9f Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Wed, 22 Feb 2023 18:48:33 +0100 Subject: [PATCH 21/27] ; * etc/NEWS: Fix typo again --- etc/NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index 4511f8e20f8..7f84d548149 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1177,7 +1177,7 @@ height use 'window-height' and 'body-lines', respectively. +++ *** 'display-buffer' provides more options for using an existing window. -The display buffer action functions 'display-buffer-reuse-window' and +The display buffer action functions 'display-buffer-use-some-window' and 'display-buffer-use-least-recent-window' now honor the action alist entry 'window-min-height' as well as the entries listed below to make the display of several buffers in a row more amenable. From ea7251ad6dfe3cfbdcea221a67c7b7d4fcbfebfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Wed, 22 Feb 2023 18:05:00 +0000 Subject: [PATCH 22/27] Eglot: go back to setting eldoc-documentation-strategy again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commits reverts part of commit e83c78b8c7784254c2c6f043530ab325c2fa7f16 Author: João Távora Date: Mon Feb 20 22:43:50 2023 +0000 Eglot: respect user's Eldoc configuration by default In that commit, I did what many longstanding issues and users were suggesting and removed Eglot's override of two Eldoc user configuration varibles. I verified that Eglot's behaviour would stay mostly unaltered but my tests were very incomplete. In short there is no way that Eglot can work acceptably with the default setting of 'eldoc-documentation-strategy', which is 'eldoc-documentation-default'. So it must be changed, either globally or locally in Eglot's minor mode. This is true for any situation where both synchronous and asynchronous documentation sources are present. In Eglot's case there are two asynchronous sources which have more importance than the synchronous source. So any other strategy except the 'eldoc-documentation-default' makes sense. * lisp/progmodes/eglot.el (eglot--managed-mode): Set eldoc-documentation-strategy to eldoc-documentation-compose. --- lisp/progmodes/eglot.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index abc090aea51..54f44d41b0d 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1764,6 +1764,8 @@ Use `eglot-managed-p' to determine if current buffer is managed.") (eglot--setq-saving flymake-diagnostic-functions '(eglot-flymake-backend)) (eglot--setq-saving company-backends '(company-capf)) (eglot--setq-saving company-tooltip-align-annotations t) + (eglot--setq-saving eldoc-documentation-strategy + #'eldoc-documentation-compose) (unless (eglot--stay-out-of-p 'imenu) (add-function :before-until (local 'imenu-create-index-function) #'eglot-imenu)) From 711a775ba761e2838a6f73bf4b3119f0fe412841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 21 Feb 2023 13:59:04 +0000 Subject: [PATCH 23/27] Eglot: simplify capability-checking code * lisp/progmodes/eglot.el (eglot--server-capable-or-lose): New helper. (eglot--signal-textDocument/willSave) (eglot--signal-textDocument/didSave): Tweak docstring. (eglot--workspace-symbols, xref-backend-identifier-at-point) (eglot-format, eglot-completion-at-point, eglot-rename) (eglot-code-actions): Use new eglot--server-capable-or-lose. --- lisp/progmodes/eglot.el | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 54f44d41b0d..f528b334c12 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1641,6 +1641,14 @@ under cursor." if (not (listp (cadr probe))) do (cl-return (if more nil (cadr probe))) finally (cl-return (or (cadr probe) t))))) +(defun eglot--server-capable-or-lose (&rest feats) + "Like `eglot--server-capable', but maybe error out." + (let ((retval (apply #'eglot--server-capable feats))) + (unless retval + (eglot--error "Unsupported or ignored LSP capability `%s'" + (mapconcat #'symbol-name feats " "))) + retval)) + (defun eglot--range-region (range &optional markers) "Return region (BEG . END) that represents LSP RANGE. If optional MARKERS, make markers." @@ -2484,7 +2492,7 @@ When called interactively, use the currently active server" :textDocument/didClose `(:textDocument ,(eglot--TextDocumentIdentifier))))) (defun eglot--signal-textDocument/willSave () - "Send textDocument/willSave to server." + "Maybe send textDocument/willSave to server." (let ((server (eglot--current-server-or-lose)) (params `(:reason 1 :textDocument ,(eglot--TextDocumentIdentifier)))) (when (eglot--server-capable :textDocumentSync :willSave) @@ -2496,7 +2504,7 @@ When called interactively, use the currently active server" :timeout 0.5)))))) (defun eglot--signal-textDocument/didSave () - "Send textDocument/didSave to server." + "Maybe send textDocument/didSave to server." (eglot--signal-textDocument/didChange) (when (eglot--server-capable :textDocumentSync :save) (jsonrpc-notify @@ -2593,8 +2601,7 @@ Try to visit the target file for a richer summary line." "Ask for :workspace/symbol on PAT, return list of formatted strings. If BUFFER, switch to it before." (with-current-buffer (or buffer (current-buffer)) - (unless (eglot--server-capable :workspaceSymbolProvider) - (eglot--error "This LSP server isn't a :workspaceSymbolProvider")) + (eglot--server-capable-or-lose :workspaceSymbolProvider) (mapcar (lambda (wss) (eglot--dbind ((WorkspaceSymbol) name containerName kind) wss @@ -2656,13 +2663,12 @@ If BUFFER, switch to it before." (cl-defun eglot--lsp-xrefs-for-method (method &key extra-params capability) "Make `xref''s for METHOD, EXTRA-PARAMS, check CAPABILITY." - (unless (eglot--server-capable - (or capability - (intern - (format ":%sProvider" - (cadr (split-string (symbol-name method) - "/")))))) - (eglot--error "Sorry, this server doesn't do %s" method)) + (eglot--server-capable-or-lose + (or capability + (intern + (format ":%sProvider" + (cadr (split-string (symbol-name method) + "/")))))) (let ((response (jsonrpc-request (eglot--current-server-or-lose) @@ -2759,8 +2765,7 @@ for which LSP on-type-formatting should be requested." :end (eglot--pos-to-lsp-position end))))) (t '(:textDocument/formatting :documentFormattingProvider nil))))) - (unless (eglot--server-capable cap) - (eglot--error "Server can't format!")) + (eglot--server-capable-or-lose cap) (eglot--apply-text-edits (jsonrpc-request (eglot--current-server-or-lose) @@ -3203,8 +3208,7 @@ Returns a list as described in docstring of `imenu--index-alist'." "unknown symbol")) nil nil nil nil (symbol-name (symbol-at-point))))) - (unless (eglot--server-capable :renameProvider) - (eglot--error "Server can't rename!")) + (eglot--server-capable-or-lose :renameProvider) (eglot--apply-workspace-edit (jsonrpc-request (eglot--current-server-or-lose) :textDocument/rename `(,@(eglot--TextDocumentPositionParams) @@ -3231,9 +3235,7 @@ at point. With prefix argument, prompt for ACTION-KIND." '("quickfix" "refactor.extract" "refactor.inline" "refactor.rewrite" "source.organizeImports"))) t)) - (unless (or (not interactive) - (eglot--server-capable :codeActionProvider)) - (eglot--error "Server can't execute code actions!")) + (eglot--server-capable-or-lose :codeActionProvider) (let* ((server (eglot--current-server-or-lose)) (actions (jsonrpc-request From 7ad5d9babed68ddb8cc4bdf7571fdf10e44e1bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Wed, 22 Feb 2023 18:50:46 +0000 Subject: [PATCH 24/27] Eglot: restore eldoc-documentation-functions on shutdown * lisp/progmodes/eglot.el (eglot--managed-mode): Restore eldoc-documentation-functions when shutting down eglot. --- lisp/progmodes/eglot.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index f528b334c12..3daca24a586 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1799,6 +1799,8 @@ Use `eglot-managed-p' to determine if current buffer is managed.") (remove-hook 'change-major-mode-hook #'eglot--managed-mode-off t) (remove-hook 'post-self-insert-hook 'eglot--post-self-insert-hook t) (remove-hook 'pre-command-hook 'eglot--pre-command-hook t) + (remove-hook 'eldoc-documentation-functions #'eglot-hover-eldoc-function t) + (remove-hook 'eldoc-documentation-functions #'eglot-signature-eldoc-function t) (cl-loop for (var . saved-binding) in eglot--saved-bindings do (set (make-local-variable var) saved-binding)) (remove-function (local 'imenu-create-index-function) #'eglot-imenu) From 28ed0d1840f94ba52b8b60bfbf222493fee2a3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Wed, 22 Feb 2023 18:44:39 +0000 Subject: [PATCH 25/27] Eglot: run eglot-managed-mode-hook after LSP didOpen This allows using the hook for interacting with the LSP server using the current buffer as the subject of that interaction ("document" in LSP parlance). * lisp/progmodes/eglot.el (eglot--maybe-activate-editing-mode): Run eglot-managed-mode-hook here. (eglot--managed-mode): Not here. --- lisp/progmodes/eglot.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 3daca24a586..8b0caf41ad7 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1814,9 +1814,7 @@ Use `eglot-managed-p' to determine if current buffer is managed.") (delq (current-buffer) (eglot--managed-buffers server))) (when (and eglot-autoshutdown (null (eglot--managed-buffers server))) - (eglot-shutdown server)))))) - ;; Note: the public hook runs before the internal eglot--managed-mode-hook. - (run-hooks 'eglot-managed-mode-hook)) + (eglot-shutdown server))))))) (defun eglot--managed-mode-off () "Turn off `eglot--managed-mode' unconditionally." @@ -1858,7 +1856,10 @@ If it is activated, also signal textDocument/didOpen." (when (and buffer-file-name (eglot-current-server)) (setq eglot--diagnostics nil) (eglot--managed-mode) - (eglot--signal-textDocument/didOpen)))) + (eglot--signal-textDocument/didOpen) + ;; Run user hook after 'textDocument/didOpen' so server knows + ;; about the buffer. + (run-hooks 'eglot-managed-mode-hook)))) (add-hook 'find-file-hook 'eglot--maybe-activate-editing-mode) (add-hook 'after-change-major-mode-hook 'eglot--maybe-activate-editing-mode) From 1841299a11dfcd875bdbdb75d1fc56d996a727f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 21 Feb 2023 14:14:05 +0000 Subject: [PATCH 26/27] Eglot: implement inlay hints (bug#61412, bug#61066) Inlay hints are small text annotations to specific parts of the whole buffer, not unlike diagnostics, but designed to help readability instead of indicating problems. For example, a C++ LSP server can serve hints about positional parameter names in function calls and a variable's automatically deduced type. Emacs can display these hints in many little 0-length overlays with an 'before-string property, thus helping the user remember those types and parameter names. Since inlay hints are potentially a large amount of data to request from the LSP server, the implementation strives to be as parsimonious as possible with these requests. So, by default, inlay hints are only requested for the visible portions of the buffer across windows showing this buffer. This is done by leveraging the 'window-scroll-functions' variable, making for a reasonably complex implementation involving per-window timers. When scrolling a window, it may take a short amount of time for inlay hints to "pop in". The new user variable 'eglot-lazy-inlay-hints' can be used to exert some control over this. Specifically, if the variable's value is set to 'nil', then inlay hints are greedily fetched for the whole buffer every time a change occurs. This is a much simpler mode of operation which may avoid problems, but is also likely much slower in large buffers. Also, because the inlay feature is probably visually suprising to some, it is turned OFF by default, which is not the usual practice of Eglot (at least not when the necessary infrastructure is present). This decision may be changed soon. Here's a good one-liner for enabling it by default in every Eglot-managed buffer: (add-hook 'eglot-managed-mode-hook #'eglot-inlay-hints-mode) I haven't tested inlay hints extensively across many LSP servers, so I would appreciate any testing, both for functional edge cases and regarding performance. There are possibly more optimization oportunities in the "lazy" mode of operation, like more aggressively deleting buffer overlays that are not in visible parts of the buffer. Though I ended up writing this one from scratch, I want to thank Dimitry Bolopopsky and Chinmay Dala for suggestions and early patches. * lisp/progmodes/eglot.el (eglot--lsp-interface-alist): Define InlayHint. (eglot-client-capabilities): Announce 'inlayHint' capability. (eglot-ignored-server-capabilities): Add :inlayHintProvider. (eglot--document-changed-hook): New helper hook. (eglot--after-change): Use it. (eglot-inlay-hint-face, eglot-type-hint-face) (eglot-parameter-hint-face): New faces. (eglot--update-hints-1, eglot--inlay-hints-after-scroll) (eglot--inlay-hints-fully, eglot--inlay-hints-lazily): New helpers. (eglot-lazy-inlay-hints): New user variable. (eglot-inlay-hints-mode): New minor mode. (eglot--maybe-activate-editing-mode): Try to activate eglot-inlay-hints-mode. (eglot--before-change): Remove overlays immediately in the area being changed. (eglot--managed-mode-off): Remove overlays. * doc/misc/eglot.texi (Eglot Features): Mention inlay hints. (Eglot Variables): Mention eglot-lazy-inlay-hints. --- doc/misc/eglot.texi | 17 +++++ lisp/progmodes/eglot.el | 145 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 156 insertions(+), 6 deletions(-) diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi index 56151b5482f..38c6adaf131 100644 --- a/doc/misc/eglot.texi +++ b/doc/misc/eglot.texi @@ -502,6 +502,15 @@ project. The command @kbd{M-x eglot-code-actions} will pop up a menu of code applicable actions at point. @end table +@item M-x eglot-inlay-hints-mode +This command toggles LSP ``inlay hints'' on and off for the current +buffer. Inlay hints are small text annotations to specific parts of +the whole buffer, not unlike diagnostics, but designed to help +readability instead of indicating problems. For example, a C++ LSP +server can serve hints about positional parameter names in function +calls and a variable's automatically deduced type. Inlay hints help +the user not have to remember these things by heart. + @end itemize Not all servers support the full set of LSP capabilities, but most of @@ -874,6 +883,14 @@ this map. For example: (define-key eglot-mode-map (kbd "") 'xref-find-definitions) @end lisp +@item eglot-lazy-inlay-hints +This variable controls the operation and performance of LSP Inlay +Hints (@pxref{Eglot Features}). If non-@code{nil}, it specifies how +much time to wait after a window is displayed or scrolled before +requesting hints for that visible portion of a given buffer. If +@code{nil}, inlay hints are always requested for the whole buffer, +even for parts of it not currently visible. + @end vtable Additional variables, which are relevant for customizing the server diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 8b0caf41ad7..df755dfa43a 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -47,9 +47,10 @@ ;; definition-chasing, Flymake for diagnostics, Eldoc for at-point ;; documentation, etc. Eglot's job is generally *not* to provide ;; such a UI itself, though a small number of simple -;; counter-examples do exist, for example in the `eglot-rename' -;; command. When a new UI is evidently needed, consider adding a -;; new package to Emacs, or extending an existing one. +;; counter-examples do exist, e.g. in the `eglot-rename' command or +;; the `eglot-inlay-hints-mode' minor mode. When a new UI is +;; evidently needed, consider adding a new package to Emacs, or +;; extending an existing one. ;; ;; * Eglot was designed to function with just the UI facilities found ;; in the latest Emacs core, as long as those facilities are also @@ -483,7 +484,9 @@ This can be useful when using docker to run a language server.") (VersionedTextDocumentIdentifier (:uri :version) ()) (WorkDoneProgress (:kind) (:title :message :percentage :cancellable)) (WorkspaceEdit () (:changes :documentChanges)) - (WorkspaceSymbol (:name :kind) (:containerName :location :data))) + (WorkspaceSymbol (:name :kind) (:containerName :location :data)) + (InlayHint (:position :label) (:kind :textEdits :tooltip :paddingLeft + :paddingRight :data))) "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. INTERFACE-NAME is a symbol designated by the spec as @@ -803,6 +806,7 @@ treated as in `eglot--dbind'." :formatting `(:dynamicRegistration :json-false) :rangeFormatting `(:dynamicRegistration :json-false) :rename `(:dynamicRegistration :json-false) + :inlayHint `(:dynamicRegistration :json-false) :publishDiagnostics (list :relatedInformation :json-false ;; TODO: We can support :codeDescription after ;; adding an appropriate UI to @@ -1625,7 +1629,8 @@ under cursor." (const :tag "Highlight links in document" :documentLinkProvider) (const :tag "Decorate color references" :colorProvider) (const :tag "Fold regions of buffer" :foldingRangeProvider) - (const :tag "Execute custom commands" :executeCommandProvider))) + (const :tag "Execute custom commands" :executeCommandProvider) + (const :tag "Inlay hints" :inlayHintProvider))) (defun eglot--server-capable (&rest feats) "Determine if current server is capable of FEATS." @@ -1818,6 +1823,7 @@ Use `eglot-managed-p' to determine if current buffer is managed.") (defun eglot--managed-mode-off () "Turn off `eglot--managed-mode' unconditionally." + (remove-overlays nil nil 'eglot--overlay t) (eglot--managed-mode -1)) (defun eglot-current-server () @@ -2285,6 +2291,7 @@ THINGS are either registrations or unregisterations (sic)." (defun eglot--before-change (beg end) "Hook onto `before-change-functions' with BEG and END." + (remove-overlays beg end 'eglot--overlay t) (when (listp eglot--recent-changes) ;; Records BEG and END, crucially convert them into LSP ;; (line/char) positions before that information is lost (because @@ -2297,6 +2304,9 @@ THINGS are either registrations or unregisterations (sic)." (,end . ,(copy-marker end t))) eglot--recent-changes))) +(defvar eglot--document-changed-hook '(eglot--signal-textDocument/didChange) + "Internal hook for doing things when the document changes.") + (defun eglot--after-change (beg end pre-change-length) "Hook onto `after-change-functions'. Records BEG, END and PRE-CHANGE-LENGTH locally." @@ -2337,7 +2347,7 @@ Records BEG, END and PRE-CHANGE-LENGTH locally." eglot-send-changes-idle-time nil (lambda () (eglot--when-live-buffer buf (when eglot--managed-mode - (eglot--signal-textDocument/didChange) + (run-hooks 'eglot--document-changed-hook) (setq eglot--change-idle-timer nil)))))))) ;; HACK! Launching a deferred sync request with outstanding changes is a @@ -3464,6 +3474,129 @@ If NOERROR, return predicate, else erroring function." (revert-buffer) (pop-to-buffer (current-buffer))))) + +;;; Inlay hints +(defface eglot-inlay-hint-face '((t (:height 0.8 :inherit shadow))) + "Face used for inlay hint overlays.") + +(defface eglot-type-hint-face '((t (:inherit eglot-inlay-hint-face))) + "Face used for type inlay hint overlays.") + +(defface eglot-parameter-hint-face '((t (:inherit eglot-inlay-hint-face))) + "Face used for parameter inlay hint overlays.") + +(defcustom eglot-lazy-inlay-hints 0.3 + "If non-nil, restrict LSP inlay hints to visible portion of buffer. + +Value is number specifying how many seconds to wait after a +window has been (re)scrolled before requesting new inlay hints +for the visible region of the window being manipulated. + +If nil, then inlay hints are requested for the entire buffer. + +This value is only meaningful if the minor mode +`eglot-inlay-hints-mode' is true. +" + :type 'number + :version "29.1") + +(defun eglot--inlay-hints-fully () + (eglot--widening (eglot--update-hints-1 (point-min) (point-max)))) + +(cl-defun eglot--inlay-hints-lazily (&optional (buffer (current-buffer))) + (eglot--when-live-buffer buffer + (when eglot--managed-mode + (dolist (window (get-buffer-window-list nil nil 'visible)) + (eglot--update-hints-1 (window-start window) (window-end window)))))) + +(defun eglot--update-hints-1 (from to) + "Request LSP inlay hints and annotate current buffer from FROM to TO." + (let* ((buf (current-buffer)) + (paint-hint + (eglot--lambda ((InlayHint) position kind label paddingLeft paddingRight) + (goto-char (eglot--lsp-position-to-point position)) + (let ((ov (make-overlay (point) (point))) + (left-pad (and paddingLeft (not (memq (char-before) '(32 9))))) + (right-pad (and paddingRight (not (memq (char-after) '(32 9))))) + (text (if (stringp label) label (plist-get label :value)))) + (overlay-put ov 'before-string + (propertize + (concat (and left-pad " ") text (and right-pad " ")) + 'face (pcase kind + (1 'eglot-type-hint-face) + (2 'eglot-parameter-hint-face) + (_ 'eglot-inlay-hint-face)))) + (overlay-put ov 'eglot--inlay-hint t) + (overlay-put ov 'eglot--overlay t))))) + (jsonrpc-async-request + (eglot--current-server-or-lose) + :textDocument/inlayHint + (list :textDocument (eglot--TextDocumentIdentifier) + :range (list :start (eglot--pos-to-lsp-position from) + :end (eglot--pos-to-lsp-position to))) + :success-fn (lambda (hints) + (eglot--when-live-buffer buf + (eglot--widening + (remove-overlays from to 'eglot--inlay-hint t) + (mapc paint-hint hints)))) + :deferred 'eglot--update-hints-1))) + +(defun eglot--inlay-hints-after-scroll (window display-start) + (cl-macrolet ((wsetq (sym val) `(set-window-parameter window ',sym ,val)) + (wgetq (sym) `(window-parameter window ',sym))) + (let ((buf (window-buffer window)) + (timer (wgetq eglot--inlay-hints-timer)) + (last-display-start (wgetq eglot--last-inlay-hint-display-start))) + (when (and eglot-lazy-inlay-hints + ;; FIXME: If `window' is _not_ the selected window, + ;; then for some unknown reason probably related to + ;; the overlays added later to the buffer, the scroll + ;; function will be called indefinitely. Not sure if + ;; an Emacs bug, but prevent useless duplicate calls + ;; by saving and examining `display-start' fixes it. + (not (eql last-display-start display-start))) + (when timer (cancel-timer timer)) + (wsetq eglot--last-inlay-hint-display-start + display-start) + (wsetq eglot--inlay-hints-timer + (run-at-time + eglot-lazy-inlay-hints + nil (lambda () + (eglot--when-live-buffer buf + (when (eq buf (window-buffer window)) + (eglot--update-hints-1 (window-start window) + (window-end window)) + (wsetq eglot--inlay-hints-timer nil)))))))))) + +(define-minor-mode eglot-inlay-hints-mode + "Minor mode annotating buffer with LSP inlay hints." + :global nil + (cond (eglot-inlay-hints-mode + (cond + ((not (eglot--server-capable :inlayHintProvider)) + (eglot--warn + "No :inlayHintProvider support. Inlay hints will not work.")) + (eglot-lazy-inlay-hints + (add-hook 'eglot--document-changed-hook + #'eglot--inlay-hints-lazily t t) + (add-hook 'window-scroll-functions + #'eglot--inlay-hints-after-scroll nil t) + ;; Maybe there isn't a window yet for current buffer, + ;; so `run-at-time' ensures this runs after redisplay. + (run-at-time 0 nil #'eglot--inlay-hints-lazily)) + (t + (add-hook 'eglot--document-changed-hook + #'eglot--inlay-hints-fully nil t) + (eglot--inlay-hints-fully)))) + (t + (remove-hook 'eglot--document-changed-hook + #'eglot--inlay-hints-lazily t) + (remove-hook 'eglot--document-changed-hook + #'eglot--inlay-hints-fully t) + (remove-hook 'window-scroll-functions + #'eglot--inlay-hints-after-scroll t) + (remove-overlays nil nil 'eglot--inlay-hint t)))) + ;;; Hacks ;;; From 94e70ed4261dbfcef679697dfa0dc2348a90dbdc Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Wed, 22 Feb 2023 17:55:30 -0800 Subject: [PATCH 27/27] ; * lisp/emacs-lisp/eldoc.el (eldoc-display-in-echo-area): Fix typo. --- lisp/emacs-lisp/eldoc.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 3f5cf0ad0dc..83948ad00d4 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -570,7 +570,7 @@ known to be truncated." Honor `eldoc-echo-area-use-multiline-p' and `eldoc-echo-area-prefer-doc-buffer'." (cond - (;; Check if he wave permission to mess with echo area at all. For + (;; Check if we have permission to mess with echo area at all. For ;; example, if this-command is non-nil while running via an idle ;; timer, we're still in the middle of executing a command, e.g. a ;; query-replace where it would be annoying to overwrite the echo