master bd537c899d9 05/12: Merge from origin/emacs-31

Eli Zaretskii <[email protected]>
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: master
commit bd537c899d950b11a9343c02b27ca06499ed046e
Merge: 07bd2e2cf98 da0565d9b57
Author: Eli Zaretskii <[email protected]>
Commit: Eli Zaretskii <[email protected]>

    Merge from origin/emacs-31
    
    da0565d9b57 Flymake: really restore advertised compatibility to Emacs 26
    8f6e2cc66ba ; * etc/EGLOT-NEWS: Briefly mention recent changes.
    b86b9c195b6 Eglot: support commas in globs (bug#81425)
    65efc35a91f Eglot: respect e-stay-out-of when turning off (bug#81593)
    7d2988e7e40 Fix Custom keybindings in the documentation
    1c69563a1c8 ; Fix last change in dframe.el
    5f6ffef879b ; Improve and correct documentation of 'getenv'
    83ec0fd8f33 Eglot: prevent showDocument disruption of sync requests (...
    27ea7e6c1e2 * lisp/progmodes/sh-script.el (bash-ts-mode): Fix 'sexp-d...
    73d959233e2 Fix setting windows' old_buffer in 'set-window-configurat...
    8b32d77a078 Fix defcustom type of 'dframe-update-speed'
    a56e964941f Speedbar: no more stale idle timers (bug#81561)
    
    # Conflicts:
    #       etc/NEWS
---
 doc/emacs/custom.texi              |  8 +++---
 doc/lispref/frames.texi            |  6 +++++
 doc/lispref/os.texi                | 12 +++++++++
 etc/EGLOT-NEWS                     |  9 +++++++
 lisp/dframe.el                     | 11 ++++++---
 lisp/env.el                        |  7 +++---
 lisp/progmodes/eglot.el            | 50 +++++++++++++++++++++-----------------
 lisp/progmodes/flymake.el          |  4 +--
 lisp/progmodes/sh-script.el        |  8 +++---
 lisp/speedbar.el                   |  3 ++-
 src/window.c                       | 24 ++++++++++++++++--
 test/lisp/progmodes/eglot-tests.el |  6 ++++-
 12 files changed, 105 insertions(+), 43 deletions(-)

diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index 77fff25b7b2..efa68ace299 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -194,11 +194,11 @@ the customization buffer:
 @end smallexample
 
 @findex Custom-goto-first-choice
-@kindex C-x C-i @r{(customization buffer)}
+@kindex C-c TAB @r{(customization buffer)}
   The first line shows that the variable is named @code{kill-ring-max},
 formatted as @samp{Kill Ring Max} for easier viewing, and also shows its
 expected type: a positive integer or zero.  The default value is
-@samp{120}.  You can move directly to the value with @kbd{C-x C-i}
+@samp{120}.  You can move directly to the value with @kbd{C-c @key{TAB}}
 (Custom-goto-first-choice).  The button labeled @samp{[Hide]}, if
 activated, hides the variable's value and state; this is useful to avoid
 cluttering up the customization buffer with very long values (for this
@@ -348,8 +348,8 @@ does not appear if Emacs was started with the @option{-q} or
 @option{-Q} option (@pxref{Initial Options}).
 
 @kindex C-c C-c @r{(customization buffer)}
-@kindex C-x C-c @r{(customization buffer)}
-@kindex C-x C-k @r{(customization buffer)}
+@kindex C-x C-s @r{(customization buffer)}
+@kindex C-c C-k @r{(customization buffer)}
 @findex Custom-set
 @findex Custom-save
 @findex Custom-reset-standard
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 2721652796b..95bfb520605 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -1665,6 +1665,12 @@ looking up X resources for the frame.
 If the frame name was specified explicitly when the frame was created,
 this parameter will be that name.  If the frame wasn't explicitly
 named, this parameter will be @code{nil}.
+
+@vindex environment@r{, a frame parameter}
+@item environment
+The list of strings, each one describing one environment variable.  This
+list is similar to the one in @code{process-environment} (@pxref{System
+Environment}), but it lists variables and values specific to the frame.
 @end table
 
 
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 04ca0241622..4032279993d 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1023,6 +1023,18 @@ in the environment, @code{getenv} returns @code{nil}.  It returns
 @samp{""} if @var{var} is set but null.  Within Emacs, a list of environment
 variables and their values is kept in the variable @code{process-environment}.
 
+Optional argument @var{frame}, if non-@code{nil}, specifies a frame, in
+which case the function searches @var{frame}'s parameter
+@code{environment} (@pxref{Basic Parameters}) for @var{var} instead of
+looking for it in @code{process-environment}.
+
+@cindex DISPLAY environment variable search
+The @samp{DISPLAY} environment variable is treated specially when
+@var{frame} is omitted or @code{nil}: if that variable is not found in
+@code{process-environment}, the function looks at the selected-frame's
+@code{display} parameter, and if that is @code{nil}, it also looks in
+@code{initial-environment}.
+
 @example
 @group
 (getenv "USER")
diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS
index ad6aae10436..8679dbcc701 100644
--- a/etc/EGLOT-NEWS
+++ b/etc/EGLOT-NEWS
@@ -18,6 +18,15 @@ to look up issue github#1234, go to
 https://github.com/joaotavora/eglot/issues/1234.
 
 
+* Changes to upcoming Eglot
+
+** Changes to 'eglot-server-programs'
+
+- new 'vala-language-server' for 'vala-mode'  (bug#81543)
+
+** Miscellaneous bugs fixed (bug#81593, bug#81538, bug#81514, bug#81425)
+
+
 * Changes in Eglot 1.24 (23/6/2026)
 
 ** New command 'M-x eglot-describe-connection'
diff --git a/lisp/dframe.el b/lisp/dframe.el
index 2332ef3056f..e2dc525ffc1 100644
--- a/lisp/dframe.el
+++ b/lisp/dframe.el
@@ -127,10 +127,13 @@ is not useful to the user.")
 
 (defcustom dframe-update-speed 1
   "Idle time in seconds needed before dframe will update itself.
-Updates occur to allow dframe to display directory information
-relevant to the buffer you are currently editing."
+Updates occur to allow dframe to display directory information relevant
+to the buffer you are currently editing.  The value will be passed
+to `run-with-idle-timer', and can be an integer or a float.
+However, `setopt' will not accept a list of the kind returned
+by `current-idle-time' as valid."
   :group 'dframe
-  :type 'integer)
+  :type 'number)
 
 (defcustom dframe-activity-change-focus-flag nil
   "Non-nil means the selected frame will change based on activity.
@@ -652,7 +655,7 @@ who requested the timer.  NULL-ON-ERROR is ignored."
        timeout
        ;; We have a timer, an off is requested, and no client
        ;; functions are left, shut er down.
-       (and dframe-timer (not timeout) dframe-client-functions))
+       (and dframe-timer (not timeout) (not dframe-client-functions)))
       ;; Only call the low level function if we are changing the state.
       (dframe-set-timer-internal timeout)))
 
diff --git a/lisp/env.el b/lisp/env.el
index a81554d0682..434e645c329 100644
--- a/lisp/env.el
+++ b/lisp/env.el
@@ -201,12 +201,13 @@ VARIABLE should be a string.  Value is nil if VARIABLE is undefined in
 the environment.  Otherwise, value is a string.
 
 If optional parameter FRAME is non-nil, then it should be a
-frame.  This function will look up VARIABLE in its `environment'
+frame.  This function will look up VARIABLE in FRAME's `environment'
 parameter.
 
 Otherwise, this function searches `process-environment' for
-VARIABLE.  If it is not found there, then it continues the search
-in the environment list of the selected frame."
+VARIABLE and returns its value if found.  If not found, and VARIABLE
+is \"DISPLAY\", the function uses the `display' parameter of the selected
+frame, and if that is also nil, it searches the `initial-environment' list."
   (declare (ftype (function (string &optional frame) (or null string)))
            (side-effect-free t))
   (interactive (list (read-envvar-name "Get environment variable: " t)))
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 18468208ffc..05efa48afdf 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -2478,21 +2478,24 @@ the previous reports for TOKEN.")
                  #'eglot--after-set-visited-file-name-hook t)
     (remove-hook 'before-save-hook #'eglot--signal-textDocument/willSave t)
     (remove-hook 'after-save-hook #'eglot--signal-textDocument/didSave t)
-    (remove-hook 'xref-backend-functions #'eglot-xref-backend t)
+    (unless (eglot--stay-out-of-p 'xref)
+      (remove-hook 'xref-backend-functions #'eglot-xref-backend t))
     (remove-hook 'completion-at-point-functions #'eglot-completion-at-point t)
     (remove-hook 'completion-in-region-mode-hook #'eglot--capf-session-flush t)
     (remove-hook 'company-after-completion-hook #'eglot--capf-session-flush t)
     (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)
-    (dolist (f (list #'eglot-hover-eldoc-function
-                     #'eglot-signature-eldoc-function
-                     #'eglot-highlight-eldoc-function
-                     #'eglot-code-action-suggestion))
-        (remove-hook 'eldoc-documentation-functions f t))
+    (unless (eglot--stay-out-of-p 'eldoc)
+      (dolist (f (list #'eglot-hover-eldoc-function
+                       #'eglot-signature-eldoc-function
+                       #'eglot-highlight-eldoc-function
+                       #'eglot-code-action-suggestion))
+        (remove-hook 'eldoc-documentation-functions f 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)
+    (unless (eglot--stay-out-of-p 'imenu)
+      (remove-function (local 'imenu-create-index-function) #'eglot-imenu))
     (eglot--flymake-reset)
     (setq eglot--flymake-report-fn nil)
     (run-hooks 'eglot-managed-mode-hook)
@@ -2962,19 +2965,22 @@ THINGS are either registrations or unregisterations (sic)."
     (cond
      ((eq external t) (browse-url uri))
      ((file-readable-p (setq filename (eglot-uri-to-path uri)))
-      ;; Use run-with-timer to avoid nested client requests like the
-      ;; "synchronous imenu" floated in bug#62116 presumably caused by
-      ;; which-func-mode.
-      (run-with-timer
-       0 nil
-       (lambda ()
-         (with-current-buffer (find-file-noselect filename)
-           (cond (takeFocus
-                  (pop-to-buffer (current-buffer))
-                  (select-frame-set-input-focus (selected-frame)))
-                 ((display-buffer (current-buffer))))
-           (when selection
-             (eglot--goto selection))))))
+      ;; Really ensure this runs when it is safe to run it.
+      ;; run-with-timer avoid nested client requests like the
+      ;; "synchronous imenu" floated in bug#62116, while the
+      ;; "post-command once" trick is for bug#81538.
+      (cl-labels ((findit ()
+                  (remove-hook 'post-command-hook #'findit)
+                  (with-current-buffer (find-file-noselect filename)
+                    (cond (takeFocus
+                           (pop-to-buffer (current-buffer))
+                           (select-frame-set-input-focus (selected-frame)))
+                          ((display-buffer (current-buffer))))
+                    (when selection
+                      (eglot--goto selection)))))
+                (if this-command
+                    (add-hook 'post-command-hook #'findit)
+                  (run-at-time 0 nil #'findit))))
      (t (setq success :json-false)))
     `(:success ,success)))
 
@@ -4961,8 +4967,8 @@ not watching some directories" eglot-max-file-watches)
                       (:*       "\\*"                   eglot--glob-emit-*)
                       (:?       "\\?"                   eglot--glob-emit-?)
                       (:{}      "{[^{}]+}"              eglot--glob-emit-{})
-                      (:range   "\\[\\^?[^][/,*{}]+\\]" eglot--glob-emit-range)
-                      (:literal "[^][,*?{}]+"           eglot--glob-emit-self))
+                      (:range   "\\[\\^?[^][/*{}]+\\]"  eglot--glob-emit-range)
+                      (:literal "[^][*?{}]+"            eglot--glob-emit-self))
      until (eobp)
      collect (cl-loop
               for (_token regexp emitter) in grammar
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 49fd1421359..8f8f2660725 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -4,7 +4,7 @@
 
 ;; Author: Pavel Kobyakov <[email protected]>
 ;; Maintainer: Spencer Baugh <[email protected]>
-;; Version: 1.4.5
+;; Version: 1.4.6
 ;; Keywords: c languages tools
 ;; Package-Requires: ((emacs "26.1") (eldoc "1.14.0") (project "0.11.1"))
 
@@ -1683,7 +1683,7 @@ default) no filter is applied."
                         (cl-sort retval (if (cl-plusp n) #'< #'>)
                                  :key #'overlay-start))))
          (tail ;; For compatibility with older Emacs.
-               (with-suppressed-warnings ((obsolete cl-member-if))
+               (with-no-warnings
                  (cl-member-if (lambda (ov)
                                  (if (cl-plusp n)
                                      (> (overlay-start ov)
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index dce24949b5f..f1ae855f6e1 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1626,11 +1626,11 @@ not written in Bash or sh."
                                  "process_substitution")
                          eos))
                    (sexp-default
-                    ;; For `C-M-f' in "$|(a)"
-                    ("$(" .
+                    ;; For `C-M-f' in "$|{a}" or "$|(a)"
+                    ("$[{(]" .
                      ,(lambda (node)
-                        (equal (treesit-node-type (treesit-node-parent node))
-                               "command_substitution"))))
+                        (member (treesit-node-type (treesit-node-parent node))
+                                '("expansion" "command_substitution")))))
                    (sentence
                     ,(rx bos (or "redirected_statement"
                                  "declaration_command"
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index e5fde873a08..6f8698fe997 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -1142,7 +1142,8 @@ supported at a time.
       (setq speedbar--window nil
 	    speedbar-frame nil
 	    dframe-attached-frame nil)
-      (speedbar-set-timer nil)
+      (with-current-buffer speedbar-buffer
+        (speedbar-set-timer nil))
       (kill-buffer speedbar-buffer)
       (setq speedbar-buffer nil)
       (when (and current-window (window-live-p current-window))
diff --git a/src/window.c b/src/window.c
index 785c71b3569..a41cde6258e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7598,7 +7598,8 @@ struct save_window_data
 
     /* All fields above are traced by the GC.
        After saved_windows, the fields are ignored by the GC.  */
-
+    /* The change stamp of the frame at the time of saving.  */
+    int change_stamp;
     /* We should be able to do without the following two.  */
     int frame_cols, frame_lines;
     /* These three should get eventually replaced by their pixel
@@ -7839,7 +7840,25 @@ the return value is nil.  Otherwise the value is t.  */)
 	  /* If we squirreled away the buffer, restore it now.  */
 	  if (BUFFERP (w->combination_limit))
 	    wset_buffer (w, w->combination_limit);
-	  wset_old_buffer (w, p->old_buffer);
+
+	  if (data->change_stamp == f->change_stamp)
+	    /* Restore W's old_buffer slot but only if the configuration
+	       was saved and restored in between two redisplay cycles,
+	       that is, if F's saved change stamp and its current change
+	       stamp are equal.  In that case we should run W's buffer
+	       change functions provided the saved old_buffer and the
+	       restored buffer differ.  If the saved old_buffer and the
+	       restored buffer are one and the same, the window
+	       excursion was only temporary and it would be distracting
+	       to run the buffer change functions for it.
+
+	       If the change stamps are not equal, run the buffer change
+	       functions provided W's current buffer (which was stored
+	       by delete_all_child_windows above in W's old_buffer slot)
+	       and the buffer that will be restored differ (Bug#81079
+	       and Bug#81589).  */
+	    w->old_buffer = p->old_buffer;
+
 	  w->pixel_left = XFIXNAT (p->pixel_left);
 	  w->pixel_top = XFIXNAT (p->pixel_top);
 	  w->pixel_width = XFIXNAT (p->pixel_width);
@@ -8409,6 +8428,7 @@ saved by this function.  */)
   data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
   data->root_window = FRAME_ROOT_WINDOW (f);
   data->focus_frame = FRAME_FOCUS_FRAME (f);
+  data->change_stamp = f->change_stamp;
   Lisp_Object tem = make_nil_vector (n_windows);
   data->saved_windows = tem;
   for (ptrdiff_t i = 0; i < n_windows; i++)
diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el
index ee99e421fe3..79132d7f3f5 100644
--- a/test/lisp/progmodes/eglot-tests.el
+++ b/test/lisp/progmodes/eglot-tests.el
@@ -1492,7 +1492,11 @@ GUESSED-MAJOR-MODES-SYM are bound to the useful return values of
   (should (eglot--glob-match "prefix/{**/*.js,**/foo.[0-9]}.suffix"
                              "prefix/a/b/c/d/foo.5.suffix"))
   (should (eglot--glob-match "prefix/{**/*.js,**/foo.[0-9]}.suffix"
-                             "prefix/a/b/c/d/foo.js.suffix")))
+                             "prefix/a/b/c/d/foo.js.suffix"))
+  ;; bug#81425
+  (should (eglot--glob-match "foo/**/notes,extra.py" "foo/bar/notes,extra.py"))
+  (should (eglot--glob-match "foo,bar.txt" "foo,bar.txt"))
+  (should (eglot--glob-match "example.[a,b]" "example.,")))
 
 (defvar tramp-histfile-override)
 (defun eglot--call-with-tramp-test (fn)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.