diff --git a/CHANGELOG.md b/CHANGELOG.md index dee8f7d15..65a001a4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/doc/modules/ROOT/pages/repl/configuration.adoc b/doc/modules/ROOT/pages/repl/configuration.adoc index 651b8c8d5..888a20add 100644 --- a/doc/modules/ROOT/pages/repl/configuration.adoc +++ b/doc/modules/ROOT/pages/repl/configuration.adoc @@ -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 diff --git a/doc/modules/ROOT/pages/troubleshooting.adoc b/doc/modules/ROOT/pages/troubleshooting.adoc index 00e97181b..4add06721 100644 --- a/doc/modules/ROOT/pages/troubleshooting.adoc +++ b/doc/modules/ROOT/pages/troubleshooting.adoc @@ -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 diff --git a/lisp/cider-repl.el b/lisp/cider-repl.el index f9cdb522c..8e5c96db9 100644 --- a/lisp/cider-repl.el +++ b/lisp/cider-repl.el @@ -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. @@ -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) diff --git a/test/cider-repl-tests.el b/test/cider-repl-tests.el index 5dd491761..8a01b6e72 100644 --- a/test/cider-repl-tests.el +++ b/test/cider-repl-tests.el @@ -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)))))