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(‘.’) 表示“当前”行的行号
# 每种结构都要用一个对应的 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})
用于选定文本块
V:进入可视行模式
用于执行较长、较复杂的命令;
syntax on:打开语法高亮let mapleader=" "set enc=utf-8:配置语言
set number:显示行号
set cursorline:设置游标线
set wrap:设置文字区间不超过当前屏幕
set showcmd:在底下显示输入的命令
set wildmenu:命令补全,按Tap
set mouse=anoremap n h:在键盘上按n时输入的是h键
noremap u k
noremap e j
noremap i l
noremap k i
noremap K I
noremap l u
noremap :nohlsearch # nohlsearch:no high light search
方便搜索时上下查找:
noremap = nzz
noremap - Nzzmap s :让在正常模式下的s键无效
map S :w:映射,当按下S键时,输入的是:w,即保存
map Q :q:设置按下Q退出vim
map R :source $MYVIMRC:按下R即刷新配置文件source $VIMRUNTIME/vimrc_example.vim:导入 Vim 的示例配置(这会打开一些有用的选项,如语法加亮、搜索加亮、命令历史、记住上次的文件位置,等等)正常模式下:
:操作,加一个动作命令行模式下:
:color blue/darkblue/default:选择主题
set nobackup
set undodir=~/.vim/undodirif !isdirectory(&undodir)call mkdir(&undodir, 'p', 0700)
endif
if has('mouse')if has('gui_running') || (&term =~ 'xterm' && !has('mac'))set mouse=aelseset mouse=nviendif
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 撤销当前行上的所有修改。
假设有下面的文本内容:if (message == "sesame open")
我们进一步假设光标停在“sesame”的“a”上,那么:
d:delete
a:all
i:inner内部的
w:word
在a和i前加上数字
linux: /usr/share/vim/vim82
里面的文件去掉“.vim”后缀后,就是文件类型的名字,你可以用类似 :setfiletype java 这样的命令来设置文件的类型,从而进行语法加亮。
let do_syntax_sel_menu = 1let do_no_lazyload_menus = 1
我们用“:help”命令查看的帮助文件就放在 doc 目录下。
除了 rrhelper 和 spellfile 属于功能支持插件,没有自己的帮助页面,其他功能都可以使用“:help”命令来查看帮助。查看帮助时,插件名称中的“Plugin”后缀需要去掉。如:help zip
修改 Vim 行为最简单的一种方式,就是把一个系统的运行支持文件复制到自己的 Vim 配置目录下的相同位置,然后修改其内容。
这种方式的缺点(在适当的时候也是优点)是,如果 Vim 的运行支持文件后来被修改 / 更新了,你也会继续使用你自己目录下的老版本修改版。如果你的修改不只是你自己的临时方案、同时也适合他人的话,最佳做法还是给 Vim 项目提交补丁,让其他所有人都能用上你的修改,这样才是开源的最佳使用方式。
一个 Vim 的插件(严格来讲,应该叫包)通常也会分散在多个目录下:
vim包管理器:
每个包有自己的目录,然后这些目录会被加到 Vim 的运行时路径(runtimepath)选项里。
有了包管理器之后,runtimepath 就会非常复杂,每个包都会增加一个自己的目录进去。
Vim 会在用户的配置目录(Unix 下是 $HOME/.vim ,Windows 下是 $HOME/vimfiles )下识别名字叫 pack 的目录,并在这个目录的子目录的 start 和 opt 目录下寻找包的目录。
Vim 8 在启动时会加载所有 pack/*/start 下面的包,而用户可以用 :packadd 命令来加载某个 opt 目录下的包,如 :packadd vimcdoc 命令可加载 vimcdoc 包,来显示中文帮助信息。
安装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
endifif has('eval')" Minpac commandscommand! 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 wildmenuset cpoptions-=nnoremap :emenu inoremap :emenu endif
endif# 在增加上面的配置之后,你就可以使用键 (当然你也可以换用其他键)加 来唤起 Vim 的文本菜单。
Vim 支持一次性打开多个文件,你只需要在命令行上写出多个文件即可,或者使用通配符。
在上面的命令后,Vim 建立了一个文件列表,并且暂时只打开其中的第一个文件。接下来,用户可以决定,要编辑哪个文件,或者查看列表,或者提前退出,等等。
在终端里进入到目标目录下;
使用 vim *.cpp *.h 或 gvim *.cpp *.h 来打开需要编辑的文件;
要编辑的文件除了当前目录下的,还有所有子目录下的:
“**”也包含了当前目录,键入 vim 进入 Vim,然后使用 :args **/*.cpp **/*.h 来打开需要编辑的文件
对于第一个文件,使用之前的方法贴入所需的文本;
使用 V 进入行选择的可视模式,移动光标选中所需的文本,然后使用 y 复制选中的各行;
执行命令 :set autowrite,告诉 Vim 在切换文件时自动存盘;
执行命令 :n|normal ggP,切换到下一个文件并执行正常模式命令 ggP,跳转到文件开头并贴入文本;
可以拆成 :n 和 ggP 两步,但文件数量较多时,反复手工敲 ggP 也挺累的。因此,可以使用了 normal 命令,在命令行模式下执行正常模式命令,下面就可以直接重复切换命令加粘贴命令,我们的编辑效率也得以大大提升。
确认修改无误后,键入 :、上箭头和回车,重复执行上面的命令;
待 Vim 报错说已经在最后一个文件里,使用 :w 存盘,或 :wq(抑或更快的 ZZ)存盘退出;
Vim 里会对每一个已打开或要打开的文件创建一个缓冲区,这个缓冲区就是文件在 Vim 中的映射。
缓冲区显示的信息:
缓冲区命令:
两个文件之间切换
Vim 对最近编辑的文件(上面提到的列表里标有“#”的文件)有特殊的支持,使用快捷键
可以在最近的两个缓冲区之间来回切换。这个快捷键还有一个用法是在前面输入缓冲区的编号:比如,用 1 可以跳转到第一个缓冲区(跟命令行模式的命令 :bfirst 或 :b1 效果相同)。 缓冲区是文件在某个 Vim 会话里的映射。这意味着,如果某个 Vim 会话里不同的窗口或标签页(下一讲里会讨论)编辑的是同一个文件,它们对应到的也会是同一个缓冲区。更重要的是,文件 / 缓冲区的修改在同一个 Vim 会话里是完全同步的——这就不会像在多会话编辑时那样发生冲突和产生错误了。
水平分割::split(缩写 :sp)
命令后面如果有文件名,表示分割窗口并打开指定的文件;如果没有文件名,那就表示仅仅把当前窗口分割开,当前编辑的文件在两个窗口里都显示。
竖直分割: :vsplit(缩写 :vs)
键盘命令:
快捷键映射:
nnoremap 命令映射正常模式下的键盘,inoremap 命令映射插入模式下的键盘;正常模式的映射简单直白,应该不需要解释,插入模式的映射使用了临时模式切换键 ,在正常模式下执行相应的窗口命令,然后返回插入模式。使用这样的键盘映射之后,这两个快捷键在正常模式和插入模式下就都可以使用了。
由于切换窗口是一个非常常见的操作,我通常会映射一下快捷键。为了跟一般的图形界面程序一致,我使用了 Ctrl-Tab 和 Ctrl-Shift-Tab:nnoremap w
inoremap w
nnoremap W
inoremap W
使用 vimdiff 或 gvimdiff 命令,后面跟两个文件名,我们就可以对这两个文件进行比较。
也可以打开第一个文件,然后使用命令 :vert diffsplit 第二个文件。
单窗口多文件编辑最适合的场景是批量修改具有相似性质的文件,
多窗口编辑最适合的场景是需要对多个文件进行对比编辑,
而其他的一些同时编辑多个文件的场景,就可以考虑多标签页的编辑方式。
键盘命令:
如果某个 Vim 会话里不同的窗口(或标签页;以下略)编辑的是同一个文件,它们对应到的也会是同一个缓冲区。
6个特殊模式项:
13 个特殊模式项:
搜索实例:
Vim 里快捷键 K 可以用来查看光标下关键字的相关文档。
" 启用 man 插件
source $VIMRUNTIME/ftplugin/man.vimset keywordprg=:Man