Dirk-Jan C. Binnema’s mode-line blog post inspired me to post about my own Emacs mode line configuration. I found the default mode line to be too busy for my tastes. I removed most of it and added to the features I care about most. Here’s what it currently looks like:

Emacs mode line

I use a proportional font for most of the mode line, along with extra padding to make the mode line taller than other lines. From left to right:

  1. Line and column position. I use a monospace font for this portion because it’s changing all the time, and I don’t want the rest of the mode line to move around.

    I also highlight the column number if I go over 80 columns, using code similar to modeline-posn.el:

    Emacs mode line with 80 column indicator
  2. Buffer status. If the buffer is modified, I use a bright white and red block:

    Emacs mode line with buffer modified indicator

    If it’s read-only, I use a blue indicator:

    Emacs mode line with buffer read only indicator
  3. Directory and buffer name. I found that the current directory matters to me so I decided to put it into the mode line, in addition to alternatives like Uniquify. Some directory names are too long so I only show the trailing portion.

  4. Mode indicators. I want to see the major mode. I’m less sure about the rest: VC mode (not all VC packages use this), narrowing (I almost never use this), recursive edit (I should use this but I don’t), minor modes (I almost never look at this part of the mode-line), process status.

  5. And what would a mode line be without Nyan mode? It only turns on if I use M-x nyan-mode.

I removed things I don’t care about: character encoding, mule, end of line conversion, tooltips, menus, file size, overwrite mode, frame information, portion of buffer being displayed, and the dashes.

Duncan MacGregor suggests splitting up the mode line into smaller pieces. However, I haven’t done that yet. Instead, I expanded everything into one big list.

;; Mode line setup
(setq-default
 mode-line-format
 '(; Position, including warning for 80 columns
   (:propertize "%4l:" face mode-line-position-face)
   (:eval (propertize "%3c" 'face
                      (if (>= (current-column) 80)
                          'mode-line-80col-face
                        'mode-line-position-face)))
   ; emacsclient [default -- keep?]
   mode-line-client
   "  "
   ; read-only or modified status
   (:eval
    (cond (buffer-read-only
           (propertize " RO " 'face 'mode-line-read-only-face))
          ((buffer-modified-p)
           (propertize " ** " 'face 'mode-line-modified-face))
          (t "      ")))
   "    "
   ; directory and buffer/file name
   (:propertize (:eval (shorten-directory default-directory 30))
                face mode-line-folder-face)
   (:propertize "%b"
                face mode-line-filename-face)
   ; narrow [default -- keep?]
   " %n "
   ; mode indicators: vc, recursive edit, major mode, minor modes, process, global
   (vc-mode vc-mode)
   "  %["
   (:propertize mode-name
                face mode-line-mode-face)
   "%] "
   (:eval (propertize (format-mode-line minor-mode-alist)
                      'face 'mode-line-minor-mode-face))
   (:propertize mode-line-process
                face mode-line-process-face)
   (global-mode-string global-mode-string)
   "    "
   ; nyan-mode uses nyan cat as an alternative to %p
   (:eval (when nyan-mode (list (nyan-create))))
   ))

;; Helper function
(defun shorten-directory (dir max-length)
  "Show up to `max-length' characters of a directory name `dir'."
  (let ((path (reverse (split-string (abbreviate-file-name dir) "/")))
        (output ""))
    (when (and path (equal "" (car path)))
      (setq path (cdr path)))
    (while (and path (< (length output) (- max-length 4)))
      (setq output (concat (car path) "/" output))
      (setq path (cdr path)))
    (when path
      (setq output (concat ".../" output)))
    output))

;; Extra mode line faces
(make-face 'mode-line-read-only-face)
(make-face 'mode-line-modified-face)
(make-face 'mode-line-folder-face)
(make-face 'mode-line-filename-face)
(make-face 'mode-line-position-face)
(make-face 'mode-line-mode-face)
(make-face 'mode-line-minor-mode-face)
(make-face 'mode-line-process-face)
(make-face 'mode-line-80col-face)

(set-face-attribute 'mode-line nil
    :foreground "gray60" :background "gray20"
    :inverse-video nil
    :box '(:line-width 6 :color "gray20" :style nil))
(set-face-attribute 'mode-line-inactive nil
    :foreground "gray80" :background "gray40"
    :inverse-video nil
    :box '(:line-width 6 :color "gray40" :style nil))

(set-face-attribute 'mode-line-read-only-face nil
    :inherit 'mode-line-face
    :foreground "#4271ae"
    :box '(:line-width 2 :color "#4271ae"))
(set-face-attribute 'mode-line-modified-face nil
    :inherit 'mode-line-face
    :foreground "#c82829"
    :background "#ffffff"
    :box '(:line-width 2 :color "#c82829"))
(set-face-attribute 'mode-line-folder-face nil
    :inherit 'mode-line-face
    :foreground "gray60")
(set-face-attribute 'mode-line-filename-face nil
    :inherit 'mode-line-face
    :foreground "#eab700"
    :weight 'bold)
(set-face-attribute 'mode-line-position-face nil
    :inherit 'mode-line-face
    :family "Menlo" :height 100)
(set-face-attribute 'mode-line-mode-face nil
    :inherit 'mode-line-face
    :foreground "gray80")
(set-face-attribute 'mode-line-minor-mode-face nil
    :inherit 'mode-line-mode-face
    :foreground "gray40"
    :height 110)
(set-face-attribute 'mode-line-process-face nil
    :inherit 'mode-line-face
    :foreground "#718c00")
(set-face-attribute 'mode-line-80col-face nil
    :inherit 'mode-line-position-face
    :foreground "black" :background "#eab700")

Update: [2016-12-22] If I were doing this again, I'd probably start with the spaceline package.

Update: [2017-01-08] I did switch to spaceline.

Labels:

10 comments:

Anonymous wrote at Monday, June 11, 2012 at 1:29:00 PM PDT

Not bad, curious about what font type you're using. Looks better than my courier for the mode-line/

Amit wrote at Monday, June 11, 2012 at 9:51:00 PM PDT

Anonymous: it's the Muli font, by Vernon Adams.

Alex V Koval wrote at Friday, June 29, 2012 at 12:39:00 PM PDT

you made my days :-) solved more questions then I ever expected. thank you for a great work!

I really like the style and the way that 80th column is yellow. It helps me a lot.

lawlist wrote at Saturday, June 15, 2013 at 9:12:00 AM PDT

AWESOME! Thank you so very much.

Anonymous wrote at Tuesday, January 21, 2014 at 10:08:00 PM PST

This is so nice (I've been using it for a while) I have prepped it for distribution via Marmalade, and placed it in a gist at https://gist.github.com/8554119

Feel free to submit it to http://marmalade-repo.org

93free wrote at Thursday, January 22, 2015 at 9:32:00 PM PST

the rainbow of nyan cat if very beautiful than the github one. I use the tip in emacswiki to edit the *xpm files, but change nothing. could you please share your xpm files and nyan-mode configs?

Amit wrote at Friday, January 23, 2015 at 10:34:00 AM PST

Hi 93free, I'm using the standard nyan-cat module (from melpa), except I turned on nyan-wavy-trail to make the trail wavy. The colors should be the same.

Amit wrote at Friday, January 23, 2015 at 10:36:00 AM PST

93free: I believe the xpm changes are already incorporated into the github/melpa module, because I no longer have any of my own customizations, and it seems to work for me, regardless of the modeline color.

Anonymous wrote at Friday, September 11, 2015 at 6:25:00 PM PDT

Amit, What is the license of the code in this blog post?

Amit wrote at Saturday, September 12, 2015 at 9:22:00 AM PDT

Anonymous, please feel free to use it in any way you wish. It's an example for you to copy and use.