BackToIndentationOrBeginning

MWIM (Move Where I Mean)

There is mwim package (available on MELPA) that tries to combine the ideas and the code from this page: it provides commands for moving to the beginning/end of “code or line” (or “line or code”).

Back to indentation or beginning of line

This function switches the point to before the first non-space character, or if the point is already there it goes to the beginning of the line. Binding “Home” to this function turns it into a very nice DoWhatIMean key.

 (defun back-to-indentation-or-beginning () (interactive)
   (if (= (point) (progn (back-to-indentation) (point)))
       (beginning-of-line)))

If you rather it go to beginning-of-line first and to indentation on the next hit use this version instead.

 (defun back-to-indentation-or-beginning ()
   (interactive) 
   (if (bolp) (back-to-indentation) (beginning-of-line)))

You can bind to “Home” key using

 (global-set-key (kbd "<home>") 'back-to-indentation-or-beginning)

Command ‘beginning-or-indentation’ in Lisp:misc-cmds.el does the same thing. In addition, repeated calls back up to previous line beginnings:

  (defun beginning-or-indentation (&optional n)
    "Move cursor to beginning of this line or to its indentation.
  If at indentation position of this line, move to beginning of line.
  If at beginning of line, move to beginning of previous line.
  Else, move to indentation position of this line.
  With arg N, move backward to the beginning of the Nth previous line.
  Interactively, N is the prefix arg."
    (interactive "P")
    (cond ((or (bolp) n)
           (forward-line (- (prefix-numeric-value n))))
          ((save-excursion (skip-chars-backward " \t") (bolp)) ; At indentation.
           (forward-line 0))
          (t (back-to-indentation))))

Here comes a function which goes to the indention, begining of line or begining of buffer:

 (defun my-home () (interactive)
   "If at the begining of line go to begining of buffer.
 If at the indention go to begining of line.
 Go to indention otherwise."
   (if (bolp) (beginning-of-buffer)
     (skip-chars-backward " \t")
     (unless (bolp) (back-to-indentation))))

– mina86

There is a subtle problem with the way this interacts with cua-mode: shift-home no longer selects anything. It should alternate between expanding the shifted selection to the beginning of the line and the beginning of indentation. If home is pressed without shift, the current shifted selection should be deselected, but not if the selection was started with ctrl-space. I was able to get this behavior with a bit of hacking, but it depends on an internal variable, cua--last-region-shifted, and doesn’t work in the simpler shift-select-mode since that variable won’t exist. Hopefully someone can improve upon this further:

  (defun back-to-indentation-or-beginning ()
    (interactive)
    (if this-command-keys-shift-translated
        (unless mark-active (push-mark nil t t))
      (when (and mark-active cua--last-region-shifted)
        (deactivate-mark)))
    (if (= (point) (progn (back-to-indentation) (point)))
        (beginning-of-line)))

After writing the above function, I now realize that there’s a simple way to tell cua-mode about back-to-indentation-or-beginning:

  (put 'back-to-indentation-or-beginning 'CUA 'move)

This seems to work perfectly. It doesn’t solve the problem for shift-select-mode without cua-mode, however.

There is a version of this for in ourcomments-util.el in nXhtml that also handles wrapped line. If on a wrapped part it first goes to the start of the wrapped line. Note: Requires the not yet released Emacs 23. (There is also a similar function for end of line.)

I’ve got this that does the standard functionality except if the cursor is at the beginning of the line and the line is empty it will insert the indentation and move to it.

 (defun genius-beginning-of-line ()
   "Move point to the first non-whitespace character on this line.
 If point was already at that position, move point to beginning of line.
 If line is empty, indent the line relative to the preceding line.
 "
   (interactive "^")
   (let ((oldpos (point)))
     (back-to-indentation)
     (and (= oldpos (point))
          (progn (move-beginning-of-line nil)
                 (when (=
                        (line-beginning-position)
                        (line-end-position))
                   (save-excursion
                     (indent-according-to-mode)))))))

End of code (before comments) or end of line

Similarly to move to end of code but not end of comments

 (defun end-of-code-or-line (arg)
   "Move to end of line, or before start of comments depending on situation.
 Toggle back and forth positions if we are already at one.
 Comments are recognized in any mode that sets syntax-ppss
 properly."
   (interactive "P")
   (when (catch 'bol 
           (let ((start (point))
                 (bol (save-excursion
                        (beginning-of-line)
                        (point)))
                 (eol (progn (move-end-of-line arg) (point))))
             (while (point-in-comment)
               (backward-char)
               (when (= (point) bol)
                 (throw 'bol t)))
             (throw 'bol (and (not (= eol start)) (>= start (point))))))
     (move-end-of-line arg)))
 (global-set-key (kbd "<end>") 'end-of-code-or-line)

Or to reverse the order, going to end of line first:

 (defun end-of-line-or-code (arg)
   "Move point to end of line. If already there, move back to end of code.
  By 'end of code' we mean before a possible comment. Comments are recognized
  in any mode that sets syntax-ppss properly."
   (interactive "P")
   (let ((eol (save-excursion
                (move-end-of-line arg)
                (point)))
         (bol (save-excursion
                (beginning-of-line)
                (point))))
     (cond ((= (point) eol)
            (move-end-of-line arg)
            (while (and (not (= bol (point)))
                        (point-in-comment))
              (backward-char))
            (skip-chars-backward " \t"))
           (t (move-end-of-line arg)))))
    (global-set-key [end] 'end-of-line-or-code)

CategoryEditing CategoryIndentation LineCommands.