Skip to content

Commit 9f3d759

Browse files
committed
Merge remote-tracking branch 'origin/main' into add-clojure-mode-tests
2 parents a39b4d9 + e69b0ac commit 9f3d759

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [#53]: Let `clojure-ts-mode` derive from `clojure-mode` for Emacs 30+.
99
- [#42]: Fix imenu support for definitions with metadata.
1010
- [#42]: Fix font locking of definitions with metadata
11+
- [#42]: Fix indentation of definitions with metadata
1112

1213
## 0.2.2 (2024-02-16)
1314

Diff for: clojure-ts-mode.el

+10-2
Original file line numberDiff line numberDiff line change
@@ -737,19 +737,20 @@ https://github.com/weavejester/cljfmt/blob/fb26b22f569724b05c93eb2502592dfc2de89
737737
(or (clojure-ts--symbol-node-p first-child)
738738
(clojure-ts--keyword-node-p first-child)))))
739739

740-
(defun clojure-ts--match-expression-in-body (_node parent _bol)
740+
(defun clojure-ts--match-expression-in-body (node parent _bol)
741741
"Match NODE if it is an expression used in a body argument.
742742
PARENT is expected to be a list literal.
743743
See `treesit-simple-indent-rules'."
744744
(and
745745
(clojure-ts--list-node-p parent)
746-
(let ((first-child (treesit-node-child parent 0 t)))
746+
(let ((first-child (clojure-ts--node-child-skip-metadata parent 0)))
747747
(and
748748
(not
749749
(clojure-ts--symbol-matches-p
750750
;; Symbols starting with this are false positives
751751
(rx line-start (or "default" "deflate" "defer"))
752752
first-child))
753+
(not (clojure-ts--match-with-metadata node))
753754
(clojure-ts--symbol-matches-p
754755
clojure-ts--symbols-with-body-expressions-regexp
755756
first-child)))))
@@ -821,6 +822,12 @@ forms like deftype, defrecord, reify, proxy, etc."
821822
(clojure-ts--match-fn-docstring parent)
822823
(clojure-ts--match-method-docstring parent))))
823824

825+
(defun clojure-ts--match-with-metadata (node &optional _parent _bol)
826+
"Match NODE when it has metadata."
827+
(let ((prev-sibling (treesit-node-prev-sibling node)))
828+
(and prev-sibling
829+
(clojure-ts--metadata-node-p prev-sibling))))
830+
824831
(defun clojure-ts--semantic-indent-rules ()
825832
"Return a list of indentation rules for `treesit-simple-indent-rules'."
826833
`((clojure
@@ -833,6 +840,7 @@ forms like deftype, defrecord, reify, proxy, etc."
833840
(clojure-ts--match-threading-macro-arg prev-sibling 0)
834841
;; https://guide.clojure.style/#vertically-align-fn-args
835842
(clojure-ts--match-function-call-arg (nth-sibling 2 nil) 0)
843+
(clojure-ts--match-with-metadata parent 0)
836844
;; Literal Sequences
837845
((parent-is "list_lit") parent 1) ;; https://guide.clojure.style/#one-space-indent
838846
((parent-is "vec_lit") parent 1) ;; https://guide.clojure.style/#bindings-alignment

Diff for: test/clojure-ts-mode-indentation-test.el

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
;;; clojure-ts-mode-indentation-test.el --- Clojure TS Mode: indentation test suite -*- lexical-binding: t; -*-
2+
3+
;; Copyright © 2022-2024 Danny Freeman
4+
5+
;; This file is not part of GNU Emacs.
6+
7+
;; This program is free software; you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation, either version 3 of the License, or
10+
;; (at your option) any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;; You should have received a copy of the GNU General Public License
18+
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
20+
;;; Commentary:
21+
22+
;; The unit test suite of Clojure TS Mode
23+
24+
(require 'clojure-ts-mode)
25+
(require 'cl-lib)
26+
(require 'buttercup)
27+
(require 's nil t) ;Don't burp if it's missing during compilation.
28+
29+
30+
(defmacro when-indenting-with-point-it (description before after)
31+
"Return a buttercup spec.
32+
33+
Check whether the swift indentation command will correctly change the buffer.
34+
Will also check whether point is moved to the expected position.
35+
36+
BEFORE is the buffer string before indenting, where a pipe (|) represents
37+
point.
38+
39+
AFTER is the expected buffer string after indenting, where a pipe (|)
40+
represents the expected position of point.
41+
42+
DESCRIPTION is a string with the description of the spec."
43+
(declare (indent 1))
44+
`(it ,description
45+
(let* ((after ,after)
46+
(expected-cursor-pos (1+ (clojure-ts--s-index-of "|" after)))
47+
(expected-state (delete ?| after)))
48+
(with-clojure-ts-buffer ,before
49+
(goto-char (point-min))
50+
(search-forward "|")
51+
(delete-char -1)
52+
(font-lock-ensure)
53+
(indent-according-to-mode)
54+
(expect (buffer-string) :to-equal expected-state)
55+
(expect (point) :to-equal expected-cursor-pos)))))
56+
57+
58+
59+
;; Backtracking indent
60+
(defmacro when-indenting-it (description &rest forms)
61+
"Return a buttercup spec.
62+
63+
Check that all FORMS correspond to properly indented sexps.
64+
65+
DESCRIPTION is a string with the description of the spec."
66+
(declare (indent 1))
67+
`(it ,description
68+
(progn
69+
,@(mapcar (lambda (form)
70+
`(with-temp-buffer
71+
(clojure-ts-mode)
72+
(insert "\n" ,form);,(replace-regexp-in-string "\n +" "\n " form))
73+
(indent-region (point-min) (point-max))
74+
(expect (buffer-string) :to-equal ,(concat "\n" form))))
75+
forms))))
76+
77+
78+
;; Provide font locking for easier test editing.
79+
80+
(font-lock-add-keywords
81+
'emacs-lisp-mode
82+
`((,(rx "(" (group "when-indenting-with-point-it") eow)
83+
(1 font-lock-keyword-face))
84+
(,(rx "("
85+
(group "when-indenting-with-point-it") (+ space)
86+
(group bow (+ (not space)) eow)
87+
)
88+
(1 font-lock-keyword-face)
89+
(2 font-lock-function-name-face))))
90+
91+
92+
(describe "indentation"
93+
(it "should not hang on end of buffer"
94+
(with-clojure-ts-buffer "(let [a b]"
95+
(goto-char (point-max))
96+
(expect
97+
(with-timeout (2)
98+
(newline-and-indent)
99+
t))))
100+
101+
(when-indenting-with-point-it "should have no indentation at top level"
102+
"|x"
103+
104+
"|x")
105+
106+
(when-indenting-it "should handle non-symbol at start"
107+
"
108+
{\"1\" 2
109+
*3 4}")
110+
111+
(when-indenting-it "should have no indentation at top level lists with metadata"
112+
"
113+
^{:foo true}
114+
(def b 2)")
115+
116+
(when-indenting-it "should have no indentation at top level vectors with metadata"
117+
"
118+
^{:foo true}
119+
[1 2]")
120+
121+
(when-indenting-it "should have no indentation at top level maps with metadata"
122+
"
123+
^{:foo true}
124+
{:a 1}")
125+
126+
(when-indenting-it "should have no indentation with metadata inside comment"
127+
"
128+
(comment
129+
^{:a 1}
130+
(def a 2))")
131+
132+
(when-indenting-it "should have params, docstring and body correctly indented in presence of metadata"
133+
"
134+
^{:foo true}
135+
(defn c
136+
\"hello\"
137+
[_foo]
138+
(+ 1 1))"))

Diff for: test/samples/indentation.clj

+25
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,28 @@
118118
([a] a)
119119
([a b]
120120
b))})
121+
122+
123+
^:foo
124+
(def a 1)
125+
126+
^{:foo true}
127+
(def b 2)
128+
129+
^{:foo true}
130+
[1 2]
131+
132+
(comment
133+
^{:a 1}
134+
(def a 2))
135+
136+
(defn hinted
137+
(^String [])
138+
(^java.util.List
139+
[a & args]))
140+
141+
^{:foo true}
142+
(defn c
143+
"hello"
144+
[_foo]
145+
(+ 1 1))

Diff for: test/test-helper.el

+9
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,13 @@ and point left there."
4646
(delete-char -1)
4747
,@body)))
4848

49+
(defun clojure-ts--s-index-of (needle s &optional ignore-case)
50+
"Returns first index of NEEDLE in S, or nil.
51+
52+
If IGNORE-CASE is non-nil, the comparison is done without paying
53+
attention to case differences."
54+
(declare (pure t) (side-effect-free t))
55+
(let ((case-fold-search ignore-case))
56+
(string-match-p (regexp-quote needle) s)))
57+
4958
;;; test-helper.el ends here

0 commit comments

Comments
 (0)