clojure-emacs / clojure-emacs/cider
REPL result presentations: clickable, reusable result objects
- Dominant language
- Emacs Lisp
- Stars
- 3.7k
- Forks
- 651
- Avg merge
- 11h 6m
- Merged PRs (30d)
- 33
Description
Recently I've been going through SLIME and SLY looking for features we still lack, and their REPL "presentations" caught my attention. It seems relatively doable for us, and it would fold several of our existing one-off commands behind a single, discoverable interaction.
Today a CIDER result is just text decorated with locrefs and content-type rendering. The underlying value isn't a first-class handle: you can't point at a printed result and inspect that exact object, tap it, def it to a var, or feed it back as input. We approximate this with `cider-inspect-last-result`, `*1`/`*2`/`*3`, grab-old-input, and `tap>`, but only ever for the last result and never as a per-result affordance.
In SLIME and SLY every result is a clickable object: inspect / pretty-print / copy-to-kill / copy the live object back into the REPL. SLY also has `#v` backreferences that reach any past value, not just the last few.
This issue tracks the CIDER (client) side. The server side, a result ring plus presentation ids, is tracked in clojure-emacs/cider-nrepl#988.
### Client design
Gated behind a new `cider-repl-use-presentations` defcustom, mirroring how `cider-repl-use-content-types` already gates rich rendering, so it degrades automatically when the middleware or option is absent.
- Thread the new `presentation-id` from the eval response through `cider-repl-handler` into `cider-repl-emit-result`.
- Wrap the emitted result region in an overlay/button carrying the id as a text property, styled with `cider-repl-result-face` (possibly a dedicated face).
- A keymap on the result region: `mouse-3` context menu plus a `C-c C-v` keyboard prefix (matching SLIME muscle memory).
- Actions, each just resolving the id server-side:
- Inspect -> `cider-inspector` against the id, no re-eval
- Tap -> `tap>` the live object
- Def to var -> bind it to a user-named var
- Copy to REPL as reference -> insert `#cider/ref N` at the input
- Pretty-print / copy printed value to kill ring (pure client-side, works without an id)
- `cider-repl-insert-presentation-ref` to insert a `#cider/ref N` backreference for the result at point.
- When `presentation-id` is absent (Babashka, plain nREPL, raw eval), results render exactly as they do today.
### Phasing
1. Server: result ring + ids + lookup op (clojure-emacs/cider-nrepl#988)
2. Client: button/overlay layer + context menu
3. Backreferences UI: `#cider/ref` insertion + refcard/help updates
4. Stretch: extend presentations to the inspector and stacktrace buffers (SLY-style cross-buffer "copy to REPL")
### Out of scope
- Switching the REPL to comint
- SLY stickers / replayable capture (overlaps with the enlighten/tracing work)
Contributor guide
Research direction
Start with the existing cider-repl-handler and cider-repl-emit-result flow, then compare its cider-repl-use-content-types gating with the proposed cider-repl-use-presentations option. Review the server-side result ring and lookup work in clojure-emacs/cider-nrepl#988 before implementing the client phases. Done means presentation-aware results degrade unchanged when no presentation-id is available and expose the specified result actions and reference insertion.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- clojure, emacs-lisp
- Domain
- developer-experience, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100