Hiding and replacing modeline strings with clean-mode-line

If you are like me, you are probably using one or more minor modes, and most of them add their own lighter to the modeline to tell you that they are running. Common examples include “Abbrev” for Abbrev mode; “yas” for Yasnippet mode and so on. Unfortunately, modeline real estate is expensive, and if you are stuck on a small screen – or if you split your Emacs windows a lot – you will find that it is often truncated, possibly hiding useful information that you actually care about, such as Which Function Mode.

There is no feature in Emacs to selectively hide or compress modeline flotsam, so I have hacked together some code to do the job for you.

For instance, in my Emacs I can collapse the following modeline string (Python Hi AC yas Eldoc Flymake:0/12 Abbrev) into (Py α υ Φ:0/12). I’ve chosen to completely obscure hi-lock-mode, abbrev-mode, and eldoc-mode but “compress” auto-complete-mode, yas/minor-mode, python-mode and flymake-mode.

I used Greek characters (How? C-u C-\ greek RET then C-\ to write Greek characters; see Diacritics in Emacs) because they look cool.

The code works rather well, and I have yet to experience any major issues with it, but do let me know if it breaks something! One important caveat is that a lot of minor modes that reach out and call other functions, like ERC or Flymake, often use functions in lieu of strings in mode-line-format and mode-line-modes, so replacing them with a string might break the minor mode, or cause it to not update properly! Please keep that in mind and experiment in a separate Emacs instance unless you know what you’re doing. Case in point: Flymake. I’ve replaced its own modeline updater function with one of my own with the “Flymake” string replaced; you could probably rejiggle it by advising the original function, then tweaking the modeline string post facto, blah, blah, blah – but I always opt for the simpler solution, which is what I’ve used below!

Here’s the code. Stick it in your emacs file, evaluate it, and you’re done. You can also force a refresh by running M-x clean-mode-line. Flymake will have to be turned off and back on for the changes to take effect in a buffer!

9:17pm update: Fixed a small bug in clean-mode-line !

(defvar mode-line-cleaner-alist
  `((auto-complete-mode . " α")
    (yas/minor-mode . " υ")
    (paredit-mode . " π")
    (eldoc-mode . "")
    (abbrev-mode . "")
    ;; Major modes
    (lisp-interaction-mode . "λ")
    (hi-lock-mode . "")
    (python-mode . "Py")
    (emacs-lisp-mode . "EL")
    (nxhtml-mode . "nx"))
  "Alist for `clean-mode-line'.

When you add a new element to the alist, keep in mind that you
must pass the correct minor/major mode symbol and a string you
want to use in the modeline *in lieu of* the original.")


(defun clean-mode-line ()
  (interactive)
  (loop for cleaner in mode-line-cleaner-alist
        do (let* ((mode (car cleaner))
                 (mode-str (cdr cleaner))
                 (old-mode-str (cdr (assq mode minor-mode-alist))))
             (when old-mode-str
                 (setcar old-mode-str mode-str))
               ;; major mode
             (when (eq mode major-mode)
               (setq mode-name mode-str)))))


(add-hook 'after-change-major-mode-hook 'clean-mode-line)

;;; alias the new `flymake-report-status-slim' to
;;; `flymake-report-status'
(defalias 'flymake-report-status 'flymake-report-status-slim)
(defun flymake-report-status-slim (e-w &optional status)
  "Show \"slim\" flymake status in mode line."
  (when e-w
    (setq flymake-mode-line-e-w e-w))
  (when status
    (setq flymake-mode-line-status status))
  (let* ((mode-line " Φ"))
    (when (> (length flymake-mode-line-e-w) 0)
      (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
    (setq mode-line (concat mode-line flymake-mode-line-status))
    (setq flymake-mode-line mode-line)
    (force-mode-line-update)))