Xah Lee, 2008-12-09, 2009-08-19
Emacs has a command to select the current word, mark-word, with default shortcut of 【Alt+@】. Selecting the current word is a frequently needed operation. However, emacs's mark-word command is inconvenient. It does not select the whole word. It only select from the cursor position to the end of the word. For example, if your word is “transmission”, and your cursor is at the “m”, then it will select just “mission”. To select the whole word, you need to move the cursor to the beginning of the word first.
Also, mark-word has a feature that if you repeat the command, then it extend the selection to the next word to the right. But again, you need first to move the cursor to the start position you want. Emacs has in fact a whole system of selecting text:
“M-@”
Set mark after end of next word (“mark-word”). This command and
the following one do not move point.
“C-M-@”
Set mark after end of following balanced expression (“mark-sexp”).
“M-h”
Put region around current paragraph (“mark-paragraph”).
“C-M-h”
Put region around current defun (“mark-defun”).
“C-x h”
Put region around the entire buffer (“mark-whole-buffer”).
“C-x C-p”
Put region around current page (“mark-page”).
(info "(emacs) Marking Objects")
Here is suggestion of a scheme that may replace or supplement the above system.
We create a command that select the whole word. When repeated, it should select the next larger syntactic unit. In human languages, that would be sentence, then paragraph, then whole buffer. In computer languages, the sequence would be: current identifier or token, current expression, current construct (or line), current block or defun. If the lang is lisp, this simply means extending the selection to the next outer parens. For a illustrated example of this, see: A Text Editor Feature: Extend Selection By Semantic Unit.
Here's the code that implements the above idea for lisp (or any simply nested syntax):
;; by Nikolaj Schumacher, 2008-10-20. Released under GPL. (defun semnav-up (arg) (interactive "p") (when (nth 3 (syntax-ppss)) (if (> arg 0) (progn (skip-syntax-forward "^\"") (goto-char (1+ (point))) (decf arg)) (skip-syntax-backward "^\"") (goto-char (1- (point))) (incf arg))) (up-list arg)) ;; by Nikolaj Schumacher, 2008-10-20. Released under GPL. (defun extend-selection (arg &optional incremental) "Select the current word. Subsequent calls expands the selection to larger semantic unit." (interactive (list (prefix-numeric-value current-prefix-arg) (or (and transient-mark-mode mark-active) (eq last-command this-command)))) (if incremental (progn (semnav-up (- arg)) (forward-sexp) (mark-sexp -1)) (if (> arg 1) (extend-selection (1- arg) t) (if (looking-at "\\=\\(\\s_\\|\\sw\\)*\\_>") (goto-char (match-end 0)) (unless (memq (char-before) '(?\) ?\")) (forward-sexp))) (mark-sexp -1)))) (global-set-key (kbd "M-8") 'extend-selection)
In the above, 【Alt+8】 is assigned to the command, because selecting whole word is a commonly needed operation, and 【Alt+8】 is one key less than 【Alt+@】 【Alt+Shift+2】, and the finger used, the 3rd finger pressing on 8, is also easier than the 4th finger press 2.
Pressing 【Alt+8】 will select the current whole word. Press it again will extend the selection to the next outer parens. The above code effectively does extend selection to higher level of semantic unit for lisp or simply nested syntax. It does not work in more complicated nesting, such as HTML/XML. For the code to work in other langs like Java, Perl, Python, XML, it'll need some more work.
Another frequently needed operation is to select text inside straight 'single' or "double" quotes. This is especially frequently needed for string datatype in popular languages such as C, C++, Java, JavaScript, Perl, Python, PHP, HTML/XML. Ideally, the extend-selection above should do it, by simply invoking the command twice, or just once when cursor is on the quote, but since the above code does not work outside of lisp syntax, so here's a additional command as a workaround to do the frequently needed operation of selecting text inside quote pairs.
(defun select-text-in-quote () "Select text between the nearest left and right delimiters. Delimiters are paired characters: ()[]<>«»“”‘’「」, including \"\"." (interactive) (let (b1 b2) (skip-chars-backward "^<>(“{[「«\"‘") (setq b1 (point)) (skip-chars-forward "^<>)”}]」»\"’") (setq b2 (point)) (set-mark b1) ) ) (global-set-key (kbd "M-*") 'select-text-in-quote)
With both of the above defined, pressing 【Alt+8】 will select whole word (or extend current selection). Pressing 【Alt+Shift+8】 (that is: 【Alt+*】) will select the text inside matching quotes.
This extend-selection scheme with transient-mark-mode on, should simplify and replace the functionality of mark-word, mark-sexp, mark-paragraph, mark-defun. With just one command to remember, and more efficient to operate. The mark-whole-buffer can be replaced by a shortcut 【Ctrl+a】 to be compatible with modern UI standard, and mark-page is today rather obsolete because it depends on page marker char “^L” (ascii 12), which is not used in most languages but only in some older emacs lisp files.
The above suggestions are implemented in Ergoemacs at ErgoEmacs Keybinding.