diff --git a/CHANGELOG.md b/CHANGELOG.md index d17f69c16..80b7af676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ ### Changes +- `cider-eval`: support re-rendering the Inspector buffer when `cider-inspector-auto-select-buffer` is set to nil and there's a `*cider-inspect*` buffer shown in a non-visible frame. + - This supports the workflow of using the inspector occasionally (less intrusively), but ready to be shown anytime. - [#3626](https://github.com/clojure-emacs/cider/issues/3626): `cider-ns-refresh`: jump to the relevant file/line on errors. - [#3628](https://github.com/clojure-emacs/cider/issues/3628): `cider-ns-refresh`: summarize errors as an overlay. - Bump the injected nREPL to [1.1.1](https://github.com/nrepl/nrepl/blob/v1.1.1/CHANGELOG.md#111-2024-02-20). diff --git a/cider-eval.el b/cider-eval.el index b504e5b40..3b02c3d26 100644 --- a/cider-eval.el +++ b/cider-eval.el @@ -1001,7 +1001,7 @@ when `cider-auto-inspect-after-eval' is non-nil." (cider--make-fringe-overlay end)) (when (and cider-auto-inspect-after-eval (boundp 'cider-inspector-buffer) - (windowp (get-buffer-window cider-inspector-buffer 'visible))) + (windowp (cider--get-inspector-window))) (cider-inspect-last-result) (select-window (get-buffer-window buffer))) (when cider-eval-register diff --git a/cider-inspector.el b/cider-inspector.el index 103452c17..6cca0de00 100644 --- a/cider-inspector.el +++ b/cider-inspector.el @@ -31,13 +31,12 @@ (require 'easymenu) (require 'seq) (require 'cider-eval) +(require 'cider-util) ;; =================================== ;; Inspector Key Map and Derived Mode ;; =================================== -(defconst cider-inspector-buffer "*cider-inspect*") - ;;; Customization (defgroup cider-inspector nil "Presentation and behavior of the CIDER value inspector." diff --git a/cider-overlays.el b/cider-overlays.el index 6310bb0d3..f487716e7 100644 --- a/cider-overlays.el +++ b/cider-overlays.el @@ -252,10 +252,13 @@ overlay." ;; string, since we want it to be at the first char. (put-text-property 0 1 'cursor 0 display-string) (when (> (string-width display-string) (* 3 (window-width))) - (setq display-string - (concat (substring display-string 0 (* 3 (window-width))) - (substitute-command-keys - "...\nResult truncated. Type `\\[cider-inspect-last-result]' to inspect it.")))) + (let ((msg (if (cider--get-inspector-window) + (format "...\nResult truncated. It is currently visible in %s" cider-inspector-buffer) + "...\nResult truncated. Type `\\[cider-inspect-last-result]' to inspect it."))) + (setq display-string + (concat (substring display-string 0 (* 3 (window-width))) + (substitute-command-keys + msg))))) ;; Create the result overlay. (setq o (apply #'cider--make-overlay beg end type diff --git a/cider-popup.el b/cider-popup.el index 5d7beb564..9efa0a115 100644 --- a/cider-popup.el +++ b/cider-popup.el @@ -55,44 +55,49 @@ If SELECT is non-nil, select the buffer. You can customize how the window will be chosen/created by adding BUFFER-NAME to the `special-display-buffer-names' list." - (let ((buffer-name (if (bufferp buffer-name) ;; ensure buffer-name is a string - (buffer-name buffer-name) - buffer-name))) - ;; if `buffer-name' belongs to `special-display-buffer-names', - ;; delegate to that mechanism the displaying of the buffer, - ;; otherwise the displaying would happen twice (ance through `special-display-buffer-names', - ;; another time through `cider-popup-buffer-display'): - (if (and (boundp 'special-display-buffer-names) - (seq-find (lambda (entry) - (equal (car entry) buffer-name)) - special-display-buffer-names)) - (progn - (display-buffer buffer-name) - (when select - (when-let ((window (get-buffer-window buffer-name))) - (select-window window)))) - (let ((window (get-buffer-window buffer-name 'visible))) - (when window - (with-current-buffer buffer-name - (set-window-point window (point)))) - ;; If the buffer we are popping up is already displayed in the selected - ;; window, the below `inhibit-same-window' logic will cause it to be - ;; displayed twice - so we early out in this case. Note that we must check - ;; `selected-window', as async request handlers are executed in the context - ;; of the current connection buffer (i.e. `current-buffer' is dynamically - ;; bound to that). - (unless (eq window (selected-window)) - ;; Non nil `inhibit-same-window' ensures that current window is not covered - ;; Non nil `inhibit-switch-frame' ensures that the other frame is not selected - ;; if that's where the buffer is being shown. - (funcall (if select #'pop-to-buffer #'display-buffer) - buffer-name `(nil . ((inhibit-same-window . - ;; A non-nil value prevents the same window from being used for display: - ,pop-up-windows) - (reusable-frames . - ;; choose any visible frame - visible))))))) - (get-buffer buffer-name))) + (if (and (not select) + (get-buffer-window buffer-name t)) + ;; if the buffer is visible on some frame and the user didn't intend `select', we're done. + ;; This supports e.g. rendering contents to frames that the user might want to remain in the background (e.g. cider-log, cider-auto-inspect-after-eval) + nil + (let ((buffer-name (if (bufferp buffer-name) ;; ensure buffer-name is a string + (buffer-name buffer-name) + buffer-name))) + ;; if `buffer-name' belongs to `special-display-buffer-names', + ;; delegate to that mechanism the displaying of the buffer, + ;; otherwise the displaying would happen twice (ance through `special-display-buffer-names', + ;; another time through `cider-popup-buffer-display'): + (if (and (boundp 'special-display-buffer-names) + (seq-find (lambda (entry) + (equal (car entry) buffer-name)) + special-display-buffer-names)) + (progn + (display-buffer buffer-name) + (when select + (when-let ((window (get-buffer-window buffer-name))) + (select-window window)))) + (let ((window (get-buffer-window buffer-name 'visible))) + (when window + (with-current-buffer buffer-name + (set-window-point window (point)))) + ;; If the buffer we are popping up is already displayed in the selected + ;; window, the below `inhibit-same-window' logic will cause it to be + ;; displayed twice - so we early out in this case. Note that we must check + ;; `selected-window', as async request handlers are executed in the context + ;; of the current connection buffer (i.e. `current-buffer' is dynamically + ;; bound to that). + (unless (eq window (selected-window)) + ;; Non nil `inhibit-same-window' ensures that current window is not covered + ;; Non nil `inhibit-switch-frame' ensures that the other frame is not selected + ;; if that's where the buffer is being shown. + (funcall (if select #'pop-to-buffer #'display-buffer) + buffer-name `(nil . ((inhibit-same-window . + ;; A non-nil value prevents the same window from being used for display: + ,pop-up-windows) + (reusable-frames . + ;; choose any visible frame + visible))))))) + (get-buffer buffer-name)))) (defun cider-popup-buffer-quit (&optional kill) "Quit the current (temp) window. diff --git a/cider-util.el b/cider-util.el index 8316af962..b18235ecc 100644 --- a/cider-util.el +++ b/cider-util.el @@ -826,6 +826,24 @@ KIND can be the symbols `ns', `var', `emph', `fn', or a face name." (t x))) menu-list)) +;; Defined here to avoid circular dependencies +(defconst cider-inspector-buffer "*cider-inspect*") + +(defun cider--get-inspector-window () + "Returns a window showing the *cider-inspect* buffer, +honoring the `cider-inspector-auto-select-buffer' preference. + +May return nil." + (get-buffer-window cider-inspector-buffer + ;; pass arguments that work well with the existing + ;; `(cider-popup-buffer-display cider-inspector-buffer cider-inspector-auto-select-buffer)' + ;; usage in cider-inspector.el, + ;; namely: for `cider-inspector-auto-select-buffer' t, only consider windows that can be selected, + ;; for `cider-inspector-auto-select-buffer' nil, consider windows in all frames. + (if cider-inspector-auto-select-buffer + 'visible + t))) + (provide 'cider-util) ;;; cider-util.el ends here diff --git a/doc/modules/ROOT/pages/debugging/inspector.adoc b/doc/modules/ROOT/pages/debugging/inspector.adoc index d894f492b..5aa98f52b 100644 --- a/doc/modules/ROOT/pages/debugging/inspector.adoc +++ b/doc/modules/ROOT/pages/debugging/inspector.adoc @@ -17,7 +17,12 @@ Alternatively, after a regular eval command, you can inspect the last evaluated value using `cider-inspect-last-result`. When an inspector buffer is visible in the background, it is automatically updated with the last result. This behavior can be controlled with the variable -`cider-auto-inspect-after-eval`. +`cider-auto-inspect-after-eval` (and `cider-inspector-auto-select-buffer` +for even more fine-grained control over the UX). + +TIP: setting `cider-auto-inspect-after-eval` to `t` and `cider-inspector-auto-select-buffer` to nil +allows you to have the cider-inspector permanently open in a background frame. This way, +it's always there as you eval forms, while it doesn't interrupt you when it's not needed.` TIP: The inspector can also be invoked in the middle of a debugging session, see xref:debugging/debugger.adoc[here] for more details.