branch: elpa/flycheck
commit 83cf0cc743a712726de9e36de203ebc9cd96f9fb
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    Make the mode-line error counts clickable
    
    mouse-1 on the counts pops up the error list, like Flymake's clickable
    indicator.  The truncation marker keeps its own tooltip explaining how
    many errors were suppressed.
---
 CHANGES.rst                  |  2 ++
 flycheck.el                  | 59 ++++++++++++++++++++++++++++++--------------
 test/specs/test-mode-line.el | 34 ++++++++++++++++++++++++-
 3 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index 340770e74c..7c56797791 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -18,6 +18,8 @@
   ``flycheck-display-errors-function`` to
   ``flycheck-display-error-messages``; custom display functions and
   extensions like flycheck-posframe keep working unchanged.
+- The error counts in the mode line are clickable: ``mouse-1`` pops up
+  the error list.
 - [#1787]: Add the ``:handle-suspicious`` property to command checkers.
   It lets a checker translate a "suspicious state" (a non-zero exit
   status with no parsable errors, e.g. a missing dependency) into
diff --git a/flycheck.el b/flycheck.el
index 45c434e4ef..9f09a5bcde 100644
--- a/flycheck.el
+++ b/flycheck.el
@@ -4362,6 +4362,26 @@ refresh the mode line."
   (run-hook-with-args 'flycheck-status-changed-functions status)
   (force-mode-line-update))
 
+(defun flycheck-mode-line-list-errors (&optional event)
+  "Pop up the error list for the buffer of EVENT's window.
+
+Without a mouse EVENT, e.g. when invoked from the keyboard, pop
+up the error list for the current buffer."
+  (interactive (list last-nonmenu-event))
+  (let ((window (and (eventp event)
+                     (posn-window (event-start event)))))
+    ;; `posn-window' may return a frame for frame-relative positions
+    (with-selected-window (if (windowp window) window (selected-window))
+      (flycheck-list-errors))))
+
+(defvar flycheck-mode-line-counts-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map [mode-line mouse-1] #'flycheck-mode-line-list-errors)
+    ;; Some setups render the mode-line construct in the header line
+    (define-key map [header-line mouse-1] #'flycheck-mode-line-list-errors)
+    map)
+  "Keymap for the error counts in the mode line.")
+
 (defun flycheck-mode-line-status-text (&optional status)
   "Get a text describing STATUS for use in the mode line.
 
@@ -4375,17 +4395,27 @@ nil."
                       (`errored "!")
                       (`finished
                        (let-alist (flycheck-count-errors 
flycheck-current-errors)
-                         (concat
-                          (if (or .error .warning .info)
-                              (format ":%s|%s|%s" (or .error 0) (or .warning 0)
-                                      (or .info 0))
-                            flycheck-mode-success-indicator)
-                          ;; Signal that some errors were suppressed over
-                          ;; `flycheck-checker-error-threshold', even when
-                          ;; the kept errors have no built-in level
-                          (if (> flycheck--suppressed-error-count 0)
-                              "+"
-                            ""))))
+                         (propertize
+                          (concat
+                           (if (or .error .warning .info)
+                               (format ":%s|%s|%s" (or .error 0) (or .warning 
0)
+                                       (or .info 0))
+                             flycheck-mode-success-indicator)
+                           ;; Signal that some errors were suppressed over
+                           ;; `flycheck-checker-error-threshold', even when
+                           ;; the kept errors have no built-in level
+                           (if (> flycheck--suppressed-error-count 0)
+                               "+"
+                             ""))
+                          'local-map flycheck-mode-line-counts-map
+                          'mouse-face 'mode-line-highlight
+                          'help-echo
+                          (concat
+                           (when (> flycheck--suppressed-error-count 0)
+                             (format "%d more errors not shown\
+ (see flycheck-checker-error-threshold)\n"
+                                     flycheck--suppressed-error-count))
+                           "mouse-1: list errors"))))
                       (`interrupted ".")
                       (`suspicious "?")))
          (face (when flycheck-mode-line-color
@@ -4397,13 +4427,6 @@ nil."
          (text (format " %s%s" flycheck-mode-line-prefix indicator)))
     (when face
       (setq text (propertize text 'face face)))
-    (when (and (eq current-status 'finished)
-               (> flycheck--suppressed-error-count 0))
-      (setq text (propertize
-                  text 'help-echo
-                  (format "%d more errors not shown\
- (see flycheck-checker-error-threshold)"
-                          flycheck--suppressed-error-count))))
     text))
 
 
diff --git a/test/specs/test-mode-line.el b/test/specs/test-mode-line.el
index 83aa79d16a..4ed739dda1 100644
--- a/test/specs/test-mode-line.el
+++ b/test/specs/test-mode-line.el
@@ -45,6 +45,38 @@
   (it "includes the prefix"
     (let ((flycheck-mode-line-prefix "foobar")
           flycheck-current-errors)
-      (expect (flycheck-mode-line-status-text 'finished) :to-equal " 
foobar:0"))))
+      (expect (flycheck-mode-line-status-text 'finished) :to-equal " 
foobar:0")))
+
+  (it "makes the error counts clickable"
+    (let* ((flycheck-current-errors
+            (list (flycheck-error-new-at 1 1 'error "boom")))
+           (text (flycheck-mode-line-status-text 'finished))
+           (counts-start (string-match ":" text)))
+      (expect (get-text-property counts-start 'local-map text)
+              :to-be flycheck-mode-line-counts-map)
+      (expect (get-text-property counts-start 'help-echo text)
+              :to-equal "mouse-1: list errors")))
+
+  (it "binds mouse-1 to the error list"
+    (expect (lookup-key flycheck-mode-line-counts-map [mode-line mouse-1])
+            :to-be 'flycheck-mode-line-list-errors)
+    (expect (lookup-key flycheck-mode-line-counts-map [header-line mouse-1])
+            :to-be 'flycheck-mode-line-list-errors))
+
+  (it "explains suppressed errors in the tooltip of the whole indicator"
+    (flycheck-buttercup-with-temp-buffer
+      (setq flycheck--suppressed-error-count 7)
+      (let* ((flycheck-current-errors
+              (list (flycheck-error-new-at 1 1 'error "boom")))
+             (text (flycheck-mode-line-status-text 'finished))
+             (counts-start (string-match ":" text))
+             (plus-pos (string-match (rx "+" eos) text)))
+        ;; The truncation marker is part of the clickable segment
+        (expect (get-text-property plus-pos 'local-map text)
+                :to-be flycheck-mode-line-counts-map)
+        ;; The tooltip explains the suppression anywhere on the counts
+        (dolist (pos (list counts-start plus-pos))
+          (expect (get-text-property pos 'help-echo text)
+                  :to-match "7 more errors not shown"))))))
 
 ;;; test-mode-line.el ends here

Reply via email to