##VIM第一步
U
一次撤销一行的全部操作。第二次使用该命令会撤销前一个U
的操作。u
和CTRL_R
撤销和重做ctrl_]
跳转到一个标签,ctrl_t
弹出标签可以回到前一个位置,ctrl_o
跳转到较早的位置。help
help {subject}
help ctrl-a
help i_ctrl-a
help -t
命令行选项help i_<Up>
help 'number'
help
help 'subject'
选项help subject()
函数help -subject
命令行参数help +subject
编译选项help eventname
引发自动命令的事件help digraphs.txt
帮助文件help pattern<Tab>
help pattern<ctrl-d>
同时列出匹配pattern
的所有可能的帮助主题helpgrep pattern
在所有帮助文件中搜索全部文本查找指定的pattern
并定位到第一个匹配的位置,用cn
跳转到下一个匹配项,cprev
或cN
跳转到前一个匹配项,cfirst
clast
分别跳转到第一个/最后一个匹配项。copen
cclose
打开/关闭快速修改窗口,在该窗口按<enter>
可以跳到当前光标所意指条目。
##移动
w
向前移动一个word,到下一个word的首字符上,b
向后移动到前一个word的首字符上。e
向前移动到下一个word的最后一个字符上,ge
向后移动到前一个word的最后一个字符上。- 有一些被认为是
non-word
的特殊字符,比如.
,-
或)
充当了word边界的作用。要改变Vim对word边界的定义,请查看iskeyword
选项。还可以以空白为分界的WORDs为单位进行移动。这种WORD与通常意义上的word的边界不同。所以此处用了大写的WORD来区分于word. 它的移动命令也是相应字母的大写形式。 $
命令将光标移动到当前行行尾。如果你的键盘上有一个<End>
键,它的作用也一样。^
命令将光标移动到当前行的第一个非空白字符上0
命令则总是把光标移动到当前行的第一个字符上。<Home>
键也是如此。- 一个最有用的移动命令是单字符搜索命令。命令
fx
在当前行上查找下一个字符x. 提示:f
意为find
.F
命令向左方向搜索。tx
命令形同fx
命令,只不过它不是把光标停留在被搜索字符上,而是在它之前的一个字符上。提示:t
意为To
. 该命令的反方向版是Tx
。这4个命令都可以用;
来重复。以,
也是重复同样的命令,但是方向与原命令的方向相反。 - 写程序的时候很容易被层层嵌套的()给弄糊涂。此时使用命令
%
就太方便了:它跳转到与当前光标下的括号相匹配的那一个括号上去。这对方括号[]和花括号fg同样适用。(具体可以处理哪些括号可以由matchpairs
选项来定义)。如果当前光标并没有停留在一个可用的括号字符上,%
也会向前为它找到一个。所以如果当前光标位于上例中的行首,%
命令还是会向前先找到第一个(
,然后找到与它匹配的)
。 G
命令。指定一个命令计数,这个命令就会把光标定位到由命令计数指定的行上。比如33G
就会把光标置于第33行上。另一个移动到某行的方法是在命令%
之前指定一个命令计数. 比如50%
将会把光标定位在文件的中间.90%
跳到接近文件尾的地方。Vim对百分比的计算是以行为单位,不是字节数,如何跳转到以字节数为百分比或为偏移的字符上去?:goto 3
。上面的这些命令都假设你只是想跳转到文件中的某一行上,不管该行当前是否显示在屏幕上。但如果你只是想移动到目前显示在屏幕上的那些行呢?H
意为Home,M
为Middle,L
为Last.- CTRL-U命令会使文本向下滚动半屏。也可以想象为在显示文本的窗口向上滚动了半屏。CTRL-D命令将窗口向下移动半屏,所以相当于文本向上滚动了半屏。要向前滚动一整屏(实际上是整屏去两行)使用命令CTRL-F(forward). 另外CTRL-B(backward)是它的反向版。很幸运CTRL-F是向前,CTRL-B是向后。
zz
命令会把当前行置为屏幕正中央。zt
命令会把当前行置于屏幕顶端,zb
则把当前行置于屏幕低端。/string
命令可用于搜索一个字符串。字符.*[]^%/?~$
有特殊意义,如果你要找的东西包括这些内容,要在这些字符前面放置一个反斜杠。?
命令与/
的工作相同,只是搜索方向相反。- 把光标定位于这个word上,然后按下
*
键。Vim将会取当前光标所在的word并以它为目标字符串进行搜索。#
命令是*
的反向版。还可以在这两个命令前加一个命令计数:3*
查找当前光标下的word的第三次出现。 - 查找整个word,如果你用
/the
来查找Vim也会匹配到there
. 要查找作为独立单词的the
使用如下命令:/the\>
。\>
是一个特殊的记法,它只匹配一个word的结束处。近似地,\<
匹配到一个word的开始处。这样查找作为一个word的the
就可以用:/\<the\>
。这个命令就不会匹配到there
或soothe
.注意*
和#
命令会在内部使用这些标记word开始和结束的特殊标记来查找整个的word(你可以用g*
和g#
命令来同时匹配那些包含在其它word中的字串。) - 如果你在编辑一段源程序时看到了一个叫
nr
的变量。你想查看一下这个变量都被用在了哪些地方。简单的办法是把光标移到nr
上然后用*
命令和n
命令一个一个地查找所有的匹配。:set hlsearch
现在你要再查找nr
, Vim就会以某种形式高亮显示所有符合的匹配。对于想查看一个变量被用在哪些地方,这个办法太棒了,不需任何其它的命令。如何排除函数外别处同名变量的干扰呢?答:/\%<3l
限定。 :set incsearch
使得你在键入目标字符串的过程中Vim就同时开始了搜索工作。使用这种方法可以让你在尚未完全键入字串时就能找到目标。set nowrapscan
该设置会使搜索过程在文件结束时就停止。或者,在你反向搜索时在到达文件开头时停止。wrapscan
选项的默认值是开,这样搜索在到达文件的头尾时都会绕向另一个方向继续进行。- 当你用
G
命令从一个地方跳转到另一个地方时,Vim会记得你起跳的位置。这个位置在Vim中是一个标记。使用下面的命令可以使你跳回到你刚才的出发点:````。再次使用上面的这个命令你就会又跳回来了。这是因为也是一个跳转命令,所以上次跳转时的起跳位置现在被标记为了
。更一般地说,只要你执行一个命令使光标定位于当前行之外的某行上去,这都叫一个跳转。包括`/`和`n`这些搜索命令(不管被找到的东西离当前位置有多远). 但是字符搜索命令`fx`和`tx`, 或者是以word为单位的移动光标位置的命令`w`和`e`不叫跳转。同时,`j`和`k`命令并不被视为一个跳转,即使你在它们之前加了命令计数让当前光标跳到老远的地方也是如此。``命令可以在两点之间来回跳转。`CTRL-O`命令是跳转到你更早些时间停置光标的位置(提示:O意为older). `CTRL-I`则是跳回到后来停置光标的更新的位置(提示:I在键盘上位于O前面).使用`CTRL-I `与按下``键一样。`:jumps`命令会列出关于你曾经跳转过的位置的列表。你最后一个跳转的位置被特别以一个`>`号标记。 - Vim允许你在文本中定义你自己的标记。命令
ma
将当前光标下的位置名之为标记a
. 从a到z一共可以使用26个自定义的标记。定义后的标记在屏幕上也看不出来。不过Vim在内部记录了它们所代表的位置。要跳转到一个你定义过的标记,使用命令{mark}</code>, {mark}就是你定义的标记的名字。命令<code>'mark</code>(单引号,或者叫呼应单引号)会使你跳转到mark所在行的行首。这与
mark略有不同,`mark会精准地把你带到你定义mark时所在的行和列。 - 可以使用
:marks
查看关于标记的列表。列表里会有一些特别的标记。'
进行此次跳转之前的起跳点,```上次编辑该文件时光标最后停留的位置,[
最后一次修改的起始位置,`]`最后一次修改的结束位置。 ##小幅改动 - 就象
dd
命令可以删除整行一样,cc
命令可以改变整行。不过仍保持原来的缩进(一行打头的空白).也正如d$
删除到行尾为止的内容,c$
改变当前光标到行尾的内容。就好象是用d$
删除然后又以a
进入Insert模式追加新的文本一样。有一些操作符+位移命令使用率是如此之高以至于它们以一个单独的字符作为其快捷方式:x
代表dl(删除当前光标下的字符),X
代表dh(删除当前光标左边的字符),D
代表d$(删除到行尾的内容),C
代表c$(修改到行尾的内容),s
代表cl(修改一个字符),S
代表cc(修改一整行)。3d2w
是删除两个word, 重复执行3次,总共是6个word. r
命令不是一个操作符命令。它等待你键入下一个字符用以替换当前光标下的那个字符。你也可以用cl
或s
完成同样的事情,但用r
的话就不需要再用键回到Normal模式了。要把一个字符替换为一个换行符使用r<Enter>
. 它会删除一个字符并插入一个换行符。在此处使用命令记数只会删除指定个数的字符:4r<Enter>
将把4个字符替换为一个换行符。.
命令是Vim中一个简单而强大的命令。它会重复上一次做出的改动。.
命令会重复你做出的所有修改,除了u
命令CTRL-R和以冒号开头的命令。.
需要在Normal模式下执行,它重复的是命令,而不是被改动的内容。- 如果你想整行整行地操纵文本,使用
V
进入Visual模式。你会看到被选中的文本是一整行为最小选择单位。此时左右移动命令毫无意义。而上下位移命令则会整行整行地选择文本。 - 如果你想以一个矩形的文本块为对象进行操作,你需要用CTRL-V进入Visual模式(在MS-Windows下使用CTRL-Q代替,CTRL-V保留原来的粘贴功能)。在编辑表格时这可就派上用场了。
- 如果你已经在Visual模式下选中了一些文本,但此时发现还要改变另一头的被选择区域,
o
命令(提示:o代表other end另一头)会让光标置于被选中文本的另一头,这样你就可以通过控制光标移动来决定被选文本将从何处开始。再按o
又会让光标置于被选文本的末端。当你进行矩形文本块内容的选择时,你有4个角都可以改变。o
只会把你带到对角的位置去,使用O
命令可以让你在同一行的左右两个角之间移动。 P
命令与p
一样取回被删除的内容,不过它把被取回的内容置于光标之前。对于以dd
删除的整行内容,P
会把它置于当前行的上一行。对于以dw
删除的部分内容,P
会把它放回到光标之前。也可以对命令p
和P
命令使用命令记数。它的效果是同样的内容被取回指定的次数。这样一来dd
之后的3p
就可以把被删除行的3份副本放到当前位置。y
操作符命令会把文本复制到一个寄存器中(指默认的寄存器)。然后可以用
p命令把它取回。因为
y是一个操作符命令,所以你可以用
yw来复制一个word. 同样可以使用命令记数。注意
yw复制的内容中包括了word之后的空白字符。如果你不想要它们,那就用
ye.
yy命令复制一整行,就象
dd是删除一整行一样。不过并不象
D删除当前光标至行尾的内容那样,
Y也是复制整行的内容。注意这种规律中的例外!复制当前光标至行尾的命令是
y$`.- 如果你用的是Vim的GUI版本(gvim),你会在
Edit
菜单中发现Copy
命令。首先在Visual模式下选择一些文本,然后用Edit/Copy菜单。现在被选择的文本就被复制到了剪贴板。这样你就可以在其它程序里粘贴这些内容了。当然也可以在Vim里面使用(从技术上说,此处的Copy命令与Normal模式下的yank命令区别在于工具栏或菜单中的Copy是把内容复制到了各应用程序共享的公用剪贴板上,Vim中对应的寄存器是*,而y命令则把文本对象复制到了Vim内部的默认寄存器上`上,它是Vim私有的)。如果你在其它应用程序里把文本内容复制到了剪贴板,也可以用Vim的Edit/Paste菜单把它粘贴过来。这在Normal模式和Insert模式下都可以。在Visual模式下被选中的文本就会被粘贴进来的内容给替换掉。 - 如果你没用GUI, 或者你不喜欢用菜单,你也可以用另一种方法来做同样的事。使用通常的
y
(yank)和p
(put)命令,不过在命令之前附加一个*(一个双引号,紧挨着是一个星). 要把一行内容复制到剪贴板:``*yy
,要把剪贴板的内容复制过来:``*p`。这些功能只有Vim支持剪贴板操作时才可用。 - 如果光标位于一个单词的中间而你要删除这个单词,通常你需要把光标移到该单词的开头然后用
dw
命令。不过有一个更简单的办法:daw
。daw
中的d
还是操作符命令。aw
是一个文本对象。提示:aw
意为A Word
. 这样daw
的完整意思是Delete A Word
, 更准确地说,该Word之后的空白字符也被删除了(即位于行末尾的单词之前的空白). cis
由操作符c
和文本对象is
组成。它是Inner Sentence
的缩写。相应地还有一个叫as
(a sentence)的。如果你想删除一个句子,你会希望把它后面的空白也给删除,所以此时最好用das
.如果你是想以新的文本替代它,空白就可以留下来,使用cis
好了。- 你也可以在Visual模式使用文本对象。它将把指定的文本对象选进Visual模式的文本选择区域中。当前模式仍是Visual模式,所以你可以多次使用该命令。例如,以
v
开始Visual模式,以as
选取一个句子。现在你可以重复使用as
来包括进更多的句子。最后你可以用一个操作符命令来作用于最终被选中的范围。查看文本对象列表:help text-objects
。 R
命令会让Vim进入replace模式。在此模式下,每个键入的字符都会替换掉当前光标下的字符。直到你键入结束该模式。R
命令会在无字符可替换时继续拓展该行以容纳更多你要键入的内容。不过并不会延续到下一行。- 可以在
:help operator
中找到一个操作符命令的列表。I
将光标置于当前行第一个非空白字符处并进入Insert模式。~
改变当前光标下字符的大小写,并将光标移至下一个字符。A
当光标置于当前行尾并进入Insert模式。
##定制vim
:version
命令会列出vim是在哪些目录中寻找vimrc的。
- 对某种文件类型来说最常用的选项可以放在一个Vim中叫文件类型plugin的脚本里。你还可以加上你自己写的,请参考
:help write-filetype-plain
.
- Vim为 众 多 不 同 的 文 件 类 型 提 供 了 相 应 的 缩 进 方 案。请 参考
filetype-indent-on
和indentexpr
选项。
:map
命令(不带参数)会列出当前已定义的映射。它至少会包括定义在Normal模式下的映射。
- 当你启动Vim时,它会自动载入一些全局的plugin,你不必额外地做任何事情。这些plugin定义了使用率很高的一些功能,但它们是以一个Vim脚本的形式而不是通过内建于Vim可执行文件内来提供。你可以在
standard-plugin-list
发现一个此类plugin的列表。另外请参考load-plugins
.你可以通过添加一个全局的plugin来获得额外的功能,这只需两步:1.得到这个plugin文件。2. 把它放到指定的目录下。
- 自己写plugin,参考
write-plugin
。
- 与全局plugin所在的目录一样,通过查看这个plugin是否提到了某个文件类型,就可以知道它是全局的还是专用于某种文件类型的,在
$VIMRUNTIME/macros
下的脚本是全局的,而在$VIMRUNTIME/ftplugin
目录下的则是专用于特定文件类型的。
- 你可以通过把一个文件类型plugin脚本放入相应的目录来完成对它的添加。路径跟添加全局plugin时的一样,不过最后一个目录名是
ftplugin
. 假设你找到了用于stuff
文件类型的plugin,目前你在Unix系统上,那么你可以这样加入该文件:mv thefile ~/.vim/ftplugin/stuff.vim
。如果这个目录下已经有了一个同名文件。你就要停下来仔细检查一下两个文件是否会引起冲突,如果没问题,你可以把要加入的新文件更名一下:mv thefile ~/.vim/ftplugin/stuff_too.vim
。下划线用于分隔用于标识文件类型的部分和其它部分,下划线其后的部分可以自由命名。如果你用otherstuff.vim
这样的名字,Vim可不能识别它,它只会在文件类型是otherstuff
时被载入。在MS-DOS上你不能使用长文件名。如果你要用一个辅助的plugin但是文件类型字符串已经超过了6个字符(MS-DOS文件名部分限制为小于等于8个字符,所以这里说文件类型字符串不能超过6个字符,因为下划线本身要占用一个字符,辅助plugin的其余部分至少会有一个字符)这就会有麻烦,不过你还可以通过一个额外的目录来处理这种情况:mkdir $VIM/vimfiles/ftplugin/fortran
copy thefile $VIM/vimfiles/ftplugin/fortran/too.vim
。文件类型plugin的文件名一般形式是:ftplugin/<filetype>.vim
,ftplugin/<filetype>_<name>.vim
,ftplugin/<filetype>/<name>.vim
。<filetype>
部分是plugin所服务的目标文件类型。只有相应类型的文件才能应用到这个plugin. plugin文件中的<name>
部分对Vim的识别工作并不起使用,你可以对几种不同的plugin都使用一样的<name>
部分也没问题。注意这些文件必需以.vim
为扩展名。
- 推荐阅读
filetype-plugins
关于文件类型plugin的文档以及如何避免映射引起冲突的信息,load-plugins
关于Vim启动过程中何时载入全局plugin,ftplugin-overrule
如何强制改变全局plugin中的设置,write-plugin
如何写一个plugin脚本,plugin-details
关于如何使用plugin或者解决你的plugin出现的bug,new-filetype
如何检测新文件类型。
- 在
runtimepath
选项里列出的目录列表中选一个目录,建立它的一个子目录doc
,:!mkdir ~/.vim/doc
。把帮助文件copy到这个doc
目录下,:!cp $VIMRUNTIME/macros/matchit.txt ~/.vim/doc
。用:helptags
命令生成一个本地化的tags文件,:helptags ~/.vim/doc
。参考write-local-help
了解更多关于写一个本地化的帮助文件的信息。
- 在
:options
中查找vim设置选项。
- 随时可以用
:help
命令来获得关于它们的更详细解释,记住在选项关键字的前后放上一个单引号。万一你把一个选项值改到自己难以收拾残局,还可以在该选项的后面放一个&符号使它恢复其默认值,如:`:set iskeyword&`。
- Vim中多数移动光标的命令会在遇到行首或行尾时停止不动。`whichwrap`选项可以用来控制这些移动光标的命令此时的行为规则。下面的设置是它的默认值
set whichwrap=b,s
。这样光标位于行首时按退格键会往回移动到上一行的行尾。同时在行尾按空格键也会移动到下一行的行首。要让左右箭头键在遇到行的边界时也能智能地上上下下,使用命令::set whichwrap=b,s,<,>
。这些都是只针对于Normal模式。要让左右箭头键在Insert模式下也能如此::set whcihwrap=b,s,<,>,[,]
。对h, l命令无效,要使h, l命令也能绕到当前行之外,需要:set whichwrap+= l,h
。
- 文件中含有制表符时,你并不能看到它们。要让这些制表符成为可见的字符:
:set list
。现在每个制表符都会以^I
显示。同时每行行尾会有一个$
字符,以便你能一眼看出那些位于一行尾部的多余空格。这样做的缺点是文件中制表符很多时整个屏幕看起来就很抱歉了。如果你的终端支持彩色显示,或者使用的是GUI, Vim就可以把制表符和空白字符高亮起来显示。这要配合使用下面的listchars
选项::set listchars=tab:>-,trail:-
。现在每个制表符会以>---
显示,同时行尾空格以-
显示。
iskeyword
选项定义了一个word中可以包含哪些字符::set iskeyword
iskeyword=@,48-57,_,128-167,224-235
,@
在这里代指所有的字母,48-57
指ASCII码从48到57的那些字符,即0到9。其余的是可打印拉丁字母。有时候你可以想把连字符也视为word的一部分,这样象w
命令就会把upper-case
看作是一个word了::set iskeyword+=-
,要把一个字符清理出去使用操作符-=
.
- Vim启动时会在窗口最底部留下一行用于显示信息。要显示的信息太长时,Vim或者把它截短让你只能看到部分内容,或者多出来的信息需要你按下回车键以滚动显示。你可以设置
cmdheight
选项来控制拿出几行来显示这些信息:set cmdheight=3
。
##使用语法高亮
- 终端上颜色代码0表示暗色,1表示亮色,而2位数字的颜色代码中十位数字4表示背景色,3表示前景色,个位数字0表示黑色,1为红,2为绿,3黄4蓝5紫6青,7为白。以;分隔不同的项,m结束一个定义,如
echo -e "\e[1;32mthis is green \e[0;37m"
会显示亮绿色,然后恢复为暗白色。
- 可以通过
set ft=markdown
来设置文件类型,也可以通过modeline
设置文件类型,可以把例如# vim: syntax=markdown
放入靠近文件的末尾。查看new-filetype
了解vim是如何确定一个文件的类型的。可以自己写一个语法高亮文件,参考mysyntaxfile
。
- 编辑
~/.vim/colors
文件夹中的vim文件,term
黑白终端的显示属性 ,cterm
彩色终端的显示属性,ctermfg
彩色终端的前景色,ctermbg
彩色终端的背景色,gui
GUI的显示属性,guifg
GUI的前景色,guibg
GUI的背景色。要让注释变为绿色:highlight Comment ctermfg=green guifg=green
可以用于cterm
和gui
的属性是bold
和underline
.如果你想兼具两者的效果,可以写成bold,underline
.更多的细节请参考:highlight
.syntax reset
重置语法高亮,syntax clear
暂时关闭语法高亮,syntax off
彻底关闭语法高亮。
- 在MS-Windows版本的Vim中你可以用下面的命令打印当前的文件:
:hardcopy
。要打印部分行,可以使用Visual模式选择被打印行,用下列命令:v100j:hardcopy
。把当前文件使用:TOhtml
转换成HTML格式使用浏览器打印。:source $VIMRUNTIME/syntax/2html.vim
。
##编辑多个文件
:edit foo.txt
,强制Vim丢弃当前未保存的修改并开始编辑新的文件,使用强制执行修饰符:edit! foo.txt
,想编辑另一个文件,但又不想保存当前文件中的改动也不想放弃当前文件的改动,你可以使它变为一个隐藏的缓冲区:hide edit foo.txt
。
vim one.c two.c three.c
命令启动vim后只显示第一个文件,完成编辑后使用:next
开始下一个文件的编辑。放弃当前改动开始下一个文件的编辑:next!
。:wnext
保存当前改动并开始编辑下一个文件。:previous
回到前一个文件。:last
移到最后一个文件。:first
移动到第一个文件。:2next
向前跳过2个文件。:args
查看整个列表中都有哪些文件。
:set autowrite
自动保存,编辑某个不希望自动保存的文件时,:set noautowrite
。
- 编辑另一个文件列表,
:args five.c six.h seven.cpp
或者:args *.java
。当然也可以使用:args!
放弃当前文件列表中未存盘的内容。
- 要在两个文件间快速切换,使用
CTRL-^
。注意CTRL-^
命令并不改变当前你在文件列表中的位置,只有命令":next"和":previous"才会引起此位置的变化。
- 跳转到另一个文件后,你还可以使用两个十分有用的标记:
"`,这个标记会带你到上次你离开该文件时光标所在的位置。另一个标记则是你最后一次对文件做出改动处:
.`。
- 可以用
mx
在一个中某个设置一个标记,然后用``x`可以将光标移到该位置。这只在当前文件内有效,如果你编辑了其它的文件并且也在其中设置了标记,这些标记将只对这个的文件有效。每个文件都有它自己的标记。它们是局部于文件的。目前为止我们用的标记还都是以小写字母命名的。还有一种以大写字母命名的标记。它们是全局标记,它们可以用在任何文件中。
- 要知道某个标记所代表的位置是什么,可以将该标记的名字作为
marks
命令的参数::marks M
。
set backup
,set backupext=.bak
- 如果你在编辑的是程序源文件,你可能会希望保存一份修改前的原始文件的一个副本。但是用备份文件的话它会在每次你写文件时被覆盖。这样备份文件将总是保存前一个版本的内容,而不是原始的版本。
patchmode
选项可以让Vim保存原始文件,它指定了备份该原始版所用的文件扩展名:set patchmode=.orig
。如果你第一次开始编辑data.txt文件,改一些东西然后存盘,Vim会保留一份该文件的原始版在data.txt.orig
中。如果你继续修改该文件,Vim也会注意到名为data.txt.orig
的文件已经存在,后续生成的备份文件将被命名为data.txt~
(或者你用backupext
选项指定的其它扩展名).如果你把patchmode
选项设置为空(默认情况正是如此), 文件的原始副本就不会被额外保存。
- 如果你要从一个文件中复制出好几块独立的文本到另一个文件中去,可将这些独立的文本存到一个寄存器中去可以避免繁琐的切换。寄存器只是Vim用来存放文本的地方。这里我们只用从a到z这26个寄存器(稍后你会发现还有其它的寄存器). 来把一个句子复制到名为f的寄存器中(f意为first):
:fyas
。"yas"命令象前面一样复制一个句子。告诉Vim把复制的内容放到寄存器f中的部分是"f
. 而且必需放在复制命令的前面。现在把3个整行的内容放到寄存器l中(l意指line):"l3Y
。要复制一个文本块到寄存器b中(b意为block):CTRL-Vjjww"by
。注意指定寄存器的部分"b紧挨在y命令的前面。这是必需的。放在"w"命令前面就不行。现在你分别在寄存器f, l, 和b中保存了3块不同的内容。开始另一个文件的编辑,将光标移到你想复制内容的地方然后:"fp
。指定寄存器的部分"f必需出现在p命令的前面。
- 要想只追加几行的内容到文件中在Visual模式下选定要写入的内容。然后用命令
:w >>logfile
追加到logfile。
- 以只读方式运行vim:
vim -R file
。如果你改动了该文件但忘了它是只读的,你还是可以保存该文件。在:write
命令之后使用!强制执行修饰符。如果是想强制性地避免对文件进行修改,可以用命令:vim -M file
,这样每个修改文件的尝试都会失败。帮助文件就是这样,比如,你试着去修改帮助文件时会看到这样的错误信息:E21: Cannot make changes, 'modifiable' is off
。你可以用-M选项告诉Vim工作在viewer模式。这都是表明你自愿如此,毕竟下面的命令还是可以去掉这层保护::set modifiable :set write
。
- 删除一个文件其中不需要的部分。现在可以把它存成一个新文件了。
:saveas
命令正好可堪此任::saveas move.c
。Vim会以给定的文件名保存当前缓冲区中的内容,同时开始编辑该文件。这样下次你再用:write
命令的话,它就是存成move.c
,而copy.c
还保持原来的内容。
##分割窗口
:close
可以关闭当前窗口,不同于:q
和ZZ
,但是:close
命令会阻止关闭最后一个窗口,以免意外地整个关闭了vim。如果打开了一大堆窗口,现在只想把重心放到其中一个上面,:only
会关闭除当前窗口外的所有其他窗口。
- 如果要打开一个新窗口并开始编辑一个空的缓冲区,使用命令:
:new
。
- ":split"命令还可以接受一个参数。如果指定了这个参数的话,它将会作为新打开窗口的高度。比如下面的命令就打开了一个高度为3行的新窗口并在其中编辑名为alpha.c的文件:
:3split alpha.c
。
##使用GUI
gvim test.c
vim -g test.c
set guiopitons-=T
:set guioptions+=l
参考guioptions
- 在微软Windows操作系统下,你可以用鼠标以通用的方式选取文本。X windows系统也有使用鼠标的标准。不幸的是,这两个标准本身并不相同。幸运的是,你还可以定制Vim. 你可以让以X windows的方式或微软的方式来使用你的鼠标。下面的命令控制鼠标遵循X Window标准:
:behave xterm
,下面的命令则使鼠标服从微软的标准::behave mswin
。xterm鼠标:左键单击 定位光标,左键拖动 在Visual模式下选取文本,中键单击 粘贴剪贴板的内容,右键单击 扩展被选择的文本到单击的位置。微软Windows下的鼠标行为:左键单击 定位光标,左键拖动 在Visual模式下选取文本,左键单击,同时按下Shift键 扩展被选择的文本到单击的位置,中键单击 粘贴剪贴板的内容,右键单击 显示弹出菜单。定制鼠标:mouse
Vim在哪些模式中使用鼠标,mousemodel
控制鼠标单击效果,mousetime
双击鼠标的间隔时间,mousehide
键入时隐藏鼠标,selectmode
控制如何可以进入Visual模式或选择模式。
- 要使被选取的文本变成"当前选择区", 使用Visual模式。例如,要选取整行的话按"V".在当前光标前插入"当前选择区"的内容:
"*P
,注意大写的"P". 小写的"p"是把文本放到当前光标的后面。"+寄存器指代"真正的剪贴板". 例如,要把自当前光标至行尾的内容放到该剪贴板:"+y$
。把"真正剪贴板"的内容放到当前光标之前:"+P
。
- 选择模式类似于Visual模式,因为它也用于选择文本。但是两者有一个明显的区别:键入文本时,被选择的文本会被删除,新键入的内容会取代它。要用Select模式,你得先打开它(对MS-Windows很可能已经是打开的了,但你还是可以手工打开它):
:set selectmode+=mouse
。现在用鼠标去选取一些文本。它会象Visual模式下一样被高亮。按下一个字符。被选择的文本将被删除,按下的字符取代了它。现在你置身于Insert模式,可以继续键入了。因为键入任何文本都会抹去被选取区域的内容,你不能用Normal模式下的"hjkl", "w"等等这些命令。不过你可以用Shift 功能键。(按住Shift键的同时按左光标键)将把光标左移。被选取部分的变化跟在Visual模式下一样。其它的Shift+光标键也行为正常。还可以使用和.
##大刀阔斧
- 录制宏
- 如果已经执行过"@a"命令,下次重复执行只需再下"@@"即可。这比"@a"更容易键入。同样,如果你上次执行的是"@b"那么"@@"命令也将重复"@b"的动作。与"."方法相比,记录回放有几个地方不同,首先,"."命令只能重复一个动作。而在上例中,"@a"重复的是好几个命令,其次,"."命令只重复最近一次改动的命令。而执行一个记录宏允许你随时都可执行同样的操作。最后,你拥有多达26个寄存器可供使用。也就是说,可以同时保存26个不同的命令宏。
- 用于命令记录的寄存器与用于yank和删除命令的寄存器是同一个东西。所以还可以多种方式混合操作这些寄存器。假设你在寄存器n中记录了一些命令。执行时发现有些命令弄错了。当然你可以再重来一遍,但是还有其它办法补救:G 到文件最后,o 生成一个新行,"np 将寄存器n的内容置于该行。你会看到这些命令就象你键入的普通文本一样,{edits} 修改错误的部分,这与编辑普通文本无异,0 到行首,"ny$ 将正确的结果回存到寄存器n中,dd 删除这行草稿。
- 目前为止我们用到的还都是小写字母的寄存器。要向寄存器追加内容而不是覆盖它,使用它的大写形式即可。假设你已经记录了一个改变word的命令在寄存器c中。它已经可以正常工作,但你又想让它搜索到下一个word继续编辑。可以使用下面的命令:
qC/word<Enter>q
,以"qC"命令开始,这使得被记录的命令将被追加到寄存器c中,而不是覆盖它当前的内容。这种方式对命令记录和一般的yank, 删除操作都有效。比如你要把几行的内容收集到一个寄存器中去,以小写来yank第一行:"aY
,现在移动到第二行,执行:"AY
,对你要收集的行重复执行这个操作。现在寄存器a就会包括所有这些行的内容。
:%s/Professor/Teacher/gc
l 把现在这个改完就退出吧,CTRL-E 向上滚屏一行,CTRL-Y 向下滚屏一行。
- 如果你要替换的字符串中包含了斜杠/, 就需要在它前面加一个反斜杠,一个更优雅的办法是用另一个字符替换/作为命令中各部分的分隔符:
:s+one/two+one or two+
。
:1,5s/this/that/g
,:54s/President/Fool/
,有一个命令在你不指定作用范围时默认是对整个文件进行操作。要使它们只作用于当前行上,可以在命令前放一个".". ":write"就是这种命令的典型。不指定作用范围,它将写入整个缓冲区的内容。下面的命令使它只把当前行写入指定文件::.write otherfile
,第一行的行号一定是1. 但是最后一行呢?"$"用于代表最后一行。比如,下面命令替换当前行到最后一行中所有的yes为no::.,$s/yes/no/
,所以,前面用到的"%"范围指定符号,实际上等价于"1,$".
- 使用一个搜索模式来指定作用范围:
:?^Chapter?,/^Chapter/s=grey=gray=g
。这里用了两个搜索模式。第一个"?^Chapter?" 向后查找,"/^Chapter/"向前。为了避免眼花瞭乱的斜杠/, ":s"命令使用"="字符作为分隔符。其实上例中还略有瑕疵:如果下一章的标题中刚好含有"grey"那么它也将会被替换掉。也许你要的就是这种效果,但如果不是呢?可以对命令的作用范围指定一个偏移作为微调:找到一个符合的模式并使用它上面的一行:/Chapter/-1
($-1是倒数第二行,编辑器里也有offset by one
),可以用任何数字来替换1. 要定位匹配模式其下的第2行:/Chapter/+2
。作用范围的上下偏移也可用于以其它形式::.+3,$-5
,这个范围从当前行其下的第3行开始,到倒数第6行。
- 使用标志可以免于上面的行号计算:在某处作上标记,然后以此标记来指定作用范围。如用"mt"来标记一个范围的开始,"mb"标记它的结束。然后就可以这样指定这个范围:(包括标记本身所在的行)
:'t,'b
。
- 如果你在Visual模式下选定了文本后按下了":", 你将会看到如下命令:
:'<,'>
,现在你只需直接键入命令,作用范围已由'<,'>
指定好了,它代表你在Visual模式下选定的文本所在的范围。<和
>实际上就是标记,分别代表一个Visual选择区域的开始和结束。退出Visual模式后这两个标记仍然保持,直到下一次进入Visual模式。所以你还可用"'<"命令来跳转到你一次在Visual模式时选定的文本区域的开始处。也可以混合使用多种方法指定作用范围::'>,$
,它表示自上一次Visual模式时选定的文本区域的结束处到文件尾这样一个区域。
- 如果你已经知道要使命令作用于几行内容,可以直接按下这个数字,然后按":". 比如,按下"5:", 你会看到:
:.,.+4
,你要做是直接键入命令。它将作用的范围是"."(当前行)到".+4"(自当前行到向下4行). 所以一共是5行。
- ":global"命令是Vim最强大的功能之一。它允许你找到符合某个匹配模式的行然后将命令作用其上。下面是其一般形式:
:[range]global/{pattern}/{command}
,乍 一 看 它 与":substitute"命 令 很 像。但 是, 这 里 执 行 的 是由{command}指定的命令。备注:":global"中所谓的命令都必需是以":"开始的命令行命令,Normal模式下的命令不能直接使用。:normal命令可以间接地让你使用Normal模式下的命令。
- 假设你想把C++风格的注释中的所有"foobar"替换为"barfoo"(这些注释将以"//"开始):
:g+//+s/foobar/barfoo/g
,该 命 令 以":g"开 始, 它 是":global"的 缩 写, 象":s"是":substitute"的缩写一样。接下来是以加号分隔的搜模式。因为我们要搜索的内容中包括有斜杠/, 所以此处用加号来分隔命的不同部分。最后是将"foobar"替换为"barfoo"的命令。全局命令的默认作用范围是整个文件。所以此例中没有指定作用围。这一点与命令":substitute"不同,它在没有指定作用范围时默认对前行一行起作用。上面给出的命令还不足以精确达到它的目标,因为它也匹配那些"//"出现在一行中间的情形,这时如果在"//"之前也出现了"foobar那么它也会被误换掉。
- 使用CTRL-V可以进入一种特殊的选择模式,在此模式下你可以选择一个矩形的文本块。Vim提供了一些特别的命令来操纵这个文本块。在Visual block模式下"$"命令会让每一行的被选择区域扩展到该行的末尾,不管这些行的长短是否参差不齐。这种选择状态持续到你发出下一个改变水平选择域的命令。所以使用命令"j"会保持这种状态,而"h"命令则会停止它。
- 是以CTRL-V进入Visual block模式。然后移动光标来调整被选择的区域。接下来键入I命令进入插入模式,键入你要插入的文本。在你键入文本的过程中,被键入的内容只会同时显示在文本块的第一行中。一旦你按下来结束插入,刚刚键入的内容就会奇迹般地出现在被选择文本块的每一行中。还有命令
c
,C
,A
等可以在此使用。~
转换大小写,U
将小写变大写,u
将大写变小写。"r"将使整个文本块的内容全部以一个字符来填充。">"命令会使你的文本块向右移动一个"shift单位", 空出来的部分放置以空格。被移动的区域起自文本块左边界。移动的多寡由选项shiftwidth
指定。欲使之移动4个空格::set shiftwidth=4
。"<"命令使文本块向左移动一个"shift单位". 不过它不象">"一样姿意,它受限于文本块左边的空间,所以如果文本块左边的空白区域短于一个"shift单位", 它也无能为力。
- "J"命令使文本块纵跨的所有文本行被连接为一行。换行符不存在了,实际上,换行符,以及每行的前导空白和后辍空白都将被替换为单个的空格。连接后的句子结尾将被放两个空格(可以通过
joinspaces
改变连接后的空格数).如果你想保留那些前导空白和后辍空白,用"gJ"命令来代替"J"。
- 前导空白正则表达式是
/^\s\+
,后缀空白正则表达式是/\s\+$
。
- ":read"命令还可接受一个行范围。被读入的文件被放在这个范围的最后一行上。所以":$r patch"将会把文件"patch"的内容追加到当前文件的最后。如果你要把文件放在第一行的上面呢?答案是特殊行号0. 当前行号为0的行并不存在。如果你以此行号作为目标行执行大多数其它命令,你会得到一个错误信息。但对"read" 命令而言允许现在这样的命令:
:0read patch
,文件"patch"将会被放在第一行的上面。
- 要写入指定范围行,可以用命令":write". 没有指定一个范围时该命令将写入整个文件的内容。指定一个范围的话它就只写入指定的行:
:.,$write tempo
,这个命令将从当前行到文件尾的内容写入文件"tempo"。:.w collection
将当前行写入到collection文件中去,.w >>collection
将当前行追加到collection中去。
- 在键入文字的时候每行的内容能自动调节到适应当前窗口的大小
:set textwidth=72
。
gqap
格式化当前文本段。gq
是vim中的一个操作符,ap
代表"a paragraph"。
guw
将词小写,gUw
将词大写。删除操作子是"d",所能删除一行的命令是"dd". 同样,"gugu"使一整行变为小写。此外,它还可简写为"guu". "gUgU"简写为"gUU", "gg"简写为"g~~"。
- 命令"!fmotiongfprogramg"以一块文本为对象将它们通过管道送至一个外部程序。换句话说,由{program}指定的外部程序,接受由{motion}命令指定的文本块作为输入,以它的输出来替换{motion}指定的文本块。
!5Gsort<Enter>
结果是sort程序将前5行排序。将输出替换这5行的内容。"!!"命令过滤当前行的内容。在Unix系统中"date"命令会显示当前的日期和日间。"!!date"会以"date"命令的输出来替换当前行的内容。要向文件里加入一个时间戳时这一命令很有用。
- 在Vim中执行如上的过滤操作需要知道一些shell的有关情况。如果在使用过滤程序时遇到问题,可以考虑检查下面一些选项的设置:,
shell
指定Vim用于运行过滤程序的shell,shellcmdflag
该shell的参数,shellquote
用于分隔shell与过滤程序时成对包围起过滤程序的字符,shellxquote
用于分隔shell与过滤程序和重定向符号时成对包围起过滤程序和重定向符号的字符,shelltype
shell的类型(只对Amiga有用),shellslash
在命令中使用斜杠(只对MS-Windows这样的系统有用),shellredir
用于将命令输出重定向到文件的字符串。
##灾难恢复
- 多数情况下恢复文件是简单的,在启动Vim时指定一个"-r"参数:
vim -r help.txt
,Vim会读取交换文件(这正是存放你已编辑的文件的地方)以及你的原文件的一些信息。
- 为安全起见,最好把它先存成另一个文件:
:write help.txt.recovered
,你可以比较一下两个文件看看上次结束的地方是不是你想要的地方。Vimdiff程序用于比较两个文件的不同是再好不过了。:w help.txt.recovered
,:edit #
,diffsp help.txt
。
- 通常最后的少量改动无法恢复。Vim会在你连续4秒不键入内容时跟磁盘同步一次,或者是连续键入了200个字符之后。这可以通过
updatetime
和updatecount
两个选项来控制。所以如果系统有所改动但Vim还没有同步时发生了宕机,那这一部分内容就无法恢复了。
- 如果你在编辑一个没有指定文件名的缓冲区时死机了,可以通过一个空字符串作为要恢复的"文件名":
vim -r ""
,确保你所在的目录是正确的,否则Vim会找不到正确的交换文件。
- Vim可以在几个地方存放交换文件。通常它跟原文件同一个目录。要找到交换文件,可以先切换到某个目录然后用下面的命令:
vim -r
, Vim会列出所有找到交换文件。它也会查看其它用来存放交换文件的目录来找到当前目录下的文件的交换文件。除此之外的其它目录就不会被搜索了,同时也不会遍历当前的目录树。
- 如果你能确切知道要用的交换文件名,你也可以在恢复时明确指定该文件。Vim会根据交换文件名找出原文件名
vim -r .help.txt.swo
。这同样适用于交换文件位于另一个非常规的目录中的情况。Vim将符合模式*.s[uvw][a-z]
的文件名视为交换文件。如果这还不行,那就根据Vim 报告的文件名把它改名。查看directory
可以获知Vim在哪些目录下存放交换文件。
swap-file
关于交换文件的位置和命名, :preserve
手工刷新交换文件,:swapname
查看原文件及其交换文件的名字,updatecount
连续击键多少次后做一次同步,updatetime
多长时间之后做一次同步,swapsync
同步交换文件时是否同时做一次磁盘同步,directory
列出存放交换文件的目录,maxmem
尚未写入交换文件的内容所受的内存限制,maxmemtot
同上,但是针对所有文件。
##奇技淫巧
- 匹配单词
:%s/\<four\>/4/gc
。
- 要对多个文件进行同样的替换操作。显而易见的办法是逐个编辑每个文件,敲入替换命令。不过用宏记录和回放功能就快多了。
vim *.cpp
,qq
,:%s/\<GetResp\>/GetAnswer/g
,:wnext
,q
,@q
,999@q
。还有一种例外:如果其中一个.cpp文件中连一个"GetResp"都没有,替换操作会引起一个错误,整个宏的执行也会被停下来。标志"e"正是致力于消除这一副作用::%s/\<GetResp\>/GetAnswer/ge
,"e"标志告诉":substitute"命令就算没找到一个匹配的目标你也不要报错。
- 将"Last, First"改为"First Last",
:%s/\([^,]*\), \(.*\)/\2 \1/
,"\2"指代在第二个"( )"中匹配的内容,也就是"First"部分,"\1"则指第一个( )中的内容,即"Last" 部分。你可以使用多达9个的反向引用。"\0"特指整个匹配到内容。除此外在替换命令中还有更多特殊的注意事项。请参考sub-replace-special
.
/^OBJS
,j
,:.,/^$/-1!sort
,跳过开头的"OBJS"行,用sort过滤自该行直到下一个空行,也可以在visual模式下选择要排序的行然后再用"!sort",排序的行比较多时会比较痛苦。
- 反转行序,:global命令可以与:move命令结合起来将所有行移到第一行的前面,这样的结果将是得到一个各行反序排列的文件。
:global/^/m 0
,也可简写为::g/^/m 0
。"^"这个正则表达式匹配一行的开头(即使该行是空行也可匹配到).":move"命令则将匹配的行移到神秘的第0行之后,所以该行会变成第一行。":global"命令并不会因这种行号的易序而发生错乱。它将继续处理剩余的行,并将每一行逐个放到文件的第一行去。这对一串连续的行也同样可行。首先移到目标范围起始行的上一行并以"mt"命令标记该行。然后移到目标范围的最末一行执行命令::'t+1,.g/^/m 't
。借助标记并不是必需的,如::10,20g/^/m0
将第10至20行移至文件首。
- 如果你要统计整个文件的其中一部分内容,你可以将光标移到要统计部分的开头处执行"gCTRL-G"命令,然后移到要统计部分的末尾再用一次"gCTRL-G". 计算两次命令得到的当前word位置之差,就得到这部分内容的字数统计。这倒是个不错的练习,不过还有另一种更简单的办法。使用Visual模式,选择要统计的部分。然后用"gCTRL-G".
- 欲知统计字数,行数等其它的统计项,请参考count-items。
- 将光标移到要查找帮助的关键字上按下:
K
,Vim会对光标所在的词执行"man"程序。找到就显示。用的是默认的分页程序来处理上下滚动(通常是"more"程序). 到达帮助内容的底部时按会让你回到Vim.不过这种办法的缺点是你不能在编辑的同时看到它。下面的小技巧会让man页同时显示在一个Vim窗口中,首先运行man对应的文件类型plugin::source $VIMRUNTIME/ftplugin/man.vim
,如果你经常光顾的话就把它放到vimrc 文件里。现在你可以用":Man"命令来打开一个窗口显示man页了::Man csh
。"CTRL-W w"会跳转到你正在编辑的内容窗口中。要显示当前光标所在字对应的man页,可以用命令:\K
(如果你重定义了, 就用你指定的字符来代替反斜杠)。
:%s/\s\+$//
消除行尾多余空格。
vim
grep -l frame_counter *.c打开所有包含了
frame_counter的c文件。Vim中有一个内置的命令可以用来在一个文件列表中查找一个指定的字符串。如果你想查找所有C程序中的"errorstring", 就可以用下面的命令:
:grep error_string *.c,这会使Vim在所有指定的文件(*.c)中查找字符串"errorstring".编辑器也打开匹配的第一个文件并将光标置于第一个包含了"errorstring"的行上。要跳转到下一个匹配的行(不论当前光标位于何处), 使用":cnext"命令即可。同样,跳转到前一个匹配的行可以用":cprev"命令,":clist"命令则可以一次列出所有的匹配。内 置 的":grep"命 令 用 到 了 外 部 命 令 grep(Unix)或findstr(Windows). 你也可以通过
grepprg`选项来指定一个执行同样功能的第三方亲信。
##加速冒号命令
- 在命令行上最常用的一些位移键是: 向左一个字符, 向右一个字符, 或 向左一个单词, 或 向右一个单词,CTRL-B 或 到命令行行首,CTRL-E 或 到命令行行尾。退格键可以删除光标之前的一个字符。要删除光标之前的整个单词,命令是CTRL-W。CTRL-U则删除光标之前的所有已键入的内容。让你可以完全重新开始。CTRL-U则删除光标之前的所有已键入的内容。让你可以完全重新开始。插入键可以切换是插入字符还是改写两种编辑模式,再按一次插入键来切换到插入模式。
- 一开始你想执行一个冒号命令或搜索一个字串,但中间改变了主意。按下CTRL-C或 可以放弃所有已经键入的命令。
- 可以在
option-list
找到一个选项名缩写的完整列表。
- 制表符键补全了光标之后的单词,Vim会在整个列表中轮番循环,CTRL-P可以反序遍历整个列表。
- 有众多的补全候选项时,最好是能一次看清所有的候选:用CTRL-D.CTRL-L命令会最大限度地补全各候选项的共同部分。
wildmode
选项可以调整补全的工作方式,wildmenu
选项使候选项以类似菜单的形式出现,suffixes
选项可以指定哪些文件不太重要,这些文件会被列在文件列表的最后,wildignore
选项指定那些根本不会被列出的文件。更多细节请参考cmdline-completion
。
- 实际上有4个历史记录。这里将要提到的是冒号命令历史记录和"/"及"?"的搜索命令历史记录,"/"和"?"都是搜索命令,所以它们共享同一个历史记录。另外的两类历史记录分别是关于表达式和
input()
函数的输入内容的。请参考cmdline-history
。要查看所有的历史记录,用命令::history
,列出的是冒号的历史记录。要查看搜索命令的历史记录,用:history /
。
- 打开命令行窗口
q:
,Vim在屏幕底部打开了一个(小)窗口。该窗口的内容是历史记录,最后一行是空行。对命令行窗口作出的修改不会被保存。历史记录不会因此被改写。除非你执行的命令是被追加到历史记录中,就象其它被执行过的命令一样。命令历史记录窗口有时十分有用,你可以在此浏览整个历史记录,找到一个相近的命令,稍加修改,然后重新执行它。也可以用搜索命令来进行查找。
##进退之间
- 象其它的Unix程序一样Vim也可以用CTRL-Z来挂起。该命令停止Vim的执行使你回到启动Vim的shell中去。你可以做些别的事。完了再用"fg"命令回到Vim.
- 如果CTRL-Z不行,你还可以用":suspend"命令。别忘了等会再让回到Vim, 否则你会丢失所有的改动。运行GUI版本的Vim时你不会回到启动Vim的shell去。CTRL-Z等效于将窗口最小化。在windows下的gvim中,CTRL-Z通常被映射为撤消命令u, 要看到它的窗口最小化效果,先执行命令
:unmap <CTRL-Z>
删除这个映射,然后再按CTRL-Z。
- 如果只执行一个shell命令的话可以在Vim中用":!fcommandg"命令。
:!{program}
执行{program},:r !{program}
执行{program} 并读取它的输出,:w !{program}
执行{program} 并把当前缓冲区的内容作为它的输入,:[range]!{program}
以{program} 过滤指定的行。注意在"!fprogramg"前面指定一个行的范围可就大不相同了。没有的话就是象通常一样执行该程序,带上范围则会把指定的行送入该程序进行过滤。
:shell
类似于用CTRL-Z挂起Vim. 不同之处在于这是一个新的shell.
- 一番辛苦之后你的寄存器里已经放入了要交换的内容,也标记了文件中的一些位置,命令历史列表中都是你精心锤炼过的命令。可是一旦你退出了Vim这些东西就会杳然无踪。好在我们有下面的对策!viminfo正是被用来存储这些信息的:命令行历史记录和搜索命令历史记录,寄存器中的内容,文件中的标记,缓冲区列表,全局变量。每次你退出Vim时这些信息都会被存储在viminfo文件中。下次启动时Vim会读取该文件的内容并据此恢复这些信息。参考
viminfo
选项的帮助和viminfo-file
了解更多信息。
'0
会准确地回到你上次退出时的位置。每次退出Vim时它都会创建一个特殊的标记。最后的一个是'0. 上次的,'0现在会变成'1, 原来的'1成了'2, 如此类推,原来的'9就丢掉了。:marks
命令可用来找出这些从0到
9的标记都指向哪里。
- 想回到最近编辑的某个文件,而不是你上次退出Vim之前编辑的文件,有一个稍嫌麻烦的办法,你可以通过下面的命令查看这样的文件列表:
:oldfiles
,如果你想编辑第二个文件,也就是上面列表中前辍以"2:"的那个,可以键入下面的命令::e #<2
,除了命令":e"你还可以在任何以文件名作为参数的命令后面使用这种格式的参数,"#<2"正如"%"(当前文件名)和"#"(准当前文件名) 一样可以代替一个普通的文件名。比如可以用下面的命令来分割出一个窗口编缉3号文件::split #<3
。诸如#<123
的这些火星文对于仅仅想编辑一个文件的情况来说显得有些不必要的复杂,下面方法会简单一些::browse oldfiles
,按q
中断继续显示的文件列表,选择文件序号进行编辑。可参考oldfiles
,v:oldfiles
,c_#<
。
- 让VIM共享viminfo:你可以在Vim用":wviminfo"和":rviminfo"命令来保存和恢信息。需要在不同的Vim实例中交换信息时这两个命令用处就大了。
- 假设你已在Vim中干了一整天了。现在想退出来第二天接着干。这时可以把目前的状态以一个会话保存起来,第二天可以据此恢复原样。一个Vim的会话含有你编辑活动的所有信息。包括文件列表,窗口布局,全局变量,选项和其它信息。(确切说到底包括什么要看
sessionoptions
选项怎么设置)。
:mksession vimbook.vim
创建一个会话文件,稍后如果你想恢复到此前的会话状态,可以执行命令:source vimbook.vim
。如果你想启动Vim时恢复某个会话,可以直接使用命令行vim -S vimbook.vim
这告诉Vim启动时读取一个特殊文件。°S°代表session(实际上,你可以用-S选项来执行任何一个Vim脚本。从这个意义上说它代表"source").上次的窗口被恢复,同样的位置,同样的大小。连映射和各选项的设置也完全一样。
- 具体会恢复哪些东西要看
sessionoptions
选项的设置。默认值是"blank,buffers,curdir,folds,help,options,winsize".blank 空窗口,buffers 所有的缓冲区,而不仅是当前窗口中的,curdir 当前目录,folds folds, 包括手工创建的,help 帮助窗口,options 所以的选项和键映射,winsize 窗口大小。你可以根据自己的喜好进行定制。比如恢复Vim窗口的大小,可以这样::set sessionoptions+=resize
。
- 会话最显见的用途是工作于不同的项目的情形。假设你把你的会话文件都保存在"~/.vim" 目录下。当前在"secret"项目,要切换到"boring"项目:
:wall
,:mksession! ~/.vim/secret.vim
,:source ~/.vim/boring.vim
。如果你打开了帮助窗口,分隔了一个,再关闭一些窗口,三番五次后屏幕上可能看起来已经乱七八糟,此时还可以用上次保存的会话文件来恢复::source ~/.vim/boring.vim
。
- 有些人同时使用MS-Windows和Unix. 如果你正是这种情况,你可以考虑把"slash"和"unix"加到
sessionoptions
选项中。这样会话文件会以兼容于两类系统的形式保存。命令如下::set sessionoptions+=unix,slash
。
- 会话能保存很多信息,但是不包括标记,寄存器和命令历史记录。要用这些东西你还是得靠viminfo.多数情况下都是独立使用会话和viminfo. 尤其是切换到另一会话但是要保存命令行的历史记录。这样你可以在一个会话中复制文件,在另一个会话中进行粘贴。你也可以同时使用会话和viminfo. 不过要自己动手。如:
:mksession!~/.vim/secret.vim
,:wviminfo! ~/.vim/secret.viminfo
。恢复时是这样::source ~/.vim/secret.vim
,:rviminfo! ~/.vim/secret.viminfo
。
- 会话保存了整个Vim的外观。但如果你只想保持一个窗口的属性的话,用视图就行了。视图用于这样的情况:你想以一种特殊的方式编辑该文件。比如打开
number
选项,定义一些folds. 就象会话一样,你可以保存视图稍后再恢复它。事实上,保存一个会话时它也的确保存了每个窗口的视图。视图有两个基本用法。第一个是让Vim决定视图文件。你可以在后来编辑该文件时恢复该视图。要保存当前窗口的视图::mkview
。Vim会决定如何保存视图。下次你再编辑该文件时你可以用下面的命令让它自己载入上次保存的视图(实际上Vim会将一个VIM脚本保存在选项viewdir
所指定的目录下。该脚本的名字以一种特定方式编码,如对于编缉E:\work\tips\vim.tip
文件时执行的:mkview
,保存的文件名是"E=-=+work=+tips=+vim.tip=", 这样执行:loadview
时Vim就可以根据这种约定的编码来查看当前被编辑的文件是否有对应的view脚本文件):loadview
。如果你想在浏览文件时关闭number
选项,或者打开所有的folds,你可以改变这些选项的设置来调整你的观感。然后这样保存该视图::mkview 1
。当然,你可以这样恢复它::loadview 1
。现在你可以通过":loadview"带不带参数来切换两个不同的视图了。用这种办法一共可以保存10个视图,从1到9再加上一个不带数字的视图。
- 第二种方式是保存视图时指定一个文件名。这个视图也可以在编辑别的文件时载入。Vim会自动切换到该视图中指定的文件去。这样你可以方便地切换到另一个文件进行编辑,同时相应的选项设置也可随身携带。比如你保存了当前文件的视图:
:mkview ~/.vim/main.vim
,可以这样恢复它::source ~/.vim/main.vim
。
- 编辑某个特殊文件时,你可能希望为该文件特别一些选项。每次输入这些命令实在是太折磨人了。使用会话或视图的话又不便于让每个人都去共享这些设置。解决之道是为每个文件添加一个模式行。这是一行让Vim设置指定选项的文本,只对当前文件有效。典型的例子是C程序中,你想把缩进量设为4个空格。这需要把
shiftwidth
选项设置为4. 相应的模式行是:/* vim:set shiftwidth=4: */
。把这行文本放到文件的前5行中或最后5行中。编辑该文件时,你看看shiftwidth
选项是不是已经设置为了4. 编辑其它文件时,它又会回到默认的设置:8.对一些文件来说把模式行作为文件头挺好,这样模式行就可以放在文件开头。对于可能打乱正文的情况来说,可以把它放在文件尾。modelines
选项控制Vim前后检查多少行来找出模式行。比如检查10行::set modelines=10
。modeline
选项可以关闭这项功能,:set nomodeline
。模式行的格式是这样的:any-text vim:set {option}={value} ... : any-text
,其中的"any-text"是说你可以在对Vim有用的部分文本之前或之后放入任何东西。这使得模式行可以以一个注释的形式出现,比如上例中的/和/.
##查找文件
- 你可以在这个特殊的缓冲区中使用Normal模式下的Vim命令来移动。比如,将光标移到一个文件上按. 这将会打开该文件进行编辑。要回到刚才的文件浏览器再次用
:edit .
命令即可,或者用:Explore
, CTRL-O也一样。试一下光标停在一个目录名上时按会怎么样。结果是文件浏览器打开该目录并显示其中的内容。在"../"上按下则会上溯到当前目录的父目录。"-"命令也是殊途同归,而且使用"-"命令时不限于当前光标位于何处。参考:help netrw
。
- 当光标位于文件名上时, 在当前窗口中打开文件,o 打开一个水平分隔的窗口显示文件,v 打开一个垂直分隔的窗口显示文件,p 使用preview-window窗口,P 在preview-window窗口中编辑,t 在一个新标签页中打开文件。
- 下面的命令控制netrw浏览器插件显示的信息:i 控制列表显示的风格(仅文件名,还是在一行中显示详细信息,逐行列出项目,还是树形显示), 其中详细信息风格包括文件大小和日期信息,s 重复按s会循环改变文件排序的方式:按文件名排序,按最后修改时间,或者根据文件大小,r 切换正反向排序。下面是几个normal模式命令的额外例子:c 将当前目录切换到浏览器正打开的目录。(请参考g:netrw_keepdir对此进行控制),R 更改当前光标下的文件,Vim会提示你输入一个新的文件名,D 删除当前光标下的文件名。Vim也会提示你进行确认,mb gb 标记书签/跳转到书签。也可以使用命令模式,如下例:
:Explore [目录名]
浏览指定的目录或当前目录,:NetrwSettings
打开netrw设置的完整列表,其中还有帮助的链接。
- 象shell一样,Vim也有一个工作目录的概念。":cd"命令会将工作目录指定为"VeryLongFileName". 你可以用":pwd"命令来获得目前的工作目录是什么。Vim会记住你上一次的工作目录,"cd -"命令会再次设定上次工作目录为当前工作目录。分隔出一个新窗口时,两个窗口都会使用同样的工作目录。如果你想在新窗口中编辑其它目录下的一个文件,你也可以为它单独另设一个工作目录,同时又不改变其它窗口的工作目录。这在Vim中叫local directory.所有的窗口都共享同一个工作目录。一旦在其中一个窗口中用":cd"命令改变了工作目录,其它窗口中的工作目录也将随之改变。对一个窗口使用":lcd"后它的工作目录会被记录下来,这样其它窗口中的":cd"或":lcd"命令就不会再影响到该目录了。在一个窗口中使用":cd"命令会重设它的工作目录为共享的工作目录。vim7.4已经有所改变。
- 查找一个文件,假设你正在编辑一个C源程序,其中有这样一行:
#include "inits.h"
,假设你想知道头文件"inits.h"中的内容。只需将光标置于该文件上然后键入:gf
,Vim就会找到并编辑该文件。如果这个文件并不在工作目录下呢?此时Vim会使用在path
选项中定义的目录去查找它。该选项的内容是一个以逗号分隔的目录名列表。假设你的头文件都位于"c:/prog/include". 下面的命令会将该目录加入你的搜索路径中去::set path+=c:/prog/include
。这个目录是一个绝对路径。所以不管你当前的工作目录为何,它都代表同样的位置。如果你的头文件是位于一个子目录呢?此时你可以指定一个相对路径。它以一个点号开始:set path+=./proto
,这告诉Vim在你使用"gf"命令的那个文件所在目录的子目录"proto"中查找指定的文件。这样命令的结果是Vim会从该目录开始,查找文件"proto/inits.h"如果没有指定"./"只有一个"proto"的话,Vim就会在当前的工作目录中查找其下名为"proto"的子目录。当前工作目录并不一定就是你正在编辑的文件所在的目录。path
选项可以以多种方法指定要在哪些目录搜索文件。请参考关于path
选项的帮助。isfname
选项用于告诉Vim哪些字符可以作为文件名的一部分,哪些不行(比如上例中的"字符).
- 如果你要找的文件名并没有以出现在当前文件中,但你已经确知它的名字,你可以这样查找它:
:find inits.h
。Vim会使用path
中的选项来搜索该文件。除了path
选项对搜索路径的影响外,这与直接使用":edit"命令毫无二致。要在另一窗口中打开指定的文件的话,可以以"CTRL-W f" 替代"gf"命令,或者用":sfind"命令来替代":find"命令,想垂直分隔窗口的话可以用:vertical sfind
。下面的例子可以方便地编辑一个位于path
中的文件:vim "+find stdio.h"
。该命令会在由path
指定的路径中搜索文件"stdio.h". 其中的双引号是必需的,它确保引号中的内容作为一个参数传给应用程序。参考-+c
。
- Vim编辑器使用缓冲区这个词来描述被编辑的文件。事实上,一个缓冲区是一个被编辑文件的副本。通常你会在完成对一个缓冲区的编辑后保存该文件。缓冲区不仅包含了文件的内容,它也记录了该缓冲区中所有的标记,设置以及其它跟缓冲区有关的东西。假设你正在编辑文件"one.txt"现在需要转而编辑"two.txt". 你可能会直接使用":edit two.txt"命令,但是你已经对"one.txt"作出了改动,所以这一命令会失败,同时你又不希望现在就保存文件"one.txt"的内容。Vim对此的解决方案是:
:hide edit two.txt
。缓冲区"one.txt"从屏幕上消失,但Vim保存了它的当前状态。这叫做隐藏缓冲区:缓冲区中确有内容但你看不到它。":hide"命令的参数是另一个命令。它使该命令工作于hidden
选项被设置的状态。你也可以自行设置该选项。其效果是当你的缓冲区看似被丢弃时,它实际上只是隐藏了起来(规律:hide与vertical都是这样的特殊命令,它们以一个完整的命令作为参数,只是以一种方式影响该命令的执行,同时此类命令并非对所有命令都有效,它只对那些涉及其影响效果的命令起使用,如vertical命令只是影响新开窗口的布局,是水平的还是垂直的。这样它对那些根本不会打开窗口的命令就形同虚设)。小心!如果你当前有一些被修改内容尚未保存的隐藏缓冲区时,不要草草地退出Vim。真要这样退出时Vim还是会提醒你有缓冲区的内容已被改变但尚未保存,除非你声明自己负全责::qa!
或:wqa
。
- 一旦一个缓冲区曾被编辑过,Vim就会记下它的一些信息。这样当它不显示在窗口中并且又不是一个隐藏缓冲区时,它还是会被保留在缓冲区列表中。这叫非活动缓冲区。缓冲区的大致类别如下:Active 出现在窗口中,内容被载入,Hidden 不显示在窗口中,但内容被载入,Inactive 不出现在窗口中,内容也未被载入。
:buffers
和:ls
命令可以列出整个缓冲区列表。缓冲区类型标志字符:u 未被列出的缓冲区unlisted-buffer,既然未被列出你又怎么知道?:ls!命令可以列出不能忝列:ls命令的缓冲区,比如以vi命令直接进入时的[未命名]缓冲区。,% 当前缓冲区,# 上一次的活动缓冲区,a 被载入并显示在某窗口中的缓冲区,h 被载入但隐藏的缓冲区,= 只读的缓冲区,- 不可编辑的缓冲区,其中
modifiable选项被关闭,+ 有改动的缓冲区
。
- 你可以用缓冲区编号指定要编辑的缓冲区。这可以免于键入其文件名:
:buffer 2
。缓冲区编辑的唯一办法就是查找缓冲区列表。这本身需要执行另一个命令。你可以用缓冲区名或只用输入缓冲区名的一部分:buffer help
,Vim会根据你键入的名字找到最佳匹配的缓冲区。如果只有一个缓冲区符合条件,就那直接使用该缓冲区,本例中是"help.txt".要在一个新窗口中打开一个缓冲区使用命令::sbuffer 3
。你可以用下面的命令来遍历整个缓冲区列表::bnext 跳转到下一个缓冲区,:bprevious 跳转到前一个缓冲区,:bfirst 跳转到第一个缓冲区,:blast 跳转到最后一个缓冲区
。要把一个缓冲区从列表中去除,可以用命令:bdelete 3
,同样,可以使用文件名。备注:即使是用":bdelete"命令删除了一个缓冲区Vim还是会记住它。实际上它被打入"unlisted"列表中,不再显示在":buffers"命令显示的缓冲区列表中。但":buffers!"还是会让它再度现身(是的,Vim可以完成Misson Impossible). 要彻底清除一个缓冲区,要使用":bwipe"同时请参考buflisted
选项。
##编辑非文本文件
- 回想计算机的史前史,那时的打字机使用两个字符来开始一个新行。首先是一个字符命令使打印头移回开始位置(回车,), 然后另一个字符命令控制向前进纸一行(进纸,).在计算机诞生之初,存储设备十分昂贵。于是有人就提出没有必要用两个字符来表示一行的结束。UNIX一族决定只用进纸一个字符来表示行尾。来自苹果阵营的人则把回车作为换行的标准。MS-DOS(和微软的Windows)仍然决定沿用古老的回车换行传统。
- 可以在
fileformats
选项里指定你希望Vim能自动识别的格式的集合。:set fileformats=unix,dos
,:set fileformats+=mac
。
- ,Vim允许你强制指定文件格式
:edit ++ff=unix file.txt
,"++"字符串告诉Vim后面紧接着的是一个选项名,对该选项的设置将覆盖它的默认值。"++ff"代表的选项是fileformat
. 你也可以指定为"++ff=mac"或"++ff=dos".不 过 并 不 是 每 个 选 项 都 有 这 种 用 法, 目 前 来 说 只有"++ff"和"++enc"可以这样用。当然也可以用这两个选项的全称"++fileformat"和"++encoding".
- 可以利用
fileformat
选项来转换文件的格式。:set fileformat=unix
,:w
。
- 在Vim中直接访问来自因特网的文件靠的是netrw这个插件。目前为止可以处理下面几种类型的URL:ftp:// uses ftp,rcp:// uses rcp,scp:// uses scp,http:// uses wget (reading only)。光标停留在链接上然后
gf
或者Ctrl+w f
。
- 要为新编辑的文件加密,可以在启动Vim时使用"-x"参数
vim -x file.txt
。要停止对一个文件加密,可以把key
选项设置为一个空字串::set key=
,下次你存盘该文件时就不会进行加密了。通过设置key
的值来进行加密可不是一个好主意,因为密码会显露无遗。任何趴在你肩膀上的人都能看到你的密码。为避免这个问题我们创造了":X"命令。它会象"-x"一样问你要一个密码::X
。
- 有一个避免别人读取你的交换文件的办法就是禁用交换文件。如果在命令行上指定了
-n
参数,就不会生成交换文件(Vim会把所有东西都放到内存里). 比如,下面的命令就在编辑加密文件"file.txt"时不使用交换文件:vim -x -n file.txt
。如果已经在编辑过程中,也可以通过下面的命令禁用交换文件::setlocal noswapfile
。
- 要保证Vim在编辑二进制文件时没有滥用它惯常的聪明办法,你需要在启动Vim时使用"-b"参数:
vim -b datafile
。这会设置binary
选项。设置该选项的作用是避免你不希望有的副作用。比如textwidth
会被设置为0, 禁止了自动换行。文件总是以Unix格式读入。
- 用Vim的二进制模式进行编辑可以用来修改一个可执行程序中的文本信息。不过注意此时只是去修改,不要去插入或删除任何东西,这样做会让你的程序死得很难看。用"R"进入替换模式进行修改倒是个不错的主意。二进制文件中很多字符都是不可打印字符。设置下面的选项可以以十六进制格式显示这些字符:
:set display=uhex
,另外,"ga"命令可以来查明当前光标下字符的本来面目。以字符为例,其输出格式是:<^[> 27, Hex 1b, Octal 033
。二进制文件里也可能出现超长的行。如果仅是想看个大概就可以把wrap
选项关闭。gCTRL-G
可以让你获知光标所在字符是整个文件中第几个字节。"go"命令可以移动到文件中指定字节去,1234go
。
- 一个地道的二进制文件编辑器会以两种方式显示内容:通常的文本显示方式和十六进制格式。在Vim中要收到这种效果你可以先用"xxd"程序来做转换。该程序随Vim一起发布。
vim -b datafile
,现在用xxd程序把文件进行十六进制格式的转储::%!xxd
,现在你可以随心所欲地浏览和编辑了,Vim将之视为普通文本。改变其十六进制不会引起右边对应字符的改变,反之也一样(一个真正的二进制文件编辑器如UltraEdit或WinHex会做这种同步,同时,只有对其十六进制形式做出改变时用xxd -r才能真正改变文件)。编辑完成后再做一次逆向转换::%!xxd -r
,逆向转换时只有其十六进制形式被认为是有效的。对可打印形式的改变会被转换程序忽略。
- 在Vim中你可以象编辑其它文件一样直接编辑一个压缩文件。"gzip"插件会在你编辑时处理解压的问题。保存时进行压缩。目前支持的压缩方法有:.Z compress,.gz gzip,.bz2 bzip2。
##快速键入
- 整个word键入有误,可以使用CTRL-W。如果发现整行键入的内容都弄乱了,可以使用CTRL-U删除它来重新开始。同时这会保留光标之后的字符并且保持原有的缩进。
- 在Insert模式下可用特殊键的小计: 到文件头, 向上滚屏, 到行首, 向左移动一个word, 向左移动一个word, 向右移动一个word, 向右移动一个word, 到行尾, 向下滚屏, 到文件尾。除此之外在
ins-special-specified
还列出了一些特殊键。
- 显示匹配字符
:set showmatch
,等待时间的长短可以由选项matchtime
来控制。比如说让Vim等待一秒半钟::set matchtime=15
,时间单位是十分之一秒。
- Vim可在编辑时自动补全一个词。首先键入一个词前面的部分,然后按下CTRL-P, Vim会据此补全整个词。使用CTRL-N可以往前查找word来补全。因为查找达到文件头尾时回绕过去循环进行,所以CTRL-N和CTRL-P往往会找到相同的word来补全,只不过查找的顺序相反。提示:CTRL-N意为Next-match, CTLR-P意为Previous-match.Vim会尝试多种办法来补全一个word. 默认情况下,它会查找以下这些地方:1.当前文件2.在其它窗口打开的文件3.其它载入缓冲区的文件(隐藏的缓冲区)4.没有载入的文件(非活动的缓冲区)5.Tag文件6.当前文件中所有被#include语句引入的头文件。可以用
complete
选项来定制Vim在补全word时所用的策略。查找时会隐含地使用ignorecase
选项。设置了该选项时,会在搜索匹配的word时忽略大小写的不同。对于自动补全有一个选项十分有用,它就是infercase
. 它使搜索匹配的word时忽略剩余部分的大小写(当然还得ignorecase
被设置了才行), 但继续保留已键入的部分的大小写。这样对于键入了"For"时Vim会查找到"fortunately"这样的匹配,但最终的结果是"Fortunately".
- 如果你自己清楚要找的东西,你可以用以下命令来补全这样一些特殊的文档元素:CTRL-X CTRL-F 文件名,CTRL-X CTRL-L 整行内容,CTRL-X CTRL-D 宏定义(也包括那些在include文件里定义的宏),CTRL-X CTRL-I 当前文件和被当前文件include的文件,CTRL-X CTRL-K 来自一个字典文件的word,CTRL-X CTRL-T 来自一个thesaurus的word,CTRL-X CTRL-] tags,CTRL-X CTRL-V Vim的命令行。键入这些特殊命令后再使用CTRL-N可以往下查找符合的匹配,CTRL-P则往上查找。关于这些命令的更多信息请参考:
ins-completion
.
- 程序源码往往具有良好的结构。这为更加智能化的补齐提供了可能。在Vim中这叫Omni补全。Omni补全的关键一击是CTRL-X CTRL-O. 显然这个O代表Omni.