diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 9dda53713f5..9ec11f4d9d5 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -748,34 +748,41 @@ flymake--severity (flymake--lookup-type-property type 'severity (warning-numeric-level :error))) -(defun flymake--indicator-overlay-spec (indicator) +(defun flymake--indicator-overlay-spec (type) "Return INDICATOR as propertized string to use in error indicators." - (let* ((value (if (symbolp indicator) + (let* ((indicator (flymake--lookup-type-property + type + (cond ((eq flymake-indicator-type 'fringes) + 'flymake-bitmap) + ((eq flymake-indicator-type 'margins) + 'flymake-margin-string)) + (alist-get 'bitmap (alist-get type ; backward compat + flymake-diagnostic-types-alist)))) + (value (if (symbolp indicator) (symbol-value indicator) indicator)) - (indicator-car (if (listp value) - (car value) - value)) - (indicator-cdr (if (listp value) - (cdr value)))) + (valuelist (if (listp value) + value + (list value))) + (indicator-car (car valuelist))) + (cond ((and (symbolp indicator-car) flymake-fringe-indicator-position) (propertize "!" 'display - (cons flymake-fringe-indicator-position - (if (listp value) - value - (list value))))) + (cons flymake-fringe-indicator-position valuelist))) ((and (stringp indicator-car) flymake-margin-indicator-position) (propertize "!" 'display `((margin ,flymake-margin-indicator-position) - ,(propertize - indicator-car - 'face - `(:inherit (,indicator-cdr - default))))))))) + ,(propertize indicator-car + 'face `(:inherit (,(cdr valuelist) default)) + 'mouse-face 'highlight + 'help-echo "Open Flymake diagnostics" + 'keymap `,(define-keymap + (format "<%s> " flymake-margin-indicator-position) + #'flymake-mouse-show-buffer-diagnostics)))))))) (defun flymake--resize-margins (&optional orig-width) "Resize current window margins according to `flymake-margin-indicator-position'. @@ -941,16 +948,7 @@ flymake--highlight-line (overlay-put ov prop (flymake--lookup-type-property type prop value))))) (default-maybe 'face 'flymake-error) - (default-maybe 'before-string - (flymake--indicator-overlay-spec - (flymake--lookup-type-property - type - (cond ((eq flymake-indicator-type 'fringes) - 'flymake-bitmap) - ((eq flymake-indicator-type 'margins) - 'flymake-margin-string)) - (alist-get 'bitmap (alist-get type ; backward compat - flymake-diagnostic-types-alist))))) + (default-maybe 'before-string (flymake--indicator-overlay-spec type)) ;; (default-maybe 'after-string ;; (flymake--diag-text diagnostic)) (default-maybe 'help-echo @@ -1369,12 +1367,21 @@ flymake-start nil))) (flymake--import-foreign-diagnostics)))))) -(defvar flymake-mode-map - (let ((map (make-sparse-keymap))) - (define-key map `[,flymake-fringe-indicator-position mouse-1] - #'flymake-show-buffer-diagnostics) - map) - "Keymap for `flymake-mode'.") +(defun flymake-mouse-show-buffer-diagnostics (event) + "Show diagnostics buffer on mouse click in the margin or fringe. +This uses two different approaches to work. +For margin it is set as a char property of the margin character directly. +While in the fringe it is set as part of the `flymake-mode-map'." + (interactive "e") + (when-let* ((diagnostics (flymake-diagnostics-at-mouse-event event))) + (flymake-show-buffer-diagnostics (car diagnostics)))) + +;; Set the fringe mouse-1 action directly and perform the filtering +;; latter iterating over the overlays. +(defvar-keymap flymake-mode-map + :doc "Keymap for `flymake-mode'." + (format "<%s> " flymake-fringe-indicator-position) + #'flymake-mouse-show-buffer-diagnostics) ;;;###autoload (define-minor-mode flymake-mode @@ -1616,6 +1623,21 @@ flymake-goto-prev-error t)) (flymake-goto-next-error (- (or n 1)) filter interactive)) +(defun flymake-diagnostics-at-mouse-event (event) + (mouse-minibuffer-check event) + (let* ((posn (event-end event)) + (pos (posn-point posn))) + (when (numberp pos) + (with-selected-window (posn-window posn) + (with-current-buffer (window-buffer) + (goto-char pos) + (flymake-diagnostics pos (1+ pos))))))) + +(defun flymake-show-buffer-diagnostics-menu (event) + (interactive "e") + (flymake-show-buffer-diagnostics + (car (flymake-diagnostics-at-mouse-event event)))) + ;;; Mode-line and menu ;;; @@ -1624,7 +1646,7 @@ flymake-menu [ "Go to next problem" flymake-goto-next-error t ] [ "Go to previous problem" flymake-goto-prev-error t ] [ "Check now" flymake-start t ] - [ "List all problems" flymake-show-buffer-diagnostics t ] + [ "List all problems" flymake-show-buffer-diagnostics-menu t ] "--" [ "Go to log buffer" flymake-switch-to-log-buffer t ] [ "Turn off Flymake" flymake-mode t ])) @@ -1652,6 +1674,15 @@ flymake-mode-line-lighter :type 'string :version "29.1") +(defcustom flymake-after-jump-hook '(pulse-momentary-highlight-one-line) + "Hook called after jumping to a diagnostic line. + +This hooks are called when `flymake-show-buffer-diagnostics' receives an +the optional `diagnostic' argument and it matches an entry in the +diagnostic's buffer." + :type 'hook + :version "31.0") + (defvar flymake-mode-line-title '(:eval (flymake--mode-line-title)) "Mode-line construct to show Flymake's mode name and menu.") @@ -1969,7 +2000,7 @@ flymake--diagnostics-buffer-name (define-obsolete-function-alias 'flymake-show-diagnostics-buffer 'flymake-show-buffer-diagnostics "1.2.1") -(defun flymake-show-buffer-diagnostics () +(defun flymake-show-buffer-diagnostics (&optional diagnostic) "Show a list of Flymake diagnostics for current buffer." (interactive) (unless flymake-mode @@ -1987,7 +2018,15 @@ flymake-show-buffer-diagnostics `((display-buffer-reuse-window display-buffer-below-selected) (window-height . (lambda (window) - (fit-window-to-buffer window 10)))))))) + (fit-window-to-buffer window 10))))) + (when (and diagnostic flymake-after-jump-hook) + (goto-char (point-min)) + (catch 'done + (while-let ((id (tabulated-list-get-id (point)))) + (if (eq (plist-get id :diagnostic) diagnostic) + (progn (run-hooks 'flymake-after-jump-hook) + (throw 'done nil)) + (forward-line)))))))) ;;; Per-project diagnostic listing