补全占位符的实现

Eglot 不能补全函数参数吗? 继续讨论:

我之前说了用text property + overlay 应该很容易实现。实际上用不上overlay:

(defface placeholder (let ((display t)
                           (attributs '(:inherit highlight)))
                       (list (cons display attributs)))
  "Face for argument placeholders."
  :group 'company)

(defface placeholder-mouse (let ((display t)
                                 (attributs '(:inherit highlight
                                                       :bold t)))
                             (list (cons display attributs)))
  "Mouse face for argument placeholders."
  :group 'company)

(defun make-placeholder (text tooltip)
  "Return a  placeholder TEXT with TOOLTIP."
  (propertize " "
              'display text
              'help-echo tooltip
              'insert-in-front-hooks (list (lambda (beg end)
                                             (message "%d %d" beg end)
                                             ;; self-remove of placeholder
                                             (save-excursion
                                               (goto-char end)
                                               (delete-char 1))))
              'face 'placeholder
              'font-lock-face 'placeholder
              'mouse-face 'placeholder-mouse
              'rear-nonsticky t))

(setq ph (make-placeholder "arg" "help"))

现在有两个小问题:

  1. 不知道为什么没法触发insert-in-front-hooks
  2. 开启了font-lock-mode的话就不会显示'face,必须要设置'font-lock-face才行,但是这样好像又影响了'mouse-face

tab跳转可以参考widget,应该不难实现,不过我想先把这几个问题修复了再说。

更新:

1)看起来像是bug:SO上有个相关的问题。确实关掉font-lock-mode就没有问题了……而且font-lock-mode还影响了help-echo……

1 个赞

是紧挨着才行吧? 修改的地方和这个field之间有其他字符就不会触发.

对于这种情况可以用 after-change-functions来处理.

这种问题最好直接给yasnippet提需求, 维护者挺活跃的, 而且还是emacs的开发人员, 经验足够丰富

这个功能是用yasnippet实现的吗?我现在是用eglot配合company,看起来像是company的功能。

可能用overlay确实不会受这些奇怪的font-lock问题影响,我只是更喜欢text-property,因为property和字符是一体的,不像overlay和字符是分离的。而且就算用overlay也有几个property要用text property实现,如果用text-property的话就不需要overlay。此外text-property可以直接返回,overlay就要直接在buffer里改。最后text-property对undo比较友好。

company自己也实现了一套, 比yasnippet简单很多, 后者应该更专业

我用yasnippet比较少,印象里是没有占位符的,yasnippet有占位符吗?

咱们理解没偏差的话, 是有的, 而且这东西最早好像来自于textmate的snippet, 从snippet发展而来, eglot的snippet补全好像就是用的yasnippet.

好,我去看看yasnippet的实现

LSP server发给client的就是textmate的snippet,正好用yas展开。至于company的占位符是什么样子的?我还没见过呢

company里面company-template.el, 只有200多行, 功能肯定简单很多.

yasnippet 和 company-template 就是 ov 实现的,我认为关键不在此,而是它们的清除时机出了问题。

如果改为直到下一次创建新的 placeholder,才把上一次清除,是不是更好呢?这样用户可以在清除之前随时 resume,类似楼主这个<简单地暂停和继续宏> 的效果,就是允许用户在编辑过程中出错、开小差。

我觉得现在的占位符的主要问题在于占位符过于脆弱 — 随便点一下或者移动point就会完全破坏所有的特殊效果,把占位符变成普通字符,完全不可理喻。理想的情况是像IDE(比如XCode)一样,在别的地方随意编辑完全不影响占位符,只有在占位符上输入或者删除占位符才会影响它。字面意义上的占位符就应该是这样:除了在上面输入会替换掉占位符以外,其它方面和普通字符一样。

不清楚你想要的效果是什么,为什么要这样?

如果用text property实现,用户完全可以undo恢复占位符,完全像普通字符一样,编辑的时候没有任何心理压力。如果用我的overlay实现(我没上传,跟text-propery差不多),也能有我上面说的在别的地方编辑完全不影响占位符的效果。我们还可以加入tab在几个占位符之间循环跳转的功能,实现不难。

就是想说如何解决「占位符过于脆弱」容易被破坏的问题。

至于 ov 和 text-property 还是 IDE 只是呈现/保持占位符的手段的不同,没有本质上的区别,决定什么时候清除才是关键。

Xcode 好像是不清除失焦占位符的,可以留下一堆未填写的空,然后去干别的,随时回来继续编辑。而 Emacs 的习惯是用键盘循环切换位置点的,因此如果补全新函数的时候、不消除上一次的残留,可能会造成干扰。如果不认为是干扰,也可以跟 Xcode 一样:不清理未编辑的占位符。

我个人偏好XCode那样留着占位符www

你看了company/yasnippet的实现了吗?我还没看。我觉得改进一下company的占位符实现会很不错。

改company的意义不大

yasnippet能保存snippet 在一定程度上可以做到重新初始化占位符 company则没有这个能力

专心做好一件事 company只管补全就好

lsp-mode 是配合 yasnippet 或者 complete-at-point 实现的

我在一个issue里看到作者说eglot会用snippet.el,但我没在代码里找到🤔


看错了,是用的yasnippet。看来改进应该在yas上

以我的方式就算弄好了吧

没有让他保留当前的环境 而是加了个隐藏项

隐藏项可以调出

llll

举个简单应用的例子(好像也没什么用)

ccccc