grep不好用的例子:有好多class/struct都含有同名的成员,例如name。那么问题来了,我怎么找出所有引用Student::name的地方,而不要School::name或者Team::name还有其他什么name的地方呢?用grep只能给出所有的,里面含有大量你不关心的结果。
你说的这个我觉得只能用 lsp 之类的智能工具解决
我觉得TAGS对C语言来说是可以的,因为就算struct成员有重名,至少函数名字都是唯一的,不同名字空间的函数一般通过加前缀的方式区分,跳转到函数定义这个基本功能多少是可用的。对C++,Java之类的语言来说,TAGS就很难用了,因为函数重名的实在太多了,在有namespace,package,class的情况下再加前缀本身是多此一举,但不这样TAGS又无法区分,连寻找函数定义这样的工作都无法很好地完成。
Ctags 对脚本语言和C语言都可以,其实只有Java这种重继承的语言需要LSP.
Ctags方案轻,主要速度快,比LSP废柴后端好。
找定义的话,我想 Ctags 其实没有你想得这么弱。
我们就讨论 Java。我在 Ctags 的测试用例里翻出个例子:
$ cat test.java
public class input {
interface greeting {
public void greet(String word);
}
public void hello () {
greeting g = new greeting() {
public void greet (String word) {
}
};
g.greet("hello");
}}
$ ctags --fields='*' -o - test.java
greet test.java /^ public void greet(String word);$/;" kind:method line:3 language:Java scope:interface:input.greeting access:public signature:(String word) roles:def end:3
greeting test.java /^ interface greeting {$/;" kind:interface line:2 language:Java scope:class:input access:default roles:def end:4
hello test.java /^ public void hello () {$/;" kind:method line:6 language:Java scope:class:input access:public signature:() roles:def end:12
input test.java /^public class input {$/;" kind:class line:1 language:Java roles:def end:12
注意这两行,我只把关键的 fields 列出来:
greeting kind:interface scope:class:input
hello kind:method scope:class:input
可见 Ctags 知道这两个符号分别是 interface 和 method,并且是在 input class 里定义的。
现在的难点是,在 Citre 里要利用这个信息的话,我们要根据上下文推测出你需要 input class 里的符号。但是可以退一步,让用户给出这个信息,那就是我上面说的这个思路:
「是 input class 里定义的」也可以作为一个条件。
Ctags 也会记录继承关系的,这些都是可以利用的。
lsp 实在搞不懂,没配起来。我猜着写了个配置,你确认下能不能用?
;; If you keep this as non-nil, `citre-mode' will override the combined backend
;; with its own (Citre only) capf backend.
(setq-default citre-enable-capf-intergration nil)
(defun lsp-citre-capf-function ()
"A capf backend that tries lsp first, then Citre."
(or (lsp-completion-at-point) (citre-completion-at-point)))
(defun enable-lsp-citre-capf-backend ()
"Enable the lsp + Citre capf backend in current buffer."
(add-hook 'completion-at-point-functions #'lsp-citre-capf-function nil t))
;; You can also put it in other hooks to suit your need.
(add-hook 'prog-mode-hook #'enable-lsp-citre-capf-backend)
用的时候要把 company-capf
后端放在 company-backends
列表的最前面,反正保证不要被其他 company 后端干扰就行。能用的话我就加到 wiki 里了。
挺好,比我的那个版本好。
不启用 citero-mode
的情况下, 使用下面的 advice, 可以在 lsp 找不到索引的时候用 citre 后端
(define-advice xref--create-fetcher (:around (-fn &rest -args) fallback)
(let ((fetcher (apply -fn -args))
(citre-fetcher
(let ((xref-backend-functions '(citre-xref-backend t)))
(apply -fn -args))))
(lambda ()
(or (with-demoted-errors "%s, fallback to citre"
(funcall fetcher))
(funcall citre-fetcher)))))
谢谢!可以把这个写进 wiki 吗?您可以创建一个新的 page 叫做 Use lsp-mode with Citre。
如果您不方便的话,可以允许我把它写进 wiki 吗?
可以的, 你来写吧
我感觉可以向 company-mode
贡献一个 company-ctags
后端,这样的话也可以同时使用 company-capf
(lsp) 和 cirte 了。
不行啊…
lsp 有没有什么好弄一点的后端?我装了 lsp-mode
和 lsp-pyright
,通过包管理器和 pip 都安装了 pyright
,结果它还是识别不到。
装个 clangd, lsp-mode 原生支持
我用 citre 内部提供的 api, 实现了一个 company 后端, 不过只有 company 的部分功能
发现 citre-capf--get-annotation
函数在, 有 cache 的情况下, 不会根据输入的 symbol 过滤一遍, 所以还得再调用一次 all-completions
(defun company-citre (-command &optional -arg &rest _ignored)
"Completion backend of for citre. Execute COMMAND with ARG and IGNORED."
(interactive (list 'interactive))
(cl-case -command
(interactive (company-begin-backend 'company-citre))
(prefix (and (bound-and-true-p citre-mode)
(or (citre-get-symbol) 'stop)))
(meta (citre-get-property 'signature -arg))
(annotation (citre-capf--get-annotation -arg))
(candidates (all-completions -arg (citre-capf--get-collection -arg)))
(ignore-case (not citre-completion-case-sensitive))))
(setq company-backends '((company-capf company-citre :with company-yasnippet :separate)))
赞!我想你的 ignore-case
应该是写反了
太感谢了!我这周末的时候试试,暂时先用着懒猫大神的方法。我也看到后面有很多其他方式,我到时候也学习下~
没注意, 修改了