NumberLines

This page is about adding line numbers to the beginnings of lines in a buffer.

See Also: LineNumbers for temporary display of line numbers in a buffer. That is, while the code here adds line numbers to the buffer content, LineNumbers is about just showing the line numbers without actually changing the buffer text.


As of Emacs 24.1, there’s a new command ‘C-x r N’ (‘rectangle-number-lines’), that can be used to number the lines. Just mark a region which you want numbered and hit ‘C-x r N’. ‘C-u’ prefix works to start from any number you choose.


If you have the cat utility (standard in Unix and Linux and which can be installed for other OSes like Windows),

1. Mark the region

2. “C-u M-|” to run command on region

3a. Enter “cat -n” in the minibuffer (to number all lines, including blank ones); or
3b. Enter “nl” in the minibuffer (to number all non-blank lines); or
3c. Enter “nl --options” in the minibuffer (many options available to set the first number, formatting, width, and style)


Here are a few basic functions I use to number lines of code that I’m using in another document. For example, this works great for putting line numbers in a verbatim environment. This makes referencing the code in the text of the document easier.

(defun number-line (n padding)
  (beginning-of-line)
  (insert (number-to-string n))
  (let ((counter 0))
    (while (< counter padding)
      (insert " ")
      (setf counter (+ counter 1))))
  (forward-line))

(defun compute-padding (i n)
  (+ 1 (- (truncate (log10 n))
          (truncate (log10 i)))))

(defun number-lines (n)
  (interactive "p")
  (let ((counter 1))
    (while (<= counter n)
      (number-line counter (compute-padding counter n))
      (setf counter (+ counter 1)))))

(defun number-lines-region (start end)
  (interactive "r")
  (let ((num-lines (count-lines start end)))
    (save-excursion
      (save-restriction
        (narrow-to-region start end)
        (goto-char (point-min))
        (number-lines num-lines)))))

(defun unnumber-line (padding)
  (beginning-of-line)
  (re-search-forward "[0123456789]+" (get-end-line) t)
  (replace-match "" nil nil)
  (delete-char padding)
  (forward-line))

(defun unnumber-lines (n)
  (interactive "p")
  (let ((counter 1))
    (while (<= counter n)
      (unnumber-line (compute-padding counter n))
      (setf counter (+ counter 1)))))

(defun unnumber-lines-region (start end)
  (interactive "r")
  (let ((num-lines (count-lines start end)))
    (save-excursion
      (save-restriction
        (narrow-to-region start end)
        (goto-char (point-min))
        (unnumber-lines num-lines)))))


Here is an alternative to the code above:

  (defun numerotate-line ()
    (interactive)
    (let ((P (point))
  	(max (count-lines (point-min)(point-max)))
  	(line 1))
      (goto-char (point-min))
      (while (< line max)
        (insert (format "%04d " line))
        (beginning-of-line 2)
        (setq line (+ line 1)))
      (goto-char P)))

Yet another solution:

    (defun number-lines-region (start end &optional beg)
      (interactive "*r\np")
      (let* ((lines (count-lines start end))
             (from (or beg 1))
             (to (+ lines (1- from)))
             (numbers (number-sequence from to))
             (width (max (length (int-to-string lines))
                         (length (int-to-string from)))))
        (if (= start (point))
            (setq numbers (reverse numbers)))
        (goto-char start)
        (dolist (n numbers)
          (beginning-of-line)
          (save-match-data
            (if (looking-at " *-?[0-9]+\\. ")
                (replace-match "")))
          (insert (format (concat "%" (int-to-string width) "d. ") n))
          (forward-line))))

This version allows you to indicate the starting value with the numeric prefix argument. The default value is 1. To begin at zero, type M-0 M-x number-lines-region. Negative numbers are also supported. Numbers are right aligned followed by a period and a space. If the point is at the beginning of the region, the lines will be numbered in descending order. If a line is already prefixed with a number, it will be overwritten with the new value.

I don’t know if it is something that I’m missing (in GNU Emacs 21.4.1), but I had to write the function “number-sequence” for the above to work:

    (defun number-sequence (from to)
      (let ((out '())
            (counter from))
        (while (<= counter to)
          (setf out (cons counter out))
          (setf counter (+ 1 counter)))
        (reverse out)))

In emacs 22, I found it is rather simple to use M-x replace-regexp to fulfill the job: Replace regexp ^.*$ with \#<tab>\& where <tab> stand for tab key

Use rectangle and format string, like ‘rectangle-number-lines’ in Emacs24. – rubikitch

  (eval-when-compile (require 'cl))
  (defun number-rectangle (start end format-string from)
    "Delete (don't save) text in the region-rectangle, then number it."
    (interactive
     (list (region-beginning) (region-end)
           (read-string "Number rectangle: " (if (looking-back "^ *") "%d. " "%d"))
           (read-number "From: " 1)))
    (save-excursion
      (goto-char start)
      (setq start (point-marker))
      (goto-char end)
      (setq end (point-marker))
      (delete-rectangle start end)
      (goto-char start)
      (loop with column = (current-column)
            while (<= (point) end)
            for i from from   do
            (insert (format format-string i))
            (forward-line 1)
            (move-to-column column)))
    (goto-char start))

--

Print sequences with format string. – rubikitch

  (defun count-string-matches (regexp string)
    (with-temp-buffer
      (insert string)
      (count-matches regexp (point-min) (point-max))))
  (defun seq (format-string from to)
    "Insert sequences with FORMAT-STRING.
  FORMAT-STRING is like `format', but it can have multiple %-sequences."
    (interactive
     (list (read-string "Input sequence Format: ")
           (read-number "From: " 1)
           (read-number "To: ")))
    (save-excursion
      (loop for i from from to to do
            (insert (apply 'format format-string
                           (make-list (count-string-matches "%[^%]" format-string) i))
                    "\n")))
    (end-of-line))

CategoryEditing