Skip to content

Commit 8eee7b0

Browse files
committed
Turn rich content on by default, fetching external content on demand
Evaluating a File or URL-shaped result no longer auto-fires a slurp request (the behavior that got the feature disabled back in 0.25, see #2825). The REPL now renders the URL plus a [show content] button and nothing is transferred until it's pressed. Inline image results are unaffected - they involve no IO and still render automatically. With the danger gone, cider-repl-use-content-types defaults to t, so images finally render in the REPL out of the box. Best paired with cider-nrepl 0.62+, which hardens the server side (scheme allowlist, size caps, graceful fetch errors).
1 parent f8a21a8 commit 8eee7b0

5 files changed

Lines changed: 97 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
### Changes
6262

6363
- Bump the default `cider-repl-history-size` from 500 to 5000.
64+
- 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).
65+
- 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).
6466
- 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.
6567
- 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.
6668
- 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.

doc/modules/ROOT/pages/repl/configuration.adoc

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -282,21 +282,30 @@ more information on configuring printing.
282282

283283
== Displaying images in the REPL
284284

285-
Expressions that evaluate to images can be rendered as images in the
286-
REPL. You can enable this behavior like this:
285+
Expressions that evaluate to images are rendered as images in the REPL.
286+
Results naming external content - a `java.io.File`, or a `java.net.URI`/`URL`
287+
with a `file:`, `http:` or `https:` scheme - render as the URL followed by a
288+
`[show content]` button; press kbd:[RET] (or click) to fetch the content and
289+
render it in place. Nothing is transferred until you press the button, so
290+
merely evaluating a `File` or `URI` has no side effects.
291+
292+
This behavior is enabled by default as of CIDER 2.0. You can disable it like
293+
this:
287294

288295
[source,lisp]
289296
----
290-
(setq cider-repl-use-content-types t)
297+
(setq cider-repl-use-content-types nil)
291298
----
292299

293-
NOTE: This setting is disabled by default due to some rough edges with the
294-
feature that were never properly addressed. See this
295-
https://github.com/clojure-emacs/cider/issues/2825[bug report] for details.
296-
297300
Alternatively, you can toggle this behavior on and off using kbd:[M-x cider-repl-toggle-content-types]
298301
or the REPL shortcut `toggle-content-types`.
299302

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

302311
Normally CIDER would detect automatically the type of a REPL (Clojure or ClojureScript), based

doc/modules/ROOT/pages/troubleshooting.adoc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,20 @@ java.net.UnknownServiceException: protocol doesn't support input
136136
at cider.nrepl.middleware.slurp$handle_slurp.invoke(slurp.clj:109)
137137
----
138138

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

141148
[source,lisp]
142149
----
143150
(setq cider-repl-use-content-types nil)
144151
----
145152

146-
That's also the default behavior.
147-
148153
=== Debugging freezes & lock-ups
149154

150155
Sometimes a CIDER command might hang for a while (e.g. due to a bug or a

lisp/cider-repl.el

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,15 @@ The `cider-toggle-pretty-printing' command can be used to interactively
109109
change the setting's value."
110110
:type 'boolean)
111111

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

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

1157-
(defun cider-repl-handle-external-body (type buffer _ &optional _show-prefix _bol)
1158-
"Handler for slurping external content into BUFFER.
1159-
Handles an external-body TYPE by issuing a slurp request to fetch the content."
1160-
(if-let* ((args (cadr type))
1161-
(access-type (nrepl-dict-get args "access-type")))
1162-
(cider-nrepl-send-request
1163-
(list "op" "cider/slurp" "url" (nrepl-dict-get args access-type))
1164-
(cider-repl-handler buffer)))
1165-
nil)
1160+
(defun cider-repl--fetch-external-body (buffer url)
1161+
"Fetch URL's content from the nREPL server and render it in BUFFER."
1162+
(cider-nrepl-send-request (list "op" "cider/slurp" "url" url)
1163+
(cider-repl-handler buffer)))
1164+
1165+
(defun cider-repl--display-external-body (buffer url &optional show-prefix bol)
1166+
"Insert URL and a button that fetches its content into BUFFER.
1167+
For compatibility with the rest of CIDER's REPL machinery, supports
1168+
SHOW-PREFIX and BOL."
1169+
(with-current-buffer buffer
1170+
(save-excursion
1171+
(cider-save-marker cider-repl-output-start
1172+
(goto-char cider-repl-output-end)
1173+
(when (and bol (not (bolp)))
1174+
(insert-before-markers "\n"))
1175+
(when show-prefix
1176+
(insert-before-markers
1177+
(propertize cider-repl-result-prefix 'font-lock-face 'font-lock-comment-face)))
1178+
(insert-before-markers
1179+
(propertize url 'font-lock-face 'cider-repl-result-face)
1180+
" ")
1181+
(let ((start (point)))
1182+
(insert-before-markers "[show content]")
1183+
(make-text-button start (point)
1184+
'follow-link t
1185+
'help-echo (format "Fetch %s and render it here" url)
1186+
'action (lambda (_button)
1187+
(cider-repl--fetch-external-body buffer url)))))))
1188+
t)
1189+
1190+
(defun cider-repl-handle-external-body (type buffer _ &optional show-prefix bol)
1191+
"Handler for referencing external content in BUFFER.
1192+
Handles an external-body TYPE by rendering the reference URL followed by a
1193+
button that fetches and renders the content on demand, via a slurp
1194+
request. Nothing is transferred (or connected to) until the button is
1195+
pressed, so merely evaluating a `File' or `URI' has no side effects."
1196+
(when-let* ((args (cadr type))
1197+
(access-type (nrepl-dict-get args "access-type"))
1198+
(url (nrepl-dict-get args access-type)))
1199+
(cider-repl--display-external-body buffer url show-prefix bol))
1200+
t)
11661201

11671202
(defvar cider-repl-content-type-handler-alist
11681203
`(("message/external-body" . ,#'cider-repl-handle-external-body)

test/cider-repl-tests.el

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,3 +641,28 @@ PROPERTY should be a symbol of either 'text, 'ansi-context or
641641
(cider-debug-sesman-friendly-session-p)
642642
(expect 'cider-sessions :to-have-been-called)
643643
(expect 'cider--sesman-friendly-session-p :to-have-been-called-times 2)))
644+
645+
(describe "cider-repl-handle-external-body"
646+
(it "renders a fetch button for the URL instead of fetching automatically"
647+
(let (rendered requested)
648+
(cl-letf (((symbol-function 'cider-repl--display-external-body)
649+
(lambda (_buffer url &rest _) (setq rendered url) t))
650+
((symbol-function 'cider-nrepl-send-request)
651+
(lambda (&rest _) (setq requested t))))
652+
(expect (cider-repl-handle-external-body
653+
(list "message/external-body"
654+
(nrepl-dict "access-type" "URL" "URL" "file:/tmp/x.png"))
655+
(current-buffer) "")
656+
:to-be-truthy)
657+
(expect rendered :to-equal "file:/tmp/x.png")
658+
(expect requested :to-be nil))))
659+
660+
(it "does nothing (but still allows the prompt) without an access type"
661+
(let (rendered)
662+
(cl-letf (((symbol-function 'cider-repl--display-external-body)
663+
(lambda (_buffer url &rest _) (setq rendered url) t)))
664+
(expect (cider-repl-handle-external-body
665+
(list "message/external-body" (nrepl-dict))
666+
(current-buffer) "")
667+
:to-be-truthy)
668+
(expect rendered :to-be nil)))))

0 commit comments

Comments
 (0)