treesit 已经合并进 master 分支了

C 中不主动说明类型默认 int。建议楼上报告个 bug 吧,emacs 在任何情况下也不应该卡死。

我用这个方法设置 python-mode 使用 python-ts-mode 可以生效,但对 js-ts-mode 无效。用的 Emacs 29 分支。

  (push '(js-mode . js-ts-mode) major-mode-remap-alist)

解决了,原来不叫 js-mode, 叫 javascript-mode, 这样写就生效了:

  (push '(javascript-mode . js-ts-mode) major-mode-remap-alist)

这是目前我个人用的设置:

(when (treesit-available-p)
  (push '(sh-mode . bash-ts-mode) major-mode-remap-alist)
  (push '(c-mode . c-ts-mode) major-mode-remap-alist)
  (push '(c++-mode . c++-ts-mode) major-mode-remap-alist)
  (push '(css-mode . css-ts-mode) major-mode-remap-alist)
  (push '(javascript-mode . js-ts-mode) major-mode-remap-alist)
  (push '(js-json-mode . json-ts-mode) major-mode-remap-alist)
  (push '(python-mode . python-ts-mode) major-mode-remap-alist))
4 个赞

应该是主要看你 auto-mode-alist 里打开文件调用的 mode 是哪个吧,我记得我配置 js 的时候看到过 javascript-mode 是 js-mode 的 alias,为啥设 js-mode 不起作用我就不知道了。

我这么写了一会儿,发现一直在添加新的 ts-mode,我就直接写成了 setq 的方式,这样删减也方便些

(when (treesit-available-p)
  (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)
          (java-mode       . java-ts-mode)
          (js-mode         . js-ts-mode)
          (javascript-mode . js-ts-mode)
          (js-json-mode    . json-ts-mode)
          (python-mode     . python-ts-mode)
          (ruby-mode       . ruby-ts-mode)
          (sh-mode         . bash-ts-mode))))
2 个赞

是啊,以后这个列表会越来越长,要是有个变量可全局开启 tree-sitter 支持就好了。不想开的 mode 再关就是了。

我也是这么干的,直接setq就好了。

自定义设置 配色方案后,效果还是很不错的。 分享我的相关配置:

2 个赞

如果你只想用新的 -ts-mode,完全卸载掉老的 mode,以 elixir-mode 为例,可以这么写。

(define-derived-mode elixir-mode elixir-ts-mode "Elixir")

(add-to-list 'auto-mode-alist '("\\.elixir\\'" . elixir-mode))
(add-to-list 'auto-mode-alist '("\\.ex\\'" . elixir-mode))
(add-to-list 'auto-mode-alist '("\\.exs\\'" . elixir-mode))
(add-to-list 'auto-mode-alist '("mix\\.lock" . elixir-mode))

而用 major-mode-remap-alist 会有一些问题,比如 org babel 高亮没办法生效。

;; 这样写大部分地方 ok,但是会有些地方不认 major-mode-remap-alist
(define-derived-mode elixir-mode elixir-ts-mode "Elixir")
(push '(elixir-ts-mode . elixir-mode) major-mode-remap-alist)

回复错人了,怎么改 :rofl:

define-derived-mode 可以把原来 mode 的 hook 和 map 也继承到 -ts-mode 上吗

不清楚,好像可以?

我觉得新增个变量的这个想法很好,就不用每个新的 ts-mode 都自己设置一遍了,大佬可以发个邮件建议一下 :ghost:

英雄所见略同(战术后仰

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

2 个赞

-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)))
1 个赞

引用被truncate到第52行了,可以一直看到第89行。

但是通过c-default-style设置缩进风格好像还是不行?

c-default-style 是用来设置 c-modec++-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)))

这两个 设置很重要的

1 个赞

这样设置对性能有影响吗?看说明渲染会多不少东西。