Subject: Re: bug#79363: 31.0.50; Font locking issue in go-ts-mode when tree-sitter grammar is automatically installed

From: Roi Martin <[email-masked]>
Date: Fri, 05 Sep 2025 10:56:09 +0200

Fix font lock and indentation in cmake-ts-mode when the tree-sitter
grammar is automatically installed.

>From ab579a84dc6ebd35fffa62c641872b7d0b2151fc Mon Sep 17 00:00:00 2001
From: Roi Martin <[email-masked]>
Date: Thu, 4 Sep 2025 07:40:32 +0200
Subject: [PATCH] Fix font lock and indentation in cmake-ts-mode

Fix font lock and indentation in cmake-ts-mode when the tree-sitter
grammar is automatically installed (Bug#79363).
* lisp/progmodes/cmake-ts-mode.el (cmake-ts-mode--indent-rules)
(cmake-ts-mode--font-lock-settings): Evaluate the rules only after the
tree-sitter grammar is installed.
(cmake-ts-mode): Call the new `cmake-ts-mode--indent-rules' and
`cmake-ts-mode--font-lock-settings' functions.
---
 lisp/progmodes/cmake-ts-mode.el | 182 +++++++++++++++++---------------
 1 file changed, 99 insertions(+), 83 deletions(-)

diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el
index 84589b1eb73b..8e49b18f7313 100644
--- a/lisp/progmodes/cmake-ts-mode.el
+++ b/lisp/progmodes/cmake-ts-mode.el
@@ -61,28 +61,36 @@ cmake-ts-mode--syntax-table
     table)
   "Syntax table for `cmake-ts-mode'.")
 
-(defvar cmake-ts-mode--indent-rules
-  `((cmake
-     ((node-is ")") parent-bol 0)
-     ((node-is "else_command") parent-bol 0)
-     ((node-is "elseif_command") parent-bol 0)
-     ((node-is "endforeach_command") parent-bol 0)
-     ((node-is "endfunction_command") parent-bol 0)
-     ((node-is "endif_command") parent-bol 0)
-     ((parent-is "foreach_loop") parent-bol cmake-ts-mode-indent-offset)
-     ((parent-is "function_def") parent-bol cmake-ts-mode-indent-offset)
-     ((parent-is "if_condition") parent-bol cmake-ts-mode-indent-offset)
-     ((parent-is "normal_command") parent-bol cmake-ts-mode-indent-offset)
-     ;;; Release v0.4.0 wraps arguments in an argument_list node.
-     ,@(ignore-errors
-         (treesit-query-capture 'cmake '((argument_list) @capture))
-         `(((parent-is "argument_list") grand-parent cmake-ts-mode-indent-offset)))
-     ;;; Release v0.3.0 wraps the body of commands into a body node.
-     ,@(ignore-errors
-         (treesit-query-capture 'cmake '((body) @capture))
-         `(((parent-is "body") grand-parent cmake-ts-mode-indent-offset)))))
+(defvar cmake-ts-mode--indent-rules nil
   "Tree-sitter indent rules for `cmake-ts-mode'.")
 
+(defun cmake-ts-mode--indent-rules ()
+  "Return tree-sitter indent rules for `cmake-ts-mode'.
+
+Tree-sitter indent rules are evaluated the first time this function
+is called.  Subsequent calls return the first evaluated value."
+  (or cmake-ts-mode--indent-rules
+      (setq cmake-ts-mode--indent-rules
+            `((cmake
+               ((node-is ")") parent-bol 0)
+               ((node-is "else_command") parent-bol 0)
+               ((node-is "elseif_command") parent-bol 0)
+               ((node-is "endforeach_command") parent-bol 0)
+               ((node-is "endfunction_command") parent-bol 0)
+               ((node-is "endif_command") parent-bol 0)
+               ((parent-is "foreach_loop") parent-bol cmake-ts-mode-indent-offset)
+               ((parent-is "function_def") parent-bol cmake-ts-mode-indent-offset)
+               ((parent-is "if_condition") parent-bol cmake-ts-mode-indent-offset)
+               ((parent-is "normal_command") parent-bol cmake-ts-mode-indent-offset)
+               ;; Release v0.4.0 wraps arguments in an argument_list node.
+               ,@(ignore-errors
+                   (treesit-query-capture 'cmake '((argument_list) @capture))
+                   `(((parent-is "argument_list") grand-parent cmake-ts-mode-indent-offset)))
+               ;; Release v0.3.0 wraps the body of commands into a body node.
+               ,@(ignore-errors
+                   (treesit-query-capture 'cmake '((body) @capture))
+                   `(((parent-is "body") grand-parent cmake-ts-mode-indent-offset))))))))
+
 (defvar cmake-ts-mode--constants
   '("ON" "TRUE" "YES" "Y" "OFF" "FALSE" "NO" "N" "IGNORE" "NOTFOUND")
   "CMake constants for tree-sitter font-locking.")
@@ -140,69 +148,77 @@ cmake-ts-mode--font-lock-compatibility-fe9b5e0
                           eol))
                   @font-lock-constant-face))))))))
 
-(defvar cmake-ts-mode--font-lock-settings
-  (treesit-font-lock-rules
-   :language 'cmake
-   :feature 'bracket
-   '((["(" ")"]) @font-lock-bracket-face)
-
-   :language 'cmake
-   :feature 'builtin
-   (cmake-ts-mode--font-lock-compatibility-fe9b5e0)
-
-   :language 'cmake
-   :feature 'comment
-   '([(bracket_comment) (line_comment)] @font-lock-comment-face)
-
-   :language 'cmake
-   :feature 'constant
-   `(((argument) @font-lock-constant-face
-      (:match ,(rx-to-string
-                `(seq bol
-                      (or ,@cmake-ts-mode--constants)
-                      eol))
-              @font-lock-constant-face)))
-
-   :language 'cmake
-   :feature 'function
-   '((normal_command (identifier) @font-lock-function-call-face))
-
-   :language 'cmake
-   :feature 'keyword
-   `([,@cmake-ts-mode--keywords] @font-lock-keyword-face)
-
-   :language 'cmake
-   :feature 'number
-   '(((unquoted_argument) @font-lock-number-face
-      (:match "\\`-?[[:digit:]]*\\.?[[:digit:]]*\\.?[[:digit:]]+\\'"
-              @font-lock-number-face)))
-
-   :language 'cmake
-   :feature 'string
-   '([(bracket_argument) (quoted_argument)] @font-lock-string-face)
-
-   :language 'cmake
-   :feature 'escape-sequence
-   :override t
-   '((escape_sequence) @font-lock-escape-face)
-
-   :language 'cmake
-   :feature 'misc-punctuation
-   ;; Don't override strings.
-   :override 'nil
-   '((["$" "{" "}"]) @font-lock-misc-punctuation-face)
-
-   :language 'cmake
-   :feature 'variable
-   :override t
-   '((variable) @font-lock-variable-use-face)
-
-   :language 'cmake
-   :feature 'error
-   :override t
-   '((ERROR) @font-lock-warning-face))
+(defvar cmake-ts-mode--font-lock-settings nil
   "Tree-sitter font-lock settings for `cmake-ts-mode'.")
 
+(defun cmake-ts-mode--font-lock-settings ()
+  "Return tree-sitter font-lock settings for `cmake-ts-mode'.
+
+Tree-sitter font-lock rules are evaluated the first time this function
+is called.  Subsequent calls return the first evaluated value."
+  (or cmake-ts-mode--font-lock-settings
+      (setq cmake-ts-mode--font-lock-settings
+            (treesit-font-lock-rules
+             :language 'cmake
+             :feature 'bracket
+             '((["(" ")"]) @font-lock-bracket-face)
+
+             :language 'cmake
+             :feature 'builtin
+             (cmake-ts-mode--font-lock-compatibility-fe9b5e0)
+
+             :language 'cmake
+             :feature 'comment
+             '([(bracket_comment) (line_comment)] @font-lock-comment-face)
+
+             :language 'cmake
+             :feature 'constant
+             `(((argument) @font-lock-constant-face
+                (:match ,(rx-to-string
+                          `(seq bol
+                                (or ,@cmake-ts-mode--constants)
+                                eol))
+                        @font-lock-constant-face)))
+
+             :language 'cmake
+             :feature 'function
+             '((normal_command (identifier) @font-lock-function-call-face))
+
+             :language 'cmake
+             :feature 'keyword
+             `([,@cmake-ts-mode--keywords] @font-lock-keyword-face)
+
+             :language 'cmake
+             :feature 'number
+             '(((unquoted_argument) @font-lock-number-face
+                (:match "\\`-?[[:digit:]]*\\.?[[:digit:]]*\\.?[[:digit:]]+\\'"
+                        @font-lock-number-face)))
+
+             :language 'cmake
+             :feature 'string
+             '([(bracket_argument) (quoted_argument)] @font-lock-string-face)
+
+             :language 'cmake
+             :feature 'escape-sequence
+             :override t
+             '((escape_sequence) @font-lock-escape-face)
+
+             :language 'cmake
+             :feature 'misc-punctuation
+             ;; Don't override strings.
+             :override 'nil
+             '((["$" "{" "}"]) @font-lock-misc-punctuation-face)
+
+             :language 'cmake
+             :feature 'variable
+             :override t
+             '((variable) @font-lock-variable-use-face)
+
+             :language 'cmake
+             :feature 'error
+             :override t
+             '((ERROR) @font-lock-warning-face)))))
+
 (defun cmake-ts-mode--defun-name (node)
   "Return the defun name of NODE.
 Return nil if there is no name or if NODE is not a defun node."
@@ -238,10 +254,10 @@ cmake-ts-mode
     (setq-local which-func-functions nil)
 
     ;; Indent.
-    (setq-local treesit-simple-indent-rules cmake-ts-mode--indent-rules)
+    (setq-local treesit-simple-indent-rules (cmake-ts-mode--indent-rules))
 
     ;; Font-lock.
-    (setq-local treesit-font-lock-settings cmake-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-settings (cmake-ts-mode--font-lock-settings))
     (setq-local treesit-font-lock-feature-list
                 '((comment)
                   (keyword string)
-- 
2.51.0