- 开发工具
- CLI
【免费下载链接】ctags
A maintained ctags implementation
导读
本文基于 Universal Ctags 仓库的 docs/README.md 文档,系统讲解这套 ctags 实现(Universal Ctags)的文档组织方式、reStructuredText(reST)写作规范,以及 man 手册页与开发者文档(Sphinx HTML)的自动生成流程。读完本文,你将掌握:哪些目录存放面向用户的 man 页源文件、哪些目录存放面向开发者的实验性文档;编写 reST 时应当遵守的标记、超链接与占位符约定;如何通过make一键生成 man 页与docs/man/下的 Sphinx 源文件;以及如何为新增的解析器添加一篇完整的 man 手册页。
一、文档体系概览:两条并行的文档生产线
Universal Ctags 的文档分为两个层次,分别面向不同的读者,也使用不同的工具链渲染:
- 面向用户的 man 手册页:源文件存放在
man/目录,以*.rst.in结尾(如 man/ctags.1.rst.in、man/ctags-optlib.7.rst.in、man/ctags-lang-asm.7.rst.in)。这些文件由Docutils(确切地说是rst2man)格式化为传统 man 手册页。 - 面向开发者的实验性文档:源文件存放在
docs/目录,以*.rst结尾(如 docs/optlib.rst、docs/optscript.rst、docs/testing-parser.rst)。这些文件由Sphinx Python Documentation Generator渲染为 HTML 在线文档。
docs/README.md对两者使用的 reST 方言做了明确界定:man 页只能使用 Docutils 文档中描述的基础 reST 语法;而docs/*.rst可以使用 Sphinx 扩展后的 reST 语法(例如跨文件的:ref:标签引用)。
从 docs/index.rst 可以看到整个docs/文档树的骨架:它以toctree汇总了building.rst、man-pages.rst、parsers.rst、option-file.rst、output-format.rst、optlib.rst、optscript.rst、testing-ctags.rst、testing-parser.rst、contributions.rst、releasing.rst等主题;其中 docs/man-pages.rst 又将docs/man/下生成的所有 man 页 reST 文件挂载进 toctree。Sphinx 构建的入口配置位于 docs/conf.py,它设置了project = 'Universal Ctags'、master_doc = 'index',并加载了docs/_ext/下的自定义扩展lexers(用于为 ctags 的输出格式提供代码高亮)。
二、reStructuredText 标记规则:让文档在 rst2man 与 rst2html 之间兼容
由于同一份*.rst.in源文件既要被rst2man处理成 man 页,又可能被rst2html/ Sphinx 处理成 HTML,标记的选择必须小心翼翼。docs/README.md给出了以下硬性约定,写作任何 ctags 文档时都应遵守:
1. 单选项、选项用法与文件路径:用两个反引号包裹。
例如选项--langdef=MyLang应写成 --langdef=MyLang。对于单个字符,则用单引号包裹,例如'-'(表示字符-)。
2. 多词选项与命令行示例:两个反引号外加双引号。
例如"-f file_name"应写成"-f file_name",ctags --help应写成"ctags --help"。
3. 引用文档中的章节:用双引号包裹。
例如引用 "Writing Documents" 一节时写作"Writing Documents"。
4. 新引入的概念词:用一个星号(强调)标记。
例如首次出现的概念词应写作*word*。
5. 选项参数占位符:一个星号加<>。
例如--kind-<LANG>选项中的参数<LANG>应写作*<LANG>*,这与 man/ctags-lang-asm.7.rst.in 中**@CTAGS_NAME_EXECUTABLE@** ... --language-force=Asm ...这类SYNOPSIS段的排版风格是一致的。
6. 反斜杠的表示:用双反引号包裹。
由于不同转换工具对转义的处理不一致,docs/README.md特别提醒:表示反斜杠时应写作 `` ``。当 rst 转换为 man 时,两个反斜杠会被合并成一个;而转换为 HTML 时,四个反斜杠才会合并成一个——直接依赖反斜杠转义很容易在不同输出格式下失效。
这些规则看似琐碎,实际是保证"同一源文件、多种输出格式"这一设计能成立的关键。对照 man/GNUmakefile.am 可以看出,man 页源文件*.rst.in会经过sed变量替换生成*.rst,再被rst2man或rst2html消费,因此源文件里任何对输出工具有歧义的记号都会成倍放大到最终产物。
三、超链接规则:同页链接与跨文件引用的正确姿势
docs/README.md将链接分为两类,并明确了各自的适用范围:
`title`_与`string <title>`_两种风格只在同一页面内有效。当它们被rst2man处理时,会以下划线形式显示(man 页中无法形成真正的跳转链接)。:ref:`label`与:ref:`string <label>`风格可以跨文件跳转,rst2html(及 Sphinx)会将其转换为真正的超链接;但这种风格在rst2man下会报错,因此严禁在 man 页中使用:ref:风格。
man 页标题(如ctags(1)、ctags-optlib(7))有一套自动链接替换机制:docs/README.md指出,man/*.[1-9].rst.in中的 man 页标题会在执行make update-docs时被替换为:ref:`ctags(1)`形式的超链接。这一机制在 man/GNUmakefile.am 中有完整的实现:update-docs目标先把GEN_IN_MAN_FILES中的文件名(如ctags.1、tags.5)通过subst/addsuffix转换为 man 页引用形式ctags(1),再生成一组sed替换模式(-e 's/\<ctags(1)/:ref:& <&>/g'),从而把生成到docs/man/*.rst里的 man 页标题统一替换为可跨文件跳转的:ref:引用。这样,docs/*.rst(面向开发者的 HTML 文档)与docs/man/*.rst(嵌入 Sphinx 的 man 页)就能互相引用。
四、文档标记约定:NOT REVIEWED YET / IN MAN PAGE / TODO / TESTCASE
docs/README.md定义了一套贯穿所有文档的标记体系,让读者一眼就能判断某段内容的成熟度:
NOT REVIEWED YET(或BEGIN: NOT REVIEWED YET…END: NOT REVIEWED YET包裹的区块):表示该节或该代码块尚未经过评审,属于草稿性质。例如 docs/contributions.rst 的 "Notes for GNU emacs users" 一节就带有.. NOT REVIEWED YET标记。IN MAN PAGE:表示该主题同时也在 ctags 的 man 页中有解释。这是开发者文档与用户文档之间建立对应关系的锚点。.. TODO: ...:面向文档本身的待办事项注释。.. TODO(code): ...:面向程序代码的待办注释(区别于纯文档 TODO)。.. TESTCASE: ...:指向当前所记录功能的测试用例位置,方便读者在 Tmain/ 或 Units/ 中验证文档描述的行为。
这套标记约定与仓库的测试文化一脉相承:docs/contributions.rst的 "Testing" 一节明确要求"修改核心就向 Tmain 添加测试用例、新增或修改解析器就向 Units 添加测试用例",而TESTCASE:标记正是把文档与测试用例直接串联起来的桥梁。
五、生成 man 页面:make、rst2man 与变量替换
5.1 构建入口与目录约定
docs/man/目录中的文件全部由man/目录下的源文件自动生成,禁止直接编辑。执行下面任一命令即可更新:
make # 在仓库顶层目录执行,更新所有生成物 make -C man # 只构建 man 页相关目标整个生成流水线定义在 man/GNUmakefile.am 中,核心目标如下:
man:从*.rst.in生成传统 man 手册页(ctags.1、ctags-optlib.7等)。update-docs:把 man 页 reST 文件生成到docs/man/*.rst,供 Sphinx 文档树引用,并完成前文所述 man 页标题的:ref:链接替换。html/pdf:分别生成 HTML 与 PDF 版本。
生成 man 页时,rst2man命令是必需的——它是 Ubuntu 上python-docutils软件包的一部分,安装该包即可获得此命令。
5.2 变量替换:@CTAGS_NAME_EXECUTABLE@、@ETAGS_NAME_EXECUTABLE@ 与 @VERSION@
man/*.rst.in中的*.in后缀意味着这些源文件包含待替换的占位符。man/GNUmakefile.am 中的REPLACE_CONF_VARS定义了三个变量替换规则:
REPLACE_CONF_VARS = sed \ -e s/[@]CTAGS_NAME_EXECUTABLE[@]/ctags/g \ -e s/[@]ETAGS_NAME_EXECUTABLE[@]/etags/g \ -e s/[@]VERSION[@]/$(VERSION)/g也就是说,*.rst.in中的@CTAGS_NAME_EXECUTABLE@、@ETAGS_NAME_EXECUTABLE@、@VERSION@会分别被替换为ctags、etags和当前构建版本号。打开 man/ctags-lang-asm.7.rst.in 可以看到实际效果:
:Version: @VERSION@ :Manual group: Universal Ctags :Manual section: 7 SYNOPSIS -------- | **@CTAGS_NAME_EXECUTABLE@** ... --languages=+Asm ... | **@CTAGS_NAME_EXECUTABLE@** ... --language-force=Asm ...这些占位符使得 man 页的SYNOPSIS、VERSION等信息在每次构建时自动与二进制保持一致,避免了手工维护重复信息。
5.3 生成 docs/man/*.rst 的细节处理
update-docs生成docs/man/*.rst时,除了把 man 页标题替换为:ref:超链接,还会删除每个文件前 10 行中的------分隔线(sed -e '1,10s/^-*$//'),以抑制 Sphinx 渲染时多余的分节索引。这些细节在 man/GNUmakefile.am 中都有注释说明,是保证docs/man/*.rst能在 Sphinx 中正常挂载(见 docs/man-pages.rst 的 toctree)的必要处理。
5.4 校验生成物
仓库同时提供了clean-docs目标用于清理生成的中间文件,并支持通过make checkgen之类的流程核对生成结果是否与提交内容一致,防止手工编辑与自动生成物发生漂移。
六、写作与提交的工程规范
man/README 明确指引作者先去阅读 docs/README.md 与 docs/contributions.rst 的 "Writing Documents" 一节。结合 docs/contributions.rst 的相应章节,仓库对文档写作还有以下工程层面的要求:
man/*.rst是 man 页的源文件,面向用户;docs/*.rst解释实验性新功能,面向开发者,其中的内容未来应逐步迁移到man/*.rst。- 新增解析器时,务必更新 docs/news.rst 中 "New parsers" 一节。
- 提交信息使用语义化前缀:
docs(web)表示修改docs/*.rst,docs(man)表示修改man/*.rst,main、Units、Tmain、dsl、operators、prelude等前缀分别对应main/目录、测试用例、测试框架、optlib/optscript 运算符等不同领域;若一次修改涉及多个领域,用逗号组合前缀(如main,Flex,JavaScript,SQL,refactor: ...)。
七、实战:为新增解析器添加一篇 man 手册页
docs/contributions.rst的 "How to add a new man page for your parser" 给出了一个完整的七步流程,这里结合前面的构建机制整理为可直接照做的清单(以语言LANGUAGE为例):
- 编写源文件:把用户需要知道的内容写入
man/ctags-lang-LANGUAGE.7.rst.in,并遵守 docs/README.md 规定的标记规则与占位符用法。 - 注册到构建清单:把
man/ctags-lang-LANGUAGE.7追加到 man/GNUmakefile.am 的GEN_IN_MAN_FILES变量中(该变量已收录 Asm、C、C++、Python、SQL、Verilog、Vim 等三十余种语言的 man 页,格式为ctags-lang-<LANG>.7)。 - 生成 Sphinx 源文件:运行
make -C man update-docs,自动在docs/man/ctags-lang-LANGUAGE.7.rst生成 reST 文件(并完成 man 页标题的:ref:链接替换与多余分隔线清理)。 - 挂载到文档树:把
ctags-lang-LANGUAGE(7)加入 docs/man-pages.rst 的 toctree。 - 提交两个文件:
git add man/ctags-lang-LANGUAGE.7.rst.in与docs/man/ctags-lang-LANGUAGE.7.rst。 - 提交信息:使用
docs(man): add a man page for LANGUAGE作为提交标题。 - 发起 Pull Request。
值得留意的是,第 5 步要求把生成的docs/man/*.rst一并提交,而非只提交源文件。这与仓库"翻译后的 C 代码也提交进 git 仓库"的策略一致:生成物随源提交,可以保证在不具备相应工具链的环境中(例如未安装 Sphinx 的机器)依然能够直接消费这些文档。
结语
Universal Ctags 的文档体系以man/*.rst.in与docs/*.rst两条源文件线为起点,经由 man/GNUmakefile.am 的变量替换、rst2man/Sphinx 渲染、update-docs的链接重写与docs/man/挂载,最终形成"man 手册页 + 开发者 HTML 文档"的完整输出。对贡献者而言,掌握 docs/README.md 中的标记、超链接与生成规则,再配合 docs/contributions.rst 的 "Writing Documents" 章节,就能让自己的文档既能在传统终端中正确呈现,也能在 Sphinx 网站上获得良好的阅读体验与交叉引用。
- 开发工具
- CLI
【免费下载链接】ctags
A maintained ctags implementation
相关推荐
FastF1 文档写作与构建全指南:从 Sphinx 环境搭建到 reStructuredText 贡献规范
FastF1 文档写作与构建全指南:从 Sphinx 环境搭建到 reStructuredText 贡献规范 本篇技术指南以 FastF1 仓库中的 文档写作指
Django 文档构建指南:基于 Sphinx 与 reStructuredText 的文档生产体系全解析
Django 文档构建指南:基于 Sphinx 与 reStructuredText 的文档生产体系全解析 本篇以 Django 仓库中 docs/README
后端Web框架Cutter 文档贡献指南:Sphinx 文档体系、写作方向与本地构建全流程
Cutter 文档贡献指南:Sphinx 文档体系、写作方向与本地构建全流程 Cutter(基于 Rizin 的开源逆向工程平台)的官方文档长期面临内容不完善的
应用安全桌面应用开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考