Fork me on GitHub
#cider
<
2020-03-18
>
yuhan08:03:55

I recently decided to reduce my mental block of refactoring things into let bindings and losing the ability to eval subexpressions - the following command looks backwards within the current defun for any let-bindings and wraps them around the sexp at point to evaluate:

(defun cider--guess-evaluation-context ()
  "Returns list of let-binding strings from the inside out, without closing parens
     \"(let [...]\""
  (save-excursion
    (let ((res ()))
      (condition-case er
          (while t
            (backward-up-list)
            (when (looking-at (rx "(" (or "when-let" "if-let" "let") (opt "*")
                                  symbol-end (* space)
                                  (group "["))) ;; binding vector
              (let ((beg (match-beginning 0))
                    (end (save-excursion
                           (goto-char (match-beginning 1))
                           (forward-sexp 1)
                           (point))))
                (push (buffer-substring-no-properties beg end) res))))
        (scan-error res)))))

(defun cider-eval-dwim ()
  (interactive)
  (let ((ctx (cider--guess-evaluation-context))
        (bounds (cider-sexp-at-point 'bounds)))
    (cider-interactive-eval (concat (apply #'concat ctx)
                                    (buffer-substring-no-properties (car bounds) (cadr bounds))
                                    (make-string (length ctx) ?\)))
                            nil bounds
                            (cider--nrepl-pr-request-map))))

❤️ 8
yuhan08:03:25

Not sure if it belongs in Cider core? hopefully someone finds it useful 🙂

bozhidar09:03:18

@qythium This already exists in CIDER. 😄

bozhidar09:03:11

See cider-eval-defun-upto-point and cider-eval-sexp-upto-point.

bozhidar09:03:26

There’s also cider-eval-in-context (or something along those lines).

bozhidar09:03:16

I guess you can enhance the existing eval in context with your logic to guess the let-bindings there.

bozhidar09:03:51

Btw, the approach with the context I took was much simpler - I just balance the unbalanced sexp at point and make it evaluatable. This way you don’t have to guess the evaluation context, as you’re using it directly.

yuhan09:03:44

yup, I knew about those functions, but they weren't suited for what I wanted

yuhan09:03:16

(let [a 1]
  [:lots
   (of unnecessary
     :things)
   (assert false)
   (let [b (inc a)]
     (+ a b))
   etc
   etc])

yuhan09:03:47

eg. I want to place my cursor at the (+ a b) form and eval, and get only the result => 3

yuhan09:03:28

cider-eval-in-context was too much friction because it didn't pick up on existing let bindings and requires you to enter a context into the minibuffer

bozhidar10:03:33

> eg. I want to place my cursor at the (+ a b) form and eval, and get only the result => 3

bozhidar10:03:55

Well, that’s exactly what eval-upto-point does. I think I’m not understanding something.

yuhan10:03:46

In the example above eval-upto-point would throw an assertion error or return all the unnecessary things

yuhan10:03:20

in particular I found this useful as a way to debug an expression which was throwing errors by inspecting sub-expressions independently of others

yuhan10:03:16

Similar to "temporary defs" method of debugging now I think of it, but without polluting the namespace

bozhidar12:03:32

Ah, I finally get it.

bozhidar12:03:17

I didn’t notice the assertion at first. Well, feel free to contribute this to CIDER. I can imagine it’d be useful to some people.