diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d7b03af7..1b0f51849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ## New features * Add new interactive command `cider-inspire-me`. It does what you'd expect. +* [#3162](https://github.com/clojure-emacs/cider/pull/3162): Save eval results into kill ring and registers. + * Add new customization variable `cider-eval-register` to automatically store the last interactive eval result into the specified register. + * Add interactive command `cider-kill-last-result` to manually save the last eval result into kill ring. ### Changes diff --git a/cider-client.el b/cider-client.el index a523d998e..00c906077 100644 --- a/cider-client.el +++ b/cider-client.el @@ -397,8 +397,8 @@ is included in the request if non-nil." (seq-mapcat #'identity) (apply #'nrepl-dict)))) (map-merge 'list - `(("nrepl.middleware.print/print" "cider.nrepl.pprint/pr" - "nrepl.middleware.print/stream?" nil)) + `(("nrepl.middleware.print/print" "cider.nrepl.pprint/pr") + ("nrepl.middleware.print/stream?" nil)) (unless (nrepl-dict-empty-p print-options) `(("nrepl.middleware.print/options" ,print-options))) (when cider-print-quota diff --git a/cider-eval.el b/cider-eval.el index e0f2e9a79..e47f1824e 100644 --- a/cider-eval.el +++ b/cider-eval.el @@ -167,6 +167,15 @@ If t, save the file without confirmation." :group 'cider :package-version '(cider . "0.16.0")) +(defcustom cider-eval-register ?e + "The text register assigned to the most recent evaluation result. +When non-nil, the return value of all CIDER eval commands are +automatically written into this register." + :type '(choice character + (const nil)) + :group 'cider + :package-version '(cider . "1.4.0")) + ;;; Utilities @@ -647,16 +656,21 @@ evaluation command. Honor `cider-auto-jump-to-error'." (defun cider-insert-eval-handler (&optional buffer) "Make an nREPL evaluation handler for the BUFFER. The handler simply inserts the result value in BUFFER." - (let ((eval-buffer (current-buffer))) + (let ((eval-buffer (current-buffer)) + (res "")) (nrepl-make-response-handler (or buffer eval-buffer) (lambda (_buffer value) (with-current-buffer buffer - (insert value))) + (insert value)) + (when cider-eval-register + (setq res (concat res value)))) (lambda (_buffer out) (cider-repl-emit-interactive-stdout out)) (lambda (_buffer err) (cider-handle-compilation-errors err eval-buffer)) - '()))) + (lambda (_buffer) + (when cider-eval-register + (set-register cider-eval-register res)))))) (defun cider--emit-interactive-eval-output (output repl-emit-function) "Emit output resulting from interactive code evaluation. @@ -715,15 +729,12 @@ when `cider-auto-inspect-after-eval' is non-nil." (end (or (car-safe (cdr-safe place)) place)) (beg (when beg (copy-marker beg))) (end (when end (copy-marker end))) - (fringed nil)) + (fringed nil) + (res "")) (nrepl-make-response-handler (or buffer eval-buffer) (lambda (_buffer value) - (if beg - (unless fringed - (cider--make-fringe-overlays-for-region beg end) - (setq fringed t)) - (cider--make-fringe-overlay end)) - (cider--display-interactive-eval-result value end)) + (setq res (concat res value)) + (cider--display-interactive-eval-result res end)) (lambda (_buffer out) (cider-emit-interactive-eval-output out)) (lambda (_buffer err) @@ -733,20 +744,31 @@ when `cider-auto-inspect-after-eval' is non-nil." (cider--display-interactive-eval-result err end 'cider-error-overlay-face))) (cider-handle-compilation-errors err eval-buffer)) - (when (and cider-auto-inspect-after-eval - (boundp 'cider-inspector-buffer) - (windowp (get-buffer-window cider-inspector-buffer 'visible))) - (lambda (buffer) + (lambda (buffer) + (if beg + (unless fringed + (cider--make-fringe-overlays-for-region beg end) + (setq fringed t)) + (cider--make-fringe-overlay end)) + (when (and cider-auto-inspect-after-eval + (boundp 'cider-inspector-buffer) + (windowp (get-buffer-window cider-inspector-buffer 'visible))) (cider-inspect-last-result) - (select-window (get-buffer-window buffer))))))) + (select-window (get-buffer-window buffer))) + (when cider-eval-register + (set-register cider-eval-register res)))))) + (defun cider-load-file-handler (&optional buffer done-handler) "Make a load file handler for BUFFER. Optional argument DONE-HANDLER lambda will be run once load is complete." - (let ((eval-buffer (current-buffer))) + (let ((eval-buffer (current-buffer)) + (res "")) (nrepl-make-response-handler (or buffer eval-buffer) (lambda (buffer value) (cider--display-interactive-eval-result value) + (when cider-eval-register + (setq res (concat res value))) (when (buffer-live-p buffer) (with-current-buffer buffer (cider--make-fringe-overlays-for-region (point-min) (point-max)) @@ -756,12 +778,18 @@ Optional argument DONE-HANDLER lambda will be run once load is complete." (lambda (_buffer err) (cider-emit-interactive-eval-err-output err) (cider-handle-compilation-errors err eval-buffer)) - (or done-handler '()) + (lambda (buffer) + (when cider-eval-register + (set-register cider-eval-register res)) + (when done-handler + (funcall done-handler buffer))) (lambda () (funcall nrepl-err-handler))))) (defun cider-eval-print-handler (&optional buffer) "Make a handler for evaluating and printing result in BUFFER." + ;; NOTE: cider-eval-register behavior is not implemented here for performance reasons. + ;; See https://github.com/clojure-emacs/cider/pull/3162 (nrepl-make-response-handler (or buffer (current-buffer)) (lambda (buffer value) (with-current-buffer buffer @@ -773,24 +801,28 @@ Optional argument DONE-HANDLER lambda will be run once load is complete." (cider-emit-interactive-eval-output out)) (lambda (_buffer err) (cider-emit-interactive-eval-err-output err)) - '())) + ())) (defun cider-eval-print-with-comment-handler (buffer location comment-prefix) "Make a handler for evaluating and printing commented results in BUFFER. LOCATION is the location marker at which to insert. COMMENT-PREFIX is the comment prefix to use." - (nrepl-make-response-handler buffer - (lambda (buffer value) - (with-current-buffer buffer - (save-excursion - (goto-char (marker-position location)) - (insert (concat comment-prefix - value "\n"))))) - (lambda (_buffer out) - (cider-emit-interactive-eval-output out)) - (lambda (_buffer err) - (cider-emit-interactive-eval-err-output err)) - '())) + (let ((res "")) + (nrepl-make-response-handler buffer + (lambda (_buffer value) + (setq res (concat res value))) + (lambda (_buffer out) + (cider-emit-interactive-eval-output out)) + (lambda (_buffer err) + (cider-emit-interactive-eval-err-output err)) + (lambda (buffer) + (with-current-buffer buffer + (save-excursion + (goto-char (marker-position location)) + (insert (concat comment-prefix + res "\n")))) + (when cider-eval-register + (set-register cider-eval-register value)))))) (defun cider-maybe-insert-multiline-comment (result comment-prefix continued-prefix comment-postfix) "Insert eval RESULT at current location if RESULT is not empty. @@ -825,7 +857,9 @@ COMMENT-POSTFIX is the text to output after the last line." (with-current-buffer buffer (save-excursion (goto-char (marker-position location)) - (cider-maybe-insert-multiline-comment res comment-prefix continued-prefix comment-postfix)))) + (cider-maybe-insert-multiline-comment res comment-prefix continued-prefix comment-postfix))) + (when cider-eval-register + (set-register cider-eval-register res))) nil nil (lambda (_buffer warning) @@ -834,6 +868,8 @@ COMMENT-POSTFIX is the text to output after the last line." (defun cider-popup-eval-handler (&optional buffer) "Make a handler for printing evaluation results in popup BUFFER. This is used by pretty-printing commands." + ;; NOTE: cider-eval-register behavior is not implemented here for performance reasons. + ;; See https://github.com/clojure-emacs/cider/pull/3162 (nrepl-make-response-handler (or buffer (current-buffer)) (lambda (buffer value) @@ -1293,6 +1329,12 @@ passing arguments." (form (format "(%s)" fn-name))) (cider-read-and-eval (cons form (length form))))) +(defun cider-kill-last-result () + "Save the last evaluated result into the kill ring." + (interactive) + (kill-new + (nrepl-dict-get (cider-nrepl-sync-request:eval "*1") "value"))) + ;; Eval keymaps (defvar cider-eval-pprint-commands-map (let ((map (define-prefix-command 'cider-eval-pprint-commands-map))) @@ -1326,6 +1368,7 @@ passing arguments." (define-key map (kbd "z") #'cider-eval-defun-up-to-point) (define-key map (kbd "c") #'cider-eval-last-sexp-in-context) (define-key map (kbd "b") #'cider-eval-sexp-at-point-in-context) + (define-key map (kbd "k") #'cider-kill-last-result) (define-key map (kbd "f") 'cider-eval-pprint-commands-map) ;; duplicates with C- for convenience @@ -1341,6 +1384,7 @@ passing arguments." (define-key map (kbd "C-z") #'cider-eval-defun-up-to-point) (define-key map (kbd "C-c") #'cider-eval-last-sexp-in-context) (define-key map (kbd "C-b") #'cider-eval-sexp-at-point-in-context) + (define-key map (kbd "C-k") #'cider-kill-last-result) (define-key map (kbd "C-f") 'cider-eval-pprint-commands-map) map)) diff --git a/doc/modules/ROOT/pages/usage/code_evaluation.adoc b/doc/modules/ROOT/pages/usage/code_evaluation.adoc index 8bb553296..07bebc83d 100644 --- a/doc/modules/ROOT/pages/usage/code_evaluation.adoc +++ b/doc/modules/ROOT/pages/usage/code_evaluation.adoc @@ -275,6 +275,34 @@ Additionally, there's the variable `cider-redirect-server-output-to-repl` that c NOTE: The redirection functionality is implemented in `cider-nrepl` as nREPL middleware. If you're using CIDER without `cider-nrepl` no output redirection is going to take place. + + +=== Storing eval results + +By default CIDER stores the return value of the most recent evaluation command +in the text register `e`. You can access these contents via `insert-register` +(kbd:[C-x r i]). + +This is often useful for closer inspection or textual manipulation of a +transiently displayed eval result, without having to re-evaluate the form with a +specialized command like `cider-insert-last-sexp-in-repl`. + +You can customize which register is used with the variable `cider-eval-register`, or set +it to `nil` to disable the feature. + +[source,lisp] +---- +(setq cider-eval-register nil) +---- + +TIP: The built-in xref:debugging/inspector.adoc[inspector] can be used to view +and navigate through complex nested results. + +You can also use the command `cider-kill-last-result`(kbd:[C-c C-v k]) after any +eval command to store its result in the kill ring. This works even when the +`cider-eval-register` feature is disabled. + + == Keybindings You might have noticed that CIDER typically has 2-3 different keybindings for @@ -383,6 +411,10 @@ kbd:[C-u C-c C-c] | `cider-load-all-files` | kbd:[C-c C-M-l] | Load (eval) all Clojure files below a directory. + +| `cider-kill-last-result` +| kbd:[C-c C-v k] +| Save the last evaluated result into the kill ring. |=== TIP: You'll find all evaluation commands and their keybindings in the `CIDER Eval` menu.