yasnippet 有没有办法让某个 mode 的 snippets 保存到另一个 mode 的目录下?

比如原本是 go-mode, 现在我用了 treesit 是 go-ts-mode, 创建 new snippet 它会提示我创建到 go-ts-mode 目录下, 但我希望它就创建到 go-mode 下. 虽然我想到可以用 symbolic, 就是让 go-ts-mode 指向 go-mode, 但这种方法我觉得不好, 一个明显的缺点是, 比如现在我添加到 go-ts-mode 了, 但是 org babel 中对于 go src block, 是 go-mode, 它查找不到这个 snippet.

可以设置 .yas-parents 来复用

https://joaotavora.github.io/yasnippet/snippet-organization.html#org7468fa9

*-mode*-ts-mode 完全可以共用,放一个地方就好了。

;; 在 *-ts-mode 下加载 *-mode 的 snippets
(advice-add 'yas--modes-to-activate :around
 (defun yas--get-snippet-tables@reverse-ts-mode (orig-fn &optional mode)
   (funcall orig-fn
            (or (car (rassq (or mode major-mode) major-mode-remap-alist))
                mode))))

;; 在 *-ts-mode 下保存 snippets 到 *-mode 目录 (也可以试试直接在 yas--table-get-create 上 advice 看看有没有不良影响)
(advice-add 'yas-new-snippet :around
 (defun yas-new-snippet@reverse-ts-mode (&rest args)
   (cl-letf* ((yas--orig-table-get-create (symbol-function 'yas--table-get-create))
              ((symbol-function 'yas--table-get-create)
               (lambda (mode)
                 (funcall yas--orig-table-get-create
                          (or (car (rassq (or mode major-mode) major-mode-remap-alist))
                              mode)))))
     (apply args))))
2 个赞

我原来也使用 .yas-parent, 后来发现直接软链就得了。。。

对这段代码我有个语法问题不理解, 我理解的是一个 symbol 可以有一个 value binding 也可以有一个 function binding, 这里 yas-new-snippet@reverse-ts-mode 使用了 cl-letf, 这个宏如果不加 symbol-function 我理解的是它进行的是 value binding, 那么 yas--orig-table-get-create 就应该是 value binding, 但 funcall yas--orig-table-get-create funcall 应该用的是第一个参数的 function binding, 但 cl-letf 不是进行的是 value binding 么? 我觉得按我的想法会出错, 我想请教是我哪里想错了呢?

虽然我用了 treesit-auto, 但发现 major-mode-remap-alist 为 nil, 于是我修改为:

(setq my/yas-major-mode-remap-alist (treesit-auto--build-major-mode-remap-alist))

然后把 major-mode-remap-alist 改为 my/yas-major-mode-remap-alist. 不知道有无必要.

岔个题,有人用tempel吗,感受如何?

symbol-function 返回的即是 value 也是 place,就当作是指针吧。

看一下 cl-left 宏的原型 (cl-letf ((PLACE VALUE) ...) BODY...),就是把 (symbol-function 'xxx) 位置的 value 替换为指定的值。所以你可以提前把该位置的 value 备份起来。