这是一封“情书”,写给那些给我的生活带来巨大改变的工具
本文最初发布于 Hynek Schlawack 的个人博客。
我在 20 世纪 90 年代中期开始涉足 AmigaBASIC,与那时相比,编程变得更加多样化了。当时,关于你正在为之编程的计算机,你可以买一本大部头的书,99% 的内容里面都有。当你打开一个单色编辑器输入代码时,那本书总是放在旁边触手可及的地方,上面满是标记和便利贴。
现如今,一本单是介绍前端 Web 框架的书,都要比 C64 程序员编写一个完整的游戏所需的书还要厚。另一方面,我们编写代码所需的一切信息通常只需一次点击就可以获得。
没有人会为开发文档付费——不管是微软还是苹果都在 Web 上提供了所有人都可以免费使用的文档。开源项目就更不用说了!
在 npm、PyPI 和 GitHub 的时代,为什么还要操作系统以外的东西,要说清楚这个问题并不容易。那以前就是一个有争议的决定,必须审慎权衡。过去,我们通常都是将依赖项与产品一起交付。
有新的可选项是好事,多样化是好处的,但是,这会导致你提高生产力所需信息的碎片化。
对于正在使用的程序包,在同一时刻,人们要打开 10 几个页签来查看 API 文档。作为一个在世界最佳冲浪景点工作过的人,我可以告诉你,当没有网络时,在线文档就会成为一个问题,尤其是当你需要使用网站的搜索功能时。
如果你和我一样,通晓多种编程语言,面对大量的子社区(即使都是用 Python,但 Flask + SQLAlchemy + Postgres 与编写基于 asyncio 的网络服务器也存在着很大的差异),很难想象一个人可以记住他所使用的每个方法的参数。主要是,如果你真和我一样,会经常忘记自己的电话号码。
这就是我为什么说,2021 年发现 Dash 于我而言是一件改变人生的大事。
大脑是为创造想法而生的,而不是为记住想法— David Allen
Dash 搜索
Dash 赋予了我一键获取所有相关 API 的能力:
我按下“空格”键,就会弹出一个浮动窗口,上面有一个激活的搜索栏;
我开始输入 API 或主题的大致名称;
我选择一个输入建议项,跳转到正式项目文档的相应位置上;
我按下 Escape,浮窗消失,编辑器再次获得焦点,我立马就可以开始输入了;
我忘了刚才看了什么,就再次按下空格,浮动弹窗在同样的位置出现。
这个过程非常短暂——所有这些操作不到 2 秒即可完成,因此,这不会打断我的思维。我只是下意识地完成了那些操作。被遗忘的原生应用之乐——是的,我知道 https://devdocs.io。
所有 API 文档都可以一键获取,这对我们的帮助太大了。
我花在记忆函数参数或类导入路径上的精力越少,我投入思考解决问题的精力就越多。
我自认为不是那种特别聪明的人,所以我得借机降低自己的心理负荷。
虽然 Dash 的 Mac 版本售价为 30 美元,但在 Windows 和 Linux 上有一个免费的版本 Zeal。另外,Windows 上还有一个收费版本 Velocity。当然,也有一个 Emacs 程序包可以提供同样的功能:helm-dash。
也就是说,在任何平台上你都可以体验到这种 API 之乐。在本文接下来的部分中,我将只介绍 Dash,因为我在使用它,不过,除非特别注明,以下内容对上述各个版本均适用。
我不知道为什么,但像 Alfred 或 VS Code 这样的应用程序也有无数的插件。无论在哪里,我都喜欢使用同样的快捷键组合查找文档。这就是我对许多在线 API 浏览器不感兴趣的原因——我希望可以在 5 秒钟内切入切出文档。
它们有一个共同点,就是本地文档的格式是一样的。
它们都基于苹果的文档集 Bundles(docsets),其中包括 HTML 文档目录、保存在 XML 属性列表中的元数据以及保存在 SQLite 数据库中的搜索索引:
some.docset
└── Contents
├── Info.plist # ← 元数据
└── Resources
├── Documents # ← HTML文档根路径
│ └── index.html
└── docSet.dsidx # ← SQLite db w/ 搜索索引
如果你的磁盘上有一堆 HTML 文件,那么你可以将其转换成一个 docset ,提供给 Dash。那只是包含元数据的 HTML 文件。由于这些文件都在你自己的磁盘上,所以操作都是离线的。
因此,docsets 可以代替你保存在本地计算机上的文档,不用做任何特殊的处理,就可以实现更快的离线访问。只要将其打包成必要的目录结构,添加一个空索引,填写简单的元数据。
Shazam!现在,你可以一键让它们出现,一键让它们消失。
让我们回到无聊的历史课堂,从头开始看:我每天都要在无数的平台上使用无数的项目。我这里说的不只是编程 API,还包括:Ansible role、CSS class、HAProxy 配置、Postgres (和 SQL)特性……诸如此类,数不胜数。
安装好的 Dash docsets
虽然 Dash 自带了 Python 和 Go 核心文档, 而且 Godoc 文档可以通过 URL 直接添加,但无论 Dash 如何努力:在现代软件开发的碎片化世界里,它永远无法提供我需要的一切。
对我来说,其最大的缺失是(不仅仅)主导 Python 生态的 Sphinx 文档。
Sphinx 是一个语言无关的文档编写框架。不管是 API 文档,还是叙事性文档,都可以,而且提供丰富的链接。之前,它因为要求用户必须使用 reStructuredText 而声名狼藉,但现在,越来越多的项目使用 MyST 程序包来编写 Markdown 格式的文档。如果你对 Sphinx 文档的样式有任何先入为主的看法,我建议你浏览下 Sphinx Themes Gallery,看看 Sphinx 文档可以多漂亮。它是用 Python 编写的,但应用广泛,苹果的 Swift、LLVM(Clang!) 项目以及一些特别流行的 PHP 项目都在使用它。
而且,它恰好提供了缺失的部分:API 条目、章节、术语表、配置选项、命令行参数等的索引——所有这些都以你喜欢的方式分散在你的文档中,但总是可以相互链接。我觉得这很好,特别是如果你遵循一个系统性的框架,如 Diátaxis。
从技术上讲,让这项工作成为可能的关键组件只是一个扩展:ntersphinx。顾名思义,它最初用于项目间的链接,为我们提供一种机器可读的索引。后来,该索引变得如此流行,现在 MkDocs 扩展 mkdocstrings 和 pydoctor 也提供了支持。你可以通过那个索引文件(objects.inv)准确识别兼容 intersphinx 的文档。
这就是为什么,十年前的今天,我启动了 doc2dash 项目。
doc2dash 是一个命令行工具,你可以从 Homebrew tap 获取,也可以从发布页面下载 Linux、macOS 和 Windows 的预构建二进制文件,还可以从 PyPI 安装。
然后,你所要做的就是将其指向一个兼容 intersphinx 的文档目录,doc2dash 会帮你完成所需的一切工作,并生成一个 docset。
doc2dash 转换
请注意,这个工具的名字是 doc2dash 而非 sphinx2dash。我一直希望它能够成为一个编写高质量转换器的框架,最早的是 Sphinx 和 pydoctor。很遗憾,我的希望落空了——这也不难理解,每个社区都希望使用自己的语言和工具。
不过,在我看来,这些工具通常看起来都是一次性的,所以我想再次声明一下,我愿意与其他人一起增加对其他文档格式的支持。
不要重复发明轮子,框架已经有了!只是几行代码而已!你不必跟我和全世界分享你的解析器。事实是,Dash 和 doc2dash 都已存在超过 10 年之久,我仍然看到朋友们会打开无数个 API 文档页签,这让我非常难过。我不断向人们展示 Dash 的实际用途,他们总是说它很酷,并把它列入未来某一天的计划。除非再推一把,否则那一天总也不会到来。
本文的果蝇部分到此结束,接下来,我将试着用一个快速上手教程来推动你,让今天成为那未来的某一天!
本教程旨在教你如何将兼容 intersphinx 的文档转换成 docset ,并提交到 Dash 的用户 docset 注册中心,这样,其他人就不用重复你的工作了。
假设你已经选择并安装了自己的 API 浏览器。你使用哪一个都没有关系,不过本教程使用 Dash。为了最后可以有选择的提交 docset ,你还需要对 GitHub 以及 pull 请求工作流有一个基本的了解。
我将以本教程为契机,开始发布自己项目的 docsets,首先从 structlog 开始。我建议你选择一个兼容 intersphinx 但 Dash 还不支持而你又经常访问其文档的项目。
让我们开始吧!
如果你已经在使用 Homebrew,那么获取 doc2dash 最简单的方法是使用我的 GitHub 库 tap:
brew install hynek/tap/doc2dash
也有面向 Linux x86-64 和 macOS 的预构建二进制包,适用于 x86-64 和 Apple Silicon,因此,应该很快就可以安装完成。
除非你了解 Python 打包方法,否则第二好的方法是使用发布页面提供的预构建二进制文件。当前,上面提供了适用于 Linux、Windows 和 macOS 的二进制文件,全都是针对 x86-64。如果受欢迎的话,我将来会提供更多面向其他平台的构建。
最后,你可以从 PyPI 获取。我强烈建议使用 pipx,以下是使用它运行 doc2dash 最简单的方法:
help pipx run doc2dash --
高级技巧:如果你了解 PyPy ,知道它的用法,并计划转化巨大的文档树:doc2dash 在 PyPy 上的速度是在 CPython 上的两倍。
接下来是最大的问题——也是一个经常性的 doc2dash 特性请求来源:你需要完整的、构建好的文档。通常,这意味着你必须在安装 doc2dash 之前下载存储库,并弄清楚如何构建文档,因为很遗憾,大多数文档网站都不提供完整文档的下载。
我的做法是首先查找 tox.ini 或 noxfile.py,看看它是否构建文档。如果没找到,就查找 readthedocs.yml,如果还是没有,就找像 docs-requirements.txt 这样的文件或者可选安装目标,如 docs。最后的希望是浏览长长的 YAML 文件,检查 CI 配置。
在安装好所有依赖项后,剩下的工作就只有在文档目录中运行 make html 命令了。
上述工作完成以后,对于 Sphinx ,会生成一个 _build/html 目录,对于 MkDocs,则会生成一个 site 目录。
对于 MkDocs,请注意,如果项目没有使用 mkdocstrings 扩展——唉,现在几乎所有流行的项目皆是如此——就不会有 objects.inv 文件,也没有可供消费的 API 数据。
我真得希望,将来更多基于 MkDocs 的项目添加 mkdocstrings 支持。至于 Sphinx,它是语言无关的。
最难的步骤已经完成,现在轮到最简单的了:将刚刚构建的文档转换为一个 docset。
你所需要做的就只是将包含 HTML 文档的目录提供给 doc2dash,并等待:
doc2dash _build/html
就是这样!
doc2dash 知道如何从 intersphinx 索引提取名称,并且默认会使用这个名称(你可以通过 --name 覆盖)。现在,你应该可以将这个 docset 添加到你选的 API 浏览器中了,应该是一切都可以工作了。
如果你传递了 --add-to-dash 或 -a 参数,那么在转换完成后,最终的 docset 会自动添加到 Dash。如果你传递了 --add-to-global 或 -A 参数,那么 doc2dash 会将生成的 docset 移到一个全局目录(类似~/Library/Application Support/doc2dash/DocSets),并从那里添加它。我自己在创建 docsets 时,一般都会使用 -A 运行 doc2dash。
对于通过上述步骤创建的 docset ,Dash 官方文档提供了一系列的改进建议。务请注意,接下来的 5 个步骤不是必须的,我多半会跳过,因为我很懒。
但对于这个项目,我想把 docset 提交到 Dash 的用户文档集注册中心,所以我会走完全程。
使用 Dash,你总是可以搜索所有已安装的文档,但有时候,你可能想要限制搜索范围。例如,当我输入 p3: (冒号是有意义的),就会切换为仅搜索 Python 3 文档集。在你开始输入之前,它会在搜索框下提供一个菜单,菜单第一项为“主页”。
在转换 structlog 文档时,主页是可能有用的索引,但通常不是我想要的。当打开主页时,我希望浏览叙述性文档。
用于设置主页的 doc2dash 选项是 --index-page 或 -I ,你想使用哪个页面,就需要提供该页面相对于文档根目录的文件名。
令人困惑的是,索引文件名是 genindex.html,而主页文件名是 HTML 中比较典型的 index.html。因此,我们要在命令行中加入 --index-page index.html。
文档可以有图标,在 Dash 中显示在 docset 名称和符号旁。这样既好看,又能帮我们更快地识别文档集,比如,当你跨多个文档集搜索时,就可以知道符号来自哪里。
structlog 有一个可爱的河狸 Logo,因此,我们使用 ImageMagick 将其大小调整到 16x16 像素:
magick \
docs/_static/structlog_logo_transparent.png \
-resize 16x16 \
docs/_static/docset-icon.png
现在,我们可以使用 --icon docset-icon.png 选项将其添加到文档集了。
为此,Dash 提供了一个菜单项“Open Online Page ⇧⌘B”,但你需要提供文档的基地址。可以使用 --online-redirect-url 或 -u 设置。
对于 Read the Docs 网站的 Python 程序包,你可以在 stable (上一个 VCS 标签)和 latest (当前主分支)之间做出选择。
如果你要从离线文档转到在线文档,我觉得 latest 更有意义,因此,我加了下面这个选项:
--online-redirect-url https://www.structlog.org/en/latest/
完成了!让我们运行下整个命令行,在 Dash 中看下效果:
doc2dash \
--index-page index.html \
--icon docs/_static/docset-icon.png \
--online-redirect-url https://www.structlog.org/en/latest/ \
docs/_build/html
Converting intersphinx docs from '/Users/hynek/FOSS/structlog/docs/_build/html' to 'structlog.docset'.
Parsing documentation...
Added 238 index entries.
00:00 :
非常赞:
structlog 的主页
注意搜索栏中的图标,在任何带有锚点的页面上按下⇧⌘B,就会进入到最新版在线文档的同一位置。
由于我想每次发布时都创建一个新版本的文档集,所以需要将创建过程自动化。structlog 已经使用 GitHub Actions 实现了 CI,因此,顺理成章地,我也就用它构建文档集了。
对于本地测试,我将利用 doc2dash 作为 Python 项目的便利,使用 tox 环境,它重用了我在测试文档本身时使用的依赖项。
tox 结合了 Makefile 和基于 ini 文件格式的虚拟环境管理器。其初衷是在多个 Python 版本上测试 Python 软件,但现在已经变强了许多。
与 Makefile 相比,它最大的优点是更便于移植,并且自带 Python 打包支持(这对于构建文档来说是必要的)。
该环境安装了 structlog[docs] ,即带有可选 docs 依赖项的程序包,还有 doc2dash 命令。然后,它会依次行 commands:
[testenv:docset]
extras = docs
deps = doc2dash
allowlist_externals =
rm
cp
tar
commands =
rm -rf structlog.docset docs/_build
sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html
doc2dash --index-page index.html --icon docs/_static/docset-icon.png --online-redirect-url https://www.structlog.org/en/latest/ docs/_build/html
cp docs/_static/[email protected] structlog.docset/[email protected]
tar --exclude='.DS_Store' -cvzf structlog.tgz structlog.docset
现在,我只需调用 tox -e docset 就可以构建文档集。在 doc2dash 支持高分辨率图标之后,它也会直接将一个 32x32 像素的 Logo 复制到文档集中。
在 CI 中做这项工作很简单,但需要大量的样本文件,所以我将直接链接到工作流。注意最后的 upload-artifact 动作,它允许我从运行总结中下载构建好的文档集。
至此,我们已经有了一个很棒的、可以自动构建的文档集。是时候分享给其他人了!
在最后一步中,我们将把构建好的文档集提交到 Dash 的用户文档集存储库,这样,其他人就可以从 Dash 的 GUI 中轻松地下载了。而且比较方便的是,在整个过程中,Dash 使用了一个每个开源爱好者可能都很熟悉的概念:GitHub pull 请求。
第一步是检查文档集贡献清单(Docset Contribution Checklist)。幸运的是,我们(有时候是 doc2dash)已经把一切都处理好了!
好了,让我们继续,创建 https://github.com/Kapeli/Dash-User-Contributions 存储库分叉,克隆到本地计算机上。
首先,你必须将 Sample_Docset 目录复制到 docsets ,并在这个过程中进行重命名。对于我来说,命令行如下:
使用 cd docsets/structlog 进入该目录,在那里继续下一步的工作。
主要步骤是添加文档集本身,但是作为一个 gzipped tar 文件。贡献指南甚至为我们提供了创建压缩包的模板。对于我来说,命令行如下:
'.DS_Store' -cvzf structlog.tgz structlog.docset tar --exclude=
你可能已经注意到,我已经在 tox 文件中完成了 tar,因此,只需复制过来即可:
$ cp ~/FOSS/structlog/structlog.tgz .
此外,它还要求图标要和 docset 中的一样,所以我从中复制了它们:
$ cp ~/FOSS/structlog/structlog.docset/icon* .
接下来,我们需要在 docset.html 文件中填写元数据,就我这个情况来说很简单:
{
"name": "structlog",
"version": "22.1.0",
"archive": "structlog.tgz",
"author": {
"name": "Hynek Schlawack",
"link": "https://github.com/hynek"
},
"aliases": []
}
最后,我们需要编写一些文档,说明我们是谁,以及如何构建 docset。看了其他一些例子后,我确定了以下内容:
# structlog
<https://www.structlog.org/>
Maintained by [Hynek Schlawack](https://github.com/hynek/).
## Building the Docset
### Requirements
- Python 3.10
- [*tox*](https://tox.wiki/)
### Building
1. Clone the [*structlog* repository](https://github.com/hynek/structlog).
2. Check out the tag you want to build.
3. `tox -e docset` will build the documentation and convert it into `structlog.docset` in one step.
tox 技巧发挥作用了——我不必向任何人解释 Python 打包了!
记着从示例 docset 中删掉我们不再用的东西:
rm -r versions Sample_Docset.tgz
完成了!提交变更:
$ git checkout -b structlog
$ git add docsets/structlog
git commit -m "Add structlog docset"
[structlog 33478f9] Add structlog docset
5 files changed, 30 insertions(+)
create mode 100644 docsets/structlog/README.md
create mode 100644 docsets/structlog/docset.json
create mode 100644 docsets/structlog/icon.png
create mode 100644 docsets/structlog/icon@2x.png
create mode 100644 docsets/structlog/structlog.tgz
$ git push -u
看起来不错,是时候提交 pull 请求了。
数小时后:
在 Dash 中查看我们贡献的 structlog docset!
非常成功:现在任何人都可以下载 structog 文档集了。我们这份简短的教程到此也就结束了。
希望我这篇文章既激发了你对 API 文档浏览器的兴趣,又让你了解了自己创建文档集的奥秘。我的目标是帮助像我一样的程序员提速,我们在完成工作时需要记忆的软件包太多了。
不过,我最大的愿望是,这篇文章能激励一些人来帮助我向 doc2dash 添加更多的格式,这样,就有更多的程序员能够享受到在弹指间查询 API 文档的乐趣。
在过去的十年中,我在 doc2dash 推广方面做得很糟,希望接下来的十年我能做得更好!
声明:本文为 InfoQ 翻译,未经许可禁止转载。
原文链接:
https://hynek.me/articles/productive-fruit-fly-programmer/
你也「在看」吗? 👇
微信扫码关注该文公众号作者