Skip to content

Commit b0e4199

Browse files
committed
*cider-error*: open a given exception in the Inspector by clicking it
Fixes #3565
1 parent eea9e5a commit b0e4199

File tree

4 files changed

+85
-6
lines changed

4 files changed

+85
-6
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master (unreleased)
44

5+
### New features
6+
7+
- [#3565](https://github.com/clojure-emacs/cider/issues/3565): [`*cider-error*`](https://docs.cider.mx/cider/usage/dealing_with_errors.html#inspector-integration): open a given Exception in the [Inspector](https://docs.cider.mx/cider/debugging/inspector.html) by clicking it, or hitting <kbd>p</kbd>.
8+
59
### Changes
610

711
- CIDER [Inspector](https://docs.cider.mx/cider/debugging/inspector.html): display Java class/method/field info when available.

cider-inspector.el

+24
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,17 @@ See `cider-sync-request:inspect-push' and `cider-inspector--render-value'"
236236
(cider-inspector--render-value result 'v2)
237237
(cider-inspector-next-inspectable-object 1))))
238238

239+
(defun cider-inspector-inspect-last-exception (index)
240+
"Inspects the exception in the cause stack identified by INDEX."
241+
(interactive)
242+
(cl-assert (numberp index))
243+
(setq cider-inspector--current-repl (cider-current-repl))
244+
(let ((result (cider-sync-request:inspect-last-exception index 'v2)))
245+
(when (nrepl-dict-get result "value")
246+
(push (point) cider-inspector-location-stack)
247+
(cider-inspector--render-value result 'v2)
248+
(cider-inspector-next-inspectable-object 1))))
249+
239250
(defun cider-inspector-previous-sibling ()
240251
"Inspect the previous sibling value within a sequential parent.
241252
See `cider-sync-request:inspect-previous-sibling' and `cider-inspector--render-value'"
@@ -387,6 +398,19 @@ instead of just its \"value\" entry."
387398
result
388399
(nrepl-dict-get result "value"))))
389400

401+
;;;###autoload
402+
(defun cider-sync-request:inspect-last-exception (index &optional v2)
403+
"Inspects the exception in the cause stack identified by INDEX,
404+
V2 indicates if the entire response should be returned
405+
instead of just its \"value\" entry."
406+
(cl-assert (numberp index))
407+
(let ((result (thread-first `("op" "inspect-last-exception"
408+
"index" ,index)
409+
(cider-nrepl-send-sync-request cider-inspector--current-repl))))
410+
(if v2
411+
result
412+
(nrepl-dict-get result "value"))))
413+
390414
(defun cider-sync-request:inspect-next-sibling (&optional v2)
391415
"Inspect the next sibling value within a sequential parent,
392416
V2 indicates if the entire response should be returned

cider-stacktrace.el

+39-6
Original file line numberDiff line numberDiff line change
@@ -799,16 +799,48 @@ the NAME. The whole group is prefixed by string INDENT."
799799
(cider-stacktrace--insert-named-group indent2 "extras: \n")
800800
(cider-stacktrace-emit-indented extra (concat indent2 " ") nil t)))))))
801801

802-
(defun cider-stacktrace-render-cause (buffer cause num note)
803-
"Emit into BUFFER the CAUSE NUM, exception class, message, data, and NOTE."
802+
(declare-function cider-inspector-inspect-last-exception "cider-inspector")
803+
804+
(defun cider-stacktrace--inspect-class (event)
805+
"Mouse handler for EVENT."
806+
(interactive "e")
807+
(let* ((pos (posn-point (event-end event)))
808+
(window (posn-window (event-end event)))
809+
(buffer (window-buffer window))
810+
(inspect-index (with-current-buffer buffer
811+
(get-text-property pos 'inspect-index))))
812+
(cider-inspector-inspect-last-exception inspect-index)))
813+
814+
(defun cider-stacktrace--inspect-class-kbd ()
815+
"Keyboard handler."
816+
(interactive)
817+
(when-let ((inspect-index (get-text-property (point) 'inspect-index)))
818+
(cider-inspector-inspect-last-exception inspect-index)))
819+
820+
(defvar cider-stacktrace-exception-map
821+
(let ((map (make-sparse-keymap)))
822+
(define-key map [mouse-1] #'cider-stacktrace--inspect-class)
823+
(define-key map (kbd "p") #'cider-stacktrace--inspect-class-kbd)
824+
map))
825+
826+
(defun cider-stacktrace-render-cause (buffer cause num note &optional inspect-index)
827+
"Emit into BUFFER the CAUSE NUM, exception class, message, data, and NOTE,
828+
make INSPECT-INDEX actionable if present."
804829
(with-current-buffer buffer
805830
(nrepl-dbind-response cause (class message data spec stacktrace)
806831
(let ((indent " ")
807832
(class-face 'cider-stacktrace-error-class-face)
808833
(message-face 'cider-stacktrace-error-message-face))
809834
(cider-propertize-region `(cause ,num)
810835
;; Detail level 0: exception class
811-
(cider-propertize-region '(detail 0)
836+
(cider-propertize-region `(detail
837+
0
838+
839+
inspect-index
840+
,inspect-index
841+
842+
keymap
843+
,cider-stacktrace-exception-map)
812844
(insert (format "%d. " num)
813845
(propertize note 'font-lock-face 'font-lock-comment-face) " "
814846
(propertize class 'font-lock-face class-face)
@@ -885,10 +917,11 @@ through the `cider-stacktrace-suppressed-errors' variable."
885917
(cider-stacktrace-render-suppression-toggle buffer error-types)
886918
(insert "\n\n"))
887919
;; Stacktrace exceptions & frames
888-
(let ((num (length causes)))
920+
(let* ((causes-length (length causes))
921+
(num causes-length))
889922
(dolist (cause causes)
890-
(let ((note (if (= num (length causes)) "Unhandled" "Caused by")))
891-
(cider-stacktrace-render-cause buffer cause num note)
923+
(let ((note (if (= num causes-length) "Unhandled" "Caused by")))
924+
(cider-stacktrace-render-cause buffer cause num note (- causes-length num))
892925
(setq num (1- num))))))
893926
(cider-stacktrace-initialize causes)
894927
(font-lock-refresh-defaults)))

doc/modules/ROOT/pages/usage/dealing_with_errors.adoc

+18
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,21 @@ Cider recognizes stacktraces printed in the following formats:
295295
buffer. When `cider-stacktrace-analyze-at-point` fails to detect the
296296
stacktrace, `cider-stacktrace-analyze-in-region` can be used to
297297
select the stacktrace manually.
298+
299+
== Inspector integration
300+
301+
Within `*cider-error*`, when clicking directly a top-level exception (any of them in the cause chain),
302+
that specific exception will be inspected with the CIDER xref:debugging/inspector.adoc[Inspector].
303+
304+
This allows you to better understand intrincate `ex-data`.
305+
306+
This clicking is defined and customizable in `cider-stacktrace-exception-map`, which has the following defaults:
307+
308+
=== Keybindings
309+
310+
|===
311+
| Action | Description
312+
313+
| kbd:[click] or kbd:[p]
314+
| Open the given exception in the Inspector.
315+
|===

0 commit comments

Comments
 (0)