Skip to content

Commit 6c39b34

Browse files
committed
Merge pull request #690 from vitoshka/truename
Three related patches on error handling.
2 parents 74d47ef + fdfc40b commit 6c39b34

File tree

2 files changed

+81
-50
lines changed

2 files changed

+81
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### New features
66

7+
* New `cider-auto-jump-to-error` control variable for auto jumping to error
8+
location.
79
* [#537](https://github.com/clojure-emacs/cider/pull/537): New support for
810
Java symbol lookup from cider-nrepl's info middleware.
911
* [#570](https://github.com/clojure-emacs/cider/pull/570): Enable toggling

cider-interaction.el

Lines changed: 79 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@
6464
(defcustom cider-show-error-buffer t
6565
"Control the popup behavior of cider stacktraces.
6666
The following values are possible t or 'always, 'except-in-repl,
67-
'only-in-repl. Any other value, including nil, will cause the stacktrace
67+
'only-in-repl. Any other value, including nil, will cause the stacktrace
6868
not to be automatically shown.
6969
7070
Irespective of the value of this variable, the `cider-error-buffer' is
71-
always generated in the background. Use `cider-visit-error-buffer' to
71+
always generated in the background. Use `cider-visit-error-buffer' to
7272
navigate to this buffer."
7373
:type '(choice (const :tag "always" t)
7474
(const except-in-repl)
@@ -79,6 +79,12 @@ navigate to this buffer."
7979
(define-obsolete-variable-alias 'cider-popup-stacktraces
8080
'cider-show-error-buffer "0.7.0")
8181

82+
(defcustom cider-auto-jump-to-error t
83+
"When non-nill automatically jump to error location during interactive compilation."
84+
:type 'boolean
85+
:group 'cider
86+
:package-version '(cider . "0.7.0"))
87+
8288
(defcustom cider-auto-select-error-buffer t
8389
"Controls whether to auto-select the error popup buffer."
8490
:type 'boolean
@@ -219,7 +225,7 @@ endpoint and Clojure version."
219225
(or (match-string 1 repl-buffer-name) "<no designation>")))
220226

221227
(defun cider-change-buffers-designation ()
222-
"Changes the designation in cider buffer names.
228+
"Change the designation in cider buffer names.
223229
Buffer names changed are cider-repl, nrepl-connection and nrepl-server."
224230
(interactive)
225231
(cider-ensure-connected)
@@ -551,8 +557,8 @@ If no local or remote file exists, return nil."
551557

552558
(defun cider--url-to-file (url)
553559
"Return the filename from the resource URL.
554-
Uses `url-generic-parse-url' to parse the url. The filename is extracted and
555-
then url decoded. If the decoded filename has a Windows device letter followed
560+
Uses `url-generic-parse-url' to parse the url. The filename is extracted and
561+
then url decoded. If the decoded filename has a Windows device letter followed
556562
by a colon immediately after the leading '/' then the leading '/' is dropped to
557563
create a valid path."
558564
(let ((filename (url-unhex-string (url-filename (url-generic-parse-url url)))))
@@ -770,9 +776,8 @@ The handler simply inserts the result value in BUFFER."
770776
(lambda (_buffer out)
771777
(cider-repl-emit-interactive-output out))
772778
(lambda (buffer err)
773-
(message "%s" err)
774-
(cider-highlight-compilation-errors
775-
buffer err))
779+
(cider-highlight-compilation-errors buffer err)
780+
(cider-jump-to-error-maybe buffer err))
776781
'()))
777782

778783
(defun cider-emit-interactive-eval-output (output)
@@ -799,8 +804,8 @@ This is controlled via `cider-interactive-eval-output-destination'."
799804
(cider-emit-interactive-eval-output out))
800805
(lambda (buffer err)
801806
(cider-emit-interactive-eval-output err)
802-
(cider-highlight-compilation-errors
803-
buffer err))
807+
(cider-highlight-compilation-errors buffer err)
808+
(cider-jump-to-error-maybe buffer err))
804809
'()))
805810

806811
(defun cider-load-file-handler (buffer)
@@ -815,8 +820,8 @@ This is controlled via `cider-interactive-eval-output-destination'."
815820
(cider-emit-interactive-eval-output value))
816821
(lambda (buffer err)
817822
(cider-emit-interactive-eval-output err)
818-
(cider-highlight-compilation-errors
819-
buffer err))
823+
(cider-highlight-compilation-errors buffer err)
824+
(cider-jump-to-error-maybe buffer err))
820825
'()
821826
(lambda (buffer ex root-ex session)
822827
(funcall nrepl-err-handler
@@ -919,19 +924,23 @@ They exist for compatibility with `next-error'."
919924
(status (when causes
920925
(cider-stacktrace-render buffer (reverse causes))))))))))
921926

927+
(defun cider--show-error-buffer-p (buffer)
928+
"Return non-nil if stacktrace buffer must be shown on error.
929+
Takes into account the current BUFFER and the value of `cider-show-error-buffer'."
930+
(let ((replp (with-current-buffer buffer (derived-mode-p 'cider-repl-mode))))
931+
(memq cider-show-error-buffer
932+
(if replp
933+
'(t always only-in-repl)
934+
'(t always except-in-repl)))))
935+
922936
(defun cider-default-err-handler (buffer ex root-ex session)
923937
"Make an error handler for BUFFER, EX, ROOT-EX and SESSION.
924938
This function determines how the error buffer is shown, and then delegates
925939
the actual error content to the eval or op handler."
926-
(let* ((replp (with-current-buffer buffer (derived-mode-p 'cider-repl-mode)))
927-
(showp (memq cider-show-error-buffer
928-
(if replp
929-
'(t always only-in-repl)
930-
'(t always except-in-repl))))
931-
(error-buffer (if (not showp)
932-
(cider-make-popup-buffer cider-error-buffer)
933-
(cider-popup-buffer cider-error-buffer
934-
cider-auto-select-error-buffer))))
940+
(let* ((error-buffer (if (cider--show-error-buffer-p buffer)
941+
(cider-popup-buffer cider-error-buffer
942+
cider-auto-select-error-buffer)
943+
(cider-make-popup-buffer cider-error-buffer))))
935944
(if (nrepl-op-supported-p "stacktrace")
936945
(cider-default-err-op-handler error-buffer session)
937946
(cider-default-err-eval-handler error-buffer session))))
@@ -972,42 +981,62 @@ See `compilation-error-regexp-alist' for help on their format.")
972981
(or type 2))
973982
message))))
974983

975-
(defun cider--find-expression-start ()
976-
"Find the beginning a list, vector, map or set outside of a string.
984+
(defun cider--goto-expression-start ()
985+
"Go to the beginning a list, vector, map or set outside of a string.
977986
978987
We do so by starting and the current position and proceeding backwards
979988
until we find a delimiters that's not inside a string."
980-
(while (or (not (looking-at "[({[]")) (eq 'font-lock-string-face (get-text-property (point) 'face)))
989+
(while (or (not (looking-at "[({[]"))
990+
(eq 'font-lock-string-face
991+
(get-text-property (point) 'face)))
981992
(backward-char)))
982993

994+
(defun cider--find-last-error-location (buffer message)
995+
"Return the location (begin . end) in BUFFER from the clojure error MESSAGE.
996+
If location could not be found, return nil."
997+
(save-excursion
998+
(with-current-buffer buffer
999+
(let ((info (cider-extract-error-info cider-compilation-regexp message)))
1000+
(when info
1001+
(let ((file (nth 0 info))
1002+
(line (nth 1 info))
1003+
(col (nth 2 info)))
1004+
(save-excursion
1005+
;; when we don't have a filename or it's different from the one of
1006+
;; the current buffer, the line number is relative to form start
1007+
(if (and file (equal (file-truename file)
1008+
(file-truename (buffer-file-name))))
1009+
(goto-char (point-min)) ; start of file
1010+
(beginning-of-defun))
1011+
(forward-line (1- line))
1012+
(move-to-column (or col 0))
1013+
(let ((begin (progn (if col (cider--goto-expression-start) (back-to-indentation))
1014+
(point)))
1015+
(end (progn (if col (forward-list) (move-end-of-line nil))
1016+
(point))))
1017+
(cons begin end)))))))))
1018+
9831019
(defun cider-highlight-compilation-errors (buffer message)
9841020
"Highlight compilation error line in BUFFER, using MESSAGE."
985-
(with-current-buffer buffer
986-
(let ((info (cider-extract-error-info cider-compilation-regexp message)))
987-
(when info
988-
(let ((file (nth 0 info))
989-
(line (nth 1 info))
990-
(col (nth 2 info))
991-
(face (nth 3 info))
992-
(note (nth 4 info)))
993-
(save-excursion
994-
;; when we don't have a filename or it's different from the one of
995-
;; the current buffer, the line number is relative to form start
996-
(if (and file (equal file (file-truename (buffer-file-name))))
997-
(goto-char (point-min)) ; start of file
998-
(beginning-of-defun))
999-
(forward-line (1- line))
1000-
;; if have column, highlight sexp at that point otherwise whole line.
1001-
(move-to-column (or col 0))
1002-
;; we need to select a region to which to apply the error overlay
1003-
;; we try to select the encompassing list, vector, set or map literal
1004-
(let ((begin (progn (if col (cider--find-expression-start) (back-to-indentation)) (point)))
1005-
(end (progn (if col (forward-list) (move-end-of-line nil)) (point))))
1006-
(let ((overlay (make-overlay begin end)))
1007-
(overlay-put overlay 'cider-note-p t)
1008-
(overlay-put overlay 'face face)
1009-
(overlay-put overlay 'cider-note note)
1010-
(overlay-put overlay 'help-echo note)))))))))
1021+
(-when-let* ((pos (cider--find-last-error-location buffer message))
1022+
(overlay (make-overlay (car pos) (cdr pos) buffer))
1023+
(info (cider-extract-error-info cider-compilation-regexp message)))
1024+
(let ((face (nth 3 info))
1025+
(note (nth 4 info)))
1026+
(overlay-put overlay 'cider-note-p t)
1027+
(overlay-put overlay 'face face)
1028+
(overlay-put overlay 'cider-note note)
1029+
(overlay-put overlay 'help-echo note)
1030+
(overlay-put overlay 'modification-hooks
1031+
(list (lambda (o &rest args) (delete-overlay o)))))))
1032+
1033+
(defun cider-jump-to-error-maybe (buffer err)
1034+
"If `cider-auto-jump-to-error' is non-nil, retrieve error location from ERR and jump to it."
1035+
(-when-let (pos (and cider-auto-jump-to-error
1036+
(cider--find-last-error-location buffer err)))
1037+
(with-current-buffer buffer
1038+
(goto-char (car pos)))))
1039+
10111040

10121041
(defun cider-need-input (buffer)
10131042
"Handle an need-input request from BUFFER."

0 commit comments

Comments
 (0)