vim的配置

记一下我的vim是怎样配置的,顺便讲一些 vimrc 的语法。

vim 的配置,主要由 vimrc 文件控制,它在 ~/.vimrc

vimrc 文件也可以导入别的 vim 配置文件,一般我们写别的配置文件,使用 .vim 后缀,并把这些文件放在 ~/.vim 里面。一些插件的配置也在这个目录里

可以用 source /path/to/xxx.vim 导入某个 .vim 文件中的配置

vimrc 语法

  1. set 某个参数 可以设置 vim 的某个参数,例如 set nu 表示设置显示行号。这个设置也可以在 vim 中手动调,在 normal 模式下输入 :set nu 也是同样的效果,区别在于它是临时的设置,需要每次都调一下,但放在 vimrc 里面就可以永久生效。如果想取消掉,就在后面加上 !,例如 set nu! 就可以取消显示行号

  2. inoremap, nnoremap 表示映射。它是这样断句的:i或n | nore | map, i或n表示它在insert模式生效还是normal模式生效,nore表示非递归(它其实是 no-recurrent),map表示映射。这个东西可以用来绑定按键,比如把 F8 设置成编译;也可以用来进行代码补全,例如把 ( 映射成 () 从而实现自动匹配括号,也可以写一长段代码进去从而实现代码补全。写多行的代码时,用 <CR> 表示一个换行

  3. exec 命令。相当于在 normal 里面先输入一个 : 然后执行后面的东西。例如,exec "w" 就相当于 :w,就是保存。可以在命令前面加上 ! 表示在 Linux 命令行中运行某个命令。例如 exec "! g++ a.cpp -o a" 就可以编译 a.cpp

  4. 定义变量:用 :let 变量名=... 来声明一个变量

  5. 定义函数:先写一个 function 函数名(),写完以后要写一个 endfunc,在中间写上函数的内容。调用函数的时候写 :call 函数名() ,和上面一行,这个可以直接在 normal 模式下手动输入,也可以写在 vimrc 文件里面永久生效

  6. if选择分支:也是 if(...) 做某事 的语法,也有 else,但是在这些 if else的最后要写一个 endif

  7. 注释:在语句前面加上一个 " 表示注释

这些是基础语法,后面有啥再说

基础设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
set nu rnu
" nu是显示行号,rnu是显示相对行号(例如,在上面多少行,这玩意配合 数字+j/k 特别好用)
set mouse=a
" 这样就可以鼠标点了
set laststatus=2
set tabstop=4
set shiftwidth=4
" 这三行用来设置tab宽度为4,具体啥意思我也不是很懂
set autoindent
set smartindent
" 这两行用来自动对齐缩进
set backspace=indent,eol,start
" 这样的话,按backspace可以把行首删除,并且使这一行并入上一行(这样就和vscode一样了)

set timeoutlen=300
inoremap ( ()<esc>i
inoremap [ []<esc>i
inoremap { {}<esc>i
inoremap {<CR> {<CR>}<esc>O
inoremap ' ''<esc>i
inoremap " ""<esc>i
" 这几个用来设置括号和引号自动匹配,其中大括号后面如果紧跟着换行的话,会变成 { <换行> }
" timeoutlen 设置延迟,单位是毫秒,300ms 可以让它不需要输入的那么快也可以识别并映射
" 关于为啥先 <esc> 一下:这个就是进入 normal 模式,然后再按下 i,这样做的话光标会停留在两个括号的中间,如果不这么干,光标会在括号的后面

代码补全设置

用 inoremap 实现这个

1
2
inoremap INIT #include<bits/stdc++.h><CR>using namespace std;<CR>#define F(i,l,r) for(int i=(l);i<=(r);++i)<CR>#define D(i,l,r) for(int i=(r);i>=(l);--i)<CR>#define MEM(x,a) memset(x,a,sizeof(x))<CR>int I(){int x=0,f=0;char c=getchar(); while(!isdigit(c))f=(c=='-'),c=getchar(); while(isdigit(c))x=x*10+c-'0',c=getchar(); return f?-x:x;}<CR><CR>void flandre()<CR>{<CR><CR>}<CR>#undef int<CR>int main()<CR>{<CR>flandre();<CR>return 0;<CR>}<CR>
inoremap DEFS #define vi vector<int><CR>#define eb emplace_back<CR>#define sz(x) ((int)x.size())<CR>#define al(x) x.begin(),x.end()<CR>#define pii pair<int,int><CR>#define fi first<CR>#define se second<CR>#define lwrb lower_bound<CR>#define uprb upper_bound<CR>

其中这个 INIT 展开出来是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<bits/stdc++.h>
using namespace std;
#define F(i,l,r) for(int i=(l);i<=(r);++i)
#define D(i,l,r) for(int i=(r);i>=(l);--i)
#define MEM(x,a) memset(x,a,sizeof(x))
int I(){int x=0,f=0;char c=getchar(); while(!isdigit(c))f=(c=='-'),c=getchar(); while(isdigit(c))x=x*10+c-'0',c=getchar(); return f?-x:x;}

void flandre()
{

}
#undef int
int main()
{
flandre();
return 0;
}

被压缩成了上面的样子。

自动识别语言的设置

主要包含快捷编译、快速注释。由于不同语言的编译和注释方式不一样,所以需要识别它是啥语言,再决定怎样做。我这里主要是 cpp 和 python,也可以再加入别的语言

写一个语言的配置

先写个cpp的。我们在 ~/.vim 中新建一个 cpp.vim,然后在这里面这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Comp()
exec 'w'
exec '! clear && g++ % -o %< && ./%<'
endfunc
" 编译并运行
" %表示文件名,%<表示去掉后缀的文件名
function CompZ()
exec 'w'
exec '! clear && g++ % -o %< && ./%< < z'
endfunc
" 编译运行,以z为输入文件(这是我本地的一个专门用来放输入的文件)
function ToggleCmt()
:let s=getline('.')
if(s[0]=='/' && s[1]=='/')
exec 's/^\/\///g'
else
exec 's/^/\/\//g'
endif
endfunc
" 这个玩意用来注释

讲一下注释里面的那个抽象字符串,它实在是比较抽象,慢慢来。

首先 vim 有一个替换文本的命令:s/a/b/g,可以把这一行里面的所有 a 字符串换成 b 字符串(s表示范围是当前行,g表示满足条件的全都替换),a可以用正则匹配

我们的逻辑是:先读取这一行,如果开头是 // 就删掉,否则就加上一个 //

这个 getline 就是读取了这一行,然后我们用替换命令来实现上述功能。vim 的正则匹配中,^ 表示行首。然后,对于第一种情况,我们相当于要把 ^// 替换成空串,这样就可以删掉了。

但我们如果直接写的话,/ 会歧义,需要转义,vim 用 \/ 转义,表示文本串中的一个字符 /。所以就写出了上面这一坨。

1
2
3
4
s / ^\/\/ / / g
* * *
*号位置表示 s/a/b/g 中具有结构意义的这个 /
^\/\/ 就是 ^//

同理 s/^/\/\//g 意思就是把 ^ 替换成一个 // ,就是在行首加入 //

识别语言并导入配置

可以用 augroup 实现。

1
2
3
4
augroup cpp
autocmd!
autocmd FileType cpp source ~/.vim/cpp.vim
augroup END

具体原理我也不太懂,总之这样就可以识别一个 cpp 文件,并调用我们写的 cpp 的配置了

似乎 FileType 后面的那个 cpp 起关键作用,是对文件后缀进行识别的。augroup 后面那个是一个“组的名称”,随便起一个都行

同理,把 cpp 换成 python 之类的就可以用 python 的配置了。

这是我的 python 的配置:

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
function Comp()
exec 'w'
exec '! clear && pyinstaller --onefile % && ./dist/%<'
endfunc
" 这是用 pyinstaller 把它打包成可执行文件(这样干挺脑残的,我主要是为了契合我平常搞C++时候的习惯才这么干)

function CompZ()
exec 'w'
exec '! clear && pyinstaller --onefile % && ./dist/%< < ./z'
endfunc

function ToggleCmt()
:let s=getline('.')
if(s[0]=='#')
exec 's/^#//g'
else
exec 's/^/#/g'
endif
endfunc
" 这里是把行首替换成 #,它看起来比C++的那坨大便要好懂的多

function RunPy()
exec 'w'
exec '! clear && python3 %'
endfunc
" 这个是直接跑

nnoremap <F7> :call RunPy()<CR>

插件

关于怎样安装插件,这里不细讲,百度一堆

我目前没使用太多插件,就一个 NERDTree 用来看文件目录,一个 coc.nvim 用来提示代码

coc的话需要再装点别的包,用来对某个语言进行针对性的提示。pythoncoc-jediC++coc-clangd

导入插件部分

1
2
3
4
5
6
call plug#begin('~/.vim/plugged')
Plug 'preservim/NERDTree'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'pappasam/coc-jedi', { 'do': 'yarn install --frozen-lockfile && yarn build', 'branch': 'main' }
" coc-clangd 我是另外安装的,用 CocInstall 命令
call plug#end()

插件的配置部分(这个代码是抄的)

1
2
3
4
5
6
7
8
9
10
11
nnoremap <F3> :NERDTreeToggle<CR>
inoremap <expr> <cr> coc#pum#visible() ? coc#pum#confirm() : "\<CR>"
" use <tab> to trigger completion and navigate to the next complete item
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
inoremap <silent><expr> <Tab>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()

完整代码

~/.vimrc

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
call plug#begin('~/.vim/plugged')
Plug 'preservim/NERDTree'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'pappasam/coc-jedi', { 'do': 'yarn install --frozen-lockfile && yarn build', 'branch': 'main' }
call plug#end()

set nu rnu
set mouse=a
set laststatus=2
set tabstop=4
set shiftwidth=4
set autoindent
set smartindent
set backspace=indent,eol,start

set timeoutlen=300
inoremap ( ()<esc>i
inoremap [ []<esc>i
inoremap { {}<esc>i
inoremap {<CR> {<CR>}<esc>O
inoremap ' ''<esc>i
inoremap " ""<esc>i

inoremap INIT #include<bits/stdc++.h><CR>using namespace std;<CR>#define F(i,l,r) for(int i=(l);i<=(r);++i)<CR>#define D(i,l,r) for(int i=(r);i>=(l);--i)<CR>#define MEM(x,a) memset(x,a,sizeof(x))<CR>int I(){int x=0,f=0;char c=getchar(); while(!isdigit(c))f=(c=='-'),c=getchar(); while(isdigit(c))x=x*10+c-'0',c=getchar(); return f?-x:x;}<CR><CR>void flandre()<CR>{<CR><CR>}<CR>#undef int<CR>int main()<CR>{<CR>flandre();<CR>return 0;<CR>}<CR>
inoremap DEFS #define vi vector<int><CR>#define eb emplace_back<CR>#define sz(x) ((int)x.size())<CR>#define al(x) x.begin(),x.end()<CR>#define pii pair<int,int><CR>#define fi first<CR>#define se second<CR>#define lwrb lower_bound<CR>#define uprb upper_bound<CR>

nnoremap <F8> :call Comp()<CR>
nnoremap <F9> :call CompZ()<CR>
nnoremap <C-A> ggVG
nnoremap <C-P> :call ToggleCmt()<CR>

nnoremap <F3> :NERDTreeToggle<CR>
inoremap <expr> <cr> coc#pum#visible() ? coc#pum#confirm() : "\<CR>"
" use <tab> to trigger completion and navigate to the next complete item
function! CheckBackspace() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
inoremap <silent><expr> <Tab>
\ coc#pum#visible() ? coc#pum#next(1) :
\ CheckBackspace() ? "\<Tab>" :
\ coc#refresh()

augroup cpp
autocmd!
autocmd FileType cpp source ~/.vim/cpp.vim
augroup END

augroup python
autocmd!
autocmd FileType python source ~/.vim/python.vim
augroup END

augroup html
autocmd!
autocmd FileType html source ~/.vim/html.vim
augroup END

~/.vim/cpp.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Comp()
exec 'w'
exec '! clear && g++ % -o %< && ./%<'
endfunc
function CompZ()
exec 'w'
exec '! clear && g++ % -o %< && ./%< < z'
endfunc
function ToggleCmt()
:let s=getline('.')
if(s[0]=='/' && s[1]=='/')
exec 's/^\/\///g'
else
exec 's/^/\/\//g'
endif
endfunc

~/.vim/python.vim

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
function Comp()
exec 'w'
exec '! clear && pyinstaller --onefile % && ./dist/%<'
endfunc

function CompZ()
exec 'w'
exec '! clear && pyinstaller --onefile % && ./dist/%< < ./z'
endfunc

function ToggleCmt()
:let s=getline('.')
if(s[0]=='#')
exec 's/^#//g'
else
exec 's/^/#/g'
endif
endfunc

function RunPy()
exec 'w'
exec '! clear && python3 %'
endfunc

nnoremap <F7> :call RunPy()<CR>