Skip to content

Commit e608cef

Browse files
committed
Add nrepl-make-eval-handler with a keyword-arg API
Closes the long-standing issue #1099. The legacy `nrepl-make-response-handler' had a 7-positional-arg signature, with five sub-handlers that all received a (BUFFER VALUE) pair regardless of whether they used the buffer. In practice the buffer was vestigial for most handlers; survey of the 14 in-tree call sites showed the majority ignored it as `_buffer'. Add `nrepl-make-eval-handler' as the replacement: a single keyword-arg form with `:buffer' and `:on-value' / `:on-stdout' / `:on-stderr' / `:on-done' / `:on-eval-error' / `:on-content-type' / `:on-truncated'. Sub-handlers take only the response slot they care about; they close over whatever buffer or other context they need. `:buffer' is still forwarded to the global handlers configured via `nrepl-namespace-handler-function' and friends. `nrepl-make-response-handler' stays as a thin shim that adapts the old (BUFFER X) lambdas to the new (X) lambdas, marked obsolete so byte- compile nudges extension authors to migrate. Behavior is preserved across the full eval-response shape -- value, stdout, stderr, done, eval-error, namespace tracking, need-input, interrupt message, content type, truncated. All 14 in-tree callers (cider-client.el, cider-repl.el, cider-eval.el, cider-profile.el) migrated to the new form, dropping ~30 LOC of ceremony per handler. New Buttercup specs cover the dispatch matrix: value/out/err routing, done semantics, the eval-error fallback chain between `:on-eval-error' and `nrepl-err-handler-function', and base64 content decoding for `:on-content-type'.
1 parent 8375c03 commit e608cef

7 files changed

Lines changed: 331 additions & 264 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [#3865](https://github.com/clojure-emacs/cider/pull/3865): Add default session feature to bypass sesman's project-based dispatch (`cider-set-default-session`, `cider-clear-default-session`).
99
- Introduce `cider-jack-in-tools` and `cider-register-jack-in-tool` so third-party packages can register new project tools for `cider-jack-in` and `cider-jack-in-universal`.
1010
- Cache the result of `cider--running-nrepl-paths` (used by `cider-locate-running-nrepl-ports`) for `cider-running-nrepl-paths-cache-ttl` seconds (default 5). Repeated `cider-connect` completions no longer re-spawn a fresh round of `ps`/`lsof` subprocesses each time. `cider-clear-running-nrepl-paths-cache` discards the cache on demand.
11+
- New `nrepl-make-eval-handler` with a keyword-arg API (`:on-value`, `:on-stdout`, `:on-stderr`, `:on-done`, `:on-eval-error`, `:on-content-type`, `:on-truncated`). Sub-handlers no longer take a buffer argument -- they close over whatever they need. `nrepl-make-response-handler`, the legacy 7-positional-arg form, is preserved as an obsolete shim that adapts the old (buffer x) lambdas to the new (x) lambdas, so existing extensions keep working.
1112

1213
### Bugs fixed
1314

lisp/cider-client.el

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ itself is present."
493493

494494
(defun cider-interrupt-handler (buffer)
495495
"Create an interrupt response handler for BUFFER."
496-
(nrepl-make-response-handler buffer nil nil nil nil))
496+
(nrepl-make-eval-handler :buffer buffer))
497497

498498
(defun cider-interrupt ()
499499
"Interrupt any pending evaluations."
@@ -901,14 +901,11 @@ FORMAT-OPTIONS is an optional configuration map for cljfmt."
901901
(nrepl-dict-get response "formatted-edn")))
902902

903903
;;; Dealing with input
904-
;; TODO: Replace this with some nil handler.
905904
(defun cider-stdin-handler (&optional _buffer)
906-
"Make a stdin response handler for _BUFFER."
907-
(nrepl-make-response-handler (current-buffer)
908-
(lambda (_buffer _value))
909-
(lambda (_buffer _out))
910-
(lambda (_buffer _err))
911-
nil))
905+
"Make a stdin response handler for _BUFFER.
906+
Intentionally swallows value/out/err so the response is consumed without
907+
side effects; only the global handlers fire (need-input, eval-error, ...)."
908+
(nrepl-make-eval-handler :buffer (current-buffer)))
912909

913910
(defun cider-need-input (buffer)
914911
"Handle an need-input request from BUFFER."

lisp/cider-eval.el

Lines changed: 131 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -627,32 +627,26 @@ The handler simply inserts the result value in BUFFER."
627627
(let ((eval-buffer (current-buffer))
628628
(res "")
629629
(failed nil))
630-
(nrepl-make-response-handler (or buffer eval-buffer)
631-
;; value handler:
632-
(lambda (_buffer value)
633-
(with-current-buffer buffer
634-
(insert value))
635-
(when cider-eval-register
636-
(setq res (concat res value))))
637-
;; stdout handler:
638-
(lambda (_buffer out)
639-
(cider-repl-emit-interactive-stdout out))
640-
;; stderr handler:
641-
(lambda (_buffer err)
642-
(cider-repl-emit-interactive-stderr err)
643-
;; Don't jump
644-
(cider-handle-compilation-errors err eval-buffer t))
645-
;; done handler:
646-
(lambda (_buffer)
647-
(when cider-eval-register
648-
(set-register cider-eval-register res))
649-
(when (and (not failed)
650-
on-success-callback)
651-
(funcall on-success-callback)))
652-
;; eval-error handler
653-
(lambda (_buffer)
654-
(setq failed t)
655-
(funcall nrepl-err-handler-function source-buffer)))))
630+
(nrepl-make-eval-handler
631+
:buffer (or buffer eval-buffer)
632+
:on-value (lambda (value)
633+
(with-current-buffer buffer
634+
(insert value))
635+
(when cider-eval-register
636+
(setq res (concat res value))))
637+
:on-stdout (lambda (out) (cider-repl-emit-interactive-stdout out))
638+
:on-stderr (lambda (err)
639+
(cider-repl-emit-interactive-stderr err)
640+
;; Don't jump
641+
(cider-handle-compilation-errors err eval-buffer t))
642+
:on-done (lambda ()
643+
(when cider-eval-register
644+
(set-register cider-eval-register res))
645+
(when (and (not failed) on-success-callback)
646+
(funcall on-success-callback)))
647+
:on-eval-error (lambda ()
648+
(setq failed t)
649+
(funcall nrepl-err-handler-function source-buffer)))))
656650

657651
(defun cider--emit-interactive-eval-output (output repl-emit-function)
658652
"Emit output resulting from interactive code evaluation.
@@ -733,106 +727,94 @@ when `cider-auto-inspect-after-eval' is non-nil."
733727
(end (when end (copy-marker end)))
734728
(fringed nil)
735729
(res ""))
736-
(nrepl-make-response-handler
737-
(or buffer eval-buffer)
738-
;; value handler:
739-
(lambda (_buffer value)
740-
(setq res (concat res value))
741-
(cider--display-interactive-eval-result res 'value end))
742-
;; stdout handler:
743-
(lambda (_buffer out)
744-
(cider-emit-interactive-eval-output out))
745-
;; stderr handler:
746-
(lambda (_buffer err)
747-
(cider-emit-interactive-eval-err-output err)
748-
(cider-handle-compilation-errors
749-
err eval-buffer
750-
;; Disable jumping behavior when compiling a single form because
751-
;; lines tend to be spurious (e.g. 0:0) and the jump brings us to
752-
;; the beginning of the same form anyway.
753-
t))
754-
;; done handler:
755-
(lambda (buffer)
756-
(if beg
757-
(unless fringed
758-
(cider--make-fringe-overlays-for-region beg end)
759-
(setq fringed t))
760-
(cider--make-fringe-overlay end))
761-
(when (and cider-auto-inspect-after-eval
762-
(boundp 'cider-inspector-buffer)
763-
(windowp (get-buffer-window cider-inspector-buffer 'visible)))
764-
(cider-inspect-last-result)
765-
(select-window (get-buffer-window buffer)))
766-
(when cider-eval-register
767-
(set-register cider-eval-register res))))))
730+
(nrepl-make-eval-handler
731+
:buffer (or buffer eval-buffer)
732+
:on-value (lambda (value)
733+
(setq res (concat res value))
734+
(cider--display-interactive-eval-result res 'value end))
735+
:on-stdout (lambda (out) (cider-emit-interactive-eval-output out))
736+
:on-stderr (lambda (err)
737+
(cider-emit-interactive-eval-err-output err)
738+
(cider-handle-compilation-errors
739+
err eval-buffer
740+
;; Disable jumping behavior when compiling a single form
741+
;; because lines tend to be spurious (e.g. 0:0) and the
742+
;; jump brings us to the beginning of the same form anyway.
743+
t))
744+
:on-done (lambda ()
745+
(if beg
746+
(unless fringed
747+
(cider--make-fringe-overlays-for-region beg end)
748+
(setq fringed t))
749+
(cider--make-fringe-overlay end))
750+
(let ((target (or buffer eval-buffer)))
751+
(when (and cider-auto-inspect-after-eval
752+
(boundp 'cider-inspector-buffer)
753+
(windowp (get-buffer-window cider-inspector-buffer 'visible)))
754+
(cider-inspect-last-result)
755+
(select-window (get-buffer-window target))))
756+
(when cider-eval-register
757+
(set-register cider-eval-register res))))))
768758

769759

770760
(defun cider-load-file-handler (&optional buffer done-handler)
771761
"Make a load file handler for BUFFER.
772762
Optional argument DONE-HANDLER lambda will be run once load is complete."
773-
(let ((eval-buffer (current-buffer))
774-
(res ""))
775-
(nrepl-make-response-handler (or buffer eval-buffer)
776-
;; value
777-
(lambda (buffer value)
778-
(cider--display-interactive-eval-result value 'value)
779-
(when cider-eval-register
780-
(setq res (concat res value)))
781-
(when (buffer-live-p buffer)
782-
(with-current-buffer buffer
783-
(cider--make-fringe-overlays-for-region (point-min) (point-max))
784-
(run-hooks 'cider-file-loaded-hook))))
785-
;; stdout
786-
(lambda (_buffer value)
787-
(cider-emit-interactive-eval-output value))
788-
;; stderr
789-
(lambda (_buffer err)
790-
(cider-emit-interactive-eval-err-output err)
791-
(cider-handle-compilation-errors err eval-buffer))
792-
;; done
793-
(lambda (buffer)
794-
(when cider-eval-register
795-
(set-register cider-eval-register res))
796-
(when done-handler
797-
(funcall done-handler buffer))))))
763+
(let* ((eval-buffer (current-buffer))
764+
(target (or buffer eval-buffer))
765+
(res ""))
766+
(nrepl-make-eval-handler
767+
:buffer target
768+
:on-value (lambda (value)
769+
(cider--display-interactive-eval-result value 'value)
770+
(when cider-eval-register
771+
(setq res (concat res value)))
772+
(when (buffer-live-p target)
773+
(with-current-buffer target
774+
(cider--make-fringe-overlays-for-region (point-min) (point-max))
775+
(run-hooks 'cider-file-loaded-hook))))
776+
:on-stdout (lambda (out) (cider-emit-interactive-eval-output out))
777+
:on-stderr (lambda (err)
778+
(cider-emit-interactive-eval-err-output err)
779+
(cider-handle-compilation-errors err eval-buffer))
780+
:on-done (lambda ()
781+
(when cider-eval-register
782+
(set-register cider-eval-register res))
783+
(when done-handler
784+
(funcall done-handler target))))))
798785

799786
(defun cider-eval-print-handler (&optional buffer)
800787
"Make a handler for evaluating and printing result in BUFFER."
801788
;; NOTE: cider-eval-register behavior is not implemented here for performance reasons.
802789
;; See https://github.com/clojure-emacs/cider/pull/3162
803-
(nrepl-make-response-handler (or buffer (current-buffer))
804-
(lambda (buffer value)
805-
(with-current-buffer buffer
806-
(insert
807-
(if (derived-mode-p 'cider-clojure-interaction-mode)
808-
(format "\n%s\n" value)
809-
value))))
810-
(lambda (_buffer out)
811-
(cider-emit-interactive-eval-output out))
812-
(lambda (_buffer err)
813-
(cider-emit-interactive-eval-err-output err))
814-
()))
790+
(let ((target (or buffer (current-buffer))))
791+
(nrepl-make-eval-handler
792+
:buffer target
793+
:on-value (lambda (value)
794+
(with-current-buffer target
795+
(insert (if (derived-mode-p 'cider-clojure-interaction-mode)
796+
(format "\n%s\n" value)
797+
value))))
798+
:on-stdout (lambda (out) (cider-emit-interactive-eval-output out))
799+
:on-stderr (lambda (err) (cider-emit-interactive-eval-err-output err)))))
815800

816801
(defun cider-eval-print-with-comment-handler (buffer location comment-prefix)
817802
"Make a handler for evaluating and printing commented results in BUFFER.
818803
LOCATION is the location marker at which to insert. COMMENT-PREFIX is the
819804
comment prefix to use."
820805
(let ((res ""))
821-
(nrepl-make-response-handler buffer
822-
(lambda (_buffer value)
823-
(setq res (concat res value)))
824-
(lambda (_buffer out)
825-
(cider-emit-interactive-eval-output out))
826-
(lambda (_buffer err)
827-
(cider-emit-interactive-eval-err-output err))
828-
(lambda (buffer)
829-
(with-current-buffer buffer
830-
(save-excursion
831-
(goto-char (marker-position location))
832-
(insert (concat comment-prefix
833-
res "\n"))))
834-
(when cider-eval-register
835-
(set-register cider-eval-register res))))))
806+
(nrepl-make-eval-handler
807+
:buffer buffer
808+
:on-value (lambda (value) (setq res (concat res value)))
809+
:on-stdout (lambda (out) (cider-emit-interactive-eval-output out))
810+
:on-stderr (lambda (err) (cider-emit-interactive-eval-err-output err))
811+
:on-done (lambda ()
812+
(with-current-buffer buffer
813+
(save-excursion
814+
(goto-char (marker-position location))
815+
(insert (concat comment-prefix res "\n"))))
816+
(when cider-eval-register
817+
(set-register cider-eval-register res))))))
836818

837819
(defun cider-maybe-insert-multiline-comment (result comment-prefix continued-prefix comment-postfix)
838820
"Insert eval RESULT at current location if RESULT is not empty.
@@ -860,26 +842,24 @@ COMMENT-PREFIX is the comment prefix for the first line of output.
860842
CONTINUED-PREFIX is the comment prefix to use for the remaining lines.
861843
COMMENT-POSTFIX is the text to output after the last line."
862844
(let ((res ""))
863-
(nrepl-make-response-handler
864-
buffer
865-
(lambda (_buffer value)
866-
(setq res (concat res value)))
867-
nil
868-
(lambda (_buffer err)
869-
(setq res (concat res err)))
870-
(lambda (buffer)
871-
(with-current-buffer buffer
872-
(save-excursion
873-
(goto-char (marker-position location))
874-
;; edge case: defun at eob
875-
(unless (bolp) (insert "\n"))
876-
(cider-maybe-insert-multiline-comment res comment-prefix continued-prefix comment-postfix)))
877-
(when cider-eval-register
878-
(set-register cider-eval-register res)))
879-
nil
880-
nil
881-
(lambda (_buffer warning)
882-
(setq res (concat res warning))))))
845+
(nrepl-make-eval-handler
846+
:buffer buffer
847+
:on-value (lambda (value) (setq res (concat res value)))
848+
:on-stderr (lambda (err) (setq res (concat res err)))
849+
:on-done (lambda ()
850+
(with-current-buffer buffer
851+
(save-excursion
852+
(goto-char (marker-position location))
853+
;; edge case: defun at eob
854+
(unless (bolp) (insert "\n"))
855+
(cider-maybe-insert-multiline-comment
856+
res comment-prefix continued-prefix comment-postfix)))
857+
(when cider-eval-register
858+
(set-register cider-eval-register res)))
859+
:on-truncated (lambda ()
860+
;; Preserve the (incidentally nil) warning the legacy
861+
;; truncated-handler form passed through.
862+
(setq res (concat res nil))))))
883863

884864
(defun cider-popup-eval-handler (&optional buffer _bounds source-buffer)
885865
"Make a handler for printing evaluation results in popup BUFFER,
@@ -890,36 +870,27 @@ This is used by pretty-printing commands."
890870
;; NOTE: cider-eval-register behavior is not implemented here for performance reasons.
891871
;; See https://github.com/clojure-emacs/cider/pull/3162
892872
(let ((chosen-buffer (or buffer (current-buffer))))
893-
(nrepl-make-response-handler
894-
chosen-buffer
895-
;; value handler:
896-
(lambda (buffer value)
897-
(cider-emit-into-popup-buffer buffer (ansi-color-apply value) nil t))
898-
;; stdout handler:
899-
(lambda (_buffer out)
900-
(cider-emit-interactive-eval-output out))
901-
;; stderr handler:
902-
(lambda (_buffer err)
903-
(cider-emit-interactive-eval-err-output err))
904-
;; done handler:
905-
nil
906-
;; eval-error handler:
907-
(lambda (_buffer)
908-
(when (and (buffer-live-p chosen-buffer)
909-
(member (buffer-name chosen-buffer)
910-
cider-ancillary-buffers))
911-
(with-selected-window (get-buffer-window chosen-buffer)
912-
(cider-popup-buffer-quit-function t)))
913-
;; also call the default nrepl-err-handler-function, so that our custom behavior doesn't void the base behavior:
914-
(when nrepl-err-handler-function
915-
(funcall nrepl-err-handler-function source-buffer)))
916-
;; content type handler:
917-
nil
918-
;; truncated handler:
919-
(lambda (buffer)
920-
(let ((warning (format "\n... output truncated to %sB ..."
921-
(file-size-human-readable cider-print-quota))))
922-
(cider-emit-into-popup-buffer buffer warning 'font-lock-warning-face t))))))
873+
(nrepl-make-eval-handler
874+
:buffer chosen-buffer
875+
:on-value (lambda (value)
876+
(cider-emit-into-popup-buffer chosen-buffer (ansi-color-apply value) nil t))
877+
:on-stdout (lambda (out) (cider-emit-interactive-eval-output out))
878+
:on-stderr (lambda (err) (cider-emit-interactive-eval-err-output err))
879+
:on-eval-error (lambda ()
880+
(when (and (buffer-live-p chosen-buffer)
881+
(member (buffer-name chosen-buffer)
882+
cider-ancillary-buffers))
883+
(with-selected-window (get-buffer-window chosen-buffer)
884+
(cider-popup-buffer-quit-function t)))
885+
;; also call the default nrepl-err-handler-function so
886+
;; our custom behavior doesn't void the base behavior:
887+
(when nrepl-err-handler-function
888+
(funcall nrepl-err-handler-function source-buffer)))
889+
:on-truncated (lambda ()
890+
(let ((warning (format "\n... output truncated to %sB ..."
891+
(file-size-human-readable cider-print-quota))))
892+
(cider-emit-into-popup-buffer chosen-buffer warning
893+
'font-lock-warning-face t))))))
923894

924895

925896
;;; Interactive valuation commands

0 commit comments

Comments
 (0)