reddit / emacs

Elisp: Go to outmost closing parentheses (for eval-last-sexp)

pragmat1c1 · 2022-05-08 17:41
When I write Emacs Lisp code, many times my cursor is within a symbolic expression (sexp), and I'd like to evaluate it. So I navigate to the end of the symbolic expression, position my cursor behind the closing paren, hit "C-x C-e" and evaluate the sexp. Is there an easier way to navgiate to the last closing paren of the sexp to evaluate it? I came up with this, to naviget to the first closing paren, but apparently it does not accomplish what I need: ``` (defun ugt-eval-last-sexp () "Eval last sexp and save result to kill-ring." (interactive) (let (result) (search-forward ")") ;; (forward-sexp) does not work for nested sexps (setq result (eval-last-sexp nil)) (message (format "Evaluated to: %s" result)))) (define-key emacs-lisp-mode-map (kbd "s-e") 'ugt-eval-last-sexp) ```
ndamee · 2022-05-08 18:28
Is it a top level expression? Then: C-M-x "Evaluate the top-level form containing point, or after point."
pragmat1c1 · 2022-05-08 18:40
You mean "eval-defun"? Does not work here: ``` (- 50<|> (+ 5 5) (* 5 7)) ``` when the cursor is at `<|>`.
SlowValue · 2022-05-08 18:48
I second `C-M-x`! Anyway, some time ago, I wrote this little function, maybe it helps (defun my-backward-up-sexp (a) "my backwards up sexps. prefix command interpretation: 0 → to beginning of all nested sexps - → to end of all nested sexps x|+x → x-times go back out of sexps to beginning -x → x-times go out of sexps to end universal-command interpreted as +x" (interactive "P") (condition-case err (let ((arg) (loop)) (cond ((null a) ;; back-up once (setq arg -1 loop nil)) ((eq a '-) ;; up to end of all sexps (setq arg 1 loop t)) ((numberp a) (cond ((= a 0) ;; back-up to begin of all sexps (setq arg -1 loop t)) (t (setq arg (- a) ;; do it a times loop nil)))) (t (setq arg (- (car a)) ;; interpret `universal-command' loop nil))) (while (progn ;; do-while loop (up-list arg t t) loop))) (scan-error ;; stay quiet nil)))
SlowValue · 2022-05-08 18:50
It works, just look at the echo area, it states > 5 (#o5, #x5, ?\C-e)
Phil-Hudson · 2022-05-08 19:21
As others have said, `eval-defun` (`C-M-x`) is what you're after. Just to add that the way to move point to the closing paren is `end-of-defun` (`C-M-e`) and conversely `beginning-of-defun` (`C-M-a`).
pragmat1c1 · 2022-05-08 19:28
Thanks, that did the trick apparently.
bhrgunatha · 2022-05-08 19:31
> [“If you think paredit is not for you then you need to become the kind of person that paredit is for.”](https://github.com/georgek/paredit-cheatsheet) paredit has a lot of functions that are useful for composing your own utilities.
thetemp_ · 2022-05-08 19:39
Not sure how you're doing it now, but assuming you're using a standard QWERTY layout, "C-M-- C-M-u" only requires you to hold Ctrl+Alt with your left hand while tapping 2 keys with your right. Another way is to do "C-M-u C-M-f". That requires moving your right hand to the middle of the keyboard, but it might be easier than the other method if you don't like using your pinky. The first method also works on Colemak. Unfortunately, on Dvorak I have to move my right hand across the keyboard with either method, but it's still not bad. EDIT: Hmm. This is a tangent, but I just realized I can press "C-M--" (or "C--", or "M--") in Dvorak using just the right hand. Normally, I wouldn't press modifier and character keys with the same hand, but this might be worthy of an exception for rare occasions.
pragmat1c1 · 2022-05-08 19:51
This! `C-M-e` and `C-M-a` is great! Thought that was only for "defun" forms, but it works for any sexp! Thanks!
Phil-Hudson · 2022-05-08 20:46
You're very welcome.
SlowValue · 2022-05-08 21:10
`paredit` is too limited. There are reasons, why so many flavors (`smartparens`, `lispy`, `puni`, and more) of its functionality are in existence.
KDallas_Multipass · 2022-05-09 02:26
While we're on the topic, I often find myself at the end of a sexp and need to add a new layer around it, like if I'm going to start an addition. I'm already at the end I need to be at but I don't know a good way of wrapping a paren group backwards. So far all I can find is a two-step process of opening a group and backwards slurping
bhrgunatha · 2022-05-09 04:13
In fact I agree - not least working strictly only with parentheses/strings. Sadly `smartparens` and `lispy` have never clicked with me. I know, I know... *I need to become the kind of person...* `puni` looks more interesting though, so I'll give that a try, thanks for the suggestions. Have you had success with any of the alternatives? ---- 1. [smartparens](https://github.com/Fuco1/smartparens) 1. [lispy](https://github.com/abo-abo/lispy) 1. [puni](https://github.com/AmaiKinono/puni)
onetom · 2022-05-09 05:53
yeah, I do such wrapping operations all the time in Cursive. Wrapping happens by pressing Cmd+<left side of a delimiter-pair>, so for parens, it's Cmd-Shift-9. If I do it at the end of a form, it still works and then I can jump inside the beginning of the newly inserted parens with Ctrl-m, which jumps to the matching paren. It works, because the cursor is still at the end of the wrapped sexp, so the outside of the opening side of that is exactly the position, where I need to type the wrapping function name. it works in Ctrl-m, Cmd-( order too. so in Emacs, that would be C-M-b, insert paren pair, then slurp, but there is no slurp in stock Emacs and inserting delimiter pairs is not on by default. however! if you DO turn on electric-pair-mode, then you can, C-M-b, C-M-SPC (mark-sexp) to select the expression you want to wrap and then left-paren will wrap, because you have an active region.
onetom · 2022-05-09 05:53
it would have been nice, if I can just learn this from somewhere very early on... maybe it's in the manual, or even the tutorial, but I find it painfully boring to read through so much stuff, which I don't need (yet) or already know... I think it's a bad habit not to read docs systematically upfront, because we are spoiled by newer generations of software, which have fewer, simpler operations, but somehow feel more intuitive, more discoverable. we seek too much instant gratification, I guess... and I'm saying it as a 45 year old, who did spend the time to read the Windows 3.1 Help about keyboard shortcuts and whatnot within the 1st year of using it.
onetom · 2022-05-09 06:02
it's a bad habit to jump away from the editing position, just to eval the top-level form you are inside. it's likely, that you will want to continue editing and eval again, in which case I don't know how can you jump back efficiently to where u come from, so the best is if you don't have to move at all. (in vim/evil u have C-i/o and Emacs has something like pop-mark, but I found it to be unintuitive. I remember someone even made a package, which revised many built-in operations, so they also leave a mark in the mark-ring, or what is it called.) I'm seeing this habit even from seasoned Emacs users and I just can't understand how they don't fell the pain of going to the end of defun, then coming back to the edit point. it must be some psychological phenomena in the background :)
onetom · 2022-05-09 06:28
I keep forgetting about these negative-argument variants of operation. Thanks for mentioning them! We should really have some tutorial video, which is geared towards lisp editing, using the built-in facilities, so newcomers feel less resistance towards hacking on their configs and learning elisp more. I for example, learnt Paredit via a Sublime package maybe 8-9 years ago, 2-3 months after I started learning Clojure, so now I'm very fluent using it via Cursive in IntelliJ, which has different bindings, then the classical/original paredit.el. Played a lot with Parinfer too, both v2 and v3, which unified the indent and paren modes, but just couldn't figure out how to use it precisely. Then I'm into my 3rd year of my Emacs journey and I still couldn't edit Clojure code as fast as in Cursive, though I'm trying to practice regularly... Started trying smartparens too, then lispy, but it just requires so much up-front time to learn and practice and there are always annoying surprises in them. :( In contrast, I don't even use all of Cursive's structural editing operations, so it's a lot easier to teach it to my colleagues too. Many of them are not bound to keys by default and I couldn't figure out what would be a good binding for them, especially when I would use them rarely. It feels like Cursive's paredit is has a great balance between versatility and the mental burden of mastering many shortcuts. I'm starting to understand that Emacs also has a pretty good balance, but I'm not sure why exactly took it so long for me to grasp that... raise-sexp should really have a binding by default though :)
Lispwizard · 2022-05-09 08:35
c-m-e pushes the mark, so you can quickly go back to where you were before you invoked it with c-u c-<space>.
SlowValue · 2022-05-09 10:30
After multiple years of `smartparens` use, I switched to `puni`. `puni` is more incomplete as `smartparens` and needs more tuning, which I haven't done yet. But `puni` seems more light and more modifiable as `smartparens`. I wouldn't like to work without any such functionality anymore. I didn't like the other alternatives for various reasons.