commit b5ea92a62b70b2cca07b3ba1d61eb6a844f1315b (HEAD, refs/remotes/origin/master) Author: Juri Linkov Date: Wed Oct 1 09:40:05 2025 +0300 * lisp/hl-line.el (global-hl-line-buffers): Skip internal buffers (bug#79547). diff --git a/lisp/hl-line.el b/lisp/hl-line.el index e9892026a9a..d0ffe2a6515 100644 --- a/lisp/hl-line.el +++ b/lisp/hl-line.el @@ -149,6 +149,7 @@ the command `global-hl-line-mode' to turn Global Hl-Line mode on." (defcustom global-hl-line-buffers '(not (or (lambda (b) (buffer-local-value 'cursor-face-highlight-mode b)) + (lambda (b) (string-match-p "\\` " (buffer-name b))) minibufferp)) "Whether the Global HL-Line mode should be enabled in a buffer. The predicate is passed as argument to `buffer-match-p', which see. commit 8453fd59d43a48d9be3a318f24b0e731cfe017b3 Author: Sean Whitton Date: Tue Sep 30 16:15:44 2025 +0100 vc-test--checkin-patch: Use atomic change groups * test/lisp/vc/vc-tests/vc-tests.el (vc-test--with-temp-change): New macro. (vc-test--checkin-patch): Use it. diff --git a/test/lisp/vc/vc-tests/vc-tests.el b/test/lisp/vc/vc-tests/vc-tests.el index 1625c3501db..e49b4edf122 100644 --- a/test/lisp/vc/vc-tests/vc-tests.el +++ b/test/lisp/vc/vc-tests/vc-tests.el @@ -786,6 +786,20 @@ This checks also `vc-backend' and `vc-responsible-backend'." (declare-function vc-hg-command "vc-hg") (declare-function vc-git--out-str "vc-git") +(defmacro vc-test--with-temp-change (buf &rest body) + (declare (indent 1) (debug (symbolp body))) + (cl-with-gensyms (handle) + `(let ((,handle (prepare-change-group ,buf))) + (unwind-protect + (with-current-buffer ,buf + (activate-change-group ,handle) + (insert "bar\n") + (basic-save-buffer) + ,@body) + (cancel-change-group ,handle) + (with-current-buffer ,buf + (basic-save-buffer)))))) + (defun vc-test--checkin-patch (backend) "Test preparing and checking in patches." (ert-with-temp-directory _tempdir @@ -813,11 +827,6 @@ This checks also `vc-backend' and `vc-responsible-backend'." (revert (msg) "Make a commit reverting the most recent change to FILE." (with-current-buffer buf - (undo-boundary) - (revert-buffer-quick) - (undo-boundary) - (undo) - (basic-save-buffer) (vc-checkin (list file) backend) (insert msg) (let (vc-async-checkin) @@ -856,9 +865,7 @@ This checks also `vc-backend' and `vc-responsible-backend'." (log-edit-done))) ;; (3) Prepare a commit with a known Author & Date. - (with-current-buffer buf - (insert "bar\n") - (basic-save-buffer) + (vc-test--with-temp-change buf (vc-root-diff nil) (vc-next-action nil) (insert desc1) @@ -873,7 +880,8 @@ This checks also `vc-backend' and `vc-responsible-backend'." ;; author, date and comment from PATCH-STRING. (let ((patch-string (get-patch-string))) (revert "Revert modification, first time") - (vc-call-backend backend 'checkin-patch patch-string nil)) + (vc-test--with-temp-change buf + (vc-call-backend backend 'checkin-patch patch-string nil))) (check author date desc1) ;; (5) Revert it again and try applying it with @@ -881,16 +889,9 @@ This checks also `vc-backend' and `vc-responsible-backend'." ;; Should take the author, date but not the comment from ;; PATCH-STRING. (let ((patch-string (get-patch-string))) - ;; FIXME: Why doesn't `revert' work properly here? - (if (and (eq backend 'Git) - (eq system-type 'windows-nt)) - (with-current-buffer buf - (vc-checkin (list file) backend) - (insert "Revert modification, second time") - (let (vc-async-checkin) - (log-edit-done))) - (revert "Revert modification, second time")) - (vc-call-backend backend 'checkin-patch patch-string desc2)) + (revert "Revert modification, second time") + (vc-test--with-temp-change buf + (vc-call-backend backend 'checkin-patch patch-string desc2))) (check author date desc2)) ;; Save exit. commit 6ef6b517aa990acec249d63a6ee5381723616cdd Author: Sean Whitton Date: Tue Sep 30 16:12:14 2025 +0100 VC: Allow deleting or moving current working tree * lisp/progmodes/project.el (project-prompter) (project-prompt-project-dir, project-prompt-project-name): * lisp/vc/vc.el (vc--prompt-other-working-tree): New ALLOW-EMPTY optional argument. (delete-working-tree, move-working-tree): Specify that callers must ensure DIRECTORY is not the current working tree. (vc-delete-working-tree, vc-move-working-tree): Pass ALLOW-EMPTY non-nil to vc--prompt-other-working-tree. Bind 'default-directory' to another working tree when operating on the current working tree. (vc-delete-working-tree): Extra prompt when asked to delete the current working tree. When deleting the current working tree, call 'bury-buffer' one or more times at the end. diff --git a/etc/NEWS b/etc/NEWS index e4024129dec..7f342bb7e48 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -525,10 +525,11 @@ It is equivalent to running 'project-any-command' with The prompt now displays the chosen project on which to invoke a command. --- -*** 'project-prompter' values may be called with up to three arguments. +*** 'project-prompter' values may be called with up to four arguments. These allow callers of the value of 'project-prompter' to specify a prompt string; prompt the user to choose between a subset of all the -known projects; and disallow returning arbitrary directories. +known projects; disallow returning arbitrary directories; and allow +returning an empty string. See the docstring of 'project-prompter' for a full specification of these new optional arguments. diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index cb018a870a6..e4e17e6a4c4 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -199,8 +199,8 @@ When it is non-nil, `project-current' will always skip prompting too.") (defcustom project-prompter #'project-prompt-project-dir "Function to call to prompt for a project. -The function is called either with no arguments or with up to three -optional arguments: (&optional PROMPT PREDICATE REQUIRE-KNOWN). +The function is called either with no arguments or with up to four +optional arguments: (&optional PROMPT PREDICATE REQUIRE-KNOWN ALLOW-EMPTY). PROMPT is the prompt string to use. @@ -216,14 +216,21 @@ If REQUIRE-KNOWN is non-nil, the value of `project-prompter' should only allow the user to select from known projects. Otherwise, the function may allow the user to input arbitrary directories. If PREDICATE and REQUIRE-KNOWN are both non-nil, the value of `project-prompter' should -not return any project root directory for which PREDICATE returns nil." +not return any project root directory for which PREDICATE returns nil. + +If ALLOW-EMPTY is non-nil, then irrespective of REQUIRE-KNOWN, the user +may enter nothing (i.e., just type RET). +In this case the function should return \"\". Conventionally this is +used to allow the user to select the current project. +Callers should append something like \" (empty for current project)\" to +PROMPT when passing ALLOW-EMPTY non-nil." :type '(choice (const :tag "Prompt for a project directory" project-prompt-project-dir) (const :tag "Prompt for a project name" project-prompt-project-name) (function :tag "Custom function" nil)) :group 'project - :version "30.1") + :version "31.1") ;;;###autoload (defun project-current (&optional maybe-prompt directory) @@ -2174,7 +2181,8 @@ the project list." (defvar project--dir-history) -(defun project-prompt-project-dir (&optional prompt predicate require-known) +(defun project-prompt-project-dir + (&optional prompt predicate require-known allow-empty) "Prompt the user for a directory that is one of the known project roots. The project is chosen among projects known from the project list, see `project-list-file'. @@ -2182,7 +2190,8 @@ If PROMPT is non-nil, use it as the prompt string. If PREDICATE is non-nil, filter possible project choices using this function; see `project-prompter' for more details. Unless REQUIRE-KNOWN is non-nil, it's also possible to enter an -arbitrary directory not in the list of known projects." +arbitrary directory not in the list of known projects. +If ALLOW-EMPTY is non-nil, it is possible to exit with no input." (project--ensure-read-project-list) (if-let* ((pred (alist-get 'prompt project-prune-zombie-projects)) (inhibit-message t)) @@ -2195,10 +2204,9 @@ arbitrary directory not in the list of known projects." (if require-known project--list (append project--list `(,dir-choice))))) (project--dir-history (project-known-project-roots)) - (pr-dir "")) - (while (equal pr-dir "") - ;; If the user simply pressed RET, do this again until they don't. - (setq pr-dir + pr-dir) + (cl-loop + do (setq pr-dir (let (history-add-new-input) (completing-read (if prompt ;; TODO: Use `format-prompt' (Emacs 28.1+) @@ -2209,14 +2217,17 @@ arbitrary directory not in the list of known projects." (lambda (choice) (or (equal choice dir-choice) (funcall predicate choice)))) - t nil 'project--dir-history)))) + t nil 'project--dir-history))) + ;; If the user simply pressed RET, do this again until they don't. + while (and (not allow-empty) (equal pr-dir ""))) (if (equal pr-dir dir-choice) (read-directory-name "Select directory: " default-directory nil t) pr-dir))) (defvar project--name-history) -(defun project-prompt-project-name (&optional prompt predicate require-known) +(defun project-prompt-project-name + (&optional prompt predicate require-known allow-empty) "Prompt the user for a project, by name, that is one of the known project roots. The project is chosen among projects known from the project list, see `project-list-file'. @@ -2224,7 +2235,8 @@ If PROMPT is non-nil, use it as the prompt string. If PREDICATE is non-nil, filter possible project choices using this function; see `project-prompter' for more details. Unless REQUIRE-KNOWN is non-nil, it's also possible to enter an -arbitrary directory not in the list of known projects." +arbitrary directory not in the list of known projects. +If ALLOW-EMPTY is non-nil, it is possible to exit with no input." (if-let* ((pred (alist-get 'prompt project-prune-zombie-projects)) (inhibit-message t)) (project--delete-zombie-projects pred)) @@ -2248,19 +2260,22 @@ arbitrary directory not in the list of known projects." (table (project--file-completion-table (reverse (if require-known choices (cons dir-choice choices))))) - (pr-name "")) - (while (equal pr-name "") - ;; If the user simply pressed RET, do this again until they don't. - (setq pr-name - (let (history-add-new-input) - (completing-read (if prompt - (format "%s: " prompt) - "Select project: ") - table nil t nil 'project--name-history)))) - (if (equal pr-name dir-choice) - (read-directory-name "Select directory: " default-directory nil t) - (let ((proj (assoc pr-name choices))) - (if (stringp proj) proj (project-root (cdr proj))))))) + pr-name) + (cl-loop + do (setq pr-name + (let (history-add-new-input) + (completing-read (if prompt + (format "%s: " prompt) + "Select project: ") + table nil t nil 'project--name-history))) + ;; If the user simply pressed RET, do this again until they don't. + while (and (not allow-empty) (equal pr-name ""))) + (pcase pr-name + ("" "") + (dir-choice (read-directory-name "Select directory: " + default-directory nil t)) + (_ (let ((proj (assoc pr-name choices))) + (if (stringp proj) proj (project-root (cdr proj)))))))) ;;;###autoload (defun project-known-project-roots () diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 006d2098c2f..821be767f81 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -378,6 +378,7 @@ ;; ;; Remove the working tree, assumed to be one that uses the same ;; backing repository as this working tree, at DIRECTORY. +;; Callers must ensure that DIRECTORY is not the current working tree. ;; This removal should be unconditional with respect to the state of ;; the working tree: the caller is responsible for checking for ;; uncommitted work in DIRECTORY. @@ -386,6 +387,7 @@ ;; ;; Relocate the working tree, assumed to be one that uses the same ;; backing repository as this working tree, at FROM to TO. +;; Callers must ensure that FROM is not the current working tree. ;; HISTORY FUNCTIONS ;; @@ -4576,19 +4578,27 @@ When called from Lisp, BACKEND is the VC backend." (defvar project-prompter) -(defun vc--prompt-other-working-tree (backend prompt) +(defun vc--prompt-other-working-tree (backend prompt &optional allow-empty) "Invoke `project-prompter' to choose another working tree. BACKEND is the VC backend. -PROMPT is the prompt string for `project-prompter'." +PROMPT is the prompt string for `project-prompter'. +If ALLOW-EMPTY is non-nil, empty input means the current working tree." (if-let* ((trees (vc-call-backend backend 'known-other-working-trees))) - (progn (require 'project) - (dolist (tree trees) - (when-let* ((p (project-current nil tree))) - (project-remember-project p nil t))) - (funcall project-prompter prompt - (lambda (k &optional _v) - (member (or (car-safe k) k) trees)) - t)) + (let (res) + (require 'project) + (dolist (tree trees) + (when-let* ((p (project-current nil tree))) + (project-remember-project p nil t))) + (setq res + (funcall project-prompter + (if allow-empty + (format "%s (empty for this working tree)" + prompt) + prompt) + (lambda (k &optional _v) + (member (or (car-safe k) k) trees)) + t allow-empty)) + (if (string-empty-p res) (vc-root-dir) res)) (user-error (substitute-command-keys "No other working trees. Use \\[vc-add-working-tree] to add one")))) @@ -4633,20 +4643,40 @@ BACKEND is the VC backend." (interactive (let ((backend (vc-responsible-backend default-directory))) (list backend - (vc--prompt-other-working-tree backend "Delete working tree")))) - ;; We could consider not prompting here, thus always failing when - ;; there is uncommitted work, and requiring the user to review and - ;; revert the uncommitted changes before invoking this command again. - ;; But other working trees are often created as throwaways to quickly - ;; test some changes, so it is more useful to offer to recursively - ;; delete them on the user's behalf. - (when (and (vc-dir-status-files directory nil backend) - (not (yes-or-no-p (format "\ + (vc--prompt-other-working-tree backend "Delete working tree" + 'allow-empty)))) + (let* ((delete-this (file-in-directory-p default-directory directory)) + (directory (expand-file-name directory)) + (default-directory + (if delete-this + (or (car (vc-call-backend backend + 'known-other-working-trees)) + (user-error "No other working trees")) + default-directory)) + (status (vc-dir-status-files directory nil backend))) + + ;; We could consider not prompting here, thus always failing when + ;; there is uncommitted work, and requiring the user to review and + ;; revert the uncommitted changes before invoking this command again. + ;; But other working trees are often created as throwaways to quickly + ;; test some changes, so it is more useful to offer to recursively + ;; delete them on the user's behalf. + (when (and status + (not (yes-or-no-p (format "\ %s contains uncommitted work. Continue to recursively delete it?" directory)))) - (user-error "Aborted due to uncommitted work in %s" directory)) - - (project-forget-project directory) - (vc-call-backend backend 'delete-working-tree directory)) + (user-error "Aborted due to uncommitted work in %s" directory)) + ;; Extra prompt to avoid a surprise after accidentally typing 'RET'. + (when (and (not status) delete-this + (not (yes-or-no-p (format "Really delete working tree %s?" + directory)))) + (user-error "Aborted")) + + (project-forget-project directory) + (vc-call-backend backend 'delete-working-tree directory) + (when delete-this + (bury-buffer) + (while (string-prefix-p directory default-directory) + (bury-buffer))))) (autoload 'dired-rename-subdir "dired-aux") ;;;###autoload @@ -4659,12 +4689,20 @@ BACKEND is the VC backend." (interactive (let ((backend (vc-responsible-backend default-directory))) (list backend - (vc--prompt-other-working-tree backend "Relocate working tree") + (vc--prompt-other-working-tree backend "Relocate working tree" + 'allow-empty) (read-directory-name "New location for working tree: " (file-name-parent-directory (vc-root-dir)))))) - (let ((inhibit-message t)) - (project-forget-project from)) - (vc-call-backend backend 'move-working-tree from to) + (let* ((move-this (file-in-directory-p default-directory from)) + (default-directory + (if move-this + (or (car (vc-call-backend backend + 'known-other-working-trees)) + (user-error "No other working trees")) + default-directory))) + (let ((inhibit-message t)) + (project-forget-project from)) + (vc-call-backend backend 'move-working-tree from to)) ;; Update visited file names for buffers visiting files under FROM. (let ((from (expand-file-name from))) commit ca704a67dc7d0601d15fe96b76c9e59f4f87b7fb Author: Stephen Berman Date: Tue Sep 30 11:05:22 2025 +0200 Fix debug specs in minibuffer-tests.el macros (bug#79499) * test/lisp/minibuffer-tests.el (with-minibuffer-setup) (completing-read-with-minibuffer-setup): Prevent instrumenting functions that call these macros from erroring due to an invalid debug specification in the 'declare' form. Use 't' as the debug spec since it is the most general and adequate here. diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el index 27e9bbbefb4..03e8ea24018 100644 --- a/test/lisp/minibuffer-tests.el +++ b/test/lisp/minibuffer-tests.el @@ -449,7 +449,7 @@ (defmacro with-minibuffer-setup (completing-read &rest body) - (declare (indent 1) (debug (collection body))) + (declare (indent 1) (debug t)) `(catch 'result (minibuffer-with-setup-hook (lambda () @@ -460,7 +460,7 @@ ,completing-read)))) (defmacro completing-read-with-minibuffer-setup (collection &rest body) - (declare (indent 1) (debug (collection body))) + (declare (indent 1) (debug t)) `(catch 'result (minibuffer-with-setup-hook (lambda () commit 40a22ced14708cc3bab8ebc971c5b6e51fc6544e Author: Juri Linkov Date: Mon Sep 29 20:47:50 2025 +0300 New value 'window' of 'global-hl-line-sticky-flag' * etc/NEWS: Rename 'global-hl-line-modes' to 'global-hl-line-buffers' (bug#79481). Mention new default value of 'global-hl-line-buffers' (bug#64993). Mention new value 'window' of 'global-hl-line-sticky-flag' that is more useful than the value 'all' now removed from NEWS (bug#64993). * lisp/hl-line.el (hl-line-nonselected): New face. (global-hl-line-sticky-flag): Add the value 'window'. (global-hl-line-buffers): Change the default value to exclude the minibuffer and 'cursor-face-highlight-mode'. (global-hl-line-mode): Handle the value 'window' of 'global-hl-line-sticky-flag'. (global-hl-line-window-redisplay): New function. diff --git a/etc/NEWS b/etc/NEWS index 320f7e40fb7..e4024129dec 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2633,16 +2633,18 @@ activate it. When t (the default), the click will both activate the frame and be interpreted as a command. --- -*** New user option 'global-hl-line-modes'. -This specifies in which major modes should the 'global-hl-line-mode' be -switched on. The default is t, which means enable it in all major -modes. - ---- -*** New value 'all' for the user option 'global-hl-line-sticky-flag'. -It updates the line highlighting in all windows and buffers, -unlike the value t that updates only windows that display -the current buffer. +*** New user option 'global-hl-line-buffers'. +This specifies in which buffers should the 'global-hl-line-mode' be +switched on. The default is all buffers except the minibuffer +and the buffers like the completions buffer that enable +'cursor-face-highlight-mode'. + +--- +*** New value 'window' for the user option 'global-hl-line-sticky-flag'. +Unlike the value t that highlights the line with buffer's point, +it highlights the line with window's point. Also it uses the new face +`hl-line-nonselected' for highlighting the line with window's point +in non-selected windows. --- *** New user option 'display-fill-column-indicator-warning'. diff --git a/lisp/hl-line.el b/lisp/hl-line.el index 541f3dc140a..e9892026a9a 100644 --- a/lisp/hl-line.el +++ b/lisp/hl-line.el @@ -79,6 +79,12 @@ when `global-hl-line-sticky-flag' is non-nil.") :version "22.1" :group 'hl-line) +(defface hl-line-nonselected + '((t :inherit hl-line :extend t)) + "Face for highlighting the line with non-selected window's point. +Used only when the value of `global-hl-line-sticky-flag' is `window'." + :version "31.1") + (defcustom hl-line-face 'hl-line "Face with which to highlight the current line in Hl-Line mode." :type 'face @@ -127,17 +133,27 @@ This means that even when point moves in a non-selected window that displays another buffer, the new position will be updated to highlight the current line of other buffers. +If the value is `window', then instead of highlighting the line +with buffer's point, the Global HL-Line mode highlights the line +with window's point that might differ from the buffer's point +when the buffer is displayed in multiple windows. + Setting this variable takes effect the next time you use the command `global-hl-line-mode' to turn Global Hl-Line mode on." :type '(choice (const :tag "Disable" nil) (const :tag "Enable for buffer in multiple windows" t) - (const :tag "Enable and update in all windows" all)) + (const :tag "Enable and update in all windows" all) + (const :tag "Highlight window-point lines" window)) :version "24.1" :group 'hl-line) -(defcustom global-hl-line-buffers '(not (derived-mode . completion-list-mode)) +(defcustom global-hl-line-buffers + '(not (or (lambda (b) (buffer-local-value 'cursor-face-highlight-mode b)) + minibufferp)) "Whether the Global HL-Line mode should be enabled in a buffer. -The predicate is passed as argument to `buffer-match-p', which see." +The predicate is passed as argument to `buffer-match-p', which see. +By default, this mode is disabled in the minibuffer and in buffers +like the completions buffer that enable `cursor-face-highlight-mode'." :type '(buffer-predicate :tag "Predicate for `buffer-match-p'") :version "31.1") @@ -159,6 +175,7 @@ This variable is expected to be made buffer-local by modes.") :version "28.1" :group 'hl-line) + ;;;###autoload (define-minor-mode hl-line-mode "Toggle highlighting of the current line (Hl-Line mode). @@ -231,6 +248,7 @@ such overlays in all buffers except the current one." (eq (overlay-buffer hl-line-overlay) curbuf)) (setq hl-line-overlay-buffer curbuf)))) + ;;;###autoload (define-minor-mode global-hl-line-mode "Toggle line highlighting in all buffers (Global Hl-Line mode). @@ -239,22 +257,43 @@ If `global-hl-line-sticky-flag' is non-nil, Global Hl-Line mode highlights the line about the current buffer's point in all live windows. +If `global-hl-line-sticky-flag' is customized to `window', +then instead of highlighting the line with buffer's point, +this mode highlights the line with window's point that might differ from +the buffer's point when the buffer is displayed in multiple windows. +In this case this mode uses the function +`global-hl-line-window-redisplay' on `pre-redisplay-functions'. + Global-Hl-Line mode uses the function `global-hl-line-highlight' on `post-command-hook'." :global t :group 'hl-line (if global-hl-line-mode - (progn + (cond + ((eq global-hl-line-sticky-flag 'window) + (add-hook 'pre-redisplay-functions + #'global-hl-line-window-redisplay)) + (t ;; In case `kill-all-local-variables' is called. (add-hook 'change-major-mode-hook #'global-hl-line-unhighlight) (global-hl-line-highlight-all) (add-hook 'post-command-hook (if (eq global-hl-line-sticky-flag 'all) #'global-hl-line-highlight-all - #'global-hl-line-highlight))) - (global-hl-line-unhighlight-all) - (remove-hook 'post-command-hook #'global-hl-line-highlight) - (remove-hook 'post-command-hook #'global-hl-line-highlight-all) - (remove-hook 'change-major-mode-hook #'global-hl-line-unhighlight))) + #'global-hl-line-highlight)))) + (cond + ((eq global-hl-line-sticky-flag 'window) + (remove-hook 'pre-redisplay-functions + #'global-hl-line-window-redisplay) + (walk-windows (lambda (window) + (redisplay--unhighlight-overlay-function + (window-parameter window 'hl-line-overlay)) + (set-window-parameter window 'hl-line-overlay nil)) + t t)) + (t + (global-hl-line-unhighlight-all) + (remove-hook 'post-command-hook #'global-hl-line-highlight) + (remove-hook 'post-command-hook #'global-hl-line-highlight-all) + (remove-hook 'change-major-mode-hook #'global-hl-line-unhighlight))))) (defun global-hl-line-highlight () "Highlight the current line in the current window." @@ -310,6 +349,27 @@ all such overlays in all buffers except the current one." global-hl-line-overlays) (setq global-hl-line-overlays nil)) + +(defun global-hl-line-window-redisplay (window) + "Highlight the overlay that indicates the line with window's point." + (let ((rol (window-parameter window 'hl-line-overlay))) + (with-current-buffer (window-buffer window) + (if (buffer-match-p global-hl-line-buffers (current-buffer)) + (let* ((bounds (save-excursion + (goto-char (window-point window)) + (if hl-line-range-function + (funcall hl-line-range-function) + (cons (line-beginning-position) + (line-beginning-position 2))))) + (new (redisplay--highlight-overlay-function + (car bounds) (cdr bounds) window rol + (if (eq window (selected-window)) + 'hl-line 'hl-line-nonselected)))) + (unless (equal new rol) + (set-window-parameter window 'hl-line-overlay new))) + (redisplay--unhighlight-overlay-function rol))))) + + (defun hl-line-move (overlay) "Move the Hl-Line overlay. If `hl-line-range-function' is non-nil, move the OVERLAY to the position commit aaf8b301e7cf404906f0d1c5d604cffa2755418c Author: Juri Linkov Date: Mon Sep 29 20:13:05 2025 +0300 Fix completions truncated on scrolling (bug#79506) * lisp/simple.el (completion-setup-function): Add 'completion--lazy-insert-strings-on-scroll' to buffer-local hook 'window-scroll-functions'. * lisp/minibuffer.el (completion--lazy-insert-strings-on-scroll): New function. (completion--in-region-1): Remove calls to the function 'completion--lazy-insert-strings' that now are handled by the scroll hook. diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index b1434868380..9e87af82a24 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -1730,7 +1730,6 @@ scroll the window of possible completions." ((eq completion-auto-select 'second-tab)) ;; Reverse tab ((equal (this-command-keys) [backtab]) - (completion--lazy-insert-strings) (if (pos-visible-in-window-p (point-min) window) ;; If beginning is in view, scroll up to the end. (set-window-point window (point-max)) @@ -1738,7 +1737,6 @@ scroll the window of possible completions." (with-selected-window window (scroll-down)))) ;; Normal tab (t - (completion--lazy-insert-strings) (if (pos-visible-in-window-p (point-max) window) ;; If end is in view, scroll up to the end. (set-window-start window (point-min) nil) @@ -2328,6 +2326,21 @@ Runs of equal candidate strings are eliminated. GROUP-FUN is a (button-put completions--lazy-insert-button 'completions-continuation completions-continuation)))))) +(defun completion--lazy-insert-strings-on-scroll (window _start) + (with-current-buffer (window-buffer window) + (let ((track-eob (eobp))) + (completion--lazy-insert-strings) + ;; Keep point at the end of the updated buffer. + (when track-eob + (with-selected-window window + (goto-char (point-max)) + (previous-completion 1) + (recenter -1) + (when cursor-face-highlight-mode + (redisplay--update-cursor-face-highlight window)))))) + (remove-hook 'window-scroll-functions + 'completion--lazy-insert-strings-on-scroll t)) + (defun completion--lazy-insert-strings (&optional button) (setq button (or button completions--lazy-insert-button)) (when button diff --git a/lisp/simple.el b/lisp/simple.el index fe5eb4da60a..fb60ba5ca16 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10702,6 +10702,8 @@ Called from `temp-buffer-show-hook'." (if base-dir (setq default-directory base-dir)) (when completion-tab-width (setq tab-width completion-tab-width)) + (add-hook 'window-scroll-functions + 'completion--lazy-insert-strings-on-scroll nil t) ;; Maybe enable cursor completions-highlight. (when completions-highlight-face (cursor-face-highlight-mode 1)) commit dc5ae70cb44354de17d0994aee4b36ecc05456ff Author: Robert Pluim Date: Wed Sep 24 10:55:13 2025 +0200 Fix macOS build with SDK version 26 * configure.ac: Use gl_CHECK_FUNCS_ANDROID_MACOS to check for 'posix_spawn_file_actions_addchdir', since it checks which version of macOS is being used for the build, rather than what is available in the SDK. (Bug#79489) diff --git a/configure.ac b/configure.ac index a6a603d8f35..6bec1adf63f 100644 --- a/configure.ac +++ b/configure.ac @@ -6352,7 +6352,7 @@ dnl recent, so we check for it specifically. AC_CHECK_HEADERS([spawn.h]) AC_SUBST([HAVE_SPAWN_H]) gl_CHECK_FUNCS_ANDROID([posix_spawn], [#include ]) -gl_CHECK_FUNCS_ANDROID([posix_spawn_file_actions_addchdir], [#include ]) +gl_CHECK_FUNCS_ANDROID_MACOS([posix_spawn_file_actions_addchdir], [#include ]) gl_CHECK_FUNCS_ANDROID([posix_spawn_file_actions_addchdir_np], [#include ]) gl_CHECK_FUNCS_ANDROID([posix_spawnattr_setflags], [#include ]) AC_SUBST([HAVE_POSIX_SPAWN]) commit 98b2516f6e868dcda33076ab6e7b7b270c468d00 Author: Eli Zaretskii Date: Mon Sep 29 15:13:49 2025 +0300 Fix 'mm-copy-to-buffer' when original text is multibyte * lisp/gnus/mm-decode.el (mm-copy-to-buffer): Always return a unibyte buffer. If the original text was multibyte, encode it while inserting it into the copy buffer. (Bug#79376) diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el index 759d19a047e..bfa7a048f7e 100644 --- a/lisp/gnus/mm-decode.el +++ b/lisp/gnus/mm-decode.el @@ -792,19 +792,24 @@ MIME-Version header before proceeding." (mm-possibly-verify-or-decrypt (nreverse parts) ctl from))) (defun mm-copy-to-buffer () - "Copy the contents of the current buffer to a fresh buffer." + "Copy the contents of the current buffer to a fresh unibyte buffer." (let ((obuf (current-buffer)) (mb enable-multibyte-characters) + (nbuf (generate-new-buffer " *mm*")) beg) (goto-char (point-min)) (search-forward-regexp "^\n" nil 'move) ;; There might be no body. (setq beg (point)) - (with-current-buffer - (generate-new-buffer " *mm*") - ;; Preserve the data's unibyteness (for url-insert-file-contents). - (set-buffer-multibyte mb) - (insert-buffer-substring obuf beg) - (current-buffer)))) + (with-current-buffer nbuf + (set-buffer-multibyte nil)) + (if (null mb) + (with-current-buffer nbuf + (insert-buffer-substring obuf beg) + (current-buffer)) + (encode-coding-region beg (point-max) 'utf-8-emacs-unix nbuf) + (with-current-buffer nbuf + (goto-char (point-max)) + (current-buffer))))) (defun mm-display-parts (handle) (cond commit 6992d0e3bb79ac353f3d2335dba29431ccd64dc3 Author: Robert Pluim Date: Mon Sep 29 11:22:32 2025 +0200 ; Fix typos * lisp/mail/mail-utils.el (mail-fetch-field, mail-mbox-from): 'headers', not 'header'. diff --git a/lisp/mail/mail-utils.el b/lisp/mail/mail-utils.el index d51e2747ba3..28cc250f6cb 100644 --- a/lisp/mail/mail-utils.el +++ b/lisp/mail/mail-utils.el @@ -319,7 +319,7 @@ If third arg ALL is non-nil, concatenate all such fields with commas between. If 4th arg LIST is non-nil, return a list of all such fields. If 5th arg DELETE is non-nil, delete all header lines that are included in the result. -The buffer should be narrowed to just the header, else false +The buffer should be narrowed to just the headers, else false matches may be returned from the message body." (save-excursion (goto-char (point-min)) @@ -404,7 +404,7 @@ matches may be returned from the message body." (defun mail-mbox-from () "Return an mbox \"From \" line for the current message. -The buffer should be narrowed to just the header." +The buffer should be narrowed to just the headers." (let* ((from (mail-strip-quoted-names (or (mail-fetch-field "from") (mail-fetch-field "really-from") (mail-fetch-field "sender")