programming musings
17 Jan 2007

eval and replace anywhere

Being a living Elisp virtual machine, Emacs naturally provides the ability to evaluate any Elisp expression anywhere. Just put the cursor right after the expression to be evaluated and press C-xC-e: the result appears in the mini-buffer. I use this continuously, for instance while reading about a variable to know its value. For instance, imagine i see this line in one of my files:

(setq planner-project "planner")

and want to know if planner-project has been modified. I just need to put my cursor right after the variable name and get its value with C-xC-e.

As i said, C-xC-e works in any (well, almost) buffer. Imagine you're writing a note and need to perform an arithmetic operation: you could write something like

Yesterday I spent (+ 2234.34 3423.4 (* 12.0 12.2) 10) dollars at ...

put the cursor just before 'dollars', press the eval shortcut, and see the result of the arithmetic operation in the mini-buffer. You memorize it, delete the Elisp expression… hmm, wait, this should be easier, shouldn't it? What we want is Emacs to eval and replace the expression for us.

I'm sure that you already know what comes next :-) As it happens, this time i didn't need to write the Elisp snippet myself: i stole it instead from Jorgen "forcer" Schäfer's configuration file:

(defun fc-eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (prin1 (eval (read (current-kill 0)))
         (current-buffer)))

Complemented with the mandatory shortcut:

(global-set-key (kbd "C-c e") 'fc-eval-and-replace)

this little gem has probably the highest usefulness to lines of code ratio in my Elisp toolbox. Give it a try!

Update: pdq notes in a comment that, if the expression to be evaluated is malformed (like, say, (+1 1)) it gets deleted, and it would be nice if it wouldn't. A quick way to get this functionality is to catch errors in eval and undo the killing in a generic error handler. To wit:

(defun fc-eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))
Tags: emacs
Other posts
Creative Commons License
jao.io by jao is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.