%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea - 普通模式 - 光标移动(motion,movement commands) - 编辑命令(editing commands) - (`c` 、`d`、`y` 都需要 motion 作为参数) - `7dw` 与 `d7w` 都是同样有效的 - `.` 重复执行前一个编辑命令 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-27B2160693988455C09C2FA19C66FE21.png|787]] `C-v{cold}`:使用字符编码插入字符(插入模式下)(vim 接受 3 位数字,超过 3 位数的需要通过 4 位 16 进制`u{code}`来输入) `t{char}`:直到某个字符(不包括该字符),till。 - `yt{char}`, `dt{char}`, `ct{char}`。 **字符信息显示**: `<C-g>`:显示当前光标位置的行号列号 `ga`:显示当前光标位置的字符编码,包括十进制和十六进制形式。 以波纹线 (~) 开头的行表示该行在文件中不存在。换句话说,如果 Vim 打开的文件不能充满这个显示的屏幕,它就会显示以波纹线开头的行。 `<C-a>` `<C-x>`:将当前光标 单字符操作汇总 - `r` + 字符:替换字符 - `x`:删除字符 ## 候选资料 > Read it later 用 f{char} 跳到当前行的某个字符上,然后用 `;` 和 `,` 命令相应地正向或反向重复此跳转 %% # Vim 帮助手册 ![image-20231108203647359](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-8C9A946E60FC5DAD4B3DBFC2568C4235.png) > [!NOTE] 注: `:help w` 与 `:help :w` 不同,前者是普通模式下的`w` 按键,后者是命令行模式中的 `w` 命令 <br><br><br> # Vim "七种基本模式" 与 "七种附加模式" Vim 有七种基本模式: - **普通模式 Normal Mode / Command Mode** - vim 启动后的默认模式。可输入所有**普通编辑命令**,例如光标移动、删除、复制和粘贴、查找等。 - **插入模式 Insert Mode** - 该模式下可直接编辑文本。 - 从普通模式切换到插入模式可以用这些命令: "i"、"I"、"a"、"A"、"o"、"O"、"c" "C"、"s" 或 "S"。 - **命令行模式 Command-Line Mode** - 普通模式下按 `:` 进入。 - **可视模式 Visual Mode** - 该模式用于**选择文本块**,以便对其执行操作(类似于按住鼠标左键进行框选) - 普通模式按 `v` 进入可视模式,然后通过移动光标选择文本。 - **选择模式 Select Mode** - 不常用。和可视模式类似,不同在于: - 选择模式下,只能通过方向键移动光标,**输入任何文本都会替换掉选定的文本**,并**使 Vim 回到插入模式**。 - 可视模式中,使用编辑命令(如复制、删除)不会退出模式。 - **Ex 模式 Ex Mode** - 普通模式下按 `Q` 进入。执行完命令后会继续停留在该模式。 - 类似于命令行模式,但支持输入更多命令。 七种附加模式: - **替换模式 Replace Mode** - 普通模式下按 `R` 进入替换模式。替换模式是插入模式的特殊情况,输入的字符将直接替换原字符。 - **插入普通模式 Insert Normal Mode** - 插入模式下按 `<C-o>` 进入,允许**运行一个普通模式命令后**返回插入模式,回到原来的位置**继续输入**。 - **命令符待决模式** Operator-pending Mode - 在输入一个操作符命令时(如 `d`, `y` 等)后**等待指定作用范围** <br><br><br> # Vim 的文本编辑理念 ⭐ Vim 中定义了以下概念: - **文本对象**(Text Object) - **文本对象修饰符**(Text Object Modifiers) - **动作**(Motion) 即**光标移动** - **操作符**(operator) Vim 中的 "**==普通模式==**" 下基于这些 "概念" 的**组合**,可实现对 "**==特定范围文本==**" 的操作。 <br> ## 文本对象 Text object > 参见[^1](P117) Vim 中的 "**文本对象**" 概念指代**一个特定的 "文本范围"**。 文本对象用于同 "**文本对象修饰符**" & "**操作符**" 结合使用,从而实现**操作特定范围的文本**。 | 文本对象标识 | 文本对象 | 说明 | | ------ | --------- | ---------------------------------- | | w | word | | | W | WORD | | | s | sentence | 以句号、问号或感叹号结束,后跟一个或多个空格或换行符 | | p | paragraph | 一个段落(以空行或行首的某些字符分隔的文本块) | | ( 或 b | 括号内的内容 | | | { 或 B | 大括号内的内容 | | | `[` | 方括号内的内容 | | | < | 尖括号内的内容 | | | t | 标签内的内容 | 示例:`<a>op the content of here</a>` | | " | 双引号内的内容 | | | ' | 单引号内的内容 | | | \` | 反引号内的内容 | | | | | | > [!info] 空白字符包括:`<SPACE>`、`<TAB>`、`<EOL>`(End of line) > [!tip] 可视模式下支持通过 `修饰符 & 文本对象` 来选中特定范围 ^594ccf <br> ### word 与 WORD ![image-20231111165724357|503](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-A4C29860A9CEEF5112735DA01751D120.png) - 「**word**」:由**空白字符**分隔的,下列**字符序列**之一: - 由连续的"**==字母==、==数字==、 ==下划线==**" 构成的字符序列 - 由其它 "**==连续非空白字符==** " 构成的字符序列 - **空行视为一个 word** - 「**WORD**」:由**空白字符**分隔的 **任何==非空字符序列==** 都视为一个 WORD - **空行视为一个 Word** > [!example] 示例:`foo_32-:.:,Jd342` > > 该字符串中: > - 共有三个 word:`"foo_32"`,`"-:.:,"`, "`"Jd342"`" > - 共有一个 WORD:`"foo_32-:.:,Jd342"` ,即整个字符串本身 <br> ## 文本对象修饰符 Modifiers 文本对象修饰符用于 "**定义文本对象范围**",用于与**操作符**结合使用,实现**对特定范围文本的操作**。 常用的文本对象修饰符包括: - `a`:around,表示**一个文本对象==周围==——包含其==前方或后方的空白字符 or 空行==**。 - `i`:inner/inside,表示**一个文本对象==内部==——仅其本身,不包括其前方或后方的空白字符 or 空行**。 > [!caution] `a` 只会包含 "**前方或者后方==其中一侧==的任意空白字符 or 空行**" <br> ## 光标移动 Motion Vim 中,将 "**==光标移动==**" 命令称之为 "motion",也称 "movement"。 `CTRL+G`:显示**当前光标所在位置 #### motion 移动 操作格式:`[number] motion`,可**搭配操作符 `operator` 实现范围操作**。 | 按键 | 光标移动说明 | | --------------------------- | ------------------------------------------------------------- | | `h`, `j`, `k`, `l` \| 方向键 | 左、下、上、右 | | `0` \| `Home` | 移动到**当前行首** | | `
\| `End` | 移动到**当前行尾** | | `^` | 移动到**当前行的第一个非空白字符** | | `g_` | 移动到**当前行的最后一个非空白字符** | | | | | `gj`、`gk` | **屏幕行**的 "下" 与 "上" | | `g0`、`g
、`g^` | 移动到**当前 "屏幕行" 的行首、行尾、行内第一个非空白字符** | | | | | `b` | 移至**当前 word 首**(若已在头部则移至前一个单词头部; move backward one words) | | `e` | 移至**当前 word 尾**(若已在尾部则移至下一个单词尾部; forwards to the end of word) | | `w` | 移至**下一个 word 首**(move forward one word) | | `ge` | 移至**上一个 word 尾**(backwards to the end of word) | | | | | `gg` | 移至**第一行**的**首个非空白字符** | | `G` | 移至**最后一行**的**首个非空白字符** | | | | | `<N>G` \| `:<N>` | 移动到**指定行**首 | | `H`、`M`、`L` | 移动到**当前屏幕的顶行、中间行、尾行** | #### 其他光标移动(不属于 motion) | 按键 | 光标移动说明 | | ----------------------- | -------------------------------------------- | | `Ctrl-U` | 向上滚动**半屏** | | `Ctrl-D` | 向下滚动**半屏** | | `Ctrl-F` \| `PageDown` | **向后翻页**(滚动一屏) | | `Ctrl-B` \| `PageUp` | **向前翻页**(滚动一屏) | | | | | `Ctrl-I` | 跳转到后一个 "**跳转**" 位置 | | `Ctrl-O` \| `` \`\` `` | 回退到前一个 "**跳转**" 位置 | | | | | `gi` | 返回 "**上次插入位置**"(上次退出插入模式时光标所在位置),并**进入插入模式** | | `g,` | 正向遍历 "**修改**" 列表 | | `g;` | 反向遍历 "**修改**" 列表 | ###### 跳转至位置标记 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-E75868CA515B531163202F83FEB1AEEF.png|386]] #### 注意事项 > [!NOTE] 屏幕行与逻辑行——`j`, `k` 与 `gj`, `gk` > > 当在 Vim 中启用了 `wrap` 设置时,超出窗口宽度的文本行将会**自动折行显示**。 > > - **逻辑行**:**以 `\n` 结尾的实际一行内容** > - **屏幕行**:**在屏幕上实际显示的各个行**,也称 "**物理行**"。 > > `j` 与 `k` 移动的单位是 "**逻辑行**",而 **==`gj` 与 `gk`== 移动的单位是 "==屏幕行=="** [^1] (P105)。 > > ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-CDBD26EC5B2433301568344A2D6381A8.png|432]] > [!NOTE] `w`、`b`、`e`、`ge` 以 word 为单位进行移动 > > ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-240D6AA43622EBDF32D8167F3D21D48C.png|311]] > > [!NOTE] `B`、`E`、`W`、`gE` 对应为以 `WORD` 为单位的移动 > [!NOTE] 部分 motion 不支持重复,例如 `0`、`^`、`gg`、`G` > [!info] 关于 "跳转" [^1](P126) > > `:jumps` 可查看跳转列表,`<C-i>` 与 `<C-o>` 用以在此列表中记录的 "**跳转项**" 之间进退。 > > "**任何改变当前窗口中活动文件的命令**"(例如打开不同文件) 都属于 "**跳转命令**",此外还包括一下行为: > > ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-1C0BCCEB8D85A6AB522E1FB5F01C9C96.png|477]] > > 常规的 motion 移动并不属于 "跳转",因此不能通过 `<C-i>` 或 `<C-o>` 进退。 ^esfo0a <br><br> ## 操作符 Operator > 参见[^1](P51) ![image-20231110161810464|487](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-6542305A0E604F5B5C1C1795E62A3F7F.png) 常用的 **Vim 操作符**如上表,这些操作符均**需要搭配** "**光标移动** motion",从而实现 "**范围操作**", 命令格式:`operator [n] motion` 或 `[n] operator motion`,其中 `[n]` 表示操作**重复次数**。 > [!NOTE] 当一个操作符被**连续调用两次**时,将**作用于==当前行==**。 > > - 例如 `dd`、`cc`、`yy`、`>>`、`<<`。 > - 由两个按键构成的操作符例如 `g~`,`gu`,`gU`,其重复模式支持两种形式: > - 重复为`gUgU` > - **视`g` 为前缀按键**,仅重复后一按键:`g~~`,`guu`, `gUU` > > 当需要重复这些**作用于整行**的命令时,可加上**前缀数字**,例如 `[n]dd`,`[n]cc`,`[n]>>`。 > > ^zp8ffv <br><br> ## 范围操作使用说明 🌠 上述几个概念在 "**普通模式**" 下搭配使用的方式有多种: - **操作符 & 光标移动**: `operator motion` - **操作符 \* 2**(表示**作用于整行**) - **操作符 & 修饰符 & 文本对象** : `operator modifier text-obj` ### (1)操作符 & 光标移动使用示例 命令格式: `[N] operator motion` 或 `operator [N] motion`,其中 `[N]` 表示操作**重复次数**。 下标**以 `d` 为例**,其他操作符 **`c`,`y`, `>` 等格式类同**。 | 示例 | 说明 | | ----------------------- | ----------------------------------------------- | | `dl` | 删除光标位置的字符,等价于 `x` | | `d0` | 删除从光标位置 "**之前** "至**行首**的所有内容 | | `d[N]
\| `D` | 删除从光标位置到**行尾**的所有内容 | | | | | `dgg`,`dG` | 删除从光标位置到**文件首行、文件尾行**的所有内容 | | | | | `d[N]j`,`d[N]k` | 删除**当前行**及**下一行**(或**上一行**)的内容 | | | | | `d[N]w`、`d[N]e`、`d[N]b` | 删除**从光标位置至下一个 word 头、当前 word 尾部、当前 word 头部**的内容 | | | | | `d%` | 删除**括号及括号内的内容**(等价于 `da(`, `da{`, `da[` ) | > [!NOTE] 部分 motion 不支持重复,例如 `0`、`^`、`gg`、`G` > [!caution] 向前删除时,不包括光标起始位置 > > ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-681C032FC16EFAAB9DC6C89600EC90A8.png|562]] ### (2)操作符 "作用于整行" 使用示例 ![[05-工具/vim/vim 使用#^zp8ffv]] ### (3)操作符 & 修饰符 & 文本对象使用示例 命令格式:`operator modifier text-object` - 对 word: - `daw` , `yaw` , `caw` , `vaw`:删除,复制,更改,选中**光标处的单词及==前或后==方的空白字符** - `diw` , `yiw` , `ciw` , `viw`:删除,复制,更改,选中**光标处的单词** - 对 paragraph: - `dap` , `yap` , `cap` , `vap`: 删除,复制,更改,选中**整个段落及其==前或后==方的空白行** - `dip` , `yip` , `cip` , `vip`: 删除,复制,更改,选中**整个段落** - 对 **==括号==** 及其内容(其他 **括号** 格式类同): - `da(` , `ai(` , `ca(` , `va(`:删除,复制,更改,选中 **==括号及其中内容==** - `di(` , `yi(` , `ci(` , `vi(`:删除,复制,更改,选中 **括号内内容** - 对 **==引号==** 及其内容(其他**引号**的格式类同) - `da"` , `ai"` , `ca"` , `va"`:删除,复制,更改,选中 **==双引号及其中内容==** - `di"` , `yi"` , `ci"` , `vi"`:删除,复制,更改,选中 **双引号内内容** <br><br><br> # Vim 的缓冲区概念 Vim 支持**同时打开多个文件**,通过维护**一组缓冲区列表**实现,**每个缓冲区对应==一个打开的文件==**。 缓冲区相关命令参见[[#缓冲区处理相关]] > [!NOTE] 什么是缓冲区? > > 通过 Vim 打开一个文件时,**文件内容被从磁盘上读入内存**,其**在内存中的映像**即称之为 "**缓冲区**"。 > Vim 中**编辑的实际上是 =="缓冲区" 的内容==**,执行 `:w` 命令后才会**将缓冲区内容写回磁盘上文件进行覆盖**。 #### 缓冲区列表标识说明 `:ls` 命令可**查看当前的缓冲区列表**。 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-769765DE8272D8DDA6A56C930AC3D343.png|459]] - `%`:标识**当前窗口对应的缓冲区** - `#`:标识可通过 `Ctrl-^` 快速轮换的缓冲区 - `+`:标识该**缓冲区内容已发生过修改** - `a`:标识 "**当前活动缓冲区**"(active) - `h`:标识 "**当前隐藏缓冲区**" <br><br> # Vim 交换文件 当通过 Vim 打开一个文件进行编辑时,**Vim 默认会在文件所在目录创建一个交换文件**。 每次**对缓冲区内容进行修改时,交换文件都会更新**,以确保在崩溃时能够恢复尽可能多的内容。 使用 "**交换文件**" 的目的: - **崩溃恢复**:如果 Vim 或系统崩溃,交换文件可以**帮助恢复未保存的修改**。 - **防止多次编辑冲突**:如果在另一个 Vim 实例中打开同一个文件,交换文件会**警告文件已经在编辑中**。 若当前目录下存在**某个文件的 "`.swap`交换文件"**,则**用 Vim 打开该文件**时将显示以下信息: ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-27B2160693988455C09C2FA19C66FE21-3.png|642]] > [!NOTE] 可通过 `:set noswapfile` 禁用交换文件 <br><br><br> # Vim 状态栏说明 ![[05-工具/vim/vim 配置#^zut8et]] <br><br><br> # Vim 标签页 & 窗口管理 Vim 中的 **"标签页" 是对 "窗口" 的分组管理**,Vim 支持**打开多个标签页**,**每个标签页下可容纳多个窗口**。 - Tab 标签页 - Window 窗口 > [!NOTE] 标签页、窗口与 "**缓冲区**" 不是一一对应的关系: > > - 一个 "缓冲区" 可能**仅在后台打开**,未对应**任何标签页或窗口**; > - **多个 "窗口"** (同一标签页或不同标签页下)可以关联到 "**同一个缓冲区**" <br> ## 标签页管理 ##### 新建标签页 Tab ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-306C1DF70557FC759164E65F079C4351.png|480]] - `:tabe[edit]` 同 `:tabnew` ##### 标签页间切换 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-72CB8BF0D933FD33BB161439B65809C1.png|559]] ##### 重排标签页 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-1CE570D414E0D68AF704BB3B1494E81B.png|547]] ##### 设置标签页中窗口的当前工作目录 - `:windo lcd <path>`: 为**当前标签页中所有窗口**设置该工作目录 <br> ## 窗口管理 ##### 其他命令 - `:lcd <path>`: **设置当前窗口的本地工作目录** ##### 新建/拆分窗口(Split Windows) ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-0B86B2A836A8073553CA43267F3F37E6.png|534]] ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-A19E0907757C1AF1A7BD9D92C9B63491.png|414]] > [!NOTE] Vim 启动时指定多文件窗口布局 > > - `vim -o {file1} {file2} {file3}` 以水平拆分的方式打开多个文件 > - `vim -O {file1} {file2} {file3}` 以垂直拆分的方式打开多个文件 ##### 关闭窗口 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-BE8E1DD9E5BC720262A638D3946AF592.png|522]] - `:q`:关闭**当前窗口** - `:qa`:退出**所有窗口** ##### 窗口间切换 ![image-20231109092708883|537](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-93F684BB243CF74A9EBE44565FABE115.png) | 快捷键 | 说明 | | -------------------- | -------------------------------------- | | `<Ctrl-W>-[n]w` | 在窗口之间循环切换,**正向移动**(从上到下,从左到右,从最低到最高层级) | | `<Ctrl-W>-[n]W` | 在窗口之间循环切换,**反向移动** | | `<Ctrl-W>-<j,k,l,r>` | 移动到**上、下、左、右方**的窗口 | | `<Ctrl-W>-p` | 返回**上一个访问**的窗口 | | `<Ctrl-W>-t` | 移动到**左上角**的窗口 | | `<Ctrl-W>-b` | 移动到**右下角**的窗口 | ##### 改变窗口大小 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-C4C602BE4C276F5FA9D1F5A72B5F504A.png|538]] <br> # Vim 运行参数 - `vim [OPTION] <filename>...` - `-R`:**只读模式**打开(等同于 `view <filename>`) - `-o` 以**水平拆分**的方式打开多个文件 - `-O` 以**垂直拆分**的方式打开多个文件 <br><br><br> # 普通模式下的行为 ## 屏幕滚动 光标不动,**除非将溢出屏幕时,将移动到屏幕边界** | 按键 | 说明 | | ------- | ---------------- | | `zz` | 将当前行显示在**屏幕正中间** | | `zt` | 将当前行显示在**屏幕顶部** | | `zb` | 将当前行显示在**屏幕底部** | | `<C-e>` | 屏幕内容向上滚动 | | `<C-y>` | 屏幕内容向下滚动 | ## 光标移动 参见[[#光标移动 Motion]] ## 进入可视模式 三种可视模式: ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-DF48AB64AD71074B9E0332EC351BA6A2.png|249]] | 按键 | 说明 | | ------------------ | ----------------------------------------------------------------------- | | `v` | 进入 **"常规可视模式"**(regular visual mode)——选中 **"当前光标位置"与"起始位置"之间的内容** | | `V` | 进入 "**行可视模式**"(visual line mode)——选中 **"当前光标位置"与"起始位置"之间的所有==整行==内容** | | `<C-v>` \| `<C-q>` | 进入 "**块可视模式**"(visual block mode)——选中 **"当前光标位置"与"起始位置"之间的==矩形框区域==内容** | - `gv`:重选**上次的高亮选区** ## 进入插入模式 > 按键后,将**移动光标位置**并进入 "**插入模式**" | 按键 | 说明 | | --- | -------------- | | `i` | 在光标位置插入 | | `a` | 在光标**之后**插入 | | `I` | 在当前**行首**插入 | | `A` | 在当前**行尾**插入 | | `o` | 在当前行**下方**插入新行 | | `O` | 在当前行**上方**插入新行 | > [!NOTE] `[N]i{input some text}<Esc>` 会将从 "**进入插入模式**" 到 "**退出插入模式**" 过程中的修改**重复 N 次**。 > > 示例:`10+i+Hello World<Enter>+<Esc>` 将插入 10 行 Hello world > > ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-47BB2A384D0D60F9D713BEEAE5465B7B.png|672]] > ## 进入替换模式 - `R` :进入**替换模式**,随后**每次输入都将替换掉光标位置的字符**(替换模式下可通过方向键移动光标) ## 重复上次修改 - `.`:重复上次**修改**——vim 会记录两种 "**==修改==**": - 重复上一次 "**编辑命令**" 带来的 **==修改==** - 重复上一次 "**进入插入模式**" 到 "**退出插入模式**" 过程中带来的 **==修改==** > [!caution] `.` 是 "重复上次修改",而不是 "上次命令"! > [!NOTE] 关于 "修改" > > 一次 "修改" 是 "**改变文档内文本的任意操作**",包括: > - **在普通模式、可视模式、命令行模式中所触发的命令**, > - 以及"**插入模式下所完成的修改**"(`i{insert some text}<ESC>`) ## 编辑相关操作 ### 撤销与重做 - `u`: 撤销 undo - `[N]u`: 重做 N 步。 - `U`:撤销**整行内**发生的**所有修改** - `CTRL + R`:重做 redo ### 复制 | | 说明 | | ----------- | -------------------------- | | `y` | 复制**当前选中的内容**(到特定 Vim 寄存器) | | `yy` \| `Y` | 复制**整行** | 其余与 motion 的结合使用参见[[#范围操作使用说明 🌠]] ### 粘贴 - `[N]p`:粘贴到光标位置**之后** - `[N]P`:粘贴到光标位置**之前** > [!NOTE] 若缓冲区内的内容是"整行"(例如执行了 `yy` 或 `dd` 后),则会将**整行内容**粘贴到**当前行**的**上一行/下一行**) ### 更改 > "更改":下列操作将首先 "**删除**" 内容,而后自动进入 "**插入模式**" | | 说明 | | ------------ | ---------------------- | | `s` \| `cl` | 更改**光标位置**处字符 | | `S` \| `cc` | 更改**整行** | | | | | `cw` \| `ce` | 更改光标位置**至`word`尾部**的内容 | | `C` \| `c
| 更改光标位置**至行尾**的内容 | 其余与 motion 的结合使用参见[[#范围操作使用说明 🌠]] ### 替换字符 - `r<char>` :替换**光标位置**处字符为 `char` ### 删除 - `x`:删除光标位置的字符 - `[n]x` 删除包含光标位置在内的 n 个字符 - `X`:删除光标位置**之前**的字符 - `d`:删除**当前选中区域内容**,常与 motion 结合使用 ###### 插入模式下的删除快捷键 ![image-20231110162828877|362](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-511F4501971023DD2E4AB0BE2E55AACB.png) ### 缩进 - `>`:增加当前行的缩减层级 - `<`:减少当前行的缩进层级 - `=`:自动缩进 - `gg=G`:**自动缩进全文** 与 motion 的结合使用参见[[#范围操作使用说明 🌠]],示例: - `>G` 增加**从当前行到文件末尾行**的缩进层级 - `<4j` | `4<<`:缩进下面 4 行 ### 改变大小写 - `~`:切换**当前光标位置处字符**大小写 - `g~`:切换 "**当前选中区域**" 的大小写 - `gu`:将 "**当前选中区域**" 全小写 - `gU`:将 "**当前选中区域**" 全大写 `g~`, `gu`, `gU` 与 motion 的结合使用参见[[#范围操作使用说明 🌠]] ### 数字加减 - `[N]<Ctrl-A>`:**将当前光标处(或光标后的首个数字处)==增加==整数值 N** - `[N]<Ctrl-X>`:**将当前光标处(或光标后的首个数字处)==减少==整数值 N** ### 连接行 - `[n]J`:连接多行,去除行之间的缩进和换行符等,两行间会插入空格。 ## 搜索查找 ![image-20231110152040462|537](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-CB1F64866F380A00EA8EDF3898EC14D6.png) ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-BF45BBEA3153AFEC7A76F57BC4AA9FEE.png|401]] #### 行内字符搜索 - `f<char>`:跳转至**当前行内光标位置后的==下==一字符 `char` 的位置** - `F<char>`:跳转至**当前行内光标位置前的==上==一字符 `char` 的位置** - `t<char>`:跳转至**当前行内光标位置后的==下==一字符 `char` 的左侧** - `T<char>`:跳转至**当前行内光标位置前的==上==一字符 `char` 的位置** - `;`:**重复**最近执行的 `f`, `t`, `F` 或 `T` 命令 - `,`:**反向重复**最近执行的 `f`, `t`, `F` 或 `T` 命令 > [!NOTE] `f<char>` 搭配 `;` 与 `,` 可实现在行内 "==同一字符==" 间跳转 #### 括号间匹配 - `%` :**匹配括号间跳转** - 若光标位置为括号,则**跳转至其==相匹配的括号==位置处**; - 否则,**跳转至==光标位置之后的括号==处**(如果存在) #### word 搜索 - **`*`** : **搜索**光标位置附近的 `word` 并跳转至该 `word` 的**下一个匹配位置** - `#` : **搜索**光标位置附近的 `word` 并跳转至该 `word` 的**上一个匹配位置** > [!NOTE] `*` 与 `#` 按以下顺序进行搜索匹配 > > 1. **光标处**由 **数字、小写字母、`@`** 组成的字符系列 > 2. 光标之后的**首个** "**数字** | **小写字母** | `@`" > 3. **光标处**的**非空 `word`** > 4. 光标之后的**非空 `word`** #### 匹配内容搜索 - `/<expr>` : **向后查找内容** `expr` - `/<expr>\c` :`\c`, 单次查找时忽略大小写 - `//`: 重复上一次查找 - `?<expr>` : **向前查找内容 `expr`** - `??` : 重复上一次查找 - `n`:重复**前一次 `/?*#` 查找**,**跳转至下一个匹配位置** - `N`:反向重复**前一次 `/?*#` 查找**,**跳转至下一个匹配位置** > [!NOTE] > - 如果**前一次查找是 `/*`(向后)**,则 `n` 就是继续**向后跳**至下一位置,而 `N` 则是**向前跳**至下一个匹配位置 > - 如果**前一次查找是 `?#`(向前)**,则 `n` 就是继续**向前跳**至下一位置,而 `N` 则是**向后跳**至下一个匹配位置。 <br><br><br> # 插入模式下的行为 #### 插入模式下的快捷键 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-ED0C79D0073E3A4F2EAF39529EF0E143.png|360]] - 整行缩进:`<C-t>` 增加,`<C-d>` 减少 - 删除:`Ctrl-W`、`Ctrl-U` (**同 bash shell 快捷键**) - `<C-p>`: 触发**关键字自动补全**,将在根据输入内容在**当前缓冲区、已打开的缓冲区以及标签列表中查找匹配的单词**,并显示一个补全选项列表。 - `<C-p>` 键可循环选项 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-2860FD0385939C3827AA6897E2D61399.png|722]] #### 插入模式与普通模式的转换 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-FFAA043F4748B2A669DE40D69D91B3EB.png|326]] - `Ctrl-O`:进入"**==插入-普通模式==**",可执行一条 "**普通模式下的命令**" 后**回到插入模式** - 示例:`<Ctrl-O>zz` <br><br><br> # 可视模式下的行为 ### 通用 ##### 特有命令 - `o`:切换选区的 **==活动端==** ![[05-工具/vim/vim 使用#^594ccf]] ##### 操作符命令 可视模式下支持所有 "普通模式下的**操作符命令**",区别在于这些**按键命令**将作用于 "**当前选中区域**": | 操作符 | 说明 | | --------- | ------------------ | | `c` | **删除选中内容并进入插入模式** | | `d` & `x` | **删除选中内容** | | `r{char}` | **替换选中内容为指定字符** | | `y` | **复制选中内容** | | `>` | **缩进选中行** | | `.` | 重复上次修改 | | ...... | | ##### 可视模式切换 可视模式切换:`v`、`V`、`Ctrl-V` 可**在三种可视模式间切换** > [!caution] 在可视模式下,选中**多行后键入`c` 进入插入模式**,**对多行选中内容的修改只会=="显示"在顶行==**,而**在退出插入模式后才应用于所有行**。 ### 块可视模式下的行为 块可视模式用以操作 "**列**" 中文本——**对==一列中的各行==分别应用操作** | 操作 | 说明 | | --- | ------------------------- | | `I` | **在选中块的每行头部插入内容** | | `A` | **在选中块的每行末尾插入内容** | | `c` | **更改选中块的每一行内容(独立应用于各个行)** | | `d` | **删除选中块的每一行内容(独立应用于各个行)** | ### 可视模式编辑示例 - `Vr-`:选中**当前整行**并替换为 `-` - `V4jr|`:选中**当前列(4 行)** 并替换为 `|` --- <br><br><br> # 命令行模式下的行为 普通模式下键入 `:` 后即进入**命令行模式**。 命令行模式中执行的命令称为 "**==Ex 命令==**"。 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-76F69FBA30F71175A9E09ED3E63335FE.png|475]] - `:undolist` 查看可用的 undo 列表。 ## 展开 - `%<Tab>`:展开为 "**当前活动缓冲区对应文件的绝对路径**" - `%:h<Tab>`:展开为 "**当前文件所在目录的路径**" ## 退出 - `:q`:退出(关闭**当前窗口**) - `:q!`:强制退出(**不保存任何更改**) ## 命令行模式下的快捷键 - `Ctrl-W`:删除至前一个单词 - `Ctrl-U`:删除至行首 ## 命令补全 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-31B19536C42D427CD648859CA78B81DD.png|451]] - `CTRL+D` :键入前缀后,显示命令列表 - `<TAB>` :补全命令 ## 当前工作目录相关 - `:pwd`:查看当前工作目录 - `:lcd <path>`: **设置当前窗口的本地工作目录** - `:windo lcd <path>`: 为**当前标签页中所有窗口**设置该工作目录 ## 文件 & 缓冲区相关 ### 打开文件 - `:e[dit] <filename>` :打开文件 - `:e!`:打开文件(使用**磁盘上文件内容**覆盖**当前缓冲区中内容**,意味着 "**丢弃所有修改**") ### 保存文件 - `:w[rite] [filename]`:**保存缓冲区内容**(**将缓冲区内容写入到磁盘上,覆盖文件内容**) - `:wa`:**保存所有缓冲区中的内容** - `:wq`:保存并退出 (同 `:x` 或 `ZZ`) > [!NOTE] 保存选中内容为文件 > > 按 `v` 进入可视模式,选中内容后再通过 `:w filename` 将选中内容保存到文件 ### 读取文件内容并插入到当前缓冲区 - `:r <filename>`:读取 **文件系统上指定文件内容**,插入到**当前光标位置处** - `:r !<command>`:读取 **外部命令的输出**,插入到当**前光标位置处** ### 缓冲区处理相关 | 命令或快捷键 | 说明 | | ----------------------------- | ----------------- | | `:ls` | 查看**缓冲区列表** | | `:bprev`,`:bnext` | 在缓冲区列表中**前后移动** | | `:bfirst`,`:blast` | 切换至**缓冲区列表首尾** | | `:buffer N` | 切换至**编号为 N 的缓冲区** | | `Ctrl-^` | 轮换**缓冲区** | | `:bdelete N...` 或 `:bd N...` | **删除缓冲区** | ##### 缓冲区列表标识 参见[[#缓冲区列表标识说明]] ##### 隐藏缓存区的处理 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-B27ECF8A9C7F1772EABF4D92DDF5F324.png|441]] ## 缓冲区文本处理 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-4603375BBD5C2C8B5088A98B10D96C49.png|628]] ## 查看修改列表 `:changes` ## 查看跳转列表 `:jumps` ![[05-工具/vim/vim 使用#^esfo0a]] ## 查看寄存器内容 - `:reg 寄存器引用`,例如 `:reg "0` ## 检查更改 - `:diffthis` ## 匹配内容替换 替换命令的格式: `:[range]s/{pattern}/{string}/[flags]` ![image-20231108230734050|466](_attachment/05-工具/vim/vim%20使用.assets/IMG-vim%20使用-7DF5771B0BA83EF36D7A57C11FF71D5C.png) 用法说明:将内容 `old` 替换为 `new` | | 说明 | | ----------------- | ---------------------------------------------- | | `:s/old/new` | 替换当前行的**首项匹配** | | `:s/old/new/g` | 替换当前行的**全部匹配** | | `:#,#s/old/new/g` | 替换 `#` 与 `#` 两行之间出现的所有匹配串 (`#` 是行号) | | | | | `:%s/old/new/g` | 替换**整个文件**内的**所有匹配** | | ` :%s/old/new/gc` | 替换**整个文件**内的**所有匹配**,每次替换之前进行询问确认(`c`:confirm) | | | | ## 匹配内容删除 `:g/pattern/d`:将匹配 `pattern` 的行全部删去 ## 执行外部命令 `:!<command>` :执行外部命令 `command`(命令执行完成后,将返回到 vim 中) ## 设置编辑器选项 设置选项: - `:set ic` 忽略大小写(ignore Case) 查找短语时显示部分匹配 - `:set hls ls` hlsearch 高亮匹配结果、incsearch - `:set number` 显示行号(在每一行之前显示) 选项前加上 `no` 表示**关闭选项**: - `:set noic` 禁用忽略大小写 - `:set nohlsearch` 禁用匹配结果高亮 - `:set nonumber` 不显示行号 <br><br><br> # 寄存器 Vim 中提供了**一组寄存器**(几十个)用以**支持特定操作**,例如 `d`、`y`、`p` 命令。 ## 寄存器说明 | 寄存器 | 引用方式 | 说明 | | --------------------- | ------------------- | -------------------------------------------------------------------------------------------------------- | | **无名寄存器** | `""` | 默认寄存器,unname。<br>`x`,`s`,`d`,`c`,`y` 系列命令(及其大写命令)都会**默认覆盖该寄存器中内容** | | **复制专用寄存器** | `"0` | 仅 **`y` 系列命令会覆盖该寄存器内容** | | | | | | **有名寄存器**<br>(共 26 个) | `"a-"z` 或 `"A`-`"Z` | 供**明确引用**使用<br>- 通过 "小写字母" 引用时,会**==覆盖==寄存器原有内容** <br>- 通过 "大写字母" 引用时,会**将新内容==追加==到寄存器原有内容末尾** <br><br> | | | | | | **表达式寄存器** | `"=` | | | **黑洞寄存器** | `"_` | 特殊寄存器,**引用该寄存器**时的含义是 "**真正地删除**",即**不存入任何寄存器**中 | | | | | | **系统剪贴板** | `"+` | 引用该寄存器表示使用 "**系统剪贴板**",例如 `"+p` 表示粘贴系统剪贴板中内容,`"+y` 表示复制到系统剪贴板 | | **选择专用寄存器** | `"*` | 引用该寄存器表示使用 "**X11 窗口系统的主剪贴板**"——其中**保存着==上一次被高亮选中的文本==** | | | | | #### 只读寄存器 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-BC724C5ED1B0AA131BE2E7767C1F1AAE.png|285]] > [!NOTE] `y` 系列命令会同时将**复制的文本**写入 "**无名寄存器`""`**"、"**复制专用寄存器`"0`**" 中 > [!NOTE] Vim 中的剪切(cut)、复制(copy)、粘贴(paste) > > Vim 中通过 `d`,`y`,`p` 命令来提供上述功能,**对应含义为:delete,yank,put**。 > > 实际上,`d` 和 `y` 命令分别是将内容 "**==剪切==**" 、"复制" 到**默认的无名寄存器**中,**==`d` 并未实现真正的删除==**。 > 如果要**实现真的删除**,应当使用 `"_d`,即引用 "**黑洞寄存器**"。 > [!info] 关于 "系统剪贴板" 与 "主剪贴板" > > 除 "**系统剪贴板**" 外,X11 窗口系统中**独立支持**另一种称为 "**==主剪贴板==**" 的剪贴板, > 其中**保存着==上一次被高亮选中的文本==**,可通过 "**鼠标中键或右键**" 进行粘贴。 > > 关于 Linux 中不同剪贴板的说明参见 [[02-开发笔记/11-Linux/Linux 相关#Linux 中的剪贴板|Linux 相关]] > > [!caution] Windows 和 Mac OS X 操作系统中没有 "**==主剪贴板==**" 的概念,因此 `"+` 与 `"*` 都表示 "系统剪贴板" <br> ## 寄存器引用 `x`,`s`,`d`,`c`,`y` 系列命令**默认**使用 "**无名寄存器**",可由以下方式**指定所使用的寄存器**: - 在**普通模式或可视模式下**,可通过为命令加上 **==`"{register}` 前缀==** 指定所用寄存器——例如 `"0p`。 - 在**插入模式**下,通过**按键 `<C-r>{register}`** **插入该寄存器中的内容**——例如 `<C-r>0` 或 ## 查看寄存器内容 - 查看寄存器内容:`:reg "<register>`,例如 `:reg "0` <br><br><br> # 参考资料 #### Vim 使用说明 - [VIM 中文用户手册: 目录](https://yianwillis.github.io/vimcdoc/doc/usr_toc.html) - [Vim: help.txt](https://vimhelp.org/) ⭐ - [Vim Tips Wiki | Fandom](https://vim.fandom.com/wiki/Vim_Tips_Wiki) (Vim 奇技淫巧) #### Vim 按键说明 - [Vim cheatsheet](https://quickref.me/vim#google_vignette) **速查表** - [Quickref - Neovim docs](https://neovim.io/doc/user/quickref.html) **详尽的按键说明(cheatsheet 速查表)** ⭐⭐⭐ - [Index - Neovim docs](https://neovim.io/doc/user/vimindex.html) **完整的按键、命令索引** ⭐(若在上面 Quickref 链接中未找到,则可以在其中寻找) - [Vim/ROADMAP.md at master · VSCodeVim/Vim · GitHub](https://github.com/VSCodeVim/Vim/blob/master/ROADMAP.md) ⭐(说明了 Vim 中常用的 **Motion 等按键效果**) - ![[_attachment/05-工具/vim/Neovim 说明.assets/IMG-Neovim 说明-A8A694CA9EC48485CA515F988BB78C95.png|551]] ##### 图例 ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-9403B3D4F1BE7E12401604F219344633.png|851]] ![[_attachment/05-工具/vim/vim 使用.assets/IMG-vim 使用-C18E29E14A4EBB8F600B7E3E929701A4.png|848]] # Footnotes [^1]: 《Practical Vim》 [^2]: Vim Tutor