每日一 Vim 笔记

2018/05/08

每日一 Vim 笔记

GitHub

本笔记是在 VS Code 上装的 Vim 插件, 有些功能好像没用

每日一 Vim(0)入门操作

基本操作

  • vim helloworld.txt (普通模式下打开 < 如果该文件不存在 vim 自动新建该文件并打开)
  • :w 或者 :write #保存正在工作状态的文件
  • :up 或者 :update #保存正在工作状态的文件 up 在 windows 下面不生效
  • :w newfile.txt #另存为文件 newfile.txt
  • :up newfile.txt #另存为 newfile.txt
  • :x #保存当前文件再退出
  • :wq #同上
  • :q! #不保存文件直接退出

:x:wq 区别:

  1. :wq 强制性写入文件并退出(存盘并退出 write and quite)。即使文件没有被修改也强制写入,并更新文件的修改时间。
  2. :x 写入文件并退出。仅当文件被修改时才写入,并更新文件修改时间;否则不会更新文件修改时间。

光标移动

  • h:向左移动
  • j:向下移动
  • k:向上移动
  • l:向右移动

每日一 Vim(1)基础进阶

翻一页 / 半页

  • ctrl + f:向下翻一页 forward 前进
  • ctrl + b:向上翻一页 backward 后退
  • ctrl + d:向下翻半页 down
  • ctrl + u:向上翻半页 up

光标一次移动一个单词的长度

  • w:移动到下一个单词的起始处(既然是 w,代表的意思就是 word,好记吧)
  • W:移动到下一个单词的起始处

那么 w 和 W 它俩有什么区别呢,w 会把一个单词理解成由连续的字母或数字或特殊字符,而 W 却以空格来识别是否到了下一个单词

与之相反的两个操作是 b 和 B

  • b:移动到前一个单词的起始处
  • B:移动到前一个单词的起始处(b 和 B 的区别与 w 和 W 是同理的)

  • e:移动到下一个单词的结尾处
  • E:移动到下一个单词的结尾处

光标在一行内的移动

  • 0(零):移动到行首
  • $:移动到行未
  • ^:移动到当前行的第一个非空字符处(如果该行首没有空格,那么效果与 0 是一样的)
  • g_:移动到当前行的最后一个非空格字符处

插入,追加字符

  • i:在当前光标位置插入字符
  • I: 在当前行行首插入
  • o:在当前行往下插入新的一空行
  • O:在当前行往上插入新的一空行
  • a:在当前光标后追加字符
  • A: 在当前行行尾插入
  • r: 单字符替换
  • R:替换当前光标的字符直到退出插入模式(按 ESC)

拷贝一个单词、行首、行尾、整行

  • y[n]w:拷贝后面 n 个单词,yw 拷贝当前单词
  • y0:拷贝的范围是当前光标处到行首
  • y$:拷贝的范围是当前光标处到行尾
  • y^:拷贝的范围是当前光标处到本行第一个字符
  • yg_:拷贝的范围是当前光标处到本行最后一个字符
  • yy/Y:拷贝当前行
  • nyy:从当前行开始拷贝 n 行(这里的 n 是数字)

拷贝完后用 p 就可以粘贴了。

  • p:粘贴到光标后
  • P:粘贴到光标前

删除一个单词,行首、行尾、整行

  • x:删除当前光标处字符(严格来说 x 不属于插入,因为你还要按 i 才能插入)
  • d[n]w:删除后面 n 个单词,dw 删除当前光标处单词
  • d0:删除光标处到行首的字符
  • d$/D:删除光标处到行尾的字符
  • d^:删除光标处到本行第一个字符
  • dg_:删除光标处到本行最后一个字符
  • dd:删除整行
  • ndd:删除 n 行(同样 n 代表数字)

每日一 Vim(2) 简单搜索

撤销恢复

  • u: 撤销 (undo)
  • ctrl + r: 重做 (redo)

命令计数器

前面知道了翻页的操作,那么我想具体的往上或往下移动那个光标呢,那么你可以使用命令计数器来实现,如果我要向上移动 8 行,那么直接 8k 就 ok 了。

匹配括号

%

移动

  • G: 移动到最后一行
  • gg: 移动到第一行
  • nG: 移动到第 n 行行首
  • ngg: 移动到第 n 行第一个非空字符处
  • :n + enter: 移动到第 n 行行首

简单搜索

  • /string: 向下搜索 string。搜索出来后,如果有多个,回车后 n 继续向下搜索,N 继续向上搜索
  • ?string: 向上搜索 string。搜索出来后,如果有多个,回车后 n 继续向上搜索,N 继续向下搜索

每日一 Vim(3)替换

  • :[addr]s / 源字符串 / 目的字符串 /[option]: 我们可以看出 addr 和 option 是可以缺省不填的,他们各个字段的意思是:

    • [addr] 代表检索范围,缺省表示当前行,1,10 表示 1 到 10 行,% 代表整个文件等价于 1,$,而 .,$ 代表当前行到文件末尾
    • s 代表替换的意思
    • option 代表操作类型,缺省只对第一个匹配的字符进行替换,g 代表全局替换,c 代表操作时确认,gc 可以组合使用
  • :s/aa/bb/g: 将光标所在行出现的所有包含 aa 的字符串中的 aa 替换为 bb
  • :%s/aa/bb/g: 将文档中出现的所有包含 aa 的字符串中的 aa 替换为 bb
  • :12,23s/aa/bb/g: 将从 12 行到 23 行中出现的所有包含 aa 的字符串中的 aa 替换为 bb
  • :%s/^/#: 全文的行首加入 # 字符, 批量注释的时候非常有用
  • :%s= *$==: 将所有行尾多余的空格删除
  • :g/^$/d: 这里的 g 表示对文章中所有符合要求字符串执行替换操作,^ 表示行首,$ 表示行尾,整个意思是:将所有的空行删除.

每日一 Vim(4)多文件编辑

每日一 Vim(5)c 命令

  • C or c$: 表示修改当前行上光标后面的部分. 进入编辑状态.
  • c0 or c^: 表示从光标处到当前行行首的部分进行修改,^ 代表首个非空格处。
  • cc OR S: 修改当前行. 进入编辑状态.
  • cw: 从光标所在的位置开始到该单词结束进行修改. 进入编辑状态
  • cfx / cFx: 这里的 x 为一任意字符, cfx 表示修改从光标到下一个字符 x 之间的文本; cFx 表示修改从光标到上一个字符 x 之间的文本.
  • cn|: 修改从光标到当前行的第 n 个字符 (不包括该字符) 间的所有字符, n 正整数.
  • cnG / cG: 这里的 n 为一任意自然数, cnG 表示修改光标所在位置到第 n 行 (不包括) 之间的所有行; cG 表示修改当前行直至末行.

c 命令所删除的数据都存在缓冲区, 可以结合 p/P 命令构成剪切粘贴操作, 方法是:

先进行 c 命令, 再按 Esc 键返回命令模式, 最后才进行 p/P 命令.

每日一 Vim(6)常用命令总结

搜索

  • /word: 从顶部往底部搜索 word
  • ?word: 从底部往顶部搜索 word
  • /jo[ha]n: 搜索 john 或 joan

    在 VS Code 中, 目前发现 \< \> 无效

  • /\< the: 搜索 the 或 theatre 或 then(只要是 the 开头就行)
  • /the\>: 搜索 the 或 breathe(只要是 the 结尾就行)
  • /\<the\>: 只搜索 the
  • /\<....\>: 搜索长度为 4 个字符的字符串
  • /\<fred\>: 搜索 fred,alfred 或者 frederick 都不能匹配
  • /fred\|joe: 搜 fred 或 joe
  • /\<\d\d\d\d\>: 搜索 4 位数字的字符串
  • /^\n\{3}: 查找 3 个空行的地方

替换

  • :%s/old/new/g: 用 new 替换文件中出现的所有 old
  • :%s/old/new/gc: 与上面这条的作用一样,只不过每替换一个就要确认一次, 貌似 VS Code 没有
  • :2,35s/old/new/g: 用 new 替换 2 到 35 行的 new
  • :5,$s/old/new/g: 替换 4 行之后所有 old
  • :%s/^/hello/g: 用 hello 替换所有行首,相当于在行首插入 hello
  • :%s/$/Harry/g: 在所有行末加入 Harray
  • :%s/onward/forward/gi: 用 forward 替换 onward,忽略大小写
  • :%s/ *$//g: 删除所有行末的空格
  • :%s/^ *//g: 删除所有行首的空格
  • :g/string/d: 删除所有出现有 string 的行
  • :v/string/d: 删除所有不包含 string 的行
  • :s/Bill/Steve/: 用 Steve 替换当前行首次出现的 Bill
  • :s/Bill/Steve/g: 用 Steve 替换当前行出现的所有 Bill
  • :%s#<[^>]\+>##g: 删除所有 HTMl 标签,保留文本
  • dit: 保留当前行 html 标签,删除文本
  • :%s/^\(.*\)\n\1$/\1/: Delete lines which appears twice
  • Ctrl+a: 递增当前光标出的数字
  • Ctrl+x: 递减当前光标处的数字
  • ggVGg?: 将全文转换为 rot13 码,这是一种简单暗号语 Rot13,重复执行此命令回复原样

大小写

  • Vu: 当前行转换为小写
  • VU: 当前行转换为大写,当然对中文无效
  • g~~: 大小写置换
  • vEU: 选择性的转换为大小,从光标起始处到
  • vE~: 也是将选中的大写转小写,小写转大写。
  • ggguG: 全文小写,其实我们可以拆分 3 个命令 gg/gu / 来记忆
  • :set ignorecase: 搜索时忽略大小写

每日一 Vim(7)自动补全

** 注:以下命令都是在插入模式下执行。**

单词自动补全:

ctrl+n :当你输入第一个字母的时候,再 ctrl+n,自动出现下拉菜单,单词默认选中第一个,继续 ctrl+nctrl+p 可以上下切换,或者用方向键(太慢) ctrl+p :同上,只是默认的选中的是列表中最后一个单词

行自动补全:

ctrl+x ctrl+l (l 指小写的 l):两个命令组合使用。在插入模式下输入已经存在行的第一个单词,再按这两个键,就会列出该整行出来

文件名自动补全:

ctrl+x ctrl+f :插入模式下,按这两个组合键,可以插入当前目录下的文件名。处用在哪里呢,当然是有时候我们要指定默认执行文件的路径,这样就方便啦。

每日一 Vim(8)—Vim 寄存器

先抛出一个问题:每次打开 vim,想找一段文本来练练手,于是打开网页 copy 了一段,问题来了,怎样粘贴到 vim 的编辑器里头去呢?如果你还在 ctrl+v 的话,说明你还无法割舍 windows,这里暂且告诉你如何粘贴:shift+insert 两个键联合起来。再来看下面的原理

寄存器是 Vim 用来存储文件的临时空间,当使用命令 y(yank)或 d(delete)复制删除文本时,该文本就会被保存在寄存器中,通过 p(put)命令插入刚删除或复制的内容。vim 的寄存器分为不同的种类:

数字寄存器:

在 normal 模式下输入 :reg,您是否看到很多 "(双引号)开头的数字了呢,这些都是寄存器,(如果暂时没看到,那么在对文本做几个操作,比如:dd,yy 等),这些寄存器里保存了最近删除的和复制的文本。

数字寄存器有十个,分别是:"0"1"2"9(注意:数字前有个双引号),寄存器 "0 保存上一次复制 (y) 操作的文本,"1"9 寄存器保存最近 9 次删除的文本行(注意这个 “行” 字),"1 保存的内容是最最近一次删除的内容(也就是说最后一次执行删除命令保存的内容)"2 保存的是倒数第二次删除的内容,依此类推,直到 "9,如果又有新的操作,那么 "9 的内容将会被 "8 的内容替换,先前 "9 的内容将被丢弃。

那么 p(put)命令粘贴是哪个寄存器中的内容呢?有时候是粘贴的是 "1 寄存器的,有时粘贴的是 "0 寄存器中的,但是总的原则就是粘贴最近一次删除或者复制的内容,如果删除是最近的一次,就是粘贴 "1 的,也就是粘贴刚刚删除的文本,如果复制是最近的一次操作,那么粘贴的内容是 "0 中的,也就是粘贴刚刚复制的内容。

字母寄存器:

"a"b"c… 都是字母寄存器,也许你执行 :reg 的时候看不到这些命令,不要紧,稍后就有了。之前粘贴我们用的都是 p 命令,如果我想粘贴其他寄存器里面的内容呢,你想到了吗?答案就是: 寄存器的名称 + p。现在我们新建一个字母寄存器,把当前三行保存到 "a 寄存器中去,具体操作如下:在 normal 模式下输入 "a3yy,这样当前三行就保存在 "a 中去了,粘贴同样在 normal 模式下,"3p 即可。如果是大写字母的寄存器,如执行:"Cdd:他的作用是把当前行删除,再把内容追加到 "c 寄存器中,也就是说字母寄存器没有大写之分,只是功能上有区别,大写就是追加,小写是替换。

其他寄存器:

"":无名寄存器,p 命令粘贴的内容,保存最近一次删除或复制的内容。 "-:(- 是个减号)小删除寄存器(small delete register),前面说过要您注意这个” 行 “字,也就是说并不是所有删除的文本都会保存在数字寄存器中,如果你删除的只是一个单词或字母: dw 或者 x,那么这个单词并不会保存在 "1 寄存器中,而是保存在 "- 寄存器里面。所有不包含换行符的删除都会保存在此寄存器中。

"* :这个就是系统寄存器喽,最开始的问题的第二个答案知道了吧

当然还有一些寄存器,这里就不一一介绍了。

每日一 Vim(9)—- 缩进

normal 模式下:

>>: 当前行增加缩进 <<: 当前行减少缩进

每日一 Vim(10)—– 正则表达式

每日一 Vim(11)– 标记

文件保存高级篇

以下部分命令在之前的篇幅中有涉及过,有句话说的好:**vim 对新手最痛苦的是选择太多,不知所措,对老手来说最让人快乐的是一个问题总有不同的解决方法,而对寻找最优方法乐此不疲 **,细心的读者相信您都能从中总结出自己的规律以及经验来。

  • :w new_file:将缓冲区内容保存为 new_file 文件,原文件内容不更改。
  • :20,$w new_file:将文件 20 行处到结尾保存为 new_file 文件
  • :.,20w new_file:将光标所在行到第 20 行保存为 new_file 文件
  • :20,30w >> new_file:追加 20 至 30 行内容到 new_file 文件中

一个文件 copy 到另一文件

  • :r filename:把 filename 中的内容插入到光标所在行的下一行
  • :100r filename: 把 filename 中的内容插入到 100 行的后面
  • :$r filename:插入行尾
  • :0r filename: 插入行首
  • :/parttern/r filename:还可以使用正则表达式,插入到匹配出的后面一行,需要注意的是如果有多处匹配,它只插入到首个匹配的地方。

标记

标记又称为书签,在某个位置打上标记后,在别处编辑完,通过命令可以回到标记处(以下命令模式中执行)

  • mx: 将当前位置标记成 x(此处的 x 可以是任意字母)
  • 'x(单引号): 光标移到标记 x 处的行首
  • `x(反引号): 光标移到标记 x 处
  • ``(双反引号): 当前光标位置与光标上次位置来回切换
  • ''(双引号): 当前光标位置与光标上次位置来回切换,光标定位在行首

每日一 Vim(12)ab 与 map 命令

每日一 Vim(13) 多窗口

默认情况下,Vim 只为一个 session 打开一个窗口,可以用参数 -o 来打开多个窗口,

:vim -o file1 fiel2,默认这个 session 会水平分割两个窗口显示,

另外参数 o 后面还可以跟数字 :vim -o3 file1 file2 这样 Vim 会打开三个窗口,最后一个窗口会留空白.

打开窗口

如果 vim 已开启,那么在 normal 模式如下命令使用:

  • 水平分割窗口

    • :split: 当前窗口一分为二,两个窗口显示相同内容。
    • :10split: 新窗口的高度 10 行
    • :split otherfile: 新窗口中打开 otherfile
    • :new: 功能和 split 一样
    • :sp: split 的缩写形式
    • ctrl+w+s: 分割窗口的快捷方式
    • :q: 关闭当前窗口
  • 垂直分割窗口

    • :vsplit: 以上所有命令都适用于打开垂直分割窗口,只要在前面加 v(vetical)

窗口光标移动:

  • 鼠标操作

    gvim 默认支持鼠标移动光标操作。

    vim 可以设置 :set mouse=a, 我猜 a 就是 available 的意思。

  • 键盘操作

  • ctrl+w+k: 使用 ctrl+w(window) 结合 hjkl 来移动。先按住 CTRL+w,再按 k,光标就移到上面窗口。hjkl 前面可加数字,移动多个窗口
  • ctrl+w+T: (大写 T)移动当前窗口至新的标签页(tab,下节专业讲讲标签页)
  • ctrl+w+K: (大写 K)HJKL 四个组合命令(移动并回流窗口命令,窗口和光标一起移动)

调整窗口尺寸

  • gvim 鼠标支持拖拉动作来改变窗口大小。我想你不会这么做,命令行才是高效率工作。
  • ctrl+w 结合 +-= 当然 +-= 前面可以接数字,分表代表增大、减小、均分窗口。
  • resize -4 明确指定窗口减少多少
  • ctrl+w 结合 < > 增加窗口宽度

每日一 Vim(14)标签页(tab)

新建标签页

  • :tabe: 新建未命名的标签页
  • :tabe file: 在新标签页中打开或新建文件 file
  • :tabnew: 和 :tabe 命令功能一样
  • :tab split: 在新标签页中打开当前窗口(缓冲区)的文件
  • :tabf *.txt: 当前目录搜索匹配 *.txt 的文件,在新标签页打开。该命令只能打开一个文件,如果该正则表达式匹配了多个文件,则提示 “文件名过多” 而无法打开。

列出标签页

  • :tabs: 列出已打开的标签列表,> 表示当前标签页

切换标签页

  • :tabn: 移动到下一个标签页(next)
  • :tabp: 移动到上一个标签页(previous)
  • gt: 等效于 :tabn
  • gT: 等效于 :tabp
  • :tabfirst: 移到第一个标签页
  • :tabr: 等效于 tabfirst
  • :tablast: 移到最后一个标签页
  • :tabm 0: 移到第一个标签页
  • :tabm: 当前标签移到最后

标签移到两端时会循环移动

关闭标签页

  • :tabc: 关闭当前标签页
  • :tabo: 关闭当前标签以外的标签页
  • :set showtabline=0: 关闭标签页菜单
  • :set showtabline=1: 显示标签页菜单
  • :tabdo: 多标签页命令,可以在多个标签页中执行命令,比如替换多个标签中的内容 :tabdo %s/foo/bar/g

更多细节::help tab-page-intro

每日一 Vim(15)折叠 (fold)

Vim 用命令 foldmethod 实现折叠功能,一共有六种折叠方式,可以用 :set foldmethod 查看当前 session 用的是哪种折叠,默认 vim 使用 manual(手动)方式。

manual

手工折叠是最基本的折叠方式,在处理小块文件的时候简单实用。

  • zf: 创建折叠(fold creation)
  • zo: 打开折叠 (open)
  • zc: 再次折叠起来 (close)

举例说明:

  • v{motion}zf: 折叠 V 模式下选中的文本。(这里的 v{motion} 指的是 Shift+v)。
  • zf\`a: 折叠当前光标处到标记 a 处的文本 (ma 就表示在当前光标出做 a 标记)
  • zf3j: 折叠当前光标出下 3 行
  • zf10G: 从当前行折叠至第 20 行
  • zfgg: 折叠至行首
  • zf%: 光标移至’{‘时,vim 会去匹配’}’,这样’{}’之间的内容就可以折叠起来

indent

vim 自动根据缩进折叠,缩进量与折叠行的嵌套深度关系由 shiftwidth 控制,通过设置 :set foldlevel=numnum 代表数字。foldlevel=0 时关闭所有折叠,等价于 zMzR 设置折行为最大值

每日一 Vim(16)Visual 模式(0)

Vim 的 Visual 模式(中文称之为可视化模式)可以对所选择的文本进行各种操作,Virsual 模式可以分为三种,分别是字符 (Characters)、行 (line)、矩形块 (rectangular block)

viwc

今天呢,就只讲一点点有关 V 模式的用途吧,在 windows 中替换一个单词惯用的手段就是先找到这个单词,鼠标双击该单词,选中之后直接输入新的单词就 Ok 了,但是使用 Vim,你就应该摒弃鼠标,甚至四个方向键也不要去碰。那么在 Vim 中,概括起来就是四个字 <E>f{char}viwc(请看小标题,这里貌似有十多个字儿,且慢,一个个解析下:<E>:Esc,进入 normal 模式,f:查找字符串,当然还可以用 “;” 或者 “,” 继续往后或往前找,v:visual 模式,iw:选中整个单词,c:删除单词,进入插入模式),这样整个单词就会删除,接着就可以插入你想替换的单词了。其次,在 Visual 模式下,hjkl 光标移动的键同样是可用的。对了,在 normal 模式下 “.” 可以重复执行上一次操作,有点象 Python 中的下划线 “_” 表示最后一个表达式的值一样。例如你最后执行的命令 dd,那么按 “.” 就会继续删除当前行。

在 VS Code 中, f 无法查找字符串, 只能使用 / 查找

每日一 Vim(17)Visual 模式(1)

字符可视化模式可以对任何单个字符或字符串甚至是多行进行处理,通常适用于处理单词或者词组,如果是想处理整行,那么就可以使用(line)行可视化模式,块可视化 则可以对文档区域操作,支持列操作。normal 模式下,命令对应的 Visual 表如下:

  • v: 基于字符的 Visual 模式
  • V: 基于行的 Visual 模式
  • Ctrl+v: 基于块的 Visual 模式
  • gv: 重新选取最后一次使用 Visual 模式选中的文本

Visual 模式之间的切换

如果当前是在字符 Visual 模式下,V 就能切换到基于行的 Visual 模式,Ctrl+v 就是切换到基于块的 Visual 模式下,来回的按 v 能在 normal 模式和字符 Visual 模式下切换。此规则同样适用与另外两种 Vrsual 模式。

每日一 Vim(18)Text-Object

前两节讲了 Visual mode 相关内容,这里提一个小问题,“如何选择一个单词?”3 秒后…,你可能会使用命令 vw,很不幸的是它会把下一个单词的首字母也选中。如果你足够细心的话,你会发现答案在之前的章节中讲过,命令是:viw。它的作用是选取一个单词(word),无论光标在这个单词的哪个位置都能选中整个单词,那么 i 到底有什么作用呢?这就是今天要讲解的内容。

  • Text-Object:

    可以指一个单词,一整句文本,抑或一对括号内的文本,甚至是 htmlxml 标签内的文本,都可以抽象成 Text-Object。与 Text-Object 紧密相关的两个命令就是 ai,啊?这两个命令不是 appendinsert 吗?其实,ai 操作在 Visual mode 或者某些操作(比如:d,y 等)后面就是另外一种效果了。例如,删除一个单词可以用 daw 或者 diw。那么 ai 又有什么区别呢?

**a 会选择一个对象(an object)包括空格在内,而 i 只会选择一个对象的内部(an inner object)不包含空格 **

下面就是一些命令含义:

  • aw: a word
  • iw: inner word
  • aW: a WORD 从当前单词向左右延伸一直到空格或换行, 包括空格
  • iW: inner WORD 同上, 但不包括空格
  • as: a sentence
  • is: inner sentence
  • ap: a paragraph
  • ip: inner paragraph
  • a[|]: a[] block(这里的’ ‘是或的意思,也就是说’a[‘和’a]’都表示一个 [] 块)
  • at: a tag (这里的 tag 可以是 html 或 xml 中任何标签对)
  • it: inner tag

比如在一个 html 文件中,当前光标在某个标签对的内容里头的时候,命令 dat 会把整个标签对包括内容都会删除,而 dit 只会删除标签对之间的内容,保留标签对。详细说明可以 :help text-objecgts

每日一 Vim(19)Visual-Block 模式

从这节开始做点小小变化,增加一些例子的成分,这些例子一般来自于实际编程情景中,算是理论与实践相结合。

Visual-Block 模式一个非常强大的功能就是它支持列操作,比如在某个代码块每行的行首插入注释符号。举例说明:假如有如下 Python 代码,我想把它全部注释

for e in exclude:
if e.endswith(".py"):
  try:
  os.remove("%sc" % e)
  except:
    pass
    try:
    with open(e, "r") as f:
  exclude[e] = (f.read(), os.stat(e))
  os.remove(e)
  except:
    pass
  1. 光标定位到代码块的行首,Ctrl+v 进入 Visual-block 模式
  2. 光标向下移动,直到选择所有代码行的第 0 列
  3. 输入 I(光标前插入字符),此时你会发现光标跳到了代码块的开头处,此时已经是 insert 模式了,现在就插入 python 的注释字符’#’
  4. Esc 键,此时你会发现代码块所选区域都打上了注释符号,如下所示:
#for e in exclude:
#if e.endswith(".py"):
#   try:
#       os.remove("%sc" % e)
#   except:
#      pass
#      try:
#      with open(e, "r") as f:
#   exclude[e] = (f.read(), os.stat(e))
#   os.remove(e)
#   except:
#        pass

第二个例子:下面是一段 JavaScript 片断:

var foo = 'a'
var bar = 'bcd'
var fb = foo + bar

我们知道 js 中大部分浏览器都能忍受后面没有分号结尾的语句,但是并不推荐这样做,因为我们有必要给他们在行末都加上分号,我们知道 vim 吸引人的地方之一就是一个问题往往有不同的解决方案,这里我们至少有两种方法,1. 替换法::1,3s/$/;/g(这里的 1,3 是第一到第三行)2. 在 Visual block 模式下 append(追加)。

我们观察上段代码发现每行的语句的长短不一,那有如何批量的加上 “;” 呢,这里关键的一个命令是 $,美元符号定位了行未。操作步骤基本还是和第一个例子差不多。只需在选中代码块的时候要注意是:Ctrl+v jj$,这样就能选中到每一行的行末。接着输入 A 命令表示在行末追加字符,输入 “;” 再按 Esc 大功告成了。最终的效果:

var foo = 'a'
var bar = 'bcd'
var fb = foo + bar

每日一 Vim(20)Vim 编码设置

每日一 Vim(21)又谈 abbreviation

每日一 Vim(23)宏 —Record、Play

今天要说的其实就和这个复读机相关,复读机在按下复读的按钮后,就开机录制需要复读的内容,再按一下录制完成,接下来就可以播放了。Vim 中也有与之惊人相似的操作,如果想重复某个操作,就可以用 ** 宏 ** 来完成,还记得以前讲过的一个命令吗:. 就是这个 ** 点 ** 可以重复执行最后一次操作,但是这个 . 的功能比较弱,没法组合使用,如下代码,想在每行末加上分号 “;”:

int a = 1
int b = 2
int c = a + b
print a
print b
print c

如果是用 . 来实现的话,首先在第一行执行 $a;,然后重复 5 次执行 j$.,这样算下来你要敲击的键总数在 15 次之多,但是我们用 Record/Play 的话,即使是 100 行代码,按键也不会超过 10 次。命令闪亮登场:q,就是这个 q,它的威力很猛。接下来就详细介绍如何操作 q 来实现上述需求。

  1. normal 模式下输入 q 启动 recoding,q 后面跟任意 a-z 的小写字母比如 m,这个字母就是宏的名字,接下来你要执行的操作就会记录在这个宏中。
  2. 执行我们的任务:“行末加分号”,命令是:$a;<Esc>j$,这条命令意思就是:移动行尾插入分号,退到 normal 模式,光标移动到下一行的末尾。
  3. 再次输入 q,表示录制结束
  4. 录制结束后我们就可以 play 了,输入 @m 就会执行宏中的操作,m 是第一步中使用的宏的名称,5@m 表示重复执行 5 次。这样,所有行都给加上分号了,真是好使。

再举一例:实现如下效果:从 1 到 100,每行 + 1。

1
2
3
...
100

命令:首先在第一行插入 1,然后光标定位了 “1” 处,进入 normal 模式,开始录制:qmyyp<Ctrl>aq,(解释:yyp:拷贝一行再粘贴在新的一行,<Ctrl>a:数字 + 1)后然执行 98@m,收工。

帮楼主补充几点:

  1. 楼主的宏中第 2 步用 A;j 就行了。定义宏的一个惯用套路是: 行内跳转定位 + 真正操作 + 移动到下一目标行。 把行内跳转定位放在开头可以让你 replay 时不用事先把光标放在特定的列位置。而因此在宏末尾再做一次行内定位就多余了。

  2. 宏与 yank 是共享寄存器的,最好有某种策略保证不会冲突。我个人的习惯是 qwer 四个寄存器用来录制临时用完即弃的宏(靠近 q 和 @比较好按)。uiop 四个键预留给 yank (靠近 “ 和 y,p 键。也就是除了常用的 “和 0 号寄存器外,再预留四个寄存器来做复制粘贴,通常够用了),其他字母键用来记录固定宏(也就是关了 vim 下次打开还会接着用的常用宏)

  3. 可以用 :put 寄存器名称 命令把宏输出到编辑区进行编辑,改好后再 yank 回去。改动时在插入模式下可以用 ctrl+v 后跟组合键来输入组合键(例如你要在宏中回车,在修改宏时可以按 ctrl+v ctrl+m ),当然直接用尖括号括住的特殊键名称亦可。 (例如 表示回车)

具体可以参考 :h keycodes 。 利用这一点可以把一些常用的但又比较复杂的宏的导出到文件中,使用时再 yank 进去,突破 26 个字母寄存器的限制。

每日一 Vim(24)行复制与移动

每日一 Vim(25)filetype—- 文件类型检测

每日一 Vim(26)Normal 命令

每日一 Vim(27)高亮所有搜索模式匹配

* 向后搜索光标所在位置的单词 # 向前搜索光标所在位置的单词 nN 可以继续向后或向前搜索匹配的字符串

:set hlsearch 高亮所有匹配字符串 :nohlsearch 临时关闭,他的缩写形式是::noh :set nohlsearch 彻底关闭,只有重新 :set hlsearch 才可以高亮搜索

:nnormap <silent> <Space> :nohlsearch<Bar>:echo<CR> 按空格关闭高亮,清空所有已经显示的 如果你想在高亮与不高亮之间快速切换,可以做一个映射 : :noremap <F4> :set hlsearch! hlsearch?<CR> 按回车,临时返回高亮搜索 :nnoremap <CR> :nohlsearch<CR><CR>

每日一Vim(28)全局命令