From 4636b516b41597cf1106529e27b6f3e36a15d941 Mon Sep 17 00:00:00 2001 From: sanjayl Date: Tue, 15 Mar 2016 22:10:28 -0400 Subject: [PATCH] Let sync-call errors use the stacktrace buffer 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 https://github.com/clojure-emacs/cider/issues/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. --- cider-client.el | 2 +- cider-interaction.el | 21 ++++++++++++++++----- nrepl-client.el | 15 +++++---------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/cider-client.el b/cider-client.el index c17fa4578..12cc8c4d6 100644 --- a/cider-client.el +++ b/cider-client.el @@ -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"))) diff --git a/cider-interaction.el b/cider-interaction.el index d4db5da0f..3575f2ce5 100644 --- a/cider-interaction.el +++ b/cider-interaction.el @@ -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 @@ -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 diff --git a/nrepl-client.el b/nrepl-client.el index bdab522a8..c00c9c4b6 100644 --- a/nrepl-client.el +++ b/nrepl-client.el @@ -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)))