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 |
Navigation / cut / paste
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.
Editing
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 |
-
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)))`
-
Toggle to last buffer
(lambda () (interactive) (execute-kbd-macro [24 98 return]))
-
Cycle through split windows
(lambda () (interactive) (other-window 1))
-
Set mark and move to beginning of buffer
(lambda nil (interactive) (set-mark (point)) (beginning-of-buffer))
-
Set mark and move to end of buffer
(lambda nil (interactive) (set-mark (point)) (end-of-buffer))
-
Goto line: M-g M-g is the standard shortcut. Not sure why I never learned that one. ↩
-
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
-
Delete space after point
(lambda () (interactive) (while (= (char-after) (string-to-char " ")) (delete-char 1)))
-
Merge following line
(lambda () (interactive) (end-of-line) (delete-char 1) (just-one-space))
-
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). ↩
-
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)))))) (backward-char)) (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)))))) )
-
Indent / outdent region by 4
(lambda (arg) (interactive "P") (indent-rigidly (region-beginning) (region-end) (or arg 4)))
-
Spellcheck region
(lambda () (interactive) (ispell-region (region-beginning) (region-end)))
-
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) (interactive) (beginning-of-line) (insert beg " ") (end-of-line) (if (or (string-equal end "") (equal end nil)) nil (insert " " end)) (forward-char 1) )
-
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) (interactive) (beginning-of-line) (let ((end (or end "")) (Here (point))) (end-of-line) (if (search-backward-regexp (concat "^[[:space:]]*" beg "[[:space:]]?") Here t) (replace-match "")) (end-of-line) (if (search-backward-regexp (concat "[[:space:]]*" end "[[:space:]]*$") Here t) (replace-match "")) (end-of-line) ) (forward-char 1) )
-
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. ↩
-
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. ↩
-
Python mode: smart-insert call to super()
(defun py-insert-super () (interactive) (let (method class args) (indent-for-tab-command) (save-excursion (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)) (indent-for-tab-command) ))
-
LaTeX mode: Insert \item after this one
(defun Deans-LaTeX-insert-item () (interactive) (if (search-forward-regexp "\\\\\\(item\\|end{\\|begin{\\)" nil t) (let () (beginning-of-line) (insert "\\item \n") (forward-char -1) (indent-for-tab-command) ) (let () (end-of-line) (insert "\n\\item ") (indent-for-tab-command) ) ) )