From: Eli Zaretskii Date: Fri, 20 Jan 2023 08:28:26 +0000 (+0200) Subject: Make tree-sitter based modes optional X-Git-Tag: emacs-29.0.90~650 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=6b2f85caa6cae1178b8abee531b0b9b0cf618a00;p=emacs.git Make tree-sitter based modes optional * lisp/progmodes/c-ts-mode.el: Update Commentary. Make 'auto-mode-alist' update conditional on the tree-sitter and grammar libraries being available. * lisp/progmodes/cmake-ts-mode.el: * lisp/progmodes/csharp-mode.el: * lisp/progmodes/dockerfile-ts-mode.el: * lisp/progmodes/go-ts-mode.el: * lisp/progmodes/java-ts-mode.el: * lisp/progmodes/js.el: * lisp/progmodes/json-ts-mode.el: * lisp/progmodes/python.el: * lisp/progmodes/ruby-ts-mode.el: * lisp/progmodes/typescript-ts-mode.el: * lisp/textmodes/css-mode.el: * lisp/textmodes/toml-ts-mode.el: * lisp/textmodes/yaml-ts-mode.el: Make 'auto-mode-alist' update for tree-sitter based modes be conditional on the tree-sitter and grammar libraries being available. (Bug#60559) --- diff --git a/etc/NEWS b/etc/NEWS index 38f2db26a1a..fa0e7a1f661 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -34,13 +34,14 @@ This feature existed in Emacs 28.1, but was less easy to request. +++ ** Emacs can be built with the tree-sitter parsing library. -This library, together with grammar libraries, provides incremental -parsing capabilities for several popular programming languages and -other formatted files. Emacs built with this library offers major -modes, described elsewhere in this file, that are based on the -tree-sitter's parsers. If you have the tree-sitter library -installed, the configure script will automatically include it in the -build; use '--without-tree-sitter' at configure time to disable that. +This library, together with separate grammar libraries for each +language, provides incremental parsing capabilities for several +popular programming languages and other formatted files. Emacs built +with this library offers major modes, described elsewhere in this +file, that are based on the tree-sitter's parsers. If you have the +tree-sitter library installed, the configure script will automatically +include it in the build; use '--without-tree-sitter' at configure time +to disable that. Emacs modes based on the tree-sitter library require an additional grammar library for each mode. These grammar libraries provide the @@ -3183,19 +3184,19 @@ indentation, and navigation by defuns based on parsing the buffer text by a tree-sitter parser. Some major modes also offer support for Imenu and 'which-func'. -Where major modes already exist in Emacs for editing certain kinds of -files, the new modes based on tree-sitter are for now entirely -optional, and you must turn them on manually, or customize -'auto-mode-alist' to turn them on automatically. +The new modes based on tree-sitter are for now entirely optional, and +you must turn them on manually, or load them in your init file, or +customize 'auto-mode-alist' to turn them on automatically for certain +files. You can also customize 'major-mode-remap-alist' to +automatically turn on some tree-sitter based modes for the same files +for which a "built-in" mode would be turned on. For example: -Where no major modes previously existed in Emacs for editing the kinds -of files for which Emacs now provides a tree-sitter based mode, Emacs -will now try to enable these new modes automatically when you visit -such files, and will display a warning if the tree-sitter library or -the parser grammar library is not available. To prevent the warnings, -either build Emacs with tree-sitter and install the grammar libraries, -or customize 'auto-mode-alist' to specify some other major mode (or -even 'fundamental-mode') for those kinds of files. + (add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode)) + +If you try these modes and don't like them, you can go back to the +"built-in" modes by restarting Emacs. But please tell us why you +didn't like the tree-sitter based modes, so that we could try +improving them. Each major mode based on tree-sitter needs a language grammar library, usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on @@ -3212,20 +3213,18 @@ We recommend to install these libraries in one of the standard system locations (the last place in the above list). If a language grammar library required by a mode is not found in any -of the above places, the mode will signal an error when you try to +of the above places, the mode will display a warning when you try to turn it on. +++ *** New major mode 'typescript-ts-mode'. A major mode based on the tree-sitter library for editing programs -in the TypeScript language. This mode is auto-enabled for files with -the ".ts" extension. +in the TypeScript language. +++ *** New major mode 'tsx-ts-mode'. A major mode based on the tree-sitter library for editing programs -in the TypeScript language, with support for TSX. This mode is -auto-enabled for files with the ".tsx" extension. +in the TypeScript language, with support for TSX. +++ *** New major mode 'c-ts-mode'. @@ -3275,15 +3274,12 @@ Bash shell scripts. +++ *** New major mode 'dockerfile-ts-mode'. A major mode based on the tree-sitter library for editing -Dockerfiles. This mode is auto-enabled for files which are named -"Dockerfile", have the "Dockerfile." prefix, or have the ".dockerfile" -extension. +Dockerfiles. +++ *** New major mode 'cmake-ts-mode'. A major mode based on the tree-sitter library for editing CMake files. -It is auto-enabled for files whose name is "CMakeLists.txt" or whose -extension is ".cmake". + +++ *** New major mode 'toml-ts-mode'. @@ -3293,23 +3289,22 @@ files written in TOML, a format for writing configuration files. +++ *** New major mode 'go-ts-mode'. A major mode based on the tree-sitter library for editing programs in -the Go language. It is auto-enabled for files with the ".go" extension. +the Go language. +++ *** New major mode 'go-mod-ts-mode'. A major mode based on the tree-sitter library for editing "go.mod" -files. It is auto-enabled for files which are named "go.mod". +files. +++ *** New major mode 'yaml-ts-mode'. A major mode based on the tree-sitter library for editing files -written in YAML. It is auto-enabled for files with the ".yaml" or -".yml" extensions. +written in YAML. +++ *** New major mode 'rust-ts-mode'. A major mode based on the tree-sitter library for editing programs in -the Rust language. It is auto-enabled for files with the ".rs" extension. +the Rust language. --- *** New major mode 'ruby-ts-mode'. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 3d887971f64..5749e568185 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -32,13 +32,37 @@ ;; `c-or-c++-ts-mode' which automatically chooses the right mode for ;; C/C++ header files. ;; -;; To use these more by default, evaluate +;; To use these modes by default, assuming you have the respective +;; tree-sitter grammars available, do one of the following: ;; -;; (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode)) -;; (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode)) -;; (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode)) +;; - If you have both C and C++ grammars installed, add ;; -;; in your configuration. +;; (require 'c-ts-mode) +;; +;; to your init file. +;; +;; - Add one or mode of the following to your init file: +;; +;; (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode)) +;; (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode)) +;; (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode)) +;; +;; If you have only C grammar available, use only the first one; if +;; you have only the C++ grammar, use only the second one. +;; +;; - Customize 'auto-mode-alist' to turn one or more of the modes +;; automatically. For example: +;; +;; (add-to-list 'auto-mode-alist +;; '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'" +;; . c++-ts-mode)) +;; +;; will turn on the c++-ts-mode for C++ source files. +;; +;; You can also turn on these modes manually in a buffer. Doing so +;; will set up Emacs to use the C/C++ modes defined here for other +;; files, provided that you have the corresponding parser grammar +;; libraries installed. ;; ;; For C-like language major modes: ;; @@ -1072,6 +1096,22 @@ the code is C or C++ and based on that chooses whether to enable (re-search-forward c-ts-mode--c-or-c++-regexp nil t)))) (c++-ts-mode) (c-ts-mode))) +;; The entries for C++ must come first to prevent *.c files be taken +;; as C++ on case-insensitive filesystems, since *.C files are C++, +;; not C. +(if (treesit-ready-p 'cpp) + (add-to-list 'auto-mode-alist + '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'" + . c++-ts-mode))) + +(if (treesit-ready-p 'c) + (add-to-list 'auto-mode-alist + '("\\(\\.[chi]\\|\\.lex\\|\\.y\\(acc\\)?\\|\\.x[bp]m\\)\\'" + . c-ts-mode))) + +(if (and (treesit-ready-p 'cpp) + (treesit-ready-p 'c)) + (add-to-list 'auto-mode-alist '("\\.h\\'" . c-or-c++-ts-mode))) (provide 'c-ts-mode) diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el index a31250f68be..c241a2868e5 100644 --- a/lisp/progmodes/cmake-ts-mode.el +++ b/lisp/progmodes/cmake-ts-mode.el @@ -194,10 +194,6 @@ the subtrees." (t `((,name . ,marker)))))) -;;;###autoload -(add-to-list 'auto-mode-alist - '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)) - ;;;###autoload (define-derived-mode cmake-ts-mode prog-mode "CMake" "Major mode for editing CMake files, powered by tree-sitter." @@ -229,6 +225,10 @@ the subtrees." (treesit-major-mode-setup))) +(if (treesit-ready-p 'cmake) + (add-to-list 'auto-mode-alist + '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode))) + (provide 'cmake-ts-mode) ;;; cmake-ts-mode.el ends here diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index 81ce41618e7..04f7f222362 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -883,9 +883,6 @@ Return nil if there is no name or if NODE is not a defun node." node "name") t)))) -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode)) - ;;;###autoload (define-derived-mode csharp-mode prog-mode "C#" "Major mode for editing Csharp code. @@ -941,7 +938,9 @@ Key bindings: ("Struct" "\\`struct_declaration\\'" nil nil) ("Method" "\\`method_declaration\\'" nil nil))) - (treesit-major-mode-setup)) + (treesit-major-mode-setup) + + (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-ts-mode))) (provide 'csharp-mode) diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el index 3f8766e6713..2a295e885b0 100644 --- a/lisp/progmodes/dockerfile-ts-mode.el +++ b/lisp/progmodes/dockerfile-ts-mode.el @@ -132,12 +132,6 @@ the subtrees." (t `((,name . ,marker)))))) -;;;###autoload -(add-to-list 'auto-mode-alist - ;; NOTE: We can't use `rx' here, as it breaks bootstrap. - '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" - . dockerfile-ts-mode)) - ;;;###autoload (define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile" "Major mode for editing Dockerfiles, powered by tree-sitter." @@ -172,6 +166,12 @@ the subtrees." (treesit-major-mode-setup))) +(if (treesit-ready-p 'dockerfile) + (add-to-list 'auto-mode-alist + ;; NOTE: We can't use `rx' here, as it breaks bootstrap. + '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" + . dockerfile-ts-mode))) + (provide 'dockerfile-ts-mode) ;;; dockerfile-ts-mode.el ends here diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 64e761d2f72..d552e1360e0 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -174,9 +174,6 @@ '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `go-ts-mode'.") -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)) - ;;;###autoload (define-derived-mode go-ts-mode prog-mode "Go" "Major mode for editing Go, powered by tree-sitter." @@ -226,6 +223,9 @@ (treesit-major-mode-setup))) +(if (treesit-ready-p 'go) + (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))) + (defun go-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." @@ -345,9 +345,6 @@ what the parent of the node would be if it were a node." '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `go-mod-ts-mode'.") -;;;###autoload -(add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode)) - ;;;###autoload (define-derived-mode go-mod-ts-mode prog-mode "Go Mod" "Major mode for editing go.mod files, powered by tree-sitter." @@ -376,6 +373,9 @@ what the parent of the node would be if it were a node." (treesit-major-mode-setup))) +(if (treesit-ready-p 'gomod) + (add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode))) + (provide 'go-ts-mode) ;;; go-ts-mode.el ends here diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index d29fcd80861..d909a366e5d 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -331,6 +331,9 @@ Return nil if there is no name or if NODE is not a defun node." ("Method" "\\`method_declaration\\'" nil nil))) (treesit-major-mode-setup)) +(if (treesit-ready-p 'java) + (add-to-list 'auto-mode-alist '("\\.java\\'" . java-ts-mode))) + (provide 'java-ts-mode) ;;; java-ts-mode.el ends here diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index cc556c4d0ec..176024863f1 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3843,7 +3843,10 @@ Currently there are `js-mode' and `js-ts-mode'." "method_definition") eos) nil nil))) - (treesit-major-mode-setup))) + (treesit-major-mode-setup) + + (add-to-list 'auto-mode-alist + '("\\(\\.js[mx]\\|\\.har\\)\\'" . js-ts-mode)))) ;;;###autoload (define-derived-mode js-json-mode js-mode "JSON" diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el index fbcda22acca..f54d0187f98 100644 --- a/lisp/progmodes/json-ts-mode.el +++ b/lisp/progmodes/json-ts-mode.el @@ -160,6 +160,10 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-major-mode-setup)) +(if (treesit-ready-p 'json) + (add-to-list 'auto-mode-alist + '("\\.json\\'" . json-ts-mode))) + (provide 'json-ts-mode) ;;; json-ts-mode.el ends here diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 21d16db287c..a869cdc5fdb 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -6713,7 +6713,10 @@ implementations: `python-mode' and `python-ts-mode'." (treesit-major-mode-setup) (when python-indent-guess-indent-offset - (python-indent-guess-indent-offset)))) + (python-indent-guess-indent-offset)) + + (add-to-list 'auto-mode-alist + '("\\.py[iw]?\\'\\|python[0-9.]*" . python-ts-mode)))) ;;; Completion predicates for M-x ;; Commands that only make sense when editing Python code diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 45174811605..d143c06a8a4 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -1047,6 +1047,20 @@ leading double colon is not added." (treesit-major-mode-setup)) +(if (treesit-ready-p 'ruby) + ;; Copied from ruby-mode.el. + (add-to-list 'auto-mode-alist + (cons (concat "\\(?:\\.\\(?:" + "rbw?\\|ru\\|rake\\|thor" + "\\|jbuilder\\|rabl\\|gemspec\\|podspec" + "\\)" + "\\|/" + "\\(?:Gem\\|Rake\\|Cap\\|Thor" + "\\|Puppet\\|Berks\\|Brew" + "\\|Vagrant\\|Guard\\|Pod\\)file" + "\\)\\'") + 'ruby-ts-mode))) + (provide 'ruby-ts-mode) ;;; ruby-ts-mode.el ends here diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el index 7536726165e..08590ae6a86 100644 --- a/lisp/progmodes/rust-ts-mode.el +++ b/lisp/progmodes/rust-ts-mode.el @@ -275,9 +275,6 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-node-text (treesit-node-child-by-field-name node "name") t)))) -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode)) - ;;;###autoload (define-derived-mode rust-ts-mode prog-mode "Rust" "Major mode for editing Rust, powered by tree-sitter." @@ -322,6 +319,9 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-major-mode-setup))) +(if (treesit-ready-p 'rust) + (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))) + (provide 'rust-ts-mode) ;;; rust-ts-mode.el ends here diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index ffd5b941daf..6aaa852895c 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -314,12 +314,6 @@ Argument LANGUAGE is either `typescript' or `tsx'." :override t '((escape_sequence) @font-lock-escape-face))) -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode)) - -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode)) - ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Major mode for editing TypeScript." @@ -375,6 +369,9 @@ Argument LANGUAGE is either `typescript' or `tsx'." (treesit-major-mode-setup))) +(if (treesit-ready-p 'typescript) + (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))) + ;;;###autoload (define-derived-mode tsx-ts-mode typescript-ts-base-mode "TypeScript[TSX]" "Major mode for editing TypeScript." @@ -410,6 +407,9 @@ Argument LANGUAGE is either `typescript' or `tsx'." (treesit-major-mode-setup))) +(if (treesit-ready-p 'tsx) + (add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))) + (provide 'typescript-ts-mode) ;;; typescript-ts-mode.el ends here diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 8991610a50f..a1d7d4bbbec 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -1827,7 +1827,9 @@ can also be used to fill comments. (setq-local treesit-simple-imenu-settings `(( nil ,(rx bos (or "rule_set" "media_statement") eos) nil nil))) - (treesit-major-mode-setup))) + (treesit-major-mode-setup) + + (add-to-list 'auto-mode-alist '("\\.css\\'" . css-ts-mode)))) ;;;###autoload (define-derived-mode css-mode css-base-mode "CSS" diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el index 2430c5f3e76..416542084f1 100644 --- a/lisp/textmodes/toml-ts-mode.el +++ b/lisp/textmodes/toml-ts-mode.el @@ -117,8 +117,6 @@ Return nil if there is no name or if NODE is not a defun node." (or (treesit-node-text (treesit-node-child node 1) t) "Root table")))) -(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode)) - ;;;###autoload (define-derived-mode toml-ts-mode text-mode "TOML" "Major mode for editing TOML, powered by tree-sitter." @@ -155,6 +153,9 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-major-mode-setup))) +(if (treesit-ready-p 'toml) + (add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))) + (provide 'toml-ts-mode) ;;; toml-ts-mode.el ends here diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el index 8c61ee062cf..a25230e6e61 100644 --- a/lisp/textmodes/yaml-ts-mode.el +++ b/lisp/textmodes/yaml-ts-mode.el @@ -117,9 +117,6 @@ '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `yaml-ts-mode'.") -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode)) - ;;;###autoload (define-derived-mode yaml-ts-mode text-mode "YAML" "Major mode for editing YAML, powered by tree-sitter." @@ -146,6 +143,9 @@ (treesit-major-mode-setup))) +(if (treesit-ready-p 'yaml) + (add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))) + (provide 'yaml-ts-mode) ;;; yaml-ts-mode.el ends here