Editor Commands

Sat, 26 Nov 2022

Editor Commands

A friend asked how I think about my editor commands (Emacs), mnemonics or something else. Having used the same editor for 25 years, I mostly don’t think about them at all. Before I can formulate a notion of what I want, it happens, and only my fingers know how it happened. In fact, when attempting to add items to this list, I often had to repeat the action and pay attention to the key presses I made since I don’t actually know what commands I typed.

This post reports my logging of every command I noticed myself using over a period of four days, resulting in “92 commands I often use” or “commands I like for an editor to have”.

For those unfamiliar with Emacs, it is customary in Emacs documentation to use an “M” symbol for the “meta” key. On a modern keyboard this means holding ALT or pressing an ESC prefix. Below I will use M- when I use ALT and type ESC when I use the escape key (though one could use them interchangeably).

Any commands which are customized include the code in a footnote.

File / buffer management

Buffers are loaded files.

Key Action  
C-x C-f Open file standard
C-x C-f Save file standard
C-M-q Close file (but just bury *scratch* buffer)1 custom
F7 Bury buffer (bury-buffer) custom
C-M-b Toggle to last buffer2 custom
C-x b Switch to buffer standard

Window management

Emacs has some odd terminology here. It calls the app (all under one title bar) a “Frame” and the frame can be split into “Windows”. This is likely reverse what you would call it these days. Emacs has the excuse of existing before terminology was standardized. Here I am using “window” in the emacs sense.

Key Action  
C-l Center point in window standard
C-x 3 Split window horizontally standard
C-x 2 Split window vertically standard
C-x 1 Close all but current split window standard
C-x 0 Close current split window standard
C-M-o Cycle through split windows3 custom

Emacs tracks a “mark” and a “point”. The point is the location of the cursor. The mark is a (typically hidden) location in the file which gets set and moved via various actions. The “region” is the content between the mark and the point.

Copied and cut text is saved to a “kill ring” allowing more than one thing to be in what is typically referred to as the clipboard.

I set (transient-mark-mode 0). There is always a mark active even if you can’t see it. Remembering where it is becomes second-nature when you run with transient mark mode disabled.

Key Action  
C-SPACE Set mark standard
C-x C-x Swap mark and point (moves cursor) standard
C-a Beginning of line standard
C-e End of line standard
HOME Set mark and move to beginning of buffer4 standard
END Set mark and move to end of buffer5 standard
ARROW Move by character or line up, down, left, right standard
C-ARROW Move by paragraph or block (typically to next blank line) up / down standard
C-ARROW Move by word left / right standard
C-s Interactive search standard
C-M-s Interactive search (regexp) standard
C-x C-g Go to line (goto-line)6 custom
C-x r s KEY Register set KEY (named copy buffer) standard
C-x r g KEY Register get KEY standard
XF86Launch1 Insert register key 17 custom
M-w Copy region (write) to kill ring standard
C-y Paste (yank) top item in kill ring (cursor at end) standard
C-u C-y Paste (yank) top item in kill ring (cursor at beginning) standard
M-y after a paste, cycle to next item in kill ring standard
M-d Cut (delete) from point to end of next word standard
C-DELETE Cut (delete) from point to end of next word standard
C-BACKSPACE Cut (delete) from point to beginning of previous word standard

In addition to the emacs copy/paste commands, I make use of the standard X11 “PRIMARY” selection. PRIMARY is set when text is selected (no key commands needed) and PRIMARY is pasted when middle-mouse is clicked. Emacs typically keeps PRIMARY and the top item of the kill ring in sync, but some apps do strange things to PRIMARY so they can occasionally fall out of sync and then I am sad until I copy/paste from emacs.


Key Action  
C-z Undo custom
M-SPACE Delete space before and after point leaving just one space standard
M-SUPER-SPACE Delete space after point8 custom
C-M-SPACE Merge following line9 custom
M-a M-a Trim trailing spaces on all lines10 custom
M-q Word-wrap paragraph standard
M-: Align (align-regexp) custom
ESC-% Interactive search and replace standard
C-t Transpose letters standard
M-t Transpose words standard
M-c Titlecase at point to end of word standard
M-l Lowercase to end of word standard
M-u Uppercase to end of word standard
SUPER-a Add 1 to number under cursor11 custom
SUPER-s Subtract 1 from number under cursor11 custom
C-c > Indent region by 412 custom
C-c < Outdent region by 412 custom
C-x TAB ARROW Indent/outdent region by 1 space per arrow press standard
C-x ( Start recording macro standard
C-x ) Finish recording macro standard
C-M-x Execute macro (call-last-kbd-macro) custom
M-x sort-lines Sort lines in region standard
ESC-$ Spellcheck word standard
C-M-$ Spellcheck region13 custom
M-> Comment current line and advance14 custom
M-< Uncomment current line and advance15 custom
TAB Indent current line16 standard
C-c i Insert emacs-template17 custom

Special / mode specific

Key Action  
C-g Cancel in-progress operation standard
ESC-# Calculator mode calc custom
mouse-1 On status bar “:”, change end-of-line in document standard
C-mouse-1 Buffer menu standard
down-mouse-3 imenu custom
M-x make-directory Create directory standard
C-c C-s Python mode: smart-insert call to super()18 custom
C-c / HTML mode: Close current tag standard

LaTeX mode

Key Action  
C-c C-c LaTeX mode: Compile document standard
C-c C-e LaTeX mode: Insert environment standard
C-c C-f C-t LaTeX mode: Insert typewriter font standard
C-c C-f C-s LaTeX mode: Insert slant font standard
C-c ] LaTeX mode: Close current environment standard
M-ENTER LaTeX mode: Insert \item after this one19 custom
C-c C-j LaTeX mode: \item here (prompt for key in description) standard

Org mode

Key Action  
C-ARROW Move bullet or list items up / down standard
C-ARROW Move bullet items in / out standard
TAB Outline folding standard
M-ENTER Start new list item here standard
SHIFT-ENTER OrgTbl Copy table value down standard
SHIFT-ARROW Modify date in schedule/deadline standard
SHIFT-ARROW Cycle list type (-, +, #, …) standard
C-c C-c Mark/unmark [ ] checkbox standard
C-c C-t d Mark recurring task done and advance the date standard
C-c - OrgTbl insert horizontal rule standard

Uncommon commands

These are things which came up during my logging period, but which are generally uncommon so wouldn’t be sorely missed if they weren’t available in my editor.

Key Action  
M-NUMBER CHAR Repeat a character NUMBER times standard
M-x align-current Pretty-align table in LaTeX mode standard

Unobserved commands

These are a few commands that I know I use fairly regularly, but they didn’t come up in the evaluation period.

Key Action  
C-x RETURN f Set output character encoding standard
C-u C-x = Describe character under cursor standard
M-c Switch to/from case-insensitive mode during a search standard

Wishlist commands

There are a handful of commands I keep in a cheat-sheet file that I wish I would learn and remember at times when they would be useful, but mostly I forget about them until I look at the sheet and think “Oh yeah, that would be useful sometimes”.

Key Action  
C-x r n KEY Set numeric register, use with C-x r i KEY and C-x r + KEY standard
C-x r SPC KEY Set positional register, use with C-x r j KEY standard
C-x r o Insert whitespace rectangle into region standard
C-x r M-w Copy a rectangular region standard
C-x r d Delete rectangular region standard
C-x r y Paste (yank) rectangular region standard
C-x r t Insert text into each line of a rectangular region standard
C-s C-w Search for word under point standard

  1. Close file (but just bury *scratch* buffer) – “*scratch*” is the default-opened buffer meant as a transient scratch space. I use persistent-scratch-filename and load-persistent-scratch to have a persistent scratch buffer that I never close.

    (lambda () (interactive) (if (string= (buffer-name) "*scratch*") (bury-buffer) (kill-this-buffer)))`

  2. Toggle to last buffer

    (lambda () (interactive) (execute-kbd-macro [24 98 return]))

  3. Cycle through split windows

    (lambda () (interactive) (other-window 1))

  4. Set mark and move to beginning of buffer

    (lambda nil (interactive) (set-mark (point)) (beginning-of-buffer))

  5. Set mark and move to end of buffer

    (lambda nil (interactive) (set-mark (point)) (end-of-buffer))

  6. Goto line: M-g M-g is the standard shortcut. Not sure why I never learned that one. 

  7. Insert register 1. My keyboards have special keys labeled simply “1”, “2”, “3”, … (not number keys and not F1, F2, … keys). They can emit all kinds of strange keycodes, XF86Launch1, s-mouse-1, … I map such keys to insert specific named registers. Typically, registers 49, 50, … (ASCII codes for 1, 2, 3, …) so the keys insert the same register as pressing C-x r g 1, C-x r g 2, ….

    (global-set-key [s-mouse-1] '(lambda () (interactive) (insert (get-register 49)))); [1] key

  8. Delete space after point

    (lambda () (interactive) (while (= (char-after) (string-to-char " ")) (delete-char 1)))

  9. Merge following line

    (lambda () (interactive) (end-of-line) (delete-char 1) (just-one-space))

  10. Trim trailing spaces on all lines. This is a cheat, but tends to be how I use it. I’ve bound M-a to toggle artist-mode which is an interesting mode that lets you draw ASCII shapes. Artist mode is a bit messy in that it leaves trailing whitespace on lines it interacts with. Therefore, when the mode exits it cleans up the file by removing trailing whitespace. Probably there is a direct command to trim trailing whitespace, but in principle this saves me a key binding (though its been years since I’ve used artist mode for its actual purpose). 

  11. Add/Subtract 1 to number under cursor

    (defun increment-buffer-value (&optional val)
      "increments number at current position in buffer"
      (interactive "p")
      (if (not val) (setq val 1))
      (while (and (char-before (point))
                  (not (string=
                      (replace-regexp-in-string "[0-9]" "." (char-to-string (char-before (point))))
                      (char-to-string (char-before (point))))))
      (if (and (char-after (point))
               (not (string=
                   (replace-regexp-in-string "[0-9]" "." (char-to-string (char-after (point))))
                   (char-to-string (char-after (point)))))
               (re-search-forward "[0-9]+" nil t))
          (replace-match (int-to-string (+ val (string-to-number (match-string 0))))))


  12. Indent / outdent region by 4

    (lambda (arg) (interactive "P") (indent-rigidly (region-beginning) (region-end) (or arg 4)))


  13. Spellcheck region

    (lambda () (interactive) (ispell-region (region-beginning) (region-end)))

  14. Comment current line and advance

    ; For each mode:
    (define-key html-mode-map "\M-\>" '(lambda () (interactive) (Dean-Quick-Comment "<!--" "-->")))
    (define-key perl-mode-map "\M-\>" '(lambda () (interactive) (Dean-Quick-Comment "#")))
    ; Helper function:
    (defun Dean-Quick-Comment (beg &optional end)
      (beginning-of-line) (insert beg " ")
      (end-of-line) (if (or (string-equal end "") (equal end nil)) nil (insert " " end))
      (forward-char 1)

  15. Uncomment current line and advance

    ; For each mode:
    (define-key html-mode-map "\M-\<" '(lambda () (interactive) (Dean-Quick-Delete-Comment "<!--" "-->")))
    (define-key perl-mode-map "\M-\<" '(lambda () (interactive) (Dean-Quick-Delete-Comment "#")))
    ; Helper function:
    (defun Dean-Quick-Delete-Comment (beg &optional end)
      (let ((end (or end "")) (Here (point)))
        (if (search-backward-regexp (concat "^[[:space:]]*" beg "[[:space:]]?") Here t) (replace-match ""))
        (if (search-backward-regexp (concat "[[:space:]]*" end "[[:space:]]*$") Here t) (replace-match ""))
      (forward-char 1)

  16. Indent current line. No electric indent (I.e., no auto-indent on return press)! Also, TAB should not move cursor when pressed in the middle of a line. I have no idea how much of this behavior is standard or customized by my settings. 

  17. Emacs-template. I have heavily tweaked how I interact with this mode in order to make it suitable for inserting snippets. The details and code release will have to wait for another blog post though. 

  18. Python mode: smart-insert call to super()

    (defun py-insert-super ()
      (let (method class args)
          (if (search-backward-regexp "^ *def +\\([a-zA-Z0-9_]+\\)( *self *\\(, *.*?\\)?):" nil t)
              (setq method (match-string 1)  args (replace-regexp-in-string "^, *" "" (or (match-string 2) "")))
          (if (search-backward-regexp "^ *class +\\([a-zA-Z0-9_]+\\)" nil t)
              (setq class  (match-string 1))
        (insert (format "super().%s(%s)\n" method args))

  19. LaTeX mode: Insert \item after this one

    (defun Deans-LaTeX-insert-item () (interactive)
      (if (search-forward-regexp "\\\\\\(item\\|end{\\|begin{\\)" nil t)
          (let ()
            (insert "\\item \n")
            (forward-char -1)
        (let ()
          (insert "\n\\item ")

Set Zero