Emacs Lisp list-matching-lines Improvement
A short elisp tutorial.
Previously, we discussed Emacs: List/Delete Matching Lines, Sort Lines. We discussed writing a convenient version of list-matching-lines that uses the current word, or text selection. Here's a solution.
(defun list-matching-lines2 () "Show lines in the current buffer matching current word or text selection. This command is the similar to `list-matching-lines'. The differences are: • The input of this command is the current word. • If there is a text selection, that is used as input. • The input is plain text, not regex." (interactive) (let (meat pos1 pos2 bds) (if (and transient-mark-mode mark-active) (setq pos1 (region-beginning) pos2 (region-end)) (progn (setq bds (bounds-of-thing-at-point 'symbol)) (setq pos1 (car bds) pos2 (cdr bds)))) (setq meat (buffer-substring-no-properties pos1 pos2)) (list-matching-lines (regexp-quote meat)) ) )
The key to understand our implementation is understanding emacs's concept of region, transient-mark-mode, text selection. If you are confused, see: What's Region, Active Region, transient-mark-mode?.
Our code above also shows a practical idiom, of automatically using the current active region as input. For more idioms, see: Elisp: How to Write Commands.
Note that starting with emacs 23, transient-mark-mode is on by default, and many commands automatically take the current text selection as input if there's one. [see Emacs 23.1 Features (released 2009-07)] So, our new list-matching-lines is a improvement, but not perfect. To make it a perfect candidate for emacs, our new version should use text selection if there's one, but if there's no text selection, it should still prompt user to enter a input, and the default input should be the current word. Because, otherwise there's no way for user to enter arbitrary input.
Also, our version's input is plain text, not regex. Plain text is probably more often used than regex, but regex is certainly more powerful. It would be a loss if there's no way to use regex. So, if we plan to incorporate our version into emacs, we probably need to think about either creating a new command, or incorporate it as part of list-matching-lines, with a option that interpret the input as string and not regex. To be compatible with overall design of emacs, we might look into what other emacs's commands do when the functionality needs to have both string and regex versions. I think in such situations, emacs usually provides 2 different commands.