overwatering.org

blog

about

Earlier this year while pairing with Julio Maia, an unashamed vim user, I noticed that the line numbers didn’t count from the top of the file in his editor. Instead, all line numbering was relative to his current line. It looked something like this.

line-numbers.jpg

This was really cool. It’s really easy to navigate and edit when you can see how many lines to move without having to count. It also didn’t hurt pairing. I could just refer to something ‘there, on line -10.’ I had to have it. So I hacked it into the linum.el mode that comes with my editor of choice, emacs.

Now that I’m reading Avdi Grimm’s emacs reboot, including his article about line numbering, I thought I should share. At least until I can get this submitted back upstream.

In your linum.el file, add the following after all the existing defcustom forms.

(defcustom linum-offset nil
  "Whether line numbers should be an offset from point or absolute within the buffer."
  :group 'linum
  :type 'boolean)

And then replace the existing linum-update-window function with the following.

(defun linum-update-window (win)
  "Update line numbers for the portion visible in window WIN."
  (setq start-line (line-number-at-pos))
  (goto-char (window-start win))
  (let ((line (line-number-at-pos))
        (limit (window-end win t))
        (fmt (cond ((stringp linum-format) linum-format)
                   ((eq linum-format 'dynamic)
                    (let ((w (length (number-to-string
                                      (count-lines (point-min) (point-max))))))
                      (concat "%" (number-to-string w) "d")))))
        (width 0))
    (run-hooks 'linum-before-numbering-hook)
    ;; Create an overlay (or reuse an existing one) for each
    ;; line visible in this window, if necessary.
    (while (and (not (eobp)) (<= (point) limit))
      (let* ((offset-line (- line start-line))
             (line-number (if linum-offset offset-line line))
             (str (if fmt
                      (propertize (format fmt line-number) 'face 'linum)
                    (funcall linum-format line-number)))
             (visited (catch 'visited
                        (dolist (o (overlays-in (point) (point)))
                          (when (string= (overlay-get o 'linum-str) str)
                            (unless (memq o linum-overlays)
                              (push o linum-overlays))
                            (setq linum-available (delete o linum-available))
                            (throw 'visited t))))))
        (setq width (max width (length str)))
        (unless visited
          (let ((ov (if (null linum-available)
                        (make-overlay (point) (point))
                      (move-overlay (pop linum-available) (point) (point)))))
            (push ov linum-overlays)
            (overlay-put ov 'before-string
                         (propertize " " 'display `((margin left-margin) ,str)))
            (overlay-put ov 'linum-str str))))
      (forward-line)
      (setq line (1+ line)))
    (set-window-margins win width)))

And then finally, in your .emacs file somewhere, turn on this new setting.

(setq linum-offset t)

There you go, I hope you find it as useful as I have.