Subject: Re: bug#78458: 31.0.50; treesit.el: thing navigation functions work incorrectly with some Clojure nodes

From: Roman Rudakov <[email-masked]>
Date: Mon, 19 May 2025 10:15:40 +0200

Juri Linkov <[email-masked]> writes:

>>>> Reproducing issues requires installing clojure-ts-mode from 
>>>> NonGNU ELPA.
>>>
>>> Please also try all these test cases
>>> after calling 'treesit-cycle-sexp-type'.
>> This makes it somewhat better.
>>
>> There is still some weird behavior (I guess it's mostly related to 
>> the
>> Clojure grammar itself):
>>
>> #|(-> (.-value (.-target %)))
>>
>> If the point is at "|", calling "forward-sexp" moves it to:
>>
>> #(->| (.-value (.-target %)))
>>
>> And executing M-x raise-sexp produces:
>>
>> (->
>>
>> How can I set the default "cycle type" programmatically for a major 
>> mode?
>
> Programmatically you can set it by just adding 
> '(treesit-cycle-sexp-type)'
> to the end of 'clojure-ts-mode'.  Then theoretically it requires
> more changes in 'clojure-ts--sexp-nodes'.  But now I realized that
> no definition can match "(" with ")" when point is between "#" and 
> "(":
>
>   (anon_fn_lit marker: "#" open: "("
>
> So the right solution is without 'treesit-cycle-sexp-type'
> but with using 'sexp-default':
>
> @@ -1549,6 +1549,12 @@ clojure-ts--thing-settings
>    `((clojure
>       (sexp ,(regexp-opt clojure-ts--sexp-nodes))
>       (list ,(regexp-opt clojure-ts--list-nodes))
> +     (sexp-default
> +      ;; For `C-M-f' in "#|(a)"
> +      ("(" . ,(lambda (node)
> +                 (and (eq (char-before (point)) ?\#)
> +                      (equal (treesit-node-type 
> (treesit-node-parent node))
> +                             "anon_fn_lit")))))
>       (text ,(regexp-opt '("comment")))
>       (defun ,#'clojure-ts--defun-node-p))
>      (when clojure-ts-use-markdown-inline
Thanks Juri. I tried your patch and for some reason it doesn't solve 
the issue neither with 'raise-sexp' nor with 'C-M-f' navigation. The 
point is moved from:

#|(-> (.-value (.-target %)))

to

#(-> (.-value (.-target %))|)

and 'raise-sexp' called from:

#(-> |(.-value (.-target %)))

produces:

#(.-value (.-target %)))

Quick debugging confirmed that when the point is between # and ( the 
matched "thing" is 'sexp-default'.
--
Best regards, Roman