《Mastering Vim》读书笔记 - 第二部分
vim 工具 vim
Lastmod: 2020-09-20

本文作为第二部分没有什么图片了,使用的vim编辑的,用了tenfyzhong/tagbar-markdown插件后,连vnote好像就可以不用了,vim威武。

Build, Test, and Execute

本章主要讲了git的基础用法,git和vim怎么结合使用,看本章的主要收获有两个:一是介绍非常好用的git插件tpope/vim-fugitive,二是对vimdiff以及怎么使用vimdiff解决冲突有了更清晰的认识。

tpope/vim-fugitive的使用,请看文章后面专门讲插件使用的章节。这里主要讲怎么使用vim作为git的冲突解决工具和怎么解决冲突进行说明。

可以使用vimdiff对比两个文件,比如vimdiff a.py b.py,当然,也可以多个文件对比vimdiff a.py b.py c.py

vimdiff中,如果对比两个文件,有以下操作:

  • ]c 可以移动到下一个有区别的行,[c可以移动到上一个有区别的行
  • do或者:diffget会将对比的window变化移动到active window。:%diffget是对整个文件操作。
  • dp或者:diffput会将active window中的变化拉取到对比的window。:%diffput是对整个文件操作。

当对比多个文件时,:diffput:diffget后面可以跟一个空格和文件名表示和active window对比的window。

配置vimdiff作为git的merge工具:

$ git config --global merge.tool vimdiff
$ git config --global merge.conflictstyle diff3
$ git config --global mergetool.prompt false

当使用git合并代码出现冲突时,可以使用git mergetool命令来使用vimdiff解决冲突。 此时,会显示4块内容,形如:

|A|B|C|
|  D  |

最左上角的window,即A表示LOCAL changes,就是本地提交的最新的代码与冲突代码最近的父代码的变化。B表示Base,就是与冲突代码最近的父代码。C表示REMOTE,就是要合并的远端的冲突代码。D表示MERGED,就是合并结果了。

D中冲突的代码部分是以下格式:

<<<<<<< [LOCAL commit/branch]
[LOCAL change]
||||||| merged common ancestors
[BASE - closest common ancestor]
=======
[REMOTE change]
>>>>>>> [REMOTE commit/branch]

使用:diffg R来在冲突的地方使用REMOTE(即上图C)中的代码,:diffg B来在冲突的地方使用BASE中的代码,:diffg L在冲突的地方使用LOCAL的代码。

本章接下来的内容讲到了tmux, screen和vim的terminal模式。tmux还是很有用的。特别是在mac os下使用iTerm,此软件将tmux集成的非常好,这个是另外的主题了,今后可以单独开文章总结一下。

screen就没必要用了,有了tmux,就不用screen了。vim的terminal模式觉得并不方便,还不如使用tmux或者iTerm多开shell了。

Refactoring Code with Regex and Macros

Search or replace with regular expressions

如果只是搜索,在命令模式下使用/xxx就行了,回车后,n键是跳到下一个,shift+n是跳到上一个匹配的结果。

Search and replace

:s/<find-this>/<replace-with-this>/<flags> 是当前行搜索/替换的命令模式

比如: :s/cat/dog会搜索当前光标所在行,并将找到的第一个cat替换为dog

常用的flags有

  • g 全局替换,即替换搜索到的所有结果
  • i 搜索时忽略大小写
  • I 搜索时不能忽略大小写
  • c 每次替换前进行确认
  • e 如果没有搜索到,不显示错误

扩展用法是:<范围>[;<范围>]s[新的分隔符, 可选]/<find-this>/<replace-with-this>/<flags>

范围可以是以下形式:

  • 数字 表明是第几行
  • $ 文件的最后一行
  • % 整个文件
  • /search-pattern/ 匹配某一行
  • ?backwards-search-pattern? 和前一个一样,不过是向前搜索来匹配一行

多个范围使用;来组合,比如20;$表示第20行和最后一行

:12;/dog/s/animal/creature/g将第12行和当前行后某行含有dog的行中的animal全部换成creature

最常用的就是:%s/dog/cat/g,就是将文件当中所有dog换成cat

如果搜索或者替换的字符串中含有/,即分隔符,可以使用新的分隔符来替换,比如下面两个是等价的: :s+path/to/dir+path/to/other/dir+gc:s/path\/to\/dir/path\/to\/other\/dir/gc

Operations across files using arglist

使用arglist进行跨文件的搜索和替换,这种使用场景个人遇到的太少,所以就不写了。真多多文件的文本查找使用grep/ag/ack等等命令应该更简单和快速,替换的话用sed吧。所以个人觉得还是不用arglist好。。。

Regex basics

搜索和替换命令中可以使用正则表达式。

vim的搜索和替换的正则表达式中的特殊字符需要使用\转义,比如\(c\|p\)arrot会匹配carrot和parrot。\warrot\?撇配carrot, parrot, farro等等,注意\w的含义是word字符。t\?表明t是可选的。pa.\+ot可以匹配parrot, patriot, pa123ot等等。.\+表明一个或多个字符。.+

特殊字符:

  • . 任何字符,除了行结尾

  • ^ 一行开头

  • $ 结尾 上面三个和大部分语言的正则表达式类似

  • \_ 任何字符,包括行结尾

  • \< word的开头

  • \> word的结尾

使用:help ordinary-atom来看相关帮助

常用的字符类别: 可以使用:help character-classes来看相关帮助

  • \s 空白,空格或者tab
  • \d 数字
  • \w word字符

分组:

  • \|
  • \(\) 分组是很好用的,例子::s/\(cat\) hunting \(mice\)/\2 hunting \1

重复:

  • * 0或者多个,贪婪的(贪婪的意思是最大匹配)
  • \+ 1个或者多个,贪婪的
  • \{-} 0或者多个,非贪婪的
  • \? 或者 \= 0个或者1个,贪婪的
  • \{n,m} n个到m个,贪婪的, m不写\{n,}就是n个到多个
  • \{-n,m} n个到m个,非贪婪的, m不写\{-n,}就是n个到多个

可以使用:help multi来查看相关帮助

再说下贪婪,对于foo2bar2来说,\w\+2会匹配foo2bar2\w\{-1,}2会匹配foo2

搜索和替换还有Magic、No Magic和Very Magic之分(写到这里,表示已经崩溃了:))。默认是Magic模式。主要是对特殊字符来说的,不详细写了,感觉先用好默认的Magic模式吧。

正则表达式还是很强大的,本人曾使用100个正则表达式将一个10年的php项目进行了简单的重构。。。没有出现大问题。。。这里不是想说自己正则牛逼(是被逼)只是想说明人们在写代码中,默认就会遵循某种模式,使用正则可以将这些模式提取出来。

Recording and playing macros

TODO: 记录和宏,暂时没有用到这么高级的功能

其实本章主要是将重构在代码操作层面的工作。还好vim-go提供了强大和精准的重构功能,让自己不用使用这种字符串替换的方式来进行重构,感谢!

其实本章主要是将重构在代码操作层面的工作。还好vim-go提供了强大和精准的重构功能,让自己不用使用这种字符串替换的方式来进行重构,感谢!

Making Vim Your Own

总结一下,本章主要是讲了几点:

  • 将.vimrc使用版本管理管理起来,俺的vimrc项目在这块应该做的比较好了:)傲娇一下。
  • 养成好的习惯。

It’s important to take time to go back, reflect, and make sure your .vimrc doesn’t become a pile of unneeded aliases, functions, and plugins.

Once in a while, take the time to go back into your .vimrc and clean up unnecessary functions and plugins, or reove key bindings you don’t use any more.

Transcending the Mundane with Vimscript

翻译过来是:使用vimscript,超越平凡

本章主要是讲解了vimscript语法,vimscript和很多脚本语言一样,也是图灵完备(Turing-complete)的,能做很多事情。说到计算机语言,肯定就有变量,类型,控制流,函数,封装等等。。。

本章还以一个自定义插件为例子,讲解了怎么使用vimscript开发插件,很有参考价值。主要是要理解插件的目录结构,

到这里,终于可以大概看下vim-go的逻辑了:)

这里就不详细写了,可以将原书本章当做参考书使用。

需要记住的点:

  • vimscript没有对象概念,但是可以通过类似于abc#xxx这样的函数名来模拟类似的抽象概念。

本章到最后,还给出了接下来学习vimscript的资源Learn Vimscript the Hard Way

Neovim

本人目前主要使用vim,这里就忽略了。

常用插件使用

本章综合了书中介绍的插件和自己使用vim插件的经验,借此推广一下自己的vim配置开源项目tomjamescn/vimrc,直接使用此项目,再结合本节说明即可

这里列出的插件不分优先顺序,功能不同而已,插件名称都是abc/xyz模式。

下面插件的源码都在github.com上,通过github.com/abc/xyz就可以访问

ctrlpvim/ctrlp.vim

此插件提供模糊搜索文件名功能

ctrl+p可以打开当前目录下的文件名的模糊搜索功能,很方便,但是性能不是特别好,TODO:今后可以看看原因,目前暂时够用了。

对于搜索到的文件,使用回车将在当前窗口中打开,如果想新开窗口,可以使用ctrl+t。

scrooloose/nerdtree

此插件提供目录树功能

下面的快捷键绑定下,可以使用F7来打开目录树,再按一次F7将关闭目录树

nmap <F7> :NERDTreeToggle<CR>

mileszs/ack.vim

此插件提供在vim内进行文件内容搜索的功能

使用此插件前,需要安装ack或者ag 下面的配置是说如果有ag的情况下,使用ag而不是使用ack。

if executable('ag')
  let g:ackprg = 'ag --vimgrep'
endif

majutsushi/tagbar

此插件提供当前当前源码文件变量,函数和方法的说明

使用此插件前,需要安装ctags。官网有链接。 按F8打开或者收起边栏。

nmap <F8> :TagbarToggle<CR>

terryma/vim-expand-region

此插件提供使用一个键来扩展选择的功能,很实用,看看官网的gif图就知道了

在命令模式下,可以使用+来选择word,在visual模式下,使用shift++来选择word

bling/vim-airline

vim定制主题框架,在vim-airline/vim-airline-themes中有很多可用主题 我使用的是let g:airline_theme='luna'luna主题,感觉看着还行。

maralla/completor.vim

此插件利用vim8的异步功能,提供异步提示的特性。

vim8下自动提示的插件很多,使用此插件是因为此插件还提供了文件路径的自动提示功能,在输入路径时很好用,还有一点,这个项目的creator是国内上海的一位大神,支持国货:)

此插件和vim-go配合的也比较好,目前没有发现什么问题。

下面是我的快捷键绑定,出现提示后,按tab键就会切换到下一个候选,按shift和tab就会切换到上一个候选。

inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
inoremap <expr> <cr> pumvisible() ? "\<C-y>\<cr>" : "\<cr>"

sjl/gundo.vim

自己对undo和redo的需求不是特别强烈,暂时没有使用这个插件

tpope/vim-fugitive

提供了vim和git的集成,很好用。

:Gstatus :Glog :Gblame

tenfyzhong/tagbar-markdown

支持在majutsushi/tagbar中显示markdown文件的层次标题

写markdown时很好用

fatih/vim-go

vim的go ide环境,太好用了!

建议看官方教程,我的vimrc项目对配置进行了封装,也可以看下。