Citre: 先进的 Ctags 前端

我今天写了个补丁,已经从我自己的 Nox 切换到 Citre 来了,Python补全非常爽,比LSP那些后端好用多了,有几点反馈意见:

  1. Tags能否自动生成,比如project-root变化的时候,检测一下tags文件,没有就子进程新建tags
  2. Tags的语言可以根据 project-root下的文件类型自动添加,不用手动设置language
  3. Python的 Class 属性好像没有全部补全,有些属性可以有些不行,倒是 Class 的函数名补全的很Nice
  4. citre-peek 按了就会弹出一个类似 frame 的东西, citre-peek 怎么玩啊?没有搞懂

citre-jump 配合 selectrum 倒是非常舒服。

6 个赞

LSP/elgot/Nox 这种LSP后端的对库的补全比较好,比如Python的 os 库,可以补全 os.path.exists 这样的函数

citre 这种基于Tag的对当前项目已经Index的补全支持很好,也就是自己写的代码补全比较好(这方面LSP反而没法补全)

继续体验,citre确实很快很好用, 我个人倾向于用 citre,不用折腾那么多后端,如果配合自动生成tags的功能,其实大多数语言反而更好用。

1 个赞

谢谢,有牛逼的黑客喜欢我的工具是最开心的事 :wink:

这么做的话可能管得有点宽了,比方说用户可能不希望每一个工程都用 ctags。我正在实现一个生成 tags 的向导,生成一次之后用一个命令就可以更新:misctools, feat: generate and update tags file by AmaiKinono · Pull Request #62 · universal-ctags/citre · GitHub

这个可能也比较难。首先很多工程下面有 Makefile,但我们不一定需要 tag 它;另外就是子目录下的文件要不要搜索的问题。我在向导里面实现了一个手动添加语言的功能。

这个最有可能的是 ctags 没有 tag 部分属性,可以看一下 tags file 里面有没有。如果确实没有的话可以给 Ctags 报 bug。

citre-peek 其实超简单 :wink: 建议看一下这个文档,每一步都跟着操作一下,一会就搞懂了。

我在文档上还是花了很多精力的,建议从 README 开始都读一下,一定会有收获。

1 个赞

这方面我也有一些想法,但可能不是用自动补全的形式来实现。参见这一楼我的回复:

感谢大佬,体验非常滴好 :+1: 。目前我是 lsp 和 citre 一起用,有些地方 lsp 没法补全的时候(比如 java 里写 sql 的 query)可以用 citre 补,还可以用 citre-peek 边查看类、函数的信息边码代码。感觉好久没有碰上这么爽的插件了,哈哈。

3 个赞

希望你能一直用 Citre 一直开心 :wink:

可以告诉我这个功能大概是怎么配的吗?

像 golang 这种可以 --exclude $GOPATH/pkg/mod/… 来把第三方库的代码加到 tag 中,我试了一下 ok, 但是 python 这种我就不熟悉了。

这不对吧,你给的这个命令应该是排除这个目录才对。

我考虑到了添加第三方库的需求,在生成 tag 的向导中会允许选择多个要扫描的目录,包括当前工程外面的。

Edit: 其实我和 Masatake 讨论过让 Ctags 自己找到依赖的那些模块的路径,但是现在找不到那个 issue 了。感觉短期也不太可能有。

另外,如果有很大的依赖库被 tag 了,那么增量更新就更重要了。

Edit2: 我刚又看了一遍才理解你和懒猫的意思。你们意思是 ctags 只扫当前工程目录,所以没有外部库的符号。但我说的意思一直是「在 tag 了那些库的符号的情况下,怎么把它们挖掘出来」。

1 个赞

@manateelazycat @rua 关于你们说到的扫描库的问题,我想提供一些信息。

Ctags 其实有 reference tags,但是目前关注的并不是函数、类等等的引用,而是模块的引用。比如在 Julia 的一个文件中如果有

using Module1

Ctags 会生成这样的 tags:

Module1	input.jl	/^using Module1$/;"	kind:module	roles:used

目前就我所知,Ctags 对大多数语言都实现了这种模块引用的 tag,其目的就是在扫描完一份代码之后,知道它使用了哪些模块。如果能再配合模块名 <-> 路径名的转换规则,就可以做到把库也一起扫描了。

(Citre 也稍微利用了一下这种 tag。如果你在 dired 里面,对头文件找定义的话(比如用 citre-peek),会把所有用到这个头文件的地方找出来。)

我现在仍然不好说这个功能什么时候会有,但 Masatake 确实一直很注重模块的 reference tags,所以还是很有希望的。

4 个赞

难过了,平时写的语言都不支持。。。。。

:rofl: 我的天,你平时都写些什么

最近是 Clojure 和 Elixir…

  ada        .ads .adb .ada
  asm        .a .asm .def .inc .ins .s .sa .S .src
  c          .c .h
  c++        .C .c++ .cc .cpp .cxx .H .h++ .hh .hpp .hxx .M .pdb
  c*         .cs .hs
  cobol      .COB .cob
  erlang     .erl .hrl
  forth      .fth .tok
  fortran    .F .f .f90 .for
  go         .go
  html       .htm .html .shtml
  java       .java
  lisp       .cl .clisp .el .l .lisp .LSP .lsp .ml
  lua        .lua .LUA
  makefile   Makefile makefile GNUMakefile Makefile.in Makefile.am
  objc       .lm .m
  pascal     .p .pas
  perl       .pl .pm
  php        .php .php3 .php4
  postscript .ps .psw
  proc       .pc
  prolog     .prolog
  python     .py
  ruby       Rakefile Thorfile .rb .ru .rbw
  scheme     .oak .sch .scheme .SCM .scm .SM .sm .ss .t
  tex        .bib .clo .cls .ltx .sty .TeX .tex
  texinfo    .texi .texinfo .txi
  yacc       .y .y++ .ym .yxx .yy

我这里显示是支持这些语言。

你这个估计不是 Universal Ctags。我手机上的 uctags 都支持 clojure 和 elixir :rofl:

$ ctags --list-languages | grep -E "(Clojure|Elixir)"
Clojure
Elixir

可以,我装个 universal ctags 试试。

ludovicchabant/vim-gutentags

这个vim插件自动生成tag的体验非常好,因为:

  1. 开箱即用,除了安装不用做任何事情.

  2. 可以指定tag文件的储存位置,日常使用的时候完全不用操心tag文件的管理(比如误入版本控制系统)

let g:gutentags_cache_dir = expand('~/.cache/tags')
  1. 它用了一些hack,来实时增量更新tag,让tag保持在最新状态的同时,性能也让人满意.
1. Incremental tags generation: don't re-generate the whole project all the time. This may be fine for small projects, but it doesn't scale.
2. External process management: if the ctags process is taking a long time, don't run another one because I saved a file again.
3. Keep the tag file consistent: don't just append the current file's tags to the tag file, otherwise you will still "see" tags for deleted or renamed classes and functions.
4. Automatically create the tag file: you open something from a freshly forked project, it should start indexing it automatically, just like in Sublime Text or Visual Studio or any other IDE.
1 个赞

Citre 主要不方便的地方是要手动生成 tags,现在我在做一个生成 tags 的向导,一旦生成过以后用一个命令就可以更新了。

我还是不打算帮用户把这些事全干了,因为稍微了解过 Ctags 就会知道,可以根据工程的需求来调整命令行参数,甚至定制 tag 生成规则(在大量用 macro 的工程里尤其有用)。我看目前大多数 Ctags 插件都用一个变量储存 ctags 命令,对所有工程都用这一个命令,这个我认为只是图省事的设计。我需要考虑到用户以后自己 tweak 命令参数的需要。

Citre 这方面做得比这个强。请读这个文档 About the name of the tags file 一节。

这个我现在还是不打算做,Universal Ctags 有可能要加这个功能。

关于 gutentags 我就想问一下:它更新出来的 tags 还是按字母顺序排序的吗?如果不是的话就没法做二分搜索了,在大工程里会没法用。

前两天我已经集成进 Centaur Emacs 了,多一个选择。univeral-tags其实从本质上讲和LSP干的事情差不多,但是由于没有JSON 解析之类的会轻量很多,但是也缺少一些功能。citre正好弥补了一些,希望能增加更多有效的小功能。加油!:+1:t2::+1:t2:

3 个赞

多谢你的工具,速度很快,也可以和lsp 配合同时使用,有一些场景lsp解析不出来,利用citre就很好work,反之亦然。

我现在遇到问题是,如在读取python 文件时,会提示“Error loading tags-file: (user-error File /home/test/TAGS is not a valid tags table)”, 但里面跳转等都正常,看起来没有问题,你知道这是什么原因么?

你的改动是不是不可以lsp与citre 同时开?另外,似乎快捷键里面少了 citre-peek,这个作者主要推荐的一个功能~

这和 Citre 无关。

TAGS 和 tags 是两个东西。TAGS 是 etags $ ctags -e 默认生成的文件名;tags 是 ctags 默认生成的文件名。二者具有不同的格式,Citre 只支持后者。

如果你没有乱动某些变量,Citre 根本不会去读 TAGS 文件。所以这肯定是其他插件的报错。

考虑到 Emacs 玩家一般不熟 Ctags,而且最近碰到不少人都有这个误解,我会在文档里仔细说明一下这个事。