Skip to content

Commit ade140e

Browse files
dan suttonbbatsov
dan sutton
authored andcommitted
Make beginning-of-defun aware of clojure comment form
Remove seq-find usage Move initialization of beginning-of-defun-function to correct spot Use new function name in tests Docstring for checkdoc
1 parent c5239f3 commit ade140e

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Changes
66

7+
* Add `clojure-toplevel-inside-comment-form` to make forms inside of `(comment ...)` forms appear as top level forms for evaluation and navigation.
78
* Require Emacs 25.1+.
89

910
## 5.8.2 (2018-08-09)

clojure-mode.el

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,8 @@ replacement for `cljr-expand-let`."
531531
(setq-local clojure-expected-ns-function #'clojure-expected-ns)
532532
(setq-local parse-sexp-ignore-comments t)
533533
(setq-local prettify-symbols-alist clojure--prettify-symbols-alist)
534-
(setq-local open-paren-in-column-0-is-defun-start nil))
534+
(setq-local open-paren-in-column-0-is-defun-start nil)
535+
(setq-local beginning-of-defun-function #'clojure-beginning-of-defun-function))
535536

536537
(defsubst clojure-in-docstring-p ()
537538
"Check whether point is in a docstring."
@@ -1898,6 +1899,7 @@ Returns a list pair, e.g. (\"defn\" \"abc\") or (\"deftest\" \"some-test\")."
18981899

18991900

19001901
;;; Sexp navigation
1902+
19011903
(defun clojure--looking-at-non-logical-sexp ()
19021904
"Return non-nil if text after point is \"non-logical\" sexp.
19031905
\"Non-logical\" sexp are ^metadata and #reader.macros."
@@ -1943,6 +1945,77 @@ This will skip over sexps that don't represent objects, so that ^hints and
19431945
(backward-sexp 1))
19441946
(setq n (1- n))))))
19451947

1948+
(defun clojure-top-level-form-p (first-form)
1949+
"Return truthy if the first form matches FIRST-FORM."
1950+
(condition-case nil
1951+
(save-excursion
1952+
(end-of-defun)
1953+
(clojure-backward-logical-sexp 1)
1954+
(forward-char 1)
1955+
(clojure-forward-logical-sexp 1)
1956+
(clojure-backward-logical-sexp 1)
1957+
(looking-at-p first-form))
1958+
(scan-error nil)))
1959+
1960+
(defun clojure-sexp-starts-until-position (position)
1961+
"Return the starting points for forms before POSITION.
1962+
Positions are in descending order to aide in finding the first starting
1963+
position before the current position."
1964+
(save-excursion
1965+
(let (sexp-positions)
1966+
(condition-case nil
1967+
(while (< (point) position)
1968+
(clojure-forward-logical-sexp 1)
1969+
(clojure-backward-logical-sexp 1)
1970+
(push (point) sexp-positions)
1971+
(clojure-forward-logical-sexp 1))
1972+
(scan-error nil))
1973+
sexp-positions)))
1974+
1975+
(defcustom clojure-toplevel-inside-comment-form nil
1976+
"Eval top level forms inside comment forms instead of the comment form itself.
1977+
Experimental. Function `cider-defun-at-point' is used extensively so if we
1978+
change this heuristic it needs to be bullet-proof and desired. While
1979+
testing, give an easy way to turn this new behavior off."
1980+
:type 'boolean
1981+
:safe #'booleanp
1982+
:package-version '(clojure-mode . "5.8.3"))
1983+
1984+
(defun clojure-find-first (pred coll)
1985+
"Find first element of COLL for which PRED return truthy."
1986+
(let ((found)
1987+
(haystack coll))
1988+
(while (and (not found)
1989+
haystack)
1990+
(if (funcall pred (car haystack))
1991+
(setq found (car haystack))
1992+
(setq haystack (cdr haystack))))
1993+
found))
1994+
1995+
(defun clojure-beginning-of-defun-function ()
1996+
"Go to top level form.
1997+
Set as `beginning-of-defun-function' so that these generic
1998+
operators can be used."
1999+
(let ((beginning-of-defun-function nil))
2000+
(if (and clojure-toplevel-inside-comment-form
2001+
(clojure-top-level-form-p "comment"))
2002+
(save-match-data
2003+
(let ((original-position (point))
2004+
clojure-comment-start clojure-comment-end)
2005+
(end-of-defun)
2006+
(setq clojure-comment-end (point))
2007+
(clojure-backward-logical-sexp 1) ;; beginning of comment form
2008+
(setq clojure-comment-start (point))
2009+
(forward-char 1) ;; skip paren so we start at comment
2010+
(clojure-forward-logical-sexp) ;; skip past the comment form itself
2011+
(if-let ((sexp-start (clojure-find-first (lambda (beg-pos)
2012+
(< beg-pos original-position))
2013+
(clojure-sexp-starts-until-position
2014+
clojure-comment-end))))
2015+
(progn (goto-char sexp-start) t)
2016+
(progn (beginning-of-defun) t))))
2017+
(progn (beginning-of-defun) t))))
2018+
19462019
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
19472020
;;
19482021
;; Refactoring support

test/clojure-mode-sexp-test.el

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,51 @@
2222
(require 'clojure-mode)
2323
(require 'ert)
2424

25+
(defmacro clojure-buffer-with-text (text &rest body)
26+
"Run body in a temporary clojure buffer with TEXT.
27+
TEXT is a string with a | indicating where point is. The | will be erased
28+
and point left there."
29+
(declare (indent 2))
30+
`(progn
31+
(with-temp-buffer
32+
(erase-buffer)
33+
(clojure-mode)
34+
(insert ,text)
35+
(goto-char (point-min))
36+
(re-search-forward "|")
37+
(delete-char -1)
38+
,@body)))
39+
40+
(ert-deftest test-clojure-top-level-form-p ()
41+
(clojure-buffer-with-text
42+
"(comment
43+
(wrong)
44+
(rig|ht)
45+
(wrong))"
46+
;; make this use the native beginning of defun since this is used to
47+
;; determine whether to use the comment aware version or not.
48+
(should (let ((beginning-of-defun-function nil))
49+
(clojure-top-level-form-p "comment")))))
50+
51+
(ert-deftest test-clojure-beginning-of-defun-function ()
52+
(clojure-buffer-with-text
53+
"(comment
54+
(wrong)
55+
(wrong)
56+
(rig|ht)
57+
(wrong))"
58+
(beginning-of-defun)
59+
(should (looking-at-p "(comment")))
60+
(clojure-buffer-with-text
61+
"(comment
62+
(wrong)
63+
(wrong)
64+
(rig|ht)
65+
(wrong))"
66+
(let ((clojure-toplevel-inside-comment-form t))
67+
(beginning-of-defun))
68+
(should (looking-at-p "(right)"))))
69+
2570
(ert-deftest test-sexp-with-commas ()
2671
(with-temp-buffer
2772
(insert "[], {}, :a, 2")

0 commit comments

Comments
 (0)