System monitor in Emacs mode-line

Posted on by Idorobots

Resistance is futile...

As we all know Emacs is a great operating system and a decent editor, and as such it has been serving me really well - I find myself assimilating more and more of my tools and daily activities into the Emacs collective. Recently I realised that Conky just wouldn't cut it anymore...

First of all, I barely look at my desktop. There's just no reason to do that other than checking some of the system stats such as memory usage or CPU load when I'm hacking arround and testing stuff.

For this particular use-case I figured the Emacs mode-line would be perfect to display all the relevant statistics directly in Emacs in such a way that I could glance through them without interrupting my workflow - giving me real-time feedback with minimal distraction.


The package I wrote contains a bunch of easy to use modules that provide various system stats directly in the Emacs mode-line:

  • cpu-stats.el - provides an easy way to display various CPU stats derived from /proc/stat. Usage:

(require 'cpu-stats)
(setq cpu-usage-update-interval 1)
(setq cpu-usage-format "Average: %A CPU0: %C0 CPU1: %C1")

  • memory-stats.el - display many different RAM and SWAP statistics in the mode-line. Usage:

(require 'memory-stats)
(setq memory-usage-update-interval 5)
(setq memory-usage-format "Mem: %R Free: %F Swap: %S")

  • network-speed.el - displays network load in the mode-line. This one was written by Vicente Hernando Ara quite some time ago and cycles the net ever since. Usage:

(require 'network-speed)
(setq network-speed-update-interval 5)
(setq network-speed-precision 1)
(setq network-speed-interface-list '("wlan0" "eth0"))
(setq network-speed-format-string "Down: %RB Up: %TB")

  • misc-stats.el - various system and Emacs stats such as load-averages, uptime etc. Usage:

(require 'misc-stats)
(setq misc-stats-update-interval 10)
(setq misc-stats-format "Emacs uptime: %E Load average: %L1")

Additionally, there are some system monitors already bundled with Emacs, such as battery.el, useful for laptop users.

Mode-line hacking

The package will look something like this out of the box:


...but with enough elbow grease you can make it look like this:


Let's start with evaluating arbitrary code in the mode-line-format as it's fairly simple.

You can use either (:eval ...) or (:propertize ...) in order to evaluate some code that returns a string or propertize it similarly to the propertize function:

(setq mode-line-format
  (list '(:eval (message "Using `message' here is a bad idea..."))
        '(:propertize " No really. Stop it!"
                      face font-lock-warning-face)

Propertizing mode-line strings gives us an opportunity to add colors to this boring part of the UI. For example in order to color the buffername according to the version control status of its associated file, we can add this to the mode-line-format:

(defvar my-vc-alist '(;; Everything is ok:
                      (up-to-date some-green-face)
                      ;; Kinda important:
                      (edited some-yellow-face)
                      (added some-yellow-face)
                      ;; Most important:
                      ;; ...

(setq mode-line-format
  (list ;; ...
         '(:eval (let ((file-name (buffer-file-name)))
              (if file-name
                  (let ((state-face (assoc (vc-state file-name)
                        (revision (vc-working-revision file-name)))
                    (propertize (concat "%b"
                                        (when revision
                                          (concat " [" revision "]")))
                                'face (cadr state-face)))
        ;; ...

Custom tool tips are fine too:

(setq mode-line-format
  (list ;; ...
        '(:propertize "%@" help-echo (concat "Default directory is: "
                           mouse-face mode-line-highlight)
        ;; ...

And a neat little thing - mode-line images. This one is a little trickier since Emacs has a hard time displaying .png's in the mode-line for some reason... I advise using .xpm's instead:

(defvar some-image (create-image "foo.xpm" 'xpm nil
                                 :ascent 'center))

(setq mode-line-format
  (list ;; ...
        '(:eval (propertize "unimportant" 'display some-image))
        ;; ...

Lastly, here you will find my lengthy, custom mode-line code1. Happy hacking.

2016-02-16: Adjusted some links & tags.

  1. It does not use all the stuff the package has to offer to elliminate some redundancies.