常言道,工欲善其事、必先利其器,熟练一套高效且趁手的工具,对开发工作的重要性不言而喻。
本文分享我的命令行开发环境,文章较长,配图较多, 其中几处详细内容,已将其折叠起来,读者可视兴趣展开阅读。
命令行工具非常多,称得上神器的,提炼为以下四个:
我选择工具的标准是:美、快、爽。
终端程序 — Alacritty ¶
Alacritty 是一款 rust 编写的、 启用 GPU 加速的终端模拟器。
天下武功,唯快不破,它唯一特点就是:快。
在 2018 年之前,我一直在用流行的 iterm 2。 不过,自从邂逅 alacritty 后,就从未离开。相比 iterm2 来说,alacritty 的功能要简单的多, 但是,它足够快。
下面的动图展示了同时在 alacritty(左) 和 iterm2 中用 viu 打开一张图片时的渲染速度:
作为终端,一定要颜值在线。 Alacritty 也支持配色,可参考 alacritty-theme , 我用的配色是 snazzy ,从未换过。 此外,选择一款 等宽的 字体,对终端的整体颜值至关重要,我一直在用的字体是 InconsolataLGC Nerd Font。
我对 alacritty 的功能需求非常少,只要它够快,够漂亮 就好。比如说,我是没有用终端 Tab 页的习惯的, 这些事情 tmux 完全可以搞定。作为终端模拟器,简单快速就好!
Shell – Fish ¶
无独有偶,选择 fish shell 的原因,仍然是它更快,同时也更轻。
这里所说的「快」,是指 shell 的 prompt 加载快, 如下图中,进入 fish 几乎是没有延迟的:
当然,不带任何配置的 zsh 和 bash 也很快。 但是,为了酷炫的颜值、快捷的功能, 许多 zsh 用户都会搭配类似 oh-my-zsh 的东西, 或者是搞一大堆配置,这都会让 shell 变慢。
但是真正的不同在于,fish 是开箱即用的,大可不必自己折腾那么多。 比如 fish 的一大特色是自带补全暗示功能:
还有自带的 ManPage 补全功能等等,这一切都无需插件。
因此 fish 的插件要相对少得多。我在用的也很少:
- pure-fish/pure 从未换过的 fish prompt 主题,它是如此简洁。
jethrokuan/z 快速跳转目录的插件
除去工具本身外,unix 中 emacs 风格的 shell 快捷键 也值得推荐, 它们在常见的 shell (fish, zsh, bash) 中都是通用的,其中部分快捷键甚至可以在网页文本框中使用。
Emacs 风格的 shell 快捷键 - 光标移动和编辑
C-a
光标回到行首,C-e
光标回到行尾C-f
光标向前移动一个字符,C-b
光标向后移动一个字符Alt-f
光标向前移动一个单词,Alt-b
光标向后移动一个单词C-k
清掉光标后面的部分,C-d
删掉光标后的一个字符 或 退出C-l
相当于clear
命令,清屏
甚至,当命令非常长的时候,还可以跳入编辑器来编辑命令 ( fish 配置 ):
Emacs 风格的 shell 快捷键 - 回翻历史命令
C-p
向上翻历史命令,C-n
向下翻历史命令C-r
向上搜索历史命令 (顺手推荐搜索命令历史的增强工具 fzf)
Emacs 风格的 shell 快捷键 - 进程挂起
C-z
挂起当前进程到后台fg
以恢复到前台
其实,主流的 shell (fish, zsh, bash) 也都支持 vi 风格的操作模式。 虽然身为 vim 用户,之所以在 shell 中选择 emacs 风格,是因为它在大部分情况下都是 默认的 设定。
在带过的每一支技术团队中,我总会提醒小伙伴们要勤用这些 emacs 风格的快捷键,它看似麻烦, 但是一旦熟练起来,一定比鼠标快。只要刻意地去用,就会熟起来,将大有裨益。
终端复用 — Tmux ¶
Tmux 是一款终端复用神器,不必多言,它早已声名远扬。
简单讲,终端复用就是在一个终端中,可以开多个 shell 会话。 一些现代的终端应用,比如 iterm2, 也支持 Tab 页 和 切屏,不过它们在 tmux 的颜值和效率面前,都相形见绌。
几乎所有的 tmux 功能,都需要按一下 前缀键 来触发, 默认的是 C-b
,我则是习惯用 C-a
。
我常用的 tmux 功能有:面板、窗口、Copy 模式、会话保持 还有 两三个小插件。
tmux - 面板和窗口快捷键
C-a "
横向打开一个面板C-a %
纵向打开一个面板C-a o
在面板之间切换C-a q
展示当前窗口的所有面板的标号C-a z
放大或缩小一个窗口C-a c
创建一个窗口C-a n
切换下一个窗口C-a p
切换上一个窗口
作为一枚 vim 党,我习惯用 hjkl
来切换面板,例如 C-a h
会跳入右边的面板、C-a j
会跳入下边的面板 等 ( 相关 tmux 配置 )。
tmux - copy 模式
刚进入 tmux 的同学,常会遇到一个问题:如何滚屏 ?
在 tmux 中可以 C-a [
来进入一个叫做 copy mode
的模式, 然后就可以用方向键滚屏了。 但是方向键太难用了,可以设定 copy mode
下采用 vim 键位 ( 相关配置 )。
在 copy 模式下,vim 键位可谓如鱼得水:
C-u
和C-d
来上下翻页hjkl
来上下左右移动光标0
来跳到行首、$
来跳到行尾w
,e
,b
来按单词为单位前后移动光标f
和F
来前后搜索字符以跳跃光标v
开始选择一块区域,V
开始按行选择一块区域y
以拷贝内容,并退出 copy 模式,q
也可退出 copy 模式
还可以在 copy 模式下调整面板大小, 仍然采用 vim 风格的 C-hjkl
,是不是很有趣? (相关配置)
tmux - 会话保持
Tmux 还有一个非常棒的功能,就是会话保持。简单来说,就是可以暂时保存工作环境,稍后可重新进入。 这个功能对于需要服务器跑脚本这种事情,非常合适,不必再担心 ssh 断掉后进程断掉。
C-a d
临时离开当前 tmux 会话 (detach 之意)tmux a
重新进入 tmux 会话 (attach 之意)
甚至如果把整个终端模拟器退出,仍然可以重新进去,工作环境不会丢失。 当我的 alacritty 出现讨厌的闪屏之类的小问题时,我会直接 Cmd-q
杀掉终端,重启终端后即可直接回到 tmux 中。 前面的 图1.2 就是在两个不同的终端应用中运行同一个 tmux 会话,两边的交互完全是同步进行的。
tmux - 用到的三个小插件
Tmux 拥有着 丰富的社区生态, 其中不乏一些 “花里胡哨” 的插件,我不怎么用,状态栏比较干净。 比较喜欢的插件则是这三个:
- tmux-prefix-highlight - 每一次按下前缀键的时候,在状态栏高亮显示
- tmux-mode-indicator - 在状态栏显示 tmux 当前的模式名称
- tmux-open - 在 copy 模式下,选中一个 URL 可直接调用浏览器打开
此外,一个细节点是,用 tmux 切屏后,在各个小窗之间跳转时容易分不清当前在哪个窗口。我们可以给小窗的边缘加上一些颜色高亮。
tmux - 配置小面板的边框颜色
set -g pane-border-style "fg=colour25"
set -g pane-active-border-style "fg=colour169 bg=colour237"
Tmux 的可配置性很强,我的建议是,多用默认的快捷键,只做少许的自定义快捷键, 毕竟我们许多时候会在服务器等其他环境下使用它。
编辑器 — Vim ¶
Vim 有着「编辑器之神」的美誉, 如果把程序员比作武林中的侠客,那么 vim 就是倚天屠龙的利器。 已诞生 30 余年, 宝刀虽老,但是在 2022 年的今天,它的文本编辑效率仍尚无敌手。
相对于现代编辑器 或 IDE 来说,上手 vim 的难度曲线要陡峭许多。 据说有许多新手在刚刚进入 vim 时,不得不关机或重启终端程序来退出它 …
不过,这是个先苦后甜的过程。 如果前面花功夫去学,坚持用下去,甚至形成肌肉记忆,就会爱上它,而 vim 也会在后期带来惊喜。 熟练之后,自会入境,享受 「指随心动、码字如飞」的感觉。
Vim 中的学问很多,我用 vim 码字也蛮多年了,但也远远不敢妄称精通,只能说是经常用。
但是,只需要了解 vim 中少部分的知识点,就足够完成大部分的编辑工作。
我将基本内容总结为下面几块。
Vim - 5 种常用的模式
Normal
普通模式,Esc
或C-c
进入Visual
可视模式,v, V, C-v
等键进入Insert
插入模式,i, I, a, A, o, O
等键进入Command
命令模式,:
进入,常用的有::w
,:q
,:wq
,:%s
,q:
等Replace
替换模式,R
进入
普通模式是最常用的模式,其他模式都要从普通模式进入。
可以设置 set showmode
来显示当前的模式,此外也可以采用 lightline 插件, 可以在状态栏看到当前的 vim 模式和其他信息。
Vim - 快速移动光标 motion
- 字符粒度:
h j k l
左、下、上、右 - 单词粒度:
w W e E
向前,b B
向后 - 行内移动:
0
行首,$
行尾,f{c}
向前搜字符、F{c}
向后搜字符c
- 按块移动:
( )
句子、{ }
段落 等 - 翻页:
C-u
向上翻页,C-d
向下翻页 - 全文:文首
gg
,文尾G
,等价于:0
和:$
这些键位,最好结合其英文含义来理解, 比如说 w
是 “word” 的意思,e
是 “end” 的意思,b
是 “backward” 的意思, f
是 “find” 的意思,C-u
是 “up” 的意思 等等。
悄悄地说,我其实并未真正去记 hjkl
到底哪个向上、哪个向下,但是手熟了之后, 手放在键盘上自然就可以运用起来。这和许多人背不过键盘布局,但是仍然可以熟练打字是一样的。 我认为 vim 的键位更多地依赖于熟练度,而不是死记硬背。
我比较常用 f
跳转,有一款加强 vim 的 f
效果的插件,叫做 quick-scope, 它会自动高亮一些字符,方便 f
去跳转,小巧有趣。
对于行内跳转光标,有一款插件叫做 vim-skip , 它以 二分的形式 移动光标,s
向前移动到一半,S
向后移动一半, 是不是很聪明!正是由于这个插件,我经常使用 s
来二分跳进光标,可以很快地靠近编辑目标附近。
这些在 vim 中都叫做 motion, 它的重要之处不仅仅在于光标移动本身,还可以 和数字、文本编辑、visual
模式相结合,举例来说:
- 可以
4j
来直接向下移动 4 行、4e
来向前跳 4 个单词 等 可以用 motion 来帮助选择文本块,比如
vaw
会选中一个单词、v
进入visual
模式后可以hl
左右调整区域范围 等等结合文本编辑,例如:
de
可以删除当前位置到单词尾巴的内容,c$
可以清除当前位置到行尾的内容,c0
可以清除到行首的内容等。有一类 motion 叫做 文本对象 text objects, 例如
ciw
可以编辑一个单词 等等。有一款插件叫做 targets.vim ,它极大地扩充了可用的文本对象。 比如说
vi"
可选中双引号之内的内容,di)
可删除括号内的内容等等。
我使用 vim-skip 的 s
二分跳进 和 0 $
的频率是很高的, 因为它们可以在行内 大幅度地跳转光标。 当光标靠近想要编辑的文本时,才开始采用小粒度移动方式(按字符或者单词)。 我也几乎不用段落跳转 {
和 }
,而是直接使用翻页 C-u/d
,并不是说后者更好,而是说习惯一种就好。 人总是很难记住很多东西的,更多的情况是,用起来一些顺手了,就会经常用它们 。
Vim - 快速编辑文本
常用编辑快键位:
a
向右插入,i
向左插入,o
向下插入,O
向上插入x
删除一个字符,d
删除选中文本,dd
删除一行r
替换当前字符,R
进入替换模式u
撤销最近一次编辑J
把下一行提上来,合到当前行c
清空重新编辑、cc
清空当前行>
向右递进、<
向左递进,>>
、<<
缩进一行y
拷贝选中区域,yy
拷贝一行,p
粘贴
可以发现,对于一些操作,连续两次即可操作一行,例如 dd
, cc
, >>
, yy
等:
其中,一些编辑操作是可以结合数字使用,例如 4x
可以连续删除 4
个字符。 也可以结合前面所说的 motion ,例如 c$
可以清掉到行尾的内容。 还可以结合 visual mode
,例如选中一块区域后 >
来缩进 等等,不再展开。
Vim 中也可以对多行编辑:
比如要批量注释一段代码,可以
C-v
进入visual mode
,然后I
插入注释字符:单单对于注释多行来说,有一个更便捷的插件,叫做 vim-commentary, 可以直接选中多行,然后按
\\
就可以了 ( 相关key mapping 配置 )也可以把多行聚合成一行,
C-v
选中多行,然后J
即可:说到多行编辑,vim 的世界中有一个出名的插件叫做 vim-multiple-cursors ,不过它已经年久失修, 而且性能贼差。我在用的是 vim-visual-multi,还是很快的。 它的一个优点在于,我们可以在多行编辑时运用 vim motion,比如
w e b f
等。
另一类常见的编辑需求,是搜索和替换:
/{text}
当前文档内向后搜索文本,?{text}
向前搜索文本n
以继续下一个结果,N
以回到上一个搜索结果:%s/a/b/
当前文档内全局替换a
到b
默认地,在 vim 中搜索文本,是没有高亮的,可以设置 set hlsearch
。 有一个叫做 traces.vim 的插件, 它可以实时地高亮搜索命中的部分。
Vim - 窗口和标签页
Vim 也支持切屏和标签页,常用的操作有:
:spl
横向切屏、:vsp
纵向切屏C-w hjkl
来跳到不同窗口:tabnew
新建标签页gt
,gT
来切换标签页
我平时用切屏比较多,因为写代码时,经常需要一边写这里、一边写那里。
推荐两个插件:
- winresizer - 用
hjkl
的方式更方便地调整 vim 窗口的大小 (和 tmux 中类似) - zoomwintab.vim - 放大和缩小 vim 窗口 (和 shell 中的
C-z
, tmux 中的z
类似, 我也采用z
作为快捷键)
Vim - 开发和编程
大部分情况下,vim 都是用来做编程开发,在这一方面,它的表现丝毫不比流行的 IDE 差:
语法高亮
所有主流的编程语言,都有对 vim 的高亮的插件。对我而言,可能唯一的问题是, 有些编程语言的插件做的太臃肿了,它们提供一揽子配套,比如 vim-go, python-mode 等等, 但我一般只需要语法高亮,并不想去学习它们额外的一些命令、键位什么的,因为这些都不通用。 针对这种 “绑上编程语言 IDE 式” 的插件,我要么找更轻量的替代品,要么就 fork 出来,只扒出来语法高亮的部分用。
对于 nvim 来说,最好的代码高亮方案无疑是 nvim-treesitter, 它提供了一揽子式的、飞快的、增量式的语法高亮能力, 再也不用对每一个语言装一个基于正则的语法高亮插件了。
Git 集成
我没有在用 vim-fugitive 之类的插件, 因为我觉得这些事情都可以在 shell 中完成,也不必为用一个插件而单独去学习新的命令。
在用的一个插件叫做 vim-signify , 它可以显示出改了哪些行。
另一款在用的插件叫做 diffview ,它可以让我们一览所有改动的情况, 简单说,就是相比 vimdiff 多了导航栏。这是一款仅支持 neovim 的插件。 我一般用在 code review 中: 用 nvim diffview 做 code review。
查看当前文件的 blame 信息, 我是直接采用 tig ,不大喜欢 nvim-blame-line 之类的插件,它们以 VirtualText 形式展示当前行 blame 信息。 而是喜欢
tig blame
这种可以看到当前文件所有行的最新 commit 信息,并且可以跳进去看具体改动。vim 和 nvim 中的 tig blame
- 在 vim 中调用
:!tig blame %
即可 - 在 nvim 中则是
:terminal tig blame %
- 在 vim 中调用
缩进和不可见字符
对于写 Python 的人而言,显示缩进的层级可能非常重要,推荐 indentLine , 在 nvim 下的话则推荐 indent-blankline.nvim 。
事实上,其实我们也不需要这种显示缩进的插件,设置
listchars
是更轻量的无插件方案:vim/nvim 中设置不可见字符
" 显示不可见字符 set list " 设置不可见字符的展示字符 set listchars=space:·,tab:▸\ ,eol:¬,extends:❯,precedes:❮
此外,对于大部分编程语言,都不希望末尾带多余空白,虽然我们可以设置
eol
行尾符的可见展示方式,但不够显眼, 不如直接红色高亮行尾空白。vim/nvim 中配置高亮行尾多余空白和清理
function! HighlightExtraWhitespace() highlight ExtraWhitespace ctermbg=red guibg=#EC7063 match ExtraWhitespace /\s\+$/ endfunction autocmd BufWinEnter * if &buftype != 'terminal' | call HighlightExtraWhitespace() | endif "保存时自动清理行尾空白 :command WS :%s/\s\+$//e autocmd BufWrite * :WS
补全和定义跳转
补全和定义跳转,是对编程效率至关重要的一环。我在用的是 coc.nvim , 它支持大部分的编程语言, 速度上不快不慢,够用,大部分情况都表现良好。
coc 中,补全列表中的条目浏览采用
C-p
和C-n
,也符合 shell 中的快捷键风格。 定义跳转,我用gd
来映射。在编程中,相信和大家一样,我是非常依赖补全和定义跳转的。
2022 年 10 月更新: 目前我已经切换到 nvim-cmp ,感觉上更轻更快, 但是仍然很佩服 coc.nvim 的成熟度和美好体验,coc 做的很友好、很用心。
格式检查
许多编程语言都有一套约定俗成的风格和检查工具,比如 black 之于 Python,clang-format 之于 C/C++, gofmt 之于 Golang 等等。Vim 中也有支持格式检查的插件,比如 ale , 它可以在编辑保存时,自动格式化代码,目前我用上去没觉得卡。
顺带一提,目前在用的配色是 PaperColor ,用了好久了, 中间偶尔会烦一下,换换配色、换换心情,不过,最终又总是回到这个配色上来。
Vim 的键位集中在字母区,大部分情况下,在 vim 中编辑,手是不用离开键盘的。 话说,是不是许多 HHKB 用户都喜欢用 vim 呢?
如果非要去理解 vim 编辑器之高效到底来自何处,恐怕只能亲身体会才能知晓。我看来,高效的不是 vim 本身, 而是它帮用户养成的编辑习惯。
目前有一款社区维护的、脱胎于 vim 的编辑器,叫做 NeoVim , 它支持 lua 语言的插件, 对 LSP 作了 内建支持, 而且完全兼容 vim ,在社区驱动下,neovim 的迭代要比 vim 快多了,社区生态也是遍地开花。 不过我仍然没有离开 vim8,因为目前为止还找不到什么动力去换,或许未来会尝试切过去试一段时间, 所谓, 生命不息,折腾不止 嘛。
2022 年 10 月 3 日 更新:
目前我已完全切到了 NeoVim 上, 尽管 vim 9 已经发布 , 但是我认为 nvim 的迭代速度更快、更开放,未来可期。
- 补全插件我切换到了 nvim-cmp, 体感上比 coc.nvim 更轻快。
- 语法高亮都切到了 nvim-treesitter 。
2024 年 7 月 17 日 更新:添加 tmux 配置小窗边框颜色的配置说明。
结尾语 ¶
命令行下的快捷键虽然多,但是不同工具的快捷键,都具有一定的共通性。 而这些快捷键熟练之后,将体会到,键盘操作是比鼠标要快的。
在配置方面,许多人都把配置做成了仓库托管在 github 上 , 我的在这里 - hit9/dotfiles。
最后,天下神器,因人而异。不同的工具在不同的人手上、发挥的效果不尽相同。 工具的强大,因为它们的高上限,而最终威力几何,取决于执剑之人 。
神兵之神,不在兵器本身,而在于用兵器的人。
(完)