Skip to content

Decouple nrepl-make-eval-handler from CIDER's UI layer#3892

Merged
bbatsov merged 1 commit intomasterfrom
decouple-nrepl-handler
Apr 29, 2026
Merged

Decouple nrepl-make-eval-handler from CIDER's UI layer#3892
bbatsov merged 1 commit intomasterfrom
decouple-nrepl-handler

Conversation

@bbatsov
Copy link
Copy Markdown
Member

@bbatsov bbatsov commented Apr 29, 2026

Closes #1099.

After #3890 introduced the keyword-arg API, nrepl-make-eval-handler still embedded several CIDER-specific concerns: it consulted nrepl-namespace-handler-function, nrepl-err-handler-function, and nrepl-need-input-handler-function, and emitted the hardcoded "Evaluation interrupted." and "Namespace \%s' not found."` messages. That kept the transport tied to the editor, which is what #1099 was originally about back in 2017.

This PR strips those concerns out.

Transport (nrepl-client.el)

nrepl-make-eval-handler loses its :buffer slot and its dispatches on the global handler hooks. Two new keyword slots take their place:

  • :on-ns -- called with NS whenever a response carries an ns slot, regardless of which other slots are present.
  • :on-status -- called with (STATUS RESPONSE) when the response carries a status slot. STATUS is the list of flags; RESPONSE is the full dict so handlers can read sibling slots (e.g. ns for "namespace-not-found").

Net result: nrepl-make-eval-handler is now a transport-layer building block. Any Emacs nREPL client could use it without dragging CIDER's UI semantics along.

Editor (cider-eval.el)

New cider-make-eval-handler wraps the transport one and layers CIDER's UI back on:

  • ns tracking via cider--update-buffer-ns
  • default :on-eval-error -> cider-default-err-handler
  • need-input prompt via cider-need-input
  • "Evaluation interrupted." and "Namespace \%s' not found."` messages

All ~14 in-tree callers in cider-client.el, cider-repl.el, cider-eval.el, and cider-profile.el switch to it. The two file-crossing references get declare-function decls.

Backward compatibility

The obsolete nrepl-make-response-handler shim is updated to wire up the global handler hooks and the legacy status messages itself. Extension code targeting the old positional API sees no behavior change -- if you were setting nrepl-namespace-handler-function, nrepl-err-handler-function, or nrepl-need-input-handler-function, the shim still consults them.

A new Buttercup spec (nrepl-make-response-handler legacy shim) is the regression guard: it asserts that nrepl-namespace-handler-function and nrepl-err-handler-function still get called when the legacy form is invoked.

Tests

8 new specs:

  • nrepl-make-eval-handler -- :on-ns firing, :on-status receiving (status response), :on-eval-error direct invocation
  • cider-make-eval-handler -- ns tracking, err-handler default, custom err handler override, need-input prompt, namespace-not-found message
  • nrepl-make-response-handler legacy shim -- still consults the global hooks (regression guard)

Full suite: 542/544 pass, 0 failures (8 new specs over the 534-spec baseline from #3891).

Closes #1099.  After Step 1 (#3890) introduced the keyword-arg API,
`nrepl-make-eval-handler' still embedded several CIDER-specific
concerns: it consulted `nrepl-namespace-handler-function',
`nrepl-err-handler-function', and `nrepl-need-input-handler-function',
and emitted the hardcoded "Evaluation interrupted." and
"Namespace `%s' not found." messages.  That kept the transport tied to
the editor, which is what #1099 was originally about.

Strip those concerns out of the transport.  `nrepl-make-eval-handler'
loses its `:buffer' slot and its dispatches on the global handler
hooks.  Two new keyword slots take their place:

  :on-ns      called with NS whenever a response carries an `ns' slot.
  :on-status  called with (STATUS RESPONSE) when the response carries
              a `status' slot.  STATUS is the list of flags; RESPONSE
              is the full dict so handlers can read sibling slots
              (e.g. `ns' for "namespace-not-found").

Add `cider-make-eval-handler' in cider-eval.el as the editor wrapper
that layers CIDER's UI back on top: ns tracking via
`cider--update-buffer-ns', default `:on-eval-error' ->
`cider-default-err-handler', `need-input' prompt via
`cider-need-input', and the "Evaluation interrupted." /
"Namespace not found." messages.  All ~14 in-tree callers in
cider-client.el, cider-repl.el, cider-eval.el, and cider-profile.el
switch to it.

The obsolete `nrepl-make-response-handler' shim is updated to wire up
the global handler hooks and the legacy status messages itself, so
extension code targeting the old positional API sees no behavior
change.

New Buttercup specs cover: `:on-ns' firing on ns-bearing responses,
`:on-status' receiving (status response), `cider-make-eval-handler''s
ns tracking / err-handler default / need-input prompting, and a
regression guard that the legacy shim still consults the global hooks.
@bbatsov bbatsov merged commit d824774 into master Apr 29, 2026
13 checks passed
@bbatsov bbatsov deleted the decouple-nrepl-handler branch April 29, 2026 10:55
tarsius pushed a commit to emacsmirror/cider that referenced this pull request Apr 29, 2026
`cider--debug-response-handler' was a hand-rolled callback that
dispatched on the debug-specific status flags (`enlighten',
`eval-error', `stack', `need-debug-input', `done') and explicitly called
`nrepl--mark-id-completed' for the done branch.

Now that `nrepl-make-eval-handler' has an `:on-status' slot (clojure-emacs#3892),
this handler fits the eval-handler shape exactly: pass an `:on-status'
that walks the same status flags and let the helper do the
mark-id-completed bookkeeping for free.

Changes the function from "I am a handler" to "I build a handler"
(callsite goes from `#'cider--debug-response-handler' to
`(cider--debug-response-handler)'), matching the convention of
`cider-make-eval-handler', `cider-repl-handler', etc.  No behavior
change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rewrite nrepl callback handling

1 participant