6

I am thinking of binding C-x C-e to a single command, which does eval-last-sexp if there is no selection or eval-region if there is a selection. This is what I have tried:

(defun my/eval()
(interactive)
(if (region-active-p) (eval-region region-beginning region-end)
(eval-last-sexp EVAL-LAST-SEXP-ARG-INTERNAL)))
(global-set-key (kbd "C-x C-e") 'my/eval)
Drew
  • 75,699
  • 9
  • 109
  • 225
godblessfq
  • 1,177
  • 8
  • 21

1 Answers1

11

First of all, a few stylistic recommendations. (Style is important in programming :-D) In Lisps, we use dashes as separators, so your function is better called my-eval, not my/eval:

(defun my-eval()
(interactive)
(if (region-active-p) (eval-region region-beginning region-end)
(eval-last-sexp EVAL-LAST-SEXP-ARG-INTERNAL)))
(global-set-key (kbd "C-x C-e") 'my-eval)

Now, Lisp code is bare syntax trees, so they have levels of nesting and proper indentation is very important, it helps to see how expressions are composed. Also, it's a good idea to have one empty line between top level forms:

(defun my-eval()
  (interactive)
  (if (region-active-p)
      (eval-region region-beginning region-end)
    (eval-last-sexp EVAL-LAST-SEXP-ARG-INTERNAL)))

(global-set-key (kbd "C-x C-e") 'my-eval)

Isn't it beautiful?

You can find out more about region-beginning and region-end with help of built-in help system: type C-h f region-beginning RET. Here we see that this is a function, actually. You call this function and it returns position of beginning of region. To call functions you place their names on the first position in a form:

(function-name arg1 arg2 ...)

Since region-beginning and region-end don't take arguments we write:

(defun my-eval()
  (interactive)
  (if (region-active-p)
      (eval-region (region-beginning) (region-end))
    (eval-last-sexp EVAL-LAST-SEXP-ARG-INTERNAL)))

Great. Now we only need to fix EVAL-LAST-SEXP-ARG-INTERNAL. As written you're trying to use value that symbol EVAL-LAST-SEXP-ARG-INTERNAL is bound to, but chances are it's not bound to any value, so you will get an error. You can read about first argument of eval-last-sexp using the same trick: C-h f eval-last-sexp RET. Documentation tells us how the argument is used, it's mainly used to handle various interactive details. We can preserve these behavioral details in my-eval this way:

(defun my-eval()
  (interactive)
  (if (region-active-p)
      (eval-region (region-beginning) (region-end))
    (call-interactively #'eval-last-sexp)))

This should do the trick. Note that when there is a region, eval-region won't print anything in the mini-buffer. If this is not the desired behavior, supply the print-flag argument:

(defun my-eval()
  (interactive)
  (if (region-active-p)
      (eval-region (region-beginning) (region-end) t)
    (call-interactively #'eval-last-sexp)))

(global-set-key (kbd "C-x C-e") #'my-eval)
Mark Karpov
  • 4,893
  • 1
  • 24
  • 53
  • 1
    `my/eval` is ok too. This originates in Clojure as far as I can tell, but in Emacs Lisp people often use it to mean that the definition is in a file `my.el`. I do this sometimes to mean that this is my addition to a library written by someone else, eg. `my/org-do-something` etc. – wvxvw Sep 05 '15 at 18:18
  • 1
    @wvxvw, Emacs Lisp is not Clojure. [Emacs Lisp conventions](https://www.gnu.org/software/emacs/manual/html_node/elisp/Coding-Conventions.html) should be used, they are written and easy to follow. Some people have written packages where `/` separator is used, and I consider it harmful because others think it's OK now. You can do whatever you want in your own config, but let's tell people what is generally accepted. For example, if you submit something for MELPA these days, Steve Purcell will politely note that `/` separator is not acceptable. – Mark Karpov Sep 05 '15 at 18:43
  • 1
    Try `find ~/.emacs.d/elpa -type f -exec grep --color -nPH -e 'defun [^\/]+\/[^\/]+' {} +` and see how many matches you get. I get around 300 hits. It's like with natural language: you cannot prevent it on such grounds (the rule was arbitrary in the first place). – wvxvw Sep 05 '15 at 18:46
  • 1
    @wvxvw, this is irrelevant. `-` is the recommended way, so this should be advised. You can try your search for hyphens too and see how many matches you get then compare the two numbers. – Mark Karpov Sep 05 '15 at 18:51
  • But I didn't say that hyphens are bad... – wvxvw Sep 05 '15 at 18:57
  • @wvxvw, well OK, if they are not bad why Clojure doesn't use them as namespace separators? Sometimes slashes, sometimes hyphens... Depends on taste and mood of programmer :-) – Mark Karpov Sep 05 '15 at 19:02
  • Clojure has modules, it uses slashes for modules and hyphens are just a way to write names composed from multiple names. – wvxvw Sep 05 '15 at 19:07
  • @wvxvw, Of course there are technical differences. But prefixes in Emacs Lisp serve the same purpose. So while Emacs Lisp doesn't have namespaces/modules why should we use two different styles of name composing? This discussion is waste of time, I see you have different point of view, so be it. – Mark Karpov Sep 05 '15 at 19:12
  • what is the purpose of the number sign (#) in front of the function name? according to this post (http://stackoverflow.com/questions/2701698/emacs-elisp-what-is-the-hash-pound-number-sign-octothorp-symbol-used-for), it looks to be unnecessary. – godblessfq Sep 06 '15 at 01:00
  • @godblessfq, you can ask a separate question about it. In short, yes it's unnecessary (especially before lambda, since it's macro that expands to `#'(lambda (...) ...)` anyway in modern Lisps), but this way I make it clear that I pass function, not just symbol (stylistic detail, again). – Mark Karpov Sep 06 '15 at 08:05
  • @godblessfq http://endlessparentheses.com/get-in-the-habit-of-using-sharp-quote.html – Kaushal Modi Oct 16 '15 at 10:57