From cd5dd5279e8d3ff207cde922cf8775a52eebd29e Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Fri, 29 Aug 2025 14:25:35 +0200 Subject: [PATCH] fix(tree-sitter): major mode remapping on first-load Also refactors +tree-sitter--major-mode-remaps-alist to be lighter. --- .../tools/tree-sitter/autoload/tree-sitter.el | 42 +++------------- modules/tools/tree-sitter/config.el | 48 +++++++++++++------ 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/modules/tools/tree-sitter/autoload/tree-sitter.el b/modules/tools/tree-sitter/autoload/tree-sitter.el index 5df7c4bdf..69dfeaabe 100644 --- a/modules/tools/tree-sitter/autoload/tree-sitter.el +++ b/modules/tools/tree-sitter/autoload/tree-sitter.el @@ -23,45 +23,15 @@ pre-Emacs 31." (declare (indent 2)) (cl-check-type mode symbol) (cl-check-type ts-mode symbol) - (setq recipes (ensure-list recipes)) + (setq recipes (mapcar #'ensure-list (ensure-list recipes))) (dolist (m (ensure-list mode)) (add-to-list '+tree-sitter--major-mode-remaps-alist - (cons - m (let (ensured?) - (lambda () - (funcall - ;; Because standard major-mode remapping doesn't offer graceful - ;; failure in some cases, I implement it myself: - (cond ((null recipes) m) - ((not (fboundp ts-mode)) - (message "Couldn't find %S, using %S instead" ts-mode m) - m) - ((and (fboundp 'treesit-available-p) - (treesit-available-p) - (fboundp ts-mode) - (or (eq treesit-enabled-modes t) - (memq ts-mode treesit-enabled-modes)) - ;; Lazily load autoload so - ;; `treesit-language-source-alist' is initialized. - (let ((fn (symbol-function ts-mode))) - (or (not (autoloadp fn)) - (autoload-do-load fn))) - ;; Only prompt once, and log other times. - (cl-every (if ensured? - (doom-rpartial #'treesit-ready-p 'message) - #'treesit-ensure-installed) - (cl-loop for r in recipes - if (listp r) - collect (car r) - else collect (list r)))) - ts-mode) - ((setq ensured? t) - m)))))))) - (with-eval-after-load 'treesit - (dolist (recipe recipes) - (when (cdr (setq recipe (ensure-list recipe))) - (cl-destructuring-bind (name &key url rev source-dir cc cpp commit) recipe + (list m ts-mode (mapcar #'car recipes) nil))) + (when (setq recipes (cl-remove-if-not #'cdr recipes)) + (with-eval-after-load 'treesit + (dolist (recipe recipes) + (cl-destructuring-bind (name &key url rev source-dir cc cpp commit) (ensure-list recipe) (setf (alist-get name treesit-language-source-alist) (append (list url rev source-dir cc cpp) ;; COMPAT: 31.1 introduced a COMMIT recipe argument. On diff --git a/modules/tools/tree-sitter/config.el b/modules/tools/tree-sitter/config.el index bec186284..3770b15a5 100644 --- a/modules/tools/tree-sitter/config.el +++ b/modules/tools/tree-sitter/config.el @@ -35,6 +35,40 @@ python-ts-mode)) (advice-add mode :around #'+tree-sitter-ts-mode-inhibit-side-effects-a)) + ;; HACK: Some *-ts-mode packages modify `major-mode-remap-defaults' + ;; inconsistently. Playing whack-a-mole to undo those changes is more hassle + ;; then simply ignoring them (by overriding `major-mode-remap-defaults' for + ;; any modes remapped with `set-tree-sitter!'). The user shouldn't touch + ;; `major-mode-remap-defaults' anyway; `major-mode-remap-alist' will always + ;; have precedence. + (defadvice! +tree-sitter--maybe-remap-major-mode-a (fn mode) + :around #'major-mode-remap + (let ((major-mode-remap-defaults + ;; Because standard major-mode remapping doesn't offer graceful + ;; failure in some cases, I implement it myself: + (cons (when-let* ((spec (assq mode +tree-sitter--major-mode-remaps-alist)) + (ts-mode (nth 1 spec)) + (langs (nth 2 spec))) + (if (not (fboundp ts-mode)) + (ignore (message "Couldn't find %S, falling back to %S" ts-mode mode)) + (prog1 (and (or (eq treesit-enabled-modes t) + (memq ts-mode treesit-enabled-modes)) + ;; Lazily load autoload so + ;; `treesit-language-source-alist' is + ;; initialized. + (let ((fn (symbol-function ts-mode))) + (or (not (autoloadp fn)) + (autoload-do-load fn ts-mode))) + ;; Only prompt once, and log other times. + (cl-every (if (get ts-mode 'ensured?) + (doom-rpartial #'treesit-ready-p 'message) + #'treesit-ensure-installed) + langs) + `((,mode . ,ts-mode))) + (put ts-mode 'ensured? t)))) + major-mode-remap-defaults))) + (funcall fn mode))) + :config ;; HACK: The implementation of `treesit-enabled-modes's setter and ;; `treesit-major-mode-remap-alist' is intrusively opinionated, so disable @@ -46,20 +80,6 @@ (setq major-mode-remap-alist (delete m major-mode-remap-alist)))) (setq treesit-major-mode-remap-alist nil) - ;; HACK: Some *-ts-mode packages modify `major-mode-remap-defaults' - ;; inconsistently. Playing whack-a-mole to undo those changes is more hassle - ;; then simply ignoring them (by overriding `major-mode-remap-defaults' for - ;; any modes remapped with `set-tree-sitter!'). The user shouldn't touch - ;; `major-mode-remap-defaults' anyway; `major-mode-remap-alist' will always - ;; have precedence. - (defadvice! +tree-sitter--ignore-default-major-mode-remaps-a (fn mode) - :around #'major-mode-remap - (let ((major-mode-remap-defaults - (if-let* ((m (assq mode +tree-sitter--major-mode-remaps-alist))) - +tree-sitter--major-mode-remaps-alist - major-mode-remap-defaults))) - (funcall fn mode))) - ;; HACK: Keep $EMACSDIR clean by installing grammars to the active profile. (add-to-list 'treesit-extra-load-path (concat doom-profile-data-dir "tree-sitter")) (defadvice! +tree-sitter--install-grammar-to-local-dir-a (fn &rest args)