整个花里胡哨的终端

作为一个码农,我天天都在用终端,自然需要一个看着舒服用着顺手的终端。这次我就来介绍一下我用过的那些花里胡哨的东西……

配色

高中的时候一直在用 Emacs,配色方案是 tangotango,这个绿色选的特别舒服。有一段时间用过 Monokai。

换成 VS Code 之后可以继续使用 Monokai,但是我似乎有点看腻了,决定寻找新的配色。试了一下 Material 之后感觉很精致,用了一段时间。后来又发现了 Nord 这个主题,又喜欢上了这种偏冷淡的风格,于是就把 VS Code/PyCharm/Vim 全改成了这个配色。

Nord Vim

字体

不知道为啥,我对字体有一种谜一般的追求。我对字体有以下要求:

  1. 作为编程字体,自然要区分 1lIoO0 以及 uvw。排除 Courier New(1l 太像了)。
  2. 正体 l 的下面那里不能是弯的。这点排除了太多字体,例如 Bitstream Vera 家族及其衍生的 DejaVu 家族, Source Code Pro,JetBrains Mono,Hack。斜体无所谓,甚至弯的更好。
  3. 0 里面是一斜,没有的话容易和 O搞混,一点的话太丑。排除 Hack,Source Code Pro,IBM Plex Mono。
  4. il 的那一竖,要是上面左边有横线,那么下面右边要有横线。排除 Monoid。
  5. -> 要对齐。排除 Monaco。
  6. *@$ 这种符号不要太奇怪。例如 FiraCode 默认的 @* 必须是六角星,不能是五角星。

以上基本上是硬性条件,要是有哪里不满足我就不舒服……另外还有几项加分项:

  1. Ligature。这点大部分现代一点的字体都能做到,远古字体应该也可以加 patch 做到。
  2. Powerline symbols。这个问题不大,大不了用 nerd fonts patcher 改一改……
  3. 字形好看。这个就是纯主观因素了。
  4. 斜体偏手写。
  5. 没有版权问题。

试了很久,最后找到三个比较满意的:

  1. 老牌名将 Consolas。我很喜欢字形和宽度,看着很舒服,可惜原版没有自带 Ligature ,而且可能还有版权问题。
  2. Operator Mono。字形有自己的特点,没有 Ligature,收费字体。手写斜体很漂亮。
  3. Iosevka。有 Ligature,字形其实一般,我刚看的时候直接被这么窄的字体吓跑了。开源。

最后我选择了 Iosevka,因为它支持定制化!作者写了一个网页来帮助定制化,每个字符都可以挑,正体斜体还可以挑不一样的。在某个版本开始可以选择把字体宽度调大(虽然调大后感觉还是没有 Consolas 好看)。相比之下,FiraCode 虽然也有一些开关可以选,但是选择余地远远没有 Iosevka 这么大。Iosevka 的斜体比不上 Operator Mono,但是也挺不错的了。

Iosevka

iTerm2

macOS 自带了 Terminal.app,那 iTerm2 有啥优势呢?

在我看来,ITerm2 起码有两个优势:

  1. tmux -CC 。这个命令可以直接和让 tmux 开出一个窗口出来,这样 tmux 出的窗口和普通的窗口一样,复制粘贴、滚动、分屏什么的都是 iTerm2 在控制,不用记 tmux 的快捷键了。
  2. Shell integration。这里面最有用的一个就是完成任务时提醒,默认快捷键 Option+Alt+A。有了它,我就可以把一个任务放在后台执行,然后愉快地切到其他地方摸鱼去了。

Shell

Shell 这个选择可太多了。默认选择 Bash。没啥好说的,就是稳。

Zsh

zsh 可以说是非常 fancy 了。它插件很多,就连 framework 都有两个大块头 oh-my-zshPrezto 就连插件管理都有一大堆(antigen, antibody, zplug, zinit)。我之前试过 oh-my-zsh ,后来忘了因为啥原因不用了,换成了 antigen,感觉还行吧……

Powerline10k (p10k)

一开始这只是 romkatv 小哥自己 fork 的 p9k(所以文档里面有很多强调和 p9k 的兼容性),但是后来好像同人逼死官方了(p9k 停止开发了)……这小哥文档写的很全。gitstatusd 这个思路我觉得不错,之前 git status 慢的要死都想让我关掉了。而且 p10k 很漂亮,看起来特别 fancy,非常可定制,信息多而不乱,不愧是我花里胡哨排行榜第一名。由于配置过多,官方都有一个 configuration wizard (p10k configure)来帮你挑选自己的配置。这里放一个官方的 configuration wizard 动画,看看它到底支持多少种花里胡哨的变种。我对 p10k 非常满意,不过还是有个小吐槽:cwd 高亮只对默认有效,换一个变种就没了……

Powerline10k

除了 p10k 外,还有一些其他的 theme。另外一个比较流行的是 spaceshipspaceship-rs。后者和前者看起来差不多,但是后者 claim 自己 cross-shell ,也就是说这不是仅限于 zsh,在其他 shell 上也可以用,而且它使用 Rust 写的,自然跑的飞快。我试了一下,感觉一般。我不太喜欢分成两行的 theme,更喜欢一行,然后左右各显示一些信息的 theme,左边的放重要信息,例如 user@host、目录这种,右边的显示一些不那么重要的信息,例如时间、版本号。而 spaceship-rs 不支持 right prompt 。虽然号称无限定制性,但是在我看来还不如 p10k 舒服。

fzf

这简直是个大杀器,可以荣登我花里胡哨排行榜第二名了。简单来说,这个插件就是模糊搜索。我主要有两种用法:

  1. 搜索之前打过的命令行(Ctrl-R)。曾经,有一个插件 zsh-history-substring-search 摆在我面前,我用了几年,直到 fzf 出现,我终于把它换了。

  2. 搜索文件(Ctrl-T)。这个是在一个目录下,想找一个文件,但是懒得输入路径了,就可以用这个方法偷懒。这里放一个官方的带有文件预览的 fzf 效果图。 fzf

zsh-autosuggestions

这个直接把 fish 复刻过来了。这里有个视频可以很清楚的介绍这是干啥的。这个插件可能和 fzf 的 Ctrl-R 重复,但是使用之后发现还挺实用的,因为很多次你就想简简单单重复上一个这样的命令。我很多次直接闪电三连鞭 py<Ctrl-F><Enter> 执行最近一个 python 命令,左右手依次打字最后一个回车完成任务,感觉自己就像那神秘的黑客了哈哈哈哈哈哈哈哈哈哈。

fast-syntax-highlighting

这个给你输入的命令行加了一个语法高亮。没多大用,但是一个好处是可以很清楚的看到文件名对不对,文件名要是不对的话高亮会不同。

z.lua

一个类似 autojump 之类的东西,就是把你曾经访问过的文件夹按照某种方式排个序,然后直接跳掉该文件夹。用的不是特别多,而且有时候文件夹名字相同可能会不准……没准哪天用 ML 整一下,搞个bbl.lua,您家的目录跳转专家?

一些现代化 Shell

zsh initial release 已经是 1990 年的事了,比我还老,远远谈不上现代。近些年来,有一些更为现代化的 Shell 的出现。我也来稍微介绍一下。之所以说现代化,是因为它们的语法或者同一个语法的语义和之前的 shell script 不一样了。

nushell

nushell 的想法可能和 powershell 有点类似,就是进程间通信不再使用 plain string,而是使用结构化的对象。我们来看看官方例子:

nushell

这里可以看到,sys 输出的是一个完整的结构,包含了文件名、大小等信息。这些信息通过管道传给 get,然后 get 对消息做一定处理后继续把这个结构化的对象传给 select ,最后再给 to json。这样一个完整的运行流程就是:先 ls/sys/open 等命令生成一个对象,然后 where/get/select/to 对这个对象进行处理,最后 to 把这个对象序列化。这就对我们的接受能力提出了挑战,以及对于那些不能生成对象的命令似乎就没用了……虽然看起来很炫酷,但是用不来……

xonsh

xonsh 把 python 和 shell 结合了起来。在里面你可以写构建 python 对象,也可以利用把 python 对象 interpolate 到 shell command 里面去。官方这张图很好的描述了它的用法。在这里,数据的传递仍然是字符串,但是我们可以利用 python 来处理字符串而不是 shell script。

xonsh

jupyter

没错,这就是我常用的 jupyter notebook。它也可以作为 shell 来用,例如下面这个 cell 就进入某个目录,然后把子目录下的文件 copy 到当前目录下。

1
2
3
!cd /tmp/aaa
for n in range(4):
!cp $n/*.pdf $n.pdf

这里 ! 开头的语句都是 shell 命令,里面可以用 $n 这样的语法来做 interpolation。除此之外都是 python 的语法。自然,背靠 python,jupyter 的包管理器就是 pip。

elvish

elvish 的主要作者是 xiaq。这人以前给 zsh 写了一些代码,后面可能是不满意吧,开始自己整一个 shell。elvish 自己发明了一套语法,不过看起来资料不太多……事实上我认为 shell script 的语法实在是太丑了,我学都不想学……elvish 这个看起来就舒服很多了。elvish 有自己的包管理器 epm,里面也有一些插件。我们之前提到过的 starship 就可以在 elvish 上面跑,还有 iTerm2 shell integration 也有。这里我就懒得贴图, 直接去官网上看样例吧。

小工具

新时代,新气象!人们不断地重复造轮子,带来了一个又一个 modern replacement。特别是 Rust 出来之后,我看到好多个新轮子都是 Rust 造的。

ls \(\Rightarrow\) lsd / exa

两者都是 Rust 写的。恭喜 exa,荣登我花里胡哨排行榜第三名!说起来我一开始在学校服务器上跑不起 exa,提示 glibc 版本不行,但我显然没有权利改 glibc 这么基础的东西。后来用了 musl 版的 exa 后终于跑起来了。下面放一张 exa 的图:

grep \(\Rightarrow\) ripgrep (rg) / the silver searcher (ag)

前者 Rust,后者 C。听说 ripgrep 的作者 BurntSushi 在写 rg 的时候自己造了一个 regex 的轮子,后来被官方收编了。速度的话我没啥感觉,但是一些 default 更好一些,例如根据 .gitignore 忽略文件。

find \(\Rightarrow\) fd

用 Rust 写的。其他很多东西我不管,但是起码不用写 find -iname '*PATTERN*' 这种奇怪的语法了。实际上我不太主动调 fd,但是 fzfCtrl-T 可以用 fd。其他的像默认正则表达式啊,快啊之类的都是一些添头了。

cat \(\Rightarrow\) bat

还用 Rust 写的……其实就是加了个语法高亮……其实这东西我不用,因为我 cat 的主要目的是复制,而 bat 加的行号都不方便复制了……但是你可以把 bat 和其它工具结合起来预览文件内容,例如 fdrg

ssh \(\Rightarrow\) et

C++ 写的,这个是我在 Facebook 实习的时候知道的,因为当时一个维护者就在公司。其实它就增强了一个特性:长连接。例如我干活的第一件事就是 ssh 连上远程服务器,但是合上笔记本盖子之后, ssh 就断掉了,et 能帮我保持这个连接,下次有网了,et 自动重连,一切就当无事发生过。当然这需要在服务器端装一些软件开一个端口……et 还无缝支持 tmux -CC,比 mosh 感觉要好用很多。

vim \(\Rightarrow\) neovim

C 写的。vim 作为远古神兽,是不少人心中的信仰。但是有人吐槽 vim 的代码实在包含了太多的历史包袱,例如这里有篇吐槽文,截取了一段 400 行、包含了 40 个 #ifdef 的代码,作用是读取一个用户的输入的字符。作者还有另外一篇吐槽文,里面提到了 neovim 起源,特别适合吃瓜。这篇文章作者试图给 vim 的插件提供异步功能,这样就可以做一些比较慢的事,例如调用外部 linter。但是 vim 的 BDFL 却不同意 merge。文章中提到了有这么一个 review 意见:

Wrong:

1
2
3
4
5
void

insert_timeouts(timeout_T *to) {
timeout_T *cur = timeouts
timeout_T *prev = NULL

OK:

1
2
3
4
5
6
7
8
9
10
/*
\* Explanation of what the function is used for
\* and of how to call it
*/
void
insert_timeouts(to)
timeout_T *to; /* short comment about to */
{
timeout_T *cur = timeouts; /* short comment about cur */
timeout_T *prev = NULL; /* short comment about prev */

NOTE: Don’t use ANSI style function declarations. A few people still have to use a compiler that doesn’t support it.

这都是 C89 就支持的东西了,这个 patch 都在 2013 年了还不能放心的用吗……然后几个月后,有人提交了类似的 patch,也没有通过,但是这次的小哥就不服,另立门户,众筹开启了 NeoVim 项目,要基于 vim 原来的代码,做一次大大大大大大大 refactor ,然后再加新功能。从结果上来看,这次众筹算是比较成功的:一开始的目标是 $10k,最后募集了$33k。于是这位小哥就风风火火去 refactor 去了(哈哈哈哈先容我笑一阵)。neovim 还要支持用 Lua 来写插件,而不是 VimL。这个我也很赞同,人生苦短,何必造这么多 DSL 呢……(当然还有语法更丑的 DSL。看什么看,说的就是你,\(\TeX\)!)最后补一句题外话,neovim 加了 async 之后,vim 8 迅速跟上也加入了 async……

说了这么多,neovim 我用起来还是有一些 bug,例如在 tmux 里面跑的话打开文件没问题,但是一旦编辑起来了就会出现错位的情况,而且似乎只在(两个)学校服务器上的远古 Linux 发行版上有这个问题,搞得我很恼火,只好又回去用 vim 了……但是我本机和自己的 VPS 上都是用 neovim。

花里胡哨排行榜

最终,将给出我的花里胡哨排行榜前三名,让我们恭喜获奖选手!

  1. p10k
  2. fzf
  3. exa