diff --git a/lisp/simple.el b/lisp/simple.el index efe5406..272905e 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -122,11 +122,13 @@ next-error-last-buffer similar mode is started, or when it is used with \\[next-error] or \\[compile-goto-error].") -;; next-error-last-buffer is made buffer-local to keep the reference +(defvar next-error-buffer nil + "The buffer-local value of the most recent `next-error' buffer.") +;; next-error-buffer is made buffer-local to keep the reference ;; to the parent buffer used to navigate to the current buffer, so the ;; next call of next-buffer will use the same parent buffer to ;; continue navigation from it. -(make-variable-buffer-local 'next-error-last-buffer) +(make-variable-buffer-local 'next-error-buffer) (defvar next-error-function nil "Function to use to find the next error in the current buffer. @@ -184,6 +186,15 @@ next-error-find-buffer-function :group 'next-error :version "27.1") +(defcustom next-error-found-function #'ignore + "Function called when a next locus is found and displayed. +Function is called with two arguments: a FROM-BUFFER buffer +from which next-error navigated, and a target buffer TO-BUFFER." + :type '(choice (const :tag "No default" ignore) + (function :tag "Other function")) + :group 'next-error + :version "27.1") + (defun next-error-buffer-on-selected-frame (&optional avoid-current extra-test-inclusive extra-test-exclusive) @@ -220,6 +231,14 @@ next-error-find-buffer (funcall next-error-find-buffer-function avoid-current extra-test-inclusive extra-test-exclusive) + ;; 1a. If next-error-buffer has no buffer-local value + ;; (i.e. never navigated to the current buffer from another), + ;; and the current buffer is a `next-error' capable buffer, + ;; use it unconditionally, so next-error will always use it. + (if (and (not (local-variable-p 'next-error-buffer)) + (next-error-buffer-p (current-buffer) avoid-current + extra-test-inclusive extra-test-exclusive)) + (current-buffer)) ;; 2. If next-error-last-buffer is an acceptable buffer, use that. (if (and next-error-last-buffer (next-error-buffer-p next-error-last-buffer avoid-current @@ -284,37 +303,35 @@ next-error (when buffer ;; We know here that next-error-function is a valid symbol we can funcall (with-current-buffer buffer - ;; Allow next-error to be used from the next-error capable buffer. - (setq next-error-last-buffer buffer) (funcall next-error-function (prefix-numeric-value arg) reset) - ;; Override possible change of next-error-last-buffer in next-error-function - (setq next-error-last-buffer buffer) - (setq-default next-error-last-buffer buffer) - (when next-error-recenter - (recenter next-error-recenter)) - (message "%s error from %s" + (next-error-found buffer (current-buffer)) + (message "%s locus from %s" (cond (reset "First") ((eq (prefix-numeric-value arg) 0) "Current") ((< (prefix-numeric-value arg) 0) "Previous") (t "Next")) - next-error-last-buffer) - (run-hooks 'next-error-hook))))) + next-error-last-buffer))))) (defun next-error-internal () "Visit the source code corresponding to the `next-error' message at point." (let ((buffer (current-buffer))) ;; We know here that next-error-function is a valid symbol we can funcall - (with-current-buffer buffer - ;; Allow next-error to be used from the next-error capable buffer. - (setq next-error-last-buffer buffer) - (funcall next-error-function 0 nil) - ;; Override possible change of next-error-last-buffer in next-error-function - (setq next-error-last-buffer buffer) - (setq-default next-error-last-buffer buffer) - (when next-error-recenter - (recenter next-error-recenter)) - (message "Current error from %s" next-error-last-buffer) - (run-hooks 'next-error-hook)))) + (funcall next-error-function 0 nil) + (next-error-found buffer (current-buffer)) + (message "Current locus from %s" next-error-last-buffer))) + +(defun next-error-found (&optional from-buffer to-buffer) + "Function to call when the next locus is found and displayed. +FROM-BUFFER is a buffer from which next-error navigated, +and TO-BUFFER is a target buffer." + (setq next-error-last-buffer (or from-buffer (current-buffer))) + (when to-buffer + (with-current-buffer to-buffer + (setq next-error-buffer from-buffer))) + (when next-error-recenter + (recenter next-error-recenter)) + (funcall next-error-found-function from-buffer to-buffer) + (run-hooks 'next-error-hook)) (defun next-error-select-buffer (buffer) "Select a `next-error' capable buffer and set it as the last used." @@ -322,8 +339,7 @@ next-error-select-buffer (list (get-buffer (read-buffer "Select next-error buffer: " nil nil (lambda (b) (next-error-buffer-p (cdr b))))))) - (setq next-error-last-buffer buffer) - (setq-default next-error-last-buffer buffer)) + (setq next-error-last-buffer buffer)) (defalias 'goto-next-locus 'next-error) (defalias 'next-match 'next-error) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 5a9a7a9..9a437b6 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -540,9 +540,11 @@ xref-goto-xref Non-interactively, non-nil QUIT means to first quit the *xref* buffer." (interactive) - (let ((xref (or (xref--item-at-point) + (let ((buffer (current-buffer)) + (xref (or (xref--item-at-point) (user-error "No reference at point")))) - (xref--show-location (xref-item-location xref) (if quit 'quit t)))) + (xref--show-location (xref-item-location xref) (if quit 'quit t)) + (next-error-found buffer (current-buffer)))) (defun xref-quit-and-goto-xref () "Quit *xref* buffer, then jump to xref on current line." diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el index 175c82f..d423706 100644 --- a/lisp/vc/add-log.el +++ b/lisp/vc/add-log.el @@ -471,6 +471,11 @@ change-log-goto-source comma-separated list. If no suitable tag can be found nearby, try to visit the file for the change under `point' instead." (interactive) + (let ((buffer (current-buffer))) + (change-log-goto-source-internal) + (next-error-found buffer (current-buffer)))) + +(defun change-log-goto-source-internal () (if (and (eq last-command 'change-log-goto-source) change-log-find-tail) (setq change-log-find-tail @@ -539,7 +545,7 @@ change-log-next-error ;; if we found a place to visit... (when (looking-at change-log-file-names-re) (let (change-log-find-window) - (change-log-goto-source) + (change-log-goto-source-internal) (when change-log-find-window ;; Select window displaying source file. (select-window change-log-find-window))))) @@ -1067,8 +1073,7 @@ change-log-mode (set (make-local-variable 'end-of-defun-function) 'change-log-end-of-defun) ;; next-error function glue - (setq next-error-function 'change-log-next-error) - (setq next-error-last-buffer (current-buffer))) + (setq next-error-function 'change-log-next-error)) (defun change-log-next-buffer (&optional buffer wrap) "Return the next buffer in the series of ChangeLog file buffers. diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index ef13f55..1e2fbb9 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1874,11 +1874,13 @@ diff-goto-source ;; the old location, and else to the new (i.e. as if reverting). ;; This is a convenient detail when using smerge-diff. (if event (posn-set-point (event-end event))) - (let ((rev (not (save-excursion (beginning-of-line) (looking-at "[-<]"))))) + (let ((buffer (when event (current-buffer))) + (rev (not (save-excursion (beginning-of-line) (looking-at "[-<]"))))) (pcase-let ((`(,buf ,line-offset ,pos ,src ,_dst ,switched) (diff-find-source-location other-file rev))) (pop-to-buffer buf) (goto-char (+ (car pos) (cdr src))) + (when buffer (next-error-found buffer (current-buffer))) (diff-hunk-status-msg line-offset (diff-xor rev switched) t)))) diff --git a/lisp/replace.el b/lisp/replace.el index 4916cb1..5835c9c 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1192,7 +1194,8 @@ 'occur-mode-mouse-goto (defun occur-mode-goto-occurrence (&optional event) "Go to the occurrence on the current line." (interactive (list last-nonmenu-event)) - (let ((pos + (let ((buffer (when event (current-buffer))) + (pos (if (null event) ;; Actually `event-end' works correctly with a nil argument as ;; well, so we could dispense with this test, but let's not @@ -1204,26 +1207,31 @@ occur-mode-goto-occurrence (occur-mode-find-occurrence)))))) (pop-to-buffer (marker-buffer pos)) (goto-char pos) + (when buffer (next-error-found buffer (current-buffer))) (run-hooks 'occur-mode-find-occurrence-hook))) (defun occur-mode-goto-occurrence-other-window () "Go to the occurrence the current line describes, in another window." (interactive) - (let ((pos (occur-mode-find-occurrence))) + (let ((buffer (current-buffer)) + (pos (occur-mode-find-occurrence))) (switch-to-buffer-other-window (marker-buffer pos)) (goto-char pos) + (next-error-found buffer (current-buffer)) (run-hooks 'occur-mode-find-occurrence-hook))) (defun occur-mode-display-occurrence () "Display in another window the occurrence the current line describes." (interactive) - (let ((pos (occur-mode-find-occurrence)) + (let ((buffer (current-buffer)) + (pos (occur-mode-find-occurrence)) window) (setq window (display-buffer (marker-buffer pos) t)) ;; This is the way to set point in the proper window. (save-selected-window (select-window window) (goto-char pos) + (next-error-found buffer (current-buffer)) (run-hooks 'occur-mode-find-occurrence-hook)))) (defun occur-find-match (n search message) @@ -1254,28 +1262,20 @@ occur-next-error Compatibility function for \\[next-error] invocations." (interactive "p") ;; we need to run occur-find-match from within the Occur buffer - (with-current-buffer - ;; Choose the buffer and make it current. - (if (next-error-buffer-p (current-buffer)) - (current-buffer) - (next-error-find-buffer nil nil - (lambda () - (eq major-mode 'occur-mode)))) - - (goto-char (cond (reset (point-min)) - ((< argp 0) (line-beginning-position)) - ((> argp 0) (line-end-position)) - ((point)))) - (occur-find-match - (abs argp) - (if (> 0 argp) - #'previous-single-property-change - #'next-single-property-change) - "No more matches") - ;; In case the *Occur* buffer is visible in a nonselected window. - (let ((win (get-buffer-window (current-buffer) t))) - (if win (set-window-point win (point)))) - (occur-mode-goto-occurrence))) + (goto-char (cond (reset (point-min)) + ((< argp 0) (line-beginning-position)) + ((> argp 0) (line-end-position)) + ((point)))) + (occur-find-match + (abs argp) + (if (> 0 argp) + #'previous-single-property-change + #'next-single-property-change) + "No more matches") + ;; In case the *Occur* buffer is visible in a nonselected window. + (let ((win (get-buffer-window (current-buffer) t))) + (if win (set-window-point win (point)))) + (occur-mode-goto-occurrence)) (defface match '((((class color) (min-colors 88) (background light))