Bedic 全文索引

搜索公开内容

知识库WIKI

初识vim

更新
阅读
11 分钟
分类
软件工具

初识vim

一、Vim是什么

Vim是一个强大的模态文本编辑器,入门门槛较高,但是一旦掌握,编辑效率非常高。

Vim与普通编辑器最大的区别在于它有多种模式,同一个按键在不同模式下含义完全不同,理解这一点是入门的关键,也是很多人刚上手时觉得很麻烦的一点


1.1 Normal模式(普通模式)

打开Vim后默认进入的模式。这个模式下,键盘上的字母不是用来输入文字的,而是用来执行命令的。比如按d是删除(delete),按y是复制(yank),按p是粘贴(paste)。这是Vim里待得最久的模式,浏览代码、跳转、删除、复制都在这里完成。

从其他任何模式回到Normal模式:按Esc键,这是Vim里按的最频繁的键,很多大佬会把Caps Lock键映射成Esc以提升效率。

为什么在 vi 的世界, 拷贝都使用 yank 这个词, 而不是 copy? - 知乎


1.2 Insert模式(插入模式)

这是真正用来输入文字的模式。从Normal模式进入Insert模式有多种方式,后面详细讲解


1.3 Visual模式(可视模式)

用来选中文本块。选中后可以执行删除、复制、缩进等操作。Vim有三种Visual子模式:字符选中v、行选中V、块选中Ctrl+v


1.4 Command-line模式(命令行模式)

在Normal模式下按:进入,可以执行保存、推出、搜索替换等命令。


二、为什么要用Vim

在VS Code、JetBrains系列如日中天的今天,为什么还要花时间学一个并不简单的30年的老编辑器呢?

  1. 编辑效率的提升:
    • 现代编辑器有漂亮的界面、智能补全、鼠标点选等功能,可以大幅提升我们的编辑体验和效率,但它们都有一个共同的瓶颈——编辑文本时手需要频繁的在键盘和鼠标之间切换,容易打断思路。
    • Vim的哲学时:手永远不离开键盘主区。移动光标、选中文本、删除、复制、格式化等所有操作都可以使用键盘完成,而且绝大多数键都在手指自然放置的位置(如果不是也可以自己调hhh),可以完全脱离鼠标。
    • 例:删除一个函数中的所有内容,使用别的编辑器需要先用鼠标选中函数体,再按删除键;而在vim例,光标在函数体内任意位置,di{三个键就完成了。在函数内容很少时其实效率差别不大,但是一旦函数内容变多,几十行几百行,使用鼠标选中时还要拖动,还要找起始和结束位置,这时效率的差别就体现出来了。
  2. 操作的可组合型:
    • Vim的编辑命令不是零散的快捷键,而是一套小语言。操作符、动作、计数词可以自由组合,最开始学习时会觉得很痛苦,但是随着学的越多,能力增长不是线性的,而是呈指数级的爆炸式增长。
  3. 无处不在:
    • Vim几乎存在于所有Unix-like系统上,当远程一台服务器时,它不一定有vscode或其它现代化编辑器,但是一定有vim,这样就不会在没有vscode的时候束手无策

三、Vim怎么用

3.1 打开与退出

3.1.1 打开文件

# 打开文件(如果不存在则新建)
vim filename

# 打开多个文件
vim file1 file2

# 以只读模式打开
vim -R filename

# 打开文件并跳转到第10行
vim +10 filename

# 打开文件并跳转到第一个匹配pattern的位置
vim +/pattern file

3.1.2 退出vim

Normal模式下:

  • 退出(未修改文件时)::q
  • 强制退出,不保存修改::w!
  • 保存并退出::wq, :x, ZZ, ZQ都可以
  • 强制保存并退出::wq!

3.1.3 保存文件

Normal模式下:

  • 保存::w
  • 另存为::w filename
  • 保存所有打开的文件::wa

3.2 移动光标

Normal模式下,Vim提供了极其丰富的移动方式。最基础的是:

h    向左移动一个字符
j    向下移动一行
k    向上移动一行
l    向右移动一格字符

Here is why vim uses hjkl keys as arrow keys

3.2.1 按词移动

w    移动到下一个词的开头
b    移动到上一个词的开头(如果光标在词中间则移动到当前词开头)
e    移动到当前词的末尾(如果已经在当前词的末尾则移动到下一个词末尾)
W    以空格为分隔移动到下一个“大词”的开头(跳过标点)
B    以空格为分隔移动到上一个“大词”的开头(跳过标点)

wW的区别:w把标点符号也当作词的分隔,W只把空格当作分隔。比如在hello-word中,按w会停在-上,按W会直接跳到下一个空格后的词。

3.2.2 行内移动

0    移动到行首
^    移动到本行第一个非空白字符
$    移动到行尾
g_   移动到本行最后一个非空白字符

3.2.3 按屏幕移动

H    移动到屏幕顶部(High)
M    移动到屏幕中间(Middle)
L    移动到屏幕底部(Low)
Ctrl+u    向上翻半页(Up)
Ctrl+d    向下翻半页(Down)
Ctrl+b    向上翻一页(Back)
Ctrl+f    向下翻一页(Forward)
zz    将当前行置于屏幕中央(Center?)
zt    将当前行置于屏幕顶部(top)
zb    将当前行置于屏幕底部(bottom)

3.2.4 按段落和代码块移动

{    移动到上一个空行(段落开头)
}    移动到下一个空行(段落开头)
[[   移动到上一个函数/代码块开头(在代码文件中)
]]   移动到下一个函数/代码块开头
%    在匹配的括号、引号之间跳转

3.2.5 文件内跳转

gg    移动到文件第一行
G     移动到文件最后一行
10G   移动到第10行
:10   移动到第10行

3.2.6 精确搜索跳转

f{char}        在当前行正向查找字符{char}并跳转(Find)
F{char}        在当前行反向查找字符{char}并跳转
t{char}        在当前行正向查找字符{char}并跳转到其前一个字符(Till)
T{char}        在当前行反向查找字符{char}并跳转到其后一个字符
;              重复上一次f/t/F/T查找
,              反向重复上一次f/t/F/T查找

ft的区别:f(光标停在(上,t(光标停在(前一个字符上。

3.3 进入Insert模式

从Normal模式进入Insert模式有多种昂是,每种适用于不同场景:

i    在光标前插入(insert)
I    在本行第一个非空白字符前插入
a    在光标后插入(append)
A    在本行末尾插入
o    在下方另起一行插入(open)
O    在上方另起一行插入
s    删除光标所在字符并进入插入模式(substitute)
S    删除当前行并进入插入模式
cc   删除当前行并进入插入模式
C    删除当前光标到行尾并进入插入模式

一个常见的场景:光标在行中间的某个位置,你想在行尾添加内容。与其用l一步步移动到行尾再按i插入,不如直接按A一步到位,提升效率。


3.4 编辑操作

Vim的编辑操作可以理解为一种“语法”:操作符+动作/范围。理解这个组合逻辑后,Vim的编辑能力会豁然开朗。

3.4.1 核心操作符

d    删除(delete)  - 实际上时剪切,删除的内容会存到寄存器
c    修改(change)  - 删除后自动进入Insert模式
y    复制(yank)
p    粘贴到光标后(paste)
P    粘贴到光标前
x    删除光标所在字符(等价于d1和delete键)
X    删除光标前一个字符(等价于dh)
r    替换光标所在字符(replace),单个字符替换,不进入Insert模式
R    进入替换模式,连续替换多个字符
u    撤销(undo)
Ctrl+r    重做(redo)
.    重复上一次修改操作(Vim最强大的命令之一)

3.4.2 操作符+动作组合

这是Vim的精华所在,将一个操作符和一个移动命令组合,就能精确地操作任意范围的文本:

dw    删除一个词(delete word)
d2w   删除两个词
d$    删除到行尾(同D)
d0    删除到行首
d^    删除到本行第一个非空白字符
de    删除到当前词末尾
dgg   删除到文件开头
dG    删除到文件末尾
dd    删除整行
2dd   删除两行
ciw   删除当前光标所在词并进入插入模式(change inner word)
ci"   删除双引号内的内容并进入插入模式(change inner ")
ci(   删除括号内的内容并进入插入模式(change inner ())
ci{   删除花括号内的内容并进入插入模式
da"   删除双引号及其内部内容(delete a ")
diw   删除当前词(不进入插入模式, delete inner word)
yiw   复制当前词
yy    复制整行
3yy   复制三行
y$    复制到行尾
yG    复制到文件末尾
5p    粘贴5次

3.4.3 text-object

上面出现的iw(inner word)i(inner quotes)a(a quotes)是Vim的文本对象概念,是Vim最搞笑的特性之一。

i(inner)表示内部,不包含边界字符;a(a/an)表示一个完整的,包含边界字符和前后空格。

常用文本对象:

iw   一个词(inner word)
aw   一个词加后面的空格(a word)
iW   一个大词(以空格分隔)
aW   一个大词加后面的空格
i"   双引号内部
a"   双引号及其内部
i'   单引号内部
a'   单引号及其内部
i(   圆括号内部 — 等同于 i)
ib   圆括号内部(inner block)
i[   方括号内部
i{   花括号内部 — 等同于 iB
a(   圆括号及其本身
a[   方括号及其本身
a{   花括号及其本身
it   HTML/XML 标签内部(inner tag)
at   HTML/XML 标签及其内部(a tag)
ip   一个段落(inner paragraph)
ap   一个段落加后面的空行
is   一个句子(inner sentence)
as   一个句子加后面的空格

实用场景举例:光标在 "hello world" 中任意位置,按 ci" 会删除引号内的所有内容,光标定位在引号之间,等待你输入新内容。按 da" 则连引号带内容一起删除。


3.5 搜索与替换

3.5.1 文件内搜索

/pattern    正向搜索pattern
?pattern    反向搜索pattern
n           跳转到下一个匹配
N           跳转到上一个匹配
*           搜索光标所在的词(正向)
#           搜索光标所在的词(反向)

搜索时可以使用正则表达式。搜索后匹配项会高亮,用:noh关闭高亮,或用:set hlsearch/:set nohlsearch控制

3.5.2 替换

:s/old/new        替换当前行第一个old
:s/old/new/g      替换当前行所有old
:%s/old/new/g     替换全文所有old
:%s/old/new/gc    替换全文所有old,但每次确认
:10,20s/old/new/g 替换第10行到第20行的所有old
:%s/old/new/gi    替换全文所有old,忽略大小写

替换中的分隔符不一定是/,可以用任何字符,这在处理路径时非常方便:

:%s#/usr/local/bin#/opt/bin#g

3.6 多文件、多窗口与标签页

3.6.1 缓冲区(Buffer)

Vim中打开的每个文件对应一个缓冲区:

:ls       列出所有缓冲区
:bnext    切换到下一个缓冲区
:bprevious切换到上一个缓冲区
:b number 切换到编号为number的缓冲区
:bd       删除当前缓冲区(关闭文件)
:bd!      强制删除缓冲区,不保存

3.6.2 窗口(Window)

:split filename        水平分割窗口打开文件(:sp)
:vsplit filename       垂直分割窗口打开文件(:vp)
Ctrl+w h               切换到左边窗口
Ctrl+w j               切换到下面窗口
Ctrl+w k               切换到上面窗口
Ctrl+w l               切换到右边窗口
Ctrl+w w               在所有窗口间循环切换
Ctrl+w q               关闭当前窗口
Ctrl+w =               让所有窗口等宽等高
Ctrl+w _               最大化当前窗口高度
Ctrl+w |               最大化当前窗口宽度
:only                  关闭其他所有窗口(:on)

3.6.3 标签页(Tab)

:tabnew filename       在新标签页打开文件
:tabclose              关闭当前标签页
:tabnext               下一个标签页(:tabn)
:tabprevious           上一个标签页(:tabp)
gt                     切换到下一个标签页
gT                     切换到上一个标签页

3.7 寄存器与宏

3.7.1 寄存器

Vim有多达26个命名寄存器(a-z),加上系统剪贴板(+*)、无名寄存器(")、数字寄存器(0-9)等。当yankdelete时,内容默认存入无名寄存器"

"ayy        复制当前行到寄存器a
"ap         粘贴寄存器a的内容
"+y         复制到系统剪贴板
"+p         从系统剪贴板粘贴
:reg        查看所有寄存器内容

3.7.2 宏(Macro)

宏时Vim最强大的功能之一,可以录制一系列操作并重复执行:

qa        开始录制宏到寄存器a(可以用任何字母)
...       执行一系列曹祖
q         停止录制
@a        执行寄存器a中的宏
10@a      执行宏10次
@@        重复上一次执行的宏

典型场景:有100行数据,每行需要做同样的格式化操作。在第一行录制宏qa,执行操作,q停止,然后99@a对剩余99行执行同样的操作

宏可以用搜索定位(/pattern),这样即使每行内容不同,也能精确找到操作位置

3.8 常用配置(~/.vimrc)

Vim的行为可以通过配置文件大幅定制。以下是一些常用的基础配置及其含义:

" 基础设置
set nocompatible          " 关闭 vi 兼容模式
set number                " 显示行号
set relativenumber        " 显示相对行号(配合 j/k 跳转极其好用)
set cursorline            " 高亮当前行
set showcmd               " 在右下角显示未完成的命令
set showmode              " 在左下角显示当前模式
set wildmenu              " 命令行补全增强

" 缩进
set autoindent            " 自动缩进
set smartindent           " 智能缩进
set tabstop=4             " Tab 显示宽度
set shiftwidth=4          " 缩进宽度
set expandtab             " 将 Tab 转换为空格
set softtabstop=4         " 按 Backspace 时一次删除 4 个空格

" 搜索
set hlsearch              " 搜索高亮
set incsearch             " 增量搜索(边输入边搜索)
set ignorecase            " 搜索忽略大小写
set smartcase             " 搜索中有大写字母时区分大小写

" 编码
set encoding=utf-8
set fileencodings=utf-8,gbk,gb2312,cp936

" 其他
set mouse=a               " 启用鼠标支持
set clipboard=unnamed     " 使用系统剪贴板
set history=1000          " 保留更多历史记录
set undofile              " 持久化撤销(关闭文件后仍可撤销)
set swapfile              " 启用交换文件防止崩溃丢失数据
set backup                " 自动备份