Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
### Changes

- Bump the default `cider-repl-history-size` from 500 to 5000.
- Enable rich content in the REPL by default (`cider-repl-use-content-types` is now t): image results render inline, and results naming external content (files, URLs) render a `[show content]` button that fetches and renders it on demand. The automatic fetching that got the feature disabled back in 0.25 ([#2825](https://github.com/clojure-emacs/cider/issues/2825)) is gone - nothing is transferred until the button is pressed - and the server side is hardened in `cider-nrepl` 0.62 (URL-scheme allowlist, size caps, graceful fetch errors).
- Bump the default `cider-repl-history-size` from 500 to 5000 and the default `cider-print-buffer-size` from 4K to 16K (fewer, larger chunks when streaming big results).
- Rename the REPL history browser from `cider-repl-history` to `cider-history` (command, mode and options), so its names no longer clash with the REPL's unrelated input-history settings (`cider-repl-history-file`, `cider-repl-history-size`); the old names keep working as obsolete aliases.
- Color the nREPL messages buffer with theme-aware faces (`nrepl-message-faces`, eight faces inheriting from standard font-lock faces) instead of a hardcoded color list; `nrepl-message-colors` is now obsolete, but still takes precedence when customized.
- Consolidate the per-buffer auto-select options into a single `cider-auto-select-buffer`, which can be `t`, `nil` or a list of the popup buffers to select (e.g. `'(error inspector)`); the old options (`cider-auto-select-error-buffer`, `cider-auto-select-test-report-buffer`, `cider-doc-auto-select-buffer`, `cider-inspector-auto-select-buffer`, `cider-cheatsheet-auto-select-buffer` and `cider-log-auto-select-frameworks-buffer`) are now obsolete, but still take precedence when customized.
Expand Down
23 changes: 16 additions & 7 deletions doc/modules/ROOT/pages/repl/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -282,21 +282,30 @@ more information on configuring printing.

== Displaying images in the REPL

Expressions that evaluate to images can be rendered as images in the
REPL. You can enable this behavior like this:
Expressions that evaluate to images are rendered as images in the REPL.
Results naming external content - a `java.io.File`, or a `java.net.URI`/`URL`
with a `file:`, `http:` or `https:` scheme - render as the URL followed by a
`[show content]` button; press kbd:[RET] (or click) to fetch the content and
render it in place. Nothing is transferred until you press the button, so
merely evaluating a `File` or `URI` has no side effects.

This behavior is enabled by default as of CIDER 2.0. You can disable it like
this:

[source,lisp]
----
(setq cider-repl-use-content-types t)
(setq cider-repl-use-content-types nil)
----

NOTE: This setting is disabled by default due to some rough edges with the
feature that were never properly addressed. See this
https://github.com/clojure-emacs/cider/issues/2825[bug report] for details.

Alternatively, you can toggle this behavior on and off using kbd:[M-x cider-repl-toggle-content-types]
or the REPL shortcut `toggle-content-types`.

NOTE: In CIDER 1.x this feature was disabled by default because the content
was fetched automatically, which meant evaluating any URL-shaped value caused
IO (see https://github.com/clojure-emacs/cider/issues/2825[the discussion]).
The on-demand button, together with the hardened `cider-nrepl` middleware
(scheme allowlist, size caps, graceful fetch errors), resolves that.

== REPL type detection

Normally CIDER would detect automatically the type of a REPL (Clojure or ClojureScript), based
Expand Down
11 changes: 8 additions & 3 deletions doc/modules/ROOT/pages/troubleshooting.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,20 @@ java.net.UnknownServiceException: protocol doesn't support input
at cider.nrepl.middleware.slurp$handle_slurp.invoke(slurp.clj:109)
----

You can disable the middleware like this:
This affected CIDER 1.x, where the content was fetched automatically as soon
as a URL-shaped value was returned. As of CIDER 2.0 (with `cider-nrepl`
0.62+) content is only fetched when you press the result's `[show content]`
button, non-fetchable URL schemes like `mailto:` are never offered for
fetching, and a failed fetch reports a plain-text error instead of crashing
the handler.

If you're stuck on older versions, you can disable the feature like this:

[source,lisp]
----
(setq cider-repl-use-content-types nil)
----

That's also the default behavior.

=== Debugging freezes & lock-ups

Sometimes a CIDER command might hang for a while (e.g. due to a bug or a
Expand Down
57 changes: 46 additions & 11 deletions lisp/cider-repl.el
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,15 @@ The `cider-toggle-pretty-printing' command can be used to interactively
change the setting's value."
:type 'boolean)

(defcustom cider-repl-use-content-types nil
(defcustom cider-repl-use-content-types t
"Control whether REPL results are presented using content-type information.
When enabled, evaluation results that are images render inline in the REPL,
and results naming external content (files, URLs) offer a button that
fetches and renders it on demand.
The `cider-repl-toggle-content-types' command can be used to interactively
change the setting's value."
:type 'boolean
:package-version '(cider . "0.17.0"))
:package-version '(cider . "2.0.0"))

(defcustom cider-repl-auto-detect-type t
"Control whether to auto-detect the REPL type using track-state information.
Expand Down Expand Up @@ -1154,15 +1157,47 @@ Part of the default `cider-repl-content-type-handler-alist'."
(cider-repl--image image 'svg t)
show-prefix bol))

(defun cider-repl-handle-external-body (type buffer _ &optional _show-prefix _bol)
"Handler for slurping external content into BUFFER.
Handles an external-body TYPE by issuing a slurp request to fetch the content."
(if-let* ((args (cadr type))
(access-type (nrepl-dict-get args "access-type")))
(cider-nrepl-send-request
(list "op" "cider/slurp" "url" (nrepl-dict-get args access-type))
(cider-repl-handler buffer)))
nil)
(defun cider-repl--fetch-external-body (buffer url)
"Fetch URL's content from the nREPL server and render it in BUFFER."
(cider-nrepl-send-request (list "op" "cider/slurp" "url" url)
(cider-repl-handler buffer)))

(defun cider-repl--display-external-body (buffer url &optional show-prefix bol)
"Insert URL and a button that fetches its content into BUFFER.
For compatibility with the rest of CIDER's REPL machinery, supports
SHOW-PREFIX and BOL."
(with-current-buffer buffer
(save-excursion
(cider-save-marker cider-repl-output-start
(goto-char cider-repl-output-end)
(when (and bol (not (bolp)))
(insert-before-markers "\n"))
(when show-prefix
(insert-before-markers
(propertize cider-repl-result-prefix 'font-lock-face 'font-lock-comment-face)))
(insert-before-markers
(propertize url 'font-lock-face 'cider-repl-result-face)
" ")
(let ((start (point)))
(insert-before-markers "[show content]")
(make-text-button start (point)
'follow-link t
'help-echo (format "Fetch %s and render it here" url)
'action (lambda (_button)
(cider-repl--fetch-external-body buffer url)))))))
t)

(defun cider-repl-handle-external-body (type buffer _ &optional show-prefix bol)
"Handler for referencing external content in BUFFER.
Handles an external-body TYPE by rendering the reference URL followed by a
button that fetches and renders the content on demand, via a slurp
request. Nothing is transferred (or connected to) until the button is
pressed, so merely evaluating a `File' or `URI' has no side effects."
(when-let* ((args (cadr type))
(access-type (nrepl-dict-get args "access-type"))
(url (nrepl-dict-get args access-type)))
(cider-repl--display-external-body buffer url show-prefix bol))
t)

(defvar cider-repl-content-type-handler-alist
`(("message/external-body" . ,#'cider-repl-handle-external-body)
Expand Down
25 changes: 25 additions & 0 deletions test/cider-repl-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -641,3 +641,28 @@ PROPERTY should be a symbol of either 'text, 'ansi-context or
(cider-debug-sesman-friendly-session-p)
(expect 'cider-sessions :to-have-been-called)
(expect 'cider--sesman-friendly-session-p :to-have-been-called-times 2)))

(describe "cider-repl-handle-external-body"
(it "renders a fetch button for the URL instead of fetching automatically"
(let (rendered requested)
(cl-letf (((symbol-function 'cider-repl--display-external-body)
(lambda (_buffer url &rest _) (setq rendered url) t))
((symbol-function 'cider-nrepl-send-request)
(lambda (&rest _) (setq requested t))))
(expect (cider-repl-handle-external-body
(list "message/external-body"
(nrepl-dict "access-type" "URL" "URL" "file:/tmp/x.png"))
(current-buffer) "")
:to-be-truthy)
(expect rendered :to-equal "file:/tmp/x.png")
(expect requested :to-be nil))))

(it "does nothing (but still allows the prompt) without an access type"
(let (rendered)
(cl-letf (((symbol-function 'cider-repl--display-external-body)
(lambda (_buffer url &rest _) (setq rendered url) t)))
(expect (cider-repl-handle-external-body
(list "message/external-body" (nrepl-dict))
(current-buffer) "")
:to-be-truthy)
(expect rendered :to-be nil)))))
Loading