Skip to content

Commit 84b752e

Browse files
committed
[Fix clojure-emacs/cider#1323] Sexp navigation near end of buffer
1 parent 27c2a6f commit 84b752e

File tree

2 files changed

+51
-22
lines changed

2 files changed

+51
-22
lines changed

clojure-mode.el

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666

6767
(require 'cl-lib)
6868
(require 'imenu)
69+
(require 'newcomment)
6970

7071
(declare-function lisp-fill-paragraph "lisp-mode" (&optional justify))
7172

@@ -682,9 +683,11 @@ Implementation function for `clojure--find-indent-spec'."
682683
(let* ((function (thing-at-point 'symbol))
683684
(method (or (when function ;; Is there a spec here?
684685
(clojure--get-indent-method function))
685-
(progn (up-list) ;; Otherwise look higher up.
686-
(clojure-backward-logical-sexp 1)
687-
(clojure--find-indent-spec-backtracking)))))
686+
;; `up-list' errors on unbalanced sexps.
687+
(ignore-errors
688+
(up-list) ;; Otherwise look higher up.
689+
(clojure-backward-logical-sexp 1)
690+
(clojure--find-indent-spec-backtracking)))))
688691
(when (numberp method)
689692
(setq method (list method)))
690693
(pcase method
@@ -1103,23 +1106,23 @@ Returns a list pair, e.g. (\"defn\" \"abc\") or (\"deftest\" \"some-test\")."
11031106

11041107

11051108
;;; Sexp navigation
1106-
(defun clojure--looking-at-logical-sexp ()
1109+
(defun clojure--looking-at-non-logical-sexp ()
11071110
"Return non-nil if sexp after point represents code.
11081111
Sexps that don't represent code are ^metadata or #reader.macros."
1109-
(forward-sexp 1)
1110-
(forward-sexp -1)
1111-
(not (looking-at-p "\\^\\|#[?[:alpha:]]")))
1112+
(comment-normalize-vars)
1113+
(comment-forward (point-max))
1114+
(looking-at-p "\\^\\|#[?[:alpha:]]"))
11121115

11131116
(defun clojure-forward-logical-sexp (&optional n)
11141117
"Move forward N logical sexps.
11151118
This will skip over sexps that don't represent objects, so that ^hints and
11161119
#reader.macros are considered part of the following sexp."
11171120
(interactive "p")
1118-
(let ((forward-sexp-function nil))
1119-
(if (< n 0)
1120-
(clojure-backward-logical-sexp (- n))
1121+
(if (< n 0)
1122+
(clojure-backward-logical-sexp (- n))
1123+
(let ((forward-sexp-function nil))
11211124
(while (> n 0)
1122-
(while (not (clojure--looking-at-logical-sexp))
1125+
(while (clojure--looking-at-non-logical-sexp)
11231126
(forward-sexp 1))
11241127
;; The actual sexp
11251128
(forward-sexp 1)
@@ -1132,17 +1135,18 @@ This will skip over sexps that don't represent objects, so that ^hints and
11321135
(interactive "p")
11331136
(if (< n 0)
11341137
(clojure-forward-logical-sexp (- n))
1135-
(while (> n 0)
1136-
;; The actual sexp
1137-
(backward-sexp 1)
1138-
;; Non-logical sexps.
1139-
(while (and (not (bobp))
1140-
(ignore-errors
1141-
(save-excursion
1142-
(backward-sexp 1)
1143-
(not (clojure--looking-at-logical-sexp)))))
1144-
(backward-sexp 1))
1145-
(setq n (1- n)))))
1138+
(let ((forward-sexp-function nil))
1139+
(while (> n 0)
1140+
;; The actual sexp
1141+
(backward-sexp 1)
1142+
;; Non-logical sexps.
1143+
(while (and (not (bobp))
1144+
(ignore-errors
1145+
(save-excursion
1146+
(backward-sexp 1)
1147+
(clojure--looking-at-non-logical-sexp))))
1148+
(backward-sexp 1))
1149+
(setq n (1- n))))))
11461150

11471151
(defconst clojurescript-font-lock-keywords
11481152
(eval-when-compile

test/clojure-mode-sexp-test.el

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,31 @@
4040
(clojure-backward-logical-sexp 1)
4141
(should (looking-at-p "\\^String biverse"))))
4242

43+
(ert-deftest test-buffer-corners ()
44+
(with-temp-buffer
45+
(insert "^String reverse")
46+
(clojure-mode)
47+
;; Return nil and don't error
48+
(should-not (clojure-backward-logical-sexp 100))
49+
(should (looking-at-p "\\^String reverse"))
50+
(should-not (clojure-forward-logical-sexp 100))
51+
(should (looking-at-p "$")))
52+
(with-temp-buffer
53+
(clojure-mode)
54+
(insert "(+ 10")
55+
(should-error (clojure-backward-logical-sexp 100))
56+
(goto-char (point-min))
57+
(should-error (clojure-forward-logical-sexp 100))
58+
;; Just don't hang.
59+
(goto-char (point-max))
60+
(should-not (clojure-forward-logical-sexp 1))
61+
(erase-buffer)
62+
(insert "(+ 10")
63+
(newline)
64+
(erase-buffer)
65+
(insert "(+ 10")
66+
(newline-and-indent)))
67+
4368
(provide 'clojure-mode-sexp-test)
4469

4570
;;; clojure-mode-sexp-test.el ends here

0 commit comments

Comments
 (0)