From ee8b4eaca12af0ef6bf0d37780efaa558c25d45e Mon Sep 17 00:00:00 2001 From: Matthew Tromp Date: Tue, 22 Apr 2025 15:27:58 -0400 Subject: [PATCH] Add `next-error' support for flymake diagnostics buffers This adds `next-error' support for flymake diagnostics buffers. Buffers created with `flymake-show-buffer-diagnostics' and `flymake-show-project-diagnostics' are now next-error enabled, and `next-error' and `previous-error' will navigate through their listed diagnostics. * lisp/progmodes/flymake.el (flymake-current-diagnostic-line) (flymake--diagnostics-next-error): Add. (flymake-show-diagnostic, flymake-show-buffer-diagnostics) (flymake-show-project-diagnostics): Set next-error-last-buffer. (flymake--tabulated-setup): Set next-error-function. (Bug#77809) Copyright-paperwork-exempt: yes --- lisp/progmodes/flymake.el | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index cfabfef78a0..2d30ec3f5bd 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -1433,6 +1433,9 @@ Interactively, with a prefix arg, FORCE is t." map) "Keymap for `flymake-mode'") +(defvar-local flymake-current-diagnostic-line 0 + "The line of the most recently focused diagnostic in a diagnostics buffer.") + ;;;###autoload (define-minor-mode flymake-mode "Toggle Flymake mode on or off. @@ -1893,7 +1896,8 @@ TYPE is usually keyword `:error', `:warning' or `:note'." (defun flymake-show-diagnostic (pos &optional other-window) "From Flymake diagnostics buffer, show source of diagnostic at POS." (interactive (list (point) t)) - (let* ((id (or (tabulated-list-get-id pos) + (let* ((diagnostics-buffer (current-buffer)) + (id (or (tabulated-list-get-id pos) (user-error "Nothing at point"))) (diag (plist-get id :diagnostic)) (locus (flymake--diag-locus diag)) @@ -1903,6 +1907,7 @@ TYPE is usually keyword `:error', `:warning' or `:note'." (goto-char b) (pulse-momentary-highlight-region b (or e (line-end-position)))))) + (setq flymake-current-diagnostic-line (line-number-at-pos pos)) (with-current-buffer (cond ((bufferp locus) locus) (t (find-file-noselect locus))) (with-selected-window @@ -1918,6 +1923,8 @@ TYPE is usually keyword `:error', `:warning' or `:note'." (car beg) (cdr beg)))) (funcall visit bbeg bend))))) + ;; Emacs < 27 + (setq next-error-last-buffer diagnostics-buffer) (current-buffer)))) (defun flymake-goto-diagnostic (pos) @@ -2031,6 +2038,7 @@ resizing columns and ommiting redudant columns." (defun flymake--tabulated-setup (use-project) "Helper for `flymake-diagnostics-buffer-mode'. And also `flymake-project-diagnostics-mode'." + (setq-local next-error-function #'flymake--diagnostics-next-error) (let ((saved-r-b-f revert-buffer-function) (refresh (lambda () @@ -2060,6 +2068,23 @@ And also `flymake-project-diagnostics-mode'." (funcall refresh) (apply saved-r-b-f args))))) +(defun flymake--diagnostics-next-error (n &optional reset) + "`next-error-function' for flymake diagnostics buffers. +N is an integer representing how many errors to move. +If RESET is non-nil, return to the beginning of the errors before +moving." + (let ((line (if reset 1 flymake-current-diagnostic-line)) + (total-lines (count-lines (point-min) (point-max)))) + (goto-char (point-min)) + (unless (zerop total-lines) + (let ((target-line (+ line n))) + (setq target-line (max 1 target-line)) + (setq target-line (min target-line total-lines)) + (forward-line (1- target-line)))) + (when-let* ((win (get-buffer-window nil t))) + (set-window-point win (point))) + (flymake-goto-diagnostic (point)))) + (define-derived-mode flymake-diagnostics-buffer-mode tabulated-list-mode "Flymake diagnostics" "A mode for listing Flymake diagnostics." @@ -2116,6 +2141,7 @@ This function doesn't move point" window) (with-current-buffer target (setq flymake--diagnostics-buffer-source source) + (setq next-error-last-buffer (current-buffer)) (revert-buffer) (setq window (display-buffer (current-buffer) @@ -2222,6 +2248,7 @@ some of this variable's contents the diagnostic listings.") (with-current-buffer buffer (flymake-project-diagnostics-mode) (setq-local flymake--project-diagnostic-list-project prj) + (setq next-error-last-buffer (current-buffer)) (revert-buffer) (display-buffer (current-buffer) `((display-buffer-reuse-window