安装

下载windows安装包, 最新版在这里
下载中文帮助安装包, 最新版在这里
安装vim-plug插件, 原文件在这里, 下载plug.vim,然后把它放到vim安装路径的autoload目录下

VIM简介

VIM是一种信仰。

对我来说vi是禅, 使用vi就是使用禅。每个命令都是心印,这对用户来说是深奥的,对未入门者来说是无法了解的。每次使用它你都能发现真理。 --Satish Reddy

商业化产品可能是有用的, 但最好的东西往往是免费的, 空气, 水, vim

高效编辑的原则

形成过程

  • 自省, 找出重复/低效的部分
  • 寻找solution
  • 使之成为习惯
  • 7 Habits

    • 他们能做事主动。 (“积极主动”)
    • 他们能关注目标。 (“以终为始”)
    • 他们能确定要务。 (“要事第一”)
    • 他们能与人共赢。 (“双赢思维”)
    • 他们能与人沟通交流。 (“知彼解己”)
    • 他们能与人合作。 (“统合综效”)
    • 他们能反省自己并弥补不足。 (“自我更新”)

区分学习和使用

  • 学习是投入,使用是产出
  • 学习是投资,使用是收益
  • 不要第二次寻找同一问题的解决方案(DRY)

拿来主义

  • 选择性收集技巧, 有用的 VS 对你有用的
  • 避免收集对自己无用的高度特殊化的技巧
  • 不要为用不到的功能买单

    • 不要提前买单
    • 技能的投入产出比
    • 遗忘曲线
    • 打磨技艺持续前进

不断提高

  • 理解而非记忆
  • 培植而非收藏
  • 精心经营个人化功能子集
  • 全面了解,不要浅尝辄止

态度

  • 学而不用,积而不发
  • 了解工具实际被设计能做的事, 而不是你希望它能做的事.
  • 高效与否, 操之在你

    • 工具只会跟使用者一样好
  • 开放态度, 不要拒绝其它工具

    • 手持锤子,满世界都是钉子

第一课

学会自己搜索答案

图片.png

第二课

完成vimtutor

vimtutor位于vim安装目录里,一个可执行程序(脚本)
它大约需要20分钟

第三课 Motion

通用

  • h/l/k/j
  • G/{num}G/gg/:{num}
  • %
  • gk/gj
  • 0/^/$
  • f{char}/F{char}/t{char}/T{char}/;/, : t=till=find-1
  • -/+/_

练习

To err is human.  To really foul up you need a computer. 
           <------------  ------------->
                    Th     tn

单词级移动

keyaction
wW移动到下一单词的开头
bB移动到上一单词的开头
eE移动到光标所在单词的末尾
       ge      b        w                               e
       <-     <-        --->                           --->
This is-a line, with special/separated/words (and some more).
   <----- <-----       -------------------->          ----->
     gE      B                   W                       E
        ge      b          w                            e

大范围移动

keyaction
%移动光标到括号左半部分( 包括(、{、[ )对应右半匹配部分( )、}、] )
}移动光标到当前段落的末尾
{移到光标到当前段落的开头
H移动光标到屏幕的第一行
M移动光标到屏幕的中间一行
L移动光标到屏幕的最后一行
Ctrl + f向前滚动一页
Ctrl + b向后滚动一页
Ctrl + u向前滚动半页
Ctrl + d向后滚动半页
/<string>向前查找, 结合n/N可以重复向前向后查找同一字符
?<string>向后查找, 可以结合n/N

关于查找

  • .*[]^%/\?~$有特殊含义,如果要查找它们,在在前面加上\.
  • 可以用:set ic:set noic来忽略或不忽略大小写
  • 输入/?后可以用<Up>或<Down>来查找历史记录。
  • 可以在单词上用*#来向前或向后查找光标下单词
  • 如果要精确匹配, 用\<\>来精确匹配开头或结尾,两者可以同时使用,如/\<the\>,这样three不会被匹配

位置标记

keydesciption
m{a-zA-Z}把位置标记 {a-zA-Z} 设在当前光标位置 (不移动光标,这不是动作命令)。
g'{mark}跳转到指定的位置标记 {mark},但在当前缓冲区内跳转时,不改变跳转表。
:marks列出所有的位置标记 (这不是动作命令),第一列的编号为零。

标志说明

markdescription
'a - 'z小写位置标记,在每个文件内有效。
'A - 'Z大写位置标记,也叫做文件标记,在文件间都有效。
'0 - '9数字位置标记,在 .viminfo 文件里设置。

跳转

keyaction
CTRL-O转到跳转表里第 [count] 个较旧的光标位置 (不是动作命令)。
CTRL-I转到跳转表里第 [count] 个较新的光标位置 (不是动作命令)。
:ju[mps]打出跳转表 (不是动作命令)。
:cle[arjumps]清除当前窗口的跳转表。

编辑命令

<number> <operator> <text object or motion>
<次数> <操作符> <文本对象或移动命令>

操作符

keyaction
c修改 (change)
d删除 (delete)
y抽出 (yank) 到寄存器 (不改变文本)
~变换大小写 (只有当 'tildeop' 置位时有效)
g~变换大小写
gu变为小写
gU变为大写
!通过外部程序过滤
=通过 'equalprg' (若为空,C-indenting) 过滤
gq文本排版
gw文本排版,不移动光标
>右移
<左移
zf定义折叠

高级技巧: 可以用":"命令定义一个动作, 例如d:call search("f")<CR>, 如果该命令多于一行,则不能用"."重复。

面向对象类型

一共三种: 字符/行/列

keytype
v在操作符后和动作命令之前应用: 即使该动作是面向行的,也强制该操作面向字符。
V在操作符后和动作命令之前应用: 即使该动作是面向字符的,也强制该操作面向行。
CTRL-V在操作符后和动作命令之前应用: 强制该动作面向列块。

练习: dj, dvj, d<C-V>j

对象定义

  • word: 一个单词由字符、数字和下划线序列或者其他的非空白字符的序列组成。单词间可以空白
    字符 (空格、制表、换行) 分隔。这一规则可以用 'iskeyword' 选项改变。空行也被认
    作单词。
  • WORD: 一个字串由非空白字符序列组成。字串以空白分隔。空行也被认作字串。
  • sentence: 一个句子以 '.'、'!' 或者 '?' 结尾并紧随着一个换行符、空格或者制表符。标点和空
    白字符之间可以出现任何数量的闭括号和引号: ')'、']'、'"' 和 '''。另,段落和小节
    的边界也视为句子的边界。
  • paragraph: 一个段落从空行或某一个段落宏命令开始,段落宏由 'paragraphs' 选项里成对出现的字
    符所定义。它的缺省值为 "IPLPPPQPP TPHPLIPpLpItpplpipbp",也就是宏 ".IP"、".LP"
    等 (这些是 nroff 宏,所以句号一定要出现在第一列)。小节边界也被视为段落边界。
    注意 空白行 (只包含空白) 不是 段落边界。
  • section: 一个小节从首列出现的换页符 (<C-L>) 或某一个小节宏命令开始。小节宏由 'sections'
    选项里成对出现的字符所定义。它的缺省值是 "SHNHH HUnhsh",也就是说小节可以从如
    下的 nroff 宏开始: ".SH"、".NH"、".H"、".HU"、".nh" 和 ".sh"。

文本对象

keydescription
aw"一个单词",选择 [count] 个单词 (见word)。包括开头或拖尾的空白,但不单独计算。在可视面向行的模式下,"aw" 切换到可视面向字符的模式。
iw"内含单词",选择 [count] 个单词 (见word)。单词之间的空白也被算为一个单词。在可视面向行的模式下,"iw" 切换到可视面向字符的模式。
aW"一个字串",选择 [count] 个字串 (见WORD)。包括开头或拖尾的空白,但不单独计算。在可视面向行的模式下,"aW" 切换到可视面向字符的模式。
iW"内含字串",选择 [count] 个字串 (见WORD)。字串之间的空白也被算为一个字串。在可视面向行的模式下,"iW" 切换到可视面向字符的模式。
as"一个句子",选择 [count] 个句子 (见sentence)。可视模式下它切换为面向字符的模式。
is"内含句子",选择 [count] 个句子 (见sentence)。可视模式下它切换为面向字符的模式。
ap"一个段落",选择 [count] 个段落 (见paragraph)。特例: 空白行 (只包含空白的行) 也被视为段落边界。可视模式下它切换为面向行的模式。
ip"内含段落",选择 [count] 个段落 (见paragraph)。特例: 空白行 (只包含空白的行) 也被视为段落边界。可视模式下它切换为面向行的模式。
a(ab"一个()块",包括'(' 和 ')'
i(ib"一个()块",不包括'(' 和 ')'
a{a{"一个{}块",包括'{' 和 '}'
i{i{"一个{}块",不包括'{' 和 '}'
a"a'a\`"一个引号字符串", 包括引号
i"i'i\`"一个引号字符串", 不包括引号

常见命令

keyactions
x删除光标下的字符 ("dl" 的缩写)
X删除光标前的字符 ("dh" 的缩写)
D从当前位置删除到行尾 ("d$" 的缩写)
dw从当前位置删除到下一个单词开头
db从当前位置删除到前一个单词的开头
diw删除光标上的单词 (不包括空白字符)
daw删除光标上的单词 (包括空白字符)
dG删除到文件末
dgg删除到文件首

上面的d可以改成c或y

插入和替换

插入模式命令

keyaction
a在光标后附加文本 [count] 次。如果光标在空行的第一列,启动插入模式。但在置位了 'virtualedit' 以后就不是!
A在行尾附加文本 [count] 次。
i在光标前插入文本 [count] 次。在插入模式里使用 CTRL-O 的时候,i_CTRL-O 不支持计数。
I在本行第一个非空白字符之前插入文本 [count] 次。如果 'cpoptions' 里有 'H' 标志位而本行只有空白,在最后一个空白前插入。
gI在第一列插入文本 [count] 次。
gi在当前缓冲区最近一次插入模式停止的位置继续插入文本。该位置记在 '^ 位置标记里。如果标记在行末之后,和 "^i" 有所差异。该位置在插入/删除行时会自动修正。但_不_在插入/删除字符时被修正。使用 :keepjumps 命令修饰符时,不改变 '^` 位置标记。
o在光标下方开启新行,并插入文本,重复 [count] 次。如果 'cpoptions' 里有 '#' 标志位,忽略计数。
O在光标上方开启新行,并插入文本,重复 [count] 次。如果 'cpoptions' 里有 '#' 标志位,忽略计数。

用<Esc>或<Ctrl-C>退出插入模式

Ex插入命令

keyActions
:{range}a[ppend][!]在指定行下方添加若干行。如果没有给出 {range},文本会在当前行之后插入。加入 [!] 切换此命令执行时的 'autoindent'。
:{range}i[nsert][!]在指定行上方添加若干行。如果没有给出 {range},文本会在当前行之前插入。加入 [!] 切换此命令执行时的 'autoindent'。

这两个命令会继续要求行,直到你输入了只包含 "." 的一行。小心反斜杠开始的行,见 line-continuation

Ex 模式 (见 -e) 下,行尾的反斜杠可用来插入 NUL 字符。所以要使一行以反斜杠结尾,用两个反斜杠。也就是说仅在行尾情况下,反斜杠数目减半。

注意: 这些命令不能和 :global:vglobal 一起使用。":append" 和 ":insert" 在 ":if" 和 ":endif"、":for" 和 ":endfor" 还有 ":while" 和 ":endwhile" 之间不能很好的工作。

插入文件

keyaction
:r[ead] [++opt] [name]在光标下方插入文件 [name] (缺省: 当前文件)。
:{range}r[ead] [++opt] [name]在指定行下方插入文件 [name] (缺省: 当前文件)。
:[range]r[ead] [++opt] !{cmd}执行 {cmd} 并把它的标准输出插入到光标下方。临时文件会建立来保存命令输出的结果,并被读到缓冲区里。'shellredir' 用来保存命令的输出结果,它可以设置是否包含标准错误的输出。

插入模式下的一些快捷键

keyaction
<Esc>CTRL-[结束插入或替换模式,回到普通模式。结束缩写。
CTRL-C退出插入模式,回到普通模式。不检查缩写。不激活 InsertLeave 自动命令事件。
CTRL-@插入最近插入的文本,并停止插入。
CTRL-A插入最近插入的文本。
<BS>CTRL-H删除光标前的字符 。
<Del>删除光标下的字符。如果光标在行尾,并且 'backspace' 选项包括 "eol",删除 <EOL>;下一行就此附加于当前行之后。如果你的 <Del> 键不正确,见 :fixdel。
CTRL-W删除光标前的单词
CTRL-U删除当前行上光标前的所有输入字符。
<Tab>CTRL-I插入制表。如果打开 'expandtab' 选项,等价数目的空格被插入 也可使用 CTRL-Q <Tab>
<NL>CTRL-J开始新行。
<CR>CTRL-M开始新行。
CTRL-K {char1} [char2]输入二合字母 (见digraphs)。当 {char1} 为特殊字符时,该键的键码以 <> 形式插入。例如字符串 <S-Space> 可以这样输入: <C-K><S-Space> (两个键)。两个键都不考虑映射。
CTRL-N查找下一个关键字 (见 i_CTRL-N)。
CTRL-P查找上一个关键字 (见 i_CTRL-P)。
CTRL-T在当前行开始处插入一个 shiftwidth 的缩进。缩进总是取整到 'shiftwidth' 的倍数 (这是 vi 兼容的)。
CTRL-D在当前行开始处删除一个 shiftwidth 的缩进。缩进总是取整到 'shiftwidth' 的倍数 (这是 vi 兼容的)。
0 CTRL-D删除所有当前行的缩进。
^ CTRL-D删除当前行的所有缩进。缩进在下一行上恢复。这可以用于插入卷标。
CTRL-V如果下一个是非数字,按本义插入。对特殊键而言,插入其终端代码。CTRL-V 之后紧接着输入的字符不经过映射。注意: 当 CTRL-V 被映射时 (例如,用来粘贴文本),你可能经常需要使用 CTRL-Q 来代替
CTRL-SHIFT-V与 CTRL-V 类似,除非激活了 modifyOtherKeys,此时插入带修饰符的键的转义序列。
CTRL-Q等同于 CTRL-V。
CTRL-X进入 CTRL-X 模式,一个子模式。那里你可以给出命令来补全单词或者滚动窗口。见 i_CTRL-Xins-completion
CTRL-E插入光标下面的字符。
CTRL-Y插入光标上面的字符。注意 CTRL-E 和 CTRL-Y 不使用 'textwidth',从而可以从长行里复制字符。
CTRL-]切换缩写,不插入字符。
<Insert>切换插入和替换模式。

插入寄存器内容

CTRL-R {register} 用于插入寄存器内容,在输入CTRL-R之后会有"显示出来,这时你需要输入寄存器名字

registerUsage
"无名寄存器,包含最近删除或抽出的文本
%当前文件名
#轮换文件名
*剪贴板内容 (X11: 主选择)
+剪贴板内容
/最近的搜索模式
:最近的命令行
.最近插入的文本
-最近的行内 (少于一行) 删除
=表达式寄存器;你会被提示输入一个表达式 (见expression)

CTRL-R {register}还有几个变种:

  • CTRL-R CTRL-R {register} : 文本按本义插入,这意味着如果寄存器包含 <BS> 这样的字符,结果会不同。例如,如果寄存器包含 "ab^Hc": CTRL-R a 产生 "ac"。CTRL-R CTRL-R a产生 "ab^Hc"。
  • CTRL-R CTRL-O {register} : 按本义插入寄存器内容,并且不进行自动缩进。
  • CTRL-R CTRL-P {register} : 按本义插入寄存器内容,修正缩进

复制并移动

keysUsage
"{a-zA-Z0-9.%#:-"}指定下次的删除、抽出和放置命令使用的寄存器 {a-zA-Z0-9.%#:-"} (大写字符使得删除和抽出命令附加到该寄存器) ({.%#:} 只能用于放置命令)。
["x]y{motion}抽出 {motion} 跨越的文本 [到寄存器 x]。如果没有字符被抽出 (例如,在第一列执行 "y0") 并且 'cpoptions' 里包括 'E' 标志位,这是一个错误。
["x]yy抽出 [count] 行 [到寄存器 x]linewise行动作。
["x]Y抽出 [count] 行 [到寄存器 x] (等同于 yy,linewise行动作)。如果你想要 "Y" 执行从光标到行尾的操作 (更合乎逻辑,但是与 Vi 不兼容),用 ":map Y y$"。
{Visual}["x]y抽出高亮文本 [到寄存器 x] (关于 {Visual} 见Visual-mode)。
{Visual}["x]Y抽出高亮行 [到寄存器 x] (关于 {Visual} 见Visual-mode)。
["x]p放置文本 [从寄存器 x] 在光标之后 [count] 次。
["x]<MiddleMouse>从一个寄存器放置文本在光标之前 [count] 次。除非另外指定,否则用 "* 寄存器。光标停留在新文本的尾部。
["x]gp如同 "p",但光标停留在新文本之后。
["x]gP如同 "P",但光标停留在新文本之后。
Ex CommandUsage
:reg[isters]显示所有编号和命名寄存器的类型和内容。但不列出用于 :redir 目的地的寄存器。类型可以是以下之一: "c" 用于 characterwise 文本; "l" 用于 linewise 文本; "b" 用于 blockwise-visual 文本
:reg[isters] {arg}显示 {arg} 里提到的编号和命名寄存器的内容。例如: :reg 1a
:di[splay] [arg]和 :registers 相同。
:[range]y[ank] [x]抽出 [range] 所指定的行 [到寄存器 x]。仅当包含+clipboard特性时才可以抽出到 "* 或 "+ 寄存器。
:[range]y[ank] [x] {count}从 [range] 的最后一行开始 (缺省: 当前行cmdline-ranges) 抽出 {count} 行 [到寄存器 x]。
:[line]pu[t] [x]放置文本 [从寄存器 x] 在行号 [line] (缺省为当前行) 之后。
:[line]pu[t]! [x]放置文本 [从寄存器 x] 在行号 [line] (缺省为当前行) 之前。
:[range]co[py] {address}把 [range] 指定的行复制到 {address} 给出的行之下。
:[range]m[ove] {address}把 [range] 指定的行移动到 {address} 给出的行之下。

put总是 linewise 行动作,因而这个命令可以用来把抽出的块放置在新行上。寄存器也可以是 '=',跟随一个可选的表达式。表达式继续到该命令结束为止。你需要在 '|' 和 '"' 字符前加上反斜杠不让它们终止你的命令行。例如: :put ='path' . \",/test\" ;如果 '=' 之后没有表达式,Vim 使用前一个表达式。用 :dis = 你可以看到它。

上面这些命令也可以用于global命令, 详细列表查看help ex-cmd-index

寄存器类型:

  1. 无名寄存器 ""
    用 "d"、"c"、"s"、"x" 等命令删除或者用 "y" 等抽出命令复制的文本都被 Vim 用来填
    充该寄存器
  2. 10 个编号寄存器 "0 到 "9
    Vim 把抽出和删除命令的文本保存在这些寄存器里。
  3. 行内删除寄存器 "-
    该寄存器保存删除不到一行内容的命令的文本
  4. 26 个命名的寄存器 "a 到 "z 或者 "A 到 "Z
    Vim 只有在你指定的时候才使用这些寄存器。指定为小写字母时替换原来的内容,指定为大写字母时附加到原来的内容。
  5. 三个只读寄存器 ":、". 和 "%
    ". 包含最近插入的文本
    "% 包含当前文件名
    “: 包含最近执行过的命令行。
  6. 轮换缓冲区寄存器 "#
    包含当前窗口buf文件名
  7. 表达式寄存器 "=
    其实并没有这么一个寄存器,这是可读写的
  8. 选择和拖放寄存器 "*、"+ 和 "~
    用这些寄存器来保存和取得 GUI 界面选择的文本。 只读的 "~ 寄存器保存最近一次拖放操作放下的文本
  9. 黑洞寄存器寄存器 "_
  10. 最近搜索模式寄存器 "/

常用选项

选项描述
用法:set all显示所有选项和设置;
:set显示当前设置的所有选项;
:set num?显示num选项的当前设置;num可以换成其他选项;
:set num打开选项与关闭选项;
:set nonumnum可以换成其他选项;
num/nonum是/否显示行号;
wrap/nowrap是(默认)/否自动换行;
wrapmargin=n设置右边界的值,当输入时到达右边界,并遇到空格时,会自动插入换行;
aw/noaw临时转入shell或使用":n"编辑其他文件时,是/否自动保存当前文件已做的修改;
flash/noflash在出错处使用闪烁提醒/使用呜叫提醒;
缩进ai/noaiautoindent是/否使用自动缩进方式,新行与前面的行保持—致的缩进;
smartindentsmartindent/nosmartindent:是否使用能识别类C语法的智能缩进方式;
cindentcindent/nocindent:是/否使用cindent缩进方式;
indentexprindentexpr/noindentexpr:是/否使用indentexpr缩进方式;
indenttype=缩进方式:autoindent、smartindent、cindent、indentexpr(同上);
shiftwidth=n自动缩进字符数;
tabstop=n将TAB键的宽度设置为n个宁符宽度,默认为8;
编码encoding=设置vim内部使用的编码字符集;如:prc;
fileencoding=设置当前编辑的文件的字符编码方式;如:utf-8;
fileencodings=设置vim自动探测fileencoding的顺序列表;如:"ucs-bom,utf-8,latin1";
termencoding=vim工作的终端的编码方式;如:utf-8;
ambiwidth=设置汉字所占字符宽度;如:double;
搜索ic/noic搜索时忽赂大小写/不忽略大小写(默认);
wrapscan在搜索时到达文件尾后是/否跳文件头继续搜索;
incsearchincsearch/noincsearch:输入搜索关键字时,是/否(默认)自动高亮匹配的字符;
hlsearchhlsearch/nohlsearch:搜索后,是/否(默认)保留匹配字符的高亮显示
编程syntax=on/off:是/否显示语法高亮;
保存ro/noro是/否只读模式,只读模式写只能通过强制方式":w!"写入,否则无法写入;
history=nhistory记录的行数,默认100个历史记录;
filefiletype on侦测文件类型;
filetype plugin on载入文件类型插件;
filetype indent on为特定文件类型载入相关缩进文件;
report=n复制或者删除了多少行时显示提示信息,默认为2;
laststatus=0,1,2是否显示状态栏,0:不显示,1:需要时间显示,2:总是显示;
list/nolist是/否将tab、换行符使用替代字符显示(^I、$);
shell=path设置vim执行外部命令时使用的shell路径,如:/bin/bash;
showmatch设置输入右半边括号时,是/否(默认)提示所对应的左半边括号;
showmode设置是(默认)/否在窗口左下角显示当前的模式:插入、替换等模式;
compatible除非.vimrc文件存在,默认vim会尝试采用vi兼容的模式;

正则表达式

  1. 表示目标字符的元字符
元字符说明
.匹配任意字符
[abc]匹配方括号中的任意一个字符,可用-表示字符范围。如[a-z0-9]匹配小写字母和数字
[^abc]匹配除方括号中字符之外的任意字符
\d匹配阿拉伯数字,等同于[0-9]
\D匹配阿拉伯数字之外的任意字符,等同于1
\x匹配十六进制数字,等同于[0-9A-Fa-f]
\X匹配十六进制数字之外的任意字符,等同于2
\l匹配[a-z]
\L匹配3
\u匹配[A-Z]
\U匹配4
\w匹配单词字母,等同于[0-9A-Za-z_]
\W匹配单词字母之外的任意字符,等同于5
\t匹配<TAB>字符
\s匹配空白字符,等同于[\t]
\S匹配非空白字符,等同于6
  1. 需要转义的字符
元字符说明
\*匹配* 字符
.匹配. 字符
\/匹配 / 字符
\匹配 \ 字符
\[匹配 [ 字符
\]匹配 ] 字符
  1. 表示数量的元字符
元字符说明
*匹配0-任意个
\+匹配1-任意个
\?匹配0-1个
\{n,m}匹配n-m个
\{n}匹配n个
\{n,}匹配n-任意个
\{,m}匹配0-m个
  1. 表示位置的元字符
元字符说明
$匹配行尾
^匹配行首
\<匹配单词词首
\>匹配单词词尾
  1. 表示子模式的元字符

\()括起来的正则表达式,在后面使用时可以依次用\1, \2等变量来表示括号里的内容

  1. 表示非打印字符的元字符
元字符说明
\n表示匹配 一个换行符。
\r表示匹配 一个回车符。
\t表示匹配 一个制表符 ( Tab 键)。
\s表示匹配 任意一个空白字符,包括空格、制表符、换页符等。
\S表示匹配 任意一个非空白字符。

替换

substitue的缩写是s, 基本语法是: [range]substitue/search/replace/[flags] [count]

对 [range] 指定的行把 {pattern} 的匹配替代成 {string}。关于 {pattern},参见 |pattern|。{string} 可以是按本义出现的字符串,也可包含特殊字符。参见 |sub-replace-special|。如果不指定 [range] 和 [count],仅在当前行进行替代。如果指定 [count],在 [range] 最后一行开始的 [count] 行进行替代。如果不指定 [range] ,则从当前行开始。[count] 必须为正数。另见 |cmdline-ranges|。
  1. range

range是同一个或多个被,;分割的行限定符组成。当用;时, 光标位置会被设置为前一个行限定符确定的行值。

如果行限定符个数多于命令需要的数量,那么前面的限定符被忽略。

行号可以用下列符号:

符号行号
{number}行号
.当前行
$文件的最后一行
%相当于 1,$ (整个文件)
't标记 t 的位置 (小写)
'T标记 T 的位置 (大写);如果标记存在于另一个文件中,则不能在范围里应用。
/{pattern}[/]下一个 匹配 {pattern} 的行
?{pattern}[?]前一个 匹配 {pattern} 的行
\/下一个 与前次搜索模式匹配的行
\?前一个 与前次搜索模式匹配的行
\&下一个 与前次替代模式匹配的行

这些符号后面可以跟一个或多个+-和一个可靠数字,如果数字省略,则认为是1
/?前面可能有另一个地址,那么查找就从那里开始。如果使用;, 那么光标会移动

/pat1//pat2/ :不移动光标
7;/pat2/ : 光标留在第7行

例子:

.+3
/that/+1
.,$
0;/that
1;/tath

  1. replace中的特殊字符
nomagic动作
\&替代为完整的匹配
&替代为 &
\0替代为完整的匹配
\1替代为匹配的第一个 () 里面的内容
\2替代为匹配的第二个 () 里面的内容
....
\9替代为匹配的第九个 () 里面的内容
\~替代为前一个 substitute 的替代字符串
~替代为 ~
\u下一个字符成为大写
\U其后字符成为大写,直到 \E 出现
\l下一个字符成为小写
\L其后字符成为小写,直到 \E 出现
\e结束 \u、\U、\l 和 \L (注意: 不是 <Esc>!)
\E结束 \u、\U、\l 和 \L
<CR>把该行在此位置一分为二 (<CR> 以 CTRL-V <Enter> 方式输入)
\r同上
\<CR>插入一个回车 (CTRL-M) (<CR> 以 CTRL-V <Enter> 方式输入)
\n插入一个 <NL> (文件里的 <NUL>) (此处并不是换行)
\b插入一个 <BS>
\t插入一个 <Tab>
\\插入单个反斜杠
\x其中 x 是上面没提到的任何一个字符: 保留作将来的扩展

\1\2 等里的数字是基于模式里 \( 出现的顺序 (从左到右)。如果一个括号组匹配多次,最后一次的匹配被使用在 \1\2 等里。例如:

:s/\(\(a[a-d] \)*\)/\2/      # 修改 "aa ab x" 为 "ab x"

\2 对应 \(a[a-d] \)。第一次匹配 "aa ",第二次匹配 "ab ", 最后一次匹配"ab "被用于\2

  1. Flags
FlagsUsage
`&必须是首个使用的标志位,保留和上次substitue相同的标志位`
`c` 确认每个替代
`e` 如果搜索不成功,不给出错误信息
`g` 对行内所有匹配进行替代
`i` 忽略模式的大小写
`I` 不忽略模式大小写
`n` 只报告匹配次数,不实际进行替代
`p` 显示包含最后一次替代的行
`#` 类似p, 且在前面加上行号
`l` 类似p,但显示方式类似:list
`r` 如果匹配模式为空,优先使用上一次使用的搜索模式,之后再是上一次substitute或global使用的模式
  1. 示例
:s/a\|b/xxx\0xxx/g               # 修改 "a b"     为 "xxxaxxx xxxbxxx"
:s/\([abc]\)\([efg]\)/\2\1/g     # 修改 "af fa bg" 为 "fa fa gb"
:s/abcde/abc^Mde/                # 修改 "abcde"    为 "abc"、"de" (两行)
:s/$/\^M/                        # 修改 "abcde"    为 "abcde^M"
:s/\w\+/\u\0/g                   # 修改 "bla bla"  为 "Bla Bla"
:s/\w\+/\L\u\0/g                 # 修改 "BLA bla"  为 "Bla Bla"
:s/aa/a^Ma/                      # 修改 "aa"  为 a<line-break>a
:s/aa/a\^Ma/                     # 修改 "aa" 为    a^Ma
:s/aa/a\\^Ma/                    # 修改 "aa" 为 a\<line-break>a

多文件编辑

  1. 已经打开一个文件

    • 打开一个新文件
      edit[!] foo.txt
    • 保存
      write
  2. 打开多个文件
    vim one.c two.c three.c
    然后可以用:[num]next, :wnext:[num]previous, :wprevious, :last, :first来切换
  3. 多文件跳转
    可以用args one.c two.c three.c来添加多个文件
    然后可以用CTRL-^来切换到上一个文件
    有两个标记非常重要:

     `'"`: 你上次离开这个文件的位置
     `'.`: 你最后一次修改文件的位置

    可以用m[a-zA-Z]来标记文件, 然后用'[mark]来跳转
    还可以用CTRL-OCTRL-I来在整个跳转序列中前后跳转

多窗口

分割窗口

可以直接用vim -O one.c two.c来直接以分割方式打开多个文件
-O : 垂直分割
-o : 水平分割

如果已经打开文件,可以使用命令来打开/关闭窗口

:sp[lit] {file}     水平分屏
:new {file}         水平分屏
:sv[iew] {file}     水平分屏,以只读方式打开
:vs[plit] {file}    垂直分屏
:clo[se]            关闭当前窗口
:only               只显示当前窗口

上述命令都有快捷键, 共同前缀是: CTRL-W

Ctrl+w s        水平分割当前窗口
Ctrl+w v        垂直分割当前窗口
Ctrl+w q        关闭当前窗口
Ctrl+w n        打开一个新窗口(空文件)
Ctrl+w o        关闭除当前窗口之外的所有窗口
Ctrl+w T        移动当前窗口到新标签页

切换窗口

Ctrl+w h        切换到左边窗口
Ctrl+w j        切换到下边窗口
Ctrl+w k        切换到上边窗口
Ctrl+w l        切换到右边窗口
Ctrl+w w        遍历切换窗口

移动窗口

Ctrl+w H        向左移动当前窗口
Ctrl+w J        向下移动当前窗口
Ctrl+w K        向上移动当前窗口
Ctrl+w L        向右移动当前窗口

调整窗口大小

Ctrl+w +        增加窗口高度
Ctrl+w -        减小窗口高度
Ctrl+w =        统一窗口高度

映射

$$ <map command> <args> {lhs} {rhs} $$

command

Command NormalVisualOperator PendingInsert OnlyCommand Line
命令 常规模式可视化模式运算符模式插入模式命令行模式
:mapnoremapyyy
:nmapnnoremapy
:vmapvnoremap y
:omaponoremap y
:map!noremap! yy
:imapinoremap y
:cmapcnoremap y

Operator-pending模式,是指当你输入操作符(比如d)时,然后继续输入的移动步长和文本对象(dw)的状态

nore的含义是, 禁止对{rhs}再进行映射扫描,以防止嵌套和递归,通常用于重定义一个命令

args

<buffer><nowait><silent><special><script><expr><unique> 可以按任意顺序使用。它们必须紧跟在命令的后边,而在其它任何参数的前边。

<buffer> : 只作用于当前buffer
<silent> : 不回显命令
<script> : 只能使用<SID>开关的脚本来映射{rhs}
<unique> : 如果映射或缩写的命令已存在,只命令失败
<expr> : 那个{rhs}是一个表达式,会用计算后的返回值代替{rhs}

强大的gv

:global 命令是 Vim 中一个更强大的命令 (之一)。它允许你找到一个匹配点并且在那里执行一个命令。它的一般形式是:

:[range]g/{pattern}/{command}

在每一匹配行上执行命令command. 这个命令只能是冒号命令, 普通模式命令不能在这里使用。如果需要,可以使用:normal命令。

如果要查看可以使用的命令,可以help ex-cmd-index。 如果要查看详细解释, 查看help 10.4help multi-repeat

vglobal相当于global!, 两者可以组合使用, 如:g/found/v/notfound/{cmd}

利用global我们可以把我们之前学的很多东西都串连起来,以完全一些非常奇妙的动作。

简单示例,

  • 要删除所有空行: :g/^$/d
  • 要在含有always..begin的行后加上:label: :g/always.*begin/s/$/ :label

exec和normal

execute命令用来把一个字符串当作Vimscript命令执行。比如: :execute "rightbelow vsplit " . bufname("#")

normal命令把我们的脚本跟日常的文本编辑按键结合起来, 比如: :normal ggdd。 为了防止递归解析, 建议永远使用normal!

利用exec和normal的组合可以将动作变成可重复的命令, 并消除转义字符问题。比如: :execute "normal! mqA;\<esc>'q"


  1. 0-9
  2. 0-9A-Fa-f
  3. a-z
  4. A-Z
  5. 0-9A-Za-z_
  6. \t

harriszh
338 声望131 粉丝

做些有趣的事,留些有用的存在


引用和评论

0 条评论