阅读更多
1 Basic Concept
1.1 Mode
vim常用的三种模式:一般模式、编辑模式与命令模式。:help mode
查看详情
一般模式与编辑模式以及命令行模式可以相互切换,但是编辑模式与命令行模式之间不可相互切换
1.1.1 Normal Mode
以vim打开一个文件就进入一般模式了(这是默认模式)
在这个模式中,你可以使用上下左右按键来移动光标,可以删除字符或删除整行,也可以复制粘贴你的文件数据
1.1.2 Insert Mode
在一般模式中,可以进行删除,复制,粘贴等操作,但是却无法编辑文件内容。要等到你按下i(I),o(O),a(A),r(R)
等任何一个字母后才会进入编辑模式
如果要回到一般模式,必须按下Esc
这个按键即可退出编辑器
1.1.3 Visual Mode
This mode is used for selecting and manipulating text visually.
1.1.4 Command-line Mode
在一般模式中,输入:
、/
、?
这三个钟的任何一个按钮,就可以将光标移动到最下面一行,在这个模式中,可以提供你查找数据的操作,而读取、保存、大量替换字符、离开vim、显示行号等操作则是在此模式中完成的
1.1.5 Ex Mode
This is an even more powerful mode than command-line mode, used for advanced editing and automation.
Ex mode, on the other hand, is a more powerful command-line mode that is entered by typing Q
or q:
from normal mode or insert mode
1.2 Buffer
每个打开的文件都对应一个buffer。buffer可以显示或者不显示
1.3 Window
window就是我们看到的并且可以操作的那个界面。一个window可以包含一个或多个buffer,总是会显示其中一个buffer(文件或者空)。允许同时开启多个窗口
1.4 Tab
tab可以包含一个或多个window。如果存在多个tab,那么会在最上方显示这些tab,就像一个现代的编辑器一样(vscode)
2 Operation Manual
2.1 Insert Mode
i,I
:进入插入模式,i为从光标所在处插入,I为在目前所在行的第一个非空格处开始插入a,A
:进入插入模式,a为从目前光标所在的下一个字符处开始插入,A为从光标所在行的最后一个字符处开始插入o,O
:进入插入模式,o为在目前光标所在的下一行处插入新的一行,O为在目前光标所在处的上一行插入新的一行s,S
:进入插入模式,s为删除目前光标所在的字符,S为删除目前光标所在的行r,R
:进入替换模式,r只会替换光标所在的那一个字符一次,R会一直替换光标所在行的文字,直到按下EscEsc
:退回一般模式[Ctrl] + [
(:help i_CTRL-[
):退回一般模式[Ctrl] + w
(:help i_CTRL-W
):向前删除单词[Ctrl] + r + [reg]
:插入寄存器中的内容,例如[Ctrl] + r + 0
:插入0
号寄存器的内容[Ctrl] + r + "
:插入默认寄存器的内容
[Ctrl] + r + =
:插入表达式计算结果,等号后面跟表达式[Ctrl] + r + /
:插入上一次搜索的关键字[Ctrl] + o + [cmd]
:临时退出插入模式,执行单条命令又返回插入模式[Ctrl] + o + 0
:光标移动到行首,等效于一般模式下的0
[Ctrl] + d/t/f
:光标所在的整行减少/增加缩进/自动调整缩进[Shift] + [Left]
:向左移动一个单词[Shift] + [Right]
:向右移动一个单词[Shift] + [Up]
:向上翻页[Shift] + [Down]
:向下翻页[Ctrl] + e
(:help i_CTRL-E
):Insert the character which is below the cursor[Ctrl] + y
(:help i_CTRL-Y
):Insert the character which is above the cursor
2.2 Moving Cursor
j或↓
:光标向下移动一个字符k或↑
:光标向上移动一个字符h或←
:光标向左移动一个字符l或→
:光标向右移动一个字符- 可以配合数字使用,如向右移动30个字符
30l
或30→
[Ctrl] + f
:屏幕向下移动一页,相当于[Page Down]
按键[Ctrl] + b
:屏幕向上移动一页,相当于[Page Up]
按键[Ctrl] + d
:屏幕向下移动半页[Ctrl] + u
:屏幕向上移动半页[Ctrl] + e
:屏幕向下移动一行[Ctrl] + y
:屏幕向上移动一行+
:光标移动到非空格符的下一行-
:光标移动到非空格符的上一行[n][space]
:n表示数字,再按空格键,光标会向右移动n个字符0(数字零)或[home]
:移动到这一行的最前面字符处^
:移动到这一行的最前面的非空白字符处$或功能键end
:移动到这一行最后面的字符处g_
:移动到这一行最后面的字符处。配合v
时,即vg_
,不包含换行符,而v$
会包含换行符H
:光标移动到屏幕最上方那一行的第一个字符M
:光标移动到这个屏幕的中央那一行的第一个字符L
:光标移动到这个屏幕的最下方那一行的第一个字符w
:跳到下一个单词开头(标点或空格分隔的单词)e
:跳到下一个单词尾部(标点或空格分隔的单词)b
:跳到上一个单词开头(标点或空格分隔的单词)W
:跳到下一个单词开头(空格分隔的单词)E
:跳到下一个单词尾部(空格分隔的单词)B
:跳到上一个单词开头(空格分隔的单词))
:向前移动一个句子(句号分隔)(
:向后移动一个句子(句号分隔)}
:向前移动一个段落{
:向后移动一个段落[(
:跳转到上一个未匹配的(
处])
:跳转到下一个未匹配的)
处[{
:跳转到上一个未匹配的{
处]}
:跳转到下一个未匹配的}
处[m
:跳到上一个method
的起始位置,若没有method
,则跳转到class
的起始位置]m
:跳到下一个method
的起始位置,若没有method
,则跳转到class
的结束位置[M
:跳到上一个method
的结束位置,若没有method
,则跳转到class
的起始位置]M
:跳到下一个method
的结束位置,若没有method
,则跳转到class
的结束位置f<x>
/[n]f<x>
:向后,跳转到第1个/第n个为x
的字符F<x>
/[n]F<x>
:向前,跳转到第1个/第n个为x
的字符t<x>
/[n]t<x>
:向后,跳转到第1个/第n个为x
的字符前T<x>
/[n]T<x>
:向前,跳转到第1个/第n个为x
的字符前;
:跳到下一个f/F/t/T
匹配的位置,
:跳到上一个f/F/t/T
匹配的位置
G
:移动到这个文件的最后一行[n]G
:n为数字,移动到这个文件的第n行gg
:移动到这个文件的第一行,相当于1G[n][Enter]
:光标向下移动n行gm
:移动到行中gj
:光标下移一行(忽略自动换行)gk
:光标上移一行(忽略自动换行)%
:跳转到{} () []
的匹配- 可以通过
:set matchpairs+=<:>
增加对尖括号<>
的识别。可能会误识别,因为文本中可能包含单个>
或<
- 可以通过
=
:按照类型自动调整缩进gg=G
2.2.1 Jump List
帮助文档::help jump-motions
将光标移动多行的指令称为跳转指令,例如:
H
、M
、L
123G
、:123
:跳转到指定行/[word]
、?[word]
、:s
、n
、N
:查找替换%
、()
、[]
、{}
''
:回到jump list
中最后一个位置,光标丢失列信息,处于行首,且该命令本身也是作为一个jump
,会被记录到jump list
中~~
:回到jump list
中最后一个位置,光标会精确到列,且该命令本身也是作为一个jump
,会被记录到jump list
中[Ctrl] + o
:回到jump list
的上一个位置,且该命令本身不是jump
,不会被记录到jump list
中[Ctrl] + i
:回到jump list
中下一个位置,且该命令本身不是jump
,不会被记录到jump list
中:jumps
:输出jump list
:clearjumps
:清除jump list
2.2.2 Change List
帮助文档::help changelist
当内容发生修改时,会记录修改的位置信息,并通过如下命令在change list
中记录的位置之间进行跳转:
g;
:回到change list
的上一个位置g,
:回到change list
的下一个位置:changes
:输出change list
2.3 Text Editing
c
、d
等命令可以配合「Moving Cursor」中的操作一起使用
dd
:删除光标所在一整行dw
:删除光标所在的字符到光标所在单词的最后一个字符[n]dd
:删除光标所在的向下n行(包括当前这一行)d1G
:删除光标所在到第一行的所有数据(包括当前这一行)dG
:删除光标所在到最后一行的所有数据(包括当前这一行)d0(这是零)
:删除从光标所在的字符到该行最前面一个字符(不包括光标所指向的字符)d^
:删除从光标所在的字符到该行最前面一个非零字符(不包括光标所指向的字符)d$
:删除光标所在的字符到该行的最后一个字符(包括光标所指向的字符)d%
:删除光标所在的字符(光标所在的字符到该行的最后一个字符之间必须包含左括号,可以是(
、[
、{
)到另一个右括号(与前一个左括号配对)之间的所有数据df<x>
/d[n]f<x>
:删除光标所在字符到第1个/第n个为x
的字符dt<x>
/d[n]t<x>
:删除光标所在字符到第1个/第n个为x
的字符前d/<word>
:删除光标所在的字符到搜索关键词<word>
前D
:同d$
cc
:改写光标所在一整行cw
:改写光标所在的字符到光标所在单词的最后一个字符[n]cc
:改写光标所在的向下n行(包括当前这一行)c1G
:改写光标所在到第一行的所有数据(包括当前这一行)cG
:改写光标所在到最后一行的所有数据(包括当前这一行)c0(这是零)
:改写从光标所在的字符到该行最前面一个字符(不包括光标所指向的字符)c^
:改写从光标所在的字符到该行最前面一个非零字符(不包括光标所指向的字符)c$
:改写光标所在的字符到该行的最后一个字符(包括光标所指向的字符)c%
:改写光标所在的字符(光标所在的字符到该行的最后一个字符之间必须包含左括号,可以是(
、[
、{
)到另一个右括号(与前一个左括号配对)之间的所有数据cf<x>
/c[n]f<x>
:改写光标所在字符到第1个/第n个为x
的字符ct<x>
/c[n]t<x>
:改写光标所在字符到第1个/第n个为x
的字符前c/<word>
:改写光标所在的字符到搜索关键词<word>
前- 用
n/N
找到下一个/上一个匹配项,按.
重复之前的操作
- 用
C
:同c$
其他:
J
:将光标所在行与下一行的数据结合成同一行x,X
:在一行字当中,x为向后删除一个字符(相当于[Del]
键),X为向前删除一个字符(相当于[Backspace]
)[n]x
:连续向后删除n个字符g~
/gu
/gU
:转换大小写/转为小写/转为大写,一般需要配合文本对象一起使用,例如guiw
guw
<
:减少缩进>
:增加缩进[Ctrl] + a
:数字+1[Ctrl] + x
:数字-1u
:复原(撤销)前一个操作[Ctrl] + r
:重做上一个操作.
:重做上一个操作
2.4 Copy & Paste
yy
:复制光标所在那一行[n]yy
:复制光标所在的向下n行(包括当前这一行)y1G
:复制光标所在行到第一行的所有数据(包括当前这一行)yG
:复制光标所在行到最后一行的数据(包括当前这一行)y0(这是零)
:复制光标所在那个字符到该行第一个字符的所有数据(不包括光标所指向的字符)y$
:复制光标所在那个字符到该行最后一个字符的所有数据(包括光标所指向的字符)p
:将已复制的数据粘贴到光标之前P
:将已复制的数据粘贴到光标之后
2.4.1 Register
vim中有许多寄存器(该寄存器并不是cpu中的寄存器),分别是:
0-9
:vim用来保存最近复制、删除等操作的内容0
:保存的是最近一次拷贝的内容1-9
:保存最近几次删除的内容,最近一次放在1
,若有新的内容被删除,那么原来的i
中的内容会存放到i+1
中,由于9
编号最大,因此该寄存器中原来的内容被丢弃
a-zA-Z
:用户寄存器,vim不会读写这部分寄存器"
:未命名的寄存器。所有删除和拷贝操作默认都会到匿名寄存器*
:系统寄存器Mac
/Windows
:同+
Linux-X11
:代表鼠标选中的区域,桌面系统中可按鼠标中键粘贴
+
:系统寄存器Mac
/Windows
:同*
Linux-X11
:在桌面系统中可按Ctrl+V
粘贴
_
:Black hole register
,类似于文件系统中的/dev/null
如何使用这些寄存器:"<reg name><operator>
- 最左侧的
"
是固定语法 <reg name>
:寄存器名称,比如0
、a
、+
、"
等<operator>
:需要执行的操作,就是y/d/p
等等q<reg name>q
:清除寄存器的内容
示例:
:reg
:查看寄存器的信息:reg <reg name>
:查看某个寄存器的内容"+yy
:将当前行拷贝到系统寄存器"+p
:将系统寄存器中的内容粘贴到光标之后
ssh到远程主机后,如何将本机系统寄存器的内容粘贴到远程主机的vim中?
- 首先确认远程主机的vim是否支持
clipboard
,通过vim --version | grep clipboard
。-clipboard
说明不支持,+clipboard
说明支持。clipboard
需要在X
环境下才能工作 - 如果系统是CentOS,需要安装图形化界面,比如
GNOME
,然后再安装vim-X11
,然后用vimx
代替vim
。vimx --version | grep clipboard
可以发现已经支持了clipboard
。至此,已经可以在ssh终端中通过vimx
使用远程主机的clipboard
了 - 未完待续,目前还没搞定本机和远程的
clipboard
的共享
2.5 Visual Selection
v
:字符选择:会将光标经过的地方反白选择vw
:选择光标开始处的当前单词(若光标在单词中间,不会选择整个单词)viw
:选择光标所处的单词(若光标在单词中间,也可以选中整个单词)vi'
:选择单引号中的内容vi"
:选择双引号中的内容vi(
:选择小括号中的内容vi[
:选择中括号中的内容vi{
:选择大括号中的内容V
:行选择:会将光标经过的行反白选择<line number>G
:跳到指定行,并反白选择中间所有内容
[Ctrl] + v
:块选择,可以用长方形的方式选择数据>
:增加缩进<
:减少缩进~
:转换大小写c/y/d
:改写/拷贝/删除u
:变为小写U
:变为大写o
:跳转到标记区的另外一端O
:跳转到标记块的另外一端gv
:在使用p
或者P
替换选中内容后,会重新选中被替换的区域gn
:选中下一个查找的内容gN
:选中上一个查找的内容
2.6 Search & Replace
- 查找
/[word]
:向下寻找一个名为word的字符串,支持正则表达式/\<[word]\>
:向下寻找一个名为word的字符串(全词匹配),支持正则表达式/\V[word]
:向下寻找一个名为word的字符串,所有字符均被视为普通字符?[word]
:向上寻找一个名为word的字符串,支持正则表达式?\<[word]\>
:向上寻找一个名为word的字符串(全词匹配),支持正则表达式?\V[word]
:向上寻找一个名为word的字符串,所有字符均被视为普通字符n
:重复前一个查找操作N
:"反向"进行前一个查找操作*
:以全词匹配的模式(\<[word]\>
)向后搜索关键词,用于匹配的关键词的获取规则如下:- 光标下的关键词
- 当前行,光标后最近的关键词
- 光标下的非空字符串
- 当前行,光标后最近的非空字符串
- 大小写是否敏感
/[word]\c
:大小写不敏感/[word]\C
:大小写敏感
#
:同*
,区别是向前搜索关键词g*
:同*
,区别是以非全词匹配的模式g#
:同#
,区别是以非全词匹配的模式- 搜索上一次选中的内容,步骤如下:
- 进入
visual
模式 - 复制:
y
- 进入搜索模式:
/
- 选择寄存器:
[Ctrl] + r
- 输入默认寄存器:
"
- 进入
- 替换
:[n1],[n2]s/[word1]/[word2]/g
:在n1与n2行之间寻找word1这个字符串,并将该字符串替换为word2,支持正则表达式:[n1],[n2]s/\<[word1]\>/[word2]/g
:在n1与n2行之间寻找word1这个字符串(全词匹配),并将该字符串替换为word2,支持正则表达式:1,$s/[word1]/[word2]/g
或者:%s/[word1]/[word2]/g
:从第一行到最后一行查找word1字符串,并将该字符串替换为word2,支持正则表达式:1,$s/[word1]/[word2]/gc
或者:%s/[word1]/[word2]/gc
:从第一行到最后一行查找word1字符串,并将该字符串替换为word2,且在替换前显示提示字符给用户确认是否替换,支持正则表达式- 可视模式选中范围,输入
:s/[word1]/[word2]/gc
进行替换
[Ctrl]+r
以及[Ctrl]+w
:将光标下的字符串添加到搜索或者替换表达式中gn
:选中下一个查找的内容gN
:选中上一个查找的内容
2.7 Record
Record refers to a feature that allows you to record a sequence of keystrokes and save it as a macro for later playback. This is a powerful and versatile feature that can help you automate repetitive tasks, make complex edits more efficiently, and improve your overall productivity when working with text.
How to Use Vim Record:
- Start Recording: To start recording a macro, press
q
followed by the register(a
toz
) where you want to store the macro. For example, press qa to start recording in registera
- Perform Actions: While recording is active, perform the series of commands, edits, or movements you want to include in your macro. Vim will record everything you do.
- Stop Recording: To stop recording, press
q
again. In our example, pressq
once more to stop recording in registera
- Replay the Macro: To replay the recorded macro, use the
@
symbol followed by the register where you stored the macro. For example, to replay thea
register macro, type@a
2.8 File
:w
:保存文件:wa
:保存所有文件:w!
:若文件属性为只读时,强制写入该文件,不过到底能不能写入,还是跟你对该文件的文件属性权限有关:q
:离开:q!
:若曾修改过文件,又不想存储,使用"!"为强制离开不保存的意思:wq
:保存后离开,若为:wq!则代表强制保存并离开:e [filename]
:打开文件并编辑:e
:重新载入当前文件ZZ
:若文件没有变更,则不保存离开,若文件已经变更过,保存后离开:w [filename]
:将编辑文件保存称为另一个文件,注意w和文件名中间有空格:r [filename]
:在编辑的数据中,读入另一个文件的数据,即将filename这个文件的内容加到光标所在行后面,注意r和文件名之间有空格:[n1],[n2]w [filename]
:将n1
到n2
的内容保存成filename
这个文件,注意w和文件名中间有空格,[n2]
与w
之间可以没有空格vim [filename1] [filename2]...
:同时编辑多个文件:n
:编辑下一个文件:N
:编辑上一个文件:files
:列出这个vim打开的所有文件:Vex
:打开目录
2.9 Text Object
文本对象:c
、d
、v
、y
、g~
、gu
、gU
等命令后接文本对象,一般格式为:<范围><类型>
- 范围:可选值有
a
和i
a
:表示包含边界i
:表示不包含边界
- 类型:小括号、大括号、中括号、单引号、双引号等等
'
"
(
/b
[
{
/B
示例:
i)
:小括号内a)
:小括号内(包含小括号本身)i]
:中括号内a]
:中括号内(包含中括号本身)i}
:大括号内a}
:大括号内(包含大括号本身)i'
:单引号内a'
:单引号内(包含单引号本身)i"
:双引号内a"
:双引号内(包含双引号本身)
2.10 Text Fold
按照折叠所依据的规则,可以分为如下4种:
manual
:手工折叠:set foldmethod=manual
zf
:需要配合范围选择,创建折叠zf
还可以与文本对象配合,例如zfi{
:折叠大括号之间的内容,不包括大括号所在行zfa{
:折叠大括号之间的内容,包括大括号所在行
zd/zD
:删除当前折叠zE
:删除所有折叠
indent
:缩进折叠:set foldmethod=indent
:set foldlevel=[n]
marker
:标记折叠:set foldmethod=marker
syntax
:语法折叠:set foldmethod=syntax
通用操作(大写表示递归):
zN
:启用折叠zn
:禁用折叠za/zA
:折叠/展开当前的代码zc/zC
:折叠当前的代码zo/zO
:展开当前的代码zm/zM
:折叠所有代码zr/zR
:展开所有代码zj
:移动到下一个折叠zk
:移动到上一个折叠
2.11 Buffer
:buffers
:列出所有buffer:buffer [n]
:显示指定buffer:bnext
:显示下一个buffer:bprev
:显示上一个buffer:edit [filename]
:将一个文件放入一个新的buffer中:bdelete [n]
:删除指定buffer(不指定时,表示当前buffer):%bdelete
:删除所有buffer:%bdelete|e#
:删除除了当前buffer之外的所有buffer。其中:e#
表示重新打开最后一个关闭的buffer
:bufdo <cmd>
:对所有buffer执行操作:bufdo e
:重新载入所有buffer对应的文件
2.12 Window
[Ctrl] + w + <xxx>
:先[Ctrl]
再w
,放掉[Ctrl]
和w
再按<xxx>
,以下操作以此为基准
vim -On file1 file2...
:垂直分屏vim -on file1 file2...
:左右分屏[Ctrl] + w + c
:关闭当前窗口(无法关闭最后一个)[Ctrl] + w + q
:关闭当前窗口(可以关闭最后一个)[Ctrl] + w + o
:关闭其他窗口[Ctrl] + w + s
:上下分割当前打开的文件[Ctrl] + w + v
:左右分割当前打开的文件:sp filename
:上下分割并打开一个新的文件:vsp filename
:左右分割,并打开一个新的文件[Ctrl] + w + l
:把光标移动到右边的屏中[Ctrl] + w + h
:把光标移动到左边的屏中[Ctrl] + w + k
:把光标移动到上边的屏中[Ctrl] + w + j
:把光标移动到下边的屏中[Ctrl] + w + w
:把光标移动到下一个屏中,如果只有两个窗口的话,就可以相互切换了[Ctrl] + w + L
:向右移动屏幕[Ctrl] + w + H
:向左移动屏幕[Ctrl] + w + K
:向上移动屏幕[Ctrl] + w + J
:向下移动屏幕[Ctrl] + w + =
:让所有屏幕都有一样的高度[Ctrl] + w + [+]
:高度增加1[Ctrl] + w + [n] [+]
:高度增加n[Ctrl] + w + -
:高度减小1[Ctrl] + w + [n] -
:高度减小n[Ctrl] + w + >
:宽度增加1[Ctrl] + w + [n] + >
:宽度增加n[Ctrl] + w + <
:宽度减小1[Ctrl] + w + [n] + <
:宽度减小n
2.13 Tab
:tabnew [filename]
:在一个新的tab中打开文件:tabnew %
:在另一个tab
中打开当前文件
:tabedit
:同tabnew
:tabm [n]
:将当前标签页移动到位置n
(n
从0开始),若不指定n
,则移动到最后gt
/:tabnext
:下一个tabgT
/:tabprev
:上一个tab:tab sball
:将所有buffer:tabdo <cmd>
:对所有tab执行操作:tabdo e
:重新载入所有tab对应的文件
2.14 Quickfix
:copen
:打开quickfix
窗口(查看编译,grep等信息):copen 10
:打开quickfix
窗口,并且设置高度为10
:cclose
:关闭quickfix
窗口:cfirst
:跳到quickfix
中第一个错误信息:clast
:跳到quickfix
中最后一条错误信息:cc [nr]
:查看错误[nr]
:cnext
:跳到quickfix
中下一个错误信息:cprev
:跳到quickfix
中上一个错误信息:set modifiable
,将quickfix
改成可写,可以用dd
等删除某个条目
2.15 Terminal
vim中可以内嵌终端
:terminal
:打开终端[Ctrl] + \ + [Ctrl] + n
:退出终端
2.16 Mapping
map
:递归映射noremap
:非递归映射unmap
:将指定按键重置成默认行为mapclear
:消所有map
配置,慎用
COMMANDS | MODES |
---|---|
map 、noremap 、unmap |
Normal, Visual, Select, Operator-pending |
nmap 、nnoremap 、nunmap |
Normal |
vmap 、vnoremap 、vunmap |
Visual and Select |
smap 、snoremap 、sunmap |
Select |
xmap 、xnoremap 、xunmap |
Visual |
omap 、onoremap 、ounmap |
Operator-pending |
map! 、noremap! 、unmap! |
Insert and Command-line |
imap 、inoremap 、iunmap |
Insert |
lmap 、lnoremap 、lunmap |
Insert, Command-line, Lang-Arg |
cmap 、cnoremap 、cunmap |
Command-line |
tmap 、tnoremap 、tunmap |
Terminal-Job |
查看所有map
:
:map
:noremap
:nnoremap
重定向所有map
到文件中:
:redir! > vim_keys.txt
:silent verbose map
:redir END
特殊参数:
<buffer>
:表示映射仅对当前<buffer>
生效<nowait>
<silent>
:禁止输出映射信息<special>
<script>
<expr>
<unique>
2.17 Key Representation
<f-num>
:例如<f1>
、<f2>
<c-key>
:表示[Ctrl]
加另一个字母<a-key>/<m-key>
:表示[Alt]
加另一个字母- 对于mac上的
[Option]
,并没有<p-key>
这样的表示方法。而是用[Option]
加另一个字母实际输出的结果作为映射键值,例如:[Option] + a
:å
2.18 Config
:set <config>?
:可以查看<config>
的值:set filetype?
:查看文件类型
:echo &<config>
:也可以查看<config>
的值:echo &filetype
:查看文件类型
set <config> += <value>
:增加配置,可以一次增加多个项目,以逗号分隔set <config> -= <value>
:删除配置,一次只能删除一个项目
2.18.1 Frequently-used Configs
1 | :set nocompatible " 设置不兼容原始 vi 模式(必须设置在最开头) |
2.18.2 Debugging Configs
runtimepath
(rtp)
: Specifies the directory paths Vim will use to search for runtime files.path
: Sets the list of directories to be searched when using commands like :find.packpath
: Determines where Vim looks for packages.backupdir
(bdir)
: Specifies the directory for backup files.directory
(dir)
: Indicates where swap files are stored.spellfile
: Defines the file locations for spell checking.undodir
: Designates the directory for undo files.viewdir
: Specifies the directory for saved views.backupskip
: Lists patterns for files that should not have backups.wildignore
: Sets the patterns to be ignored during file name completion.suffixes
: Defines suffixes that are less important during filename matching.helpfile
: Specifies the location of the help file.tags
: Lists the tag files used for tag commands.
2.18.3 Config File
vim会主动将你曾经做过的行为记录下来,好让你下次可以轻松作业,记录操作的文件就是~/.viminfo
vim的全局设置值一般放置在/etc/vimrc
(or /etc/vim/vimrc
)这个文件中,不过不建议修改它,但是可以修改~/.vimrc
这个文件(默认不存在,手动创建)
在运行vim的时候,如果修改了~/.vimrc
文件的内容,可以通过执行:source ~/.vimrc
来重新加载~/.vimrc
,立即生效配置
2.19 Variable
Neovim supports several types of variables:
- Global Variables
(g:)
: These are accessible from anywhere in your Neovim configuration and during your Neovim sessions. They are often used to configure plugins and Neovim settings. - Buffer Variables
(b:)
: These are specific to the current buffer (file) you are working on. Changing the buffer will change the scope and access to these variables. - Window Variables
(w:)
: These are specific to the current window. Neovim allows multiple windows to be open, each can have its own set of w: variables. - Tab Variables
(t:)
: These are associated with a specific tab in your Neovim environment. - Vim Variables
(v:)
: These are built-in variables provided by Neovim that contain information about the environment, such as v:version for the Neovim version or v:count for the last used count for a command.
Setting Variables:
1 | let g:my_variable = "Hello, Neovim!" |
Accessing Variables:
1 | :echo g:my_variable |
Unsetting Variables:
1 | :unlet g:my_variable |
2.20 Help Doc
:help CTRL-W
:查看普通模式下ctrl + w
按键的帮助:help i_CTRL-V
:查看插入模式下ctrl + v
按键的帮助,其中i_
表示insert mode
:help v_CTRL-A
:查看可视模式下ctrl + a
按键的帮助,,其中v_
表示visual mode
help :s
:查看:s
命令的帮助
文档路径:/usr/share/vim/vim82/doc
/usr/share/vim/vim82/doc/help.txt
:主目录文档
vimtutor
:提供一个简易的教程
2.21 Troubleshooting
vim -V10logfile.txt
echo &runtimepath
2.22 Assorted
echo
:echom xxx
:信息会保留在message中,可以通过:message
查看
- 命令历史
q:
:进入命令历史编辑q/
:进入搜索历史编辑q[a-z
]:q后接任意字母,进入命令记录- 可以像编辑缓冲区一样编辑某个命令,然后回车执行
- 可以用
[Ctrl] + c
退出历史编辑回到编辑缓冲区,但此时历史编辑窗口不关闭,可以参照之前的命令再自己输入 - 输入
:x
关闭历史编辑并放弃编辑结果回到编辑缓冲区 - 可以在空命令上回车相当于退出历史编辑区回到编辑缓冲区
[Ctrl] + g
:统计信息g + [Ctrl] + g
:字节统计信息
2.22.1 Symbol Index
[Ctrl] + ]
:跳转到光标指向的符号的定义处gf
:跳转光标指向的头文件- 通过
set path=
或set path+=
设置或增加头文件搜索路径 - 通过
set path?
可以查看该变量的内容
- 通过
[Ctrl] + ^
:在前后两个文件之间跳转
2.22.2 Insert Form Feed(tab)
参考How can I insert a real tab character in Vim?,在我们设置了tabstop
、softtabstop
、expandtab
等参数后,tab
会被替换成空格,如果要输入原始的\t
字符,可以在insert
模式下,按[Ctrl] + v + i
,其中:
[Ctrl] + v
表示输入原始的字面值i
表示\t
2.22.3 Multiply-line Editing
示例:多行同时插入相同内容
- 在需要插入内容的列的位置,按
[Ctrl] + v
,选择需要同时修改的行 - 按
I
进入编辑模式 - 编写需要插入的文本
- 按两下
ecs
示例:多行行尾同时插入相同内容
- 在需要插入内容的列的位置,按
[Ctrl] + v
,选择需要同时修改的行 - 按
$
移动到行尾 - 按
A
进入编辑模式 - 编写需要插入的文本
- 按两下
ecs
示例:多行同时删除相同的内容
- 在需要插入内容的列的位置,按
[Ctrl] + v
,选择需要同时修改的行 - 选中需要同时修改的列
- 按
d
即可同时删除
2.22.4 中文乱码
编辑/etc/vimrc
,追加如下内容
1 | set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936 |
2.22.5 Project Customized Config
同一份~./vimrc
无法适用于所有的项目,不同的项目可能需要一些特化的配置项,可以采用如下的设置方式
1 | if filereadable("./.workspace.vim") |
3 Plugin
3.1 Overview
3.1.1 Plugin Manager
目前,使用最广泛的插件管理工具是:vim-plug,通过一个命令直接安装即可
1 | curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ |
基本用法
- 以
call plug#begin()
开头 - 中间是
Plug
的相关命令 - 以
call plug#end()
结尾,默认会开启如下功能,如果不需要的话,可以手动关闭filetype plugin indent on
syntax enable
基本操作
:PlugStatus
:查看插件状态:PlugInstall
:安装插件:PlugClean
:清除插件
修改下载源:默认从github.com
上下载,稳定性较差,可以按照如下方式修改~/.vim/autoload/plug.vim
1 | " 将 |
如何安装来自不同源的插件:
- 方案1:指定插件的完整地址,比如
Plug 'morhetz/gruvbox'
需要改成Plug 'https://github.com/morhetz/gruvbox'
- 方案2:禁用
URI
校验。默认情况下,Plug
不允许插件来自不同源,若要关闭此功能,可以按照如下方式修改~/.vim/autoload/plug.vim
1
2
3
4
5
6
7
8
9
10" 删掉如下代码片段
elsif !compare_git_uri(current_uri, uri)
[false, ["Invalid URI: #{current_uri}",
"Expected: #{uri}",
"PlugClean required."].join($/)]
" 删掉如下代码片段
elseif !s:compare_git_uri(remote, a:spec.uri)
let err = join(['Invalid URI: '.remote,
\ 'Expected: '.a:spec.uri,
\ 'PlugClean required.'], "\n")
3.1.2 Frequently-Used Plugins
3.2 Prepare
为什么需要准备环境,vim的插件管理不是会为我们安装插件么?因为某些复杂插件,比如ycm
是需要手动编译的,而编译就会依赖一些编译相关的工具,并且要求的版本比较高
由于我用的系统是CentOS 7.9
,通过yum install
安装的工具都过于陈旧,包括gcc
、g++
、clang
、clang++
、cmake
等等,这些工具都需要通过其他方式重新安装
3.2.1 vim8 (Required)
上述很多插件对vim的版本有要求,至少是vim8
,而一般通过yum install
安装的vim版本是7.x
1 | # 卸载 |
3.2.2 Symbol-ctags (Recommend)
Home: ctags
ctags
的全称是universal-ctags
安装:参照github官网文档进行编译安装即可
1 | git clone https://github.com/universal-ctags/ctags.git --depth 1 |
ctags
参数:
--c++-kinds=+px
:ctags
记录c++文件中的函数声明,各种外部和前向声明--fields=+ailnSz
:ctags
要求描述的信息,其中:a
:如果元素是类成员的话,要标明其调用权限(即public或者private)i
:如果有继承,则标明父类l
:标明标记源文件的语言n
:标明行号S
:标明函数的签名(即函数原型或者参数列表)z
:标明kind
--extras=+q
:强制要求ctags做如下操作,如果某个语法元素是类的一个成员,ctags默认会给其记录一行,以要求ctags对同一个语法元素再记一行,这样可以保证在VIM中多个同名函数可以通过路径不同来区分-R
:ctags
递归生成子目录的tags(在项目的根目录下很有意义)
在工程中生成ctags
:
1 | # 与上面的~/.vimrc中的配置对应,需要将tag文件名指定为.tags |
如何为C/C++
标准库生成ctags
,这里生成的标准库对应的ctags
文件是~/.vim/.cfamily_systags
1 | mkdir -p ~/.vim |
如何为Python
标准库生成ctags
,这里生成的标准库对应的ctags
文件是~/.vim/.python_systags
(ctags, vim and python code)
1 | ctags --languages=python --python-kinds=-iv --fields=+ailnSz --extras=+q -R -f ~/.vim/.python_systags /usr/lib64/python3.6 |
使用:
[Ctrl] + ]
:跳转到符号定义处。如果有多条匹配项,则会跳转到第一个匹配项[Ctrl] + w + ]
:在新的窗口中跳转到符号定义处。如果有多条匹配项,则会跳转到第一个匹配项:ts
:显示所有的匹配项。按ECS
再输入序号,再按Enter
就可以进入指定的匹配项:tn
:跳转到下一个匹配项:tp
:跳转到上一个匹配项g + ]
:如果有多条匹配项,会直接显式(同:ts
)
推荐配置,在~/.vimrc
中增加如下配置
- 注意,这里将tag的文件名从
tags
换成了.tags
,这样避免污染项目中的其他文件。因此在使用ctags
命令生成tag文件时,需要通过-f .tags
参数指定文件名 ./.tags;
表示在文件所在目录下查找名字为.tags
的符号文件,;
表示查找不到的话,向上递归到父目录,直到找到.tags
或者根目录.tags
是指在vim的当前目录(在vim中执行:pwd
)下查找.tags
文件
1 | " tags搜索模式 |
3.2.3 Symbol-cscope (Optional)
Home: cscope
相比于ctags
,cscope
支持更多功能,包括查找定义、查找引用等等。但是该项目最近一次更新是2012年,因此不推荐使用。推荐使用gtags
如何安装:
1 | wget -O cscope-15.9.tar.gz 'https://sourceforge.net/projects/cscope/files/latest/download' --no-check-certificate |
如何使用命令行工具:
1 | # 创建索引,该命令会在当前目录生成一个名为cscope.out索引文件 |
如何在vim中使用
1 | " 添加数据库 |
配置快捷键(~/.vimrc
):
1 | " 启用 quickfix |
注意事项:
- 尽量在源码目录创建数据库,否则cscope默认会扫描所有文件,效率很低
3.2.4 Symbol-gtags (Optional)
Home: gtags
gtags
的全称是GNU Global source code tagging system
这里有个坑,上面安装的是gcc-10.3.0
,这个版本编译安装global
源码会报错(dev-util/global-6.6.4 : fails to build with -fno-common or gcc-10),错误信息大概是global.o:(.bss+0x74): first defined here
,因此,我们需要再安装一个低版本的gcc,并且用这个低版本的gcc来编译global
1 | # 安装源 |
1 | # 安装相关软件 |
如何使用命令行工具:
1 | # 把头文件也当成源文件进行解析,否则可能识别不到头文件中的符号 |
在~/.vimrc
中增加如下配置
- 第一个
GTAGSLABEL
告诉gtags
默认C/C++/Java
等六种原生支持的代码直接使用gtags
本地分析器,而其他语言使用pygments
模块 - 第二个环境变量必须设置(在我的环境里,不设置也能work),否则会找不到
native-pygments
和language map
的定义
1 | " native-pygments 设置后会出现「gutentags: gtags-cscope job failed, returned: 1」,所以我把它换成了 native |
FAQ
:
global -d
找不到类定义,可能原因包括- final修饰的类,
gtags
找不到其定义,坑爹的bug,害我折腾了很久
- final修饰的类,
global -d
无法查找成员变量的定义
3.2.5 LSP-clangd (Recommend)
clangd
是LSP, Language Server Protocol
的一种实现,主要用于C/C++/Objective-C
等语言
3.2.6 LSP-ccls (Optional)
ccls
是LSP, Language Server Protocol
的一种实现,主要用于C/C++/Objective-C
等语言
安装:参照github官网文档进行编译安装即可
1 | git clone https://mirror.ghproxy.com/https://github.com/MaskRay/ccls.git |
如何为工程生成全量索引?
- 通过
cmake
等构建工具生成compile_commands.json
,并将该文件至于工程根目录下 - 配置
LSP-client
插件,我用的是LanguageClient-neovim
- vim打开工程,便开始自动创建索引
3.2.7 LSP-jdtls (Optional)
jdtls
是LSP, Language Server Protocol
的一种实现,主要用于Java
语言
安装:参照github官网文档进行编译安装即可
1 | git clone https://github.com/eclipse/eclipse.jdt.ls.git --depth 1 |
安装后的配置文件以及二进制都在./org.eclipse.jdt.ls.product/target/repository
目录中
- 运行日志默认在config目录中,例如
./org.eclipse.jdt.ls.product/target/repository/config_linux/
目录下
3.3 Color Scheme
3.3.1 gruvbox
Home: gruvbox
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
将gruvbox
中的配色方案(执行完:PlugInstall
才有这个文件哦)移动到vim指定目录下
1 | # ~/.vim/colors 目录默认是不存在的 |
3.3.2 solarized
Home: solarized
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
将solarized
中的配色方案(执行完:PlugInstall
才有这个文件哦)移动到vim指定目录下
1 | # ~/.vim/colors 目录默认是不存在的 |
3.4 vim-airline
Home: vim-airline
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.5 indentLine
Home: indentLine
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.6 nerdtree
Home: nerdtree
前言:coc.nvim
插件体系提供了coc-explore
,如果使用了coc.nvim
插件,就不需要其他的文件管理器了
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
:NERDTreeToggle
:打开文件管理器:NERDTreeFind
:打开文件管理器,并且定位到当前文件
3.7 vim-cpp-enhanced-highlight
Home: vim-cpp-enhanced-highlight
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.8 rainbow
Home: rainbow
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.9 vim-gutentags
Home: vim-gutentags
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
:GutentagsUpdate
:手动触发更新tags
问题排查步骤:
let g:gutentags_define_advanced_commands = 1
:允许gutentags
打开一些高级命令和选项- 运行
:GutentagsToggleTrace
:它会将ctags/gtags
命令的输出记录在vim的message
记录里 - 保存文件,触发数据库更新
:message
:可以重新查看message
常见问题:
gutentags: gtags-cscope job failed, returned: 1
- 原因1:由于
git
仓库切换分支,可能会导致gtagsdb
乱掉。而gutentags
会用gtags --incremental <gtagsdb-path>
这样的命令来更新gtagsdb
,这样可能会导致segment fault
,表象就是gutentags: gtags-cscope job failed, returned: 1
- 解决方式:修改
gutentags
源码,将--incremental
参数去掉即可。一键修改命令:sed -ri "s|'--incremental', *||g" ~/.vim/plugged/vim-gutentags/autoload/gutentags/gtags_cscope.vim
- 解决方式:修改
- 原因1:由于
- 如何禁用:
let g:gutentags_enabled = 0
let g:gutentags_dont_load = 1
3.9.1 gutentags_plus
Home: gutentags_plus
没有该插件时,我们一般按照如下方式使用gtags
set cscopeprg='gtags-cscope'
:让cscope
命令指向gtags-cscope
cscope add <gtags-path>/GTAGS
:添加gtagsdb
到cscope
中cscope find s <symbol>
:开始符号索引
该插件提供一个命令GscopeFind
,用于gtags
查询
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
键位映射说明:
keymap | desc |
---|---|
\gd |
查找光标下符号的定义 |
\gr |
查找光标下符号的引用 |
\ga |
查找光标下符号的赋值处 |
\gt |
查找光标下的字符串 |
\ge |
以egrep pattern 查找光标下的字符串 |
\gf |
查找光标下的文件名 |
\gi |
查找引用光标下头文件的文件 |
安装:进入vim界面后执行:PlugInstall
即可
3.9.2 vim-preview
Home: vim-preview
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
- 在
quickfix
中,按p
打开预览 - 在
quickfix
中,按P
关闭预览 D
:预览页向下滚动半页U
:预览页向上滚动半页
3.10 coc.nvim
Home: coc.nvim
该插件是作为LSP Client
,可以支持多种不同的LSP Server
编辑~/.vimrc
,添加Plug相关配置(公共配置)
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
:CocStart
:若在配置中取消了自启动,则需要手动开启:CocUpdate
:更新所有插件:CocConfig
:编辑配置文件,其路径为~/.vim/coc-settings.json
:CocAction
:代码生成:CocList [options] [args]
- 编辑模式
[Ctrl] + o
:切换到一般模式
- 一般模式
i/I/o/O/a/A
:进入编辑模式p
:开启或关闭预览窗口[Ctrl] + e
:向下滚动预览窗口中的内容[Ctrl] + y
:向上滚动预览窗口中的内容
- 编辑模式
:CocCommand <插件命令>
:CocCommand workspace.showOutput
:查看日志
相关路径:
~/.config/coc/extensions
:插件目录
配置文件~/.vim/coc-settings.json
的内容如下:
- 如何修改头文件搜索路径?在
compile_commands.json
或compile_flags.txt
中通过-I
参数指定即可 - 索引文件路径:
<project path>/.cache/clangd
- 在
cmake
中设置set(CMAKE_CXX_STANDARD 17)
,其生成的compile_commands.json
中包含的编译命令不会包含-std=gnu++17
参数,于是clangd
在处理代码中用到的c++17
新特性时会报warning
(例如Decomposition declarations are a C++17 extension (clang -Wc++17-extensions)
)。通过设置CMAKE_CXX_FLAGS
,加上编译参数-std=gnu++17
可以解决该问题- 仅仅设置
CMAKE_CXX_STANDARD
是不够的,还需要设置CMAKE_CXX_STANDARD_REQUIRED
,参考CMake’s set(CMAKE_CXX_STANDARD 11) does not work
- 仅仅设置
- 在
cmake
中设置set(CMAKE_CXX_COMPILER g++)
也不会对clangd
起作用,例如clang
没有-fopt-info-vec
这个参数,仍然会warning
clangd
使用的标准库搜索路径:由编译器决定,即compile_commands.json
中编译命令所使用的编译器决定。如果这个编译器是个低版本的,那么就会用低版本对应的头文件路径,高版本则对应高版本头文件路径
Tips
:
client coc abnormal exit with: 1
:大概率是node
有问题node
版本别太新也别太旧,v16
比较好
3.10.1 coc-explorer
Home: coc-explorer
coc-explorer
提供了类似于nerdtree
的文件管理器的功能,结构更清晰也更易用
安装:进入vim界面后执行:CocInstall coc-explorer
即可
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
使用:
?
:帮助文档j
:下移光标k
:上移光标h
:收起目录l
:展开目录或打开文件gh
:递归收起(全部收起)gl
:递归展开(全部展开)*
:选择/取消选择J
:选择/取消选择,并下移光标K
:选择/取消选择,并上移光标Il
:启用/关闭文件label
预览Ic
:启用/关闭文件内容预览q
:退出a
:新建文件A
:新建目录r
:重命名df/dF
:删除文件,df
放入回收站,dF
永久删除
符号:
?
:新文件,尚未纳入git
A
:新文件,已加入暂存区M
:文件已修改dim
:文件与上一个提交不一致bright
:文件与暂存区不一致
其他:
- 文件前面的数字是错误数量,可以通过
Il
查看查看完整的label
3.10.2 coc-java
Home: coc-java
Java
语言的LSP-Server
的实现是jdt.ls。而coc-java
是coc.nvim
的扩展,对jdt.ls
进行进一步的封装
安装:进入vim界面后执行:CocInstall coc-java
即可
- 安装路径:
~/.config/coc/extensions/node_modules/coc-java
- 数据路径:
~/.config/coc/extensions/coc-java-data
配置::CocConfig
,增加如下内容
1 | { |
使用:
:CocCommand workspace.showOutput java
:查看jdt.ls
日志"java.trace.server": "verbose"
:更详细的日志
:CocCommand java.open.serverLog
:查看jdt.ls
原始日志
Tips:
- 若项目用到了
thrift
或者protobuf
这些会创建源码的三方库。需要将这部分源码以及源码编译生成的.class
文件打包成.jar
文件,然后通过配置,告知jdt.ls
-
通过配置
java.project.referencedLibraries
,传入额外的jar路径。该配置好像无法起作用。Doesn’t recognize imports in classpath on a simple project提到将vim
换成neovim
可以解决,其他相关的issue
如下: -
通过配置
.classpath
,参考配置eclipse.jdt.ls/org.eclipse.jdt.ls.core/.classpath1
2
3
4
<classpath>
<classpathentry kind="lib" path="xxx.jar" sourcepath="xxx-source"/>
</classpath>- 假设子模块用到了
thrift
,那么需要在子模块的目录下放置.classpath
,而不是在工程根目录放置.classpath
- 假设子模块用到了
-
- 有插件
org.eclipse.m2e:lifecycle-mapping
的时候,jdt.ls
没法正常工作,目前暂未解决
3.10.3 coc-pyright
Home: coc-pyright
安装:进入vim界面后执行:CocInstall coc-pyright
即可
配置::CocConfig
,增加如下内容
python.analysis.typeCheckingMode
:禁用reportGeneralTypeIssues
等错误信息。python是动态类型的语言,静态类型推导的错误信息可以忽略
1 | { |
Tips:
- 用pip安装的三方库,pyright找不到
- 可以使用venv模块来构建隔离的python环境,步骤如下(
coc-pyright
官网)
1
2
3
4python3 -m venv .venv
source .venv/bin/activate
<install modules with pip and work with Pyright>
deactivate - 可以使用venv模块来构建隔离的python环境,步骤如下(
3.10.4 coc-rust-analyzer
Home: coc-rust-analyzer
安装:进入vim界面后执行:CocInstall coc-rust-analyzer
即可
- 确保
rust-analyzer
已经正常安装:rustup component add rust-analyzer
3.10.5 coc-snippets
Home: coc-snippets
coc-snippets
用于提供片段扩展功能(类似于IDEA
中的sout
、psvm
、.var
等等)
安装:进入vim界面后执行:CocInstall coc-snippets
即可
- 安装路径:
~/.config/coc/extensions/node_modules/coc-snippets
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
使用:
- 在编辑模式下,输入片段后,按
<c-e>
触发片段扩展 :CocList snippets
:查看所有可用的snippet
问题:
- 最新版本无法跳转到
fori
的类型占位符,转而使用另一个插件UltiSnips
3.10.5.1 vim-snippets
Home: vim-snippets
vim-snippets
插件提供了一系列snippet
的定义
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:与coc-snippets
自带snippet
的用法一致
3.10.6 coc-settings.json
1 | { |
coc.preferences.diagnostic.displayByAle
:是否以ALE
插件的模式进行显示diagnostic.virtualText
:是否显式诊断信息diagnostic.virtualTextPrefix
:诊断信息的前缀diagnostic.virtualTextCurrentLineOnly
:是否只显示光标所在行的诊断信息explorer.file.reveal.auto
:使用在文件管理器中高亮当前buffer
的所对应的文件suggest.noselect
:true/false
,表示自动补全时,是否自动选中第一个。默认为false
,即自动选中第一个,如果再按tab
则会跳转到第二个。Ability to tab to first option
3.11 LanguageClient-neovim
Home: LanguageClient-neovim
该插件是作为LSP Client
,可以支持多种不同的LSP Server
编辑~/.vimrc
,添加Plug相关配置(公共配置)
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可。由于安装时,还需执行一个脚本install.sh
,该脚本要从github下载一个二进制,在国内容易超时失败,可以用如下方式进行手动安装
1 | # 假定通过 :PlugInstall 已经将工程下载到本地了 |
用法:
:LanguageClientStart
:由于在上面的配置中取消了自启动,因此需要手动开启:LanguageClientStop
:关闭:call LanguageClient_contextMenu()
:操作菜单
键位映射说明:
keymap | desc |
---|---|
\rd |
查找光标下符号的定义 |
\rr |
查找光标下符号的引用 |
\rv |
查看光标下符号的说明 |
\rn |
重命名光标下的符号 |
\hb |
查找光标下符号的父类(ccls独有) |
\hd |
查找光标下符号的子类(ccls独有) |
3.11.1 C-Family
3.11.1.1 clangd
这里我们选用的LSP-Server
的实现是clangd
(推荐)
编辑~/.vimrc
,添加Plug相关配置(clangd
的特殊配置)
clangd
。相关配置参考LanguageClient-neovim/wiki/Clangdclangd
无法更改缓存的存储路径,默认会使用${project}/.cache
作为缓存目录clangd
会根据--compile-commands-dir
参数指定的路径查找compile_commands.json
,若查找不到,则在当前目录,以及每个源文件所在目录递归向上寻找compile_commands.json
1 | call plug#begin() |
3.11.1.2 ccls
这里我们选用的LSP-Server
的实现是ccls
(不推荐,大型工程资源占用太高,且经常性卡死)
编辑~/.vimrc
,添加Plug相关配置
ccls
。相关配置参考ccls-project-setupccls
会在工程的根目录寻找compile_commands.json
1 | call plug#begin() |
其中,~/.vim/languageclient.json
的内容示例如下(必须是决定路径,不能用~
)
ccls
可以通过如下配置更改缓存的存储路径
1 | { |
3.11.2 Java
这里我们选用的LSP-Server
的实现是jdtls, Eclipse JDT Language Server
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
创建完整路径为/usr/local/bin/jdtls
的脚本,内容如下:
1 |
|
问题:
- 无法访问JDK以及三方库中的类
- 对于Maven项目,若在标准的目录结构中有额外的目录,例如
<project-name>/src/main/<extra_dir>/com
,那么jdt.ls
无法自动扫描整个工程,除非手动打开文件,才会把该文件加入解析列表中
3.12 vimspector
Home: vimspector
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
- 页面布局
Variables and scopes
:左上角。回车用于展开和收起Watches
:左中。进入编辑模式,输入表达式按回车可新增Watch
;删除键可删除Watch
StackTrace
:左下角。按回车可展开线程堆栈Console
:标准输出,标准错误
- 对于每个项目,我们都需要在项目的根目录提供一个
.vimspector.json
,来配置项目相关的debug
参数configurations.<config_name>.default: true
,是否默认使用该配置。如果有多个配置项的话,不要设置这个C-Family
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34{
"configurations": {
"C-Family Launch": {
"adapter": {
"extends": "vscode-cpptools",
"sync_timeout": 100000,
"async_timeout": 100000
},
"filetypes": ["cpp", "c", "objc", "rust"],
"configuration": {
"request": "launch",
"program": "<path to binary>",
"args": [],
"cwd": "<working directory>",
"environment": [],
"externalConsole": true,
"MIMode": "gdb"
}
},
"C-Family Attach": {
"adapter": {
"extends": "vscode-cpptools",
"sync_timeout": 100000,
"async_timeout": 100000
},
"filetypes": ["cpp", "c", "objc", "rust"],
"configuration": {
"request": "attach",
"program": "<path to binary>",
"MIMode": "gdb"
}
}
}
}
3.12.1 coc-java-debug
Home: coc-java-debug
coc-java-debug
依赖coc.nvim
、coc-java
以及vimspector
- 通过
coc.nvim
来安装、卸载插件,其接口通过CocCommand
对外露出 coc-java-debug
是vimspector
的adapter
安装:进入vim界面后执行:CocInstall coc-java-debug
即可
使用:
:CocCommand java.debug.vimspector.start
- 对于每个项目,我们都需要在项目的根目录提供一个
.vimspector.json
,来配置项目相关的debug
参数adapters.java-debug-server.port
:是java-debug-server
启动时需要占用的端口号,这里填占位符,在启动时会自动为其分配一个可用的端口号configurations.<config_name>.configuration.port
:对应Java
程序的debug
端口号configurations.<config_name>.configuration.projectName
:对应pom.xml
的项目名称。Debugging Java with JDB or Vim。如果这个参数对不上的话,那么在Watches
页面添加Watch
时,会报如下的错误- 未设置该参数时:
Result: Cannot evaluate because of java.lang.IllegalStateException: Cannot evaluate, please specify projectName in launch.json
- 填写错误的项目名称时:
Result: Cannot evaluate because of java.lang.IllegalStateException: Project <wrong name> cannot be found
- Visual Studio Code projectName
- Debugger for Java
- 未设置该参数时:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29{
"adapters": {
"java-debug-server": {
"name": "vscode-java",
"port": "${AdapterPort}"
}
},
"configurations": {
"Java Attach": {
"adapter": {
"extends": "java-debug-server",
"sync_timeout": 100000,
"async_timeout": 100000
},
"configuration": {
"request": "attach",
"host": "127.0.0.1",
"port": "5005",
"projectName": "${projectName}"
},
"breakpoints": {
"exception": {
"caught": "N",
"uncaught": "N"
}
}
}
}
}
3.13 Copilot.vim
Home: Copilot.vim
Getting started with GitHub Copilot
OpenAI
加持的自动补全,可以根据函数名补全实现
版本要求:
Neovim
Vim >= 9.0.0185
编辑~/.vimrc
,添加Plug相关配置(公共配置)
1 | call plug#begin() |
用法:
-
Login & Enable
1
2:Copilot setup
:Copilot enable -
:help copilot
3.14 Code Completion
前言:coc.nvim
插件体系提供了大部分语言的代码补全功能,如果使用了coc.nvim
插件,就不需要使用下面的这些补全插件了
3.14.1 YouCompleteMe
Home: YouCompleteMe
这个插件比较复杂,建议手工安装
1 | # 定义一个函数,用于调整github的地址,加速下载过程,该函数会用到多次 |
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
ycm
如何解析代码:
- 使用
compilation database
:如果当前目录下存在compile_commands.json
, 则读取该文件,对代码进行编译解析 .ycm_extra_conf.py
:若没有compilation database
,那么ycm
会在当前目录递归向上寻找并加载第一个.ycm_extra_conf.py
文件,如果都找不到,则加载全局配置(如果配置了g:ycm_global_ycm_extra_conf
参数的话)
配置~/.ycm_extra_conf.py
,内容如下(仅针对c/c++,对大部分简单的工程均适用),仅供参考
1 | def Settings(**kwargs): |
安装:进入vim界面后执行:PlugInstall
即可
使用:
- 默认情况下,只能进行通用补全,比如将文件中已经出现的字符加入到字典中,这样如果编写同样的字符串的话,就能够提示补全了
- 如果要进行语义补全,可以结合
compile_commands.json
,通过cmake
等构建工具生成compile_commands.json
,并将该文件至于工程根目录下。再用vim打开工程便可进行语义补全 [Ctrl] + n
:下一个条目[Ctrl] + p
:上一个条目
3.14.2 vim-javacomplete2
Home: vim-javacomplete2
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.15 AsyncRun
Home: AsyncRun
本质上,AsyncRun
插件就是提供了异步执行命令的机制,我们可以利用这个机制定义一些动作,比如编译
、构建
、运行
、测试
等,提供类似于IDE
的体验
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.16 ALE
Home: ALE
前言:coc.nvim
插件体系提供了大部分语言的错误诊断功能,如果使用了coc.nvim
插件,就不需要使用其他的错误诊断插件了
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
:ALEInfo
:查看配置信息,拉到最后有命令执行结果- 如何配置
C/C++
项目:不同C/C++
项目的结构千差万别,构建工具也有很多种,因此ALE
很难得知需要用什么编译参数来编译当前文件。因此ALE
会尝试读取工程目录下的compile_commands.json
文件,并以此获取编译参数 - 指定三方库的头文件路径。每种类型的编译器对应的环境变量名是不同的,这里仅以
gcc
和g++
为例export C_INCLUDE_PATH=${C_INCLUDE_PATH}:<third party include path...>
export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}:<third party include path...>
问题:
- 若
linter
使用的是gcc
或者g++
,即便有语法错误,也不会有提示信息。但是使用:ALEInfo
查看,是可以看到报错信息的。这是因为ALE识别错误是通过一个关键词error
,而在我的环境中,gcc编译错误输出的是中文错误
,因此ALE不认为这是个错误。修改方式如下mv /usr/share/locale/zh_CN/LC_MESSAGES/gcc.mo /usr/share/locale/zh_CN/LC_MESSAGES/gcc.mo.bak
mv /usr/local/share/locale/zh_CN/LC_MESSAGES/gcc.mo /usr/local/share/locale/zh_CN/LC_MESSAGES/gcc.mo.bak
- 如果找不到
gcc.mo
文件的话,可以用locate
命令搜索一下
3.17 vim-signify
Home: vim-signify
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
set signcolumn=yes
,有改动的行会标出:SignifyDiff
:以左右分屏的方式对比当前文件的差异
3.18 textobj-user
Home: textobj-user
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
使用:
ia/aa
:参数对象。可以用via/vaa
/dia/daa
/cia/caa
来选中/删除/改写当前参数ii/ai
:缩进对象。可以用vii/vai
/dii/dai
/cii/cai
来选中/删除/改写同一缩进层次的内容if/af
:函数对象。可以用vif/vaf
/dif/daf
/cif/caf
来选中/删除/改写当前函数的内容
3.19 LeaderF
Home: LeaderF
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
- 依赖
ctags
用法:
:LeaderfFunction!
:弹出函数列表:LeaderfMru
:查找最近访问的文件,通过上面的配置映射到快捷键[Ctrl] + n
- 通过上面的配置,将文件模糊搜索映射到快捷键
[Ctrl] + p
- 搜索模式,输入即可进行模糊搜索
tab
:切换到普通模式,普通模式下,可以通过j/k
上下移动<c-r>
:在fuzzy search mode
以及regex mode
之间进行切换<c-f>
:在full path search mode
以及name only search mode
之间进行切换<c-u>
:清空搜索内容<c-j>/<c-k>
:上下移动<c-a>
:选中所有<c-l>
:清除选中<c-s>
:选中当前文件<c-t>
:在新的tab
中打开选中的文件<c-p>
:预览
3.20 fzf.vim
Home: fzf.vim
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
- 安装会额外执行
~/.vim/plugged/fzf/install
这个脚本,来下载fzf
的二进制,如果长时间下载不下来的话,可以改成代理地址后(在脚本中搜索github
关键词,加上https://mirror.ghproxy.com/
前缀),再手动执行脚本进行下载安装
用法(搜索相关的语法可以参考junegunn/fzf-search-syntax):
[Ctrl] + j/k
/[Ctrl] + n/p
:以行为单位上下移动PageUp/PageDown
:以页为单位上下移动- 匹配规则
xxx
:模糊匹配(可能被分词)'xxx
:非模糊匹配(不会被分词)^xxx
:前缀匹配xxx$
:后缀匹配!xxx
:反向匹配- 上述规则均可自由组合
- 如何精确匹配一个包含空格的字符串:
'Hello\ world
。由于常规的空格被用作分词符,因此空格前要用\
进行转义
3.21 vim-grepper
Home: vim-grepper
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
:Grepper
:进行全局搜索(依赖grep命令)
3.22 vim-fugitive
Home: vim-fugitive
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
:Git
:作为git
的替代,后跟git
命令行工具的正常参数即可
3.23 nerdcommenter
Home: nerdcommenter
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
\cc
:添加注释,对每一行都会添加注释\cm
:对被选区域用一对注释符进行注释\cs
:添加性感的注释\ca
:更换注释的方式\cu
:取消注释\c<space>
:如果被选区域有部分被注释,则对被选区域执行取消注释操作,其它情况执行反转注释操作
3.24 vim-codefmt
Home: vim-codefmt
支持各种格式化工具:
C-Family
:clang-format
CSS
/Sass
/SCSS
/Less
:js-beautify
JSON
:js-beautify
HTML
:js-beautify
Go
:gofmt
Java
:google-java-format
/clang-format
Python
:Autopep8
/Black
/YAPF
Shell
:shfmt
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
:FormatCode
:格式化:Glaive codefmt
:查看配置(也可以通过:help codefmt
查看所有配置项)clang_format_executable
:clang_format
可执行文件路径,可以通过Glaive codefmt clang_format_executable="clang-format-10"
进行修改
安装Python
的格式化工具autopep8
1 | pip install --upgrade autopep8 |
安装Perl
的格式化工具perltidy
-
cpan install Perl::Tidy
-
brew install perltidy
-
perltidy
相关的pull request
尚未合入,需要自行合入,Add perl formatting support using Perltidy,步骤如下:1
2git fetch origin pull/227/head:pull_request_227
git rebase pull_request_227- 或者,如果不想这么做,可以用如下方式暂时代替:
1
2
3
4
5
6
7
8
9" 配置 perl 的格式化,需要用 gg=G 进行格式化
" https://superuser.com/questions/805695/autoformat-for-perl-in-vim
" 通过 cpan Perl::Tidy 安装 perltidy
autocmd FileType perl setlocal equalprg=perltidy\ -st\ -ce
if has('nvim')
autocmd FileType perl nnoremap <silent><buffer> <c-l> gg=G<c-o>
else
autocmd FileType perl nnoremap <silent><buffer> <c-l> gg=G<c-o><c-o>
endif
- 或者,如果不想这么做,可以用如下方式暂时代替:
安装json
的格式化工具js-beauty
npm -g install js-beautify
3.25 vim-surround
Home: vim-surround
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
用法:
- 完整用法参考
:help surround
cs
:cs, change surroundings
,用于替换当前文本的环绕符号cs([
cs[{
cs{<q>
ds
:ds, delete surroundings
,用于删除当前文本的环绕符号ds{
ds<
ds<q>
ys
:you surround
,用于给指定文本加上环绕符号。文本指定通常需要配合文本对象一起使用ysiw[
:iw
是文本对象ysa"fprint
:其中a"
是文本对象,f
表示用函数调用的方式环绕起来,print
是函数名。形式为print(<text>)
ysa"Fprint
:类似ysa"fprint
,F
表示会在参数列表前后多加额外的空格。形式为print( <text> )
ysa"<c-f>print
:类似ysa"fprint
,<c-f>
表示环绕符号加到最外侧。形式为(print <text>)
yss
:给当前行加上环绕符号(不包含leading whitespace
和trailing whitespace
)yss(
yssb
yss{
yssB
yS
:类似ys
,但会在选中文本的前一行和后一行加上环绕符号ySiw[
:iw
是文本对象
ySS
:类似yes
,但会在选中文本的前一行和后一行加上环绕符号ySS(
ySSb
ySS{
ySSB
[visual]S
:用于给visual mode
选中的文本加上环绕符号vllllS'
:其中,v
表示进入visual
模式,llll
表示向右移动4个字符vllllSfprint
:其中,v
表示进入visual
模式,llll
表示向右移动4个字符,f
表示用函数调用的方式环绕起来,print
是函数名。形式为print(<text>)
vllllSFprint
:类似vllllSfprint
,F
表示会在参数列表前后多加额外的空格。形式为print( <text> )
vllllS<c-f>print
:类似vllllSfprint
,<c-f>
表示环绕符号加到最外侧。形式为(print <text>)
3.26 UltiSnips
Home: UltiSnips
UltiSnips is the ultimate solution for snippets in Vim.
编辑~/.vimrc
,添加Plug相关配置
1 | call plug#begin() |
安装:进入vim界面后执行:PlugInstall
即可
3.27 My Full Settings
1 | " 加载额外的配置 |
4 vim-script
4.1 Tips
filereadable
无法识别~
,需要用expand
,例如filereadable(expand('~/.vim/gtags.vim'))
- 函数名要用大写字母开头,或者
s:
开头。大写字母开头表示全局可见,s:
开头表示当前脚本可见 exists('&cscopequickfix')
:判断是否存在参数cscopequickfix
has('nvim')
:判断是否启用了某功能
5 nvim
5.1 Install
1 | git clone https://github.com/neovim/neovim.git |
Or Install from Nvim development (prerelease) build (Prefer)
1 | wget https://github.com/neovim/neovim/releases/download/v0.9.5/nvim-linux64.tar.gz |
5.1.1 Node Version Management
nvm:
1 | nvm ls-remote |
1 | npm install -g n |
5.2 config path
1 | " ~/.config/nvim |
5.3 nvim share configuration of vim
nvim
和vim
使用不同的目录来管理配置文件,通过软连接就可以实现共享配置,如下:
1 | # nvim's config file is ~/.config/nvim/init.vim |
5.4 Tips
:intro
- 可能会提示
Vimspector unavailable: Requires Vim compiled with +python3
之类的问题::checkhealth
进行自检,这里会提示安装pynvim
let g:python3_host_prog = '/path/to/your/python3'
- 在一个新的环境,安装完
nvim
后,最好都用checkhealth
检查一遍,否则很多插件可能会因为依赖python
等模块而无法正常工作,例如LeaderF
node
用16.19
版本,可以用nvm install v16.19.0
进行安装
6 Tips
6.1 Large Files Run Slowly
禁止加载所有插件
1 | vim -u NONE <big file> |
6.2 Export Settings
Example 1
1 | :redir! > vim_keys.txt |
Example 2
1 | :redir! > vim_settings.txt |
6.3 Save and Exit Slowly in Large Project
在大型工程中文件保存退出非常慢,发现是vim-gutentags
插件,及其相关配置导致的。在项目配置文件.workspace.vim
中添加如下内容进行禁用:
1 | let g:gutentags_enabled = 0 |
7 Reference
- 《Vim 中文速查表》
- 如何在 Linux 下利用 Vim 搭建 C/C++ 开发环境?
- Vim 8 中 C/C++ 符号索引:GTags 篇
- Vim 8 中 C/C++ 符号索引:LSP 篇
- 三十分钟配置一个顺滑如水的 Vim
- CentOS Software Repo
- 《Vim 中文版入门到精通》
- VimScript 五分钟入门(翻译)
- 使用 Vim 搭建 Java 开发环境
- 如何优雅的使用 Vim(二):插件介绍
- 打造 vim 编辑 C/C++ 环境
- Vim2021:超轻量级代码补全系统
- How To Install GCC on CentOS 7
- 8.x版本的gcc以及g++
- VIM-Plug安装插件时,频繁更新失败,或报端口443被拒绝等
- Cannot find color scheme ‘gruvbox’ #85
- 《鸟哥的Linux私房菜》
- Mac 的 Vim 中 delete 键失效的原因和解决方案
- 解决linux下vim中文乱码的方法
- vim-set命令使用
- 解決 ale 的 gcc 不顯示錯誤 | 把 gcc 輸出改成英文
- Mapping keys in Vim - Tutorial
- centos7 安装GNU GLOBAL
- The Vim/Cscope tutorial
- GNU Global manual
- Vim Buffers, Windows and Tabs — an overview