Sunday, April 21, 2013

Using Emacs for Fun & Profit. Part 1: Making the Mode Line Useful

Summary
The Emacs mode line is somewhat cryptic.  A brief introduction to mode line customization in Emacs is given.
 
The Default Mode Line
The Emacs mode line is an area below the contents of a buffer displaying information such as current line number of the cursor, buffer name, and major/minor modes.  Here is the default modeline (in Emacs 24.2.1)


The line and column numbers are shown as are the buffer name and current modes.  Not so clear though are the mysterious "U:---" and "All".  What do they mean?

If I open a file and page down several times the word "All" changes to "39%" which is the amount of text below the bottom of the window.



What about  that mysterious  "-:--" which  was "U:**-"  in the  scratch buffer's
mode line?

The emacs documentation for the mode line states that the left part of the mode line has the form

CS:CH-FR

Where
  • CS is the coding system (possibly prefixed with a  character designating the current input method).
  • The character(s) immediately after CS indicate the end-of-line convention.  This can be "\" or "(DOS)" if the DOS/WINDOWS carriage return + linefeed convention is used to indicate end-of-line.
  • CH is
    •  "--" if the buffer is unmodified,
    • "**" if the buffer has been edited,
    • "%%" if the buffer is read-only and unmodified and
    • "%*" if the buffer is read-only and modified         
  • The character following CH is a dash ("-") unless the default directory for the buffer is on a remote machine, in which case it is a "@".
  • FR is the frame name and is seen only on text terminals.
Customizing the Mode Line  
If you're like me, then you probably won't remember the bizarre conventions of the default mode line in your day-to-day use of emacs. Fortunately the mode line can be customized like anything else in emacs.  I'll walk through the interesting parts of customizing a mode line to look like this



  (the vertical text was added to explain each part)

Here is the elisp code for this modeline

(0) (setq-default mode-line-format
(1)  (list
(2)    "  "
(3)    mode-line-buffer-identification
(4)    " │ "
(5)    "dir: "
(6)    '(:eval (last-dir default-directory))
(7)    " │ "
(8)    ;; '%02' to set to 2 chars at least; prevents flickering
(9)      "%04l"
(10)     ","
(11)     "%02c" 
(12)   " │ "
(13)   '(:eval (if (buffer-modified-p) "M" "-"))
(14)   '(:eval (if buffer-read-only    "R" "-"))
(15)   '(:eval (if (window-dedicated-p (selected-window)) "D" "-"))
(16)   " │ "
(17)   mode-line-modes    
(18)   )) 
 
The Emacs lisp variable mode-line-format on line 0 determines what gets placed onto the mode line.  This variable must be set with setq-default so that the new value can be seen in all buffers.

The predefined variable on line 3, mode-line-buffer-identification, will show the current buffer name in bold text. Clicking on the buffer identification with mouse-1 will cause Emacs to switch to the next buffer in its buffer list and clicking on it with mouse-2 will switch to the previous buffer.

Lines 4 and 5 are simply text that will be displayed verbatim. The current line and column are displayed by lines 9 and 11.

Percent characters followed by a single-letter code in literal strings are a signal for Emacs to substitute various data. Some examples:
  • %I - Abbreviated size of buffer (e.g. 32k, 2M, etc.)
  • %p - percentage of buffer text above the top of the window.
  • %P - percentage of buffer text below the bottom of the window.  This is displayed in the default mode line.
Others can be found here. In our case, we are using %l and %c to display the cursor line and column. Additionally, you can designate a field width in C's printf() style by placing a number after the '%'.

Emacs also allows arbitrary pieces of lisp code to be evaluated when constructing the mode line. Here the real power of mode line customization can be seen. A simple example is on line 6 which uses the :eval construct. On this line, the default directory for the current buffer is passed to the function last-dir which peels off all but the last level of the directory path

(defun last-dir (p)
  (let ((dirs (reverse (split-string p "/"))))
    (cond ((and (equal (car dirs) "")
                (equal (cadr dirs) ""))
           "/")   ; root dir
          ((and (equal (car dirs) "")
                (equal (cadr dirs) "~"))
           "~")   ; home dir
          (t (cadr dirs))))) 

The variable mode-line-modes is used on line 17 to display the major and minor modes which are active for the current buffer. Clicking on the major mode name with mouse-1 will display a menu of available commands for that mode. Clicking on the minor mode name with mouse-1 will display a pop-up menu allowing you to turn off the minor mode or display help. Clicking on the major or minor mode name with mouse-2 will display a menu of minor modes to choose from.

Consult the Emacs documentation for more details on mode line customization.
http://www.gnu.org/software/emacs/manual/html_node/elisp/Mode-Line-Format.html#Mode-Line-Format

No comments:

Post a Comment