Skip to content

REPL result presentations: clickable, reusable result objects #4015

Description

@bbatsov

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 (A result ring for REPL presentations (addressable result objects) 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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions