文章目录

  • Vim script
  • 打印输出和字符串
  • 变量
  • 数字
  • 复杂数据结构
  • 表达式
  • 控制结构
  • 函数和匿名函数
  • 重要命令
  • 事件
  • 内置函数
  • 四种模式
  • 正常(normal)模式
  • 插入(insert)模式
  • 可视(visual)模式:v/V
  • 命令行(command-line)模式
  • vim的键描述
  • Vim脚本语言
  • 备份和撤销文件
  • 鼠标支持
  • 中文支持
  • 图形界面的字体配置
  • 光标移动
  • 文本修改
  • 文本对象选择d/y/c
  • 演示 a、i 和 w、双引号、圆括号搭配使用
  • 其他搭配
  • 对多个(层)文件对象进行操作
  • 更快地移动
  • 重复
  • vim的运行支持文件
  • syntax:Vim 的语法加亮文件
  • doc:Vim 的帮助文件
  • colors:Vim 的配色方案
  • plugin:Vim 的“插件”,即用来增强 Vim 功能的工具
  • 用户的vim配置目录
  • vim软件包
  • 安装minpac包管理器
  • 多文件打开与缓冲区:复制粘贴的正确姿势
  • 复制粘贴
  • 多文件的打开方式
  • 工作流
  • 缓冲区的管理和切换
  • 窗口和标签页:修改、对比多个文件的正确姿势
  • 多窗口编辑
  • 双窗口比较
  • 多标签页编辑
  • 正则表达式
  • 正则表达式搜索
  • 最长匹配和最短匹配
  • 正则表达式替换
  • 编程支持
  • 查看文档
  • 自动完成
  • 记录


Vim script
打印输出和字符串
  • Vim 里使用 "或’ 来引起一个字符串。
  • 可以在 ’ 括起的字符里把 ’ 重复一次来得到这个字符本身,即 ‘It’‘s’ 相当于 “It’s”。
  • 字符串可以用 . 运算符来拼接。字典访问也可以用 .
  • 可以使用 . 或 … 进行字符串拼接。
echo 'Hello world!'
变量
# 变量可以用 let 命令来赋值
# Vim 的变量可以手工取消,需要的命令是 unlet。
let answer = 42
echo 'The meaning of life, the universe and everything is ' . answer
数字
复杂数据结构

Vim 脚本内置支持的复杂数据结构是列表(list)和字典(dictionary)。

  • 列表(list)
let primes = [2, 3, 5, 7, 11, 13, 17, 19]
# 可以用下标访问,比如用 primes[0] 就可以得到 2。
  • 字典(dictionary)
# Vim 脚本的续行——下一行的第一个非空白字符如果是 \,则表示这一行跟上一行在逻辑上是同一行
let int_squares = {
      \0: 0,
      \1: 1,
      \2: 4,
      \3: 9,
      \4: 16,
      \}
      
# 键会自动转换成字符串,而值会保留其类型。
# 访问字典里的某一个元素可以用方括号,如 int_squares['2'];或使用 .,如 int_squares.2。
表达式
  • Vim 脚本的表达式里可以使用括号,可以调用函数(形如 func(…))
  • 支持加(+)、减(-)、乘(*)、除(/)和取模(%)
  • 支持逻辑操作(&&、|| 和 !)
  • 还支持三元条件表达式(a ? b : c)
  • == 和 != 运算符对所有类型都有效
  • 而 <、>= 等运算符对整数、浮点数和字符串都有效
  • 对于文本处理,常见的情况是我们使用 =~ 和 !~ 进行正则表达式匹配,前者表示匹配的判断,后者表示不匹配的判断。比较操作符可以后面添加 # 或 ? 来强制进行大小写敏感或不敏感的匹配(缺省受 Vim 选项 ignorecase 影响)。表达式的左侧是待匹配的字符串,右侧则是用来匹配的正则表达式
  • 在表达式的左侧,需要有 echo 这样的命令
  • 如果你只想调用一个函数,而不需要使用其返回的结果,则应使用 call func(…) 这样的写法
  • 我们在插入模式和命令行模式下都可以使用按键 =(两个键)后面跟一个表达式来使用表达式的结果
  • 在替换命令中,我们在 = 后面也同样可以跟一个表达式,来表示使用该表达式的结果。
  • 当前编辑文件的每一行前面插入行号和空格:
:%s/^/\=line('.') . ' '/
  • line 是 Vim 的一个内置函数,line(‘.’) 表示“当前”行的行号
控制结构
  • 在 while 和 for 循环语句里,你可以使用 break 来退出循环,也可以使用 continue 来跳过循环体内的其他语句。
# 每种结构都要用一个对应的 endif、endwhile 和 endfor 来结束
" 简单条件语句
if 表达式
  语句
endif

" 有 else 分支的条件语句
if 表达式
  语句
else
  语句
endif

" 更复杂的条件语句
if 表达式
  语句
elseif 表达式
  语句
else
  语句
endif

" 循环语句
while 表达式
  语句
endwhile

" for循环
for var in object
  这儿可以使用 var
endfor
函数和匿名函数
function 函数名(参数1, 参数2, ...)
  函数内容
endfunction

# 匿名函数

echo map(range(1, 5), {idx, val -> val * val})
重要命令
  • execute(缩写 exe):它能用来把后面跟的字符串当成命令来解释。
  • source(缩写 so)命令:它用来载入一个 Vim 脚本文件,并执行其中的内容。
  • map 系列键映射命令:
  • set
  • noremap、inoremap
  • let
事件
内置函数
四种模式
正常(normal)模式
插入(insert)模式
  • i(insert):在光标前面进入插入模式;
  • I 则相当于 ^i,把光标移到行首非空白字符前然后进入插入模式。
  • a(append):在光标后面进入插入模式
  • A:在光标所在的行尾进行插入
  • o:在光标的下一行 进行输入
  • O:在光标的上一行 进行输入
可视(visual)模式:v/V

用于选定文本块

V:进入可视行模式

命令行(command-line)模式

用于执行较长、较复杂的命令;

  • 进入命令行模式 ::
  • 搜索:/ ?
vim的键描述
  • 表示 Esc 键;显示为“⎋”
  • 表示回车键;显示为“↩”
  • 表示空格键;显示为“␣”
  • 表示 Tab 键;显示为“⇥”
  • 表示退格键;显示为“⌫”
  • 表示删除键;显示为“⌦”
  • 表示光标上移键;显示为“⇡”
  • 表示光标下移键;显示为“⇣”
  • 表示光标左移键;显示为“⇠”
  • 表示光标右移键;显示为“⇢”
  • 表示 Page Up 键;显示为“⇞”
  • 表示 Page Down 键;显示为“⇟”
  • 表示 Home 键;显示为“↖”
  • 表示 End 键;显示为“↘”
  • <S-…> Shift 组合键;显示为“⇧”
  • <C-…> Control 组合键;显示为“⌃”
  • <M-…> Alt 组合键;显示为“⌥”
  • <D-…> Command 组合键;显示为“⌘”(Mac 键盘)
Vim脚本语言
syntax on:打开语法高亮

let mapleader=" "

set enc=utf-8:配置语言
set number:显示行号
set cursorline:设置游标线
set wrap:设置文字区间不超过当前屏幕
set showcmd:在底下显示输入的命令
set wildmenu:命令补全,按Tap
set mouse=a

noremap n h:在键盘上按n时输入的是h键
noremap u k
noremap e j
noremap i l
noremap k i
noremap K I
noremap l u
noremap <LEADER><CR> :nohlsearch<CR> # nohlsearch:no high light search
方便搜索时上下查找:
noremap = nzz
noremap - Nzz

map s <nop>:让在正常模式下的s键无效
map S :w<CR>:映射,当按下S键时,输入的是:w<CR>,即保存
map Q :q<CR>:设置按下Q退出vim
map R :source $MYVIMRC<CR>:按下R即刷新配置文件

source $VIMRUNTIME/vimrc_example.vim:导入 Vim 的示例配置(这会打开一些有用的选项,如语法加亮、搜索加亮、命令历史、记住上次的文件位置,等等)

正常模式下:
<operation><motion>:操作,加一个动作

命令行模式下:
:color blue/darkblue/default:选择主题
备份和撤销文件
set nobackup
set undodir=~/.vim/undodir


if !isdirectory(&undodir)
  call mkdir(&undodir, 'p', 0700)
endif
鼠标支持
if has('mouse')
  if has('gui_running') || (&term =~ 'xterm' && !has('mac'))
    set mouse=a
  else
    set mouse=nvi
  endif
endif
中文支持
set fileencodings=ucs-bom,utf-8,gb18030,latin1
图形界面的字体配置
  • windows
if has('gui_running')
  set guifont=Courier_New:h10
endif
  • 在 Ubuntu 下把字体设成 10 磅的 DejaVu Sans Mono
" Linux 和 Windows 不同,不能用 '_' 取代空格
set guifont=DejaVu\ Sans\ Mono\ 10
  • 宽字符字体配置
set guifontwide=Noto\ Sans\ Mono\ CJK\ SC\ 11
光标移动
  • w(word):向后跳转一个单词。小写的跟编程语言里的标识符的规则相似,认为一个单词是由字母、数字、下划线组成的(不严格的说法)。
  • W:向后跳转一个单词。大写的命令则认为非空格字符都是单词。
  • b(back):向前跳转一个单词。小写的跟编程语言里的标识符的规则相似,认为一个单词是由字母、数字、下划线组成的(不严格的说法)。
  • B:向前跳转一个单词。大写的命令则认为非空格字符都是单词。
  • f(find)和 t(till):寻找字符

它们的作用都是找到下一个(如果在输入它们之前先输入数字 n 的话,那就是下面第 n 个)紧接着输入的字符。两者的区别是,f 会包含这个字符,而 t 不会包含这个字符。

This is vim: the best editor out there.
当光标在T的上面时:使用于d/y/c,即删除、复制、剪切
df:(f:表示从光标寻找到最近的一个:):从光标一直删除到冒号
dt:(t:表示从光标寻找到最近的一个:):从光标一直删除到冒号前,即不包括冒号本身
  • ( 和 ) 移到上一句和下一句
  • { 和 } 移到上一段和下一段
  • gg、:跳转到文件的开头
  • :跳转到文件的结尾
  • G:跳转到最后一行的第一个字符,而不是最后一个字符
文本修改
  • d(delete) 加动作来进行删除(dd 删除整行);D 则相当于 d$,删除到行尾。
d<数字><方向键>:往相应的方向删除对应的数字
  • c (cut)加动作来进行修改(cc 修改整行);C 则相当于 c$,删除到行尾然后进入插入模式。
  • i 在当前字符前面进入插入模式;I 则相当于 ^i,把光标移到行首非空白字符上然后进入插入模式。
  • a 在当前字符后面进入插入模式;A 相当于 $a,把光标移到行尾然后进入插入模式。
  • o 在当前行下方插入一个新行,然后在这行进入插入模式;O 在当前行上方插入一个新行,然后在这行进入插入模式。
  • u 撤销最近的一个修改动作;U 撤销当前行上的所有修改。
文本对象选择d/y/c
演示 a、i 和 w、双引号、圆括号搭配使用
假设有下面的文本内容:

if (message == "sesame open")
我们进一步假设光标停在“sesame”的“a”上,那么:
d:delete
a:all
i:inner内部的
w:word
  • ‘dw’(理解为 delete word)会删除“ame␣”,结果是“if (message == “sesopen”)”
  • ‘dW’
  • ‘diw’(理解为 delete inside word)会删除“sesame”,结果是“if (message == " open")”
  • ‘daw’(理解为 delete a word)会删除“sesame␣”,结果是“if (message == “open”)”
  • ‘diW’会删除““sesame”,结果是“if (message == open”)”
  • ‘daW’会删除““sesame␣”,结果是“if (message == open”)”
  • ‘di"’会删除“sesame open”,结果是“if (message == “”)”
  • ‘da"’会删除““sesame open””,结果是“if (message ==)”
  • ‘di(’或‘di)’会删除“message == “sesame open””,结果是“if ()”
  • ‘da(’或‘da)’会删除“(message == “sesame open”)”,结果是“if␣”
其他搭配
  • 搭配 s(sentence)对句子进行操作——适合西文文本编辑
  • 搭配 p(paragraph) 对段落进行操作——适合西文文本编辑,及带空行的代码编辑
  • 搭配 t(tag)对 HTML/XML 标签进行操作——适合 HTML、XML 等语言的代码编辑
  • 搭配 ` 和 ’ 对这两种引号里的内容进行操作——适合使用这些引号的代码,如 shell 和 Python
  • 搭配方括号(“[”和“]”)对方括号里的内容进行操作——适合各种语言(大部分都会用到方括号吧)
  • 搭配花括号(“{”和“}”)对花括号里的内容进行操作——适合类 C 的语言
  • 搭配角括号(“<”和“>”)对角括号里的内容进行操作——适合 C++ 的模板代码
对多个(层)文件对象进行操作

在a和i前加上数字

更快地移动
  • 我们仍然可以使用 和 来翻页,但 Vim 更传统的用法是 和 ,分别代表 Backward 和 Forward。
  • 除了翻页,Vim 里还能翻半页,有时也许这种方式更方便,需要的键是 和 ,Up 和 Down。
  • 如果你知道出错位置的行号,那你可以用数字加 G 来跳转到指定行。类似地,你可以用数字加 | 来跳转到指定列。
  • 你只关心当前屏幕的话,可以快速移动光标到屏幕的顶部、中间和底部:用 H(High)、M(Middle)和 L(Low)就可以做到。
  • 只要光标还在屏幕上,你也可以滚动屏幕而不移动光标。需要的按键是 和 。
  • 另外一种可能更实用的滚动屏幕方式是,把当前行“滚动”到屏幕的顶部、中部或底部。Vim 里的对应按键是 zt、zz 和 zb。
  • [[:跳转到上一个函数;
  • ]]:跳转到下一个函数;
重复
  • ; 重复最近的字符查找(f、t 等)操作
  • , 重复最近的字符查找操作,反方向
  • n 重复最近的字符串查找操作(/ 和 ?),已替换成=
  • N 重复最近的字符串查找操作(/ 和 ?),反方向,已替换成-
  • . 重复执行最近的修改操作
vim的运行支持文件

linux: /usr/share/vim/vim82

syntax:Vim 的语法加亮文件

里面的文件去掉“.vim”后缀后,就是文件类型的名字,你可以用类似 :setfiletype java 这样的命令来设置文件的类型,从而进行语法加亮。

let do_syntax_sel_menu = 1

let do_no_lazyload_menus = 1
doc:Vim 的帮助文件

我们用“:help”命令查看的帮助文件就放在 doc 目录下。

colors:Vim 的配色方案
plugin:Vim 的“插件”,即用来增强 Vim 功能的工具

除了 rrhelper 和 spellfile 属于功能支持插件,没有自己的帮助页面,其他功能都可以使用“:help”命令来查看帮助。查看帮助时,插件名称中的“Plugin”后缀需要去掉。如:help zip

  • gzip:编辑 .gz 压缩文件(能在编辑后缀为 .gz 的文件时自动解压和压缩,你会感觉不到这个文件是压缩的)
  • logiPat:模式匹配的逻辑运算符(允许以逻辑运算、而非标准正则表达式的方式来写模式匹配表达式)
  • manpager:使用 Vim 来查看 man 帮助(强烈建议试一下,记得使用 Vim 的跳转键 C-] 和 C-T)
  • matchparen:对括号进行高亮匹配(现代编辑器基本都有类似的功能)
  • netrwPlugin:从网络上编辑文件和浏览(远程)目录(支持多种常见协议如 ftp 和 scp,可直接打开目录来选择文件)
  • rrhelper:用于支持 --remote-wait 编辑(Vim 的多服务器会用到这一功能)
  • spellfile:在拼写文件缺失时自动下载(Vim 一般只安装了英文的拼写文件)
  • tarPlugin:编辑(压缩的)tar 文件(注意,和 gzip 情况不同,这儿不支持写入)
  • tohtml:把语法加亮的结果转成 HTML(自己打开个文件,输入命令“:TOhtml”就知道效果了)
  • zipPlugin:编辑 zip 文件(和 tar 文件不同,zip 文件可支持写入)
用户的vim配置目录

修改 Vim 行为最简单的一种方式,就是把一个系统的运行支持文件复制到自己的 Vim 配置目录下的相同位置,然后修改其内容。

这种方式的缺点(在适当的时候也是优点)是,如果 Vim 的运行支持文件后来被修改 / 更新了,你也会继续使用你自己目录下的老版本修改版。如果你的修改不只是你自己的临时方案、同时也适合他人的话,最佳做法还是给 Vim 项目提交补丁,让其他所有人都能用上你的修改,这样才是开源的最佳使用方式。

  • Vim 软件包的支持(“:help packages”)
  • 异步任务支持(“:help channel”、“:help job”和“:help timers”)
  • 终端支持(“:help terminal”)
vim软件包
  • 一个 Vim 的插件(严格来讲,应该叫包)通常也会分散在多个目录下:
  • 插件的主体通常在 plugin 目录下
  • 插件的帮助文件在 doc 目录下
  • 有些插件只对某些文件类型有效,会有文件放在 ftplugin 目录下
  • 有些插件有自己的文件类型检测规则,会有文件放在 ftdetect 目录下
  • 有些插件有特殊的语法加亮,会有文件放在 syntax 目录下
  • vim包管理器:

每个包有自己的目录,然后这些目录会被加到 Vim 的运行时路径(runtimepath)选项里。

有了包管理器之后,runtimepath 就会非常复杂,每个包都会增加一个自己的目录进去。

Vim 会在用户的配置目录(Unix 下是 $HOME/.vim ,Windows 下是 $HOME/vimfiles )下识别名字叫 pack 的目录,并在这个目录的子目录的 start 和 opt 目录下寻找包的目录。

Vim 8 在启动时会加载所有 pack/*/start 下面的包,而用户可以用 :packadd 命令来加载某个 opt 目录下的包,如 :packadd vimcdoc 命令可加载 vimcdoc 包,来显示中文帮助信息。

安装minpac包管理器

安装minpac之后,我们就有了三个新的命令,可以用来更新(安装)包、清理包和检查当前包的状态。

# 下载安装包
git clone https://github.com/k-takata/minpac.git ~/.vim/pack/minpac/opt/minpac

# 在.vimrc配置文件添加内容:

if exists('g:loaded_minpac')
  " Minpac is loaded.
  call minpac#init()
  call minpac#add('k-takata/minpac', {'type': 'opt'})

  " Other plugins
endif

if has('eval')
  " Minpac commands
  command! PackUpdate packadd minpac | source $MYVIMRC | call minpac#update()
  command! PackClean  packadd minpac | source $MYVIMRC | call minpac#clean()
  command! PackStatus packadd minpac | source $MYVIMRC | call minpac#status()
endif
  • 通过 minpac 安装扩展包

在“Other plugins”那行下面加入以下内容:

call minpac#add(‘tpope/vim-eunuch’)

保存文件,然后我们使用 :PackUpdate 命令。

  • 最近使用的文件
安装 yegappan/mru 包

if !has('gui_running')
  " 设置文本菜单
  if has('wildmenu')
    set wildmenu
    set cpoptions-=<
    set wildcharm=<C-Z>
    nnoremap <F10>      :emenu <C-Z>
    inoremap <F10> <C-O>:emenu <C-Z>
  endif
endif

# 在增加上面的配置之后,你就可以使用键 <F10>(当然你也可以换用其他键)加 <Tab> 来唤起 Vim 的文本菜单。
多文件打开与缓冲区:复制粘贴的正确姿势
复制粘贴
  • :粘贴内容
多文件的打开方式

Vim 支持一次性打开多个文件,你只需要在命令行上写出多个文件即可,或者使用通配符。

在上面的命令后,Vim 建立了一个文件列表,并且暂时只打开其中的第一个文件。接下来,用户可以决定,要编辑哪个文件,或者查看列表,或者提前退出,等等。

  • :args:可以显示“参数”,即需要编辑的多个文件的列表
  • :args 文件名:使用新的文件名替换参数列表
  • :next(可缩写为 :n):打开下一个文件;如当前文件修改(未存盘)则会报错中止,但如果命令后面加 ! 则会放弃修改内容,其他命令也类似
  • :Next(缩写 :N)或 :previous(缩写 :prev):打开上一个文件
  • :first 或 :rewind:回到列表中的第一个文件
  • :last:打开列表中的最后一个文件
工作流
  1. 在终端里进入到目标目录下;
  2. 使用 vim *.cpp *.h 或 gvim *.cpp *.h 来打开需要编辑的文件;

要编辑的文件除了当前目录下的,还有所有子目录下的:

“**”也包含了当前目录,键入 vim 进入 Vim,然后使用 :args **/*.cpp **/*.h 来打开需要编辑的文件

  1. 对于第一个文件,使用之前的方法贴入所需的文本;
  2. 使用 V 进入行选择的可视模式,移动光标选中所需的文本,然后使用 y 复制选中的各行;
  3. 执行命令 :set autowrite,告诉 Vim 在切换文件时自动存盘;
  4. 执行命令 :n|normal ggP,切换到下一个文件并执行正常模式命令 ggP,跳转到文件开头并贴入文本;

可以拆成 :n 和 ggP 两步,但文件数量较多时,反复手工敲 ggP 也挺累的。因此,可以使用了 normal 命令,在命令行模式下执行正常模式命令,下面就可以直接重复切换命令加粘贴命令,我们的编辑效率也得以大大提升。

  1. 确认修改无误后,键入 :、上箭头和回车,重复执行上面的命令;
  2. 待 Vim 报错说已经在最后一个文件里,使用 :w 存盘,或 :wq(抑或更快的 ZZ)存盘退出;
缓冲区的管理和切换

Vim 里会对每一个已打开或要打开的文件创建一个缓冲区,这个缓冲区就是文件在 Vim 中的映射。

  • 缓冲区显示的信息:
  • 文件名前面有编号;
  • 除了当前活跃文件的标记“%a”,还有个文件被标成了“#”,这表示最近的缓冲区;缓冲区列表里还可能有其他标记,如“+”表示缓冲区已经被修改。
  • 文件名后面有行号,表示光标在文件中的位置。
  • 缓冲区命令:
  • :buffers 或 :ls:可以显示缓冲区的列表
  • :buffer 缓冲区列表里的编号(:buffer 可缩写为 :b):跳转到编号对应的缓冲区;如当前缓冲区已被修改(未存盘)则会报错中止,但如果命令后面加 ! 则会放弃修改内容;其他命令也类似
  • :bdelete 缓冲区列表里的编号(:bdelete 可缩写为 :bd):删除编号对应的缓冲区;编号省略的话删除当前缓冲区
  • :bnext(缩写 :bn):跳转到下一个缓冲区
  • :bNext(缩写 :bN)或 :bprevious(缩写 :bp):跳转到上一个缓冲区
  • :bfirst 或 :brewind:跳转到缓冲区列表中的第一个文件
  • :blast:跳转到缓冲区列表中的最后一个文件
  • 两个文件之间切换

Vim 对最近编辑的文件(上面提到的列表里标有“#”的文件)有特殊的支持,使用快捷键 <C-^> 可以在最近的两个缓冲区之间来回切换。这个快捷键还有一个用法是在前面输入缓冲区的编号:比如,用 1<C-^> 可以跳转到第一个缓冲区(跟命令行模式的命令 :bfirst 或 :b1 效果相同)。

缓冲区是文件在某个 Vim 会话里的映射。这意味着,如果某个 Vim 会话里不同的窗口或标签页(下一讲里会讨论)编辑的是同一个文件,它们对应到的也会是同一个缓冲区。更重要的是,文件 / 缓冲区的修改在同一个 Vim 会话里是完全同步的——这就不会像在多会话编辑时那样发生冲突和产生错误了。

窗口和标签页:修改、对比多个文件的正确姿势
多窗口编辑
  • 水平分割::split(缩写 :sp)

命令后面如果有文件名,表示分割窗口并打开指定的文件;如果没有文件名,那就表示仅仅把当前窗口分割开,当前编辑的文件在两个窗口里都显示。

  • 竖直分割: :vsplit(缩写 :vs)

键盘命令:

  • 加方向键(h、j、k、l、 等等)可以在窗口之间跳转
  • w 跳转到下一个(往右和往下)窗口,如果已经是右下角的窗口,则跳转到左上角的窗口
  • W 跳转到上一个(往左和往上)窗口,如果已经是左上角的窗口,则跳转到右下角的窗口
  • n 或 :new 打开一个新窗口
  • c 或 :close 关闭当前窗口;当前窗口如果已经是最后一个则无效
  • o 或 :only 只保留当前窗口,关闭其他所有窗口
  • s 和 :split 作用相同,把当前窗口横向一分为二
  • v 和 :vsplit 作用相同,把当前窗口纵向一分为二
  • = 使得所有窗口大小相同(当调整过终端或图形界面 Vim 的窗口大小后特别有用)
  • _ 设置窗口高度,命令前的数字表示高度行数,默认为纵向占满(想专心编辑某个文件时很有用)
  • | 设置窗口宽度,命令前的数字表示宽度列数,默认为横向占满
  • + 增加窗口的高度,命令前的数字表示需要增加的行数,默认为 1
  • - 减少窗口的高度,命令前的数字表示需要减少的行数,默认为 1
  • > 增加窗口的宽度,命令前的数字表示需要增加的列数,默认为 1
  • (提醒,我们用 表示“<”键)减少窗口的宽度,命令前的数字表示需要增加的列数,默认为 1

快捷键映射:

nnoremap 命令映射正常模式下的键盘,inoremap 命令映射插入模式下的键盘;正常模式的映射简单直白,应该不需要解释,插入模式的映射使用了临时模式切换键 ,在正常模式下执行相应的窗口命令,然后返回插入模式。使用这样的键盘映射之后,这两个快捷键在正常模式和插入模式下就都可以使用了。

由于切换窗口是一个非常常见的操作,我通常会映射一下快捷键。为了跟一般的图形界面程序一致,我使用了 Ctrl-Tab 和 Ctrl-Shift-Tab:

nnoremap <C-Tab>   <C-W>w
inoremap <C-Tab>   <C-O><C-W>w
nnoremap <C-S-Tab> <C-W>W
inoremap <C-S-Tab> <C-O><C-W>W
双窗口比较

使用 vimdiff 或 gvimdiff 命令,后面跟两个文件名,我们就可以对这两个文件进行比较。

也可以打开第一个文件,然后使用命令 :vert diffsplit 第二个文件。

多标签页编辑

单窗口多文件编辑最适合的场景是批量修改具有相似性质的文件,

多窗口编辑最适合的场景是需要对多个文件进行对比编辑,

而其他的一些同时编辑多个文件的场景,就可以考虑多标签页的编辑方式。

  • 多标签页编辑允许在编辑器里同时修改多个(未存盘的)文件;
  • 多标签页编辑一次只展示一个文件
  • 通过选择标签页(或使用键盘)可以方便地在多个标签页中进行切换

键盘命令:

如果某个 Vim 会话里不同的窗口(或标签页;以下略)编辑的是同一个文件,它们对应到的也会是同一个缓冲区。

  • 在已有命令行模式命令前加 tab␣ 可以在新标签页中展示命令的结果,如 :tab help 可以在新标签页中打开帮助,:tab split 可以在新标签页中打开当前缓冲区;
  • :tabs 展示所有标签页的列表;
  • :tabnew 或 :tabedit 可以打开一个空白的新标签页,后面有文件名的话则打开该文件;
  • :tabclose 可以关闭当前标签页(如果标签页里只有一个窗口,使用窗口关闭命令 c 应该更快);
  • :tabnext、gt 或 可以切换到下一个标签页
  • :tabNext、:tabprevious 、gT 或 可以切换到上一个标签页
  • :tabfirst 或 :tabrewind 切换到第一个标签页
  • :tablast 切换到最后一个标签页
正则表达式
正则表达式搜索
  • . 可以匹配除换行符外的任何字符:如 a. 可以匹配“aa”、“ab”、“ac”等,但不能匹配“a”、“b”或“ba”。如果需要匹配换行符(跨行匹配)的话,则需要使用 _.。
  • *表示之前的匹配原(最普通的情况为单个字符)重复零次或多次:如 aa* 可以匹配“a”、“aa”或“aaa”,a.* 可以匹配“a”、“aa”、“abc”等等,但两者均不能匹配“b”。
  • ^ 匹配一行的开头,如果出现在模式的开头的话;在其他位置代表字符本身。
  • $ 匹配一行的结尾,如果出现在模式的结尾的话;在其他位置代表字符本身。
  • ~ 匹配上一次替换的字符串,即如果上一次你把“foo”替换成了“bar”,那 ~ 就匹配“bar”。
  • […] 匹配方括号内的任一字符;方括号内如果第一个字符是 ^,表示对结果取反;除开头之外的 - 表示范围:如 [A-Za-z] 表示任意一个拉丁字母,[^-+/] 表示除了“+”、“-”、“”、“/”外的任意字符。
  • \ 的含义取决于下一个字符,在大部分的情况下,包括上面的这几个(.、*、\、^、$、~、[ 和 ]),代表后面这个字符本身;在跟某些字符时则有特殊含义(后面我们会讨论最重要的那些)。

6个特殊模式项:

  • ? 表示之前的匹配原重复零次或一次:如 aa? 可以匹配“a”、“aa”,但不能完整匹配“aaa”(可以匹配其前两个字符、后两个或最后一个字符)。
  • + 表示之前的匹配原重复一次或多次:如 aa+ 可以匹配“aa”、“aaa”,但不能匹配“a”或“b”。
  • {n,m} 表示之前的匹配原重复 n 到 m 遍之间,两个数字可以省略部分或全部:如 a{3}(可读作:3 个“a”)可以匹配“aaa” ,a{,3}(可读作:最多 3 个“a”)可以匹配“”、“a”、“aa”和“aaa”;两个数字都省略时等价于 *,也就是之前的匹配原可以重复零次或多次。
  • ( 和 ) 括起一个模式,将其组成为单个匹配原:如 (foo)? 可以表示单词“foo”出现零次或一次。( 和 ) 还有一个附加作用,是捕获匹配的内容,按 ( 出现的先后顺序,可以用 \1、\2 到 \9 来引用。如果你不需要捕获匹配内容的话,用 %( 和 ) 的性能更高。
  • & 是分支内多个邻接(concat)的分隔符,概念上可以和与操作相比,表示每一项都需要匹配成功,然后取最后一项的结果返回:如 .foo.&.bar. 匹配同时出现了“foo”和“bar”的完整行。相对来讲,& 没那么常用。
  • | 是多个分支的分隔符,概念上可以和或操作相比,表示任意一项匹配成功即可:如 foo|bar 可匹配“foo”或“bar”两单词之一。

13 个特殊模式项:

  • < 匹配单词的开头
  • > 匹配单词的结尾
  • \s 匹配空白字符 和
  • \S 匹配非空白字符
  • \d 匹配数字,相当于 [0-9]
  • \D 匹配非数字,相当于 [^0-9]
  • \x 匹配十六进制数字,相当于 [0-9A-Fa-f]
  • \X 匹配非十六进制数字,相当于 [^0-9A-Fa-f]
  • \w 匹配单词字符,相当于 [0-9A-Za-z_]
  • \W 匹配非单词字符,相当于 [^0-9A-Za-z_]
  • \h 匹配单词首字符,相当于 [A-Za-z_]
  • \c 忽略大小写进行匹配

搜索实例:

  • 搜索函数名:在前后加上匹配单词头尾的标记,如,\<begin\>。
  • 被誉为最有用的 Vim 提示,是把光标移到希望搜索的关键字上,然后按下 * 键。Vim 会提取光标下的关键字,并自动添加 < 和 > 进行搜索。
  • 搜索 begin 或 end:/\<\(begin\|end\)\>
  • HTML 标签匹配:<.\{-1,}>
最长匹配和最短匹配
  • *、?、+ 和 {} 都属于最长匹配(也叫贪婪匹配)
  • 在 Vim 里,最短匹配只有一种形式,{-n,m},其意义和之前说的 {n,m} 基本相同,但结果是较短而非较长的字符串。
正则表达式替换
编程支持
查看文档

Vim 里快捷键 K 可以用来查看光标下关键字的相关文档。

" 启用 man 插件
source $VIMRUNTIME/ftplugin/man.vim

set keywordprg=:Man
自动完成
  • 当光标下的文件名可以在 path 选项标识的目录下找到时,我们可以很方便地跳转过去。你需要的是正常模式命令 gf(goto file) 和 f(会打开一个新窗口)。
记录
  • 按键是 KeyCastr,录屏是 GIF Brewery。Screenkey
  • vim如何离线安装插件?如何配置网络?
  • :e Tab:查看当前目录下的文件?
  • vim打开一个项目如何在文件和目录之间跳转?
  • 可视模式怎么使用?
  • 配置python完全支持:如何使用指定路径的解释器?、如何进行引用跳转和查看方法的说明?如何运行和debug?如何在项目中使用git?如何更好地使用代码补全?