阅读更多
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
Character-wise Movement:
j
/[n]j
: Move down by 1/n line.k
/[n]k
: Move up by 1/n line.h
/[n]h
: Move left by 1/n character.l
/[n]l
: Move right by 1/n character.f<x>
/[n]f<x>
: Move to the next 1/n occurrence of<x>
in the current line.F<x>
/[n]F<x>
: Move to the previous 1/n occurrence of<x>
in the current line.t<x>
/[n]t<x>
: Move to just before the next 1/n occurrence of<x>
in the current line.T<x>
/[n]T<x>
: Move to just after the previous next 1/n occurrence of<x>
in the current line.;
: Repeat the lastf/F/t/T
command.,
: Repeat the lastf/F/t/T
command in the opposite direction.
[n][space]
: Move right by n character.0
: Move to the beginning of the line.^
: Move to the first non-blank character of the line.$
: Move to the end of the line.g_
: Move to the last non-blank character of the line.gm
: Move to the middle character of the line.
Word-wise Movement:
w
: Move to the start of the next word.W
: Move to the start of the next word (words are delimited by spaces).e
: Move to the end of the next word.E
: Move to the end of the next word (words are delimited by spaces).b
: Move to the beginning of the previous word.B
: Move to the beginning of the previous word (words are delimited by spaces).ge
: Move to the end of the previous word.gE
: Move to the end of the previous word (words are delimited by spaces).
Line-wise Movement:
gj
: Move down by one visual line (It works with wrapped lines).gk
: Move up by one visual line (It works with wrapped lines).+
: Move to the first non-blank character of the next line.-
: Move to the first non-blank character of the previous line.G
: Move to the last line of the file.[n]G
: Move to a specific line<n>
.gg
: Move to the first line of the file.[n][Enter]
: Move to the next n lines.H
: Move to the top of the screen.M
: Move to the middle of the screen.L
: Move to the bottom of the screen.
Screen-wise Movement:
<c-f>
: Move forward by one full screen.<c-b>
: Move backward by one full screen.<c-d>
: Move down by half a screen.<c-u>
: Move up by half a screen.<c-e>
: Scroll the screen down by one line.<c-y>
: Scroll the screen up by one line.zz
: Put the current line in the middle of the screen.zt
: Put the current line in the top of the screen.zb
: Put the current line in the bottom of the screen.
Paragraph and Section Movement:
)
: Move to next sentence.(
: Move to previous sentence.}
: Move to next paragraph.{
: Move to previous paragraph.])
: Move to next unmatched)
.[(
: Move to previous unmatched(
.]}
: Move to next unmatched}
.[{
: Move to previous unmatched{
.]m
: Move to next start of a method.[m
: Move to previous start of a method.]M
: Move to next end of a method.[M
: Move to previous end of a method.%
: Move to matched of{} () []
.- You can add recognition for angle brackets
<>
by using:set matchpairs+=<:>
. It may cause misrecognition, as the text may contain single>
or<
.
- You can add recognition for angle brackets
=
: Adjust indent.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.2.3 Mark
m<letter>
: Set a mark. Lowercase for local mark, uppercase for global mark.'<letter>
: Jump to a mark.
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
:map <c-l>
:map <f5>
:map \rn
: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
或者:so %
来重新加载~/.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
3.1.1.1 vim-plug
Home: vim-plug
Install:
1 | curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ |
Usage:
-
Config
1
2
3
4
5
6call plug#begin()
" List your plugins here
Plug 'tpope/vim-sensible'
call plug#end() -
:PlugStatus
-
:PlugInstall
-
:PlugClean
Update source(~/.vim/autoload/plug.vim
):
1 | " Change |
How to install plugins from different sources:
- Option 1: Specify the full URL of the plugin. For example, change
Plug 'morhetz/gruvbox'
toPlug 'https://github.com/morhetz/gruvbox'
. - Option 2: Disable
URI
validation. By default,Plug
does not allow plugins from different sources. To disable this feature, modify~/.vim/autoload/plug.vim
as follows:1
2
3
4
5
6
7
8
9
10" Delete following code snippet
elsif !compare_git_uri(current_uri, uri)
[false, ["Invalid URI: #{current_uri}",
"Expected: #{uri}",
"PlugClean required."].join($/)]
" Delete following code snippet
elseif !s:compare_git_uri(remote, a:spec.uri)
let err = join(['Invalid URI: '.remote,
\ 'Expected: '.a:spec.uri,
\ 'PlugClean required.'], "\n")
3.1.1.2 packer.nvim
Home: packer.nvim
Install:
1 | git clone --depth 1 https://github.com/wbthomason/packer.nvim\ |
Configuration:
-
~/.config/nvim/init.vim
1
2
3if has('nvim')
lua require('packer-plugins')
endif -
~/.config/nvim/lua/packer-plugins.lua
1
2
3
4
5
6
7
8vim.cmd [[packadd packer.nvim]]
return require('packer').startup(function(use)
-- Packer can manage itself
use 'wbthomason/packer.nvim'
-- Your plugins
end)
Usage:
PackerCompile
: You must run this orPackerSync
whenever you make changes to your plugin configuration. Regenerate compiled loader file.PackerClean
: Remove any disabled or unused plugins.PackerInstall
: Clean, then install missing plugins.PackerStatus
: Show list of installed 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 |
Usage:
[Ctrl] + ]
:跳转到符号定义处。如果有多条匹配项,则会跳转到第一个匹配项[Ctrl] + w + ]
:在新的窗口中跳转到符号定义处。如果有多条匹配项,则会跳转到第一个匹配项:ts
:显示所有的匹配项。按ECS
再输入序号,再按Enter
就可以进入指定的匹配项:tn
:跳转到下一个匹配项:tp
:跳转到上一个匹配项g + ]
:如果有多条匹配项,会直接显式(同:ts
)
Configuration(~/.vimrc
):
- 注意,这里将tag的文件名从
tags
换成了.tags
,这样避免污染项目中的其他文件。因此在使用ctags
命令生成tag文件时,需要通过-f .tags
参数指定文件名 ./.tags;
表示在文件所在目录下查找名字为.tags
的符号文件,;
表示查找不到的话,向上递归到父目录,直到找到.tags
或者根目录.tags
是指在vim的当前目录(在vim中执行:pwd
)下查找.tags
文件
1 | " tags search mode |
3.2.3 Symbol-cscope (Optional)
Home: cscope
相比于ctags
,cscope
支持更多功能,包括查找定义、查找引用等等。但是该项目最近一次更新是2012年,因此不推荐使用。推荐使用gtags
Install:
1 | wget -O cscope-15.9.tar.gz 'https://sourceforge.net/projects/cscope/files/latest/download' --no-check-certificate |
如何使用命令行工具:
1 | # 创建索引,该命令会在当前目录生成一个名为cscope.out索引文件 |
如何在vim中使用
1 | " 添加数据库 |
Configuration(~/.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 | # 把头文件也当成源文件进行解析,否则可能识别不到头文件中的符号 |
Configuration(~/.vimrc
):
- 第一个
GTAGSLABEL
告诉gtags
默认C/C++/Java
等六种原生支持的代码直接使用gtags
本地分析器,而其他语言使用pygments
模块 - 第二个环境变量必须设置(在我的环境里,不设置也能work),否则会找不到
native-pygments
和language map
的定义
1 | " Setting native-pygments causes "gutentags: gtags-cscope job failed, returned: 1", so I changed it to 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
Configuration(~/.vimrc
):
1 | call plug#begin() |
Install:
1 | # ~/.vim/colors not exist by default |
3.3.2 solarized
Home: solarized
Configuration(~/.vimrc
):
1 | call plug#begin() |
Install:
1 | # ~/.vim/colors not exist by default |
3.3.3 catppuccin
Home: catppuccin/nvim
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { "catppuccin/nvim", as = "catppuccin" } |
3.3.4 Trending Neovim Colorschemes
3.4 Dashboard
Suggest me some startup screen plugins
3.4.1 dashboard-nvim
Home: dashboard-nvim
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { |
FAQ:
- It has compatible issue with LeaderF, every time use LeaderF, the bottom line go up by one line.
3.4.2 alpha-nvim
Home: alpha-nvim
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { |
3.5 vim-airline
Home: vim-airline
Configuration(~/.vimrc
):
1 | call plug#begin() |
3.6 lazy.nvim tools
3.6.1 noice.nvim
Home: noice.nvim
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { |
3.6.2 which-key
Home: which-key
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { |
3.7 indentLine
Home: indentLine
Configuration(~/.vimrc
):
1 | call plug#begin() |
3.8 Highlighting
3.8.1 nvim-treesitter
Home: nvim-treesitter
Configuration(~/.config/nvim/lua/packer-plugins.lua
):
1 | use { |
Usage:
:TSInstall <language_to_install>
:TSInstallInfo
3.8.2 vim-cpp-enhanced-highlight
Home: vim-cpp-enhanced-highlight
Configuration(~/.vimrc
):
1 | call plug#begin() |
3.9 coc.nvim
Home: coc.nvim
This plugin serves as an LSP Client
and can support multiple different LSP Servers
.
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:CocStart
:若在配置中取消了自启动,则需要手动开启:CocUpdate
:更新所有插件:CocConfig
:编辑配置文件,其路径为~/.vim/coc-settings.json
:CocAction
:代码生成:CocInfo
:CocList [options] [args]
:CocList extensions
- Operation
- 编辑模式
[Ctrl] + o
:切换到一般模式
- 一般模式
i/I/o/O/a/A
:进入编辑模式p
:开启或关闭预览窗口[Ctrl] + e
:向下滚动预览窗口中的内容[Ctrl] + y
:向上滚动预览窗口中的内容
- 编辑模式
:CocCommand <插件命令>
:CocCommand workspace.showOutput
:查看日志
Paths:
~/.config/coc/extensions
:插件目录
Help Doc(:help coc-nvim
):
:help coc-inlayHint
FAQ:
client coc abnormal exit with: 1
:大概率是node
有问题node
版本别太新也别太旧,v16
比较好clangd
版本16以上,支持展开宏定义(K
)- 如何修改头文件搜索路径?在
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
中编译命令所使用的编译器决定。如果这个编译器是个低版本的,那么就会用低版本对应的头文件路径,高版本则对应高版本头文件路径
3.9.1 coc-explorer
Home: coc-explorer
Install:
:CocInstall coc-explorer
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
?
:帮助文档j
:下移光标k
:上移光标h
:收起目录l
:展开目录或打开文件gh
:递归收起(全部收起)gl
:递归展开(全部展开)*
:选择/取消选择J
:选择/取消选择,并下移光标K
:选择/取消选择,并上移光标Il
:启用/关闭文件label
预览Ic
:启用/关闭文件内容预览q
:退出a
:新建文件A
:新建目录r
:重命名df/dF
:删除文件,df
放入回收站,dF
永久删除- Symbols:
?
:新文件,尚未纳入git
A
:新文件,已加入暂存区M
:文件已修改dim
:文件与上一个提交不一致bright
:文件与暂存区不一致
- Assorted:
- 文件前面的数字是错误数量,可以通过
Il
查看查看完整的label
- 文件前面的数字是错误数量,可以通过
3.9.2 coc-java
Home: coc-java
Java
语言的LSP-Server
的实现是jdt.ls。而coc-java
是coc.nvim
的扩展,对jdt.ls
进行进一步的封装
Install:
:CocInstall coc-java
- 安装路径:
~/.config/coc/extensions/node_modules/coc-java
- 数据路径:
~/.config/coc/extensions/coc-java-data
Configuration(:CocConfig
)
1 | { |
Usage:
: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.9.3 coc-pyright
Home: coc-pyright
Install:
:CocInstall coc-pyright
Configuration(: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环境,步骤如下(
-
格式化import
CocCommand pyright.organizeimports
3.9.4 coc-rust-analyzer
Home: coc-rust-analyzer
Install:
:CocInstall coc-rust-analyzer
- 确保
rust-analyzer
已经正常安装:rustup component add rust-analyzer
3.9.5 coc-snippets
Home: coc-snippets
coc-snippets
用于提供片段扩展功能(类似于IDEA
中的sout
、psvm
、.var
等等)
Install:
:CocInstall coc-snippets
- 安装路径:
~/.config/coc/extensions/node_modules/coc-snippets
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
- 在编辑模式下,输入片段后,按
<c-e>
触发片段扩展 :CocList snippets
:查看所有可用的snippet
FAQ:
- 最新版本无法跳转到
fori
的类型占位符,转而使用另一个插件UltiSnips
3.9.5.1 vim-snippets
Home: vim-snippets
vim-snippets
插件提供了一系列snippet
的定义
Configuration(~/.vimrc
):
1 | call plug#begin() |
使用:与coc-snippets
自带snippet
的用法一致
3.9.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 optioninlayHint.display
:是否默认显示inlayHint
3.10 vimspector
Home: vimspector
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
- 页面布局
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": "<absolute path to binary>",
"args": [],
"cwd": "<absolute 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": "<absolute path to binary>",
"MIMode": "gdb"
}
}
}
}
3.10.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
即可
Usage:
: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.11 Copilot.vim
Home: Copilot.vim
Getting started with GitHub Copilot
OpenAI
加持的自动补全,可以根据函数名补全实现
版本要求:
Neovim
Vim >= 9.0.0185
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
-
Login & Enable
1
2:Copilot setup
:Copilot enable -
:help copilot
3.12 textobj-user
Home: textobj-user
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
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.13 LeaderF
Home: LeaderF
Configuration(~/.vimrc
):
1 | call plug#begin() |
- 依赖
ctags
Usage:
: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>
:预览
- 不起作用,可能是
python
的问题:checkhealth
3.14 fzf.vim
Home: fzf.vim
Configuration(~/.vimrc
):
1 | call plug#begin() |
- 安装会额外执行
~/.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.15 Git Plugins
3.15.1 vim-fugitive
Home: vim-fugitive
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:Git
:作为git
的替代,后跟git
命令行工具的正常参数即可
3.15.2 diffview.nvim
Home: diffview.nvim
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:DiffviewOpen
:DiffviewOpen HEAD~2
:DiffviewOpen <commit>
3.16 nerdcommenter
Home: nerdcommenter
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
\cc
:添加注释,对每一行都会添加注释\cm
:对被选区域用一对注释符进行注释\cs
:添加性感的注释\ca
:更换注释的方式\cu
:取消注释\c<space>
:如果被选区域有部分被注释,则对被选区域执行取消注释操作,其它情况执行反转注释操作
3.17 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
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
: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.18 vim-surround
Home: vim-surround
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
- 完整用法参考
:help surround
cs
:cs, change surroundings
,用于替换当前文本的环绕符号cs([
cs[{
cs{<q>
cs{>
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.19 UltiSnips
Home: UltiSnips
UltiSnips is the ultimate solution for snippets in Vim.
Configuration(~/.vimrc
):
1 | call plug#begin() |
3.20 vim-wordmotion
Home: vim-wordmotion
Configuration(~/.vimrc
):
1 | call plug#begin() |
3.21 Complete Configuration
3.21.1 ~/.vimrc
or ~/.config/nvim/init.vim
1 | " Load extra config (pre step) |
3.21.2 ~/.config/nvim/lua/packer-plugins.lua
mkdir -p ~/.config/nvim/lua
1 | vim.cmd [[packadd packer.nvim]] |
4 Legacy Plugins
These are the plugins I have eliminated.
4.1 nerdtree
Home: nerdtree
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:NERDTreeToggle
: Open the file manager.:NERDTreeFind
: Open the file manager, and locate the current file.
4.2 vim-gutentags
Home: vim-gutentags
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:GutentagsUpdate
: Manually trigger tag updates.
Trouble-shooting:
let g:gutentags_define_advanced_commands = 1
: Allowsgutentags
to enable some advanced commands and options- Run
:GutentagsToggleTrace
: It will log the output ofctags/gtags
commands in vim’smessage
loglet g:gutentags_trace = 1
: Provides similar functionality
- Save the file to trigger a database update
:message
: Allows you to review the message log again
FAQ:
gutentags: gtags-cscope job failed, returned: 1
- Reason 1: Switching branches in a
git
repository may cause thegtagsdb
to become corrupted.gutentags
uses a command likegtags --incremental <gtagsdb-path>
to update thegtagsdb
, which can result in a segmentation fault. This issue manifests asgutentags: gtags-cscope job failed, returned: 1
.- Solution: Modify the
gutentags
source code to remove the--incremental
parameter. Use the following command to modify it in one step:sed -ri "s|'--incremental', *||g" ~/.vim/plugged/vim-gutentags/autoload/gutentags/gtags_cscope.vim
- Solution: Modify the
- Reason 1: Switching branches in a
gutentags: ctags job failed, returned: 1
- Reason 1: The installed version of ctags is too old. Reinstall a newer version.
- How to disable:
let g:gutentags_enabled = 0
let g:gutentags_dont_load = 1
4.2.1 gutentags_plus
Home: gutentags_plus
Without this plugin, we typically use gtags
in the following way:
set cscopeprg='gtags-cscope'
: Set thecscope
command to point togtags-cscope
cscope add <gtags-path>/GTAGS
: Add thegtagsdb
tocscope
cscope find s <symbol>
: Start symbol indexing
The plugin provides a command GscopeFind
for gtags
queries.
Configuration(~/.vimrc
):
1 | call plug#begin() |
Keymap Explanation:
Keymap | Description |
---|---|
\gd |
Find the definition of the symbol under the cursor |
\gr |
Find references to the symbol under the cursor |
\ga |
Find assignments to the symbol under the cursor |
\gt |
Find the string under the cursor |
\ge |
Search the string under the cursor using egrep pattern |
\gf |
Find the filename under the cursor |
\gi |
Find files that include the header under the cursor |
4.2.2 vim-preview
Home: vim-preview
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
- In
quickfix
, pressp
to open the preview - In
quickfix
, pressP
to close the preview D
: Scroll down half a page in the previewU
: Scroll up half a page in the preview
4.2.3 rainbow
Home: rainbow
Configuration(~/.vimrc
):
1 | call plug#begin() |
4.3 ALE
Home: ALE
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:ALEInfo
: View configuration information; scroll to the bottom to see the command execution results- How to configure
C/C++
projects: DifferentC/C++
projects vary greatly in structure, and there are many build tools available. As a result, it’s difficult forALE
to determine the correct compilation parameters for the current file. Therefore,ALE
will try to read thecompile_commands.json
file in the project directory to obtain the necessary compilation parameters. - Specify the header file path for third-party libraries. The environment variable name varies for different types of compilers. Here is an example using
gcc
andg++
:export C_INCLUDE_PATH=${C_INCLUDE_PATH}:<third party include path...>
export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}:<third party include path...>
FAQ:
- If the
linter
usesgcc
org++
, even with syntax errors, no warning messages will appear. However, by using:ALEInfo
, you can see the error messages. This happens because ALE identifies errors by the keyworderror
, but in my environment,gcc
outputs compilation errors in Chinese as错误
. As a result, ALE does not recognize these as errors. The solution is as follows: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
- If you cannot find the
gcc.mo
file, you can use thelocate
command to search for it.
4.4 LanguageClient-neovim
Home: LanguageClient-neovim
Configuration(~/.vimrc
):
1 | call plug#begin() |
Install:
- After entering the Vim interface, execute
:PlugInstall
. During installation, a scriptinstall.sh
needs to be executed, which downloads a binary from GitHub. In mainland China, this download may time out and fail. You can manually install it using the following method:
1 | # Assuming the project has already been downloaded locally via :PlugInstall |
Usage:
:LanguageClientStart
: Since auto-start was disabled in the configuration above, you need to start it manually:LanguageClientStop
: Stop the language client:call LanguageClient_contextMenu()
: Open the operations menu
Keymap Explanation:
Keymap | Description |
---|---|
\rd |
Find the definition of the symbol under the cursor |
\rr |
Find references to the symbol under the cursor |
\rv |
View the description of the symbol under the cursor |
\rn |
Rename the symbol under the cursor |
\hb |
Find the parent class of the symbol under the cursor (ccls only) |
\hd |
Find the subclasses of the symbol under the cursor (ccls only) |
4.4.1 C-Family
4.4.1.1 clangd
Configuration(~/.vimrc
):
clangd
: For related configuration, refer to LanguageClient-neovim/wiki/Clangdclangd
cannot change the cache storage path; by default, it uses${project}/.cache
as the cache directoryclangd
searches forcompile_commands.json
in the path specified by the--compile-commands-dir
parameter. If not found, it recursively searches in the current directory and the directories above each source file’s location
1 | call plug#begin() |
4.4.1.2 ccls
It is not recommended, as large projects consume too many resources and often freeze.
Configuration(~/.vimrc
):
ccls
: For related configuration, refer to ccls-project-setupccls
searches forcompile_commands.json
in the root directory of the project
1 | call plug#begin() |
~/.vim/languageclient.json
- All paths must be absolute paths;
~
cannot be used
1 | { |
4.4.2 Java-jdtls
Configuration(~/.vimrc
):
1 | call plug#begin() |
Create a script with the full path /usr/local/bin/jdtls
containing the following content:
1 |
|
FAQ:
- Cannot access classes in the JDK and third-party libraries.
- For Maven projects, if there are additional directories in the standard directory structure, such as
<project-name>/src/main/<extra_dir>/com
,jdt.ls
cannot automatically scan the entire project. The file will only be added to the parsing list if opened manually.
4.5 Code Completion
4.5.1 YouCompleteMe
Home: YouCompleteMe
Install:
1 | # Define a function to adjust GitHub URLs to speed up the download process. This function will be used multiple times |
Configuration(~/.vimrc
):
1 | call plug#begin() |
How it worked:
- Using
compilation database
: If there is acompile_commands.json
in the current directory, it reads this file to compile and parse the code .ycm_extra_conf.py
: If there is nocompilation database
,ycm
will recursively search upward in the directory hierarchy for the first.ycm_extra_conf.py
file. If none is found, it will load the global configuration (if theg:ycm_global_ycm_extra_conf
parameter is set)
Configure ~/.ycm_extra_conf.py
, with the following content (for C/C++, applicable to most simple projects), for reference only
1 | def Settings(**kwargs): |
Usage:
- By default, only generic completion is available, such as adding already existing characters from the file to the dictionary. This way, if the same string is typed again, it will suggest completion
- For semantic completion, you can generate a
compile_commands.json
using build tools likecmake
and place it in the root directory of the project. Then, open the project in vim to enable semantic completion [Ctrl] + n
: Next entry[Ctrl] + p
: Previous entry
4.5.2 vim-javacomplete2
Home: vim-javacomplete2
Configuration(~/.vimrc
):
1 | call plug#begin() |
4.6 vim-grepper
Home: vim-grepper
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
:Grepper
4.7 vim-signify
Home: vim-signify
Configuration(~/.vimrc
):
1 | call plug#begin() |
Usage:
set signcolumn=yes
,有改动的行会标出:SignifyDiff
:以左右分屏的方式对比当前文件的差异
5 vim-script
5.1 Tips
filereadable
无法识别~
,需要用expand
,例如filereadable(expand('~/.vim/gtags.vim'))
- 函数名要用大写字母开头,或者
s:
开头。大写字母开头表示全局可见,s:
开头表示当前脚本可见 exists('&cscopequickfix')
:判断是否存在参数cscopequickfix
has('nvim')
:判断是否启用了某功能
6 nvim
6.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.10.2/nvim-linux64.tar.gz |
6.1.1 Node Version Management
nvm:
1 | nvm ls-remote |
1 | npm install -g n |
6.2 config path
1 | " ~/.config/nvim |
6.3 nvim share configuration of vim
nvim
和vim
使用不同的目录来管理配置文件,通过软连接就可以实现共享配置,如下:
1 | # nvim's config file is ~/.config/nvim/init.vim |
6.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
进行安装
7 Tips
7.1 Large Files Run Slowly
禁止加载所有插件
1 | vim -u NONE <big file> |
7.2 Export Settings
Example 1
1 | :redir! > vim_keys.txt |
Example 2
1 | :redir! > vim_settings.txt |
7.3 Save and Exit Slowly in Large Project
在大型工程中文件保存退出非常慢,发现是vim-gutentags
插件,及其相关配置导致的。在项目配置文件.workspace.vim
中添加如下内容进行禁用:
1 | let g:gutentags_enabled = 0 |
7.4 How to show which key I hit
- Enter normal mode.
- Type
:map
then press<c-v>
. - Type the key you wanted, then it interpreters it into the actual value.
7.5 copy text through SSH
Note: As of Neovim 10.0 (specifically since this PR), native support for OSC52 has been added and therefore this plugin is now obsolete. Check :h clipboard-osc52 for more details.
:checkhealth clipboard
: Check if there’s clipboard can be used.tmux
can provide a default clipboard.
Item2 Config
: General -> Selection -> Applications in terminal may access clipboard.
8 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