admin 管理员组

文章数量: 887021

vim配置与基本操作

  这份vim配置主要用于C family的开发与阅读。它面向大型项目,所以以下代码都将以linux kernal为例子展示。除去配置外也将记录一些vim的基本操作,辅助记忆~


1. vim基本配置

  首先是一些编码、主题以及缩进的配置。创建一个***~/.vimrc***文件,所有vim相关的配置都可以在这个文件里面设置:

"设置文件编码
set encoding=utf-8
set fileencodings=utf-8
set termencoding=utf-8

"设定leader键
let mapleader=','

let g:solarized_termcolors=256
"设置主题
syntax on
set background=dark
colorscheme onehalfdark
"常用主题onedark,xcodelight,xcodedark,xcodewwdc
"gotham,gotham256,solarized

set cursorline
"设置保持历史记录10000
set history=10000

"打开文件时禁止折叠
set nofoldenable
"按照语法高亮进行折叠
set fdm=indent

set display=lastline
" scrolloff控制光标上下的边距为多少时翻页,emmm,说的有点抽象,改改这个数字就很清楚了
set scrolloff=5
set matchtime=2
set matchpairs+=<:>
" 显示行号可以通过在命令行中设置:set nonumber关闭行号。要想永久关闭或者开启就要在vimrc中设置了
set number
set showcmd
set showmatch

" 设置文件不备份,这里被注释掉;
set nobackup
set noundofile
set noswapfile
"set backupext=.bak
"set backupdir=~/.vim/vim_bak/

"语法高亮
set syntax=on
" 去掉输入错误的提示声音
set noeb
" 在处理未保存或只读文件的时候,弹出确认
set confirm
" 自动缩进
set autoindent
set cindent

" 设置tab为四个空格空格代替Tab。空格比起制表符拥有更好的兼容性
" 注意: 插入模式下输入【ctrl+v+i】可以强制输入一个tab
" 针对已经存在的制表符,可以通过:%retab将制表符替换成四个空格
set tabstop=4     " tabstop 表示一个 tab 显示出来是多少个空格的长度,默认8
set softtabstop=4 " softtabstop 表示在编辑模式的时候按退格键的时候退回缩进的长度,当使用 expandtab 时特别有用
set expandtab     " 当设置成 expandtab 时,缩进用空格来表示,noexpandtab 则是用制表符表示一个缩进
set autoindent    " 自动缩进
set cindent       " 自动缩进补充
set shiftwidth=4  " 自动缩进空白字符个数
" 行尾部的空格会显示红色
highlight WhitespaceEOL ctermbg=red guibg=red
match WhitespaceEOL /\s\+$/

" 显示行号
set number
" 历史记录数
set history=1000
"禁止生成临时文件
set nobackup
set noswapfile
"搜索忽略大小写
set ignorecase

set incsearch

set autoread
set autowrite

" 鼠标定位
" 鼠标定位和鼠标拷贝似乎不能共存,按住shift再使用鼠标拷贝
set mouse=a

" 设置光标的形态
" 普通模式下为光标方块,插入模式下为竖线
let &t_SI.="\e[6 q" "SI = INSERT mode
let &t_SR.="\e[4 q" "SR = REPLACE mode
let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE)

" 设置光标颜色
highlight Cursor guifg=white guibg=white
highlight iCursor guifg=white guibg=white
set guicursor=n-v-c:block-Cursor
set guicursor+=i:ver100-iCursor
set guicursor+=n-v-c:blinkon0
set guicursor+=i:blinkwait10

" 垂直分割线颜色
" 就是分页的时候的那条分割线
hi VertSplit guibg=#31312D guifg=#526A83 ctermfg=White ctermbg=Black term=none cterm=none gui=none

  关于vim的自带主题可以在/usr/share/vim/vim81/colors找到。可以在网上搜索自己喜欢的主题,然后将对应的colorscheme.vim文件放在这个文件夹下面,通过在vimrc中colorscheme xxxx配置对应主题。或者也可以在vim normal模式下面通过命令行colorscheme xxxx来配置,但是会被vimrc中的配置覆盖,请注意。

  因为是在wsl使用的vim,鼠标操作对我还是蛮重要的,就设置了set mouse = a,就是可以通过鼠标翻页。不过用这个设置之后就不能直接通过鼠标选择然后拷贝了。想要拷贝的话,需要通过鼠标选中然后按住shift再右键即可。但是这样拷贝的话还会把行号和换行符拷贝了,所以还得关掉行号显示,通过:set nonumber来关掉行号,嘛,换行符就没法子了,不过讲道理拷贝那么多东西直接重定向一下不好么。ubuntu好久没用,但好像是没这么麻烦来着。

  有几个设置tab的选项请原样按照上面来进行配置。可以通过再normal模式下:set list显示制表符和换行符,用:set nolist关闭。相应效果如下:

  换行符显示为**$符号,而制表符显示为^I**符号。通过在normal模式下:%retab就可以将制表符换成空格了。

  还有一个leader键的设置,如上就是let mapleader=','。这是一个快捷键映射,但是我用的比较少,太多快捷键容易记混,还是更喜欢在normal命令行下敲几个字母。一般有些键盘映射诸如map <leader>wq :wq<CR>这样的映射啊,前面那个 <leader>就是就是自定义的前缀键了。通过这个键还是可以有很多骚操作的,但其实很多功能现在插件都有集成,不需要那么复杂,详见下面。


2. vim基本操作

  VIM的基本模式有许多种,我自己常用的有以下四种。

  • 一是normal模式,在这个模式下主要做的是命令行操作。打开vim就会进入normal模式,在任何情况下按ESC都可以进入normal模式。一般而言:符号后面接的是一些vim命令,?/后面接的匹配模式。

    1. 对于文件内容的操作,这些基本操作是必须记忆的
    命令效果
    :w :q :wq :q!w是保存文件,q是退出vim,wq是保存并退出,q!是不保存强制退出
    :NN是数字,:N可以跳转到某行
    i o在normal模式下按i与o可以进入insert模式,注意没有冒号
    yy yG ygg yNgyy拷贝当前光标指向行,yG拷贝当前行到文档末的全部内容,ygg拷贝当前行到文档头的全部内容,yNG拷贝当前行到第N行的内容
    p粘贴(yxx拷贝的内容或者dxx删除的内容)
    ctrl+shift+v从系统的剪切板中粘贴。ubuntu上面是这样,所以我把wsl的粘贴也配置成这样了
    dd dG dgg dNG类似与y系列操作,不过这是删除操作。dd删除当前行,dG删除当前到文档尾部全部行,dgg删除当前到文档头部全部行,dNG删除当前行到第N行间全部内容。注意这里的删除类似剪切,可以通过p来粘贴刚刚被d指令删除的内容
    u ctrl+ru可以撤回,ctrl+r是反撤回
    1. 跳转,查找与替换。注意查找是用的linux自带的grep,效率比较低,所以如果要在整个项目内查找文本不建议使用内置命令,用riggrep替代之(见下文):
    命令效果
    :NN是行号,:N可以跳转到某行
    gg Ggg跳转至文件头部,G跳转至文件尾部
    ctrl+] g+ctrl+]跳转到定义,需要ctags支持,见下文
    ctrl+t ctrl+o两个命令都是跳转回上一个地方。但是ctrl+t只限定tag跳转,也就是通过ctrl+]的跳转。而ctrl+o更加通用,像用gg跳到文件头,可以ctrl+o调回来。但是ctrl+o在文件之间的跳转经常有bug…
    /parttern ?parttern在当前文件中搜索。/是向下搜索,?是向上搜索。parttern是匹配模式,支持正则表达式(根据vim版本不同支持程度不同,但是通配符基本都会支持的)
    shift+* shift+#在当前文件中查找光标指向的符号
    u ctrl+ru可以撤回,ctrl+r是反撤回
    :[addr]s/src/dst/[opt]替换操作,src与dst都是匹配模式,支持一些通配符(根据vim的版本好像有不同,比较老的不支持正则)。命令是把src的内容替换成dst的内容。[addr]限定查找区域,%s是全局查找,1,ns表示第1行到第n行,s表示当前行,.,$s表示当前行到最后一行。[option]限定替换模式,g表示替换匹配行中全部匹配内容,为空则只替换第一个匹配单词。如:1,100s/hello/world/g就是把第1到100行所有的hello替换成world。

    ​ 查找如图所示。在输入/或者?后进入查找模式,为全匹配查找。该查找中使用了通配符.。一般查找结果会高亮显示,在找到结果后按回车结束查找。通过nN在查找结果之间跳转。小写的n是跳到下一个查找结果,大写的N与之相反。当然,如果是要在当前文件中查找光标指定的符号,不用/然后再打一堆字那么麻烦,直接shift+#就好,然后也可以通过n与N再查找结果之间跳转:

  如果想要显示所有匹配的项,该怎么做呢?可以使用:%g/parttern/p,效果如下:

  是熟悉的more界面,这里显示了所有parttern匹配的行,并且可以通过:N界面跳转。上面那个命令格式和替换指令很像,它的格式是这样的:{range}g/{parttern}/{cmd},range和替换指令相同,%g就是全文查找。cmd默认为p,也就是:print,可以在quickfix中打印所有匹配行,其他可以参考help global。不过后边会使用fzf对他进行替换

  3. 多tab与分页:

命令效果
tabnew path/file新建一个tab,在该tab中打开文件
tabclose关闭当前tab。后边加路径可以关闭指定tab。通过:wq也可以关闭tab
tabmove - tabmove +左移(右移)tab,可以通过:help tabpage查看更具体的操作
ctrl+pageup,ctrl+pagedown在tab之间切换
vsplit file split file打开文件并且水平/垂直切分窗口
ctrl +w +w在一个tab内部的不同的窗口之间跳转。包括quickfix,水平切分和垂直切分的窗口都可以通过这样跳转,但是不可以跳转到不同的tab。

  多tab是我很喜欢的东西,尤其是拿来看代码,可以提供类似opengrok的体验。这里只是简单展示一下效果,tab这东西配合fzf才是真滴牛皮~,效果图如下。上面的一堆tab就像是浏览器里面的tab一样,通过ctrl+翻页键在不同tab间可以切换。多tab功能在vim7后就添加了,泛用性还是很不错的:

  4. 杂项:

命令效果
:terminal生成终端,按ctrl+d退出
:set line/noline显示(不显示)制表符与换行符
:set number/nonumber显示(不显示)行号
:help xxxx查阅相关的帮助文档
  • 二是insert模式,通过在normal模式下面输入i或者o进入insert模式,ESC退回normal模式。insert模式下面的编辑就类似于平时的编辑了,不多叙述。
  • 三是visual模式,在normal下输入v、ctrl+v、V进入。三种方法所进入的选择模式不同,具体可以体验一下。在选择了对应的块后,可以对其进行复制、剪切、删除、拷贝操作,与normal上的操作是共同的。如下通过ctrl+r进入visual模式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z4aOiKnG-1635733121802)(img6.png)]

  选中块后,按x或者d删除选择内容,按y拷贝选择内容。

  • 四是replace模式,进入方式主要有三种,r,R,RGr模式进入单字符替换;R模式进入多字符替换模式,RGR的区别在于,前者一般将制表符打印为四个空格。但是在上述配置完成后,RRG实际上就拥有了相同的效果。

3. VIM美化

  vim美化着实没什么心得。主要就是colorscheme的设置了,上面也已经提过。通过将对应的xxxxxx.vim拷贝到/usr/share/vim/vimxx/colors/文件夹下面,然后在vimrc中设置colorscheme xxxxxx,可以ls查看该文件夹下面有什么主题,vim自带的比较好看的主题有darkblue,其他就一般吧。我比较喜欢的主题是onehalf/vim/colors at master · sonph/onehalf (github),下载对应的onehalfdark.vim文件并按照上面步骤做即可。我装了个airline插件用于美化状态栏,嫌airline卡可以换成更加轻量的lightline。

"===============================================================
"powerline
set laststatus=2
let g:Powerline_symbols='unicode'

"===============================================================
"airline
" tabline,也就是上方的tab列表
let g:airline#extensions#tabline#enabled = 1
" 显示tab的分割
let g:airline#extensions#tabline#show_splits = 0
" 不显示buffer
let g:airline#extensions#tabline#show_buffers = 0
" tab的显示风格
let g:airline#extensions#tabline#alt_sep = 1
let g:airline#extensions#tabline#left_sep = ' '
" 不同tab的左间隔符
let g:airline#extensions#tabline#left_alt_sep = '◀'

let g:airline#extensions#tabline#tab_nr_type = 1 " tab number
let g:airline#extensions#tabline#show_tab_nr = 0

" let g:airline#extensions#tabline#formatter = 'default'
" 只显示文件名字
let g:airline#extensions#tabline#formatter = 'unique_tail'
" 超出长度显示...
let g:airline#extensions#tabline#overflow_marker = '…'
let g:airline_powerline_fonts = 1

" 关闭一堆不需要的
let g:airline#extensions#tabline#buffer_nr_show = 0
let g:airline#extensions#tabline#exclude_preview = 0
"if !exists('g:airline_symbols')
"  let g:airline_symbols = {}
"endif

" 设置主题
let g:airline_theme="onedark"

let g:airline_left_sep = '▶'
let g:airline_left_alt_sep = '❯'
let g:airline_right_sep = '◀'
let g:airline_right_alt_sep = '❮'

  上面的安装流程使用的是Plug.vim,这个东西用起来很简单。首先在github上面找到plug.vim,然后把plug.vim拷贝到~/.vim/autoload/下面,就ok了,~/.vim/auttoload文件夹里面的插件在vim打开时自带运行。想要安装插件,像下面这样:

"plug插件管理器
call plug#begin('~/.vim/plugged')

"底部状态栏美化
"Plug 'vim-airline/vim-airline'
Plug 'Lokaltog/vim-powerline'

call plug#end()
filetype plugin indent on

  想要安装啥就在上面的begin和end中间加一句Plug 'xxxxx',然后在命令行执行:PluginInstall。更新插件的话,就是:PluginUpdate。删除插件只要把vimrc里面对应的Plug 'xxxxx'删除,然后执行PluginClean就可以了。

  airline的效果大概就是这样啦,简单但是够用。上面显示tab的名字和数量,每个tab显示tab编号以及文件名。下面会显示行号编码和文件类型什么的。这里本来有git状态显示,但是airline集成的话比较卡顿,所以并没有开启。


4. VIM代码阅览

  vim要配合一些额外的部件来进行代码阅读。诸如查找定义,查找声明,查找函数引用,git状态之类。以下列出几个主要的插件以及我平时的使用方式:

1. ctags与cscope

  这两兄弟跟随了vim许多年,最大的好处就是兼容性极强,管你服务器是ubuntu14还是20都能用。不过使用体验嘛,emmm,一言难尽,好处是在大型项目上面表现还行,但是ctags是真的有很多定义,尤其是对宏还有C++模板类,是查不出来的,略坑爹。

  • 安装

  在命令行中安装:

sudo apt install ctags cscope
# cscope兼容ctags
  • 配置
" 设置tag跳转快捷键
nnoremap <leader>] g<C-]>

"=================================================================
" cscope
" cscope -Rbq,生成cscope数据库,使用方式类似ctags
" cscope find c name,查找调用该函数的函数
" set quickfix,把信息打到quickfix里面,不过还是全屏好用
" set cscopequickfix=s-,c-,d-,i-,t-,e-

" use both cscope and ctag for 'ctrl-]', ':ta', and 'vim -t'
" set cscopetag

" check cscope for definition of a symbol before checking ctags: set to 1
" if you want the reverse search order.
set csto=0

" add any cscope database in current directory
if filereadable("cscope.out")
        cs add cscope.out
" else add the database pointed to by environment variable
elseif $CSCOPE_DB != ""
        cs add $CSCOPE_DB
endif

" show msg when any other cscope db added
set cscopeverbose

" 设置输出文件信息长度,文件路径深度最高为五
:set cspc=5

" 设置输出信息的颜色,这里还需要改进,颜色设置不够显眼
:hi ModeMsg ctermfg=Blue
  • 使用

  首先在项目根目录下面用下面两个指令生成数据库:

ctags -R
cscope -Rbq

  对于C++项目,可以ctags -R --c++-kinds=+px --fields=+iaS --extra=+q来生成针对C++的tag。这两个指令-R选项都意味着在当前目录下递归生成tag。

  这时候在该目录下面就应该出现了相应的tags文件与cscope.out文件,他们是跳转用的键值数据库。然后在根目录直接打开vim,并在normal模式下输入指令

:set tags=rootpath/tags 
:cscope add rootpath/cscope.out

  很麻烦是吧,所以在vimrc中加入对应的自动执行指令,这样每次打开根目录,就会检查是否存在tags文件与cscope文件,有的话就把他们加进来,没有的话,就没有了。为啥不创建?你创建个试试就知道了,比如在linux2.6的源码库下面创建这两玩意儿,多少得花个好几分钟。要是赶时间岂不是得把电脑砸了~

if filereadable("tags")
	set tags+=./tags
endif
if filereadable("cscope.out")
        cs add cscope.out
" else add the database pointed to by environment variable
elseif $CSCOPE_DB != ""
        cs add $CSCOPE_DB
endif

  经过一系列配置就可以使用了。这俩插件的主要作用就是查找与跳转到定义,以及查找函数被调用处:

  • ctrl+] :跳转到符号定义,存在多个定义,会从数据库中自己选一个定义跳转过去

  • g+ctrl+] :跳转到符号定义,存在多个定义,显示在quicktab中,自己可以选择一个

  • ctrl+t :跳转回上一个地方

  • ctrl+o :同样是跳转回上一个地方,但是用处更多,比如你用gg跳到文件头了,它也可以给你跳回来。就是用这个有时候跳着

    跳着就迷失了方向,所以我更喜欢ctrl+t或者buffer

  • [[ :跳转到当前函数头部

  • ]] :跳转到当前函数尾部,还有[]和][两个快捷键,类似的意思,一个是上一个函数尾,一个是下一个函数头

  • 因为一般用的都是g+ctrl+]那个命令啦,这三个键简直反人类,所以给map一下:
    nnoremap <leader>] g<C-]>,这样直接按 ,+]就可以跳转了,效果如下:

  将光标移动到对应的符号上,然后按,+],就显示出了一堆定义的地方。在下面输入数字来进行跳转。

  • cscope find c FuncName :查找调用函数的地方。查找结果和上面类似,当然也可以把该命令映射成快捷键:
nnoremap <leader>c :cs find c <C-R>=expand("<cword>")<CR><CR>

  这样只要把光标放到函数上,然后按,+c,就可以显示调用该函数的地方了,效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tPJifrBR-1635733121804)(img4.png)]

  ctags与cscope的组合,配置完快捷键以后使用起来也不算太过麻烦,就像其他IDE也需要导入项目一样,这里无非多敲两命令。蛋疼的是他们两即便组合起来,还是偶尔出现找不到定义的情况(和代码风格也有关系,像linux内核那种到处是宏的地方确实难为他们了)。以及上述效果展示,我也找了一阵子但是只能显示出这种配色,因为它的匹配结果也是通过more来打印的,以后再慢慢改进吧~

2. gtags

  gtags名字和上面两很像,就知道它是干啥的了。它是gnu家族的一元,可以对ctags和cscope做不到的进行补充。像ctags可以找到函数定义但是无法找到函数引用,而cscope虽然可以找到函数引用,但是对于C++支持不好,更别说java之类。gtags用处广泛,像是vscode的默认补全就是通过gtags生成的。安装起来很简单,ubuntu下直接安装:

sudo apt install global

  gtags是上面两者的补充,所以不应该覆盖而是共存,见配置:

" gtags

set cscopetag " 使用 cscope 作为 tags 命令
set cscopeprg='gtags-cscope' " 使用 gtags-cscope 代替 cscope

"gtags.vim 设置项
let GtagsCscope_Auto_Load = 1
let CtagsCscope_Auto_Map = 1
let GtagsCscope_Quiet = 1
" 并不是禁止了cscope与ctags,gtags是在C++与java方面的补充

  在这份配置中gtags兼容了cscope的接口,所以使用方式不变,快捷键也不变,和cscope一样。

3. tagbar与nerdtree

  标签列表与文件树,没什么特别好说的,也是两个老插件,相对而言比较容易配置,傻瓜式拷贝就行:

"标签导航插件
Plug 'majutsushi/tagbar'
"文件树
Plug 'preservim/nerdtree'

"================================================================
"tagbar
"设置tagbar使用的ctags的插件,必须要设置对
let g:tagbar_ctags_bin='/usr/bin/ctags'
""设置tagbar的窗口宽度
let g:tagbar_width=35
"设置tagbar的窗口显示的位置,为右边
let g:tagbar_left=0
"打开文件自动 打开tagbar
"autocmd BufReadPost *.cpp,*.c,*.h,*.hpp,*,*.cxx call tagbar#autoopen()
"映射tagbar的快捷键
map <F9> :TagbarToggle<CR>
" 设置焦点在tagbar
let g:tagbar_autofocus=1

"==============================================================
"nerdtree
"vim打开空文件时直接打开文件树
"autocmd StdinReadPre * let s:std_in=1
"autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif

"vim打开文件夹时打开文件树
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists("s:std_in") | exe 'NERDTree' argv()[0] | wincmd p | ene | exe 'cd '.argv()[0] | endif

autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif

" 文件树列表显示在左侧
let g:NERDTreeWinPos="left"
" 宽度为30
let g:NERDTreeWinSize=30
" let g:NERDTreeShowLineNumbers=1
" let g:neocomplcache_enable_at_startup = 1
" 将打开文件树的操作映射到F8键
nnoremap <F8> :NERDTreeToggle<cr>

" NERDTress File highlighting
function! NERDTreeHighlightFile(extension, fg, bg, guifg, guibg)
        exec 'autocmd filetype nerdtree highlight ' . a:extension .' ctermbg='.a:bg .' ctermfg='. a:fg .' guibg='. a:guibg .' guifg='. a:guifg
        exec 'autocmd filetype nerdtree syn match ' . a:extension .' #^\s\+.*'.a:extension .'$#'
endfunction

" 根据文件类型不同做的颜色配置。配合nerdtree的配色插件还蛮多的,做出vscode那种效果也是完全可以做到的
call NERDTreeHighlightFile('cpp', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('cc', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('c', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('h', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('hpp', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('md', 'blue', 'none', '#3366FF', '#151515')
call NERDTreeHighlightFile('json', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('html', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('css', 'cyan', 'none', 'cyan', '#151515')
call NERDTreeHighlightFile('js', 'Red', 'none', '#ffa500', '#151515')

  通过F8打开或者关闭标签列表,通过F9打开或者关闭文件树,效果如下:

  tagbar生成的tag列表是基于ctags的,通过zc或者zo关闭或者打开对应的列表,这个逻辑与vim类似。nerdtree文件树的root目录是根据vim打开时的位置确定的,可以通过大写的C来切换root目录。按F8或者F9后光标自动会跳转到文件数或者tagbar上,选择对应的tag然后回车就可以跳转到指定位置,然后可以用ctrl+t跳回来。对于文件树呢,它还支持鼠标操作,并且按t可以新建一个tab再跳转,按s为水平分割,i为垂直分割,具体可以看help,总之要比tagbar的功能丰富不少。

4. fzf与ripgrep

  和上面两兄弟不同,fzf是新时代的先锋,具备异步,高集成,使用更加人性化诸多特点为一体。它的功能极度丰富,下面只是说一些我自己的探索结果:

  • 安装,通过plug来进行。能通过plug安装的插件都是好文明:
sudo apt install fzf ripgrep

" 注意系统中要安装fzf,vim中也要安装
" 因为fzf一开始并不是为了vim而设置的,而是后来兼容的
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

  这里还安装了Ripgrep,这是一个文本检索工具,类似于linux自带的grep,不过性能非常强劲,用它来配合fzf事半功倍。此外fzf默认使用linux下的find指令查找文件,也可以对其替换,比如我是用fd,替换了find,如下:

sudo apt install fd-find

  在/etc/profile或者~/.bashrc里面设置全局变量改变fzf的默认行为:

export FZF_DEFAULT_COMMAND="fdfind --exclude={.git,.idea,.vscode,tags} --type f"
# 默认是export FZF_DEFAULT_COMMAND="find"
# 这里用fdfind替换Linux原生find,并且不搜索一些文件/文件夹
  • 配置
"fzf
"
" FZF -e name:在当前文件夹下精确匹配搜索文件
" Files name : 在当前文件夹下模糊匹配搜索文件,相当于FZF name
" Tags name  :根据ctags生成的tags搜索标签
" Rg name    :全文本模糊匹配,需要安装额外工具,详见官方md

" This is the default extra key bindings
" 默认的动作,回车是跳转,ctrl+t是打开一个新的tab然后跳转到指定位置
let g:fzf_action = {
  \ 'ctrl-t': 'tab split',
  \ 'ctrl-x': 'split',
  \ 'ctrl-v': 'vsplit' }
" Default fzf layout
" - down / up / left / right
let g:fzf_layout = { 'down': '~40%' }
" In Neovim, you can set up fzf window using a Vim command
" let g:fzf_layout = { 'window': 'enew' }
" let g:fzf_layout = { 'window': '-tabnew' }
" let g:fzf_layout = { 'window': '10split enew' }

" Customize fzf colors to match your color scheme
let g:fzf_colors =
\ { 'fg':      ['fg', 'Normal'],
  \ 'bg':      ['bg', 'Normal'],
  \ 'hl':      ['fg', 'Comment'],
  \ 'fg+':     ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
  \ 'bg+':     ['bg', 'CursorLine', 'CursorColumn'],
  \ 'hl+':     ['fg', 'Statement'],
  \ 'info':    ['fg', 'PreProc'],
  \ 'border':  ['fg', 'Ignore'],
  \ 'prompt':  ['fg', 'Conditional'],
  \ 'pointer': ['fg', 'Exception'],
  \ 'marker':  ['fg', 'Keyword'],
  \ 'spinner': ['fg', 'Label'],
  \ 'header':  ['fg', 'Comment'] }
" Enable per-command history.
" CTRL-N and CTRL-P will be automatically bound to next-history and
" previous-history instead of down and up. If you don't like the change,
" explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS.
let g:fzf_history_dir = '~/.local/share/fzf-history'

" [Buffers] 如果可能跳到已存在窗口
let g:fzf_buffers_jump = 0
" [[B]Commits] 自定义被'git log'使用的选项
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'

" [Tags] 定义用来产生tag的命令
let g:fzf_tags_command = 'ctags -R'
" [Commands] --expect expression for directly executing the command
let g:fzf_commands_expect = 'alt-enter,ctrl-x'
  • 使用
命令效果
:Files xxxx从当前目录开始递归的搜索文件
:Rg xxxx使用Ripgrep,从当前目录开始递归搜索文本(类似的还有Ag,用的是sliversearch,速度不如Rg)
:Rg -e xxxx使用正则表达式搜索
:Tags xxxx搜索tags,默认的tags是ctags
:Buffers显示所有已经打开的buffer
:Lines xxxx显示所有匹配的行
:Colors显示所有的配色主题
:HelpTags显示所有的帮助文档,这是个很有用的命令,fzf会从man page和vim文件夹中提取对应的help tag

  fzf的所有命令格式都类似,默认都是递归模糊搜索。按回车是跳转到指定位置,ctrl+t是打开一个新的tab再跳转,ctrl+s是打开一个水平分割窗口再跳转。

  Files命令可以递归检索文件。一般我会在项目的根目录直接打开vim,然后使用:Files搜索文件,默认的是进行模糊匹配,加上-e选项可以用正则和全匹配:

  quickfix的左侧是匹配到的文件,右侧是文件的预览窗口,按回车就可以打开文件。或者使用ctrl+t,可以打开一个新的tab。

  :Rg命令可以快速检索对应的字符串,如果不输入-e那就是默认模糊搜索。类似的,回车打开匹配处,ctrl+t打开一个新的tab:

  打开新的tab,相关tab的信息显示在右上角,文件路径会被压缩:

  Buffers命令可以显示打开过的文件的历史,可以用它快速定位文件:

  大部分情况下我会通过ctags与cscope来查找符号定义与符号引用(当然也包括gtags了),通过fzf来查找文件。如果无法找到相关定义,则使用Ripgrep来进行全文本搜索。通过vim的多tab机制以及fzf的buffer功能可以模拟类似浏览器的搜索与跳转体验。

  像FZF这样的集成工具还是蛮多的,比如LeaderF,操作也都是类似的,不多加介绍了。LeaderF安装起来更简单,通过plug直接安装,像是没有权限无法安装fzf的话,LeaderF就是挺好的替换选项。

5. Mark.vim

  生成高亮标记,在Mark - a little script to highlight several words in different colors simultaneously : vim online下载该插件,然后移动mark.vim到~/.vim/plugin目录下就可以了。默认的快捷键是<leader>+m,可以标记(取消标记)一个单词。:Mark命令取消所有的标记:

" Mark                                                                                                      " 打开vim时重置mark       
set viminfo='64,<8192,s1024,!,h

  效果如下,只要把光标移动到对应单词下面,就可以按<leader>+m标记单词。这个标记在不同的tab之间也会生效:


5. VIM中的C++自动补全与纠错

自动补全

  现在C/C++补全以及不再是ycm一家独大,lsp(language server protocol)的出现简化了这方面的配置,像是vscode上面比较流行的基本都是lsp了。vim当然也有lsp,不过我这里还是用ycm,主要是用习惯了,ycm的一些特别的功能也很是有趣。另外,ycm在新近的版本中也实现了异步的补全功能,论性能还是不搓的。

  • 安装

  最简单的安装方法就是在plug中加上对应的语句,然后执行:PluginInstall

Plug 'ycm-core/YouCompleteMe'

  不过因为要上外网,不用特殊方法这样是基本安装不了的。所以用了个取巧的法子(仅限于debian系):

sudo apt install vim-addon-manager
sudo apt install vim-youcompleteme
vim-addons install youcompleteme

  这样安装还不够,需要一些额外配置。创建一个~/.ycm_extra_conf.py文件,我自己的.ycm_extra_conf.py文件如下,对应配置要根据系统修改:

import os
import ycm_core

flags = [
    '-Wall',
    '-Wextra',
    '-Werror',
    '-Wno-long-long',
    '-Wno-variadic-macros',
    '-fexceptions',
    '-DNDEBUG',
    '-std=c++20',							# 支持的C++版本
    '-x',
    'c++',
    '-I',
    '/usr/include',							# 补全所用的头文件
    '-isystem',
    '/usr/lib/gcc/x86_64-linux-gnu/9/',		# 补全所用的头文件
    '-isystem',
    '-isystem'
    '/usr/include/c++/9',
    '-isystem',
  ]

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '', '.c', '.go']

def FlagsForFile( filename, **kwargs ):
  return {
    'flags': flags,
    'do_cache': True
  }
  • 配置

  这份配置是默认配置做了一些修改:

"==============================================================
"YCM

" 每次重新生成匹配项,禁止缓存匹配项
let g:ycm_cache_omnifunc=0
" 在注释中也不能补全
let g:ycm_complete_in_comments=0
" 关闭额外预览窗口
let g:ycm_add_preview_to_completeopt = 0
" 基于syntastic的代码诊断,觉得慢的话可以换成ale,我这里就关掉了
let g:ycm_show_diagnostics_ui = 0
let g:ycm_server_log_level = 'info'
" 敲入几个字符开始触发补全
let g:ycm_min_num_identifier_candidate_chars = 2
let g:ycm_collect_identifiers_from_comments_and_strings = 1
let g:ycm_complete_in_strings=1
let g:ycm_key_invoke_completion = '<c-z>'
set completeopt=menu,menuone

let g:ycm_global_ycm_extra_conf='~/.ycm_extra_conf.py'

let g:ycm_confirm_extra_conf = 0

noremap <c-z> <NOP>

" 选择补全语言
let g:ycm_semantic_triggers =  {
           \ 'c,cpp,python,java,go,erlang,perl': ['re!\w{2}'],
           \ 'cs,lua,javascript': ['re!\w{2}'],
           \ }


" ycm补全框颜色
" 不过实际上这是设置了PMenu的高亮,可以通过:help highlight查看已经设置的高亮信息
highlight PMenu ctermfg=0 ctermbg=242 guifg=black guibg=darkgrey
highlight PMenuSel ctermfg=242 ctermbg=8 guifg=darkgrey guibg=black

" ycm获取类型信息
nnoremap ty :YcmCompleter GetType<CR>

  配置完成直接使用就可以,ycm还有个有趣的东西就是获取类型信息,但是不够完善,主要可以用来看看模板信息以及auto的类型,上面就把看类型信息的方法映射到快捷键ty,在normal模式下面按ty就可以看到符号类型了。顺带一提nnoremap这个map,第一个n代表这是normal模式下的映射,nore表示非递归映射。补全效果如下图,补全框的色彩风格如上是可以自定义的:

纠错

  代码纠错的插件就更多了,这里用的是ale,关闭了ycm自带的代码纠错。虽说现在ycm也实现了异步纠错(我放弃ycm纠错用ale就是因为一开始它是同步运行的),不过ale使用起来一直很顺手,我就没有换回ycm的打算了。

  • 安装
" ale语法检查
Plug 'w0rp/ale'

" 然后执行:PluginInstall
  • 配置
"================================================================
"ale
"始终开启标志列
let g:ale_sign_column_always = 0
let g:ale_set_highlights = 0
"自定义error和warning图标
let g:ale_sign_error = '✗'
let g:ale_sign_warning = '⚡'
"在vim自带的状态栏中整合ale,airline也可以显示这些信息
let g:ale_statusline_format = ['✗ %d', '⚡ %d', '✔ OK']
"显示Linter名称,出错或警告等相关信息
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
"普通模式下,sp前往上一个错误或警告,sn前往下一个错误或警告
nmap sp <Plug>(ale_previous_wrap)
nmap sn <Plug>(ale_next_wrap)
"<Leader>s触发/关闭语法检查

"文件内容发生变化时不进行检查
let g:ale_lint_on_text_changed = 'never'
"打开文件时不进行检查
let g:ale_lint_on_enter = 0


" C 语言配置检查参数
let g:ale_c_gcc_options              = '-Wall -Werror -O2 -std=c11'
let g:ale_c_clang_options            = '-Wall -Werror -O2 -std=c11'
let g:ale_c_cppcheck_options         = ''
" C++ 配置检查参数
" 因为我使用的是clang++进行代码,clang++当前版本对于C++20支持一般,就先用C++17了
let g:ale_cpp_gcc_options            = '-Wall -Werror -O2 -std=c++17'
7et g:ale_cpp_clang_options          = '-Wall -Werror -O2 -std=c++17
let g:ale_cpp_cppcheck_options       = ''

"
"使用clang对c和c++进行语法检查,对python使用pylint进行语法检查
let g:ale_linters = {
\   'c++': ['clang++'],
\   'c': ['clang'],
\   'python' : ['flake8']
\}

  代码纠错也是异步运行的,如果不想使用可以通过:ALEDisable关闭。

杂项
  • 彩虹花括号
" 彩虹括号
" 让不同层级的括号具有不同的颜色
"Plug 'luochen1990/rainbow'
Plug 'kien/rainbow_parentheses.vim'

"================================================================
"rainbow
let g:rbpt_colorpairs = [
    \ ['brown',       'RoyalBlue3'],
    \ ['Darkblue',    'SeaGreen3'],
    \ ['darkgray',    'DarkOrchid3'],
    \ ['darkgreen',   'firebrick3'],
    \ ['darkcyan',    'RoyalBlue3'],
    \ ['darkred',     'SeaGreen3'],
    \ ['darkmagenta', 'DarkOrchid3'],
    \ ['brown',       'firebrick3'],
    \ ['gray',        'RoyalBlue3'],
    \ ['darkmagenta', 'DarkOrchid3'],
    \ ['Darkblue',    'firebrick3'],
    \ ['darkgreen',   'RoyalBlue3'],
    \ ['darkcyan',    'SeaGreen3'],
    \ ['darkred',     'DarkOrchid3'],
    \ ['red',         'firebrick3'],
    \ ]

let g:rbpt_max = 16
let g:rbpt_loadcmd_toggle = 0
au VimEnter * RainbowParenthesesToggle
au Syntax * RainbowParenthesesLoadRound
au Syntax * RainbowParenthesesLoadSquare
au Syntax * RainbowParenthesesLoadBraces

  效果展示:

  • 自动括号匹配
"自动补全括号
Plug 'jiangmiao/auto-pairs'
  • 缩进线
"缩进指示线,在编辑py和golang之类的时候很不错
Plug 'Yggdroot/indentLine'

  效果展示:

  • 更漂亮的语法高亮
" 针对C++的语法高亮
Plug 'octol/vim-cpp-enhanced-highlight'

6. 杂项

  • 快速注释

  没有用插件的必要吧,改改配置就行了。按F2插入文件头,F3插入修改注释

"=================================================================
map <F2> :call SetTitle()<CR>

func SetComment()
        call setline(1,"/************************************************************************")
        call append(line("."),   "*   Copyright (C),xxxxxxxxxxxxxxxxxxxxxxx")
        call append(line(".")+1, "*   ")
        call append(line(".")+2, "*   File Name  :".expand("%:t"))
        call append(line(".")+3, "*   Author     :张三")
        call append(line(".")+4, "*   Version    :")
        call append(line(".")+5, "*   Date       :".strftime("%Y-%m-%d"))
        call append(line(".")+6, "*       Description:")
        call append(line(".")+7, "*")
        call append(line(".")+8,"************************************************************************/")
        call append(line(".")+9, "")
        call append(line(".")+10, "")
endfunc
" 加入shell,Makefile注释
func SetComment_sh()
        call setline(3, "#================================================================")
        call setline(4, "#   Copyright (C) xxxxxxxxxxxxxxxxxxxxxxx")
        call setline(5, "#   ")
        call setline(6, "#   File Name  :".expand("%:t"))
        call setline(7, "#   Author     :张三")
        call setline(8, "#   Version    :")
        call setline(9, "#   Date       :".strftime("%Y-%m-%d"))
        call setline(10, "#   Description:")
        call setline(11, "#")
        call setline(12, "#================================================================")
        call setline(13, "")
        call setline(14, "")
endfunc
" 定义函数SetTitle,自动插入文件头
func SetTitle()
        if &filetype == 'make'
                call setline(1,"")
                call setline(2,"")
                call SetComment_sh()

        elseif &filetype == 'sh'
                call setline(1,"#!/system/bin/sh")
                call setline(2,"")
                call SetComment_sh()

        else
             call SetComment()
             if expand("%:e") == 'hpp'
                  call append(line(".")+10, "#ifndef _".toupper(expand("%:t:r"))."_H")
                  call append(line(".")+11, "#define _".toupper(expand("%:t:r"))."_H")
                  call append(line(".")+12, "#ifdef __cplusplus")
                  call append(line(".")+13, "extern \"C\"")
                  call append(line(".")+14, "{")
                  call append(line(".")+15, "#endif")
                  call append(line(".")+16, "")
                  call append(line(".")+17, "#ifdef __cplusplus")
                  call append(line(".")+18, "}")
                  call append(line(".")+19, "#endif")
                  call append(line(".")+20, "#endif //".toupper(expand("%:t:r"))."_H")

             elseif expand("%:e") == 'h'
                call append(line(".")+10, "#pragma once")
             elseif &filetype == 'c'
                call append(line(".")+10,"#include \"".expand("%:t:r").".h\"")
             elseif &filetype == 'cpp'
                call append(line(".")+10, "#include \"".expand("%:t:r").".h\"")
             endif
        endif
endfunc

map <F3> :call QuickComment()<CR>
func QuickComment()
	if &filetype == 'make'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    elseif &filetype == 'c'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
	elseif &filetype == 'sh'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
	elseif &filetype == 'cpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
	elseif &filetype == 'hpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    endif
endfunc
  • F5编译并运行

  写一些小代码的时候会用的。不过现在都有了内置terminal,感觉没啥存在意义了啊

"=================================================================
"Quickly Run
""""""""""""""""""""""
map <F5> :call CompileRunGcc()<CR>
func! CompileRunGcc()
    exec "w"
    if &filetype == 'c'
        exec "!g++ % -o %<"
        exec "!time ./%<"
    elseif &filetype == 'cpp'
        exec "!g++ % -o %<"
        exec "!time ./%<"
    elseif &filetype == 'java'
        exec "!javac %"
        exec "!time java %<"
    elseif &filetype == 'sh'
        :!time bash %
    elseif &filetype == 'python'
        exec "!time python3 %"
    endif
endfunc
  • 擅用跳转

  除去G,gg,NG这样基本的跳转指令外,[[]]这两个指令也是很有意思的,可以跳到函数头和函数尾。此外ctrl+o指令可以少用,容易把buffer搞乱。多使用ctrl+t(跨文件跳转)以及fzf或者LeaderF的Buffer功能。

  • terminal

  在vim8.1之后实现了内置终端,asyncrun之类的插件也因此成为了历史。通过:terminal就可以打开一个终端,包括了异步执行任务等等功能,详见:help terminal

  • 编辑远程文件

  远程编辑有三种法子,一是ssh到远程,不多说。二是将远程文件夹挂载到本地,如:

sshfs -C -o reconnect 张三@123.123.123.123:/root/path/project /path/project

  /path/project必须得是空文件夹。卸载则使用:umount /path/project。出去sshfs,还有nfs等其他远程挂载方式

  第三种法子是直接用vim打开:

vim scp://张三@123.123.123.123:/root/path/project

  这些挂载方式效率和网络息息相关,能用IDE自带的挂载还是会更好一些


7. TODO

  • 有个很牛逼的插件叫vim-spector,用于可视化的调试代码(就是像vscode那样)。不过嘛暂时用不到,先记着再说。反正还是大代码看log,小代码手打gdb咯
  • vim内置的一堆more是否有办法替换呢,虽然可以设置格式让输出不那么丑,但more用起来还是别扭,嗯,慢慢找吧
  • ctags一系列工具生成了一堆tags文件,需要将他们全部移动到废弃的目录中,否则会污染项目
  • ctags和cscope会直接跳转到指定位置,这个行为并不一定时我想要的,看看有没有办法改一改script换掉它的默认行为

8. 完整的vimrc

" 映射的一些常用的操作
" f8	: 打开当前文件大纲,包括class定义,方法,成员变量等(使用ctags)
" f9	: 打开文件树
" ctrl+]:跳转到符号定义处
" ,+c   :跳转到符号被引用处
" ,+s   :在tags中查找符号
" ,+m   :高亮标记单词

"标签跳转:通过在项目根目录执行ctags -R生成tags文件,项目中的文件需要set tags=path/tags
"然后通过ctrl+]跳转到定义(或者g+ctrl+],会显示多个定义),通过ctrl+o跳转回去
"

"设置文件编码
set encoding=utf-8
set fileencodings=utf-8
set termencoding=utf-8

"设定leader键,Mark.vim使用了leader键
let mapleader=','

let g:solarized_termcolors=256
"设置主题
syntax on
set background=dark
colorscheme onehalfdark
"常用主题onedark,xcodelight,xcodedark,xcodewwdc
"gotham,gotham256,solarized

set cursorline
"设置保持历史记录10000
set history=10000

"打开文件时禁止折叠
set nofoldenable
"按照语法高亮进行折叠
set fdm=indent

set display=lastline
set scrolloff=5
set matchtime=2
set matchpairs+=<:>
set number
set showcmd
set showmatch


" 设置文件不备份,这里被注释掉;
set nobackup
set noundofile
set noswapfile
"set backupext=.bak
"set backupdir=~/.vim/vim_bak/

"语法高亮
set syntax=on
" 去掉输入错误的提示声音
set noeb
" 在处理未保存或只读文件的时候,弹出确认
set confirm
" 自动缩进
set autoindent
set cindent

" 设置tab为四个空格空格代替Tab
" 注意: 插入模式下输入【ctrl+v+i】可以强制输入一个tab
set tabstop=4     " tabstop 表示一个 tab 显示出来是多少个空格的长度,默认8
set softtabstop=4 " softtabstop 表示在编辑模式的时候按退格键的时候退回缩进的长度,当使用 expandtab 时特别有用
set expandtab     " 当设置成 expandtab 时,缩进用空格来表示,noexpandtab 则是用制表符表示一个缩进
set autoindent    " 自动缩进
set cindent       " 自动缩进补充
set shiftwidth=4  " 自动缩进空白字符个数
highlight WhitespaceEOL ctermbg=red guibg=red
match WhitespaceEOL /\s\+$/

" 显示行号
set number
" 历史记录数
set history=1000
"禁止生成临时文件
set nobackup
set noswapfile
"搜索忽略大小写
set ignorecase

set incsearch

set autoread
set autowrite

" 鼠标定位
" 鼠标定位和鼠标拷贝似乎不能共存,按住shift再使用鼠标拷贝
set mouse=a

" 普通模式下为光标方块,插入模式下为竖线
let &t_SI.="\e[6 q" "SI = INSERT mode
let &t_SR.="\e[4 q" "SR = REPLACE mode
let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE)

"光标颜色
highlight Cursor guifg=white guibg=white
highlight iCursor guifg=white guibg=white
set guicursor=n-v-c:block-Cursor
set guicursor+=i:ver100-iCursor
set guicursor+=n-v-c:blinkon0
set guicursor+=i:blinkwait10

set guitablabel=%N\ %f

"垂直分割线颜色
hi VertSplit guibg=#31312D guifg=#526A83 ctermfg=White ctermbg=Black term=none cterm=none gui=none

"plug插件管理器
call plug#begin('~/.vim/plugged')

"文件树
Plug 'preservim/nerdtree'
"Plug 'ryanoasis/vim-devicons'

"自动补全括号
Plug 'jiangmiao/auto-pairs'

"底部状态栏美化
"Plug 'vim-airline/vim-airline'
"Plug 'Lokaltog/vim-powerline'

"缩进指示线,在编辑py的时候很不错
Plug 'Yggdroot/indentLine'

"主题
Plug 'altercation/vim-colors-solarized'

"针对C++的语法高亮
Plug 'octol/vim-cpp-enhanced-highlight'

"ale语法检查
Plug 'w0rp/ale'

"标签导航插件
Plug 'majutsushi/tagbar'

"彩虹括号
"Plug 'luochen1990/rainbow'
Plug 'kien/rainbow_parentheses.vim'

"跳转与检索
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'

call plug#end()

filetype plugin indent on

"==============================================================
"YCM

" 每次重新生成匹配项,禁止缓存匹配项
let g:ycm_cache_omnifunc=0
" 在注释中也不能补全
let g:ycm_complete_in_comments=0
"关闭额外预览窗口
let g:ycm_add_preview_to_completeopt = 0
"基于syntastic的代码诊断,觉得慢的话可以换成ale
let g:ycm_show_diagnostics_ui = 0
let g:ycm_server_log_level = 'info'
let g:ycm_min_num_identifier_candidate_chars = 2
let g:ycm_collect_identifiers_from_comments_and_strings = 1
let g:ycm_complete_in_strings=1
let g:ycm_key_invoke_completion = '<c-z>'
set completeopt=menu,menuone

let g:ycm_global_ycm_extra_conf='~/.ycm_extra_conf.py'

let g:ycm_confirm_extra_conf = 0

noremap <c-z> <NOP>

" 选择语言
let g:ycm_semantic_triggers =  {
           \ 'c,cpp,python,java,go,erlang,perl': ['re!\w{2}'],
           \ 'cs,lua,javascript': ['re!\w{2}'],
           \ }


" ycm补全框颜色
highlight PMenu ctermfg=0 ctermbg=242 guifg=black guibg=darkgrey
highlight PMenuSel ctermfg=242 ctermbg=8 guifg=darkgrey guibg=black

" ycm获取类型信息
nnoremap ty :YcmCompleter GetType<CR>

"==============================================================
"nerdtree
"vim打开空文件时直接打开文件树
"autocmd StdinReadPre * let s:std_in=1
"autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif

"vim打开文件夹时打开文件树
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists("s:std_in") | exe 'NERDTree' argv()[0] | wincmd p | ene | exe 'cd '.argv()[0] | endif

autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif


" NERDTree.vim
" let g:NERDTreeWinPos="left"
let g:NERDTreeWinSize=30
" let g:NERDTreeShowLineNumbers=1
" let g:neocomplcache_enable_at_startup = 1
" 将打开文件树的操作映射到F8键
nnoremap <F8> :NERDTreeToggle<cr>

" NERDTress File highlighting
function! NERDTreeHighlightFile(extension, fg, bg, guifg, guibg)
        exec 'autocmd filetype nerdtree highlight ' . a:extension .' ctermbg='.a:bg .' ctermfg='. a:fg .' guibg='. a:guibg .' guifg='. a:guifg
        exec 'autocmd filetype nerdtree syn match ' . a:extension .' #^\s\+.*'.a:extension .'$#'
endfunction

call NERDTreeHighlightFile('cpp', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('cc', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('c', 'blue', 'none', 'blue', '#151515')
call NERDTreeHighlightFile('h', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('hpp', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('md', 'blue', 'none', '#3366FF', '#151515')
call NERDTreeHighlightFile('json', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('html', 'yellow', 'none', 'yellow', '#151515')
call NERDTreeHighlightFile('css', 'cyan', 'none', 'cyan', '#151515')
call NERDTreeHighlightFile('js', 'Red', 'none', '#ffa500', '#151515')

"================================================================
"ale
"始终开启标志列
let g:ale_sign_column_always = 0
let g:ale_set_highlights = 0
"自定义error和warning图标
let g:ale_sign_error = '✗'
let g:ale_sign_warning = '⚡'
"在vim自带的状态栏中整合ale
let g:ale_statusline_format = ['✗ %d', '⚡ %d', '✔ OK']
"显示Linter名称,出错或警告等相关信息
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
"普通模式下,sp前往上一个错误或警告,sn前往下一个错误或警告
nmap sp <Plug>(ale_previous_wrap)
nmap sn <Plug>(ale_next_wrap)
"<Leader>s触发/关闭语法检查

"文件内容发生变化时不进行检查
let g:ale_lint_on_text_changed = 'never'
"打开文件时不进行检查
let g:ale_lint_on_enter = 0


" C 语言配置检查参数
let g:ale_c_gcc_options              = '-Wall -Werror -O2 -std=c11'
let g:ale_c_clang_options            = '-Wall -Werror -O2 -std=c11'
let g:ale_c_cppcheck_options         = ''
" C++ 配置检查参数
let g:ale_cpp_gcc_options            = '-Wall -Werror -O2 -std=c++17'
let g:ale_cpp_clang_options          = '-Wall -Werror -O2 -std=c++17'
let g:ale_cpp_cppcheck_options       = ''

"
"使用clang对c和c++进行语法检查,对python使用pylint进行语法检查
let g:ale_linters = {
\   'c++': ['clang++'],
\   'c': ['clang'],
\   'python' : ['flake8']
\}

"===============================================================
"powerline
set laststatus=2
let g:Powerline_symbols='unicode'

"===============================================================
"airline
" tabline,也就是上方的tab列表
let g:airline#extensions#tabline#enabled = 1
" 显示tab的分割
let g:airline#extensions#tabline#show_splits = 0
" 不显示buffer
let g:airline#extensions#tabline#show_buffers = 0
" tab的显示风格
let g:airline#extensions#tabline#alt_sep = 1
let g:airline#extensions#tabline#left_sep = ' '
let g:airline#extensions#tabline#left_alt_sep = '◀'

let g:airline#extensions#tabline#tab_nr_type = 1 " tab number
let g:airline#extensions#tabline#show_tab_nr = 0

" let g:airline#extensions#tabline#formatter = 'default'
" 只显示文件名字
let g:airline#extensions#tabline#formatter = 'unique_tail'
" 文件名过长则显示...
let g:airline#extensions#tabline#overflow_marker = '…'
let g:airline_powerline_fonts = 1

" 关闭一堆不需要的
let g:airline#extensions#tabline#buffer_nr_show = 0
let g:airline#extensions#tabline#exclude_preview = 0
"if !exists('g:airline_symbols')
"  let g:airline_symbols = {}
"endif

let g:airline_theme="onedark"

let g:airline_left_sep = '▶'
let g:airline_left_alt_sep = '❯'
let g:airline_right_sep = '◀'
let g:airline_right_alt_sep = '❮'

"================================================================
"rainbow
let g:rbpt_colorpairs = [
    \ ['brown',       'RoyalBlue3'],
    \ ['Darkblue',    'SeaGreen3'],
    \ ['darkgray',    'DarkOrchid3'],
    \ ['darkgreen',   'firebrick3'],
    \ ['darkcyan',    'RoyalBlue3'],
    \ ['darkred',     'SeaGreen3'],
    \ ['darkmagenta', 'DarkOrchid3'],
    \ ['brown',       'firebrick3'],
    \ ['gray',        'RoyalBlue3'],
    \ ['darkmagenta', 'DarkOrchid3'],
    \ ['Darkblue',    'firebrick3'],
    \ ['darkgreen',   'RoyalBlue3'],
    \ ['darkcyan',    'SeaGreen3'],
    \ ['darkred',     'DarkOrchid3'],
    \ ['red',         'firebrick3'],
    \ ]

let g:rbpt_max = 16
let g:rbpt_loadcmd_toggle = 0
au VimEnter * RainbowParenthesesToggle
au Syntax * RainbowParenthesesLoadRound
au Syntax * RainbowParenthesesLoadSquare
au Syntax * RainbowParenthesesLoadBraces

"================================================================
"tagbar
"设置tagbar使用的ctags的插件,必须要设置对
let g:tagbar_ctags_bin='/usr/bin/ctags'
""设置tagbar的窗口宽度
let g:tagbar_width=35
"设置tagbar的窗口显示的位置,为右边
let g:tagbar_left=0
"打开文件自动 打开tagbar
"autocmd BufReadPost *.cpp,*.c,*.h,*.hpp,*,*.cxx call tagbar#autoopen()
"映射tagbar的快捷键
map <F9> :TagbarToggle<CR>
" 设置焦点在tagbar
let g:tagbar_autofocus=1

"=================================================================
" ctags
" 设置tag跳转快捷键
nnoremap <leader>] g<C-]>
" 添加已经存在的tags文件
if filereadable("tags")
        set tags+=./tags
endif
" ctags -R --c++-kinds=+px --fields=+iaS --extra=+q


"=================================================================
"fzf
"
" FZF -e name:在当前文件夹下精确匹配搜索文件
" Files name : 在当前文件夹下模糊匹配搜索文件,相当于FZF name
" Tags name  :根据ctags生成的tags搜索标签
" Ag name    :全文本模糊匹配,需要安装额外工具,详见官方md

" This is the default extra key bindings
let g:fzf_action = {
  \ 'ctrl-t': 'tab split',
  \ 'ctrl-x': 'split',
  \ 'ctrl-v': 'vsplit' }
" Default fzf layout
" - down / up / left / right
let g:fzf_layout = { 'down': '~40%' }
" In Neovim, you can set up fzf window using a Vim command
" let g:fzf_layout = { 'window': 'enew' }
" let g:fzf_layout = { 'window': '-tabnew' }
" let g:fzf_layout = { 'window': '10split enew' }

" Customize fzf colors to match your color scheme
let g:fzf_colors =
\ { 'fg':      ['fg', 'Normal'],
  \ 'bg':      ['bg', 'Normal'],
  \ 'hl':      ['fg', 'Comment'],
  \ 'fg+':     ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
  \ 'bg+':     ['bg', 'CursorLine', 'CursorColumn'],
  \ 'hl+':     ['fg', 'Statement'],
  \ 'info':    ['fg', 'PreProc'],
  \ 'border':  ['fg', 'Ignore'],
  \ 'prompt':  ['fg', 'Conditional'],
  \ 'pointer': ['fg', 'Exception'],
  \ 'marker':  ['fg', 'Keyword'],
  \ 'spinner': ['fg', 'Label'],
  \ 'header':  ['fg', 'Comment'] }
" Enable per-command history.
" CTRL-N and CTRL-P will be automatically bound to next-history and
" previous-history instead of down and up. If you don't like the change,
" explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS.

" fzf的缓存文件,加快查找
let g:fzf_history_dir = '~/.local/share/fzf-history'

" [Buffers] 如果可能跳到已存在窗口,这里关闭了
let g:fzf_buffers_jump = 0
" [[B]Commits] 自定义被'git log'使用的选项
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'

" [Tags] 定义用来产生tag的命令,好像就ctags可以,gtags不兼容。LeaderF可以使用gtags
let g:fzf_tags_command = 'ctags -R'
" [Commands] --expect expression for directly executing the command
let g:fzf_commands_expect = 'alt-enter,ctrl-x'

" 历史缓存文件,加快查找速度
let g:fzf_history_dir = '~/.local/share/fzf-history'

"=================================================================


"=================================================================
" Mark
" 打开vim时重置mark
set viminfo='64,<8192,s1024,!,h


"=================================================================
" cscope
" cscope -Rbq,生成cscope数据库,使用方式类似ctags
" cscope find c name,查找调用该函数的函数
" set quickfix,把信息打到quickfix里面,不过还是全屏好用
" set cscopequickfix=s-,c-,d-,i-,t-,e-

" use both cscope and ctag for 'ctrl-]', ':ta', and 'vim -t'
" set cscopetag

" check cscope for definition of a symbol before checking ctags: set to 1
" if you want the reverse search order.
set csto=0

" add any cscope database in current directory
if filereadable("cscope.out")
        cs add cscope.out
" else add the database pointed to by environment variable
elseif $CSCOPE_DB != ""
        cs add $CSCOPE_DB
endif

" show msg when any other cscope db added
set cscopeverbose

" 设置输出文件信息长度,文件路径深度最高为五
:set cspc=5

" 设置输出信息的颜色
" 通过:highlight查看所有高亮属性
:hi ModeMsg ctermfg=Blue
:hi MoreMsg ctermfg=Red
:hi Directory term=bold ctermfg=114 guifg=#98c379

" 快捷键
nmap <leader>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nnoremap <leader>s :Tags <C-R>=expand("<cword>")<CR><CR>

" 同时查找ctags和cscope的数据库
set cst


"=================================================================
" gtags
set cscopetag " 使用 cscope 作为 tags 命令
set cscopeprg='gtags-cscope' " 使用 gtags-cscope 代替 cscope

"gtags.vim 设置项
let GtagsCscope_Auto_Load = 1
let CtagsCscope_Auto_Map = 1
let GtagsCscope_Quiet = 1
" 并不是禁止了cscope与ctags,gtags是在C++与java方面的补充


"=================================================================
map <F2> :call SetTitle()<CR>

func SetComment()
        call setline(1,"/************************************************************************")
        call append(line("."),   "*   Copyright (C), xxxxxxxxxxxxxxxx.")
        call append(line(".")+1, "*   ")
        call append(line(".")+2, "*   File Name  :".expand("%:t"))
        call append(line(".")+3, "*   Author     :张三")
        call append(line(".")+4, "*   Version    :")
        call append(line(".")+5, "*   Date       :".strftime("%Y-%m-%d"))
        call append(line(".")+6, "*       Description:")
        call append(line(".")+7, "*")
        call append(line(".")+8,"************************************************************************/")
        call append(line(".")+9, "")
        call append(line(".")+10, "")
endfunc
" 加入shell,Makefile注释
func SetComment_sh()
        call setline(3, "#================================================================")
        call setline(4, "#   Copyright (C),xxxxxxxxxxxxxxxxx.")
        call setline(5, "#   ")
        call setline(6, "#   File Name  :".expand("%:t"))
        call setline(7, "#   Author     :张三")
        call setline(8, "#   Version    :")
        call setline(9, "#   Date       :".strftime("%Y-%m-%d"))
        call setline(10, "#   Description:")
        call setline(11, "#")
        call setline(12, "#================================================================")
        call setline(13, "")
        call setline(14, "")
endfunc
" 定义函数SetTitle,自动插入文件头
func SetTitle()
        if &filetype == 'make'
                call setline(1,"")
                call setline(2,"")
                call SetComment_sh()
        elseif &filetype == 'sh'
                call setline(1,"#!/system/bin/sh")
                call setline(2,"")
                call SetComment_sh()
        else
             call SetComment()
             if expand("%:e") == 'hpp'
                  call append(line(".")+10, "#ifndef _".toupper(expand("%:t:r"))."_H")
                  call append(line(".")+11, "#define _".toupper(expand("%:t:r"))."_H")
                  call append(line(".")+12, "#ifdef __cplusplus")
                  call append(line(".")+13, "extern \"C\"")
                  call append(line(".")+14, "{")
                  call append(line(".")+15, "#endif")
                  call append(line(".")+16, "")
                  call append(line(".")+17, "#ifdef __cplusplus")
                  call append(line(".")+18, "}")
                  call append(line(".")+19, "#endif")
                  call append(line(".")+20, "#endif //".toupper(expand("%:t:r"))."_H")

             elseif expand("%:e") == 'h'
                call append(line(".")+10, "#pragma once")
             elseif &filetype == 'c'
                call append(line(".")+10,"#include \"".expand("%:t:r").".h\"")
             elseif &filetype == 'cpp'
                call append(line(".")+10, "#include \"".expand("%:t:r").".h\"")
             endif
        endif
endfunc

map <F3> :call QuickComment()<CR>
func QuickComment()
        if &filetype == 'make'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    elseif &filetype == 'c'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'sh'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'cpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'hpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    endif
endfunc


, "#endif")
                  call append(line(".")+20, "#endif //".toupper(expand("%:t:r"))."_H")

             elseif expand("%:e") == 'h'
                call append(line(".")+10, "#pragma once")
             elseif &filetype == 'c'
                call append(line(".")+10,"#include \"".expand("%:t:r").".h\"")
             elseif &filetype == 'cpp'
                call append(line(".")+10, "#include \"".expand("%:t:r").".h\"")
             endif
        endif
endfunc

map <F3> :call QuickComment()<CR>
func QuickComment()
        if &filetype == 'make'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    elseif &filetype == 'c'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'sh'
        call append(line("."), "# start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "# end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'cpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
        elseif &filetype == 'hpp'
        call append(line("."), "// start modified by 张三 in ".strftime("%Y-%m-%d")." ")
        call append(line(".")+1, "// end modified by 张三 in ".strftime("%Y-%m-%d")." ")
    endif
endfunc

本文标签: 项目 vim