10

Vim 使用技巧整理

 2 years ago
source link: http://kuanghy.github.io/2019/11/23/vim-skill
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Vim 使用技巧整理

文本编辑 | Nov 23, 2019 | vim

Vim 是 VIMproved 的缩写,即 Vim 编辑器是 Vi 编辑器的改进版。Vim 采用模式编辑的理念,其提供多种操作模式,按键在不同的模式下作用不同。 如,普通模式用于浏览文件,插入模式用于插入文本,可视模式下可以选择行或文本块,命令模式可以执行命令等等。

和模式编辑紧密相连的概念是 操作符动作操作符 指的是开始某个行为,如修改、删除或者选择文本;之后你要用一个 动作 来指定需要操作的文本区域。比如,要改变括号内的文本,需要执行 ci((读做 change inner parentheses);删除整个段落的内容,需要执行 dap(读做:delete around paragraph)。

Vim 存在一个兼容模式,该模式让 Vim 兼容 Vi。在兼容模式下运行时,Vim 大部分增强及改善的功能将不可用。需注意的是,这种模式下,Vim 并不能简单等同 Vi - 此模式只是设定一些类似 Vi 编辑器工作方式的默认选项。

Vim 包含三种不同的操作模式,即 命令模式(或者叫 普通模式)、插入模式底行命令模式。使用 ESCi/o/a等,: 来切换不同模式。打开 Vim 时,默认停留在 命令模式,按 i 等键可以进入 插入模式 进行文本编辑,按 ESC 键可以退出编辑模式,然后输入 : 可进入底行命令模式。编辑模式和底行命令模式都只能从命令模式进入,ESC 键主要用于退出编辑模式和底行命令模式。另外,还有两种常用的工作模式,可视模式 (Visual-mode)粘贴模式(Paste-mode)

在以下的描述中,所有以 : 开头的命令都表示在底行命令模式下的命令,所有不以 : 开头的命令都表示在普通模式下的命令。

Vim 自带一个交互式的教程,包含一些基础的操作,可以通过终端运行以下命令打开教程来练习使用:

$ vimtutor

打开文件

从命令行中打开:

打开文件
$ vim filename

当指定一个目录时会打开一个目录树
$ vim dirname

打开多个文件并横向分屏
$ vim -o file1 file2 file3

打开多个文件并纵向分屏
$ vim -o file1 file2 file3

打开文件并调到指定行
$ vim filename +num

在打开文件前,先执行指定的命令
vim -c cmd filename

恢复上次异常退出的文件
vim -r filename

以只读的方式打开文件,但可以强制保存
vim -R filename

只读的方式打开文件,不可以强制保存
vim -M filename

打开文件,并将光标停留在第一个找到的 string 上
vim +/string filename

用已有的 vim 进程打开指定的文件
vim --remote filename

从 Vim 中打开文件:

打开文件
:e filename

打开目录树(默认打开当前目录)
:Ex dirname

打开一个文件并横向分屏
:sp filename
:split filename

打开一个文件并纵向分屏
:vsp filename
:vsplit filename

打开以光标所在字符串为文件名的文件
gf

保存与退出

:w -- 保存修改
:wa[ll] -- 保存所有修改过的窗口
:wq -- 保存并退出
:x -- 保存并退出
ZZ -- 保存并退出

:n1,n2w filename -- 选择性保存从某n1行到另n2行的内容

:saveas newfilename -- 另存为

:q[uit]  -- 退出 vim
:q! -- 强制退出(放弃修改)
:qa[ll] -- 关闭所有窗口,退出vim

:close -- 关闭当前窗口

:only -- 只保留当前窗口,关闭其它窗口(CTRL-W o)

缓冲区

缓冲区是一个文件的内容占用的那部分 Vim 内存。每一份文件都是在他们自己独有的缓冲区打开的,每次文本都是作为缓冲区的一部分显示的。列出缓冲区可以用如下三个命令:

:buffers
:files
:ls
:ls
  1 %a   "test1"                        line 1
  2      "test2"                        line 0
  3      "test3"                        line 0

其中,第一列是文件编号,第二列是缓冲文件的状态,第三列是文件的名称,第四列是上一次编辑的位置。 缓冲文件的状态有如下几种(仅供参考):

  • - 非活动的缓冲区
  • a 当前被激活缓冲区(光标所在的缓冲区)
  • h 隐藏的缓冲区
  • % 当前的缓冲区(指当前窗口可见的缓冲区,因为可以分割窗口,可能有多个)
  • # 交换缓冲区
  • = 只读缓冲区
  • + 已经更改的缓冲区

切换工作区用 :buffer/:b 命令,或者用 :sbuffer/sb

:[s]b 编号
:[s]buffer 文件名

:[s]bn[ext]
:[s]bp[revious]
:[s]bl[ast]
:[s]bf[irst]

添加或删除缓冲区

添加一个文件到缓存区
:bad[d] 文件名

新建一个未命名的缓冲区
:enew

从缓冲区删除一个文件
:bdel[ete] 文件名/编号

参数列表

缓冲区列表是 Vim 的特性。在这之前的 vi 中,仅仅只有参数列表,参数列表在 Vim 中依旧可以使用。

每一个通过 shell 命令传递给 Vim 的文件名都被记录在一个参数列表中。可以有多个参数列表:默认情况下所有参数都被放在全局参数列表下,但是你可以使用 :arglocal 命令去创建一个新的本地窗口的参数列表。

使用 :args 命令可以列出当前参数。使用 :next:previous:first:last 命令可以切换在参数列表中的文件。通过使用 :argadd:argdelete 或者 :args 等命令改变参数列表。

参数列表在有些情况下是非常有用的,如使用 :argdo 做批处理,示例:

:args **/*.[ch]
:argdo %s/foo/bar/ge | update

以上命令将替换掉当前目录以及其子目录中所有的 C 源文件和头文件中的 “foo” 为 “bar”。:argdo 命令会对参数列表中的文件执行相同的动作。

更多关于参数列表的信息,可以通过查阅离线文档了解 :h argument-list

标签/窗口

窗口 是缓冲区更上一层的视窗。如果想同时查看几个文件或者查看同一文件的不同位置,则可以开启多个窗口。窗口可以水平或者竖直分割并且现有窗口的高度和宽度可以被调节。

打开多个窗口可以用以下命令:

# 横向打开一个新窗口
:sp[lit]
:sp[lit] filename
:new
:new filename

# 纵向打开一个新窗口
:vsp[lit]
:vsp[lit] filename

ctrl-w s  上下分割当前文件
ctrl-w v  左右分割当前文件

# 水平分割一个窗口,浏览文件系统
:Sex

# 垂直分割一个窗口,浏览文件系统
:Vex

窗口大小纵向调整:

:ctrl+w +  纵向扩大(行数增加)
:ctrl+w -  纵向缩小 (行数减少)
:res(ize) num  如 :res 5,显示行数调整为5行
:res(ize) +num  把当前窗口高度增加 num 行
:res(ize) -num  把当前窗口高度减少 num 行

窗口大小横向调整:

:vertical res(ize) num  指定当前窗口为num列
:vertical res(ize)+num  把当前窗口增加num列
:vertical res(ize)-num  把当前窗口减少num列

标签页 是可以容纳一系列 窗口 的容器。打开标签可以使用以下命令

:tabe[dit] [文件名]
:tabnew [文件名]

切换标签页:

# 下一个标签
gt
:tabn[ext]

# 上一个标签页
gT
:tabp[revious]

# 快速切换到第一个标签或最后一个标签
:tabfir[st]  :tabr[ewind]
:tabl[ast]

使用 :ectrl+^ 可以回到刚才编辑的文件,这已操作感觉很实用。

其他操作:

# 显示所有标签
:tabs

# 关闭标签
:tabc[lose]

# 关闭所有其他标签页,只保留当前活动标签页
:tabo[nly]

# 将当前标签页移到第 n 个标签页之后
:tabm[ove] N

# 同时在多个标签页中执行命令
:tabdo command

如 :tabdo %s/food/drink/g 可一次完成对所有文件的替换操作,而不用针对每个文件重复操作

随便说一下,缓冲区列表是全局可见的,可以在任何标签中访问任何一个缓冲区。

寄存器

寄存器是存储文本内容的空间。常用的「复制」操作就是把文本存储到寄存器,「粘贴」操作就是把文本从寄存器中读出来。例如常用的复制快捷键 y,粘贴快捷键 p,也都是对寄存器(匿名寄存器 Unnamed)的操作。

Vim 提供了大致 10 类共 48 个寄存器。寄存器以 " 开头进行标记,即 "{register}。可以用 “{register}y 来拷贝到 {register} 中, 用 “{register}p 来粘贴 {register} 中的内容。如:”ayy 可以拷贝当前行到寄存器 a 中,而 “ap 则可以粘贴寄存器 a 中的内容。

寄存器大致分为以下几类:

  • 匿名寄存器 ""
  • 编号寄存器 "0"9
  • 小删除寄存器 "-
  • 26 个命名寄存器 "a"z
  • 3 个只读寄存器 ":, "., "%
  • Buffer 交替文件寄存器 "#
  • 表达式寄存器 "=
  • 选区和拖放寄存器 "*, "+, "~
  • 黑洞寄存器 "_
  • 搜索模式寄存器 "/

动作/操作符/文本对象

动作 值移动光标的操作,如熟悉 h、j、k 和 l,以及 w 和 b 等,/, ? 也是一个动作。他们都可以搭配数字使用,比如 2?the 可以将光标移动到倒数第二个 “the” 出现的位置。可以通过 :h navigation 来查看支持的动作。

操作符 是对某个区域文本执行的操作。如,d、~、gU 和 > 都是操作符。这些操作符既可以在普通模式下使用,也可以在可视模式下使用。在普通模式中,顺序是先按操作符,再按动作指令,比如 >j。在可视模式中,选中区域后直接按操作符即可,比如 Vjd。操作符也可以搭配数字使用,比如 2gUw 可以将当前单词以及下一个单词转成大写。由于动作和操作符都可以搭配数字使用,因此 2gU2w 与执行两次 gU2w 效果是相同的。有关操作符的详细帮助,可以通过 :h operator 来查看。

文本对象 是双向选择的文本(动作是单向选择的)。文本对象操作可以选中符号(比如括号、中括号和大括号等)标记的范围内文本,也作用于整个单词、整个句子等其他情况。文本对象不能用于普通模式中移动光标的操作,因为光标还没有智能到可以向两个方向同时跳转。但这个功能可以在可视模式中实现,因为在对象的一端选中的情况下,光标只需要跳转到另一端就可以了。可以通过 :h text-objects 来详细了解关于文本对象的内容

文本对象操作一般用 ia 加上对象标识符操作,其中 i 表示在对象内(英文 inner)操作,a 表示对整个对象(英文 around)操作,这时开头和结尾的空格都会被考虑进来。如,diw 可以删除当前单词,ca( 可以改变括号以及括号中的内容。

文本对象同样可以与数字搭配使用。比如,像 ((( ))) 这样的文本,假如光标位于最内层的括号上或最内层的括号内,那么 d2a( 将会删除从最内层开始的两对括号,以及他们之间的所有内容。其实,d2a( 这个操作等同于 2da(。需要注意的是,在 Vim 的命令中,如果有两处都可以接收数字作为参数,那么最终结果就等同于两个数字相乘。在这里,d 与 a( 都是可以接收参数的,一个参数是 1,另一个是 2,也可以把它们相乘然后放到最前面。

Vim 是一个可高度定制的编辑器,对编辑器的定制通过添加配置项和插件来完成,其读取配置文件的顺序可以通过:

:version

来查看,如以下为 MacOSX 上的结果:

  system vimrc file: "$VIM/vimrc"
    user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
     user exrc file: "$HOME/.exrc"
      defaults file: "$VIMRUNTIME/defaults.vim"
 fall-back for $VIM: "/usr/share/vim"

一些配置示例:https://github.com/kuanghy/vimconfig.

常用配置列举:

" 不要工作在 Vi 兼容的模式下
:set nocp

" 显示不可视字符
:set list

" 开启/取消粘贴模式
:set paste
:set nopaste

" 显示/隐藏行号
:set number
:set nu
:set nonumber
:set nonu

" 在搜索时忽略/不忽略大小写
:set ic
:set noic

:set fileencoding        " 查看文件编码
:set fileencoding=utf-8  " 转换文件编码

:set fileformat?         " 查看文件格式
:set fileformat=unix     " 设置文件格式

:set bomb?     " 查询 BOM
:set bomb      " 添加 BOM
:set nobomb    " 删除BOM

配置 Vim 支持系统剪切板,首先查看 Vim 本身是否支持:

vim --version | grep clipboard

输出的 clipboard 和 xterm_clipboard 前面为加号(+)表示支持,为减号(-)表示不支持。或者:

:echo has('clipboard')

输出 1 表示支持,输出 0 表示不支持。如果不支持可以尝试重新编译安装。支持系统剪切板后便可使用如下命令操作剪切板:

"+y 复制内容到系统剪切板
"+p 把系统剪切板里的内容粘贴到 vim

也可以配置 Vim 与系统剪切板共享复制粘贴(设置剪切板为匿名寄存器):

if has("clipboard")
    set clipboard=unnamed  " copy to the system clipboard
    if has("unnamedplus")  " X11 support
        set clipboard+=unnamedplus
    endif
endif

单位级

  • h 向左一字符
  • j 下一行
  • k 上一行
  • l 向右一字符

单词级

  • w or W 向右移动到下一单词开头
  • e or E 向右移动到单词结尾
  • b or B 向左移动到单词开头

注:所有小写单词都是以分词符作为单词界限,大写字母以空格作为界限。

块级

  • ( 移动到当前句子开头
  • ) 移动到下一句子开头
  • { 移动到当前段落开头
  • } 移动到下一段落开头
  • + 移动到下一行开头
  • - 移动到上一行开头
  • gg 到文档第一行
  • G 到文档最后一行
  • 0, | 到行首(第 1 列)
  • ^ 到第一个非空白字符
  • $ 到行尾
  • 0nl, n| 到当前行的第n 列
  • g_ 到当前行的最后一个非空格字符处
  • H 到屏幕的首行
  • L 到屏幕尾行
  • M 到屏幕中间
  • % 到匹配的括号(包括小括号、中括号、大括号)
  • zt 将当前行移到屏幕顶部
  • zz 将当前行移到屏幕中部
  • zb 将当前行移到屏幕底部
  • Ctrl-d 向下移动半页
  • Ctrl-u 向上移动半页
  • Ctrl-f 向下移动一页
  • Ctrl-b 向上移动一页
  • :<N> or <N>gg 跳转到第 N 行
  • :+<N> or <N>j 向下跳 N 行
  • :-<N> or <N>k 向上跳 N 行
注:| 表示 bar 的意思,是普通模式下用于跳转到当前行某一列的一个命令 (To screen column [count] in the current line),单个 表示当前行的第 0 列 (行首)。使用 0nl 跳转到指定列时,表示先用命令 0 将光标移动到行首,nl 表示执行 n 次向右移动光标操作;使用 n 时,表示使用 命令跳转到当前行的第 n 列。

插入

执行插入操作需进入 插入模式,以下操作均可实现插入操作:

i 在当前光标位置插入字符
I 在当前行首位置插入字符
o 在当前行往下插入新的一空行
O 在当前行往上插入新的一空行
a 在当前光标后追加字符
A 在当前行尾追加字符
r 替换当前字符
R 替换当前光标的字符直到退出插入模式(按ESC)
c 删除选中文本并进入插入模式
C 删除至行尾并进入插入模式
s 删除当前字符并进入插入模式
S 删除当前行并进入插入模式
:r filename 把文件的内容插入当前行的下一行
:r! command 把命令返回的结果插入到当前行的下一行

复制与粘贴

y (yanking)操作符用于复制文本,p 操作符用于粘贴文本,以下列举常用的复制操作:

yw 拷贝当前的一个单词
y0 拷贝的范围是当前光标处到行首
y^ 同上
y$ 拷贝的范围是当前光标处到行尾
yy 拷贝当前行
Y  同上
Nyy 从当前行开始拷贝 N 行
yf + 字符 复制从当前字符到指定字符
yG 拷贝当前行到文件尾
ygg 拷贝当前行到文件头
ggyG 复制整个文件
"+y 复制到系统剪切板
"+p 粘贴剪切板中的内容

Vim 还提供了基于底行命令模式的整行复制与移动命令:

:[range]co[py]{address}
:[range]t{address}

:[range]m[ove]{address}

命令 copy 可以简写成 :co 或者 :t,命令 move 可以简写成 m。示例:

:t5    拷贝当前行到第5行的下一行
:t.    拷贝当前行到光标下一行,相当于 `Yp` 或者 `yyp`
:t$    拷贝当前行到文件最后一行

:50,100move200    移动50行到100行的内容到第200行后面

删除/修改

x 操作符用于删除单个字符或选中的文本,d 操作符用于删除单词、行、选中的文本等:

x   删除当前光标处字符
X   删除光标所在前一个字符
dw  删除一个单词
de  删除到本单词末尾
dE  删除到本单词末尾包括标点在内
db  删除到前一个单词
dB  删除到前一个单词包括标点在内
d0  删除光标位置到本行开头
d$  删除从当前光标到行尾
D   同上
dd  删除一行
df + 字符  删除从当前字符到指定字符

# 删除括号或者引号中的内容
di(
di'
di"

# 包括括号或者引号一起删除
da(
da'
da"

c 操作符用于修改文本内容,即执行 c 操作时,会先删除选中的文本,然后再自动切换到插入模式:

cw         修改一个单词
c$         修改从当前字符到行尾
cc         修改整行
C          修改当前光标至行尾
cf + 字符   修改从当前字符到指定字符

# 修改括号或者引号中的内容
ci(
ci'
ci"

# 包括括号或者引号一起修改
ca(
ca'
ca"

撤销/重做/合并行

  • u 撤销
  • ctrl-r 重做

选中行,在执行 J 操作符可合并多行到一行,默认合并当前行与下一行。

在使用 Vim 的一些操作时,无非就两步,即先选择要操作的内容,在执行相应的操作。要操作的内容即是这里所说的 范围(Ranges)。可以使用 :h cmdline-ranges 来查看有关命令操作范围的有关信息。

  • 大多数命令都可以加一个数字,用于指明操作范围
  • 范围可以是一个行号,用于指定某一行
  • 范围也可以是一对通过 ,; 分割的行号
  • 大部分命令,默认只作用于当前行
  • :g[lobal] 默认会作用于所有行

范围的使用是十分直观的,以下是一些删除的例子(其中,:d:delete 的缩写):

命令 操作范围
:d 当前行
:.d 当前行
:1d 第一行
:$d 最后一行
:1,$d 所有行
:%d 所有行(这是 1,$ 的语法糖)
:.,5d 当前行至第 5 行
:,5d 当前行至第 5 行
:,+3d 当前行及接下来的 3 行
:1,+3d 第一行至当前行再加 3 行
:,-3d 当前行及向上的 3 行(Vim 会弹出提示信息,因为这是一个保留的范围)
:3,'xdelete 第三行至标注 为 x 的那一行
:/^foo/,$delete 当前行以下,以字符 “foo” 开头的那一行至结尾
:/^foo/+1,$delete 当前行以下,以字符 “foo” 开头的那一行的下一行至结尾

其中, . 表示当前行,$ 表示结束,% 表示所有行,-+ 分别表示前后的偏移量。

; 也可以用于表示范围。区别在于,a,b 的 b 是以当前行作为参考的。而 a;b 的 b 是以 a 行作为参考的。比如说,现在的光标在第 5 行。这时 :1,+1d 会删除第 1 行至第 6 行,而 :1;+1d 会删除第 1 行和第 2 行。

文档内查找

  • * 向后查找光标当前所在单词
  • # 向前查找光标当前所在单词
  • g* 向后查找光标当前所在单词的字符序列,如当前单词为 foo 时,foobar 也会被找到
  • g# 向前查找光标当前所在单词的字符序列
  • /<pattern> 向后查找指定字符串
  • ?<pattern> 向前查找指定字符串

在执行查找命令后,按 n 会继续查找下一个,N 会继续查找上一个。注意,n 和 N 是有方向性的,若之前通过 * 查找,则 n 会继续向文档尾方向查找,N 向文档首方向;反之,若你通过 # 查找,则 n 指向文档首,N 指向文档尾。

在使用 /? 查找时,加入 \c 表示大小写不敏感查找,\C 表示大小写敏感查找。

行内查找

  • f<X> 当前行内向行尾方向查找并定位到字符 X
  • t<X> 当前行内向行尾方向查找并定位到字符 X 之前
  • F<X> 当前行内向行首方向查找并定位到字符 X
  • T<X> 当前行内向行首方向查找并定位到字符 X 之后

在执行查找命令后,; 继续向当前方向查找下一个字符,, 向当前相反方向查找下一个字符。

括号匹配查找

可以使用 % 对 ( 和 ),[ 和 ],{ 和 } 进行匹配查找,当光标位于其中一个 符号 上时,按下 %,光标会跳到与之匹配的另外一个符号上。

元字符

. 匹配任意字符
[abc] 匹配方括号中的任意一个字符,可用-表示字符范围。如[a-z0-9]匹配小写字母和数字
[^abc] 匹配除方括号中字符之外的任意字符
\d 匹配阿拉伯数字,等同于[0-9]
\D 匹配阿拉伯数字之外的任意字符,等同于[^0-9]
\x 匹配十六进制数字,等同于[0-9A-Fa-f]
\X 匹配十六进制数字之外的任意字符,等同于[^0-9A-Fa-f]
\l 匹配[a-z]
\L 匹配[^a-z]
\u 匹配[A-Z]
\U 匹配[^A-Z]
\w 匹配单词字母,等同于[0-9A-Za-z_]
\W 匹配单词字母之外的任意字符,等同于[^0-9A-Za-z_]
\t 匹配<TAB>字符
\s 匹配空白字符,等同于[\t]
\S 匹配非空白字符,等同于[^\t]

表示数量的元字符

注意:下面除了 * 以外,其他都需要在前面加上 \

*    匹配 0-任意个
\+   匹配 1-任意个
\?   匹配 0-1 个
\{n,m}   匹配 n-m 个
\{n}     匹配 n 个
\{n,}    匹配 n-任意个
\{,m}    匹配 0-m 个

表示位置的元字符

$  匹配行尾
^  匹配行首
\<  匹配单词词首
\>  匹配单词词尾

需转义的字符

\*  匹配* 字符
\.  匹配. 字符
\/  匹配 / 字符
\\   匹配 \ 字符
\[  匹配 [ 字符
\]  匹配 ] 字符

在正则表达式中以 \(\) 括起来的内容表示一个分组,在正则表达式后面使用的时候可以用 \1\2 等变量(1、2 表示分组序号)来访问 \(\) 中的内容。如 \(foo\).*\1 可以配置 foo_bar_foo 等字符串。

需要同时查找多个字符串,可以使用 “或” 运算符,即 \|。如 /foo\|bar 会同时查找 foo 和 bar 两个字符;再如 /end\(if\|while\|for\) 匹配 “endif”,”endwhile” 和 “endfor” 字符串。

在 Vim 中默认使用的搜索模式被称为 magic 模式。在这种模式下,Vim 自动为某些额外的符号赋予特殊含义,例如 .*[ 等。这种模式的初衷是想能在 Vim 中更容易地构造简单的正则表达式,但它却没能为诸如 +?(){ 等符号赋予特殊含义,这些符号还必须经过转义才具有特殊含义。

Vim 还提供了 very magic 搜索模式 用于查找字符串,在这种模式下统一了所有特殊符号的规则:除下划线 _、大小写字母以及数字 0 到 9 之外的所有字符都具有特殊含义。该模式使用 \v 开启,如:/\vend(if|while|for),这样,用于为特殊字符进行转义的反斜杠字符便可以去掉,使得匹配表达式的可读性更强。如该种模式下,便可以用 <> 符号表示单词定界符,而无需转义。

此外,还有 very nomagic 搜索模式,在该模式中有且只有反斜杠 \ 具有特殊意义,即消除了附加在 .* 以及 ? 等大多数字符上的特殊含义。也就是绝大多数字符都按原义进行查找匹配,该模式使用 \V 开启。如要查找 a.k.a. 字符串时,如果不使用 very nomagic 模式搜索,则其他的字符串也可能被找到,如 backward,除非使用转义 /a\.k\.a\.。而使用 very nomagic 模式就要简单得多 /\Va.k.a.。 `

Vim 中的简单替换可以使用 r/Rc/Cs/S 等操作符:

r  替换当前字符
R  替换当前光标的字符直到退出替换模式(按ESC)
cw  替换当前单词
cc  替换当前行,相当于 S
C   替换当前位置到行尾,相当于 c$

此外,还可以使用 :s (substitute)操作,配置范围、模式查找等实现更加强大的替换功能,其格式为:

[range]s/{pattern}/{string}/[flags]

flags 有如下四个选项

  • c confirm,每次替换前询问
  • e error,不显示错误
  • g globle,不询问,整行替换。如果不加 g 选项,则只替换每行的第一个匹配到的字符串
  • i ignore,忽略大小写

可以同时使用多个 flag,如 cgi 表示不区分大小写,整行替换,替换前询问。示例:

:1,10s/from/to/g  表示在第1到第10行(包含第1,第10行)之间搜索替换
:10s/from/to/g  表示只在第10行搜索替换
:%s/from/to/g  表示在所有行中搜索替换
:1,$s/from/to/g  同上

:%s/\s+$//g  删除行尾空格
:%s/^\s*// 或 :%s/^ *//  删除行首多余空格
:%s/^$// 或 :g/^$/d  删除沒有內容的空行
:%s/^\s*$// 或 :g/^\s*$/d  删除包含有空格组成的空行
:%s/^[ |\t]*$// 或 :g/^[ |\t]*$/d  删除以空格或 tab 开头到结尾的空行

标记 可以理解为 书签,在某处打上标记后,可以快速从别处跳转回来。标记可以分为三类:

  • a-z 用户设置,仅对当前的一个文件生效,也就意味着只可以在当前文件中跳转
  • A-Z 用户设置,全局标记,可以作用于不同文件。大写标注也称为「文件标注」。跳转时有可能会切换到另一个缓冲区
  • 0-9 由 viminfo 记录,0 代表 viminfo 最后一次被写入的位置。实际使用中,就代表 Vim 进程最后一次结束的位置。1 代表 Vim 进程倒数第二次结束的位置,以此类推

定义一个标记用 m 操作符,如 ma 标记当前问题为 a 标记。在标记间跳转用 ' / g' 或者 ` / g` 加上标注名。单引号与倒引号的区别在与,单引号会跳转回被标记行的第一个非空字符,而倒引号会跳转回被标记行的被标记列。

还有一些其他的跳转方式:

'[ 与 `[    上一次修改或复制的第一行或第一个字符
'] 与 `]    上一次修改或复制的最后一行或最后一个字符
'< 与 `<    上一次在可视模式下选取的第一行或第一个字符
'> 与 `>    上一次在可视模式下选取的最后一行或最后一个字符
'' 与 `'    上一次跳转之前的光标位置
'" 与 `"    上一次关闭当前缓冲区时的光标位置
'^ 与 `^    上一次插入字符后的光标位置
'. 与 `.    上一次修改文本后的光标位置
'( 与 `(    当前句子的开头
') 与 `)    当前句子的结尾
'{ 与 `{    当前段落的开头
'} 与 `}    当前段落的结尾

标记也可以搭配 范围 一起使用。如果在可视模式下选取一些文本,然后按下 :,这时命令行会被填充为 :'<,'>,这即表示在可视模式下选取的范围。

使用 :marks 可以查看当前所有的标记,使用 :h mark-motions 更多关于标记的帮助信息。

寄存器主要用于存储文本内容,其为复制粘贴功能提供辅助。寄存器的访问和操作使用冒号 " 作为前缀,如 "ayy 表示复制当前行到 a 寄存器,"ap 表示粘贴寄存器中的内容。使用 :reg 可以查看当前所有寄存器中的内容,使用 :reg "{register_name} 可以查看指定寄存器的内容。

匿名寄存器(Unnamed): 保存最近一次的复制或删除操作 (d, c, s, x, y)。如果当前使用的 vim 版本支持剪切板,则可以将匿名寄存器定向到剪切板上,这样便可以与系统共享剪切板:

set clipboard=unnamed

编号寄存器(Numbered): 即以数字命令的寄存器,从 "0"9 共 10 个。其中 "0 保存着最近一次复制的内容,"1"9 保存着删除掉的字符串。 删除操作符包括 s, c, d, x。 删除掉的字符串会被存到 “1 中,上次删除的则会被存到 “2 中,以此类推。

小删除寄存器(Small delete): 保存最近一次行内删除的内容,如 dw 删除一个词,d9l 删除 9 个字符,cb 向前更改一个词等。

命名寄存器(Named): 其有 "a"z 共 26 个,这类寄存器只有在被指定时才会被定义和使用。其实在录制宏时,所有键盘操作会以字符串的形式存到寄存器中。需注意的是,寄存器名也可以为大写,当使用小写字母进行操作时会覆盖当前寄存器内容,而当使用大写字母进行操作时会追加当前寄存器内容。如 "Ayy 会复制当前行并追加到寄存器 a 中。

只读寄存器(Read-only): 共有 3 个只读寄存器,其值是由 Vim 提供,不允许改变:

  • ".:最近一次 insert 模式中插入的文本。注意 . 命令用于重复上次操作,而 ". 用于存储上次插入
  • "%:当前文件名,不是全路径,也不是纯文件名,而是从当前 Vim 的工作目录到该文件的路径,即相对路径
  • "::最近一次底行命令模式下使用的命令。正如 @a 可以执行 "a 寄存器中的宏一样,@: 可以执行上次命令

交替文件寄存器(Alternate buffer): 交替文件寄存器 "# 存储着当前 Vim 窗口(Window)的交替文件。交替文件是指 Buffer 中的上一个文件,可通过 Ctrl+^ 来切换交替文件与当前文件。

表达式寄存器(Expression): 表达式寄存器 "= 主要用于计算 Vim 脚本的返回值,并插入到文本中。当键入 "= 后光标会移动到命令行,此时可以输入任何 Vim 脚本的表达式,例如 3+2,按下回车并且 p 则会得到 5。这对于调试 Vim 脚本是非常有用的,比如调用一个函数看它是否有正确的返回值。

选择(Selection)和拖放(Drop)寄存器: 包括 "*, "+, 和 "~,这三个寄存器的行为是和 GUI 相关的。

"*"+ 在 Mac 和 Windows 中,都是指系统剪切板(clipboard),例如 "*yy 即可复制当前行到剪切板。 以供其他程序中粘贴。其他程序中复制的内容也会被存储到这两个寄存器中。 在X11系统中(绝大多数带有桌面环境的Linux发行版),二者是有区别的:

  • "* 指 X11 中的 PRIMARY 选区,即鼠标选中区域。在桌面系统中可按鼠标中键粘贴。
  • "+ 指 X11 中的 CLIPBOARD 选区,即系统剪切板。在桌面系统中可按 Ctrl+V 粘贴。

拖放寄存器 "~ 是只读的,当有文本拖拽到 Vim 时,被拖拽的文本被存储在 "~ 中。Vim 默认的行为是将 "~ 中内容插入到光标所在位置。

黑洞寄存器(Black hole): 所有删除或拷贝到黑洞寄存器 "_ 的文本将会消失,这是为了在删除文本的同时不影响任何寄存器的值,其通常用于 Vim 脚本中。

搜索寄存器(Last search pattern): 搜索寄存器 "/ 用于存储上一次搜索的关键词,即最近一次通过 /?:global 等命令调用的匹配条件。该寄存器是可写的,例如: let @/ = "harttle" 将会把 “harttle” 写入该寄存器。下次搜索时不输入搜索词直接回车便会搜索 “harttle”。

在 Vim 中可以录制一系列按键动作,并把他们存储到寄存器中,这便是 。宏是一系列操作的集合,它可以将一些复杂的操作进行记录,之后可以进行回放。

操作符 q 用于开启或结束宏录制,按 q{register} 开始进入录制,然后再按 q 可结束录制。如果要对宏进行回放,按 @{register}

示例一,在行末加分号,命令为:

qa
$a;<Esc>j$,
q

命令的含义是:开启宏录制,并记录到寄存器 a 中,先移动到行尾,然后在行尾插入分号,接着退到普通模式,再把光标移动到下一行的末尾,最后结束宏录制。录制结束后,输入 @a 便会执行宏中的操作,5@m 表示重复执行 5 次宏操作。

示例二,从 1 到 100,每行 +1,首先在第一行插入 1,然后光标定位到第一行的 “1” 上,执行宏录制:

qb
yyp<Ctrl>a
q

命令的含义是:开始录制宏到寄存器 b 中,yy 复制当前行,p 粘贴到下一下, <Ctrl>a 让当前光标所在数字加 1。然后执行 98@b 将宏回访 98 遍即可实现将数字加到 100。

插入计算结果

在插入模式下,输入 ctrl-r =,然后输入表达式,就能在光标处得到计算结果。

保存无权限的只读文件

如果打开了一些没有权限编辑的只读文件,并修改了内容,且希望对修改进行保存时,可以用如下命令(前提是当前用户有 sudo 权限):

:w !sudo tee %

高亮普通文件

有的文件可能没有后缀(扩展名),Vim 无法识别文件类型,所以也无法进行语法高亮,此时可以手动设置文件的类型,以开启语法高亮。如设置文件类型为 shell 脚本类型:

:set filetype=sh

编辑远程文件

Vim 内置的插件 netrw 支持对远程文件的编辑。它的原理是将远程的文件通过 scp 复制到本地的临时文件中,再用这个文件打开一个缓冲区,然后在保存时再将文件复制回远程位置。以下命令列举在本地打开 SSH 远程服务器上文件的方式:

:e scp://user@remotehost/.vimrc

:e scp://user@remotehost/~/.vimrc

:e scp://user@remotehost//etc/passwd

也可以配置 ~/.ssh/config 文件,使得命令更加简单,如 ~/.ssh/config 存在如下配置:

Host test
    HostName test.site.com
    Port 23456
    User test

那么编辑文件的命令就可以变得很简单:

:e scp://test/.vimrc

查看安装的所有脚本

:scriptnames

有用的快捷键

K    打开光标所在词的 manpage
.    重复上一次的操作,如 dd 删除一行后,. 命令可继续执行删除

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK