通过对linux中自带的vimtutor命令学习,以及《vim实用技巧》学习,然后对常用的vim命令进行总结,方便以后忘记了常看。
vim file +n :打开文件并跳到第N行
默认显示行号:编辑或新建~/.vimrc 添加一行 set nu 即可,或者在/etc/vimrc 内编辑
模式切换
按键操作 | 用途 |
---|---|
<Esc> |
切换到普通模式 |
<Ctrl+[> |
切换到普通模式 |
<Ctrl+o> |
切换到插入-普通模式,能让我们执行一次普通模式命令。 在此模式中, 可以执行一个普通模式命令, 执行完后, 马上又返回到插入模式 |
插入-普通模式是一个子模式, 可以让我们执行一个普通模式命令, 之后马上又回到插入模式。
普通模式
命令的基本模式 operation [number] range
基础定位移动
" 面向行的移动
k上
h左 l右
j下
4h 左4个字符 4k 上4行 4j 下4行 4l 右4个字符
2gg "定位到第2行代码,等同于2G
2G "定位到第2行代码
gg "定位到整个代码的第1行
G "定位到整个代码的最后一行
0或^ "行首
$ "行尾
" 面向单词的移动
w "向后跳到下一个单词的开始处
b "向前跳到上一个单词的开始处
e "向后跳到下一个单词的结束处
ge "向前跳到上一个单词的结束处
2e,2w,2b表示移动2个单位
" 面向字串的移动
W、 B、 E 和gE
" 面向字符的移动
f "光标正向移动到行内的指定字符前
F "光标反向移动到行内的指定字符前
t "光标正向移动到行内的指定字符的前一个字符
T "光标反向移动到行内的指定字符的前一个字符
; "正向重复执行字符查找
, "反向重复执行字符查找
" 飞雷神
mm "将位置标记在m
`m "回到标记 m 的位置
'm "回到标记 m 的所在行首
H "当前屏幕可见的第一行
M "当前屏幕可见的中间
L "当前屏幕可见的最后一行
Ctrl+o "快速跳回上一个位置
快速移动
行移动
区分实际行与屏幕行(超出屏幕显示区域的vim会帮你soft wrap) , j、 k、 0 和 $ 都用于操作实际行,而如果在这些键前加上 g 前缀的话, 就会让 Vim 对屏幕行进行操作
命令 | 光标动作 |
---|---|
j | 向下移动一个实际行 |
gj | 向下移动一个屏幕行 |
k | 向上移动一个实际行 |
gk | 向上移动一个屏幕行 |
0 | 移动到实际行的行首 |
g0 | 移动到屏幕行的行首 |
^ | 移动到实际行的第一个非空白字符 |
g^ | 移动到屏幕行的第一个非空白字符 |
$ | 移动到实际行的行尾 |
g$ | 移动到屏幕行的行尾 |
如果你想让 j 及 k 命令操作屏幕行而不是实际行, 可以重新映射它们。把下面加到你的 vimrc 文件中
nnoremap k gk
nnoremap gk k
nnoremap j gj
nnoremap gj j
基于单词的移动
先学会用 w 和 b命令 ,e 和 ge 命令是对此命令集的补充
单词与字串
单词:字母、 数字、 下画线, 或其他非空白字符的序列组成,单词间以空白字符分隔(参见 :h word)
字串:由非空白字符序列组成, 字串间以空白字符分隔(参见 :h WORD)
普通用户可以这样简单地想: 字串比单词更长!
我们之前面向单词的动作命令, 都有一个面向字串的命令与其对应, 这当中包括 W、 B、 E 和gE。
命令 | 光标动作 |
---|---|
对应单词 | |
w | 正向移动到下一单词的开头 |
b | 反向移动到当前单词/上一单词的开头 |
假设想把单词“fast”改成“faster” | |
e | 正向移动到当前单词/下一单词的结尾 |
ge | 反向移动到上一单词的结尾 |
对应字串 | |
W | 正向移动到下一字串的开头 |
B | 反向移动到当前单词/上一字串的开头 |
E | 正向移动到当前单词/下一字串的结尾 |
gE | 反向移动到上一字串的结尾 |
感受一下单词与字串的差别
e.g. we're going too slow # 可以试一下这个文本
例如, 如果想把“we”“you”
按键操作 | 缓冲区内容 |
---|---|
{start} | e.g. we’re going too slow |
cwyou |
e.g. you’re going too slow |
在另外一些时候, 我们可能更想把“we’re”“it’s”
按键操作 | 缓冲区内容 |
---|---|
{start} | e.g. we’re going too slow |
cWit’s |
e.g. it’s going too slow |
基于字符的移动
f{char}
在光标位置与当前行行尾之间查找指定的字符, 如果找到了, 就会把光标移到此字符上; 如果未找到, 则保持光标不动
命令 | 用途 |
---|---|
f{char} | 正向移动到下一个 {char} 所在之处 |
F{char} | 反向移动到上一个 {char} 所在之处 |
t{char} | 正向移动到下一个 {char} 所在之处的前一个字符上 |
T{char} | 反向移动到上一个 {char} 所在之处的后一个字符上 |
; | 重复上次的字符查找命令 |
, | 反转方向查找上次的字符查找命令 |
有意思的例子
按键操作 | 缓冲区内容 |
---|---|
{start} | I’ve been expecting you, Mister Bond. |
f, | I’ve been expecting you, Mister Bond. |
dt. | I’ve been expecting you. |
dt.
表示删除从 当前光标所在字符,到t.
所找到的点号(.
)前的字符
技巧
在使用字符查找命令时, 最好是选择出现频率比较低的字母作目标字符。
Improve your writing by deleting excellent adjectives.
让光标移到单词“excellent”上,更好的选择是用 fx
, 这条命令一下就能让我们移动到此单词上, 接下来就可以用 daw 命令删除该单词了
飞雷神
在Vim的前身vi里,并没有诸如现在的可视模式这样的功能。那时,位置标记是一个比现在重要得多的功能。但现在,很多在vi里需要用位置标记完成的工作,都可以在Vim里用可视模式来做,因此对位置标记的需求也就相应减少了。但是位置标记在Vim里并没有过时,它们仍然有用处。
第一步:标记
m{a-zA-Z}
命令会用选定的字母标记当前光标所在位置
- 小写位置标记只在每个缓冲区局部可见
- 大写位置标记则全局可见
第二步:跳转
有两种方式:
'{mark}
命令跳到位置标记所在行, 并把光标置于该行第一个非空白字符上;{mark}` 命令则把光标移动到设置此位置标记时光标所在之处;(推荐)
Vim自动设置的标记
Vim 会自动设置一些位置标记, 这些标记用起来非常方便。 Vim 会自动设置一些位置标记, 这些标记用起来非常方便。
位置标记 | 跳转到 |
---|---|
`` | 当前文件中上次跳转动作之前的位置 |
`. | 上次修改的地方 |
`^ | 上次插入的地方 |
`[ | 上次修改或复制的起始位置 |
`] | 上次修改或复制的结束位置 |
`< | 上次高亮选区的起始位置 |
`> | 上次高亮选区的结束位置 |
括号间跳转
%
命令允许在一组开、 闭括号间跳转(参见 :h % ) , 它可作用于 ()
、 {}
以及[]
例子:修改括号的陷阱
假设想把 %w{London Berlin New\ York}
改成普通的列表定义["London", "Berlin", "New York"]
文本对象
var tpl = [
'<a href="{url}">{title}</a>'
]
在上面的代码中, 每个开括号字符{
都对应一个闭括号字符}
、[
和]
、<
和>
、以及HTML标签也是一样。这些配对符号具有规整的格式,而Vim能够理解其结构,并允许对它们分隔的区域进行操作。文本对象就是基于结构定义的文本区域(参见:htext-objects)
文本对象自身并不是动作命令, 不能用它们在文档中移动。 但是却可以在可视模式及操作符待决模式中使用文本对象
记住: 每当在命令语法里看到 {motion} 时, 也可以在这个地方使用文本对象, 常见的例子包括
d{motion}
、c{motion}
和y{motion}
Vim 的文本对象分为两类:
一类是操作分隔符的文本对象, 如i)、 i” 和it,称为 分隔符文本对象
另一类用于操作文本块, 如单词、 句子和段落,称为 范围文本对象
Vim 的文档把它们称为“块对象”(block object) 和“非块对象”(non-block object)
分隔符文本对象
用于快速选择引号括号内容
以 i
开头的文本对象会选择分隔符内部的文本,而以a
开头的文本对象会选择包括分隔符在内的整个文本,i——>“inside”,a——>“around”或“all”。
文本对 象 | 选择区域 | 文本对象 | 选择区域 |
---|---|---|---|
a) 或 ab | 一对圆括号 (parentheses) | i) 或 ib | 圆括号 (parentheses) 内部 |
a} 或 aB | 一对花括号 {braces} | i} 或 iB | 花括号 {braces} 内部 |
a] | 一对方括号 [brackets] | i] | 方括号 [brackets] 内部 |
a> | 一对尖括号 <angle brackets> |
i> | 尖括号 <angle brackets> 内部 |
a’ | 一对单引号 ‘single quotes’ | i’ | 单引号 ‘single quotes’ 内部 |
a” | 一对双引号 “double quotes” | i” | 双引号 “double quotes” 内部 |
a` | 一对反引号 backticks | i` | 反引号 backticks 内部 |
at | 一对 XML 标签 <xml>tags</xml> |
it | X 部ML标签<xml>tags</xml> 内 |
i( 和 i) 等同, a[ 和 a] 也相同
例子:
(some text)
di) 即可删除括号内容
范围文本对象
文本对象 | 选择范围 |
---|---|
iw | 当前单词 |
aw | 当前单词及一个空格 |
iW | 当前字串 |
aW | 当前字串及一个空格 |
is | 当前句子 |
as | 当前句子及一个空格 |
ip | 当前段落 |
ap | 当前段落及一个空行 |
一般来说, d{motion}
命令和 aw
、 as
和 ap
配合起来使用比较好, 而 c{motion}
命令和 iw
及类似的文本对象一起用效果会更好
例子
1、假设想删除下句中的单词“excellent” 此时可以用 daw
命令
按键操作 | 缓冲区内容 |
---|---|
{start} | Improve your writing by deleting excellent adjectives. |
daw | Improve your writing by deleting adjectives. |
这条命令会删除此单词,外加一个空格, 因此结果会很干净。 如果用的是 diw
,删完后就会有两个连在一起的空格
2、假设想把此单词改成另外一个单词, 这次可以用 ciw
命令
按键操作 | 缓冲区内容 |
---|---|
{start} | Improve your writing by deleting excellent adjectives. |
ciwmost<Esc> |
Improve your writing by deleting most adjectives. |
ciw 命令只删除该单词, 而不删除其前后的空白字符, 随后它会进入插入模式, 这刚好是我们想要的效果。 如果用的是caw
, 最后两个单词就会连在一起, 变成“mostadjectives”。
编辑
i "光标处插入
a "光标后一个字符处插入
A "光标所在行末尾插入
o "光标下方新建一行
O "光标上方新建一行
p "粘贴在光标后
P "粘贴在光标前
y "复制选择的文本
yw或ye "复制一个单词
yy "复制 光标所在的这一行
4yy "复制 光标所在行开始向下的4行
dd "剪切 光标所在的这一行
2dd "剪切 光标所在行 向下 2行
d0 "从当前的光标开始剪切,一直到行首
D "从当前的光标开始剪切,一直到行末
daw "删除光标所在的单词
dw "删除光标后的一个单词
d2w "删除光标后2个单词
x "删除当前的光标所在的字符,每次只会删除一个
X "删除当前光标前面的那个,每次只会删除一个
r "替换光标后的一个字符
R "连续替换光标后的字符
ce或cw "修改该单词到单词结尾
C或c$ "修改光标后该行的全部内容
J "连接两行
. "重复执行上一次的命令
u "撤销最后的操作
U "撤销对整行的修改
ctrl+r "反撤销
ctrl+a 或 ctrl+x "对光标下的数字进行加减,10ctrl+a可以每次加10,再配合点号.可以重复累加 *
撤销
撤销块的概念
i{insert some text}<Esc>
是一次修改。
如果在插入模式中使用了 <Up>、 <Down>、 <Left>或 <Right>
这些光标键, 将会产生一个新的撤销块。
操作符 + 动作命令 = 操作
d{motion}
,d是操作符, motion是动作
操作符与动作命令的结合形成了一种语法。 这种语法的第一条规则很简单, 即一个操作由一个操作符, 后面跟一个动作命令组成。 学习新的动作命令及操作符, 就像是在学习Vim的词汇一样。 如果掌握了这一简单的语法规则, 在词汇量增长时, 就能表达更多的想法。
Vim的语法只有一条额外规则, 即当一个操作符命令被连续调用两次时, 它会作用于当前行。 所以 dd 删除当前行, 而 >> 缩进当前行。 gU 命令是一种特殊情况, 我们既可以用 gUgU , 也可以用简化版的gUU 来使它作用于当前行。
Vim操作符
命令 | 用途 |
---|---|
c | 修改 |
d | 删除 |
y | 复制到寄存器 |
g~ | 反转大小写 |
gu | 转换为小写 |
gU | 转换为大写 |
> | 增加缩进 |
< | 减小缩进 |
= | 自动缩进 |
! | 使用外部程序过滤{motion}所跨越的行 |
一键代替两键
快捷按键 | 等效按键 | 效果 |
---|---|---|
S | ^C | 清空当前行 |
C | c$ | 删除当前行光标后的内容 |
s | cl | TODO |
I | ^i | 在行首插入 |
A | $a | 在行尾插入 |
o | A\<Enter> | 在下方新建一行空白行 |
O | ko<> | 在上方新建一行空白行 |
删除与查找结合起来
学会把d{motion}
操作符与查找动作结合在一起使用, 这是个很大的进步, 你
可以好好在朋友和同事们面前炫耀一番了。
例子:
删除take与到get之间的内容
按键操作 | 缓冲区内容 |
---|---|
{start} | This phrase takes time but eventually gets to the point. |
d/ge\ |
This phrase gets to the point. |
虽然光标是在单词“gets”开头的“g”上的, 但此字符却被排除在删除操作之外(参见 :h exclusive )。jizx的理解是/ge
查找时,光标是在ge之前的,因此删除时不包括ge
。
复制
yyp
会使用寄存器,:t.
则不会
在复制距离较远的行时,:t
命令通常更加高效
删除一个单词
The end is nigh
假设光标在h上,要删除nigh,可行的方法有db x
,b dw
,以及daw
推荐daw
,可以把 daw 命令解读为“delete a word”,因为.
会把这一个命令完整记住,而其他的命令会被视为2部分
行尾添加字符串
<C-v>G$ " 全选
A; " 进入插入模式,添加;
<Esc> " 完成插入
或者使用替换命令
%s/$/;/g
对数字进行加减
ctrl+a
ctrl+x
分别会对光标下的数字进行加减,默认一次加1,10ctrl+a
可以每次加10,再配合.
可以重复累加
使用ctrl+a
的话,对007会进行八进制的加法:007 + 001 = 010, 如果你想要10进制的,set nrformats=
这会让Vim把所有数字都当成十进制, 不管它们是不是以0开
头的。
重复与回退
目的 | 操作 | 重复 | 回退 |
---|---|---|---|
做出一个修改 | {edit} | . | u |
在行内查找下一指定字符 | f{char}/t{char} | ; | , |
在行内查找上一指定字符 | F{char}/T{char} | ; | , |
在文档中查找下一处匹配项 | /pattern | n | N |
在文档中查找上一处匹配项 | ?pattern | n | N |
执行替换 | :s/target/replacement | & | u |
执行一系列修改 | qx{changes}q | @x | u |
重复上次的 Ex 命令非常简单 | :move5 | @: | u |
.
范式
用一次按键移动,另一次按键执行,再没有比这更好的了,不是吗?这就是我们的理想解决方案。我们将会一次又一次地看到这一编辑模式,所以为了方便起见,把它叫做“.范式”。
重复与计数
只在必要时使用次数
计算次数很是讨厌, 因此我宁愿按6次 .
命令, 也不愿意只为减少按键的次数, 而浪费同样的时间去统计次数。 如果我多按了一次 . 命令怎么办? 没关系, 只要按一次 u 键就可以回退回来。
翻页
ctrl+f "向下翻一页代码
ctrl+b "向上翻一页代码
ctrl+d "向下翻半页代码
ctrl+u "向上翻半页代码
" 可视化模式,可以配合d,x,y等进行修改,也可以进来末行模式:w filename 进行另存
v "字符可视化模式(Characterwise visual mode),文本选择是以字符为单位的,
V "行可视化模式(Linewise visual mode),文本选择是以行为单位的。
ctrl-V "块可视化模式(Blockwise visual mode),可以选择一个矩形内的文本。
>> "向右移动代码
<< "向左移动代码
shift+zz "相当于wq
查找与替换
* "高亮光标下的全部单词,使用 n 跳到下一处
/xxx "向下查找xxx
/xxx\c "忽略大小写
/xxx\C "区分大小写
?xxx "向上查找xxx
?xxx\c "忽略大小写
?xxx\C "区分大小写
输入n则继续查找下一个匹配
ctrl+o "光标跳转到查询到的上一个位置
ctrl+i "光标跳转到查询到的下一个位置
% "快速查找光标所在处的括号所匹配的另一个括号 (),[],{}
:s/old/new "替换该行第一个匹配串
:s/old/new/g "替换该行全部匹配串
:#,#s/old/new/g "替换#到"行之间的词
:%s/old/new/gc "替换全文匹配串,并逐个询问是否替换
命令*
等效于输入 /\<<C-r><C-w>\><CR>
序列, 请参见命令行模式下的“快速复制单词”一节,关于 \<
和\>
在模式中的作用, 请参见技巧77的讨论)。
在命令行模式中的%
表示所有行
例子:在行尾添加分号
$
表示行尾,替换为;
。不能写成%s/$/;$/g
,暂时不知道为什么。
:%s/$/;/g
查看字符编码
如果你想知道文档中任意字符的编码, 只需把光标移到它上面并按ga
命令, 然后屏幕下方会显示出一条消息, 分别以十进制和十六进制的形式显示出其字符编码(参见 :h ga )
插入模式
不离开插入模式粘贴
在普通模式,使用复制命令yt
把“some text”复制到复制专用寄存器中
然后在插入模式中, 按 <C-r>0
把刚才复制的文本粘贴到光标所在位置
<C-r><C-p>{register}
命令则会更智能一些,它会按原义插入寄存器内的文本,并修正任何不必要的缩进,不过这个命令有点不太好输入!因此,如果我想从 一个寄存器里粘贴很多行文本的话,我更喜欢切换到普通模式,然后使用某个粘贴命令。
编辑
按键操作 | 用途 |
---|---|
<C-h> |
删除前一个字符(同退格键) |
<C-w> |
删除前一个单词 |
<C-u> |
删至行首 |
插入特殊字符
在插入模式下,ctrl+v
进入特殊字符输入状态
假设想插入大写字母“A”, 它的字符编码是65, 因此需要输入 <C-v>065
假设想插入字符编码为00bf的反转问号(“¿”) , 只需在插入模式中输入 <C-v>u00bf
如果<C-v>
命令后面跟一个非数字键, 它会插入这个按键本身代表的字符。 例如, 如果启用了 ‘expandtab’ 选项, 那么按\
二合字母输入特殊字符
在插入模式中, 只需输入
用命令:digraphs
可以查看可用的二合字母列表, 不过该命令的输出不太好阅读。 也可以用 :h digraph-table
查看另一个更为有用的列表。
总结
插入非常用字符
按键操作 | 用途 |
---|---|
<C-v>065 |
以十进制字符编码插入字符A |
<C-v>u1F3B |
以十六进制字符编码插入字符 |
<C-v>nondigit |
按原义插入非数字字符 |
<C-k>{char1}{char2} |
插入以二合字母{char1}{char2}表示的字符 |
可视模式
命令 | 用途 |
---|---|
v | 激活面向字符的可视模式 |
V | 激活面向行的可视模式 |
<C-v> |
激活面向列块的可视模式 |
gv | 重选上次的高亮选区 |
可视模式间切换的命令。
按键操作 | 用途 |
---|---|
<Esc> / <C-[> |
回到普通模式 |
v / V / \<C-v> |
切换到普通模式(在对应的面向字符可视模式、 面向行的可视模式和面 向列块的可视模式中使用时) |
V | 切换到面向字符的可视模式 |
V | 切换到面向行的可视模式 |
<C-v> |
切换到面向列块的可视模式 |
O/o | 切换高亮选区的活动端 |
经验
如果想使点命令能够重复某些有用的工作, 那么最好要远离可视模式。 作为一般的原则, 在做一系列可重复的修改时, 最好首选操作符命令, 而不是其对应的可视模式命令。
对一次性的修改任务来说, 可视模式完全够用, 并且尽管Vim的动作命令允许进行精确的移动, 但有时要修改的文本范围的结构很难用动作命令表达出来, 而处理这种情形恰恰是可视模式擅长的。
命令行模式
:w "保存
:w filename "保存为指定的文件
:q "退出
:wq "保存并且推出
:x "等同于wq
:r filename "读取外部文件粘贴到光标处
:r !ls "获取命令输出内容粘贴到光标处
命令行补全
:set col
<C-d>
命令会让Vim 显示可用的补全列表(参见 :h c_CTRL-D),如果多次按 <Tab>
键, 命令行上会依次显示colder、 colorscheme, 然后再回到最初的 col, 如此循环往复。
调整wildmode
选项可以自定义补全行为(参见 :h wildmode
) 。
bash shell的方式工作(列出所有候选项)
set wildmenu
set wildmode=longest,list
zsh 提供的自动补全菜单
set wildmenu
set wildmode=full
当 wildmenu
’选项被启用时, Vim 会提供一个补全导航列表。 可以按
执行 shell 命令
:!{cmd}
适用于执行一次性命令,比如:!ls
:shell
可以启动一个交互的shell会话执行多条命令,用exit
命令可以退出此shell并返回Vim
注意区分
:!ls
和:ls
的不同之处。前者调用的是 shell 中的 ls 命 令,而 :ls 调用的是 Vim的内置命令,用来显示缓冲区列表的内容。
在 Vim 的命令行中, 符号 %
代表当前文件名,如果当前正在编辑 Python 文件,可以用:!python %
执行此文件。
推荐Ctrl-z 和 fg
假设正在 bash shell 中运行 Vim, 然后需要执行一些 shell 命令。 可以先按 Ctrl-z 挂起Vim 所属的进程, 并把控制权交还给bash。 此时 Vim 进程在后台处于挂起状态, 让我们可以像往常一样与 bash 会话进行交互。 运行下面这条命令可以查看当前的作业 列表。
➾ $ jobs
《[1]+ Stopped vim
在 bash 中, 可以用 fg 命令唤醒一个被挂起的作业, 把它移到前台。 这会让 Vim 恢复成挂起前的状态。 Ctrl-z 和 fg 命令比Vim 提供的 :shell 和 exit 命令更加方便快捷。
把缓冲区内容作为标准输入或输出
:read !{cmd}
把{cmd}
命令的标准输出读入当前缓冲区中
:write !{cmd}
把缓冲区内容作为指定命令的标准输入
注意感叹号
根据叹号在命令行上的位置不同, 它的含义也不大相同。
➾ :write !sh
➾ :write ! sh
➾ :write! sh
前两个命令都会把缓冲区的内容传给外部的 sh 命令作为标准输入, 而最后一条命令调用 :write!
命令把缓冲区内容写到一个名为sh
的文件, 这里的叹号表示强制
:write !sh
命令的作用是在shell中执行当前缓冲区中的每行内容, 查阅:h rename-files
可看到该命令的一个绝佳示例。
当前目录中有以下文件:,想要将*.c
改为 *.bla
buffer.c
charset.c
digraph.c
…
$ vim
:r !ls *.c
:%s/\(.*\).c/mv & \1.bla
:w !sh
:q!
历史记录
与bash一样,上下键↑↓
可以浏览历史;
如果输入部分命令,↑↓
就会过滤包含部分命令的记录
Vim 不仅会记录 Ex 命令的历史, 还会为查找命令单独保存一份历史记录。 在按 /
调出查找提示符后, 用 ↑↓
可以正向或反向遍历之前的查找记录。
命令行窗口
命令行窗口相当于另一个vim窗口,使用 Vim 完整的、 区分模式的编辑能力来修改历史命令。默认处于普通模式。基本上所有vim操作(i, x等
)都可以使用
命令 | 动作 |
---|---|
q/ | 打开 正向查找命令 历史的命令行窗口 |
q? | 打开 反向查找命令 历史的命令行窗口 |
q: | 打开 Ex 命令历史的命令行窗口 |
<Ctrl-f> |
当处于 命令行模式 下时意识到需要 更强大的编辑能力,可以用 |
:q | 退出命令行窗口 |
<CR> |
执行光标所在行的命令 |
快速复制光标下的单词
在输入命令行的时候,vim始终记住光标的位置,使用快捷键ctrl+r ctrl+w
可以快速输入光标下的单词,ctrl+r ctrl+a
可以快速输入光标下的字符串(字符串范围是离光标最近的前后两个空格之间的字符串)
:%s/tally/<C-r><C-w>/g # 将tally替换为光标下的单词
打字机模式
用zz
命令可以重绘屏幕, 并把当前行显示在窗口正中, 这样就能够阅读当前行之上及之下的半屏内容。 我常常会键入<C-o>zz
, 在插入-普通模式中触发这条命令。 此操作完成后就会直接回到插入模式, 因此可以不受中断地继续打字。
复制粘贴与寄存器
复制粘贴删除快捷键
普通模式:y(yank)、p(put) 、d(delete)
Ex命令命令行模式: :delete c
, 把当前行剪切到寄存器 c, 然后再执行 :put c
命令将其粘贴至当前光标所在行之下
怎样才能知道 p 命令是把寄存器的文本粘贴到当前字符之后还是当前行之后呢? 这取决于这个指定的寄存器是怎样被赋值的。 面向行的复制或者删除操作(如 dd、 yy 或者 dap) , 将创建面向行的寄存器; 面向字符的复制或者删除操作(如x、 diw或者 das) 则创建面向字符的寄存器。
p的粘贴位置问题处理
我不喜欢被迫去判断面向字符的文本区域到底是放在光标之前还是之后。 因此, 较之使用普通模式的 p
和 P
命令, 我有时更喜欢在插入模式中使用 <C-r>{register}
的映射项来粘贴面向字符的文本区域。 通过这种方式, 寄存器的文本总会被插入光标之前, 就像我们在插入模式下手动输入它们一样。
因此推荐在插入模式下:
- 通过输入
<C-r>"
来插入无名寄存器的内容 - 通过输入
<C-r>0
来插入复制专用寄存器的内容
寄存器
Vim的删除、 复制与粘贴命令都会用到众多寄存器中的某一个。
在普通模式,可以通过给命令加 "{register}
前缀的方式指定要用的寄存器。 若不指明, Vim将缺省使用无名寄存器,它用双引号表示,例如, ""p
, 它完全等同于 p
命令。
在插入模式,可以输入ctrl+r {register}
获取寄存器内容
查看寄存器内容:reg "0
黑洞寄存器"-
删除文本而不把其内容复制到任何寄存器,用下画线符号(参见 :h quote_ ) 可以引用黑洞寄存器。 因此, "_d{motion}
会执行真正的删除操作。
复制专用寄存器"0
使用 y{motion}
命令时, 要复制的文本不仅会被拷贝到无名寄存器中, 而且也被拷贝到了复制专用寄存器 "0
。
复制专用寄存器 ,仅当使用 y{motion}
命令时才会被赋值。 换句话讲, 使用 x
、 s
、 c{motion}
以及 d{motion}
命令均不会覆盖该寄存器。
有名寄存器"a – "z
Vim提供了一组以26个英文字母(参见 :h quote_alpha ) 命名的有名寄存器。 因此可以剪切( “ad{motion}) 、 复制(”ay{motion}) 和粘贴(”ap) 多达26段文本。
用小写字母引用有名寄存器, 会覆盖该寄存器的原有内容;
用大写字母的话, 会将新内容添加到该寄存器的原有内容之后。
表达式寄存器"=
表达式寄存器可以用来执行一段Vim脚本
在普通模式中,执行"=
, Vim将跳到命令行模式, 并显示提示符“=”。 这时, 可以输入一段Vim脚本表达式并按 <CR>
执行, 如果返回的是字符串(或者可被强制转换成字符串的数据),Vim将会使用它。
在插入模式中, 输入 <Cr>=
,会在屏幕的下方显示提示符“=”, 可以在其后输入要执行的表达式, 输入表达式后敲一下 <CR>
,Vim就会把执行的结果插入文档的当前位置了。
<C-r>=6*35<CR> # 就会得到结果
只读寄存器
寄存器 | 等价方法 | 内容 |
---|---|---|
"% |
<C-r>% |
当前文件名 |
"# |
<C-r># |
轮换文件名 |
". |
<C-r>. |
上次插入的文本 |
": |
<C-r>: |
上次执行的Ex命令 |
"/ |
<C-r>/ |
上次查找的模式 |
系统剪切板"+
与选择专用寄存器"*
Vim的加号寄存器"+
与系统剪贴板等效相通。
Linux的X11视窗系统支持另一种被叫作主剪贴板(primary)的剪贴板,它保存着上次被高亮选中的文本,可以用鼠标中键(如果有的话)把它们粘贴出来。Vim的星号寄存器对应主剪贴板,可用*
号加以引用。
寄存器 | 用途 |
---|---|
"+ |
X11剪贴板, 用剪切、 复制与粘贴命令操作 |
"* |
X11主剪贴板, 用鼠标中键操作 |
Windows与Mac OS X操作系统并没有主剪贴板的概念, 因此 "+
寄存器与 "*
寄存器可以混用, 它们都代表系统剪贴板。
X11剪贴板的功能可在编译Vim时被激活或禁用。 如果想验证该功能是否在自己的Vim中被激活, 可运行 :version命令, 然后找到
xterm_clipboard关键字。 如果它前面有个减号, 就表示这个版本的Vim不支持该功能, 加号则表示此功能已被激活
用寄存器内容替换高亮选区的文本
在可视模式下使用 p
命令时, Vim将用指定的寄存器内容来替换高亮选区中的文本,
它不再把无名寄存器既用于复制又用于删除, 因为根本就没有删除这一步。 相反的, 把删除和粘贴合成了一步, 完成高亮选区的替换。
粘贴缩进问题
当在插入模式下使用系统粘贴命令时, Vim就像我们用手敲键盘一样地输入字符。 一旦 autoindent
选项被启用, 意味着每当创建新行时, Vim都会保持同级缩进。 剪贴板中每行起始的空格是在之前自动缩进的基础上累加出来的, 这样将导致一行比一行往右偏。
打开粘贴
paste
选项允许手动通知Vim“要使用系统粘贴命令了”。paste
选项启用后,Vim将禁用所有插入模式下的映射项与缩写,并重置很多选项,其中就包括autoindent
。
关闭粘贴
使用完系统粘贴命令之后,还要再次关闭paste
选项。这意味着先切换回普通模式,再运行Ex命令:setpaste!
。这样比较麻烦,可以通过下面的方法简化步骤:
paste
选项启用后, 在Vim插入模式下创建自定义映射项的方法都失效了。 作为替代方案, 可以把 pastetoggle
选项(参见 :h’pastetoggle’ ) 映射成一个功能键。
推荐::set pastetoggle=<f5>
终极方法(在xshell中没测试成功)
普通模式下的 “+p 命令用来粘贴加号寄存器中的内容, 即系统剪贴板的镜像。 更多细节, 请参见系统剪贴板(”+) 与选择专用寄存器(”*) 。 无论 paste
与autoindent
选项激活与否, 该命令都能保证位于剪贴板中的文本缩进不会乱套。
粘贴的推荐结论
p
与 P
命令对于粘贴多行文本区域非常重要, 但是对于小段的、 面向字符的文本来讲, 使用 <C-r>{register}
映射项的方式会更直观。
查找与正则
查找快捷键
命令 | 用途 |
---|---|
n | 跳至下一处匹配, 保持查找方向与偏移不变 |
N | 跳至上一处匹配, 保持查找方向与偏移不变 |
/ |
正向跳转至相同模式的下一处匹配 |
? |
反向跳转至相同模式的上一处匹配 |
gn | 进入面向字符的可视模式, 并选中下一处匹配 |
gN | 进入面向字符的可视模式, 并选中上一处匹配 |
相关设置
循环查找
:set wrapscan
:set ws
"如果只想在当前光标位置至文档结尾的范围内查找,而不想绕回文档继续查找的话
暂时关闭高亮
:set nohlsearch
命令彻底禁用查找高亮功能(使用 :se nohls
与 :se hls!
效果一样)。但在执行其他查找时,我们又可能想重新激活它。
:nohlsearch
命令暂时关闭查找高亮功能(参见 :h :noh
)。此命令使得高亮功能一直处于关闭状态,直到执行新的或重复的查找命令为止。
通过创建映射项,可以加速操作。
nnoremap<silent> <C-l> :<C-u>nohlsearch<CR><C-l>`
边输入边查找
:set incsearch
:预览第一处匹配
将光标匹配到结尾
/lang/e<CR>
查看多次后发现要移动到结尾处,可以不用重新输入模式,直接使用//e<CR>
历史记录
Vim会一直记录我们执行过的查找模式,因此可以方便地重用它们。
在普通模式想再次执行上一次的查找时可以不输入模式,直接按 n
, N
,/
或者?
,此时 Vim 将重用上一次的查找模式,然后正向或反向查找。
在命令行模式,当查找提示符/
或?
出现时,可以通过 <Up>
键,滚动浏览之前的查找记录。
自动补全
快捷键<C-r><C-w>
会用当前预览的匹配结果对查找域进行自动补全。如果已在查找域中输入了“carr”,执行该命令会将“ot”添加到结尾,使其最终匹配完整的单词“carrot”。
注意,
<C-r><C-w>
自动补全功能在查找内容中存在元字符\v
前缀时会有瑕疵,<C-r><C-w>
会把光标下的完整单词,而不是单词的余下部分,作为补全的内容(例如,执行补全后会变成/\vcarrcarrot<CR>
)。
大小写相关
临时区分大小写
/str\C 区分大小写
/str\c 不区分大小写
小写字母\c会让查找模式忽略大小写,而大写字母\C
会强制区分大小写。这两个元字符可以出现在模式的任意位置,不过在末尾可读写比较好。
smartcase选项
smartcase
选项被启用后,无论何时,只要在查找模式中输入了大写字母,ignorecase
设置就不再生效了。 换句话说,如果模式全是由小写字母组成的,就会按照忽略大小写的方式查找,但只要输入一个大写字母,查找方式就会变成区分大小写的了。
正则
转义问题之 一: very magic
案例
body { color: #3c3c3c; }
a { color: #0000EE; }
strong { color: #0000EE; }
想要匹配颜色
/#\([0-9a-fA-F]\{6}\|[0-9a-fA-F]\{3}\)
此例用到了3类括号。
- 方括号
[]
缺省具有特殊含义,因此不用转义。 - 圆括号
()
会按原义匹配普通字符(
及)
,因此需要转义,使其具有特殊含义。圆括号无论开闭括号都必须转义。 - 花括号
{}
也一样需要转义,不过,只需为开括号转义,而与之对应的闭括号则不用,因为Vim会推测我们的意图。
解决方法
可以利用 \v
模式开关来统一所有特殊符号的规则。该元字符将会激活 very magic搜索模式,即假定除_
、大小写字母以及数字0~9之外 的所有字符都具有特殊含义。因此上例进行修改后如下:
/\v#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})
由于出现在起始位置的\v
开关,位于它后面的所有字符都具有特 殊含义。这样一来,那些反斜杠字符就可以去掉了,可读性更强了。
总结
作为通用法则,如果想按正则表达式查找,就用模式开关 \v
,
而如果想按原义查找文本, \V
会使得其后的模式中只有反斜杠有特殊的意义。
转义问题之二:特殊字符的特殊处理
\V
原义开关使得按原义查找文本变得更容易,因为符号 .
、+
以及 *
的特殊含义被屏蔽掉了。但还有一些字符,其特殊含义无法被屏蔽。
要处理的字符串:http://vimdoc.net/search?q=/\\
正向查找时要转义 /
字符
/\Vhttp://vimdoc.net/search?q=/\\ # 错误写法
实际上只会匹配 /字符串/
,也就是/\Vhttp:/
,因此需要对/
进行转义
/\Vhttp:\/\/vimdoc.net\/search?q=\/\\\\ # 正确写法
反向查找时要转义?
号
与正向类似,匹配的内容是?字符串?
,因此需要对?
进行转义
?http://vimdoc.net/search\?q=/\\\\
查找域结束符/
与?
你可能会觉得奇怪,为什么查找域会把某个字符视为结束符呢?它为什么不把所有位于查找提示符之后的内容都纳入查找匹配呢?答案是如果在查找域结束符之后附加某些标志位,可以调 整Vim查找命令的行为。例如,如果运行命令 /vim/e<CR>
,光标将会移到每个匹配的结尾,而非起始。
每次都要转义符号 \
在查找域中,还有一个字符需要转义,即反斜杠。通常情况下,一 个 \
的出现预示着紧挨着它后面的字符将会得到某种特殊对待。如果变为 \\
,前者会消除后者的特殊含义,让Vim查找一个反斜杠。
无论采用的是正向还是反向查找方式,反斜杠字符永远都需要转义。
用编程的方式转义字符
用手动方式转义字符既耗时费力,又容易出错。幸运的是,Vim脚本提供了一个库函数escape({string}, {chars})
{chars}
参数将指定哪些字符需要用反斜杠转义。
- 如果要进行正向查找,可以调用
escape(str, '/\')
,它会为每个/
与\
加上反斜杠前缀。 - 如果进行的是反向查找,则要换用
escape(str,'?\')
"uyi
将正则复制到寄存器 u 中输入 / 或 者 ? 调出查找提示符
依次输入原义开关
\V
与<C-r>=
,Vim就会从查找提示符的状态切换到表达寄存器提示符的状态了=escape(@u, getcmdtype().'\')
getcmdtype()
返回命令类型,比如正向查找返回/
,反向返回?
在Vim脚本中,
.
起到连接字符串的作用,因此正向查找时getcmdtype().'\'
将产生/\
单词边界
< 与 > 单词前后定界符
/\v<the>
只匹配 the ,而不会匹配 these。这是零宽度元字符,它们本身不匹配任何字符,仅表示单词与围绕此单词的空白字符(或标点符号)之间的边界
子匹配
案例:查找重复的单词
/\v<(\w+)\_s+\1>
诀窍就在于 ()
与 \1
的组合使用。任何圆括号内部的匹配文本都会自动保存到一个临时的仓库。可以用 \1
引用这段被捕获的文本。另外,不论模式中是否使用了圆括号,元字符\0
永远会引用整个匹配。
\_s
会匹配空白符或换行符,\_
表示包含换行符,s
在正则中表示空白符,因此还以是\_w
匹配字母或换行符。
不捕获子匹配
有时只想使用圆括号的分组功能,但并不关心捕获的子匹配。例如,可以使用以下模式来匹配作者名字的两种形式。
/\v(And|D)rew Neil
这一次使用圆括号的目的在于匹配“Andrew”或者“Drew”,但并不想捕获位于圆括号内部的“And或D”。可以在圆括号前面 加上% ,指示Vim不要将括号内的内容赋给寄存器 \1
,就像这样。
/\v%(And|D)rew Neil
如果你发现自己经常会用到多组圆括号,使用
%
的速度会比原来快了一些
案例:把所有的名和姓调换位置
/\v(%(And|D)rew) (Neil)
:%s//\2, \1/g
该查找模式会把“Andrew”或者“Drew”赋给寄存器 \1
,而把“Neil”赋给寄存器 \2
。如果没有对第二组圆括号使用 %()
,便会得到无用的文本片段,从而扰乱替换域。
截取部分匹配
比如想查找带引号的字符串,比如:"Vim"
,但是只想修改 Vim,因此可使用元字 符 \zs
与 \ze
对匹配进行裁剪,使其成为这个完整模式的一个子集
/\v"\zs[^"]+\ze"
\zs
与\ze
之间的内容就是你感兴趣的内容,而外部的其他字符可以认为是额外的限制条件。
可以只有\zs
,比如查找Practical Vim,但只想修改 Vim,可以这样做:
/Practical \zsVim
增强*
功能
在普通模式下,*
命令可以查找光标下的单词。通过一小段 Vim脚本,可以重新定义可视模式下的 *
命令,使其可以查找当前选中高亮的文本,而不仅仅是光标下的单词。
xnoremap * :<C-u>call <SID>VSetSearch('/')<CR>/<C-R>=@/<CR><CR>
xnoremap # :<C-u>call <SID>VSetSearch('?')<CR>?<C-R>=@/<CR><CR>
function! s:VSetSearch(cmdtype)
let temp = @s
norm! gv"sy
let @/ = '\V' . substitute(escape(@s, a:cmdtype.'\'), '\n', '\\n', 'g')
let @s = temp
endfunction
可以直接将这段代码粘贴至你的 vimrc 文件中,或者安装visual star search插件。
工程目录查找:grep、vimgrep、ack
vim内部grep
vim的 :grep Waldo *
命令是对外部 grep 程序的包装,用法与 grep
一致,Vim将在后台为我们在shell中执行 grep -n Waldo *
定制 grep
配置grepprg
与grepformat
这两个选项,可以对 Vim 查找的行为进行定制。
grepprg="grep -n $* /dev/null"
grepformat="%f:%l:%m,%f:%l%m,%f %l%m"
grepprg:
$*
表示占位符,将会被:grep
命令的参数代替grepformat:
%f
表示文件名,%l
表示行号,%m
则表示匹配行的文本,%c
表示列号。字符串可以包含以逗号分隔的多组格式。
vimgrep
:vim[grep][!] /{pattern}/[g][j] {file} …
{file}
参数一定不能为空,它可以是文件名、通配符、反引号表达 式以及这些类型的组合
➾ :vim /going/g *.txt
除了可以使用和*
通配符外,也可以使用##
符号,它将被扩展成参数列表中的所有文件。
因此可以先把希望查找的文件加入参数列表,然后再在参数列表中的 所有文件上运行 :vimgrep
➾s :args *.txt
➾ :vim /going/g ##
优点:这种方式能够两件事分开:要在哪些文件中查找,以及要用什么模式查找。一旦文件被 加入参数列表,在这组文件上执行多少次
:vimgrep
命令都可以。
使用:vimgrep
的主要优点在于其使用的模式与Vim的查找命令一 致。如果是使用 :grep
在工程范围内查找相同模式,就不得不先把该模式转化成POSIX正则表达式
ack:beyond grep
首先,需要安装 ack
ubuntu
➾ $ sudo apt-get install ack-grep
➾ $ sudo ln -s /usr/bin/ack-grep /usr/local/bin/ack
OS X
➾ $ brew install ack
定制 ‘grepprg’ 与 ‘grepformat’ 这两个选项, 实现让 :grep
调用 ack
➾ :set grepprg=ack\ --nogroup\ --column\ $*
➾ :set grepformat=%f:%l:%c:%m
这样在浏览查找结果时,就可以跳转到每一处匹配的精确位置,而不仅是准确的行
grep采用的 是POSIX风格的正则表达式,ack则采用的是Perl风格的正则表达 式。如果 :grep命令在后台调用ack,可能会引起误导,因此也可以使用Ack.vim插件。fugitive.vim插件也提供了一个名为 :Ggrep的自定义命令用于执行git-grep。
替换
:[range]s[ubstitute]/{pattern}/{string}/[flags]
标志位
g
使得subsititute命令可在全局范围内执行,即可以修改一行 内的所有匹配,而不仅仅是第一处匹配。c
让我们有机会可以确认或拒绝每一处修改。n
会抑制正常的替换行为,即让 Vim 不执行替换操作,而只是报告本次 substitute 命令匹配的个数。- 执行 substitute 命令时,如果在当前文件中没有匹配到该模式,Vim 会提示错误信息“E486: 找不到模式”。标志位
e
专门用于屏蔽这些错误提 示。 &
仅仅用于指示Vim重用上一次substitute命令所用过的标志 位。技巧93展示了其应用的场景。
替换域中的特殊字符
一些字符在用作查找模式时具有特殊含义。替换域中也有一些特殊字符。过查询 :h sub-replacespecial ,可以找到完整的列表
符号 | 描述 |
---|---|
\r | 插入一个换行符 |
\t | 插入一个制表符 |
\\ |
插入一个反斜杠 |
\1 | 插入第1个子匹配 |
\2 | 插入第2个子匹配(以此类推,最多到 \9) |
\0 | 插入匹配模式的所有内容 |
& | 插入匹配模式的所有内容 |
~ | 使用上一次调用 :substitute时的 {string} |
\={Vim script} | 执行 {Vim Script} 表达式;并将返回的结果作为替换 {string} |
全局替换
将文件想象成二维平面,字符沿着x轴增加,文本行则随着y轴向下增长。在缺省情况下,substitute命令仅仅作用于当前行的第一处匹配。
为了使substitute命令作用于整个横轴,需要引入标志位g
。g
看似为全局之意(global),实则有误导之嫌。也许有人想借此标志位在整个文件范围内进行替换操作,但实际上,它仅表示“当前一整行范围”。
:s/going/rolling/g
怎样才能控制substitute命令在整个文件的纵轴上执行呢?
答案是设定一个范围。如果在substitute命令的开头加上前缀%
,它就会在文件的每一行上执行了。
:%s/going/rolling/g
每次替换进行询问
引入标志位c
后,vim 会对每处匹配结果提示“替换为str?”
Vim会体贴 地提示所有的选项“y/n/a/q/l/E/Y”。下表展示了每种答案的含义。
回答 | 用途 |
---|---|
y | Yes 替换此处匹配 |
n | No 忽略此处匹配 |
q | Quit 退出替换过程 |
l | last 替换此处匹配后退出 |
a | all 替换此处与之后所有的匹配 |
<C-e> |
向上滚动屏幕 |
<C-y> |
向下滚动屏幕 |
一分为二:先查找再替换
执行substitute命令通常包括两个步骤:
- 撰写查找模式
- 设计合适的替换字符串
利用查找的历史记录功能,可以将替换分为两步,先测试查找内容,然后进行替换。因此,一分为二的技术让我们消除了这两项任务的耦合性,这才是关键所在。
对于:%s/\n/,
将“换行替换为逗号”这种简单的命令,就没必要将它一分为二了,否则非但得不到 什么好处,反而有可能增加工作量。
对于复杂的内容,推荐一分为二。
➾ /\v'(([^']|'\w)+)'
将查找域留空,Vim将重用上一次的查找命令
➾ :%s//“\1”/g
实际上,我们刚才所做的等同于如下命令。
➾ :%s/\v'(([^']|'\w)+)'/“\1”/g
但是也有不好的影响,会在命令历史中留下一项不完整的记录,从而导致当再想重用之前的substitute命令时,会遇到困难。
如果你觉得将来会以完整形式来调用历史记录中的substitute命令, 就要养成在查找域中填充内容的习惯。只需在命令行中输入 <C-r>/
, 即可把上次的查找内容粘贴进来。因此,通过以下命令,就可以在命令历史中创建一项完整的记录。
➾ /\v'(([^']|'\w)+)'
➾ :%s/<C-r>//“\1”/g
global命令
:global
命令允许在某个指定模式的所有匹配行上运行Ex命令
:[range] global[!] /{pattern}/ [range][Excmd]
[Excmd]
可以是除 :global
命令之外的任何Ex命令,如果不指定任何 [Excmd]
,Vim将缺省使用 :print
。
:global!
或者 :vglobal
(v表示invert)反转:global
命令的行为。这两条命令将指示Vim在没有匹配到指定模式 的行上执行 [Excmd]
。
案例
复制TODO 内容
假设想把所有TODO项收集到一起。
首先运行
qaq
,将寄存器 a清空。:g/TODO/yank A
把包含TODO注释的行复制到此寄存器中要用大写字母A引用寄存器。这意味着Vim将 把内容附加到指定的寄存器,用小写字母 a的话,则会覆盖原有寄存器 的内容。因此,这条global命令可以被解读为“将所有匹配模式 /TODO/ 的文本行依次附加到寄存器 a。
"ap
命令,就可以将寄存器 a的内容粘贴进去 了。
另一种方案
该命令是将所有TODO项 复制到当前文件的末尾,而不是把它们附加到寄存器。
:g/TODO/t$
global 高级
假设想对 CSS 内容进行排序
html {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
# 排序后
html {
border: 0;
font-size: 100%;
font: inherit;
margin: 0;
padding: 0;
vertical-align: baseline;
}
命令
:g/{/ .+1,/}/-1 sort
分析
Ex命令通常都会接受“范围”作为其参数,因此 global 命令可以扩展为如下:
:g/{pattern}/[range][Excmd]
因此上面的排序命令可以分解为 2 部分
第一部分是g/{/
找到{
第二部分是.+1,/}/-1 sort
,其中.+1,/}/-1
表示范围,去掉偏移后:.,/}/
,
.
符号通常表示光标所在行,但在 :global
命令的上下文中,它则表示 {pattern}
的匹配行。因此.,/}/
的含义是“从匹配模式/{/
那一行开始,一直到匹配模式 /}/
的那一行为止”。
结论
:global
命令的广义形式如下:
:g/{start}/ .,{finish} [Excmd]
可以将其解读为“对从 {start} 开始,到 {finish} 结束的所有文 本行,执行指定的 [Excmd]”。
例子
假设想对某一段指定范围内的文本内容进行缩进,用Ex命令 :>
:g/{/ .+1,/}/—1 >
每当调用 :>
命令时,Vim都会提示一条信息。如果在 [cmd] 的前面加 上 :slient
(参见 :h :sil ),就可以屏蔽这些信息:
:g/{/sil .+1,/}/−1 >
文件
缓冲区列表:ls
查看缓存区
:ls
标记 +
号, 表示这个缓冲区被修改过了
标记为a
, 表示它当前是活动缓冲区(active)
标记为 h
, 表示它是一个隐藏缓冲区(hidden)
切换缓冲区
:bnext "切换
:bnext! "强制切换,不保存
退出缓冲区
:quit
当想关闭编辑会话时, vim就会提醒某个缓冲区中有未保存的修改 ,并把第一个有改动的隐藏缓冲区载入当前窗口, 这样就可以决定如何处理它。
- 如果要保留修改, 可以执行
:write
命令把缓冲区保存到文件; - 如果想摒弃此修改, 可以执行
:edit!
, 重新从磁盘读取此文件; - 如果会话里有不止一个被修改过的隐藏缓冲区,那么每次执行
:quit
命令时,都会激活下一个未保存的缓冲区。可以用:write
及:edit!
来保存或摒弃此修改。
在退出时, 处理隐藏缓冲区的方式总结
命令 | 用途 |
---|---|
:w[rite] | 把缓冲区内容写入磁盘 |
:e[dit]! | 把磁盘文件内容读入缓冲区(即回滚所做修改) |
:qa[ll]! | 关闭所有窗口, 摒弃修改而无需警告 |
:wa[ll]! | 把所有改变的缓冲区写入磁盘 |
参数列表:args
当不带参数运行 :args
命令时, 它会打印当前参数列表的内容。
另外, 也可以用下列格式来设置参数列表的内容
:args {arglist}
- 用文件名指定文件
:args index.html app.js
- 用 Glob 模式指定文件
:args **/*.js **/*.css
*符号用于匹配0个或多个字符, 但它的范围仅局限于指定的目录, 而不会递归其子目录(参见 :h wildcard )
** 通配符也匹配0个或多个字符, 但它可以递归进入指定目录的子目录
可以把这两种通配符结合起来用, 并加上部分文件名或目录名, 以此构造一个模式(即所谓的 glob模式)
用反引号读取命令指定文件
:args `cat chapters.txt`
参数列表比缓冲区列表更容易管理,这使其成为对缓冲区进行分组的理想方式。使用:args {arglist}
命令,一下就可清空并重新设置参数列表,接着可以用:next
及:prev
命令遍历参数列表中的文件,或是用:argdo
命令在列表中的每个缓冲区上执行同一条命令。
多屏幕
新建分屏
命令 | 用途 |
---|---|
在新窗口中打开同一缓冲区 | |
水平切分当前窗口, 新窗口仍显示当前缓冲区 | |
垂直切分当前窗口, 新窗口仍显示当前缓冲区 | |
在新窗口中打开另一个缓冲区 | |
:sp[lit] {file} | 水平切分当前窗口, 并在新窗口中载入{file} |
:vsp[lit] {file} | 垂直切分当前窗口, 并在新窗口中载入{file} |
先执行 <C-w>s , 再执行 :edit {filename} |
水平切分当前窗口, 并在新窗口中载入{file} |
先执行 <C-w> v, 再执行 :edit {filename} |
垂直切分当前窗口, 并在新窗口中载入{file} |
分屏切换
可以使用鼠标来激活窗口,请注意:set mouse=
TODO如何设置?
也可以使用快捷键来激活窗口
上下左右与hjkl
的一致
命令 | 用途 |
---|---|
在窗口间循环切换 | |
切换到左边的窗口 | |
切换到下边的窗口 | |
切换到上边的窗口 | |
切换到右边的窗口 |
关闭分屏
Ex 命令 | 普通模式命令 | 用途 |
---|---|---|
:clo[se] | 关闭活动窗口 | |
:on[ly] | 只保留活动窗口, 关闭其他所有窗口 |
调整分屏大小
完整的列表请查阅 :h window-resize
命令 | 用途 |
---|---|
使所有窗口等宽、 等高 | |
最大化活动窗口的高度 | |
最大化活动窗口的宽度 | |
[N] |
把活动窗口的高度设为[N]行 |
[N] |
把活动窗口的宽度设为[N]列 |
改变窗口大小是我喜欢用鼠标做的少量操作之一, 其做法很简单
重新排序分屏
window-moving
http://vimcasts.org/episodes/working-with-windows/
标签tab
Vim 的标签页与缓冲区并非一一对应的关系, 相反, 应该把标签页想成容纳一系列窗口的容器
技巧41 如何使用标签页 不太明白 TODO
:lcd {path}
命令让我们可以设置当前窗口的本地工作目录。 如果创建了一个新标签页, 并用 :lcd
命令切换到另一个目录, 就可以把每个标签页限制在不同的工程范围内。 注意: :lcd
只影响当前窗口,而非当前标签页。 如果一个标签页包含了两个或更多的窗口, 可以用:windo lcd {path}
命令为所有这些窗口设置本地工作目录。
打开和关闭标签
:tabedit {filename}
命令可以打开一个新的标签页, 如果省略了 {filename}
参数, 那么 Vim 会创建一个新标签页, 里面包含一个空缓冲区。
命令 | 用途 |
---|---|
:tabe[dit] {filename} | 在新标签页中打开 {filename},如果省略了 {filename} 参数, 那么 Vim 会创建一个新标签页, 里面包含一个空缓冲区。 |
\ |
把当前窗口移到一个新标签页 |
:tabc[lose] | 关闭当前标签页及其中的所有窗口 |
:tabo[nly] | 只保留活动标签页, 关闭所有其他标签页 |
标签页间切换
Ex 命令 | 普通模式命令 | 用途 |
---|---|---|
:tabn[ext] {N} | {N}gt | 切换到编号为 {N} 的标签页 |
:tabn[ext] | gt | 切换到下一标签页 |
:tabp[revious] | gT | 切换到上一标签页 |
重排标签
:tabmove [N]
命令可以重新排列标签页
- 当 [N] 为0时, 当前标签页会被移到开头
- 如果省略 [N], 当前标签页会被移到结尾
如果终端支持鼠标可以通过鼠标拖曳来进行重排操作。
使用sudo保存文件
➾ :w !sudo tee % > /dev/null
《 Password:
W12: Warning: File "hosts" has changed and the buffer was
changed in Vim as well
[O]k, (L)oad File, Load (A)ll, (I)gnore All:
此时进行两次交互。 首先要输入用户的密码, 然后 Vim 会警告我们该文件已被修 改了, 并显示出一个选项菜单。 这里建议按 l
键重新将该文件载入缓冲区。
这条命令是如何工作的?
:write !{cmd}
命令会把缓冲区的内容作为标准输入传给指定的 {cmd}
, {cmd}
可以是任何外部程序。 虽然Vim仍然是以普通用户运行的, 但是可以让调用的外部进程以超级用户权限运行。
在本例中, tee
程序将以sudo权限运行, 也就是说它拥有写 /etc/hosts
文件的权限。在 Vim 命令行中, %
符号具有特殊含义。 它会展开成当前文件的完整路径/etc/hosts
。 因此,该命令的后半部分可以展开为下面的命令:tee /etc/hosts >/dev/null
。 这条命令会把缓冲区的内容当作标准输入, 并用它来覆盖/etc/hosts
文件的内容。
之后, Vim 会检测到该文件已经被一个外部程序修改。 一般情况下, 这意味着缓冲区中的内容和文件不同步了, 这就是为什么 Vim 会提示我们做出选择, 是要保留缓冲区中的版本, 还是载入磁盘上的版本 。
宏
按键
黄金法则:在录制一个宏时,要确保每条命令都可被重复执行。
q{register} 录制
q 停止
@{register} 命令执行指定寄存器的内容
100@{register} 以串行方式重复 100 次命令,执行指定寄存器的内容
@@ 来重复最近调用过的宏
点与宏
对于重复次数不多的工作,点范式是一种高效的编辑策略, 但它不能指定执行的次数。为了克服该限制,可以录制一个廉价 的、一次性的宏,然后再加次数进行回放。
11;.
会先运行11次 ;
命令,再运行1次 .
命令,因此并不会运行成功。
通过录制一个最简单的宏,可以模拟执行11次的 ;.
,即 qq;.q
,然后11@q
首先 qq将指示Vim录制后续的按键操作并将它们保存至寄存器q中。然后再输入命令
;.
。最后按下q键结束宏的录制。可以加上次数11执 行这个宏 11@q,即执行11次;.
。
并行宏
执行宏的时候,如果遇到错误,后续的内容将不会继续执行,因此为了避免某一行文本运行失败而提前退出宏,推荐并行宏
1. one
2. two
// break up the monotony
3. three
4. four
步骤:
qa
0f.r)w~
q
jVG
可视模式选择剩余行:'<,'>normal @a
对剩余行都执行寄存器 a 中的宏
1( One
2( Two
// break up the monotony
3( Three
4( Four
追加宏
你可能遇到刚一按下
q
键,停止了宏的录制,才发现应该在结束之前按一下j
键,将光标移至下一行。
在输入 qa
时,Vim将开始录制接下来的按键操作,并将它们保存到寄存器 a
中,这会覆盖该寄存器原有的内容。
如果输入的是 qA
,Vim也 会录制按键操作,但会把它们附加到寄存器a
原有的内容之后。可以用这种方式更正该错误。
修改宏
用于录制宏的寄存器,与用作复制、粘贴操作的寄存器相同。因此,如果想修改寄存器 a中的宏,只需将其粘贴至文档中,便可以像编辑普通文本一样编辑它了。
:put a
把寄存器 a中的内 容粘贴至新的一行- 修改宏内容
0
回到行首"ay$
复制宏内容到寄存器 a 中,"add
会将换行符都复制进去,因此不推荐dd
删除文本
宏中的变量
partridge in a pear tree
turtle doves
French hens
calling birds
golden rings
最终想变成这样
1) partridge in a pear tree
2) turtle doves
3) French hens
4) calling birds
5) golden ring
:let i=1
设置变量qa
开始录制I<C-r>=i<CR>)<Esc>
插入变量 i:let i += 1
变量递增q
退出录制
配置
可以将定制化的选项写入文件,加以保存。此后通过 :source {file}
命令加载配置。在加载文件时,Vim会把每一行文本当作Ex
命令加以执行,就好像在Vim命令行上执行它们一样。
每当想在当前缓冲区应用这些配置项时,可以运行这条命令::source two-space-indent.vim
vimrc 的路径
- 单次启用某个配置项,在命令模式下,先输入一个冒号,再输入配置
- 用户个人的配置
- 在UNIX 系统中,Vim希望能找到路径为 ~/.vimrc的文件
- 在Windows系统 中,理想的文件路径为 $HOME/_vimrc
- Vim 的全局配置一般在
/etc/vim/vimrc
或者/etc/vimrc
,对所有用户生效
无论运行的是哪种系统,都可以通过:edit $MYVIMRC
来编辑配置文件,:source $MYVIMRC
为当前的Vim 会话加载新的配置选项,如果活动的缓冲区是vimrc文件则可以简化为:so%
查看、设置参数
对于布尔类型,要么打开,要么关闭。”关闭”就是在”打开”前面加上前缀no
。以 ‘ignorecase’ 选项为例
:set ignorecase "打开
:set noignorecase "关闭
:set ignorecase! "反转该设置
:set ignorecase? "获取该选项当前的状态
:set ignorecase& "重置为默认值
对于要用到字符串或者数字的配置
:set tabstop=2
:set ts=2 sts=2 sw=2 et "可以用一条 set 语句设置多组选项。
另外,大多数Vim选项都有其简写形式。
生效范围
局部生效
Vim的设置项通常全局生效,但有些选项只对一个窗口或缓冲区生效。例如,当运行 :setlocal tabstop=4
时,只会影响当前活动的缓冲区。这意味着我们可以打开不同的文件,并为每个文件单独定制。
缓冲区生效
如果我们想在现有的所有缓冲区内应用同样的设置,可以运行以下命令。
:bufdo setlocal tabstop=4
窗口生效
‘number’ 选项只在窗口范围内生效。运行 :setlocal number
时,Vim将会激活当前活动窗口的显示行号功能。如果想为每个窗口都激活该功能,可以运行下面这条命令。
:windo setlocal number
末行命令自动补全
" 末行命令自动补全
set wildmenu " (跟下面组合使用?没看出效果)
set wildmode=longest:list,full "命令模式下,底部操作指令按下 Tab 键自动补全。第一次按下 Tab,会显示所有匹配的操作指令的清单;第二次按下 Tab,会依次选择各个指令。
为特定类型的文件应用个性化设置
我们的偏好设置有可能根据文件的类型不同而有所差异。例如,假设排版格式要求,对 Ruby文件要采用两个空格的缩进,而对JavaScript 文件采用4列宽度的制表符。
if has("autocmd")
filetype on
autocmd FileType ruby setlocal ts=2 sts=2 sw=2 et
autocmd FileType javascript setlocal ts=4 sts=4 sw=4 noet
autocmd FileType javascript compiler nodelint
endif
autocmd语句的检测机制将指示Vim监听某一类事件,一旦该事件发生,Vim将执行指定的命令(参见 :h :autocmd )。在本例中, 将监听 FileType事件,它会在Vim检测出当前文件类型时被触发。可以为相同类型的事件添加不止一条自动命令。
如果想在某一类文件中应用很多项设置,这样做会使 vimrc 变得很乱。另一种方法是使用文件类型插件(ftplugin)来定制不同文件类型。针对不同的语言,都有单独的配置文件,路径为~/.vim/after/ftplugin/javascript.vim
setlocal ts=4 sts=4 sw=4 noet
compiler nodelint
为了能够使用 ftplugin 机制,必须确保检测文件类型的功能以及插件功能都被激活了。请检查 vimrc,看看是否包含了filetype plugin on
推荐的配置
http://www.ruanyifeng.com/blog/2018/09/vimrc.html
外观、代码风格
" 颜色相关
syntax on "打开语法高亮,自动识别代码
set hlsearch "搜索时,高亮显示匹配结果
set hls "高亮显示匹配到的关键字‘hlsearch’
“set noh 取消高亮显示匹配结果
”set nohlsearch 取消高亮显示匹配结果
set showmatch "光标遇到圆括号、方括号、大括号时,自动高亮对应的另一个圆括号、方括号和大括号
set t_Co=256 "启用256色
" 换行相关
set tabstop=4 "按下Tab 键时,Vim 显示的空格数
set wrap "自动折行,即太长的行分成几行显示。
set linebreak "不会在单词内部折行。只有遇到指定的符号(比如空格、连词号和其他标点符号),才发生折行
" 光标位置相关
set scrolloff=5 "垂直滚动时,光标距离顶部/底部的行数,方便看到后面的内容
set sidescrolloff=15 "水平滚动时,光标距离行首或行尾的位置(单位:字符)。该配置在不折行时比较有用
" 状态栏相关
set ruler "在状态栏显示光标的当前位置(位于哪一行哪一列)
set laststatus=2 "是否显示状态栏。0:不显示,1:只在多窗口时显示,2:显示
set showmode "在底部显示,当前处于命令模式还是插入模式
set showcmd "命令模式下,在底部显示,当前键入的指令。比如,键入的指令是2y3d,那么底部就会显示2y3,当键入d的时候,操作完成,显示消失。
" 辅助显示
set nu
set number "显示行号
set list "如果行尾有多余的空格(包括 Tab 键),该配置将让这些空格显示成可见的小方块。与listchars配合使用
"""""""""""""" 没效果或没用的😁
" set cursorline 光标所在的当前行用下划线高亮(没什么用)
" set relativenumber 显示光标所在的当前行的行号,其他行都为相对于该行的相对行号。(没什么用)
" set spell spelllang=en_us 打开英语单词的拼写检查(不推荐,太亮了)
" set textwidth=80 设置行宽,即一行显示多少个字符。(没效果?)
" set wrapmargin=2 指定折行处与编辑窗口的右边缘之间空出的字符数
编辑相关
set mouse=a "支持使用鼠标
set encoding=utf-8 "使用 utf-8 编码。
" 缩进相关
set autoindent "按下回车键后,下一行的缩进会自动跟上一行的缩进保持一致
set expandtab "tab转为空格,而不是\t。
set softtabstop=4 "Tab 转为多少个空格
filetype indent on "开启文件类型检查,并且载入与该类型对应的缩进规则。比如,如果编辑的是.py文件,Vim 就是会找 Python 的缩进规则~/.vim/indent/python.vim
set history=1000 "Vim 需要记住多少次历史操作。
set nocompatible "不与 Vi 兼容(采用 Vim 自己的操作命令)。
" 文件备份、历史相关
set nobackup "不创建备份文件。默认情况下,文件保存时,会额外创建一个备份文件,它的文件名是在原文件名的末尾,再添加一个波浪号(〜)。
set swapfile "创建交换文件。交换文件主要用于系统崩溃时恢复文件,文件名的开头是.、结尾是.swp。
set undofile "关闭文件后仍保留撤销历史。Vim 会在编辑时保存操作历史,用来供用户撤消更改。默认情况下,操作记录只在本次编辑时有效,一旦编辑结束、文件关闭,操作历史就消失了。打开这个设置,可以在文件关闭后,操作记录保留在一个文件里面,继续存在。这意味着,重新打开一个文件,可以撤销上一次编辑时的操作。撤消文件是跟原文件保存在一起的隐藏文件,文件名以.un~开头。
set autochdir "自动切换工作目录。这主要用在一个 Vim 会话之中打开多个文件的情况,默认的工作目录是打开的第一个文件的目录。该配置可以将工作目录自动切换到,正在编辑的文件的目录。
set backupdir=~/.vim/.backup// "要新建这个文件夹
set directory=~/.vim/.swp// "要新建这个文件夹
set undodir=~/.vim/.undo// "要新建这个文件夹
" 设置备份文件、交换文件、操作历史文件的保存位置。结尾的//表示生成的文件名带有绝对路径,路径中用%替换目录分隔符,这样可以防止文件重名。
set autoread "打开文件监视。如果在编辑过程中文件发生外部改变(比如被别的编辑器编辑了),就会发出提示。
" 末行命令自动补全
set wildmenu "(跟下面组合使用?没看出效果)
set wildmode=longest:list,full "命令模式下,底部操作指令按下 Tab 键自动补全。第一次按下 Tab,会显示所有匹配的操作指令的清单;第二次按下 Tab,会依次选择各个指令。
""""""" 暂时不知道有什么用的
set shiftwidth=4 "在文本上按下>>(增加一级缩进)、<<(取消一级缩进)或者==(取消全部缩进)时,每一级的字符数
"实际行与屏幕行相关的按键映射
nnoremap k gk
nnoremap gk k
nnoremap j gj
nnoremap gj j
nnoremap <Space> <C-f> "Vim 空格翻页
map <F12> :set mouse=<CR> "F12按键设置为关闭鼠标选择功能
搜索相关
set incsearch
set is "输入搜索模式时,每输入一个字符,就自动跳到第一个匹配的结果
set ignorecase
set ic "搜索时忽略大小写
set smartcase "如果同时打开了ignorecase,那么对于只有一个大写字母的搜索词,将大小写敏感;其他情况都是大小写不敏感。比如,搜索Test时,将不匹配test;搜索test时,将匹配Test
自动生成相关
"创建py自动添加头部 jizx
func SetTitle()
call setline(1, "\#!/usr/bin/python")
call setline(2, "\# -*- coding=utf8 -*-")
call setline(3, "\"\"\"")
call setline(4, "\# @Author : jizhongxian@baidu.com")
call setline(5, "\# @Created Time : ".strftime("%Y-%m-%d %H:%M:%S"))
call setline(6, "\# @Description : ")
call setline(7, "\"\"\"")
normal G
normal 10o
call setline(10, "def main():")
call setline(11, " pass")
call setline(13, "def test():")
call setline(14, " pass")
call setline(16, "if __name__ == '__main__':")
call setline(17, " main()")
endfunc
autocmd bufnewfile *.py call SetTitle()
tab相关
缩进<
与>
要想让 <
和 >
命令正常工作, 需要把 ‘shiftwidth’ 及‘softtabstop’ 的值设为4, 并启用 ‘expandtab’ 选项。 如果想了解这些配置是如何协同工作的, 请查阅Vimcasts.org上的“Tabs and Spaces”主题。
tab and space
http://vimcasts.org/episodes/tabs-and-spaces/
tabstop, softtabstop, shiftwidth, expandtab
如果你喜欢使用 tab,那应该确保 tabstop == softtabstop
. 减少缩进时混淆 tabs 和spaces。
如果你喜欢使用 space, 那应该确保 softtabstop == shiftwidth
. 这样在不论在插入模式中 按下tab键,还是在普通/可视模式中使用缩进命令>
,都可以保证插入相同数量的空格。
" put all this in your .vimrc or a plugin file
" Set tabstop, softtabstop and shiftwidth to the same value
command! -nargs=* Stab call Stab()
function! Stab()
let l:tabstop = 1 * input('set tabstop = softtabstop = shiftwidth = ')
if l:tabstop > 0
let &l:sts = l:tabstop
let &l:ts = l:tabstop
let &l:sw = l:tabstop
endif
call SummarizeTabs()
endfunction
function! SummarizeTabs()
try
echohl ModeMsg
echon 'tabstop='.&l:ts
echon ' shiftwidth='.&l:sw
echon ' softtabstop='.&l:sts
if &l:et
echon ' expandtab'
else
echon ' noexpandtab'
endif
finally
echohl None
endtry
endfunction
https://stackoverflow.com/questions/1562336/tab-vs-space-preferences-in-vim/1610732#1610732
关于粘贴缩进问题
结论:使用:set paste
在Vim中粘贴Python代码后,缩进就全乱了。仔细研究了以下,原来是自动缩进的缘故,于是做如下设置:
:set noai nosi
取消了自动缩进和智能缩进,这样粘贴就不会错行了。但在有的vim中不行,还是排版错乱。
后来发现了更好用的设置:
:set paste
进入paste模式以后,可以在插入模式下粘贴内容,不会有任何变形。这个真是灰常好用,情不自禁看了一下帮助,发现它做了这么多事:
textwidth设置为0
wrapmargin设置为0
set noai
set nosi
softtabstop设置为0
revins重置
ruler重置
showmatch重置
formatoptions使用空值
下面的选项值不变,但却被禁用:
lisp
indentexpr
cindent
怪不得之前只设置noai和nosi不行,原来与这么多因素有关!
快捷键设置
但这样还是比较麻烦的,每次要粘贴的话,先set paste,然后粘贴,然后再set nopaste。更方便的方法是使用键盘映射:
:map <F10> :set paste<CR>
:map <F11> :set nopaste<CR>
这样在粘贴前按F10键启动paste模式,粘贴后按F11取消paste模式即可。其实,paste有一个切换paste开关的选项,这就是pastetoggle。通过它可以绑定快捷键来激活/取消 paste模式。比如(暂时没试成功)
:set pastetoggle=<F11>
这样减少了一个快捷键的占用,使用起来也更方便一些。
以上这些设置只是打开这次回话才有效,想要永久有效,需要在~/.vimrc
中添加上面的命令
" 不需要冒号
set pastetoggle=<F11>
自动补全
<C-p>
在插入模式下触发自动补全,并向上选择候选项(prev)
<C-n>
在插入模式下触发自动补全,并向下选择候选项(next)
补全类型
命令 | 补全类型 |
---|---|
<C-n> |
普通关键字 |
<C-p> |
普通关键字 |
<C-x><C-n> |
当前缓冲区关键字 |
<C-x><C-i> |
包含文件关键字 |
<C-x><C-]> |
标签文件关键字 |
<C-x><C-k> |
字典查找 |
<C-x><C-l> |
整行补全 |
<C-x><C-f> |
文件名补全 |
<C-x><C-o> |
全能(Omni) 补全 |
不论使用哪种自动补全命令,当其弹出式菜单出现时,都可以用
ignorecase
选项被启用后,在自动补全时也会忽略大小写,在自动补全时也会忽略大小写,可以通过set infercase
选项来修正这一行为。
弹出框操作
按键操作 | 作用 |
---|---|
<C-n> |
使用来自补全列表的下一个匹配项(next 匹配项) |
<C-p> |
使用来自补全列表的上一个匹配项(previous 匹配项) |
<Down> |
选择来自补全列表的下一个匹配项,但不改变文本 |
<Up> |
选择来自补全列表的上一个匹配项,但不改变文本 |
<C-y> 或<CR> |
确认使用当前选中的匹配项(yes) |
<C-e> |
还原最早输入的文本(从自动补全中exit) |
<C-h> (与 <BS> ) |
从当前匹配项中删除一个字符 |
<C-l> |
从当前匹配项中增加一个字符 |
{char} | 中止自动补全并插入字符 {char} |
实时更新补全列表
在与自动补全弹出式菜单的交互过程中,输入 <C-n><C-p>
是我最喜欢的技巧之一:在不关闭弹出式菜单的情况下,可以继续输入文本,而Vim将实时过滤补全列表。
该技巧对于其他自动补全功能也同样有效。例如,可以通过 <C-x> <C-o><C-p>
对全能补全的结果进行实时性过滤。
定制普通关键字自动补全
普通关键字自动补全,会把来自于缓冲区列表、包含文件以及标签文件的单词列表组合在一起,并生成补全建议。如果想改变该功能的行为,可以通过complete
选项来定制普通关键字补全时扫描的位置。该选项包含一组由逗号分隔的单个字符,当某个参数出现时,就意味着需要扫描该参数代表的位置。该选项的缺省设置为complete=.,w,b,u,t,i
。可以使用以下命令禁止扫描所有的包含文件。
:set complete-=i
或者,可以通过以下命令来激活拼写字典自动补全功能。
:set complete+=k
请查阅 :h ‘complete’ ,以便了解各个参数的作用。
启用字典
有时候,我们可能想通过自动补全功能输入某个单词,但它并没有在任何打开的缓冲区、包含文件或者标签文件中出现过。在这种情况下,可以在字典中查找。
为了激活该功能,需要为Vim提供一份合适的单词列表。最简单的方法就是通过运行 :set spell
也可以通过dictionary
’选项来指定一个或多个含有单词列表的文件(参见 :h ‘dictionary’)
补全一整行
当使用自动补全功能补全单词时,Vim会记住该单词的来源位置。如果紧接着再次调用自动补全功能,Vim就会插入位于其后的单词。可以一次次重复此动作以插入整个单词序列。用这种方式复制短句通常比复制粘贴更快。
Vim的自动补全不仅仅可以插入单词序列,也可以用于插入一系列行。如果重复使用 <C-x><C-l>
命令(技巧116),就可以插入文档其他位置上的若干个连续的行。
补全文件名
Vim的文件名自动补全功能只相对于工作目录的路径进行扩展,而不是相对于当前编辑文件的路径,理解这一点很重要。
通过 :pwd
命令(print working directory)获取到工作目录的路径信息
通过 :cd {path}
命令(change directory)随时切换工作目录
根据上下文自动补全
技巧 119
输入 ba,由于“ba”作为CSS属性 的一部分,因此显示的列表内容将包括 background、background-attachment以及其他的几种属性。在此例中,选择的是 backgroundcolor。而当第二次触发全能补全时,尽管没有输入任何文本,但Vim会根据上下文判断出我们需要的是颜色信息,因此,它提供了3项补全建议:#
、rgb(
以及 transparent
。
拼写检查
拼写检查快捷键
:set spell ”启用拼写检查
:set spelllang=en_us “设置拼写字典,默认是英文
[s "反向跳转
]s "正向跳转
z= "更正建议列表
zg "把当前单词添加到拼写文件中,即可避免以后对该单词的错误检查,使Vim可以识别它
zw "把当前单词从拼写文件中删除
zug "撤销针对当前单词的zg或zw命令
使用其他拼写字典
内置了支持英语的拼写文件,可以 到http://ftp.vim.org/vim/runtime/spell/ 下载它支持的其他几 十种语言的拼写文件
定制专有名词字典
很多单词,如grep。我既不想让Vim将它们标记为拼写错误,也不想让Vim视其为合法的英语单词。作为折中方案,单独维护一个单词列表,专门用于保存Vim的术语。这样一来,在撰写 Vim相关的文章时,可以随时把它作为拼写文件加载进来。
setlocal spelllang=en_us
setlocal spellfile=~/.vim/spell/en.utf-8.add
setlocal spellfile+=~/books/practical_vim/jargon.utf-8.add
‘spellfile’ 选项,可以指定一个文件路径,用于保存 由 zg 和 zw 命令添加、删除的单词
~/.vim/spell/en.utf-8.add
是缺省路径,它保存所有由 zg 命 令添加的单词
~/books/practical_vim/jargon.utf-8.add
保存由我维护的Vim术语列表
现在对于每一个被拼写检查器误判的单词,目前都有两种处理方式,既可以通过 2zg
将其添加到Vim的术语列表中,也可以通过 1zg
将其添加到缺省的单词列表中。
插入模式下使用自动补全
只有某行文本出现的拼写错误不止一处时,<C-x>s
命令才能充分发挥出其优势,然后使用<C-p>
<C-n>
进行上下选择
根据创建的文件类型产生模板
在~/.vimrc
中添加一下内容,即可在创建*.py
时,自动添加头部信息
func SetPyTitle()
call setline(1, "\#!/usr/bin/python")
call setline(2, "\# -*- coding=utf8 -*-")
call setline(3, "\"\"\"")
call setline(4, "\# @Author :")
call setline(5, "\# @Created Time : ".strftime("%Y-%m-%d %H:%M:%S"))
call setline(6, "\# @Description : ")
call setline(7, "\"\"\"")
normal G q''''''
normal o
normal o
endfunc
autocmd bufnewfile *.py call SetPyTitle()
创建*.sh
时,自动添加头部信息
func SetShTitle()
call setline(1, "\#!/usr/bin/sh")
call setline(2, "\source ~/.bashrc")
call setline(3, "")
call setline(4, "\# @Author : ")
call setline(5, "\# @Created Time : ".strftime("%Y-%m-%d %H:%M:%S"))
call setline(6, "\# @Description : ")
call setline(7, "")
normal G q''''''
normal o
normal o
endfunc
autocmd bufnewfile *.sh call SetShTitle()
插件推荐
surround.vim 用它可以很容易地给选中的文本加分隔符
matchit.vim 可以在配对的关键字间跳转
其他
自定义操作符:h :map-operator
自定义动作命令 :h omapinfo
别将反向字符查找命令弃之不用
技巧 50
Vim 几乎为键盘上的每个键都赋予了一个功能。 如果想创建自定义映射项, 那么该把它们绑定到哪个键上呢? Vim 提供了一个 <Leader>
, 以此作为用户自定义命令的名字空间。 下面的例子显示了如何利用 <Leader>
来创建自定义映射项。
noremap <Leader>n nzz
noremap <Leader>N Nzz
缺省的<Leader>
键是\
,因此可以按\n
和\N
来触发刷新屏幕的功能。 在有些键盘上, \
命令不太容易够到, 因此 Vim 允许把<Leader>
键映射为其他更方便的字符(参见 :h mapleader) 。 一个普遍的选择是把逗号设置为 <Leader>
键。 如果你也是这么做的, 我强烈建议把反向字符查找命令映射为另一个键。 下面给出了一个例子。
let mapleader=","
noremap \ ,
;
和,
命令是互为补充的, 如果去掉了其中一个,整个字符查找命令集的用处就会大打折扣了。
交互式教程
TODO
技巧31没看懂
第7,9,16,17章还没看
技巧70
gn 的作用
c%(
技巧92
技巧 73 的总结
技巧21 gv命令会激活可视模式,并重新将上次被选中的文本高亮起 来
技巧96 交换两个或更多的单词
技巧97 在多个文件中执行查找与替换
虚拟替换模式替换制表符
POSIX风格的正则表达式,Perl风格的正则表达式来了解一下