atuin 是最近在群里看到的工具。功能和我自己用 skim 糊的脚本一样,搜索并执行 shell 的命令历史用的。但是,它的数据存储使用的是 SQLite3,并且它是使用 Rust 编程语言编写的。于是事情有了一些好的变化。
首先,因为 atuin 并不像 Web 服务那样,会持续打开并操作数据库,所以 SQLite3 并发容易报错的问题并不需要担心。而 atuin 会记录执行时间、耗时、工作目录和退出码等信息。更多的元信息,能给之后的搜索和分析提供更多帮助。
其次,因为搜索走的数据库查询,因此并不需要像我用 skim 那样,每次把全部历史加载到内存。这样就可以保留更多的历史记录而不用怕越用越慢了。不知道 SQLite3 的搜索功能效率如何,但我几万条记录,已经可以明显感觉到加载耗时的差异了。
最后,它是 Rust 写的——这点很重要,因为这大大地方便了我对它进行修改(而不像某 Zig 写的工具,我翻了半天文档都没改对最后只好放弃了)。
当然,让我没多犹豫就决定尝试 atuin 的最重要的原因是:它独立于 shell 原本的历史记录功能,并不会取而代之。所以它要是不合我意,我只要把它删掉就好了,原本的历史记录丝毫不受影响。
于是我到现在已经用半个月了,结果非常满意。不过也已经对它做了好多修改了。比较重要的如下:
-
支持 Shift+Del 键删除记录。有时候会不小心打错命令。这种命令记在历史里时不时被翻出来,不但占用显示空间,还容易不小心选错然后相同的错误又犯一遍,甚至因为没看清命令细节而不小心删掉好多文件(还好我有快照)。atuin 的作者最近也加了删除功能,但是是在另一个界面操作,对于我这种经常在找命令的时候要删除多条命令的用法来说,不光麻烦,而且上下文切换的代价很大,会忘记自己原本是要干什么的。
-
精确匹配模式,这是 skim 的叫法。你叫它多子字符串匹配也行。自从 fzf 流行以来,大家都迷上了子序列匹配的所谓「模糊匹配(fuzzy match)」。但是我不喜欢这种匹配方法,会给出太多不相关的结果,加大脑力负担。真正好的模糊匹配是 agrep 那种基于编辑距离的算法,打错点字没关系那种。所以我给 atuin 也加上了精确匹配模式,同时还提升了查询性能呢。
-
反转 UI 的
--invert
命令行选项。像我之前使用 skim 那样,当光标位于终端窗口的上半部分时,我希望我搜索时打字的地方在上方;而当光标来到终端窗口的下半部分时,搜索时光标也放下边。这样关注的焦点就不会跳很远,有连贯性,节省认知脑力。atuin 本身有反转 UI 的功能,但是是写在配置文件里的,而我需要视情况决定要不要反转 UI,所以还是得加个命令行选项。 -
更改了选中项的颜色。atuin 原本用的是红色,我总觉得是哪里有报错……
还有些不太重要的修改,可以来我的分支查看:https://github.com/lilydjwg/atuin/commits/lilydjwg。注意这个分支我会经常 rebase 的。
另外我修改过的 zsh 插件在 https://github.com/lilydjwg/dotzsh/blob/master/plugins/atuin.zsh。
值得一提的是,atuin 还支持同步。同步的数据本身是加密的,但是还是会泄露一堆诸如什么时候在跑命令之类的元数据,所以我自己跑了个服务。服务很好跑,但是同步似乎有些问题。我两个系统,两边都导入了之前的历史记录并同步,但是后同步的那个系统上的历史,很难被同步过去。甚至 atuin 发现本地比远程多,就从最新开始慢慢上传,直到两边一样多;如果远程比本地多,那就把远程的删掉一些(我也不知道它删了哪些,我是看到访问日志里巨量的 DELETE 请求才意识到问题的)。总之经过我不懈地反复运行,最终它只比远程多几条记录了,并且绝大部分历史记录已经两边都有了。我猜它可能没想到我会从不同的系统上同步已有且已分歧的数据吧……