cider icon indicating copy to clipboard operation
cider copied to clipboard

cider-eval-list-at-point eval's outer sexp

Open bo-tato opened this issue 2 years ago • 4 comments

Expected behavior

On this code (println (+ 1 (* 2 3))) with the cursor anywhere in (* 2 3) we expect to eval 6, as I understand from: https://github.com/clojure-emacs/cider/pull/2881

This adds a new function cider-eval-list-at-point, that evaluates a list around point [as in: code delimited by the nearest pair of parens surrounding point]

Actual behavior

with the cursor anywhere from * 2 3) we get 7, from evaling (+ 1 (* 2 3)), and on the opening ( of (* 2 3) it evals the outer println

CIDER version information

;; CIDER 1.5.0 (Strasbourg), nREPL 1.0.0
;; Clojure 1.11.1, Java 17.0.5

Emacs version

28.1

Operating system

Ubuntu 22.04.1 LTS

JDK distribution

OpenJDK 64-Bit Server VM Temurin-17.0.5+8

bo-tato avatar Feb 02 '23 15:02 bo-tato

it seems this is something to do with evil mode, if I turn off evil mode cider-eval-list-at-point works as expected

bo-tato avatar Feb 04 '23 15:02 bo-tato

I found this thread talking about similar behaviour with evil/cider: https://www.reddit.com/r/emacs/comments/10f3eff/comment/j4wrt6t/

they link this source which is where evil is modifying the last-sexp behaviour: https://github.com/emacs-evil/evil/blob/8a05eb99c6ee60eb502a2c586fa2e771a513c417/evil-integration.el#L241-L251

so if you enable evil-move-beyond-eol then it disables that and cider-eval-list-at-point works as expected, but then it has the weird (for vimmers) behaviour of cursor moving one past the end of the line, and you need to position cursor one past what you want to evaluate

I "fixed" it for me by adding 1- in cider-eval-list-at-point:

    (goto-char (1- (cadr (cider-list-at-point 'bounds))))

obviously I'm not proposing making that change in cider as it'd break non-evil users. I'm new with emacs, maybe someone more experienced can suggest the right way to fix this or the right way for me to get the behaviour I want. basically I just want three shortcuts, with cursor on foo in (+ 1 (* 2 foo) 2) one will eval foo: currently I have set to cider-eval-last-sexp one will eval (* 2 foo): currently I have set to cider-eval-list-at-point with this hacky 1- patch and one will eval base form, set to cider-eval-defun-at-point also the one other behaviour I miss from vim was be able to eval mark, so if I'm editing some function, and have some code that calls into the function, I can mark the code that calls the function, and then eval mark while editing the function to test it, without having to move back and forth. I don't know if that's possible or easy to configure here.

Feel free to close this issue cause it's really with evil mode and not cider, but maybe there is other cider users with evil mode that can suggest how to fix this

bo-tato avatar Feb 04 '23 20:02 bo-tato

that 1- doesn't even fix it in evil mode, as then it doesn't work right in insert mode or inside strings. I have a new try for a fix, that I'm not sure if it's the right change to make but at least this I've tested and behaves as it should in evil whatever mode normal or insert, and also behaves correctly for normal users without evil mode: in cider-eval-list-at-point I remove:

(goto-char (cadr (cider-list-at-point 'bounds)))
(cider-eval-last-sexp output-to-current-buffer)))

and replace with:

(skip-chars-forward "^)")
(cider-eval-sexp-up-to-point output-to-current-buffer)

And I think this is actually a minor improvement, as previously cider-eval-list-at-point would eval a string or [] or {} if you were inside them, rather than evaluating the surrounding parens. strings or vec/map are data literals you generally already see them in your source and what you actually want to eval in repl is the surrounding function, this is also the behaviour the docstring implies: Evaluate the list (eg. a function call, surrounded by parens) around point.

Edit: oops, I can't just goto to next ), I have goto next matching ), I changed (skip-chars-forward "^)") to (evil-next-close-paren), I can't find if emacs/cider has an easy function to go to next matching close paren (just sexp that also includes ] } etc) that works without evil

bo-tato avatar Feb 07 '23 13:02 bo-tato

I think there are just sexp-based helper functions currently.

bbatsov avatar Feb 09 '23 06:02 bbatsov