Relative Line Numbers In Emacs

(2012-03-16: line numbers are now right-aligned, and displayed in the correct face.)

The problem here is that by the time a custom linum-format function is called, point has already been moved (by linum-update-window) to the line in question, so we can no longer use it to establish the difference between the two lines; it would just print a zero for every line.

There is a linum-before-numbering-hook, but this is run after point has been moved to the start of the buffer, so that's not useful for our purpose.

The following code solves the problem by using advice for linum-update to store the current line number, so that it will be available to the custom linum-format function.

To right-align the numbers I initially used a hard-coded format string of %3d on the basis that a single window showing more than 100 lines of code was not terribly likely. If you're a fan of follow-mode, however (or simply have multiple windows on the same buffer), that circumstance becomes exceedingly likely; so the code now calculates the number of columns required dynamically. The use of linum-before-numbering-hook makes this more efficient than the approach taken by the default dynamic linum format.

Note that if you comment out the add-hook, the faster non-dynamic approach is used.

(defvar my-linum-format-string "%3d")

(add-hook 'linum-before-numbering-hook 'my-linum-get-format-string)

(defun my-linum-get-format-string ()
  (let* ((width (1+ (length (number-to-string
                             (count-lines (point-min) (point-max))))))
         (format (concat "%" (number-to-string width) "d")))
    (setq my-linum-format-string format)))

(defvar my-linum-current-line-number 0)

(setq linum-format 'my-linum-relative-line-numbers)

(defun my-linum-relative-line-numbers (line-number)
  (let ((offset (- line-number my-linum-current-line-number)))
    (propertize (format my-linum-format-string offset) 'face 'linum)))

(defadvice linum-update (around my-linum-update)
  (let ((my-linum-current-line-number (line-number-at-pos)))
    ad-do-it))
(ad-activate 'linum-update)

I just came across Scott Jaderholm's code for this, and remembered seeing this question, so I decided to post a link to the relevant lines in his .emacs.

Update: If you're using MELPA (and you should be!), just M-x package-install RET linum-relative.


In Emacs 26.1, there's a built-in line number mode (display-line-numbers-mode). Enable it and set (setq display-line-numbers 'relative) to use relative line numbers.