Saving match data in-between Elisp evals
22 Feb 2015This is a new feature I've added recently to lispy that's useful when debugging regex-related code.
The gist of it is that the match data is a single global object in Emacs.
So if you call string-match
with your C-x C-e, there's no
guarantee that e.g. match-beginning
will return the proper thing with another C-x C-e,
since any package running in your Emacs could mess with the match data (packages that use timers
or post-command hooks etc.).
After getting annoyed by this a few times, I've finally added a
fail-safe to e (lispy-eval
) and p
(lispy-eval-other-window
). Here's how it looks like:
(defvar lispy-eval-match-data nil)
(defun lispy--eval-elisp-form (form lexical)
"Eval FORM and return its value.
If LEXICAL is t, evaluate using lexical scoping.
Restore and save `lispy-eval-match-data' appropriately,
so that no other packages disturb the match data."
(let (val)
(fset '\, #'identity)
(set-match-data lispy-eval-match-data)
(setq val (eval form lexical))
(setq lispy-eval-match-data (match-data))
(fset '\, nil)
val))
There's also a little dance of ignoring comma operators in the rare
case when I want to eval inside a backquoted list. The two
functions that you can take away from this exercise are match-data
and set-match-data
which appropriately return and store a list of
integers. Keeping the string separate from the regex match is a neat
way to improve performance.