背景:
主业C++开发。elisp初学。spacemacs develop用户。lsp-mode + ccls
问题:
比较新的spacemacs下,C++中lsp比较完美,但敲字符串后无法自动用 company-dabbrev
补全,影响体验。比较老的spacemacs develop的commit没有这个问题
排查:(已编辑)
根本原因不是OP中描述的那样,而是函数 company--capf-data
会在补全字符串时不为空。也就是说,ccls在这时候也会返回东西给到 lsp-mode
。
可能的魔改方案:
- 魔改 ccls ,毕竟双引号确实应该是个 trigger-char,但仅限于补全头文件时,可以加个判断
- 魔改某个elisp函数,加个advice之类的,也是加个判断筛选
采用的魔改方案:
- 在
company-capf
的prefix
阶段加个flag,捕获company--capf-data
的返回值 - 如果满足字符串的判定,将上述返回值改成
nil
,否则原样返回
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fix `company-capf' catching string unwillingly
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(with-eval-after-load 'lsp-completion
(defun dc4ever/filter-capf-lsp-retval (res)
"Filter return value to `nil' in the following conditions:
- We are dealing with `company-capf' `pcase' `prefix'
- We are using `lsp-completion-at-point' as capf
- We are using `ccls' as lsp server
- We are trying to complete a string starting with \"
- We are not trying to complete header files"
(unless (and (and (boundp 'dc4ever/capf-prefix?) dc4ever/capf-prefix?)
(eq 'lsp-completion-at-point (car res))
(eq 'ccls (lsp--workspace-server-id (car (lsp-workspaces))))
(let ((bounds-start (nth 1 res)))
(save-excursion
(goto-char bounds-start)
(unless (= (point) (point-at-bol))
(and
(not (equal "#include "
(buffer-substring-no-properties
(point-at-bol)
(+ (point-at-bol) (length "#include ")))))
(equal "\"" (buffer-substring-no-properties
(- (point) 1) (point))))))))
res))
(defun dc4ever/capf-wrapper (func &rest r)
"Wrap `company-capf' with a special tmp variable `dc4ever/capf-prefix?'
when we are calling with 'prefix command"
(if (eq 'prefix (car r))
(let ((dc4ever/capf-prefix? t))
(apply func r))
(apply func r)))
(advice-add 'company-capf
:around 'dc4ever/capf-wrapper)
(advice-add 'company--capf-data
:filter-return 'dc4ever/filter-capf-lsp-retval))
请各位大佬指点,谢谢。
PS: 以下为OP
用 edebug
跟踪代码发现,在 lsp-completion-at-point
中,双引号 \"
是一个 trigger-char
。这导致如下代码在尝试补全字符串时 (例如, "str|"
时)
:company-prefix-length
(save-excursion
(goto-char bounds-start)
(and (lsp-completion--looking-back-trigger-characterp trigger-chars) t))
evaluate成 t
导致无法交给优先级更低的 company-dabbrev
接管。