Snarfing String Within Delimiters With One Defun
1 Executive Summary
I found that I frequently needed to snarf a string enclosed within delimiters, e.g., URLs in email messages <url>, bolded, italics and other styled text in org-mode etc. I first tried package ciel but found that it did not handle all the delimiters I wanted. However looking into it further revealed that emacs had all the tools needed to reduce the task to a single defun!
2 The Solution
Here is the solution I implemented at emacspeak-wizards-snarf-sexp. invoking this command with point on the opening delimiter snarfs the enclosed string into the kill-ring; an optional prefix arg clears it as well. The code below is the same as in the Emacspeak project, but with emacspeak-specific calls removed:
(defun snarf-sexp-contents (&optional delete) "Snarf the contents between delimiters at point. Optional interactive prefix arg deletes it." (interactive "P") (let ((orig (point)) (pair nil) (pairs ;;; The delimiter pairs: '((?< ?>) (?\[ ?\]) (?\( ?\)) (?{ ?}) (?\" ?\") (?' ?') (?` ?') (?| ?|) (?* ?*) (?/ ?/) (?- ?-) (?_ ?_) (?~ ?~))) (char (char-after)) (stab nil)) ;;; Syntax table we use (unless (setq pair (assoc char pairs)) ;;; Not on a delimiter (error "Point is not on a supported delimiter")) (setq stab (copy-syntax-table)) (with-syntax-table stab (cond ((= (cl-first pair) (cl-second pair)) ;;;Like quotes (modify-syntax-entry (cl-first pair) "\"" ) (modify-syntax-entry (cl-second pair) "\"" )) (t;;; Like parens (modify-syntax-entry (cl-first pair) "(") (modify-syntax-entry (cl-second pair) ")"))) (save-excursion;;; We have our sexp (forward-sexp) ;;; Will error out if delims dont match (cond (delete ;;; Clear sexp contents (kill-region (1+ orig) (1- (point)))) (t ;;; Copy sexp contents (kill-ring-save (1+ orig) (1- (point)))))))))
2.1 Key Take-Aways
- S-expressions are a key Emacs concept with extensive built-in support.
- S-expressions are determined by matching delimiters.
- Delimiters are defined by the syntax-table in effect.
- Emacs-lisp primitives let us define and manipulate temporary syntax-tables.
- Putting it all together, the underlying task of snarfing the contents within a pair of delimiters reduces to a few calls to the underlying primitives.