Citre: 先进的 Ctags 前端

我没什么特殊配制,感觉默认配置就很舒服

(use-package citre
  :defer t
  :init
  (require 'citre-config)
  :config
  (defun prog-mode-citre-bindings()
    (local-set-key (kbd "C-M-]") 'citre-jump)
    (local-set-key (kbd "C-M-t") 'citre-jump-back)
    (local-set-key (kbd "C-M-p") 'citre-peek)
    (local-set-key (kbd "C-M-i") 'custom-citre-completion-at-point)
    )
  (add-hook 'verilog-mode-hook 'prog-mode-citre-bindings)
  (add-hook 'c-mode-hook 'prog-mode-citre-bindings)

  )

哇,遇到使用 verilog-mode的同仁,能分享个配置地址给抄抄么?

verilog 或者 vhdl 用户是不是用 ctags 挺多的啊,前几天看到 reddit 上一个 Citre 用户也是用 verilog 的(

反正我用的挺舒服的 :grinning:,也不需要复杂的成员变量补全,感觉lsp啥的也用不上

1 个赞

前几天说自己解决了 Windows 上卡顿的问题,结果被 @Kermit95bug 报告 啪啪打脸 :rofl:

这次仔细研究了 Emacs 的 keyboard quit 机制,把等待进程的部分整个重写了,从原理上保证了计算补全时 Emacs 的响应性。

经过我和 @Kermit95 在 Windows 和 Linux 上反复测试,在大工程里用 Citre + company,打字终于像水一样顺滑了 :wink:

9 个赞

感谢 这个会自己弹出补全吗?我打一半好像不会自己补全

弹出补全需要用专门的插件做界面,目前比较流行的是 company。需要确保 company-capfcompany-backends 列表里面(最好是前面,以免被其它后端拦截)

Edit: 我不用 doom,看起来它默认 company-backends 就只有 company-capf 一个,但是在启用语言的 major mode 时会覆盖掉。比方说按它设计,补全 ruby 要求你装 robe,如果没有的话自然就不行了。

看文档:

如果你打算编程的时候就用 Citre 的话,我猜可以直接这样:

(after! prog-mode
  (set-company-backend! 'prog-mode '(company-capf)))

那个人就是我哈哈哈哈哈哈哈哈哈哈

emmmmm我是可以直接自动补全的,我主要写c和verilog,不清楚你是什么语言

无233333我就用的默认(

:rofl: 绝了

刚添加了生成 tags 文件的功能: GitHub - universal-ctags/citre: Ctags IDE on the True Editor

反复设计之后,还是感觉怎么组织和利用 tags 文件这个问题有太多种可能,如果贪多求全的话可能反而做不好这个工具,因此目前就做了最简单省心的:

  • 随便打开一个工程里的文件或者目录。

  • M-x citre-update-tags-file,如果在缓存文件夹里没找到 tags 文件,Citre 会引导你创建一个。

  • 接下来你要选择工程根目录(也是 ctags 扫描的目录),要扫描的语言,缓存目录。

  • Citre 会在缓存目录下创建这样一个文件:

    工程的最后一层目录名(为了方便看)-工程目录的 md5-扫描的语言.tags
    

    不需要储存其他信息或者写任何文件。

  • 更新 tags 文件的时候,再次运行 citre-update-tags,Citre 会直接从 tags 的文件名里面读语言,从 tags 文件里面读工程根目录,然后装配命令参数进行更新。

列表 citre-tags-file-cache-dirs 里的目录都可以作为缓存文件夹用。允许相对路径,用的时候会按 citre-project-root-function 探测到的工程目录展开,因此也可以把缓存文件夹放到工程里面。

tags 文件生成是异步的,而且可以在 TRAMP 上用,只要远程机器有安装 Universal Ctags 就可以。

如果有更复杂的需求,我目前打算是交给用户,然后在手册里写一下怎么包装一个自己的命令来方便更新。

希望大家多多试用,多给反馈!

6 个赞

用 transient.el 写一个 ctags 菜单不知道效果怎么样?

写一个 UI 帮用户装配命令行倒不是难事,难的是 tags 文件需要反复生成。遂,这个命令行要保存到哪?

如果用户想在一个工程的不同部分用不同的 tags 文件(Citre 是可以做到的,见 citre-tags-file-alist),是不是还要提供分别更新的功能呢?

如果用户不用 uctags,而是 hasktags、gotags 怎么办呢?

我在设计的时候考虑到的小问题还要更多。每一个其实都不难解决,可是都解决掉的话,连我自己都不想用这个工具了。

所以最后做成了现在这样极简的样子。

我认为生成 tags 文件应该是构建系统干的事。Citre 提供的东西可以开箱即用,能覆盖 80% 的场景就可以了。

3 个赞

好的 感谢正在努力尝试中

另外,用 “~/.cache/emacs-citre/” 作为默认 cache 目录,是不是更直观一点?

这个自己改就好啦

不过关于你说的这个,其实 Universal Ctags 有计划把命令行参数也写到 tags 文件里,这样可以保证增量更新时参数一致。如果这个做出来了,Citre 就不需要设计别的工具了,像你说的这样把命令行装配出来,然后只管第一次生成就行。

Edit: 我发现其实可以直接让 Citre 往 tags 文件里注入 pseudo tags,这样就不用等 uctags 帮我们实现了:Request: pseudo tags to record command line arguments · Issue #3085 · universal-ctags/ctags · GitHub

Ctags 有辦法做到 fuzzy search 嗎? 像是 lsp workspace symbol 可以列出所有symbol 在用 completion engine (helm, ivy) 補全

citre-jump 目前需要 cursor 在 symbol上 有時想找某個 symbol 但不知他在哪個 file or 哪個file 引用他

在空白处用一下 xref-find-definitions 应该就可以。

你说的这个需求很有价值,我觉得 xref 的界面还是过于简陋。一直想做一个交互式过滤 tags 文件的工具,参见 Citre: 先进的 Ctags 前端 - #24,来自 kinono

目前对于怎么实现还是没有太好的想法。初步计划是这样:

  • 先给 citre-peek 增加一个过滤工具,当找出太多定义以后可以用这个来排除掉一部分。初步探索一下这种 UI 应该怎么设计。
  • 做一个模糊补全工具,像上面说的这样可以交互式过滤,可能基于 consult 或 completing-read(当然不依赖外部库是最好的)。
  • 把这个补全工具拓展一下,使得过滤出来的结果可以插入到当前 buffer(补全),可以跳转过去,也可以转换成一个 citre-peek 或 xref 会话。

这就是我设想中 Citre 的终极形态,可以最大限度地利用 tags 记录的信息和 readtags 提供的过滤功能。

1 个赞