如果我都设为 emacs.git, 在 src/1.c 运行更新 tags 文件命令的时候, 会报
Can't find tags file for this buffer. Create one? (y or n)
如果我都设为 emacs.git, 在 src/1.c 运行更新 tags 文件命令的时候, 会报
Can't find tags file for this buffer. Create one? (y or n)
怎会如此 我回去也看下吧
windows原生emacs当代码中文路径时,会提示这个,是不是要改一下编码变量。 英文路径就没有这个问题。
citre-core--get-lines: readtags exits 1
d:\DevTools\ctags\readtags.exe: cannot open tag file: Invalid argument: d:/Hello/管理系 ?Codes/ReactApp/.tags/.!.tags
你试试?我不熟悉 Windows
对了,我是用 ~/.cache/tags
有些中文字符的coding-system都不知要啥编码,所以算了,自己写个函数生成tag其实也行。
那之后也没法用啊 读 tags 文件用的也是 readtags
现在只能将代码放在没有中文路径的地方。英文路径下就没发现有啥问题。 windows下那个code-system的编码,我也不是很懂。
我使用下面的代码测试了一下
(defun citre-core-write-pseudo-tag (tagsfile name value comment)
"Write a pseudo tag to TAGSFILE.
TAGSFILE is the absolute path of the tags file. NAME is the name
of the pseudo tags, without the beginning \"!_\". VALUE is its
value, and COMMENT is its comment info.
When there's already a pseudo tag with the same name, COMMENT
will not overwrite the original comment."
(setq comment (concat "/" comment "/;\""))
(with-temp-file tagsfile
(insert-file-contents tagsfile)
;; Jump over all pseudo tags.
(while (eq (char-after) ?!)
(forward-line))
;; Record the point position, and don't search beyond it later.
(let ((end (point)))
(goto-char 0)
(if (search-forward (concat "!_" name) end 'noerror)
(progn
(dotimes (_ 2)
(search-forward "\t"))
(setq comment (buffer-substring (point) (line-end-position)))
(delete-region (line-beginning-position) (line-end-position))
(unless (eobp)
;; Delete the newline character.
(delete-char 1)))
(goto-char 0))
(insert "!_" name "\t" value "\t" comment "\n")
(write-region (point-min) (point-max) (format "%s%s" tagsfile (random 10)) nil :silent)
)))
得到三个文件
-rw-r--r-- 1 feng feng 11308748 7月 15 16:57 !home!feng!emacs!emacs.git!src!.tags
-rw-r--r-- 1 feng feng 11308748 7月 15 16:57 !home!feng!emacs!emacs.git!src!.tags3
-rw-r--r-- 1 feng feng 204 7月 15 16:57 !home!feng!emacs!emacs.git!src!.tags4
!_CITRE_CMD ctags|-o|%TAGSFILE%|--languages=C|--kinds-all=*|--fields=*|--extras=*|-R /command line to generate this tags file/;"
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/;" extras:pseudo
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/;" extras:pseudo
!_TAG_OUTPUT_FILESEP slash /slash or backslash/;" extras:pseudo
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/;" extras:pseudo
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/;" extras:pseudo
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //;" extras:pseudo
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/;" extras:pseudo
!_TAG_PROGRAM_URL https://ctags.io/ /official site/;" extras:pseudo
!_TAG_PROGRAM_VERSION 0.0.0 //;" extras:pseudo
../lwlib/lwlib.h menu.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:36 language:C roles:local extras:reference
../lwlib/lwlib.h term.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:54 language:C roles:local extras:reference
../lwlib/lwlib.h widget.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:43 language:C roles:local extras:reference
../lwlib/lwlib.h xfns.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:85 language:C roles:local extras:reference
../lwlib/lwlib.h xmenu.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:87 language:C roles:local extras:reference
../lwlib/xlwmenu.h xfns.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:97 language:C roles:local extras:reference
../lwlib/xlwmenu.h xmenu.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:79 language:C roles:local extras:reference
../lwlib/xlwmenu.h xterm.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:93 language:C roles:local extras:reference
../oldXMenu/XMenu.h xmenu.c /^#include "..\/oldXMenu\/XMenu.h"/;" kind:header line:91 language:C roles:local extras:reference
A gmalloc.c /^#define BLOCK(A) ((size_t) ((char *) (A) - _heapbase) \/ BLOCKSIZE + 1)$/;" kind:macroparam line:165 language:C scope:macro:BLOCK roles:def
A image.c /^#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))$/;" kind:macroparam line:5650 language:C scope:macro:COLOR roles:def
A intervals.c /^rotate_left (INTERVAL A)$/;" kind:parameter line:323 language:C scope:function:rotate_left typeref:typename:INTERVAL file: roles:def extras:fileScope
A intervals.c /^rotate_right (INTERVAL A)$/;" kind:parameter line:272 language:C scope:function:rotate_right typeref:typename:INTER
...
!_CITRE_CMD ctags|-o|%TAGSFILE%|--languages=C|--kinds-all=*|--fields=*|--extras=*|-R /command line to generate this tags file/;"
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/;" extras:pseudo
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/;" extras:pseudo
!_TAG_OUTPUT_FILESEP slash /slash or backslash/;" extras:pseudo
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/;" extras:pseudo
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/;" extras:pseudo
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //;" extras:pseudo
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/;" extras:pseudo
!_TAG_PROGRAM_URL https://ctags.io/ /official site/;" extras:pseudo
!_TAG_PROGRAM_VERSION 0.0.0 //;" extras:pseudo
../lwlib/lwlib.h menu.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:36 language:C roles:local extras:reference
../lwlib/lwlib.h term.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:54 language:C roles:local extras:reference
../lwlib/lwlib.h widget.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:43 language:C roles:local extras:reference
../lwlib/lwlib.h xfns.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:85 language:C roles:local extras:reference
../lwlib/lwlib.h xmenu.c /^#include "..\/lwlib\/lwlib.h"/;" kind:header line:87 language:C roles:local extras:reference
../lwlib/xlwmenu.h xfns.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:97 language:C roles:local extras:reference
../lwlib/xlwmenu.h xmenu.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:79 language:C roles:local extras:reference
../lwlib/xlwmenu.h xterm.c /^#include "..\/lwlib\/xlwmenu.h"/;" kind:header line:93 language:C roles:local extras:reference
../oldXMenu/XMenu.h xmenu.c /^#include "..\/oldXMenu\/XMenu.h"/;" kind:header line:91 language:C roles:local extras:reference
A gmalloc.c /^#define BLOCK(A) ((size_t) ((char *) (A) - _heapbase) \/ BLOCKSIZE + 1)$/;" kind:macroparam line:165 language:C scope:macro:BLOCK roles:def
A image.c /^#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))$/;" kind:macroparam line:5650 language:C scope:macro:COLOR roles:def
A intervals.c /^rotate_left (INTERVAL A)$/;" kind:parameter line:323 language:C scope:function:rotate_left typeref:typename:INTERVAL file: roles:def extras:fileScope
A intervals.c /^rotate_right (INTERVAL A)$/;" kind:parameter line:272 language:C scope:function:rotate_right typeref:typename:INTERVAL file: roles:def extras:fileScope
ABI_VERSION comp.c /^#define ABI_VERSION /;" kind:macro line:432 language:C file: roles:def extras:fileScope end:43
...
!_TAG_PROC_CWD /home/feng/emacs/emacs.git/src/ /dir in which ctags runs/;"
!_CITRE_CMD ctags|-o|%TAGSFILE%|--languages=C|--kinds-all=*|--fields=*|--extras=*|-R /command line to generate this tags file/;"
创建完 tags 文件再升级时,提示找不到 recipe 的问题,已在 master 分支修复。
原因很蠢 就是我写代码的时候考虑 CITRE_CMD
是 Citre 自己加的,TAG_PROC_CWD
是 Ctags 会写的,所以创建完 tags 文件以后就只写了 CITRE_CMD
,忘记了部分 ctags 程序并不会写 TAG_PROC_CWD
。
另外这个「指定在某目录中使用某 tags 文件,结果在其子目录中找不到」,我这里复现不了。如果你继续碰到这个问题,希望能提供 Citre 的配置,以及生成 tags 文件时的具体操作。
我只能说 666
赞美楼主!!
总算可以快乐地编MATLAB了,之前真小破车一直将就着(啥没有,就Emacs原生功能撑着),撒花~~
两个问题都消失了,可能本身就是一个问题,另外我提交了一个小 pr,更新了一下 prompt,个人感觉更漂亮一点
Citre save tags file.
[1] Save to a directory specified.
[2] Save to global cache directory.
[3] Save to project cache directory.
[4] Save to a file specified (modify `citre-tags-file-alist' is required).
==> Please type a number (1-4) to choose:
我个人现在超喜欢目前的交互状态,不多不少,完美!
我目前工作流程是:对没tagging过的项目,建个空的.tags文件,关掉 -> 运行更新tags命令(第一次会提示写ctags recipe)。搞定,快乐地使用~
个人不是很喜欢lsp那种minibuffer里 prompt满天飞,有种windows式的笨拙感。
这个recipe的设计,简单大方又自由度极大;如需要每个子文件夹都可以来个.tags,完美避免上百M tags文件parsing速度慢的问题(linux kernel 2.6的源文件,如用同一个tags文件,跳转没问题,但用imenu很慢,得有个几秒)
拯救了Emacs下编辑matlab重度用户啊。无跳转好些年了,一直靠Ivy + ag/rg这类搜索方式撑着。
如果补全库函数的功能加强就完美了
这一步应该也不需要。你可以直接 citre-create-tags-file
,会有个向导帮你创建,或者 citre-update-this-tags-file
,在找不到 tags 文件的情况下也会问你要不要创建。
个人喜欢 ctags 的主要原因还是 hackable 我也觉得 lsp-mode 有点太打扰用户了。
这个是因为 tags 文件是按 tag 名字的字母顺序排序的,在已知名字(跳转到定义的情况)或名字的开头一部分(补全的情况)时,可以做二分搜索。imenu 的话是不知道名字但知道路径,所以只能把所有 tags 全过一遍。
我之前见过一种做法是运行 imenu 的时候,直接 tag 一下当前文件,在临时路径里生成一个 tags 文件。感觉对大工程来说这样反而快一点。
目前的话你可以在 tags 文件的 recipe 里面增加扫描的路径,把外部库一起扫描了。不知你觉得这样好不好?
将来的话还是打算做一个交互式过滤 tags 文件的工具,这样可以按条件从某个 tags 文件中过滤出所需的符号然后插入当前 buffer。
我个人其实对补全也不是很依赖。我觉得补全主要就是告诉用户「你拼写对了」这么个作用,Emacs 的 dabbrev 也很可以了。
我自己的经验是,真正感觉需要「补全」的时候,其实是已经忘记了那个符号怎么拼,但我知道「它在哪个库里面,或者路径里有哪个单词,然后符号里面有一个什么单词,然后它是个函数/变量/类」之类的信息。这种时候补全没有用,substring 补全还算有点用(就是你可以敲那个符号的一部分来补全,不一定要敲开头。Citre 支持,见文档),真正有用的就是交互式过滤。
话说设计的时候我就考虑到这种情况(虽然我自己完全没想出什么使用场景),然后设计了能给不同文件夹用不同 tags 文件的机制,没想到真的有人这么用
谢谢指导!还在学习使用中,不过目前体感已经很赞了~
这个似乎不错啊,因为imenu也就需要个当前的文件的临时tags文件;单体文件都不会大,所以这个方法完全可行。这个想法很赞!
个人感觉哈,纯探讨。毕竟citre是个tagging系统,跳转、列表才是主业。补全只提供个大概(自己代码的)感觉就可以了。更复杂的需求还是尽量交给lsp这类的,要不然太臃肿了,而且也会变慢。我记得针对C/C++有过一个rtags的东东,配出来也没咋用过,太臃肿了(接管大多lsp的活,那时还没lsp),最后导致使用兴趣缺缺。
其实我就是想有的时候看下第三方库的源码,可能和语言有关系,我现在用 go 可以很方便跳进源码,因为本地就有存。
Anyway, 我就是随口一说, ctags 目前我觉得已经挺完美的了
这个的问题是需要预设一个 ctags 命令,那肯定是要写一个对大多数情况适用的 universal ctags 命令(目前我是打算这么做)。这样用户对这个工程调整过的参数就不能反映了,或者如果使用 hasktags 之类其他的 ctags 程序也就不能用了。
我本来想到现在 tags 文件自带 recipe 了,可以直接从里面读命令,但是仔细想一下,被扫描的路径也是写在命令里面的,而且没有可靠的办法把它们分离出来(特别是使用其它 ctags 程序的情况),所以还是没用了。