Citre 0.4: eglot 后端 + citre-peek,流畅的代码阅读体验

Citre 0.4 发布了! :tada:

Xref 后端适配器

Citre 现在增加了 Xref 后端适配器,可以把 Xref 后端变成 Citre 后端,从而利用 Citre 提供的代码阅读工具。

基于这个适配器,提供了 eglot 后端。准确的定义/引用查询配合 citre-peek 不离开 buffer 就可以追踪代码逻辑的设计,可以提供流畅的代码阅读体验。

(不离开当前文件就可以 peek 到系统库中的定义)

用户手册还提供了把 elisp 的 xref 后端变成 Citre 后端的例子,非常简单。您可以参照这个例子来适配其他的 xref 后端,比如 dumb-jump 等等。

citre-query-* 命令

现在提供了 citre-query-jump(-to-reference)citre-query-peek(-reference) 命令。直接 call 的话会让用户输入符号名字;带有 prefix argument 的话则会在用户输入时使用项目中的符号作为补全。

重写了 tags 文件生成命令

这部分移除了一些少用的特性,此外原先是将命令嵌入 tags 文件中的(太 hack 了),现在改成了使用 Universal Ctags 本身就支持的 option file。因此更新后您可能需要重新生成已有的 tags 文件。

23 个赞

tql,一直在用,非常好用

很好用,感谢作者的贡献!

我之前就想自己手搓第二个功能,但是还没等我开始写代码,新版就推出这个功能了!很凑巧 :laughing:

1 个赞

以前用 Citre 来浏览大型项目(如 linux kernel)或 lsp 不支持的项目,但因为和 eglot 有冲突,就关闭了,现在好了,又可以愉快的使用了。感谢大佬的工作!

这个新特性引入一个Bug:不能指定dir/file了。

原因是: ctags 传参格式是 ctags [options] [file(s)] ,目前向导生成的dir/file是在 option file 中(citre-ctags-cmd-buf-add-dir-or-file),所以 ctags 没有读取 dir/file 入参。

我本地验证结果:

  1. ctags --options=/home/archer/.cache/tags/\!home\!archer\!workspace\!android\!xxxx\!android\!.ctags - 只能生成当前项目的tag
  2. ctags --options=/home/archer/.cache/tags/\!home\!archer\!workspace\!android\!xxxx\!android\!.ctags ./ /home/archer/workspace/aosp/frameworks/base - 能生成当前项目的tag + aosp/frameworks/base(指定的外部项目)的tag

谢谢,这是我疏忽了,已经修复了,办法是又加了一个文件储存要扫描的文件列表,然后在 option file 中用 -L 选项读取。

:grinning: 感谢,新版本很好用。

好像新版本没有再将 tags 放在 .ctags.d 目录下了,这是为啥呀?

考虑到用户「把 tags 文件放在特别的地方」一般是为了避免污染工程目录,现在就留了三种方式:

  • 工程目录下 .ctags.d 目录放 option file,tags.tags 是 tags 文件。这个做法好处是生成以后你可以直接在工程目录下运行 $ ctags 来更新。

  • 所有相关的文件全都放到 ~/.cache/tags/

  • 有其他特殊需求,手动生成 tags 文件,再把 citre-tags-file 作为 directory-local variable 来修改(用户手册有例子)。

我一直都是 lsp 和 citre 同时使用,然后各用各个的😂 tags强在跨语言的补全能力,同时还不需要本地工具链即可使用。两套系统一起使用这么久了也没觉得有什么问题,挺舒服的。即便现在 citre-peek 能配合 lsp 来用,感觉也没有什么配置的动力😂

其实不需要配置的,M-x eglot 以后 eglot 后端就可用了,跳转不了的时候 tags 和 global 会作为 fallback。eglot 后端的主要意义是让 lsp 能用上 citre-jumpcitre-peek

citre0.4 我在没有开启eglot时,总会提示错误:error in process sentinel: Selecting deleted buffer 开启eglot以后错误就消失了。这是不是需要有啥配置可以忽略eglot?感觉是citre默认在读取eglot的buffer?

我一般也不开 eglot,没碰见这个错误。可否提供复现步骤或者 backtrace?

有一个问题哈,citre 中我使用 tags 作为 backends,company-mode 中我的 backends 是(company-capf company-keywords company-dabbrev company-files),但是开启补全时(C++),我写 uint32_ 这种它似乎也会去 tags 中搜寻,然后会特别卡。

另一个 readtags 的疑惑就是,每一次 peek 或者 complete 操作,都回去 tags 整个文件中做 binary search 吗?我有这个疑问是因为我的 tags 文件很大(6GiB),我怕太频繁的查询会消耗硬盘过度

我写 uint32_ 这种它似乎也会去 tags 中搜寻,然后会特别卡。

它肯定是会去搜寻的。tags 后端不分析语法的,写任何一个单词都会尝试补全。

要说卡的话倒不一定,您可以检查一下 citre-capf-optimize-for-popup 是否为 t,如果是的话,在 readtags 找补全的时候用户输入可以打断它,这样就不会卡,我在内核里面实测也不会卡。但这个我也不敢保证,因为进程相关的东西好像在不同机器上表现不一样,这块一直有用户报告一些我怎么也复现不了的问题。

每一次 peek 或者 complete 操作,都回去 tags 整个文件中做 binary search 吗?

会的。

我的 tags 文件很大(6GiB),我怕太频繁的查询会消耗硬盘过度

如果找定义的话,正因为使用了 binary search,搜索大小 tags 文件的代价不会差别很大;补全的话可能会有些影响,因为大 tags 文件里同一前缀的符号可能更多。

其实我个人更建议的方案是弹出式补全只用 dabbrev 这类的后端,需要补全其他的符号时用 completion-at-point(默认快捷键是 C-M-i)。这样用起来干扰比较少,什么时候读 tags 文件也可控。

2 个赞

奥我懂了,关键点是补全的形式选择,即 popup 还是 manually trigger,这个我倒是没考虑。之前一直用 Clion,它是 popup 形式,里面内容感觉是精心准备筛选过的的(感觉很准确)。

另外一个问题是,你提到“弹出式补全只用 dabbrev 这类的后端”,那 company 插件是如何判断弹出式补全使用那些 backends 呢?(假如我配置了 company-capf company-keywords company-dabbrev company-files

以及一个衍生问题,citre 如果使用 tags 补全,它是如何和 company mode 配合的呢? 是 company 问 company-capf backend 获取补全列表,而后者通过 capf 机制调用completion-at-point-functions 吗(其中 citre 去修改 completion-at-point-functions 变量?)

那 company 插件是如何判断弹出式补全使用那些 backends 呢

company 会逐个尝试 company-backends 里面的后端。

是 company 问 company-capf backend 获取补全列表,而后者通过 capf 机制调用completion-at-point-functions 吗(其中 citre 去修改 completion-at-point-functions 变量?)

就是这样的。

1 个赞