又又又又开始学 Vim 了😪

为了能像 Gilles Castel 那样记笔记(用 Vim + snippets 居然可以在课堂上同步记数学笔记😱),我又又又又一次捡起了 Vim 。感觉 Vim 之所以这么难学,是因为没一篇教程写对路了的😒。

我的最初想法是重现一个新手可能会遇到的问题,寻找原生的解决方案 & 更优雅的方案。不过回头看,更加深切地感受到,这么多年过去,Vim & Emacs 的对手(各种 IDE )换了一波又一波,它俩却还屹立在那,不得不说其设计中有很多先进那个时代、即使在今天仍不过时的思想(当然,也必然存在很多缺陷。当我们认识了这些缺陷,并知道原生如何解决、以及如何更好地解决,使用插件🧩就更加得当)。就算从程序设计的角度,Vim 仍然值得深入学习。

Unix 上最早的文本编辑器是 ed ,而后经过几代的改进,包括 em (editor for mortals) ,en ,最终到 ex 。再之后才是 vi ,Vim (vi improved) 。这段有趣而没用的历史,我一定要告诉你。

1. 打开 & 退出

  • 用 Vim 打开某份文件:vim a.txt
  • MD,怎么卡死了!<ctrl-w> 也退不出去🤯!
  • 哦,要按 i (insert) 进入「编辑模式🖋[1]」才可以写字😒;
  • MD,ctrl-s 怎么保存不了🤯!
  • 哦,要按 <esc> 退出「编辑模式🖋」,进入到「思考模式🤔[2]」才能执行命令;
  • 保存 & 退出::wq (其实是进入了「命令行模式」);

这么会有这么反人性的设计😒。改下配置 vim ~/.vimrc (即,告诉 Vim 你的使用习惯)。当然,你可以改成熟知的 ctrl + s( Vim 习惯写成 c-s ),但为了符合 Vim 的用键传统,还是用单字母吧:

" Save & quit
map Q :q<CR>
map S :w<CR>

现在你可以用 S 保存,按 Q 退出了。

但是,要是在新文件里写了点什么,怎么保存呢?:w <new_filename>

map S :write %<CR>  " % :活动缓冲区的完整文件路径。

其实,这样写也不准确。改变原生键位最好准确指定起效的模式,要是能给出原生键位的替代方案就更好了。比如,幸运的是,不会和 surround.vim 的 S 命令冲突。

" Save & quit
nnoremap S :w %<CR>     " ⚠️ 幸运的是,不会和 surround.vim 的 S 命令(只在 visual mode 下起效)冲突。
nnoremap Q :q<CR>

听人说,Vim 的强大来自「多模式」?呵呵,你也可以将「多模式」理解为「反人性」(例如:同一键位在不同的模式下作用可能天差地别。详见下表)。∴别再说什么「「多模式」是 Vim 之髓」了😓。我认为,Vim 的强大源于它既提供了粗粒度的操作,又提供了细粒度的操作。强大的工具其实莫不如是,比如 PS 。后面再详细解释。

no. 操作 思考模式🤔 可视模式🌈 编辑模式🖋
::no.:: i & a 进入「编辑模式🖋」插入 (insert / append) (或「思考模式🤔」下 <operator> 后)i<text-object>(inner / inside) & a<text-object>(arround / all)
::no.:: o 进入「编辑模式🖋」并插入新行 在高亮选区两端来回切换
::no.:: c-r 重做 (redo) <c-r><register> 意为插入寄存器 register 的内容

2. 怎么对调 caps lockesc

你听到的第一个建议,大概率是改键:将 <caps lock> 改为 <esc> 。这件事在 MacOS 上原生自带:

Windows 上也不难,下一个 PowerToys ,用里面的 Keyboard Manager 就搞定。

最麻烦的是 Linux ,折腾了很久都没有成功😓。

3.界面太丑怎么办🥴🤢🤮?

Vim 最为人诟病的就是「记忆负担太重」。比如:在不同的模式之间切换,完全凭脑力。再比如什么 marks 啦、buffers 啦、tabs 啦……原厂的统统不显示。

最简单的改造方式是高亮显示当前行 / 列:

set cursorline
set cursorcolumn

可以装个叫 vim-airline 的美化插件😍,至少不同模式的颜色不同。但你得先装个管理插件的插件 vim-plug

装好以后在 ~/.vimrc 里写:

call plug#begin()
" ...
call plug#end()

现在你终于可以装 vim-airline 了:

call plug#begin()

Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'

call plug#end()

let g:airline_theme = 'simple'

airline 除了好看,一定要把 Smarter tab line 打开:

let g:airline#extensions#tabline#enabled = 1

现在,当你打开多个文件 vim *.md ,就可以用 :bprevious & :bnext 来回切换缓冲区 (buffers) 了。太蠢了是不🤢🤮?还是改个快捷键吧。这是从 Tim Pope 的 unimpaired.vim 那抄来的:

" 快速遍历 Vim 列表
" ⚠️ 加 ! 后可以强制切换缓冲区。
nnoremap <silent> [b :bprevious!<CR>
nnoremap <silent> ]b :bnext!<CR>
nnoremap <silent> [B :bfirst!<CR>
nnoremap <silent> ]B :blast!<CR>

你最好再装个 Powerline

但还是没有解决 marks、buffers、tabs 的提示问题啊?那还得靠插件:

4. 怎么在窗口间切换啊?

当你装插件上瘾以后,比如 NERDTreeUndo Tree,会遇到一个问题,怎么切换到新开的窗口上呢?

原生命令是:

命令 效果
<C-w>w 在窗口间循环切换 🔁
<C-w>h 切换到左边的窗口 ⬅️
<C-w>j 切换到下边的窗口 ⬇️
<C-w>k 切换到上边的窗口 ⬆️
<C-w>l 切换到下边的窗口 ⬇️
<C-w>c 关闭活动窗口 ❌

但还是喜欢 @TheCW 的改法:

" ===
" === Window management
" ===
" Set <LEADER> as <SPACE>
let mapleader="\<space>"
" Use <space> + new arrow keys for moving the cursor around windows
map <LEADER>w <C-w>w
map <LEADER>k <C-w>k
map <LEADER>j <C-w>j
map <LEADER>h <C-w>h
map <LEADER>l <C-w>l

5. 最纠结的改键😵

排名 原生键位 想改成 改键原因 得失
::no.:: : ; 需要频繁进入 Ex mode 。 ; & , 是一对操作。
::no.:: <Leader>[3] 用哪个?缺省是 \

6. 常用连招

从按键效率来说,当然是「单键」>「双击单键」>「易记的键组合」>……:

no. 快捷键 效果 初始模式 切入模式
::no.:: A (等效于 $a)在行尾添加文本。 normal mode🤔 insert mode🖋
::no.:: I (等效于 ^i)在行首添加文本。 normal mode🤔 insert mode🖋
::no.:: o (等效于 A<CR>)在当前行下方新起一行。 normal mode🤔 insert mode🖋
::no.:: O (等效于 ko)在当前行上方插入一行。 normal mode🤔 insert mode🖋
::no.:: C (等效于 c$ normal mode🤔 insert mode🖋
::no.:: s (等效于 cl)删掉光标下的字符,然后进入插入模式。即,替换光标下的字符。 normal mode🤔 insert mode🖋
::no.:: S (等效于 ^c normal mode🤔 insert mode🖋
::no.:: dd 删除当前行。 normal mode🤔 normal mode🤔
::no.:: >> 增加当前行缩进。 normal mode🤔 normal mode🤔
::no.:: << 减少当前行缩进。 normal mode🤔 normal mode🤔
::no.:: ea 在单词结尾 (end) 添加文本。 normal mode🤔 insert mode🖋
::no.:: gf go to file. normal mode🤔 normal mode🤔
::no.:: xp 调换光标之后的两个字符。 normal mode🤔 normal mode🤔
::no.:: gUU 将当前行整行转换为大写。 normal mode🤔 normal mode🤔
::no.:: yyp 复制当前行,并粘贴在下方。 normal mode🤔 normal mode🤔
::no.:: daw delete a word. normal mode🤔 normal mode🤔
::no.:: vit visully select inside the tag.
::no.:: gv 重选上次的高亮选区。
::no.:: f,dt. 删除句子的后半段。 normal mode🤔 normal mode🤔
::no.:: qaq 清空寄存器 a
::no.:: gUaw 将当前单词转换为大写。 normal mode🤔 normal mode🤔

7. 成对操作🎎

我觉得,学 Vim 完全可以比照学二外的方式——比较 & 联系。

no. 快捷键 效果 初始模式 切入模式
::no.:: a v.s. A 从后方 (append) 插入。 normal mode🤔 insert mode🖋
::no.:: i v.s. I 从前方插入 (insert) 。 normal mode🤔 insert mode🖋
::no.:: n v.s. N 下一处 (next) 。
::no.:: o v.s. O 插入新行。 normal mode🤔 insert mode🖋
::no.:: v v.s. V 进入 Visual mode 。
::no.:: f<char> / F<char> v.s. t<char> / T<char> 正向 / 反向行内查找 <char> ,区别在于包不包括 chartill 不包括)。 normal mode🤔 normal mode🤔
::no.:: ; v.s. , 继续寻找与调转方向搜寻前次搜寻的位置。 normal mode🤔 normal mode🤔
::no.:: /<pattern><CR> v.s. ?<pattern><CR> 文内查找。 normal mode🤔 comand mode🎛
::no.:: <C-a> v.s. <C-x> 对当前行其后最近的数字执行加 / 减操作。 normal mode🤔 normal mode🤔
::no.:: . v.s. u 重复与撤回。 normal mode🤔 normal mode🤔
::no.:: normal mode🤔下的命令 v.s. Ex 命令 ⚠️:normal mode🤔下的命令适合在本地操作,而 Ex 命令则可远距离操作。比如: p v.s. :t (copy To) 。
::no.:: <c-]> v.s. :tag <keyword> 跳转到 tag 到定义处。
::no.:: mm v.s. ``m` 标记位置📌 m / 跳转到标记📌 m
::no.:: (in visual mode)o v.s. (in normal mode)% 在高亮选区两端来回切换 v.s. 在括号(([{ v.s. }]))间跳转 。
::no.:: <c-o> v.s. <c-i> 在跳转列表 (:jumps) 中后退 / 前进(📢注意:低头看一下,在 qwerty 键盘⌨️中,i o 是紧挨在一起的)。
重复类型 重复操作符 回退操作符
文本编辑重复 . u
行内查找重复 ; ,
全文查找重复 n N
文本替换重复 & u
宏重复 @<register> u

8. 插件🧩

no. 插件名 用途 原生解决方案
::no.:: NERDTree 文件管理 netrw,标配插件,across NETwork Read and Write files 的意思。
::no.:: coc-yank 可视复制
::no.:: vim-peekaboo 寄存器增强。(Peekaboo extends " and @ in normal mode and <CTRL-R> in insert mode so you can see the contents of the registers.)
::no.:: Undo Tree
::no.:: vim-devicons 美化插件:添加图标
::no.:: vim-table-mode 美化插件:增强表格
::no.:: vim-signature 增强书签📌 marks
::no.:: vim-gitgutter 在行号栏显示修改状态(必须置于 Git 看管之下)。 (changs list):changes & g;, g,
::no.:: vim-surround 增强 text object ,实现快速环绕编辑。请和 wildfire.vim 配合食用。
::no.:: wildfire.vim 按下 <enter> 就能智能选中最近的文本块。请和 vim-surround 配合食用。
::no.:: vim-expand-region 快速扩大 / 缩小选中区域
::no.:: vim-commentary 注释
::no.:: NERD Commenter 注释
::no.:: coc.nvim 补全🤖️
::no.:: ctrlp.vim
::no.:: Tagbar tag 导航
::no.:: vim-markdown MarkDown 增强
::no.:: markdown-preview.nvim MarkDown 预览

从 @theCW 那抄来的超有用的 MarkDown 速记技巧

动作 用途
,b 加粗
,d code
,c 代码块
,p 图片🎨
,a 链接🔗
,f 跳转到下一定位点 <++>
autocmd Filetype markdown inoremap ,f <Esc>/<++><CR>:nohlsearch<CR>c4l
autocmd Filetype markdown inoremap ,n ---<Enter><Enter>
autocmd Filetype markdown inoremap ,b **** <++><Esc>F*hi
autocmd Filetype markdown inoremap ,s ~~~~ <++><Esc>F~hi
autocmd Filetype markdown inoremap ,i ** <++><Esc>F*I
autocmd Filetype markdown inoremap ,d `` <++><Esc>F`i
autocmd Filetype markdown inoremap ,c ~~~<Enter><++><Enter>~~~<Enter><Enter><++><Esc>4kA
autocmd Filetype markdown inoremap ,h ====<Space><++><Esc>F=hi
autocmd Filetype markdown inoremap ,p [图片上传失败...(image-cd8e3a-1663893306192)] <++><Esc>F[a
autocmd Filetype markdown inoremap ,a [](<++>) <++><Esc>F[a
autocmd Filetype markdown inoremap ,1 #<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,2 ##<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,3 ###<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,4 ####<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,l --------<Enter>

Ref📚


  1. 本应译为「插入模式🖋」,但我不喜欢这个翻译。

  2. 借用 @Drew Neil 在《Practical Vim》里的话就是:画家在休息时不会把画笔放在画布上。对 Vim 而言也是这样,normal 模式就是 Vim 的自然放松状态。所以我更喜欢把 normal mode 称之为「思考模式🤔」。

  3. 用来自定义用户自己的名字空间。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章