25 KiB
vim-galore 中文翻译
Vim from zero to hero - Vim 从入门到精通
- 原文地址:https://github.com/mhinz/vim-galore
- 原文作者:Marco Hinz
- 本文地址:https://github.com/wsdjeg/vim-galore-zh_cn
简介
基础
- 缓冲区,窗口,标签
- 当前缓冲区,加载缓冲区,缓冲区列表,命名缓冲区
- 参数列表
- 按键映射
- 快捷键前缀
- 寄存器
- 范围
- 标注
- 补全
- 动作,操作符,文本对象
- 自动命令
- 变更历史,跳转历史
- 内容变更历史记录
- 全局位置信息表,局部位置信息表
- 宏
- 颜色主题
- 折叠
- 会话
- 局部化
用法
- 获取离线帮助
- 获取离线帮助(备选)
- 获取在线帮助
- 执行自动命令
- 剪贴板
- 打开文件时恢复光标位置
- 备份文件,交换文件,撤销文件以及 viminfo 文件的处理
- 编辑远程文件
- 插件管理
- 片段插入
- 使用外部程序和过滤器
- MatchIt
技巧
- 聪明的使用 n 和 N
- 聪明的使用命令行历史
- 智能 Ctrl-l
- 禁用错误报警声音和图标
- 快速移动当前行
- 快速添加空行
- 快速编辑自定义宏
- 快速跳转到源(头)文件
- 在 GUI 中快速改变字体大小
- 根据模式改变光标类型
- 防止水平滑动的时候失去选择
- 重新载入保存文件
- 智能当前行
- 更快的关键字补全
命令
- :global - 在所有匹配行执行命令
- :normal and :execute - 脚本梦之队
- :redir - 重定向消息
调试
杂项
怪癖
主题列表
插件列表
Neovim
简介
什么是 Vim?
Vim 是一个历史悠久的文本编辑器,可以追溯到 qed。Bram Moolenaar 于 1991 年发布初始版本。
该项目托管在 vim.org。
获取 Vim:用包管理器安装或者直接到 vim.org 下载。
讨论使用相关问题最好使用 vim_use 邮件列表或者使用 IRC(Freenode) 的 #vim
频道。
项目在 Github 上开发,项目讨论请订阅 vim_dev 邮件列表。
通过阅读 Why, oh WHY, do those #?@! nutheads use vi? 来对 Vim 进行大致的了解。
Vim 哲学
Vim 采用模式编辑的理念,即它提供了多种模式,按键在不同的模式下作用不同。你可以在 普通模式 下浏览文件,在 插入模式 下插入文本,在 可视模式 下选择行,在 命令模式 下执行命令等等。起初这听起来可能很复杂,但是这有一个很大的优点:不需要通过同时按住多个键来完成操作,大多数时候你只需要依次按下这些按键即可。越常用的操作,所需要的按键数量越少。
和模式编辑紧密相连的概念是“操作符”和“动作”。_操作符_开始一些行为,例如:修改,删除,或者选择文本。之后你要用一个_动作_来指定需要操作的文本区域。比如,要改变括号内的文本,需要执行 ci(
(读做 change inner parentheses);删除整个段落的内容,需要执行 dap
(读做:delete
around paragraph)。
如果你能看见 Vim 老司机操作,你会发现他们使用 Vim 脚本语言就如同钢琴师弹钢琴一样。复杂的操作只需要几个按键就能完成。他们甚至不用刻意去想,因为这已经成为肌肉记忆了。这减少认识负荷并帮助人们专注于实际任务。
入门
Vim 自带一个交互式的教程,内含你需要了解的最基础的信息,你可以通过终端运行以下命令打开教程:
$ vimtutor
不要因为这个看上去很无聊而跳过,按照此教程多练习。你以前用的 IDE 或者其他编辑器很少是有“模式”概念的,因此一开始你会很难适应模式切换。但是你 Vim 使用的越多,肌肉记忆 将越容易形成。
Vim 基于一个 vi 克隆,叫做 Stevie,支持两种运行模式:"compatible" 和 "nocompatible"。在兼容模式下运行 Vim 意味着使用 vi 的默认设置,而不是 Vim 的默认设置。除非你新建一个用户的 vimrc
或者使用 vim -N
命令启动 Vim,否则就是在兼容模式下运行 Vim!请大家不要在兼容模式下运行 Vim。
下一步
- 创建你自己的 vimrc。
- 在第一周准备备忘录。
- 通读基础章节了解 Vim 还有哪些功能。
- 按需学习!Vim 是学不完的。如果你遇到了问题,先上网寻找解决方案,你的问题可能已经被解决了。Vim 拥有大量的参考文档,知道如何利用这些参考文档很有必要:获取离线帮助。
- 浏览附加资源。
最后一个建议:使用插件之前,请先掌握 Vim 的基本操作。很多插件都只是对 Vim 自带功能的封装。
精简的 vimrc
用户的 vimrc 配置文件可以放在 ~/.vimrc
,或者为了更好的分离放在 ~/.vim/vimrc
,后者更便于通过版本控制软件备份和同步整个配置,比方说 Github。
你可以在网上找到许多精简的 vimrc 配置文件,我的版本可能并不是最简单的版本,但是我的版本提供了一套我认为良好的,非常适合入门的设置。
最终你需要阅读完那些设置,然后自行决定需要使用哪些。:-)
精简的 vimrc 地址:minimal-vimrc
如果你有兴趣,这里是我(原作者)的 vimrc。
建议:大多数插件作者都维护不止一个插件并且将他们的 vimrc 放在 Github 上展示(通常放在叫做 "vim-config" 或者 "dotfiles" 的仓库中),所以当你发现你喜欢的插件时,去插件维护者的 Github 主页看看有没有这样的仓库。
我正在使用什么样的 Vim
使用 :version
命令将向你展示当前正在运行的 Vim 的所有相关信息,包括它是如何编译的。
第一行告诉你这个二进制文件的编译时间和版本号,比如:7.4。接下来的一行呈现 Included patches: 1-1051
,这是补丁版本包。因此你 Vim 确切的版本号是 7.4.1051。
另一行显示着一些像 Tiny version without GUI
或者 Huge version with GUI
的信息。很显然这些信息告诉你当前的 Vim 是否支持 GUI,例如:从终端中运行 gvim
或者从终端模拟器中的 Vim 内运行 :gui
命令。另一个重要的信息是 Tiny
和 Huge
。Vim 的特性集区分被叫做 tiny
,small
,normal
,big
and huge
,所有的都实现不同的功能子集。
:version
主要的输出内容是特性列表。+clipboard
意味这剪贴板功能被编译支持了,-clipboard
意味着剪贴板特性没有被编译支持。
一些功能特性需要编译支持才能正常工作。例如:为了让 :prof
工作,你需要使用 huge
模式编译的 Vim,因为那种模式启用了 +profile
特性。
如果你的输出情况并不是那样,并且你是从包管理器安装 Vim 的,确保你安装了 vim-x
,vim-x11
,vim-gtk
,vim-gnome
这些包或者相似的,因为这些包通常都是 huge
模式编译的。
你也可以运行下面这段代码来测试 Vim 版本以及功能支持:
" Do something if running at least Vim 7.4.42 with +profile enabled.
if (v:version > 704 || v:version == 704 && has('patch42')) && has('profile')
" do stuff
endif
相关帮助:
:h :version
:h feature-list
:h +feature-list
备忘录
为了避免版权问题,我只贴出链接:
- http://people.csail.mit.edu/vgod/vim/vim-cheat-sheet-en.png
- https://cdn.shopify.com/s/files/1/0165/4168/files/preview.png
- http://www.nathael.org/Data/vi-vim-cheat-sheet.svg
- http://michael.peopleofhonoronly.com/vim/vim_cheat_sheet_for_programmers_screen.png
- http://www.rosipov.com/images/posts/vim-movement-commands-cheatsheet.png
或者在 Vim 中快速打开备忘录:vim-cheat40。
基础
缓冲区,窗口,标签
Vim 是一个文本编辑器。每次文本都是作为缓冲区的一部分显示的。每一份文件都是在他们自己独有的缓冲区打开的,插件显示的内容也在它们自己的缓冲区中。
缓冲区有很多属性,比如这个缓冲区的内容是否可以修改,或者这个缓冲区是否和文件相关联,是否需要同步保存到磁盘上。
窗口 是缓冲区上一层的视窗。如果你想同时查看几个文件或者查看同一文件的不同位置,那样你会需要窗口。
请别把他们叫做_分屏_。你可以把一个窗口分割成两个,但是这并没有让这两个窗口完全_分离_。
窗口可以水平或者竖直分割并且现有窗口的高度和宽度都是可以被调节设置的,因此,如果你需要多种窗口布局,请考虑使用标签。
标签页 (标签)是窗口的集合。因此使用标签当你想使用多种窗口布局的时候。
简单的说,如果你启动 Vim 的时候没有附带任何参数,你会得到一个包含着一个呈现一个缓冲区的窗口的标签。
顺带提一下,缓冲区列表是全局可见的,你可以在任何标签中访问任何一个缓冲区。
已激活,已载入,已列出,已命名,缓冲区
用类似 vim file1
的命令启动 Vim 。这个文件的内容将会被加载到缓冲区中,你现在有一个已载入的缓冲区。如果你在 Vim 中保存这个文件,缓冲区内容将会被同步到磁盘上(写回文件中)。
由于这个缓冲区也在一个窗口上显示,所以他也是一个已激活的缓冲区。如果你现在通过 :e file2
命令加载另一个文件,file1
将会变成一个隐藏的缓冲区,并且 file2
变成已激活缓冲区。
使用 :ls
我们能够列出所有可以列出的缓冲区。插件缓冲区和帮助缓冲区通常被标记为不可以列出的缓冲区,因为那并不是你经常需要在编辑器中编辑的常规文件。通过 :ls!
命令可以显示被放入缓冲区列表的和未被放入列表的缓冲区。
未命名的缓冲区是一种没有关联特定文件的缓冲区,这种缓冲区经常被插件使用。比如 :enew
将会创建一个无名临时缓冲区。添加一些文本然后使用 :w /tmp/foo
将他写入到磁盘,这样这个缓冲区就会变成一个已命名的缓冲区。
参数列表
全局缓冲区列表是 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”代替。
相关帮助::h argument-list
按键映射
使用 :map
命令家族你可以定义属于你自己的快捷键。该家族的每一个命令都限定在特定的模式下。从技术上来说 Vim 自带高达 12 中模式,其中 6 种可以被映射。另外一些命令作用于多种模式:
递归 | 非递归 | 模式 |
---|---|---|
:map |
:noremap |
normal, visual, operator-pending |
:nmap |
:nnoremap |
normal |
:xmap |
:xnoremap |
visual |
:cmap |
:cnoremap |
command-line |
:omap |
:onoremap |
operator-pending |
:imap |
:inoremap |
insert |
例如:这个自定义的快捷键只在普通模式下工作。
:nmap <space> :echo "foo"<cr>
使用 :nunmap <space>
可以取消这个映射。
对于更少数,不常见的模式(或者他们的组合),查看 :h map-modes
。
到现在为止还好,对新手而言有一个问题会困扰他们::nmap
是递归执行的!结果是,右边执行可能的映射。
你自定义了一个简单的映射去输出“Foo”:
:nmap b :echo "Foo"<cr>
但是如果你想要映射 b
(回退一个单词)的默认功能到一个键上呢?
:nmap a b
如果你敲击a,我们期望着光标回退到上一个单词,但是实际情况是“Foo”被输出到命令行里!因为在右边,b
已经被映射到别的行为上了,换句话说就是 :echo "Foo"<cr>
。
解决此问题的正确方法是使用一种_非递归_的映射代替:
:nnoremap a b
经验法则:除非递归是必须的,否则总是使用非递归映射。
通过不给一个右值来检查你的映射。比如:nmap
显示所以普通模式下的映射,:nmap <leader>
显示所有以 <leader>
键开头的普通模式下的映射。
如果你想禁止用标准映射,把他们映射到特殊字符 <nop>
上,例如::noremap <left> <nop>
。
相关帮助:
:h key-notation
:h mapping
:h 05.3
快捷键前缀
"Leader" 键是一个触发器,默认为 \\
。我们可以通过在 map
中调用 <leader>
来为 <leader>
键设置映射
nnoremap <leader>h :helpgrep<space>
这样,我们只需要先按 \ 然后按 h 就可以执行 :helpgrep<space>
了。如果你想通过先按 空格 键来触发,只需要这样做:
let mapleader = ' '
nnoremap <leader>h :helpgrep<space>
另外,还有一个叫 <localleader>
的,可以把它理解为局部环境中的 <leader>
,默认值依然为 \。当我们需要只对某一个条件下(比如,特定文件类型的插件)的缓冲区设置特别的 <leader>
键,那么我们就可以通过修改当前环境下的 <localleader>
来实现
注意:如果你打算设置 Leader 键,请确保在设置按键映射之前,先设置好 Leader 键。如果你先设置了含有 Leader 键的映射,然后又修改了 Leader 键,那么之前映射的 Leader 键是不会因此而改变的。你可以通过执行 :nmap <leader>
来查看普通模式中已绑定给 Leader 键的所有映射
请参阅 :h mapleader
与 :h maploacalleader
来获取更多帮助
寄存器
寄存器就是存储文本的地方。我们常用的"复制"操作就是把文本存储到寄存器,"粘贴"操作就是把文本从寄存器中读出来。顺便,在 Vim 中复制的快捷键是 y,粘贴的快捷键是 p
Vim 为我们提供了如下的寄存器:
类型 | 字符 | 读写者 | 是否为只读 | 包含的字符来源 |
---|---|---|---|---|
Unnamed | " |
vim | [ ] | 最近一次的复制或删除操作 (d , c , s , x , y ) |
Numbered | 0 to 9 |
vim | [ ] | 寄存器 0 : 最近一次复制。寄存器 1 : 最近一次删除。寄存器 2 : 倒数第二次删除,以此类推。对于寄存器 1 至 9 ,他们其实是只读的最多包含 9 个元素的队列。这里的队列即为数据类型 queue |
Small delete | - |
vim | [ ] | 最近一次,内容在一行以内的删除 |
Named | a to z , A to Z |
user | [ ] | 如果你通过复制操作存储文本至寄存器 a ,那么 a 中的文本就会被完全覆盖。如果你存储至 A ,那么会将文本添加给寄存器 a ,不会覆盖之前已有的文本 |
Read-only | : , . , % |
vim | [x] | : : 最近一次使用的命令,. : 最近一次添加的文本,% : 当前的文件名 |
Alternate buffer | # |
vim | [ ] | 大部分情况下,这个寄存器是当前窗口中,上一次访问的缓冲区。请参阅 :h alternate-file 来获取更多帮助 |
Expression | = |
user | [ ] | 复制 VimL 代码时,这个寄存器用于存储代码片段的执行结果。比如,在插入模式下复制 <c-r>=5+5<cr> ,那么这个寄存器就会存入 10 |
Selection | + , * |
vim | [ ] | * 和 + 是 剪贴板 寄存器 |
Drop | ~ |
vim | [x] | 存储最近一次添加进 Vim 中的文本 |
Black hole | _ |
vim | [ ] | 对于当前操作,如果你不希望在其他寄存器中保留文本,那就在命令前加上 _ 。比如,"_dd 命令不会将文本放到寄存器 " 、1 、+ 或 * 中 |
Last search pattern | / |
vim | [ ] | 最近一次通过 / 、? 或 :global 等命令调用的正则表达式 |
只要不是只读的寄存器,用户都有权限修改它的内容,比如:
:let @/ = 'register'
这样,我们按 n 的时候就会跳转到单词 "register" 出现的地方
有些时候,你的操作可能已经修改了寄存器,而你没有察觉到。请参考 :h registers
获取更多帮助
上面提到过,复制的命令是 y,粘贴的命令是 p 或者 P。但请注意,Vim 会区分"字符选取"与"行选取"。请参考 :h linewise
获取更多帮助
行选取:
命令 yy
或 Y
都是复制当前行。这时移动光标至其他位置,按下 p
就可以在光标下方粘贴复制的行,按下 P
就可以在光标上方粘贴至复制的行
字符选取:
命令 0yw
可以复制第一个单词。这时移动光标至其他位置,按下 p
就可以在当前行、光标后的位置粘贴单词,按下 P
就可以在当前行、光标前的位置粘贴单词
将文本存到指定的寄存器中:
命令 "aY
可以将当前行复制,并存储到寄存器 a
中。这时移动光标至其他位置,通过命令 "AY
就可以把这一行的内容扩展到寄存器 a
中,而之前存储的内容也不会丢失
为了便于理解和记忆,建议大家现在就试一试上面提到的这些操作。操作过程中,你可以随时通过 :reg
来查看寄存器的变化
有趣的是:
在 Vim 中,y
是复制命令,源于单词 "yanking"。而在 Emacs 中,"yanking" 代表的是粘贴(或者说,重新插入刚才删掉的内容),而并不是复制
范围
范围 (Ranges) 其实很好理解,但很多 Vim 用户的理解不到位
- 很多命令都可以加一个数字,用于指明操作范围
- 可以是一个 "地址",用于指定某一行
- 可以是一个 "地址" 或者一对通过
,
或;
分割的一对 "地址" - 大部分命令,默认只作用于当前行
- 只有
:white
和:global
是默认作用于所有行的
范围的使用是十分直观的。以下为一些例子(其中,: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 行
你可以在通过在地址前加上 /
来设置多个地址,比如:
:/foo//bar//quux/d
这就会删除当前行之后的某一行。定位方式是,现在当前行之后寻找第一个包含 "foo" 字符的那一行,然后在找到的这一行之后寻找第一个包含 "bar" 字符的那一行,然后再在找到的这一行之后寻找第一个包含 "quux" 的那一行。删除的就是最后找到的这一行
加入我们
可以协助我们核对翻译,或者从章节列表中认领章节进行翻译。