Skip to content

Commit 82df151

Browse files
committed
Define sexp-default thing to improve navigation in Emacs 31
1 parent 3522b57 commit 82df151

File tree

4 files changed

+119
-3
lines changed

4 files changed

+119
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [#96](https://github.com/clojure-emacs/clojure-ts-mode/pull/96): Highlight function name properly in `extend-protocol` form.
66
- [#96](https://github.com/clojure-emacs/clojure-ts-mode/pull/96): Add support for extend-protocol forms to `clojure-ts-add-arity` refactoring
77
command.
8+
- Slightly improved navigation by s-expressions for Emacs 31.
89

910
## 0.4.0 (2025-05-15)
1011

clojure-ts-mode.el

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,8 @@ literals with regex grammar."
788788

789789
(defun clojure-ts--metadata-node-p (node)
790790
"Return non-nil if NODE is a Clojure metadata node."
791-
(string-equal "meta_lit" (treesit-node-type node)))
791+
(or (string-equal "meta_lit" (treesit-node-type node))
792+
(string-equal "old_meta_lit" (treesit-node-type node))))
792793

793794
(defun clojure-ts--var-node-p (node)
794795
"Return non-nil if NODE is a var (eg. #\\'foo)."
@@ -1545,10 +1546,23 @@ function literal."
15451546
"code_span")
15461547
"Nodes representing s-expressions in the `markdown-inline' parser.")
15471548

1549+
(defun clojure-ts--default-sexp-node-p (node)
1550+
"Return TRUE if point is NODE is either function literal or set or has metadata."
1551+
(or
1552+
;; Opening paren of set or function literal.
1553+
(and (eq (char-before (point)) ?\#)
1554+
(string-match-p (rx bol (or "anon_fn_lit" "set_lit") eol)
1555+
(treesit-node-type (treesit-node-parent node))))
1556+
;; Node with metadata.
1557+
(clojure-ts--metadata-node-p (treesit-node-prev-sibling node))))
1558+
15481559
(defconst clojure-ts--thing-settings
15491560
`((clojure
15501561
(sexp ,(regexp-opt clojure-ts--sexp-nodes))
15511562
(list ,(regexp-opt clojure-ts--list-nodes))
1563+
(sexp-default
1564+
;; For `C-M-f' in "#|(a)" or "#|{1 2 3}"
1565+
(,(rx (or "(" "{" "[")) . ,#'clojure-ts--default-sexp-node-p))
15521566
(text ,(regexp-opt '("comment")))
15531567
(defun ,#'clojure-ts--defun-node-p))
15541568
(when clojure-ts-use-markdown-inline
@@ -2130,7 +2144,7 @@ type, etc. See `treesit-thing-settings' for more details."
21302144
(newline-and-indent))
21312145
(when single-arity-p
21322146
(insert-pair 2 ?\( ?\))
2133-
(backward-up-list))
2147+
(forward-char -1))
21342148
(insert "([])\n")
21352149
;; Put the point between square brackets.
21362150
(down-list -2)))
@@ -2601,6 +2615,13 @@ REGEX-AVAILABLE."
26012615
0
26022616
t)
26032617

2618+
;; Improve navigation by matching parenthesis for Emacs 31+
2619+
(when (>= emacs-major-version 31)
2620+
(setq-local up-list-function
2621+
(lambda (&optional arg escape-strings no-syntax-crossing)
2622+
(let ((treesit-sexp-type-regexp 'sexp))
2623+
(treesit-up-list arg escape-strings no-syntax-crossing)))))
2624+
26042625
;; Workaround for treesit-transpose-sexps not correctly working with
26052626
;; treesit-thing-settings on Emacs 30.
26062627
;; Once treesit-transpose-sexps it working again this can be removed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
;;; clojure-ts-mode-navigation-test.el --- Clojure[TS] Mode: code navigation test suite -*- lexical-binding: t; -*-
2+
3+
;; Copyright (C) 2025 Roman Rudakov
4+
5+
;; Author: Roman Rudakov <rrudakov@fastmail.com>
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+
;; Verify that Emacs' built-in navigation commands work as expected.
23+
24+
;;; Code:
25+
26+
(require 'clojure-ts-mode)
27+
(require 'buttercup)
28+
(require 'test-helper "test/test-helper")
29+
30+
(describe "function literals"
31+
(describe "forward-sexp"
32+
(when-refactoring-with-point-it "should navigate to a closing paren if point is before an opening paren"
33+
"#|(-> (.-value (.-target %)))"
34+
"#(-> (.-value (.-target %)))|"
35+
(forward-sexp))
36+
(when-refactoring-with-point-it "should navigate to a closing paren if point is before a # character"
37+
"|#(-> (.-value (.-target %)))"
38+
"#(-> (.-value (.-target %)))|"
39+
(forward-sexp)))
40+
41+
(describe "backward-up-list"
42+
(when-refactoring-with-point-it "should navigate to the beginning of a parent expression"
43+
"#(-> |(.-value (.-target %)))"
44+
"|#(-> (.-value (.-target %)))"
45+
(backward-up-list)))
46+
47+
(describe "raise-sexp"
48+
(when-refactoring-with-point-it "should keep balanced parenthesis"
49+
"#(-> |(.-value (.-target %)))"
50+
"|(.-value (.-target %))"
51+
(raise-sexp))))
52+
53+
(describe "sets"
54+
(describe "forward-sexp"
55+
(when-refactoring-with-point-it "should navigate to a closing paren if point is before an opening paren"
56+
"#|{1 2 3}"
57+
"#{1 2 3}|"
58+
(forward-sexp))
59+
(when-refactoring-with-point-it "should navigate to a closing paren if point is before a # character"
60+
"|#{1 2 3}"
61+
"#{1 2 3}|"
62+
(forward-sexp)))
63+
64+
(describe "backward-up-list"
65+
(when-refactoring-with-point-it "should navigate to the beginning of a parent expression"
66+
"#{1 |2 3}"
67+
"|#{1 2 3}"
68+
(backward-up-list)))
69+
70+
(describe "raise-sexp"
71+
(when-refactoring-with-point-it "should not keep unwanted characters"
72+
"#{1 |2 3}"
73+
"|2"
74+
(raise-sexp))))
75+
76+
(describe "nodes with metadata"
77+
(describe "forward-sexp"
78+
(when-refactoring-with-point-it "should navigate to a closing paren if point is before an opening paren"
79+
"^String |[arg]"
80+
"^String [arg]|"
81+
(forward-sexp))
82+
;; This is not perfect, but with the current grammar we cannot handle it better.
83+
(when-refactoring-with-point-it "should naigate to a closing paren if point is before metadata"
84+
"|^String [arg]"
85+
"^String [arg]|"
86+
(forward-sexp))))
87+
88+
(provide 'clojure-ts-mode-navigation-test)
89+
;;; clojure-ts-mode-navigation-test.el ends here

test/samples/refactoring.clj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,14 @@
7676
(def my-name "Roma")
7777

7878
(defn say-hello
79-
[]
79+
^String []
8080
(println "Hello" my-name))
8181

82+
(defn foo
83+
^{:bla "meta"}
84+
[arg]
85+
body)
86+
8287
(definline bad-sqr [x] `(* ~x ~x))
8388

8489
(defmulti service-charge (juxt account-level :tag))

0 commit comments

Comments
 (0)