From 21361d0563524f25805de4705ab6a0fe16ea3d44 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 29 Apr 2023 15:39:54 -0700 Subject: [PATCH] Fix FOR_EACH_TAIL fontification (bug#62951) Fix the fontification inconsistency between different FOR_EACH_TAIL's. See the comment for more explanation. Also enable the emacs-devel feature automatically when c-ts-mode-emacs-sources-support is on. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--for-each-tail-regexp): Move up. (c-ts-mode--font-lock-settings): New font-lock rule for FOR_EACH_TAIL. (c-ts-mode--fontify-for-each-tail): New function. (c-ts-mode): Automatically enable emacs-devel feature. --- lisp/progmodes/c-ts-mode.el | 41 +++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 113f3b6ee84..761a87c5a78 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -536,6 +536,11 @@ MODE is either `c' or `cpp'." "+=" "*=" "/=" "%=" "|=" "&=" "^=" ">>=" "<<=" "--" "++") "C/C++ operators for tree-sitter font-locking.") +(defvar c-ts-mode--for-each-tail-regexp + (rx "FOR_EACH_" (or "TAIL" "TAIL_SAFE" "ALIST_VALUE" + "LIVE_BUFFER" "FRAME")) + "A regexp matching all the variants of the FOR_EACH_* macro.") + (defun c-ts-mode--font-lock-settings (mode) "Tree-sitter font-lock settings. MODE is either `c' or `cpp'." @@ -686,10 +691,14 @@ MODE is either `c' or `cpp'." :language mode :feature 'emacs-devel :override t - '(((call_expression + `(((call_expression (call_expression function: (identifier) @fn) @c-ts-mode--fontify-DEFUN) - (:match "^DEFUN$" @fn))))) + (:match "^DEFUN$" @fn)) + + ((function_definition type: (_) @for-each-tail) + @c-ts-mode--fontify-for-each-tail + (:match ,c-ts-mode--for-each-tail-regexp @for-each-tail))))) ;;; Font-lock helpers @@ -791,6 +800,20 @@ This function corrects the fontification of the colon in (treesit-node-start arg) (treesit-node-end arg) 'default override start end)))))) +(defun c-ts-mode--fontify-for-each-tail (node override start end &rest _) + "Fontify FOR_EACH_TAIL variants in Emacs sources. +For NODE, OVERRIDE, START, and END, see +`treesit-font-lock-rules'. The captured NODE is a +function_definition node." + (let ((for-each-tail (treesit-node-child-by-field-name node "type")) + (args (treesit-node-child-by-field-name node "declarator"))) + (treesit-fontify-with-override + (treesit-node-start for-each-tail) (treesit-node-end for-each-tail) + 'default override start end) + (treesit-fontify-with-override + (1+ (treesit-node-start args)) (1- (treesit-node-end args)) + 'default override start end))) + (defun c-ts-mode--fontify-error (node override start end &rest _) "Fontify the error nodes. For NODE, OVERRIDE, START, and END, see @@ -984,11 +1007,12 @@ if `c-ts-mode-emacs-sources-support' is non-nil." ;; skips those FOR_EACH_*'s. Note that we only ignore FOR_EACH_*'s ;; with a unbracketed body. Those with a bracketed body parse more ;; or less fine. - -(defvar c-ts-mode--for-each-tail-regexp - (rx "FOR_EACH_" (or "TAIL" "TAIL_SAFE" "ALIST_VALUE" - "LIVE_BUFFER" "FRAME")) - "A regexp matching all the variants of the FOR_EACH_* macro.") +;; +;; In the meantime, we have a special fontification rule for +;; FOR_EACH_* macros with a bracketed body that removes any applied +;; fontification (which are wrong anyway), to keep them consistent +;; with the skipped FOR_EACH_* macros (which have no fontification). +;; The rule is in 'emacs-devel' feature. (defun c-ts-mode--for-each-tail-body-matcher (_n _p bol &rest _) "A matcher that matches the first line after a FOR_EACH_* macro. @@ -1187,7 +1211,8 @@ in your configuration." (treesit-range-rules 'c-ts-mode--emacs-set-ranges)) (setq-local treesit-language-at-point-function - (lambda (_pos) 'c))))) + (lambda (_pos) 'c)) + (treesit-font-lock-recompute-features '(emacs-devel))))) ;;;###autoload (define-derived-mode c++-ts-mode c-ts-base-mode "C++" -- 2.39.2