不清楚,好像可以?
我觉得新增个变量的这个想法很好,就不用每个新的 ts-mode 都自己设置一遍了,大佬可以发个邮件建议一下
英雄所见略同(战术后仰
Emacs-devel 邮件列表已经有相关的讨论了,Philip Kaludercic 提出可以设置一个 treesit-enabled-modes
,但是 Eli Zaretskii 不同意,认为这样不方便用户对每个 mode 决定是否启用 tree-sitter。 可以关注这 2 个讨论主题:
https://lists.gnu.org/r/emacs-devel/2022-12/msg01293.html
https://lists.gnu.org/r/emacs-devel/2022-12/msg01251.html
-map 是会继承的,除非改键了。
-hook 没说明,感觉没继承,我没继续往下翻它的具体实现。
订正:-hook 实际上是继承了的,明显的例子是prog-mode-hook。理解可能有错,欢迎指正。
以下附源码comment部分、以及一个define-derived-mode 的 pp-macroexpansion。(太长被truncated了)
M-x pp-macroexpand-expression RET (define-derived-mode elixir-mode elixir-ts-mode "Elixir")
可以看到继承了 -mode-map, -syntax-table, -abbrev-table, 以及 -hook。比较长,得滚动一下,其中 elixir-ts-mode 的 -hook 包裹在 delay-mode-hooks 里:
(progn
(defvar elixir-mode-hook nil)
(unless
(get 'elixir-mode-hook 'variable-documentation)
(put 'elixir-mode-hook 'variable-documentation "Hook run after entering Elixir mode.\nNo problems result if this variable is not bound.\n`add-hook' automatically binds it. (This is true for all hook variables.)"))
(unless
(boundp 'elixir-mode-map)
(put 'elixir-mode-map 'definition-name 'elixir-mode))
(with-no-warnings
(defvar elixir-mode-map
(make-sparse-keymap)))
(unless
(get 'elixir-mode-map 'variable-documentation)
(put 'elixir-mode-map 'variable-documentation
(purecopy "Keymap for `elixir-mode'.")))
(progn
(defvar elixir-mode-syntax-table)
(unless
(boundp 'elixir-mode-syntax-table)
(put 'elixir-mode-syntax-table 'definition-name 'elixir-mode)
(defvar elixir-mode-syntax-table
(make-syntax-table)))
(unless
(get 'elixir-mode-syntax-table 'variable-documentation)
(put 'elixir-mode-syntax-table 'variable-documentation
(purecopy "Syntax table for `elixir-mode'."))))
(progn
(defvar elixir-mode-abbrev-table)
(unless
(boundp 'elixir-mode-abbrev-table)
(put 'elixir-mode-abbrev-table 'definition-name 'elixir-mode)
(defvar elixir-mode-abbrev-table
(progn
(define-abbrev-table 'elixir-mode-abbrev-table nil)
elixir-mode-abbrev-table)))
(unless
(get 'elixir-mode-abbrev-table 'variable-documentation)
(put 'elixir-mode-abbrev-table 'variable-documentation
(purecopy "Abbrev table for `elixir-mode'."))))
(put 'elixir-mode 'derived-mode-parent 'elixir-ts-mode)
nil
(defun elixir-mode nil "Major mode derived from `elixir-ts-mode' by `define-derived-mode'.\nIt inherits all of the parent's attributes, but has its own keymap,\nabbrev table and syntax table:\n\n `elixir-mode-map', `elixir-mode-abbrev-table' and\n`elixir-mode-syntax-table'\n\nwhich more-or-less shadow elixir-ts-mode's corresponding tables.\n\nIn addition to any hooks its parent mode might have run, this mode\nruns the hook `elixir-mode-hook', as the final or penultimate step\nduring initialization.\n\n\\{elixir-mode-map}"
(interactive)
(delay-mode-hooks
(elixir-ts-mode)
(setq major-mode 'elixir-mode)
(setq mode-name "Elixir")
(progn
(if
(get 'elixir-ts-mode 'mode-class)
(put 'elixir-mode 'mode-class
(get 'elixir-ts-mode 'mode-class)))
(unless
(keymap-parent elixir-mode-map)
(set-keymap-parent elixir-mode-map
(current-local-map)))
(let
((parent
(char-table-parent elixir-mode-syntax-table)))
(unless
(and parent
(not
(eq parent
(standard-syntax-table))))
(set-char-table-parent elixir-mode-syntax-table
(syntax-table))))
(unless
(or
(abbrev-table-get elixir-mode-abbrev-table :parents)
(eq elixir-mode-abbrev-table local-abbrev-table))
(abbrev-table-put elixir-mode-abbrev-table :parents
(list local-abbrev-table))))
(use-local-map elixir-mode-map)
(set-syntax-table elixir-mode-syntax-table)
(setq local-abbrev-table elixir-mode-abbrev-table))
(run-mode-hooks 'elixir-mode-hook)))
引用被truncate到第52行了,可以一直看到第89行。
但是通过c-default-style设置缩进风格好像还是不行?
c-default-style 是用来设置 c-mode
和 c++-mode
的,至于 c-++-ts-mode
的缩进风格怎么调我还没试过。
用 c-ts-mode-indent-offset
。
我最近也在折腾配色方案,但是不知道为什么,我默认的配色方案似乎就有些问题,不知道能否指导一下,如何排查?
举个例子,go-ts-mode 中是这样配置的:
(defvar go-ts-mode--font-lock-settings
(treesit-font-lock-rules
:language 'go
:feature 'function
‘((call_expression
function: (selector_expression
field: (field_identifier) @font-lock-function-name-face))
(call_expression
function: (identifier) @font-lock-function-name-face)
(function_declaration
name: (identifier) @font-lock-function-name-face)
(method_declaration
name: (field_identifier) @font-lock-function-name-face))))
实际使用过程中,只有 foo()
这样的函数能高亮,foo.bar()
这样的函数就不会高亮
我看过 explore-mode 里面,定义里的 field: (field_identifier)
也是能对于到 foo.bar()
里面的 bar
的,但是就是无法高亮 bar
(call_expression
function: (selector_expression
field: (field_identifier) @font-lock-function-name-face))
(setq-local treesit-font-lock-level 4)
(treesit-font-lock-recompute-features '(command string variable function operator bracket keyword)))
这两个 设置很重要的
这样设置对性能有影响吗?看说明渲染会多不少东西。
反正我是没感觉到卡顿,以前使用 emacs-tree-sitter.el 的时候,也是这样配色的。也没遇到性能上的问题。
@casouri 最近发了篇 Blog 介绍 Emacs 29 中的 tree-sitter 使用和未来的计划。还不了解用法的可以看看。
https://archive.casouri.cc/note/2023/tree-sitter-in-emacs-29/index.html
感谢分享。设置 treesit-language-source-alist
这个变量后,就可以直接在 Emacs 里安装相关的 parser 了
(setq treesit-language-source-alist
'((bash . ("https://github.com/tree-sitter/tree-sitter-bash.git"))
(c . ("https://github.com/tree-sitter/tree-sitter-c.git"))
(cmake . ("https://github.com/uyha/tree-sitter-cmake.git"))
(cpp . ("https://github.com/tree-sitter/tree-sitter-cpp.git"))
(csharp . ("https://github.com/tree-sitter/tree-sitter-c-sharp.git"))
(css . ("https://github.com/tree-sitter/tree-sitter-css.git"))
(dockerfile . ("https://github.com/camdencheek/tree-sitter-dockerfile.git"))
(go . ("https://github.com/tree-sitter/tree-sitter-go.git"))
(gomod . ("https://github.com/camdencheek/tree-sitter-go-mod.git"))
(html . ("https://github.com/tree-sitter/tree-sitter-html.git"))
(java . ("https://github.com/tree-sitter/tree-sitter-java.git"))
(javascript . ("https://github.com/tree-sitter/tree-sitter-javascript.git"))
(json . ("https://github.com/tree-sitter/tree-sitter-json.git"))
(python . ("https://github.com/tree-sitter/tree-sitter-python.git"))
(ruby . ("https://github.com/tree-sitter/tree-sitter-ruby.git"))
(rust . ("https://github.com/tree-sitter/tree-sitter-rust.git"))
(toml . ("https://github.com/tree-sitter/tree-sitter-toml.git"))
(tsx . ("https://github.com/tree-sitter/tree-sitter-typescript.git" nil "tsx/src"))
(typescript . ("https://github.com/tree-sitter/tree-sitter-typescript.git" nil "typescript/src"))
(yaml . ("https://github.com/ikatyang/tree-sitter-yaml.git"))))
这样直接在 Emacs 里 M-x treesit-install-language-grammar 就可以了,不用每次都要到 admin/notes/xxx
里去手动安装了,这样默认会装在 (user-emacs-directory)/tree-sitter
下面
不过现在 Emacs 更新后,auto-mode-alist
里没了 xxx-ts-mode
,还得自己手动加,
以 go-ts-mode
为例
虽然 mode 文件里有写这么一行,但这不应该是调用了 go-ts-mode
后才会生效的吗?除了提前在自己的配置文件里加上 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
,还有啥好的解决办法么
随手糊了一个,但治标不治本,现在将就用
(dolist (list `((cmake . (,(rx (or "CMakeLists.txt" ".cmake") eos) . cmake-ts-mode))
(dockerfile . (,(rx (or (seq "Dockerfile" (opt "." (zero-or-more nonl))) (seq "." (any "Dd") "ockerfile")) eos) . dockerfile-ts-mode))
(go . (,(rx ".go" eos) . go-ts-mode))
(gomod . (,(rx "/go.mod" eos) . go-mod-ts-mode))
(rust . (,(rx ".rs" eos) . rust-ts-mode))
(tsx . (,(rx ".tsx" eos) . tsx-ts-mode))
(typescript . (,(rx ".ts" eos) . typescript-ts-mode))
(yaml . (,(rx ".y" (opt "a") "ml" eos) . yaml-ts-mode))))
(let ((parser (car list))
(alist (cdr list)))
(when (treesit-ready-p parser)
(add-to-list 'auto-mode-alist alist))))
另一种方法是 (add-to-list 'major-mode-remap-alist '(go-mode . go-ts-mode))
,这样在激活 go-mode 时调用 go-ts-mode.
但 Emacs 没有内置的 go-mode
,除非装了 go-mode
这个包,这样 remap 的时候才有用
今天有大佬根据 casouri 的starter guide 写了个treesit-auto, 包含了各种语言的source-alist, 以及各个mode的 fallback,如果想偷懒的话可以直接装这个。
文章中包的地址多了个后缀.el打不开,用这个地址:GitHub - renzmann/treesit-auto: Automatically pick between Tree-sitter and default major modes in Emacs 29+
edit: typo
我个人不大需要这样的包,自己常用的也就那几个 mode,放到个人配置就好了。而且 tree-sitter 还在不断改动。等 emacs-29 发布时应该会有一个官方推荐设置。
上面提到的 treesit-language-source-alist
变量不是应该提供一个默认值更好吗?还要让用户去设置这一大串。
不过我还是更加喜欢用脚本。
嗯,我个人也只用python, js, clojure,但也是脚本一次性全build了。除了其中 clojure 的source link 要自己找,整体上工作量不大。
不过一开始设置的时候还是比较蒙圈的,直到starter guide出来后,思路算是清晰了。