Skip to content

[eval] Refactor exception handling logic and overlay display #3789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 21, 2025
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
### Changes

- [#3782](https://github.com/clojure-emacs/cider/issues/3782): **(Breaking)** Drop official support for Emacs 26.
- Bump the injected `cider-nrepl` to [0.53.0](https://github.com/clojure-emacs/cider-nrepl/blob/master/CHANGELOG.md#0530-2025-03-19).
- Info: recognize printed Java classes/methods and munged Clojure functions in stacktrace outputs.
- Inspector: add dedicated view for Exceptions.
- Stop vendoring Haystack dependency.
- [#3777](https://github.com/clojure-emacs/cider/issues/3777): Inspector no longer displays parsed Javadoc for Java classes and members.
- [#3784](https://github.com/clojure-emacs/cider/issues/3784): Inspector: make point less erratic when navigating between inspector screens.
- [#3790](https://github.com/clojure-emacs/cider/issues/3790): Stacktrace: show messages and data for all exception causes by default.
- [#3789](https://github.com/clojure-emacs/cider/issues/3789): Refactor and simplify exception handling.

## 1.17.1 (2025-02-25)

Expand Down
407 changes: 173 additions & 234 deletions cider-eval.el

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion cider-stacktrace.el
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ the NAME. The whole group is prefixed by string INDENT."
"Emit into BUFFER the CAUSE NUM, exception class, message, data, and NOTE,
make INSPECT-INDEX actionable if present."
(with-current-buffer buffer
(nrepl-dbind-response cause (class message data spec stacktrace)
(nrepl-dbind-response cause (class message data spec triage stacktrace)
(let ((indent " ")
(class-face 'cider-stacktrace-error-class-face)
(message-face 'cider-stacktrace-error-message-face))
Expand All @@ -855,6 +855,11 @@ make INSPECT-INDEX actionable if present."
(propertize (or message "(No message)")
'font-lock-face message-face)
indent t))
(when triage
(insert "\n")
(cider-stacktrace-emit-indented
(propertize (string-trim triage) 'font-lock-face message-face)
indent nil))
(when spec
(insert "\n")
(cider-stacktrace--emit-spec-problems spec (concat indent " ")))
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.52.1"
(defconst cider-required-middleware-version "0.53.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.52.1"]])
:plugins [[cider/cider-nrepl "0.53.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.52.1"]
:plugins [[cider/cider-nrepl "0.53.0"]
[refactor-nrepl "3.9.0"]])
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.52.1"]]
:plugins [[cider/cider-nrepl "0.53.0"]]
----

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

[source,clojure]
----
{:repl {:plugins [[cider/cider-nrepl "0.52.1"]]}}
{:repl {:plugins [[cider/cider-nrepl "0.53.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.52.1"}}
:cider-clj {:extra-deps {cider/cider-nrepl {:mvn/version "0.53.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.52.1"}
cider/cider-nrepl {:mvn/version "0.53.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.52.1'
devImplementation 'cider:cider-nrepl:0.53.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.52.1"}}}' -m nrepl.cmdline --middleware '["cider.nrepl/cider-middleware"]'
$ clojure -Sdeps '{:deps {nrepl {:mvn/version "1.3.1"} cider/cider-nrepl {:mvn/version "0.53.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.52.1"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
$ clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.53.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.52.1"] ;; 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.53.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.52.1'
devImplementation 'cider:cider-nrepl:0.53.0'
devImplementation 'cider:cider-piggieback:0.5.3'
}

Expand Down
2 changes: 1 addition & 1 deletion nrepl-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ the corresponding type of response."
(when (member "interrupted" status)
(message "Evaluation interrupted."))
(when (member "eval-error" status)
(funcall (or eval-error-handler nrepl-err-handler)))
(funcall (or eval-error-handler nrepl-err-handler) buffer))
(when (member "namespace-not-found" status)
(message "Namespace `%s' not found." ns))
(when (member "need-input" status)
Expand Down
61 changes: 1 addition & 60 deletions test/cider-error-parsing-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
(match-string 1 clojure-compiler-warning))
:to-equal "warning")))
;; FIXME: duplicate spec names
(dolist (regexp (list cider-clojure-compilation-regexp cider-clojure-compilation-error-regexp))
(let ((regexp cider-clojure-compilation-regexp))
(it "Recognizes a clojure-1.10 error message"
(let ((clojure-1.10-compiler-error "Syntax error compiling at (src/ardoq/service/workspace_service.clj:227:3)."))
(expect clojure-1.10-compiler-error :to-match regexp)
Expand All @@ -139,65 +139,6 @@
(match-string 2 clojure-1.10-compiler-error))
:to-equal "src/haystack/parser.cljc")))))

(describe "cider-clojure-runtime-error-regexp"
(it "Recognizes a clojure-1.10 runtime error message"

;; Something like "(ArithmeticException)" will be absent for Exception and RuntimeException in particular
(let ((specimen "Execution error at foo/foo (src/haystack/parser.cljc:4)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "src/haystack/parser.cljc"))

(let ((specimen "Execution error (ArithmeticException) at foo/foo (src/haystack/parser.cljc:4)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "src/haystack/parser.cljc"))

;; without exception class cause-type
(let ((specimen "Execution error at (src/haystack/parser.cljc:4)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "src/haystack/parser.cljc"))

;; without foo/foo symbol
(let ((specimen "Execution error (ArithmeticException) at (src/haystack/parser.cljc:4)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "src/haystack/parser.cljc")))

(it "Recognizes a clojure-1.10 runtime spec validation error message"
(let ((specimen "Execution error - invalid arguments to foo/bar at (src/haystack/parser.cljc:4)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "src/haystack/parser.cljc")))

;; Java source locations may be negative (#3687)
(it "Recognizes an error thrown from a java source file"
(let ((specimen "Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "FileInputStream.java")))

(it "Recognizes errors thrown during the result printing phase"
(let ((specimen "Error printing return value (ClassCastException) at clojure.core/file-seq$fn (core.clj:4997)."))
(expect specimen :to-match cider-clojure-runtime-error-regexp)
(expect (progn
(string-match cider-clojure-runtime-error-regexp specimen)
(match-string 2 specimen))
:to-equal "core.clj"))))

(describe "cider-module-info-regexp"
(it "Matches module info provided by Java"
(expect " (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.IObj is in unnamed module of loader 'app')"
Expand Down
Loading