From 4a6182424df8fac17a6141980248a33bf26f823a Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 2 Dec 2024 20:47:38 -0800 Subject: [PATCH] Validate font-lock rules when setting up tree-sitter major mode When tree-sitter grammar make breaking changes, major modes breaks completely: no highlighting is shown. This new function will run in treesit-major-mode-setup, validate each font-lock features, and disable the ones that are not compatible with the new grammar, so that the rest of the features still work. It also displays a warning explaining the situation, which looks like this: Warning (treesit-font-lock-rules-mismatch): Emacs cannot compile every font-lock rules because a mismatch between the grammar and the rules. This is most likely due to a mismatch between the font-lock rules defined by the major mode and the tree-sitter grammar. This error can be fixed by either downgrading the grammar (tree-sitter-c) on your system, or upgrading the major mode package. The following are the temporarily disabled features: - `preprocessor' for c. * lisp/treesit.el (treesit-validate-font-lock-rules): New function. (treesit-major-mode-setup): Validate font-lock rules. (cherry picked from commit ed9eaaa9964f46ef5f9a9c084a1cb8f1ae1926a3) --- lisp/treesit.el | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index be6c8820638..221c539f86a 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1210,6 +1210,48 @@ docstring of `treesit-font-lock-rules' for what is a feature." (append rules (nthcdr feature-idx treesit-font-lock-settings))))))) +(defun treesit-validate-font-lock-rules (settings) + "Validate font-lock rules in SETTINGS before major mode starts. + +If the tree-sitter grammar currently installed on the system is +incompatible with the major mode's font-lock rules, this procedure will +detect the problematic rule, disable it temporarily, and notify the +user." + (let ((faulty-features ())) + (dolist (setting settings) + (let* ((query (treesit-font-lock-setting-query setting)) + (lang (treesit-query-language query)) + (enabled (treesit-font-lock-setting-enable setting))) + (when (and enabled + (condition-case nil + (progn + (treesit-query-compile lang query 'eager) + nil) + (treesit-query-error t))) + (push (cons (treesit-font-lock-setting-feature setting) + lang) + faulty-features)))) + (when faulty-features + (treesit-font-lock-recompute-features + nil (mapcar #'car faulty-features)) + (let* ((languages + (string-join + (delete-dups (mapcar (lambda (feat) + (format "tree-sitter-%s" (cdr feat))) + faulty-features)) + ", ")) + (features (string-join + (mapcar + (lambda (feat) + (format "- `%s' for %s" + (car feat) (cdr feat))) + faulty-features) + ",\n"))) + (display-warning + 'treesit-font-lock-rules-mismatch + (format "Emacs cannot compile every font-lock rules because a mismatch between the grammar and the rules. This is most likely due to a mismatch between the font-lock rules defined by the major mode and the tree-sitter grammar.\n\nThis error can be fixed by either downgrading the grammar (%s) on your system, or upgrading the major mode package. The following are the temporarily disabled features:\n\n%s." + languages features)))))) + (defun treesit-fontify-with-override (start end face override &optional bound-start bound-end) "Apply FACE to the region between START and END. @@ -3134,7 +3176,8 @@ before calling this function." (add-hook 'pre-redisplay-functions #'treesit--pre-redisplay 0 t) (when treesit-primary-parser (treesit-parser-add-notifier - treesit-primary-parser #'treesit--font-lock-mark-ranges-to-fontify))) + treesit-primary-parser #'treesit--font-lock-mark-ranges-to-fontify)) + (treesit-validate-font-lock-rules treesit-font-lock-settings)) ;; Syntax (add-hook 'syntax-propertize-extend-region-functions #'treesit--pre-syntax-ppss 0 t) -- 2.39.5