yasnippet最后一个占位符如果是括号,则无法擦除?

比方说:yasnippet脚本里

(let ((${1:var} ${2:exp}))
  ${0:body})

然后在代码里打let会展开成这样:

(let ((var exp) )
  body)

接下来,你写代码TAB到body这个占位符:

(let ((foo (bar 123)) )
  |body) ;<----此时光标在body这里,并自动选中了body

如果你想写的表达式是常数(比如 1 2 3 'abc等)则没问题,body会被擦除。

但是如果打括号(比如 一个函数调用)则会把body括起来,变成:

(let ((foo (bar 123)) )
  (body))

不知道你们有没有遇到过类似的问题,每次都要手动删除这个body,很麻烦。

这个跟 yasnippet 没有关系吧。你是不是启用了electric-pair-mode 或者 smartparens之类的?

是的,我启用了 smartparens

你说和yasnippet没关系,但奇怪的是偏偏最后那个占位符有问题,中间的没问题。。。

emacs -Q 单独加载 yasnippet 排除看看。

Snippet 写成这样就没事了呀

(let ((${1:var} ${2:exp}))
  $0)

但是我还是想写一个占位符(这样可以和其他占位符保持一致)。。。

你也有这个问题吗?

还是我一个人独有。。。

应该是yasnippet对$0站位符有特殊处理。文字body用的是选区包裹而不是其他yasnippet形式一样。然后smartparens之类的插件让你在对选区上按(时自动包裹了选区

(let ((${1:var} ${2:exp}))
  ${3:body})$0

要不写成这个样子吧

1 个赞

很不错,非常感谢!

之前一直不清楚$0的意义,只是照抄内置snippet,以为它就表示最后一个Placeholder fields。

现在看起来,$0只是表示一个 Tab stop fields,而不是一个 Placeholder fields。


这甚至部分解决了这个问题:yasnippent的问题:你们是怎么处理变长参数和嵌套的? - #8,来自 chansey97

因为相当于一个nested expression完后后可以jump到外部,这样外部的多参数就可以空格之后继续往下写了。

(之所以说部分解决,因为像let那样每一个var-val pair有自己的括号,所以val如果是嵌套表达式它只能jump到自己的外部,但jump不出var-val的括号。但确实能解决问题过程调用的那种变参)

缺点是对于已经嵌套了yasnippet的placeholder,需要比平时多按一次tab键盘。

感觉yasnippet对于${0:xxx}这种形式确实处理有点问题。

看了 7 楼回答,我貌似回想起来了,$0 不是你这么用的。

跳到 $0 的时候,yasnippet 的调用 已经结束 了。绝大多数情况下,$0 作为一个特殊 tabstop,不应该有缺省值这样的 placeholder,只能是 $0 这样裸的形式。

在大部分情况下,$0 在 snippet 里是可以省略的。这么一说,是不是容易理解了?我手边没有电脑,你试一下应该是这样。

但是使用$0需要比平时多打一个TAB

实际上,以下代码:

(let ((${1:var} ${2:exp}))
  ${3:body})$0

最后那个$0应该可以省略不写的,因为最后一个Tab stop fields显然就是end of “snippet code”。

但这相比:

(let ((${1:var} ${2:exp}))
  ${0:body})

还是有区别的。

第二段代码,TAB到body之后,再TAB是会跳到下一个placeholder(可能是外层snippet)。

但第一段代码,TAB到body之后,再TAB会先跳到$0的位置,然后再TAB才会跳到下一个placeholder。

所以需要多打一个TAB(好处是可以跳到外层去)


但是以上并不代表snippet实现就没BUG,因为{0:body}的语法其实是没问题的,仅仅是对 smartparens有冲突,如果没smartparens则没问题。。。

snippet实现没问题,smartparens篡改了启用选区时(的行为(改为包裹选区)

这算是高度hackable的代价之一。谁遭得住


yasnippet把$0作为yas在选区上展开时选区内内容的存放地点,所以$0的默认值被选区包围是正常的行为。

1 个赞

{0:body}的语法是有问题的。它不出错,不代表你可以这么做。$0 设计来就是让你多按一次 tab 的:明确告诉 yasnippet 调用结束了,完成状态的切换。

至于 yasnippet 的嵌套我之前没试过。和 smartparens 之类的插件关系也不大。

你再看看文档吧?印象里 $0 不是这么用的。在其它编辑器里的 snippet 插件也没这个用法。

但你怎么解释非$(0:xxx)的那些占位符 smartparens是OK的?

(非$(0:xxx)的那些占位符也是包裹选区的)

我觉得yasnippet可能还是有问题。。。

placeholder 和 选区 还是有区别的,尽管外观视觉上它俩差不多。至于是如何区分的,为何 smartparens 表现不一致,那得看 yasnippet 的代码了。

作为一个广泛使用的插件,features 多少暂且不论。yasnippet 出问题的可能性极小,别轻易怀疑。