测试了一下更新后的company。
发现一个问题:
doc-buffer preview 报错:
Error running timer: (error "Company: backend (company-capf :separate company-yasnippet :separate company-tempo :separate company-keywords :separate company-abbrev) error \"Wrong type argument: stringp, (stringp nil)\" with args (doc-buffer template)")
我有一个 template
snippet,内容如下:
# -*- mode: snippet -*-
# name: template
# key: template
# --
;;; ${1:$$(file-name-base)}.el --- $2 -*- lexical-binding: t; -*-
;;; Time-stamp: <2020-02-02 17:37:34 stardiviner>
;;; Commentary:
$3
;;; Code:
$0
(provide '$1)
;;; $1.el ends here
是因为snippet里面的 $$(file-name-base)
函数的缘故。删掉这个函数后就可以预览了。不知道有什么解决办法没有?可能是因为yasnippet内部的expand机制缘故。
是会报错,问题是出在yasnipet-expand-snippet。测试
(yas-expand-snippet "${1:$$(file-name-base)}.el")
*** Eval error *** Wrong type argument: stringp, (stringp nil)
这样测试是能过的
(yas-expand-snippet "${1:$$(upcase yas-text)}")
问题是这个file-name-base应该。
这种情况应该比较少见,类似函数 file-name-base
这种依赖于当前环境的这种情况。
(如果没有解决办法,我觉得可以加一个条件判断来跳过报错,或者可以用 ignore-errors
这样的粗暴办法)
这样忽略错误不是根本办法。。可以让yasnippet author 瞅瞅其实。
肯定的,所以我说是“如果没有解决办法”。毕竟我也不熟悉yasnippet的展开机制。
比较奇怪的是,我第一次选择到 template
的时候,会上面那个错误,但是当我delete一个字符,然后重新补全的时候,company-yasnippet又能显示 template
的 doc-buffer 了。不过里面并没有显示 $$(file-name-base)
的文件名,难道是cache缓存的结果?
file-name-base 接受一个参数 filename 。。docbuffer没有所以挂掉了。。我在瞅瞅yasnippet
另外,我看 company-yasnippet--doc
的代码逻辑,是不是把 (funcall mode)
的那个逻辑放在启动yasnippet-minor-mode 和expand之前更好点?
@@ -101,16 +101,16 @@ (defun company-yasnippet--doc (arg)
(let ((template (get-text-property 0 'yas-template arg))
(mode major-mode))
(with-current-buffer (company-doc-buffer)
- (yas-minor-mode 1)
- (yas-expand-snippet (yas--template-content template))
(delay-mode-hooks
(let ((inhibit-message t))
(if (eq mode 'web-mode)
- (progn
- (setq mode 'html-mode)
- (funcall mode))
+ (progn
+ (setq mode 'html-mode)
+ (funcall mode))
(funcall mode)))
- (ignore-errors (font-lock-ensure)))
+ (ignore-errors (font-lock-ensure))
+ (yas-minor-mode 1)
+ (yas-expand-snippet (yas--template-content template)))
(current-buffer))))
没啥影响,你这个还是要报错的。这个filename-base会接收当前文件名为参数,docbuffer并没有。
doc-buffer 应该有buffer名字的 (with-current-buffer (company-doc-buffer) ...
(company-doc-buffer)
返回的是 #<buffer *company-documentation*>
.
你看下源码。。filename或者buffer-file-name…
(defun file-name-base (&optional filename)
"Return the base name of the FILENAME: no directory, no extension."
(declare (advertised-calling-convention (filename) "27.1"))
(file-name-sans-extension
(file-name-nondirectory (or filename (buffer-file-name)))))
这不就解决了吗。。给一个buffer-file-name不就好了
我想了下,觉得还是 再加上 ignore-errors
比较稳定,因为yasnippet expand可能不止这种缺少 buffer-file-name
的情况,还有其他的edge case。所以ignore-errors会防止报错。个人观点。虽然这个导致了忽略报错情况。
我也赞成用 ignore-error 或者直接给出错误提示。如果 snippet 写错了或者由于 bug 无法展开不至于在 company 里报错。
错误是出在使用了这种特殊函数的情况,其他的snippet展开应该是没问题。加上ignore-error是可以的,但是没有doc出来也没有错误。用户不会觉得很奇怪吗。给出错误会打扰用户输入的思维。感觉也不是很好。
可以在 doc buffer 中显示原始字符串,并给出错误提醒。
还有个问题:为什么要用 delay-mode-hooks
?有什么考量呢?
我简化了下,这样就能工作:
(defun my-company-yasnippet--doc (arg)
(let ((template (get-text-property 0 'yas-template arg))
(mode major-mode)
(file-name (buffer-file-name)))
(with-current-buffer (company-doc-buffer)
(let ((inhibit-message t)
(buffer-file-name file-name))
(ignore-errors
(yas-minor-mode 1)
(yas-expand-snippet (yas--template-content template))
(funcall mode)
(font-lock-ensure)))
(current-buffer))))
company有没有办法做到 0 delay 自动弹出且不影响输入的流畅性呢?
隔壁有帖子说native-comp
branch 很流畅。