Emacs Redux

Return to the Essence of Text Editing

Smarter Navigation to the Beginning of a Line

| Comments

In Emacs there are two essential commands when you have to go the beginning of a line - move-beginning-of-line(bound to C-a) and back-to-indentation(bound to M-m). The first takes you to the first column of a line and the latter takes you the first non-whitespace character on a line.

Generally, I find back-to-indentation more useful, but occasionally it makes sense to go to the real beginning of a line as well. What doesn’t make sense is to have to think all the time what command is the most appropriate in a particular situation. Wouldn’t it be great if C-a initially took you to the first non-whitespace char(as back-to-indentation does) on a line, and if pressed again took you to the actual beginning of the line? It would be! Let’s get it done:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(defun smarter-move-beginning-of-line (arg)
  "Move point back to indentation of beginning of line.

Move point to the first non-whitespace character on this line.
If point is already there, move to the beginning of the line.
Effectively toggle between the first non-whitespace character and
the beginning of the line.

If ARG is not nil or 1, move forward ARG - 1 lines first.  If
point reaches the beginning or end of the buffer, stop there."
  (interactive "^p")
  (setq arg (or arg 1))

  ;; Move lines first
  (when (/= arg 1)
    (let ((line-move-visual nil))
      (forward-line (1- arg))))

  (let ((orig-point (point)))
    (back-to-indentation)
    (when (= orig-point (point))
      (move-beginning-of-line 1))))

;; remap C-a to `smarter-move-beginning-of-line'
(global-set-key [remap move-beginning-of-line]
                'smarter-move-beginning-of-line)

The command will keep toggling between the first non-whitespace char and the beginning of the line when invoked.

Here’s a visual example(| is the cursor):

1
2
3
4
5
6
7
8
This is a short example
    text|
    # pressing C-a once
   |text
    # pressing C-a again
|   text
    # pressing C-a again
   |text

This functionality could also be implemented with defadvice, but I tend to avoid their use.

smarter-move-beginning-of-line is part of Prelude.

P.S. The credit for this tip goes to Sebastian Wiesner.

Comments