citre-peek
的思路也很赞 ,或许我可以尝试结合 reference tags 和 citre-peek
做出一个类似 calltree.pl 的界面出来。
Go for it
如果您需要帮助,请 email 我。我的 email 在 Citre 的代码里。
有种商业软件客服的聊天感觉
Citre 为您提供优质的支持与服务
看起来很不错的样子,性能不高或者不方便用lsp的场景很适合
有时候在多语言的工程中,希望从一个语言直接跳到另一个语言的定义(包括从文档跳到代码中的定义),这个事也只有 Ctags 可以做到。
我在这份文档中比较了 Ctags 与现在的智能工具的优缺点,Ctags 其实是有一些不能忽视的优点的。
我想确认下您说的 TAGS 是指 Emacs 自带的那个 etags 生成的,还是 Ctags 生成的那个 tags 文件?
另外看到 Centaur Emacs 有 paypal 的捐赠链接,想问下您有提现过吗 如果有的话,是怎么操作的呢?
我用的新编译的universal-ctags,但是遇到这个错误:
Error in menu-bar-update-hook (imenu-update-menubar): (error "readtags exits 1
ctags: Unknown option: -t")
我也编译了一下最新的 uctags,但不能复现。我怀疑你用的 readtags 程序可能不是 uctags 自带的。
试一下 $ readtags -h
看看有没有这么个 option:
-t TAGFILE | --tag-file TAGFILE
Use specified tag file (default: "tags").
Edit: 我刚想到一种可能性,你是不是把 citre-readtags-program
改成了 ctags
的路径?
感谢大神,ctags我经常用,也知道 Ctags 可以用正则或者 optscript 实现用户自定义 tag 规则
,但实际这么做时又搞不定,想请教一个这方面的问题,比如我写了以下代码:
return array(
"test_func"=>function(string $str="test_func"){
return $str;
}
);
这是一段php代码,返回一个数组其中定义了一个函数,将其保存为org.php
文件,然后调用这个函数时我是这么写的:
$org=require("./org.php");
echo $org["test_func"]("hello");
这种写法在php里应该比较少见,但在其它语言有近似用法的不少(比如nodejs的require等 )
我用universal-ctags生成的tags文件并不识别这种写法,不能在函数调用处$org["test_func"]()
跳转到函数定义,想通过自定义tag规则来支持这种写法,但正则水平不行,没搞定,只好来请教擅长ctags的高手们
对,确实是这个原因,我设置为nil就正常了。
$ cat options.ctags
--langdef=PHPext{base=PHP}
--kinddef-PHPext=a,arrayfunc,function defined in arrays
--regex-PHPext=/"(.*)"=>function/\1/a/
$ cat test.php
return array(
"test_func"=>function(string $str="test_func"){
return $str;
}
);
$ ctags --options=./options.ctags --fields='*' -f - test.php
test_func test.php /^ "test_func"=>function(string $str="test_func"){$/;" kind:arrayfunc line:2 language:PHPext roles:def extras:subparser
您可以把 options.ctags
存在 ~/.ctags.d/
或运行 ctags 时目录的 ./.ctags.d/
文件夹下,ctags 运行时就会自动加载它。
解析:
-
--langdef=PHPext{base=PHP}
定义一个叫
PHPext
的新语言(取 PHP extended 之意),作为 PHP 的 subparser 使用。扩展一个 parser 时,定义一种新语言是被鼓励的,这样就不会和语言本身的 kind 冲突。如果运行一下
$ ctags --list-kinds=php
,可以看到已经有一个简写为a
的 kind,表示aliases
。 -
--kinddef-PHPext=a,arrayfunc,function defined in arrays
为 PHPext 定义一个简写为
a
,全名为arrayfunc
的 kind,含义是function defined in arrays
。 -
--regex-PHPext=/"(.*)"=>function/\1/a/
这一行的语法是
--regex-<LANG>=<PATTERN>/<NAME>/[<KIND>/]LONGFLAGS
。我们一段一段看:-
"(.*)"=>function
用于匹配的模式。加括号的地方是这个函数的名字。
-
\1
把加括号的模式匹配到的部分拿出来作为 tag 的名字。
-
a
规定这个 tag 的 kind 为刚刚定义的
a
。
-
请参阅 Extending ctags with Regex parser (optlib)
如果还有问题,欢迎随时讨论,这样我可以多点例子来证明 ctags is hackable
大多数 ctags 用户都不知道 readtags 的存在,所以我想有这样的误操作也正常。我想一下怎么在 README 里强调一下这个事情。
readtags 是很有意思的程序,它自带了一个类 Scheme 的 DSL,用来指定对 tags 进行过滤和排序的规则。Citre 大量地使用了这个东西。
我平常是直接用 ctags -e
输出 etags 形式的文件,然后 Emacs 自带的 etags.el 就可以自动识别了,并且 xref 也是直接支持的,补全的话也有 company-etags
。
那么 citre 除了 citre-peek
外的优势在哪里呢?
说一些我现在能想到的。
最重要的是,TAGS 格式本身信息不是很丰富,基本上就只有名字和位置信息。tags 格式更加丰富一些,你看我的截图里那些符号都标明了种类(也就是说一个符号是 macro、function 还是别的什么)和类型。
基于这些信息,Citre 可以实现更准确的过滤和排序。一个很实用的东西是对非全局的符号,ctags 会标明它的 scope
是 file
。Citre 在找定义或补全时会排除具有 file scope,且不在当前文件中的符号。这样可以排除大量不需要的结果。
另外,注意到我自动补全的截图中,由于当前符号在一个 .
的后面,Citre 推测你需要一个结构体成员,因此补全出来的结果中 member
种类是放在其他结果前面的。虽然基于 ctags 的工具做不到 lsp 那么智能,但我们可以提供类似这样的贴心小规则。利用 TAGS 文件是不可能做到这一点的。
总而言之,更丰富的信息可以帮我们更好地理解代码。试想我们要做这样一件事情:我需要某个库里面的一个函数,我不知道它叫什么,但它的功能是插值,所以里面应该有 interpolate
之类的单词。。。我们可以把这些条件扔给 readtags,让它帮我们找我们想要的东西。或许在将来 Citre 会提供一个交互式工具让你做这件事情,而利用 TAGS 文件的话是绝无可能的。
另外,TAGS 格式是按照文件和行号顺序排序的,而 tags 是按照名字的字母顺序排序的,因此 readtags 可以做二分搜索,使得在大工程中补全和找定义也相当快。company-etags
应该做不到这一点。
Edit: 还有一点是 TAGS 文件一般是整个加载到一个 buffer 里使用的,对巨型工程来说不现实。Citre 不需要做这样的事情。
我试用了一下,就算在 LLVM 这种大项目下速度也还是非常快。LZ 不考虑给 Emacs 28 贡献一下嘛,例如把这个功能实现成一个 ctags.el,这样就能把以前 Emacs 自带的那个 etags 给废弃了。
感觉回复,这个问题解决了
还没试用。
既然支持编辑相关的功能(自动补全),那是不是考虑支持自动更新tags文件?大概看了下代码,没发现有这功能。
祝你用得开心
关于进 Emacs 这件事,其实我也考虑过。我想做的是把 citre-core.el
分离出来,作为一个 readtags 抽象层并入 Emacs(masatake 也和我说过这个想法)。这样别人也可以基于这个东西开发各种各样的工具。但 readtags 并不是像 grep 那样流行的程序,我想 Emacs 很可能不会想要这个东西。
而且 Citre 要求使用 Universal Ctags 的 readtags。Exuberant Ctags 其实也带一个 readtags,但缺少利用类 Scheme 表达式进行过滤和排序的关键特性。考虑到仍然有很多人使用 Exuberant Ctags,如果我被要求支持这个 readtags 的话,很多事情就没法做了。
其他的做法,像是做一个利用 Emacs 自带功能读 tags 文件的东西,或者做一个 xref 的 ctags 后端,我觉得意义不大,不如直接用 Citre。