Skip to content

Commit

Permalink
Let sync-call errors use the stacktrace buffer
Browse files Browse the repository at this point in the history
Sync-call errors do not bind *e unlike eval-call errors. This made it
impossible to use the stacktrace middleware to create the nicely
analyzed and formatted stacktrace buffer (see Issue #1420
#1420).

In order to rectify this, the nREPL code was modified slightly to store
sync-call related errors and provide a mechanism for the stacktrace
middleware to retrieve and process these stored exceptions. This results
in the ability for sync-call related errors to be analyzed and presented
using the standard stacktract buffer.
  • Loading branch information
sanjayl committed Mar 19, 2016
1 parent d3a7790 commit 4636b51
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 16 deletions.
2 changes: 1 addition & 1 deletion cider-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ CONTEXT represents a completion context for compliment."
(when err
;; err will be a stacktrace with a first line that looks like:
;; "clojure.lang.ExceptionInfo: Unmatched delimiter ]"
(error (car (split-string err "\n"))))
(error (summarize-error response)))
(nrepl-dict-get response "formatted-edn")))


Expand Down
21 changes: 16 additions & 5 deletions cider-interaction.el
Original file line number Diff line number Diff line change
Expand Up @@ -811,13 +811,20 @@ into a new error buffer."
(cond (class (cons response causes))
(status (cider--render-stacktrace-causes causes)))))

(defun cider-default-err-op-handler ()
"Display the last exception, with middleware support."
(defun cider-default-err-op-handler (&optional storage-key)
"Display an exception, with middleware support.
If optional argument STORAGE-KEY is not given, will return the most recent
exception bound to *e; this binding typically happens during a non-sync
`eval` op. Optional argument STORAGE-KEY will look up a stored exception
instead of trying to use the *e bound exception; this is useful when the
error occurred due to a sync request op which typically do not bind *e."
;; Causes are returned as a series of messages, which we aggregate in `causes'
(let (causes)
(cider-nrepl-send-request
(append
(list "op" "stacktrace" "session" (cider-current-session))
(when storage-key
(list "storage-key" storage-key))
(when (cider--pprint-fn)
(list "pprint-fn" (cider--pprint-fn)))
(when cider-stacktrace-print-length
Expand All @@ -830,11 +837,15 @@ into a new error buffer."
;; after it has been handled, so it's fine to set it unconditionally here
(setq causes (cider--handle-stacktrace-response response causes))))))

(defun cider-default-err-handler ()
(defun cider-default-err-handler (&optional storage-key)
"This function determines how the error buffer is shown.
It delegates the actual error content to the eval or op handler."
It delegates the actual error content to the eval or op handler.
Optional argument STORAGE-KEY will be passed to the op handler to help
retrieve a stored exception instead of trying to use the *e bound
exception; this is useful when the error occurred due to a sync request op
which typically do not bind *e."
(if (cider-nrepl-op-supported-p "stacktrace")
(cider-default-err-op-handler)
(cider-default-err-op-handler storage-key)
(cider-default-err-eval-handler)))

(defvar cider-compilation-regexp
Expand Down
15 changes: 5 additions & 10 deletions nrepl-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -965,16 +965,11 @@ sign of user input, so as not to hang the interface."
(when (member "done" status)
(when-let ((ex (nrepl-dict-get response "ex"))
(err (nrepl-dict-get response "err")))
;; non-eval requests currently don't set the *e var
;; which is required by the stacktrace middleware
;; so we have to handle them differently until this is resolved
(if (member "eval-error" status)
(funcall nrepl-err-handler)
;; dump the stacktrace in the REPL
;; TODO: This has to be replaced with rendering of the
;; standard stacktrace buffer
(cider-repl-emit-interactive-stderr err)
(switch-to-buffer-other-window connection)))
;; Non-eval requests currently don't set the *e var
;; but instead get stored in util/storage, the storage-key
;; lets us retrieve these errors. If there's no storage-key,
;; then this will end up returning *e.
(funcall nrepl-err-handler (nrepl-dict-get response "storage-key")))
(when-let ((id (nrepl-dict-get response "id")))
(with-current-buffer connection
(nrepl--mark-id-completed id)))
Expand Down

0 comments on commit 4636b51

Please sign in to comment.