Subject: bug#60983: 29.0.60; Tree-sitter user-level control

From: Theodor Thornhill <[email-masked]>
Date: Sun, 29 Jan 2023 20:12:39 +0100

Eli Zaretskii <[email-masked]> writes:

>> From: Yuan Fu <[email-masked]>
>> Date: Mon, 23 Jan 2023 15:55:30 -0800
>> Cc: Eli Zaretskii <[email-masked]>,
>>  Bug Report Emacs <[email-masked]>
>> 
>> >> Thanks.  What about the questions I asked regarding indentation
>> >> features, and specifically about c-ts-mode-indent-style?
>> > 
>> > I am working on that, but I hit some issues where I cannot make treesit recognize the new settings before the whole treesit-major-mode-setup reruns. Just setting the symbol doesn't work, and reenabling the mode inside of the :set function isn't the best idea maybe?
>> > 
>> > I'd love some pointers to how other modes do similar stuff, but I didn't really find anything.
>> 
>> One common approach is to iterate over all live buffer and reset the variable (in this case treesit-simple-indent-rules) on applicate buffers (in this case c/c++-ts-mode buffers).
>> 
>> It would be nice to also have a command c-ts-mode-set-style (like c-set-style) that takes a style symbol and sets treesit-simple-indent-rules accordingly. And in major-mode setup, ie, c-ts-mode’s body, you call it with c-ts-mode-indent-style.
>
> This command now exists, courtesy of Theo, but I see some strange
> misbehavior with it in c++-ts-mode, related to keymap inheritance:
>
>   emacs -Q
>   M-x c-ts-mode RET
>   C-h c C-c C-q
>   => C-c C-q runs the command c-ts-mode-indent-defun
>
> But
>
>   M-x c++-ts-mode RET
>   C-h c C-c C-q
>   => C-c C-q is undefined
>
> This is strange, since the binding is defined in c-ts-mode-map, which
> is used in c-ts-base-mode:
>
>   (defvar-keymap c-ts-mode-map
>     :doc "Keymap for the C language with tree-sitter"
>     :parent prog-mode-map
>     "C-c C-q" #'c-ts-mode-indent-defun
>     "C-c ." #'c-ts-mode-set-style)
>
>   ;;;###autoload
>   (define-derived-mode c-ts-base-mode prog-mode "C"
>     "Major mode for editing C, powered by tree-sitter.
>
>   \\{c-ts-mode-map}"
>     :syntax-table c-ts-mode--syntax-table
>
> and both c-ts-mode and c++-ts-mode derive from c-ts-base-mode:
>
>   (define-derived-mode c-ts-mode c-ts-base-mode "C"
>     "Major mode for editing C, powered by tree-sitter.
>
>   (define-derived-mode c++-ts-mode c-ts-base-mode "C++"
>     "Major mode for editing C++, powered by tree-sitter.
>
> What's missing here?  Stefan, any advice?

I'm sure you know this, but adding the below patch "fixes" it.  It seems
like the inheritance isn't registered somehow without a defined
mode-map?

Theo

diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 612c41bf07..e9f9eea69c 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -703,6 +703,10 @@ c-ts-mode-map
   "C-c C-q" #'c-ts-mode-indent-defun
   "C-c ." #'c-ts-mode-set-style)
 
+(defvar-keymap c++-ts-mode-map
+  :doc "Keymap for the C++ language with tree-sitter"
+  :parent c-ts-mode-map)
+
 ;;;###autoload
 (define-derived-mode c-ts-base-mode prog-mode "C"
   "Major mode for editing C, powered by tree-sitter.
@@ -810,7 +814,9 @@ c++-ts-mode
     (add-to-list \\='major-mode-remap-alist
                  \\='(c-or-c++-mode . c-or-c++-ts-mode))
 
-in your configuration."
+in your configuration.
+
+\\{c++-ts-mode-map}"
   :group 'c++
 
   (when (treesit-ready-p 'cpp)