From: Juri Linkov Date: Tue, 17 Apr 2018 19:27:48 +0000 (+0300) Subject: Use next-error-found to set next-error-last-buffer. X-Git-Tag: emacs-27.0.90~5154 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=0c9e3df3c2088b61feb4b4e00d24419459962273;p=emacs.git Use next-error-found to set next-error-last-buffer. https://lists.gnu.org/archive/html/emacs-devel/2018-04/msg00207.html * lisp/simple.el (next-error-buffer): New buffer-local variable instead of making buffer-local next-error-last-buffer. (Bug#20489) (next-error-found-function): New defcustom. (next-error-buffer-on-selected-frame): Use t for avoid-current arg of next-error-buffer-p. (next-error-find-buffer): Add second rule for using the current next-error-buffer if it's not visited by other navigation. (next-error, next-error-internal): Call next-error-found. (next-error-found): New function with body extracted mostly from next-error. * lisp/vc/add-log.el (change-log-goto-source-internal): New function with body from change-log-goto-source. (change-log-goto-source): Call change-log-goto-source-internal and next-error-found. (change-log-next-error): Call change-log-goto-source-internal instead of change-log-goto-source. (change-log-mode): Don't set next-error-last-buffer. (Bug#28864) * lisp/vc/diff-mode.el (diff-goto-source): Call next-error-found. * lisp/progmodes/xref.el (xref-goto-xref): Call next-error-found. * lisp/replace.el (occur-mode-goto-occurrence) (occur-mode-goto-occurrence-other-window) (occur-mode-display-occurrence): Call next-error-found. (occur-next-error): Remove unnecessary with-current-buffer. (Bug#27362, bug#30646) --- diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index ee8886a4e16..b7c44d60838 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el @@ -354,17 +354,6 @@ See `compilation-error-screen-columns'" (defalias 'kill-grep 'kill-compilation) -;;;; TODO --- refine this!! - -;; (defcustom grep-use-compilation-buffer t -;; "When non-nil, grep specific commands update `compilation-last-buffer'. -;; This means that standard compile commands like \\[next-error] and \\[compile-goto-error] -;; can be used to navigate between grep matches (the default). -;; Otherwise, the grep specific commands like \\[grep-next-match] must -;; be used to navigate between grep matches." -;; :type 'boolean -;; :group 'grep) - ;; override compilation-last-buffer (defvar grep-last-buffer nil "The most recent grep buffer. @@ -1083,6 +1072,7 @@ This command shares argument histories with \\[rgrep] and \\[grep]." (concat command " " null-device) command) 'grep-mode)) + ;; Set default-directory if we started lgrep in the *grep* buffer. (if (eq next-error-last-buffer (current-buffer)) (setq default-directory dir)))))) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 5a9a7a925a9..9a437b6f690 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -540,9 +540,11 @@ SELECT is `quit', also quit the *xref* window." 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/replace.el b/lisp/replace.el index 4916cb138e6..058e14452d7 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1192,7 +1192,8 @@ To return to ordinary Occur mode, use \\[occur-cease-edit]." (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 +1205,31 @@ To return to ordinary Occur mode, use \\[occur-cease-edit]." (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) @@ -1253,29 +1259,20 @@ To return to ordinary Occur mode, use \\[occur-cease-edit]." "Move to the Nth (default 1) next match in an Occur mode buffer. 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)) diff --git a/lisp/simple.el b/lisp/simple.el index 7d94b64913f..b51be3a8f8a 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -122,11 +122,13 @@ A buffer becomes most recent when its compilation, grep, or 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. @@ -177,14 +179,23 @@ rejected, and the function returns nil." (defcustom next-error-find-buffer-function #'ignore "Function called to find a `next-error' capable buffer." - :type '(choice (const :tag "Single next-error capable buffer on selected frame" + :type '(choice (const :tag "No default" ignore) + (const :tag "Single next-error capable buffer on selected frame" next-error-buffer-on-selected-frame) - (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 +(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) "Return a single visible next-error buffer on the selected frame." @@ -193,7 +204,7 @@ rejected, and the function returns nil." (delq nil (mapcar (lambda (w) (if (next-error-buffer-p (window-buffer w) - avoid-current + t extra-test-inclusive extra-test-exclusive) (window-buffer w))) (window-list)))))) @@ -220,16 +231,24 @@ that buffer is rejected." (funcall next-error-find-buffer-function avoid-current extra-test-inclusive extra-test-exclusive) - ;; 2. If next-error-last-buffer is an acceptable buffer, use that. + ;; 2. 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)) + ;; 3. 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 extra-test-inclusive extra-test-exclusive)) next-error-last-buffer) - ;; 3. If the current buffer is acceptable, choose it. + ;; 4. If the current buffer is acceptable, choose it. (if (next-error-buffer-p (current-buffer) avoid-current extra-test-inclusive extra-test-exclusive) (current-buffer)) - ;; 4. Look for any acceptable buffer. + ;; 5. Look for any acceptable buffer. (let ((buffers (buffer-list))) (while (and buffers (not (next-error-buffer-p @@ -237,7 +256,7 @@ that buffer is rejected." extra-test-inclusive extra-test-exclusive))) (setq buffers (cdr buffers))) (car buffers)) - ;; 5. Use the current buffer as a last resort if it qualifies, + ;; 6. Use the current buffer as a last resort if it qualifies, ;; even despite AVOID-CURRENT. (and avoid-current (next-error-buffer-p (current-buffer) nil @@ -245,7 +264,7 @@ that buffer is rejected." (progn (message "This is the only buffer with error message locations") (current-buffer))) - ;; 6. Give up. + ;; 7. Give up. (error "No buffers contain error message locations"))) (defun next-error (&optional arg reset) @@ -284,37 +303,35 @@ To control which errors are matched, customize the variable (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 @@ To control which errors are matched, customize the variable (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/vc/add-log.el b/lisp/vc/add-log.el index 175c82f8c00..41a99916994 100644 --- a/lisp/vc/add-log.el +++ b/lisp/vc/add-log.el @@ -471,6 +471,11 @@ A change log tag is a symbol within a parenthesized, 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 +544,7 @@ Compatibility function for \\[next-error] invocations." ;; 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 +1072,7 @@ Runs `change-log-mode-hook'. (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 ef13f55b931..1e2fbb97fcf 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1874,11 +1874,13 @@ then `diff-jump-to-old-file' is also set, for the next invocations." ;; 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))))