9

The default of key binding C-a/C-e is only for one thing, move to the beginning/end of the line, is there any package that can make Emacs act like this:

  1. If I'm not at the end of a line, C-e will go to the end of the line, otherwise, go the end of next line
  2. If I'm not at the beginning of a line, C-a will go to beginning of the line, otherwise go to the beginning of the next line.

The point is you can just keep hitting C-a/e to go to beginning/end of every line without moving your finger to reach C-n/p.

And with a prefix(C-u) they will go to the beginning/end of line in the opposite direction.

CodyChan
  • 2,599
  • 1
  • 19
  • 33
  • In a comment to an answer below @kaushalmodi points out that I may have mis-interpreted your question. Do you want `C-a` to go "up" and `C-e` to go "down"? In other words, is the meaning of "next line" the same in items 1 and 2? – Constantine Nov 20 '14 at 15:19
  • @Constantine I actually did think about the "`C-a` to up, and `C-e` to down" problem when I posted this question, but then I thought if someone gave `defun` solution like you, anyone would know what to do if he likes `C-a` to "up".. – CodyChan Nov 24 '14 at 15:17
  • OK; I think it is still worth fixing. I'll update the answer -- it's just a one-line change. – Constantine Nov 24 '14 at 15:20

3 Answers3

11

I don't know of a package that would enable this behavior, but here's one way to do it.

Press C-h k C-a to discover that C-a is bound to move-beginning-of-line; this is the function we need to modify --- or just use to implement the "moving to the beginning" part. Similarly, with C-h k I can find forward-line, which will be used to move up/down.

To be able to bind a function to a key we need to make it a command, so we need to use the interactivespecial form (see Using Interactive). To take the C-u prefix argument we need the "P" code character.

Combining this with bolp (check if at the beginning of a line) and eolp (check if at an end of a line), we can write:

(defun my-move-beginning-of-line (arg)
  (interactive "P")
  (when (bolp) (previous-line (if arg -1 1)))
  (move-beginning-of-line nil))

(defun my-move-end-of-line (arg)
  (interactive "P")
  (when (eolp) (forward-line (if arg -1 1)))
  (move-end-of-line nil))

Now we can re-bind C-a and C-e to call these:

(global-set-key [remap move-beginning-of-line] #'my-move-beginning-of-line)
(global-set-key [remap move-end-of-line] #'my-move-end-of-line)

Alternatively, one could add advice to move-beginning-of-line and move-end-of-line.

Constantine
  • 9,072
  • 1
  • 34
  • 49
  • This is a really good explanation and an elegant solution. There's a typo in the `my-move-beginning-of-line` function.. Should it be `(previous-line (if arg -1 1))` or `(forward-line (if arg 1 -1))` ( 1 and -1 switched)? – Kaushal Modi Nov 20 '14 at 12:06
  • @kaushalmodi: in the question both items 1 and 2 say "next line", which I interpreted as "down". So, let's ask the question's author! :-) – Constantine Nov 20 '14 at 15:16
  • Ah, I added my own assumption to the OP's question. You are right, he does specify to go to the *next* line when using either `C-a` or `C-e`. – Kaushal Modi Nov 20 '14 at 15:32
  • @kaushalmodi: It turns out you were right! I updated the answer to make `C-a` go "up". – Constantine Nov 24 '14 at 15:23
8

Library misc-cmds.el has long had this feature.

These are the relevant commands, and suggested key bindings (these bindings are made in setup-keys.el).

(cond ((fboundp 'move-beginning-of-line)
       (substitute-key-definition 'move-beginning-of-line 'beginning-of-line+ global-map)
       (substitute-key-definition 'move-end-of-line 'end-of-line+ global-map))
      (t
       (substitute-key-definition 'beginning-of-line 'beginning-of-line+ global-map)
       (substitute-key-definition 'end-of-line 'end-of-line+ global-map)))
(when (boundp 'visual-line-mode-map)
  (define-key visual-line-mode-map [remap move-beginning-of-line] nil)
  (define-key visual-line-mode-map [remap move-end-of-line]       nil)
  (define-key visual-line-mode-map [home] 'beginning-of-line+)
  (define-key visual-line-mode-map [end]  'end-of-line+)
  (define-key visual-line-mode-map "\C-a" 'beginning-of-visual-line+)
  (define-key visual-line-mode-map "\C-e" 'end-of-visual-line+)))

Here is what C-h f end-of-line+ says, as one example:

end-of-line+ is an interactive compiled Lisp function in
`misc-cmds.el'.

It is bound to C-e, end.

(end-of-line+ &optional N)

Move cursor to end of current line or end of next line if repeated.
This is similar to `end-of-line', but:
  If called interactively with no prefix arg:
     If the previous command was also `end-of-line+', then move to the
     end of the next line.  Else, move to the end of the current line.
  Otherwise, move to the end of the Nth next line (Nth previous line
     if N<0).  Command `end-of-line', by contrast, moves to the end of
     the (N-1)th next line.
Drew
  • 75,699
  • 9
  • 109
  • 225
1

The following two functions perform the desired actions.

(defun move-beginning-of-line-or-previous (&optional pre)
  "Move to the start of the line. If we are already at the start
of the line, move to the start of the previous line or, if called 
with a prefix argument, the next line."
  (interactive "P")
  (let* ((pos (point)))
    (move-beginning-of-line nil)
    (if (= (point) pos)
        (if pre
            (next-line)
          (previous-line)))))

(defun move-end-of-line-or-next (&optional pre)
  "Move to the end of the line. If we are already at the end of
the line, move to the end of the next line or, if called with a 
prefix argument, the previous line."
  (interactive "P")
  (let* ((pos (point)))
    (move-end-of-line nil)
    (if (= (point) pos)
        (if pre
            (previous-line)
          (next-line)))))
Patrick Steele
  • 1,105
  • 9
  • 10