Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
- [#3793](https://github.com/clojure-emacs/cider/issues/3793): **(Breaking)** Remove features that relied on printed exception parsing:
- `cider-stacktrace-analyze-string` and `cider-stacktrace-analyze-at-point` functions.
- Automatic stacktrace parsing in log viewer.
- Bump the injected `cider-nrepl` to [0.54.0](https://github.com/clojure-emacs/cider-nrepl/blob/master/CHANGELOG.md#0540-2025-04-05).
- Bump the injected `cider-nrepl` to [0.55.0](https://github.com/clojure-emacs/cider-nrepl/blob/master/CHANGELOG.md#0550-2025-04-10).
- [compliment#122](https://github.com/alexander-yakushev/compliment/pull/122): Completion: sort candidates by priority.
- Inspector: add dedicated view for Exceptions.
- Stop vendoring Haystack dependency.
- Stop vendoring Puget dependency. You can still use `puget` pretty-printer in CIDER, but you need to depend on Puget explicitly. If Puget is not found on the classpath, CIDER will revert to `clojure.pprint/pprint` for pretty-printing.
- [#3777](https://github.com/clojure-emacs/cider/issues/3777): Inspector no longer displays parsed Javadoc for Java classes and members.
- [#3790](https://github.com/clojure-emacs/cider/issues/3790): Stacktrace: show messages and data for all exception causes by default.
- [#3807](https://github.com/clojure-emacs/cider/issues/3807): Stacktrace: make exception data individually inspectable.
- [#3789](https://github.com/clojure-emacs/cider/issues/3789): Refactor and simplify exception handling.
- [#3789](https://github.com/clojure-emacs/cider/issues/3796): Completion: disable client-side sorting (defer to backend-provided candidate order).
- [#3797](https://github.com/clojure-emacs/cider/issues/3797): Completion: enable `cider-completion-style` by default (this enables richer completion suggestions where candidates don't have to strictly match the prefix).
Expand Down
17 changes: 12 additions & 5 deletions cider-eval.el
Original file line number Diff line number Diff line change
Expand Up @@ -295,15 +295,21 @@ When clojure.stracktrace is not present."
(cider-nrepl-sync-request:eval
"(println (ex-data *e))")))

(defun cider--render-stacktrace-causes (causes &optional error-types is-compilation)
(defun cider--render-stacktrace-causes (causes &optional error-types
is-compilation repl)
"If CAUSES is non-nil, render its contents into a new error buffer.
Optional argument ERROR-TYPES contains a list which should determine the
op/situation that originated this error.
If IS-COMPILATION is true, render the stacktrace into the error buffer but
don't bring it forward."
don't bring it forward.
REPL connection can be provided to set it as the connection for the created
*cider-error* buffer."
(when causes
(let ((error-buffer (cider-new-error-buffer #'cider-stacktrace-mode
error-types is-compilation)))
(let* ((repl (or repl (cider-current-repl)))
(error-buffer (cider-new-error-buffer #'cider-stacktrace-mode
error-types is-compilation)))
(with-current-buffer error-buffer
(setq cider--ancillary-buffer-repl repl))
(cider-stacktrace-render error-buffer causes error-types))))

(defconst cider-clojure-compilation-error-phases-default-value
Expand Down Expand Up @@ -362,7 +368,8 @@ For others, pop up *cider-error* buffer."
(nrepl-notify msg type))))
;; Render stacktrace in *cider-error* buffer if it is a runtime error.
(cider--render-stacktrace-causes
causes nil (member ex-phase (cider-clojure-compilation-error-phases)))
causes nil (member ex-phase (cider-clojure-compilation-error-phases))
(with-current-buffer source-buffer (cider-current-repl)))
;; If the error is a compilation error (which we normally don't show
;; *cider-error* buffer for), or the error buffer is disabled, compensate for
;; the lack of info with a overlay error. Verify that the provided buffer is
Expand Down
20 changes: 9 additions & 11 deletions cider-inspector.el
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,17 @@ See `cider-sync-request:inspect-push' and `cider-inspector--render-value'"
(push (point) cider-inspector-location-stack)
(cider-inspector--render-value result :next-inspectable))))

(defun cider-inspector-inspect-last-exception (index)
"Inspects the exception in the cause stack identified by INDEX."
(defun cider-inspector-inspect-last-exception (index &optional ex-data)
"Inspects the exception in the cause stack identified by INDEX.
If EX-DATA is true, inspect ex-data of the exception instead."
(interactive)
(cl-assert (numberp index))
(let ((result (cider-sync-request:inspect-last-exception index)))
(let ((result (cider-nrepl-send-sync-request
`("op" "inspect-last-exception"
"index" ,index
,@(when ex-data
`("ex-data" "true")))
(cider-current-repl))))
(when (nrepl-dict-get result "value")
(setq cider-inspector-location-stack nil)
(cider-inspector--render-value result :next-inspectable))))
Expand Down Expand Up @@ -423,14 +429,6 @@ current-namespace."
(cider-nrepl-send-sync-request `("op" "inspect-previous-sibling")
(cider-current-repl)))

;;;###autoload
(defun cider-sync-request:inspect-last-exception (index)
"Inspects the exception in the cause stack identified by INDEX."
(cl-assert (numberp index))
(cider-nrepl-send-sync-request `("op" "inspect-last-exception"
"index" ,index)
(cider-current-repl)))

(defun cider-sync-request:inspect-next-sibling ()
"Inspect the next sibling value within a sequential parent."
(cider-nrepl-send-sync-request `("op" "inspect-next-sibling")
Expand Down
58 changes: 43 additions & 15 deletions cider-stacktrace.el
Original file line number Diff line number Diff line change
Expand Up @@ -796,27 +796,48 @@ the NAME. The whole group is prefixed by string INDENT."

(declare-function cider-inspector-inspect-last-exception "cider-inspector")

(defun cider-stacktrace--inspect-class (event)
"Mouse handler for EVENT."
(defun cider-stacktrace--inspect-mouse (event &optional ex-data)
"Mouse handler for EVENT.
If EX-DATA is true, inspect ex-data of the exception instead."
(interactive "e")
(let* ((pos (posn-point (event-end event)))
(window (posn-window (event-end event)))
(buffer (window-buffer window))
(inspect-index (with-current-buffer buffer
(get-text-property pos 'inspect-index))))
(cider-inspector-inspect-last-exception inspect-index)))
(cider-inspector-inspect-last-exception inspect-index ex-data)))

(defun cider-stacktrace--inspect-class-kbd ()
"Keyboard handler."
(defun cider-stacktrace--inspect-kbd (&optional ex-data)
"Keyboard handler.
If EX-DATA is true, inspect ex-data of the exception instead."
(interactive)
(when-let ((inspect-index (get-text-property (point) 'inspect-index)))
(cider-inspector-inspect-last-exception inspect-index)))
(cider-inspector-inspect-last-exception inspect-index ex-data)))

(defun cider-stacktrace--inspect-ex-data-mouse (event)
"Mouse handler for EVENT."
(interactive "e")
(cider-stacktrace--inspect-mouse event t))

(defun cider-stacktrace--inspect-ex-data-kbd ()
"Keyboard handler."
(interactive)
(cider-stacktrace--inspect-kbd t))

(defvar cider-stacktrace-exception-map
(let ((map (make-sparse-keymap)))
(define-key map [mouse-1] #'cider-stacktrace--inspect-class)
(define-key map (kbd "p") #'cider-stacktrace--inspect-class-kbd)
(define-key map (kbd "i") #'cider-stacktrace--inspect-class-kbd)
(define-key map [mouse-1] #'cider-stacktrace--inspect-mouse)
(define-key map (kbd "p") #'cider-stacktrace--inspect-kbd)
(define-key map (kbd "i") #'cider-stacktrace--inspect-kbd)
(define-key map (kbd "RET") #'cider-stacktrace--inspect-kbd)
map))

(defvar cider-stacktrace-ex-data-map
(let ((map (make-sparse-keymap)))
(define-key map [mouse-1] #'cider-stacktrace--inspect-ex-data-mouse)
(define-key map (kbd "p") #'cider-stacktrace--inspect-ex-data-kbd)
(define-key map (kbd "i") #'cider-stacktrace--inspect-ex-data-kbd)
(define-key map (kbd "RET") #'cider-stacktrace--inspect-ex-data-kbd)
map))

(defun cider-stacktrace-render-cause (buffer cause num note &optional inspect-index)
Expand All @@ -839,10 +860,10 @@ make INSPECT-INDEX actionable if present."
,cider-stacktrace-exception-map)
(insert (format "%d. " num)
(propertize note 'font-lock-face 'font-lock-comment-face) " "
(propertize class 'font-lock-face class-face 'mouse-face 'highlight)))
(propertize class 'font-lock-face class-face 'mouse-face 'highlight)
"\n"))
;; Detail level 1: message + ex-data
(cider-propertize-region '(detail 1)
(insert "\n")
(if (equal class "clojure.lang.Compiler$CompilerException")
(cider-stacktrace-render-compile-error buffer cause)
(cider-stacktrace-emit-indented
Expand All @@ -859,18 +880,25 @@ make INSPECT-INDEX actionable if present."
(cider-stacktrace--emit-spec-problems spec (concat indent " ")))
(when data
(insert "\n")
(cider-stacktrace-emit-indented data indent nil t)))
(cider-propertize-region `(inspect-index
,inspect-index
keymap
,cider-stacktrace-ex-data-map
mouse-face
highlight)
(cider-stacktrace-emit-indented data indent nil t)))
(insert "\n"))
;; Detail level 2: stacktrace
(cider-propertize-region '(detail 2)
(let ((beg (point))
(bg `(:background ,cider-stacktrace-frames-background-color :extend t)))
(dolist (frame stacktrace)
(insert "\n")
(cider-stacktrace-render-frame buffer frame))
(cider-stacktrace-render-frame buffer frame)
(insert "\n"))
(overlay-put (make-overlay beg (point)) 'font-lock-face bg)))
;; Add line break between causes, even when collapsed.
(cider-propertize-region '(detail 0)
(insert "\n\n")))))))
(insert "\n")))))))

(defun cider-stacktrace-initialize (causes)
"Set and apply CAUSES initial visibility, filters, and cursor position."
Expand Down
2 changes: 1 addition & 1 deletion cider.el
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ the artifact.")

Used when `cider-jack-in-auto-inject-clojure' is set to `latest'.")

(defconst cider-required-middleware-version "0.54.0"
(defconst cider-required-middleware-version "0.55.0"
"The CIDER nREPL version that's known to work properly with CIDER.")

(defcustom cider-injected-middleware-version cider-required-middleware-version
Expand Down
2 changes: 1 addition & 1 deletion dev/docker-sample-project/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
:dependencies [[org.clojure/clojure "1.11.1"]
[clj-http "3.12.3"]]
:source-paths ["src"]
:plugins [[cider/cider-nrepl "0.54.0"]])
:plugins [[cider/cider-nrepl "0.55.0"]])
2 changes: 1 addition & 1 deletion dev/tramp-sample-project/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
:dependencies [[org.clojure/clojure "1.11.1"]
[clj-http "3.12.3"]]
:source-paths ["src"]
:plugins [[cider/cider-nrepl "0.54.0"]
:plugins [[cider/cider-nrepl "0.55.0"]
[refactor-nrepl "3.9.0"]])
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions doc/modules/ROOT/pages/basics/middleware_setup.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ Use the convenient plugin for defaults, either in your project's

[source,clojure]
----
:plugins [[cider/cider-nrepl "0.54.0"]]
:plugins [[cider/cider-nrepl "0.55.0"]]
----

A minimal `profiles.clj` for CIDER would be:

[source,clojure]
----
{:repl {:plugins [[cider/cider-nrepl "0.54.0"]]}}
{:repl {:plugins [[cider/cider-nrepl "0.55.0"]]}}
----

WARNING: Be careful not to place this in the `:user` profile, as this way CIDER's
Expand All @@ -43,11 +43,11 @@ run `cider-connect` or `cider-connect-cljs`.

[source,clojure]
----
:cider-clj {:extra-deps {cider/cider-nrepl {:mvn/version "0.54.0"}}
:cider-clj {:extra-deps {cider/cider-nrepl {:mvn/version "0.55.0"}}
:main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware]"]}

:cider-cljs {:extra-deps {org.clojure/clojurescript {:mvn/version "1.10.339"}
cider/cider-nrepl {:mvn/version "0.54.0"}
cider/cider-nrepl {:mvn/version "0.55.0"}
cider/piggieback {:mvn/version "0.6.0"}}
:main-opts ["-m" "nrepl.cmdline" "--middleware"
"[cider.nrepl/cider-middleware,cider.piggieback/wrap-cljs-repl]"]}
Expand All @@ -66,7 +66,7 @@ NOTE: Make sure you're using https://github.com/clojurephant/clojurephant[Clojur
----
dependencies {
devImplementation 'nrepl:nrepl:0.9.0'
devImplementation 'cider:cider-nrepl:0.54.0'
devImplementation 'cider:cider-nrepl:0.55.0'
}

tasks.named('clojureRepl') {
Expand Down
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/basics/up_and_running.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ simple - CIDER passes the extra dependencies and nREPL configuration to
your build tool in the command it runs to start the nREPL server. Here's how
this looks for `tools.deps`:

$ clojure -Sdeps '{:deps {nrepl {:mvn/version "1.3.1"} cider/cider-nrepl {:mvn/version "0.54.0"}}}' -m nrepl.cmdline --middleware '["cider.nrepl/cider-middleware"]'
$ clojure -Sdeps '{:deps {nrepl {:mvn/version "1.3.1"} cider/cider-nrepl {:mvn/version "0.55.0"}}}' -m nrepl.cmdline --middleware '["cider.nrepl/cider-middleware"]'

TIP: If you don't want `cider-jack-in` to inject dependencies automatically, set
`cider-inject-dependencies-at-jack-in` to `nil`. Note that you'll have to setup
Expand Down Expand Up @@ -332,7 +332,7 @@ It is also possible for plain `clj`, although the command is somewhat longer:

[source,sh]
----
$ clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.54.0"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
$ clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.55.0"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
----

Alternatively, you can start nREPL either manually or using the facilities
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/cljs/shadow-cljs.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ And connect to it with `cider-connect`.
...For that to work, `shadow-cljs.edn` contents like the following are assumed:

```clj
:dependencies [[cider/cider-nrepl "0.54.0"] ;; mandatory (unless it's inherited from deps.edn or otherwise present in the classpath of shadow-cljs's JVM process)
:dependencies [[cider/cider-nrepl "0.55.0"] ;; mandatory (unless it's inherited from deps.edn or otherwise present in the classpath of shadow-cljs's JVM process)
[refactor-nrepl/refactor-nrepl "3.9.0"]] ;; refactor-nrepl is optional

:nrepl {:middleware [cider.nrepl/cider-middleware ;; it's advisable to explicitly add this middleware. It's automatically added by shadow-cljs (if available in the classpath), unless `:nrepl {:cider false}`
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/cljs/up_and_running.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ or in `build.gradle`:
----
dependencies {
devImplementation 'nrepl:nrepl:1.3.1'
devImplementation 'cider:cider-nrepl:0.54.0'
devImplementation 'cider:cider-nrepl:0.55.0'
devImplementation 'cider:cider-piggieback:0.5.3'
}

Expand Down
15 changes: 9 additions & 6 deletions doc/modules/ROOT/pages/usage/dealing_with_errors.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,21 @@ for instance:

== Inspector integration

Within `*cider-error*`, when clicking directly a top-level exception (any of them in the cause chain),
that specific exception will be inspected with the CIDER xref:debugging/inspector.adoc[Inspector].
Within `*cider-error*`, when clicking directly a top-level exception (any of
them in the cause chain), that specific exception will be inspected with the
CIDER xref:debugging/inspector.adoc[Inspector]. You can also click on the
rendered exception data to inspect it directly.
Copy link
Member

@bbatsov bbatsov Apr 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a good a idea to add here a couple of screenshots or some short gif video.


This allows you to better understand intrincate `ex-data`.
This clicking is defined and customizable in `cider-stacktrace-exception-map`
and `cider-stacktrace-ex-data-map`.

This clicking is defined and customizable in `cider-stacktrace-exception-map`, which has the following defaults:
image::cider-stacktrace-inspect.gif[Inspect the exceptions and ex-data]

=== Keybindings

|===
| Action | Description

| kbd:[click] or kbd:[i] or kbd:[p]
| Open the given exception in the Inspector.
| kbd:[click] or kbd:[i] or kbd:[p] or kbd:[Return]
| Open the given exception or ex-data in the Inspector.
|===
Loading