记一下我的vim是怎样配置的,顺便讲一些 vimrc 的语法。
vim 的配置,主要由 vimrc 文件控制,它在 ~/.vimrc
vimrc 文件也可以导入别的 vim 配置文件,一般我们写别的配置文件,使用 .vim 后缀,并把这些文件放在 ~/.vim 里面。一些插件的配置也在这个目录里
可以用 source /path/to/xxx.vim 导入某个 .vim 文件中的配置
vimrc 语法
set 某个参数 可以设置 vim 的某个参数,例如 set nu 表示设置显示行号。这个设置也可以在 vim 中手动调,在 normal 模式下输入 :set nu 也是同样的效果,区别在于它是临时的设置,需要每次都调一下,但放在 vimrc 里面就可以永久生效。如果想取消掉,就在后面加上 !,例如 set nu! 就可以取消显示行号
inoremap, nnoremap 表示映射。它是这样断句的:i或n | nore | map, i或n表示它在insert模式生效还是normal模式生效,nore表示非递归(它其实是 no-recurrent),map表示映射。这个东西可以用来绑定按键,比如把 F8 设置成编译;也可以用来进行代码补全,例如把 ( 映射成 () 从而实现自动匹配括号,也可以写一长段代码进去从而实现代码补全。写多行的代码时,用 <CR> 表示一个换行
exec 命令。相当于在 normal 里面先输入一个 : 然后执行后面的东西。例如,exec "w" 就相当于 :w,就是保存。可以在命令前面加上 ! 表示在 Linux 命令行中运行某个命令。例如 exec "! g++ a.cpp -o a" 就可以编译 a.cpp
定义变量:用 :let 变量名=... 来声明一个变量
定义函数:先写一个 function 函数名(),写完以后要写一个 endfunc,在中间写上函数的内容。调用函数的时候写 :call 函数名() ,和上面一行,这个可以直接在 normal 模式下手动输入,也可以写在 vimrc 文件里面永久生效
if选择分支:也是 if(...) 做某事 的语法,也有 else,但是在这些 if else的最后要写一个 endif
注释:在语句前面加上一个 " 表示注释
这些是基础语法,后面有啥再说
基础设置 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的话需要再装点别的包,用来对某个语言进行针对性的提示。python 用 coc-jedi,C++ 用 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>