emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Flymake, compilation-mode lighters very noisy


From: Yuri Khan
Subject: Re: Flymake, compilation-mode lighters very noisy
Date: Wed, 21 Nov 2018 16:54:59 +0700

On Wed, Nov 21, 2018 at 3:16 AM João Távora <address@hidden> wrote:

>> Flymake, though, delegates the work to the function
>> ‘flymake--mode-line-format’, which is pretty involved (110 lines of
>> code). Not much I can do with that, as a user, except copy-pasting
>> that function into my init.el with a minor change.
>
> To your point, propose a way to break up that function. What variable and 
> what semantics would you like to see? Would it be enough for a variable to 
> state the minimum severity you would want to always see, even with zero 
> occurance? In your case you would set it somewhere above "error".... If you 
> read closely you'll find it's now at "warning", though indeed hardcoded.

Well, as I said before, the function is “pretty involved”. That is to
say, I do not immediately understand all the things it is doing. You
are asking me to read and comprehend it. Hm, okay.


* I see it first calls a few functions to get the current state and
binds their results to local variables. Gonna ignore that for a
moment. It also does some data reshaping (7 lines) from the
buffer-local variable ‘flymake--backend-state’ into local variable
‘diags-by-type’. That could be a helper function.

* I see it dynamically builds a mode line construct, which is always a list.

* Its first element is always the minor mode name, propertized to show
some statistics on mouse hover, show the mode menu on click, and show
help on middle click. This part takes 17 lines. The only dynamic
dependencies of this part are (length known), (length running), and
(length disabled).

* The second element is nil in the normal case, but may turn into a
status item when there are no known backends, or some backends are
still running, or all backends are disabled. This part consists of a
data collection part (12 lines, binds three variables in a pcase-let)
and a conditionally applied mode line construct template (10 lines,
depends on ind, face, explain variables bound just above).

* The last part of the function (56 lines) conditionally generates a
list of "[", followed by space-separated counters by type in
descending severity level order, followed by "]". A counter for a type
is skipped if it has no diagnostics and its severity is lower than
:warning. Each counter is a decimal number representation of the
number of diagnostics of a particular severity, propertized with the
face corresponding to the severity level, a constant mouse-face, and a
dynamically-generated keymap. The mode line construct for each counter
essentially depends on: (length diags), severity, and type.


So I guess what I would like to see is a better separation of logic
from presentation. Concretely, what I would do is:

1. Extract many variables, each of which represents a single mode line
construct used in the Flymake mode line indicator. Make them reference
any necessary data passed as values of predefined symbols.

2. Extract constants such as the Flymake indicator’s keymap as
defconsts, and near-constants such as each type’s counter’s keymap as
defuns.

3. Move the decision to display or skip each element into its
corresponding data structure, possibly using the (SYMBOL THEN ELSE)
mode line construct.

4. The flymake-mode-line-format will be left with all the calculations
and a bunch of (format-mode-line) calls using the variables extracted
in (1), wrapped in let forms binding the necessary dynamic values to
symbols for variables to use.


A little code to demonstrate:

;;..5...10....5...20....5...30....5...40....5...50....5...60....5...70..
;; A user could elide zero counts from here
;; by wrapping each (format …) into a (when …)
(defvar flymake-overall-indicator-help-echo-format
  '((:eval (format "%d known backends\n" flymake-known-backend-count))
    (:eval (format "%d running backends\n" flymake-running-backend-count))
    (:eval (format "%d disabled backends\n" flymake-disabled-backend-count))
    ("mouse-1: Display minor mode menu\n")
    ("mouse-2: Show help for minor mode")))

(defvar flymake-overall-indicator-format
  '(:propertize " Flymake"
                mouse-face mode-line-highlight
                help-echo flymake-overall-indicator-help-echo
                keymap flymake-overall-indicator-keymap))

(defun flymake--mode-line-format ()
  (let* ((known …)
         …more variables…)
    `(,(let* ((flymake-known-backend-count (length known))
              (flymake-running-backend-count (length running))
              (flymake-disabled-backend-count (length disabled))
              (flymake-overall-indicator-help-echo
               (format-mode-line flymake-overall-indicator-help-echo-format)))
         (format-mode-line flymake-overall-indicator))
      …more mode line constructs…)))

This way, for each element, the user gets a well-defined way to
customize when and how it appears, without having to copy the whole
function.


Now as to why a simple severity level variable will not cut it: The
color coding is helpful, but people with different accessibility needs
will want to replace it with different things. A color-blind user may
want to add letters, e.g. 0e 0w. A user with ADD-like symptoms will
prefer no color, with or without letters. A visually inclined user may
want to replace the string “Flymake” with a Unicode check mark/info
sign/warning sign/cross. A small screen user will want to see only one
counter with the most severity, and hide warnings if there are errors.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]