tree-sitter是一个解析器生成工具和增量解析库。它可以为源文件构建语法树,当源文件修改时可以高效的更新语法树。
自Emacs 29开始,内置treesit模块实现了对tree-sitter的支持。
安装语言解析器#
为某一个编程语言添加tree-sitter支持时,运行M-x treesit-install-language-grammar
命令,会先clone语言解析器的仓库,然后在进行编译安装。
通过设定treesit-language-source-alist
变量来定义每种语言解析器的仓库地址,这样在进行命令安装时就不需要再输入仓库地址。
;; M-x `treesit-install-language-grammar` to install language grammar.
(setq treesit-language-source-alist
'((bash . ("https://github.com/tree-sitter/tree-sitter-bash"))
(c . ("https://github.com/tree-sitter/tree-sitter-c"))
(cpp . ("https://github.com/tree-sitter/tree-sitter-cpp"))
(css . ("https://github.com/tree-sitter/tree-sitter-css"))
(cmake . ("https://github.com/uyha/tree-sitter-cmake"))
(csharp . ("https://github.com/tree-sitter/tree-sitter-c-sharp.git"))
(dockerfile . ("https://github.com/camdencheek/tree-sitter-dockerfile"))
(elisp . ("https://github.com/Wilfred/tree-sitter-elisp"))
(elixir "https://github.com/elixir-lang/tree-sitter-elixir" "main" "src" nil nil)
(go . ("https://github.com/tree-sitter/tree-sitter-go"))
(gomod . ("https://github.com/camdencheek/tree-sitter-go-mod.git"))
(haskell "https://github.com/tree-sitter/tree-sitter-haskell" "master" "src" nil nil)
(html . ("https://github.com/tree-sitter/tree-sitter-html"))
(java . ("https://github.com/tree-sitter/tree-sitter-java.git"))
(javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
(json . ("https://github.com/tree-sitter/tree-sitter-json"))
(lua . ("https://github.com/Azganoth/tree-sitter-lua"))
(make . ("https://github.com/alemuller/tree-sitter-make"))
(markdown . ("https://github.com/MDeiml/tree-sitter-markdown" nil "tree-sitter-markdown/src"))
(ocaml . ("https://github.com/tree-sitter/tree-sitter-ocaml" nil "ocaml/src"))
(org . ("https://github.com/milisims/tree-sitter-org"))
(python . ("https://github.com/tree-sitter/tree-sitter-python"))
(php . ("https://github.com/tree-sitter/tree-sitter-php"))
(typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" nil "typescript/src"))
(tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" nil "tsx/src"))
(ruby . ("https://github.com/tree-sitter/tree-sitter-ruby"))
(rust . ("https://github.com/tree-sitter/tree-sitter-rust"))
(sql . ("https://github.com/m-novikov/tree-sitter-sql"))
(scala "https://github.com/tree-sitter/tree-sitter-scala" "master" "src" nil nil)
(toml "https://github.com/tree-sitter/tree-sitter-toml" "master" "src" nil nil)
(vue . ("https://github.com/merico-dev/tree-sitter-vue"))
(kotlin . ("https://github.com/fwcd/tree-sitter-kotlin"))
(yaml . ("https://github.com/ikatyang/tree-sitter-yaml"))
(zig . ("https://github.com/GrayJack/tree-sitter-zig"))))
Emacs会先在treesit-extra-load-path
目录查找语言解析器,然后在~/.emacs.d/tree-sitter/
目录查找语言解析器。
使用预编译的语言解析器#
tree-sitter-langs包提供了预编译的语言解析器,在release页面下载对应操作系统的语言解析器,将包内的库文件解压到~/.emacs.d/tree-sitter/
目录下。
需要将所有的<LANGUAGE>.so
重命名为libtree-sitter-<LANGUAGE>.so
,批量重命名的快捷命令如下:
for f in * ; do mv -- "$f" "libtree-sitter-$f" ; done
检查语言解析器是否可用#
Eval: (treesit-language-available-p 'python)
t
Eval: (treesit-language-available-p 'klingon)
nil
使用tree-sitter#
首先判断当前版本Emacs是否内置treesit支持。
(and (fboundp 'treesit-available-p)
(treesit-available-p))
Emacs内置了一些语言解析器,通过<LANGUAGE>-ts-mode
可以打开tree-sitter支持。
(setq major-mode-remap-alist
'((c-mode . c-ts-mode)
(c++-mode . c++-ts-mode)
(conf-toml-mode . toml-ts-mode)
(csharp-mode . csharp-ts-mode)
(css-mode . css-ts-mode)
(go-mode . go-ts-mode)
(go-mod-mode . go-mod-ts-mode)
(java-mode . java-ts-mode)
(javascript-mode . js-ts-mode)
(js-mode . js-ts-mode)
(js-json-mode . json-ts-mode)
(ruby-mode . ruby-ts-mode)
(sh-mode . bash-ts-mode)
(python-mode . python-ts-mode)))
(add-to-list 'auto-mode-alist '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode))
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
还有其它很多语言没有内置支持,可以使用treesit-parser-create
来手动开启。
(add-hook 'emacs-lisp-mode-hook (lambda ()
(when (treesit-language-available-p 'elisp)
(treesit-parser-create 'elisp))))