关于vim:工欲善其事必先利其器系列之四构建基于Vim的补全跳转插件YouCompleteMe的Docker镜像一键部署开发环境

2次阅读

共计 26876 个字符,预计需要花费 68 分钟才能阅读完成。

日期 作者 版本 备注
2021-03-24 dingbin V1.0

C++ 程序员日常开发中不可避免地遇到变更电脑,变更服务器等事件时重建搭建 C ++ 开发环境切实过于沉重,须要消耗很多不必要的宝贵时间。vim 的 YouCompleteMe(简称 YCM) 插件能够实现较好的 C /C++ 语言主动补全跳转性能,是利用 vim 进行 C /C++ 代码编辑的必备神器之一。而后理论中 YCM 的装置及其简单,不仅依赖 python 动态链接库,还依赖特定高版本的 gcc 和 clang 或 clangd 和 cmake 等。筹备这些前置组件也很费时费力。有鉴于此,本文介绍一种新的玩法,并给出实际操作细节和间接可用的 docker 镜像成绩,即:构建基于 Vim 的 C ++ 补全跳转插件 YouCompleteMe 的 Docker 镜像,一键实现任意机器上 C ++ 开发环境搭建。具体操作办法介绍如下。

环境筹备

工夫:2021-03-24

机器配置:CentOS Linux release 7.5.1804 (Core),8 核 12G

创立根底的 docker 镜像

思考装置以后工夫下最新版本的 vim 和 YoucompleteMe 插件。参考 YouCompleteMe 官网介绍的装置办法要求 vim/gcc/clang/clangd/cmake/python 都在比拟高的版本下能力装置胜利。而咱们为了制作 docker 镜像,因而不可能选很旧的根底 os。参考 YCM 官网的倡议,咱们根底 OS 抉择 ubuntu 20.04 LTS。hub.docker.com 上间接现成的镜像文件。配置文件须要筹备好如下 3 个配置文件,本文间接贴出原文内容如下:

vim 配置文件.vimrc

set nocompatible              " be iMproved, required
filetype off                  " required
set encoding=utf-8
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'
Plugin 'flazz/vim-colorschemes'
Plugin 'godlygeek/csapprox'
Plugin 'Valloric/YouCompleteMe'
call vundle#end()            " required
filetype plugin indent on    " required

set cst
set csto=1 
set nocsverb
set csverb

"set smd"set showmode
"set sc"set showcmd

set aw         "set autowrite
set awa        "set autowriteall

set  title

" 使关上文件时使光标主动定位到上一次文件被敞开时的精确行
if has("autocmd")
  autocmd BufRead *.txt set tw=78
  au BufReadPost * exe "normal! g`\""
endif

" 设置高亮关键字显示
syntax enable
syntax on     "等同于 syn on" 禁止在搜寻到文件两端时从新搜寻
"set nows"set nowrapscan              
set ws

" 设置搜寻式的匹配字符串高亮显示
set hls    "set hlsearch" 设置搜寻式的匹配字符串不高亮显示
"set nohls"set nohlsearch 

" 高亮光标所在的以后行 set cursorline
set cul         "相同的设置是 set nocul"set nocul


" 搜寻时在未齐全输出结束要检索的文本时就开始检索
set is       "set incsearch" 搜寻时在未齐全输出结束要检索的文本时不开始检索
"set nois"set noincsearch

" 设置以 backspace 删除主动缩进的,行末回车,行首的字符,很有用
set backspace=indent,eol,start

set ic   "相同是 set noic"set scs  "相同是 set noscs" 加强模式中的命令行主动实现操作, 十分有用
set wildmenu

"设置代码折叠为按语法折叠"set foldmethod=syntax
" 设定折叠形式为手动
set foldmethod=manual
" 设置启动 vim 时不要主动折叠代码
set foldlevel=100
set fdc=1      "set foldcolumn=1" 设置帮忙的语言为中文
set helplang=cn
"set helplang=en" 实现 C 程序的缩进(indent)
set cin   

" 设置行号
set nu
"set nonu" 设置 256 色调
set t_Co=256
"设置配色计划"colorscheme 简写成 colo
"colo colorful"colo white2 
colo  desert
"colo  night"colo  navajo
"colo  lucius"colo  blackdust
"colo  freya"colo  darkslategray
"colo  torte"colo  fruidle
"colo colorful" 设置编辑模式下状态栏标尺显示
set ru "set ruler" 设置编辑模式下状态栏标尺不显示
"set noru"set noruler

" 记录历史的行数
set history=1000

"检测文件类型"filetype on
filetype plugin on
" 开启文件类型检测 的插件和缩进开
filetype plugin indent on   

" 设置能够至上一行和下一行的字符按键
set ww=b,s,<,>,[,]  ",h,l"Alt 组合键不映射到菜单上
set winaltkeys=no

" 同时反对 GBK 和 UTF- 8 编码
set fileencodings=utf-8,ucs-bom,gbk,cp936
set fileencoding=utf-8
set encoding=utf-8
" 如果在终端环境下应用 Vim,须要设置 termencoding 和终端所应用的编码统一。例如:set termencoding=utf-8 

"设置更新 ctags 文件的快捷键"map <F3>   : !  ${HOME}/tools/gen_tags_by_dingbin.bash "%:p:h" z6tags  <CR>
"map <F4>   : !  ${HOME}/tools/gen_tags_by_dingbin.bash"%:p:h"oatags  <CR>"map <F5>   : !  ${HOME}/tools/gen_tags_by_dingbin.bash "%:p:h" qttags  <CR>

"===================================================================================================================="map <silent> <F4>   : cs show <CR>: let @i = &tags <CR> :let @j = $CSCOPE_TAGS <CR> : !genvimtags -vimCtags <c-r>i -vimCscope <c-r>j <cr> :so ${VIM_SCRIPT_HOME}/configure/vimSourceFile <cr>
"map <silent> <F5>   : cs show <CR>: let @i = &tags <CR> :let @j = $CSCOPE_TAGS <CR> : !genvimtags  -g -vimCtags <c-r>i -vimCscope <c-r>j <cr> :so ${VIM_SCRIPT_HOME}/configure/vimSourceFile <cr>"====================================================================================================================

"设置 grep 插件的快捷键"nnoremap <silent> <F4> :Grep<CR>

"-----------------------------------------------------" 主动缩进的时候,缩进尺寸为 4 个空格。" 即 shiftWidth,主动缩进的空格数,用于 <<,>>,cindent
set shiftwidth=4         

"softtabstop,sts, 默认是 0," 执行编辑操作,如插入 <Tab> 或者应用 <BS> 时,把 <Tab> 算作空格的数目
set softtabstop=4     "set sts=4" 编辑时将所有 Tab 替换为空格。"该选项只在编辑时将 Tab 替换为空格,如果关上一个曾经存在的文件,并不会将已有的 Tab 替换为空格。" 设置了该选项后,如果想输出 tab 制表符,先输出 CTRL- V 或 CTRL-Q,再输出 tab 制表符
set et    "相同的设置是 set noet"Tab 宽度为 4 个字符。set ts=4      "即 set tabstop=4"Tab 操作快捷方式!
"nnoremap <C-TAB>  :tabnext<CR><CR>:TlistClose<CR><CR>:TlistToggle<CR><CR>"nnoremap <C-S-TAB>  :tabprev<CR><CR>:TlistClose<CR><CR>:TlistToggle<CR><CR>
"nnoremap <C-TAB>  :tabnext<CR><CR>:TlistClose<CR><CR>"nnoremap <C-S-TAB>  :tabprev<CR><CR>:TlistClose<CR><CR>


""对于 tab 的快捷键"map tn :tabnext<cr>
"map tp :tabprevious<cr>"map td :tabnew .<cr>
"map te :tabedit<SPACE>"map tc :tabclose<cr>
""map tf :tabnew %:p<cr>:TlistClose<CR><CR>:TlistToggle<CR><CR>"map tf :tabnew %:p<cr>:TlistClose<CR><CR>

" 覆盖文件时不备份
set nobackup                                                        
" 胜利保留文件之前备份             
set wb          "set writebackup"set nowb         "set nowritebackup" 插入括号时, 短暂地跳转到匹配的对应括号
set sm            "set showmatch" 短暂跳转到匹配括号的工夫
set matchtime=2

" 设置魔术
set magic                   

" 容许在有未保留的批改时切换缓冲区,此时的批改由 vim 负责保留
set hidden                  

" 开启新行时应用智能主动缩进
set smartindent             
set autoindent
" 关上一般文件类型的主动缩进。该主动缩进不如 cindent 智能,但它能够为你编辑非 C/C++ 文件提供肯定帮忙。set ai

"选中状态下 Ctrl+c 复制"vmap <C-c> "+y" 留神应用的过程中能够通过 e 和 b 键盘以 word 为单位后退或后退以抉择文本
"set keymodel=" 不应用此性能
set keymodel=startsel,stopsel     "应用此性能"visual 模式下标签查找 (*,#) 可用
vnoremap  *  y<ESC>/<C-r>"<CR>  
vnoremap  #  y<ESC>?<C-r>"<CR>  
nnoremap  g[:tag <C-R>=expand("<cWORD>")<CR><CR>
vnoremap  g[  <ESC>:tag <C-r>*<CR>

:inoremap (()<ESC>i
:inoremap [[]<ESC>i
:inoremap ;; <ESC>A;<CR>

" 插入模式下使 Ctrl+ h,j,k,l 四个键成果等同于挪动上、下、左、右方向键
inoremap <C-h> <Left>
inoremap <C-j> <Down>
inoremap <C-k> <Up>
inoremap <C-l> <Right>
"插入模式下使 ctrl+ w,b 两个键成果等同于一般模式下 ctrl+w(后退一个单词),ctrl+b(" 后退一个单词)
inoremap <C-b> <C-o>b
inoremap <C-w> <C-o>w
" 插入模式下使 ctrl+ f(front),Ctrl+e(end)两个键成果等同于一般模式下 <home>,<end> 键
inoremap <C-e>  <C-o><End>
inoremap <C-f>  <C-o><Home>
"插入模式下 ctrl + d, 等效于一般模式下 backspace 键," 插入模式下 ctrl + x, 等效于一般模式下 delete 键,inoremap <C-d> <BS>
inoremap <C-x> <Del>

" 指定在抉择文本时, 光标所在位置也属于被选中的范畴
set selection=inclusive
"-----------------------------------------------------"-----------------------------------------------------
" 指定不折行。如果一行太长,超过屏幕宽度,则向左边延长到屏幕里面。如果应用图形界面的话,指定不折行视觉效果会好得多。set nowrap
"set wrap" 设置显示时一行的文本宽宽
set tw=80       "set textwidth=80" 增加程度滚动条。如果你指定了不折行,那为窗口增加一个程度滚动条就十分有必要了。set guioptions-=b
" 去除 vim 的 GUI 版本的 toolbar
set guioptions+=T
" 去除 vim 的 GUI 版本的 menubar
set guioptions+=m

"设置断行,当一行的文字太长时,为主动智能在一个单词的两头" 空白处断开到下一行显示,留神:这里的断行只用显示,并不在行末加 <EOF>
set lbr           "set linebreak" 关上断行模块对亚洲语言反对。m 示意容许在两个汉字之间断行,即便汉字之间没有呈现空格。"B 示意将两行合并为一行的时候,汉字与汉字之间不要补空格。该命令反对的更多的选项请参看用户手册。set fo+=mB

"配置字体"set fileencoding=gbk
"set guifont=Courier\ 11"set guifont=Inconsolata\ Medium\ 9  "史上最难看的 vim 字体"set guifont=Bitstream_Vera_Sans_Mono:h10:cANSI
"set gfw= 幼圆:h10.5:cGB2312
set guifont=Bitstream\ Vera\ Sans\ Mono\ 13

" 当右键单击窗口的时候,弹出快捷菜单
set mousemodel=popup
" 不应用抉择模式
set selectmode=

" 设置屏幕滚动的 ctrl+d,ctrl+ u 的行数,默认是窗口的一半,即半屏
set scr=4

"-----------------------------------------------------"""""""""""""""""""""""""""""""
""Taglist plugin settings"""""""""""""""""""""""""""""""
"let Tlist_Auto_Highlight_Tag = 1"let Tlist_Hightlight_Tag_On_BufEnter = 1
"let Tlist_GainFocus_On_ToggleOpen = 0"if 0 focus at code window, if 1 focus at tag window
""" 启动 vim 主动关上 taglist
"let Tlist_Auto_Open = 0"
""不同时显示多个文件的 tag,只显示以后文件的"let Tlist_Show_One_File = 1
""" 如果 taglist 窗口是最初一个窗口,则退出 vim
"let Tlist_Exit_OnlyWindow = 1"
""让以后不被编辑的文件的办法列表主动折叠起来"let Tlist_File_Fold_Auto_Close = 0
""" 把 taglist 窗口放在屏幕的右侧,缺省在左侧 
"let Tlist_Use_Right_Window=1"
""显示 taglist 菜单"let Tlist_Show_Menu = 1
"""taglist window width
"let Tlist_WinWidth = 40"
"let Tlist_Process_File_Always = 1"
""是否容许关上 taglist 窗口时主动加宽窗口, 默认为容许."let Tlist_Inc_Winwidth = 1
""精简模式, 不同的 tag 类别之间没有空行, 默认为有空行"let Tlist_Compact_Format = 1
""tag 是以何种程序排序, 以"order"还是"name", 默认是 order, 能够用 s 切换,"let Tlist_Sort_Type = "order"
""" 用 <ALT> + 数字切换 Tab 窗口
""用过 Gnome-terminal 的人都晓得, 在一个 Terminal 里关上多个 TAB 窗口, 用 ALT+ 数字就能够"" 切换到相应的窗口. 很喜爱这个性能, 映射如下:
""noremap <M-1> 1gt"noremap <M-2> 2gt
"noremap <M-3> 3gt"noremap <M-4> 4gt
"noremap <M-5> 5gt"noremap <M-6> 6gt
"noremap <M-7> 7gt"noremap <M-8> 8gt
"noremap <M-9> 9gt"noremap <M-0> 10gt
"""""""""""""""""""""""""""""""""
""Winmanager plugin settings"""""""""""""""""""""""""""""""
""设置界面宰割"let g:winManagerWindowLayout='FileExplorer|TagList'
""let g:winManagerWindowLayout = BufExplorer,FileExplorer|TagList"
""let g:winManagerWindowLayout = TagList|FileExplorer,BufExplorer"
""" 设置 winmanager 的宽度,默认为 25
""let g:winManagerWidth = 30"
""定义关上敞开 winmanager 按键"nmap wm :WMToggle<cr>
""nmap <silent> <F8> :WMToggle<cr>"nmap <silent> <F4> :TlistToggle<cr>
"""1)将插件显示在右侧
""关上 winmanager.vim,在 function! <SID>StartWindowsManager()函数中批改:"" 将:wincmd H 批改为 wincmd L:""for now assume that the explorer windows always stay on the left."" TODO: make this optional later
""make the explorers window always stay on the right ---by chenyong""        wincmd H
""wincmd L"
""2)进入 vim 主动关上 winmanager"" 在进入 vim 时主动关上 winmanager
"let g:AutoOpenWinManager = 0"" 相应的在 winmanager.vim 中批改:""set auto open Winmanager""if g:AutoOpenWinManager 
""autocmd VimEnter * nested call s:StartWindowsManager()|1wincmd w""endif
"""3)退出缓冲区时,主动退出 vim
""这个性能是参考了 taglist 的主动退出性能,在 taglist.vim 中批改的。"" 函数:function! s:Tlist_Window_Exit_Only_Window()中的 winbunr(2)改为 winbunr(3),""即只剩 2 个窗口时敞开,思考到 2 个窗口必定是同时存在,所以这样还是可行的:"" 同时在 vimrc 中须要设置:""let Tlist_Exit_OnlyWindow=1"
""""""""""""""""""""""""""""""""
""QuickFix plugin settings"""""""""""""""""""""""""""""""
"nmap <F7> :cw<cr>:cn<cr>"nmap <F6> :cw<cr>:cp<cr>
"nmap <F9> :cclose<cr>"
""""""""""""""""""""""""""""""""""""""""""""""""""""""" 设定是否应用 quickfix 窗口来显示 cscope 后果
"""""""""""""""""""""""""""""""""""""""""""""""""""""":set cscopequickfix=s-,g-,c-,d-,i-,t-,e-,f-"
"""cscope find"的用法:""cs find c|d|e|f|g|i|s|t name
""0 或 s     查找本 C 符号(能够跳过正文)""1 或 g     查找本定义
""2 或 d     查找本函数调用的函数""3 或 c     查找调用本函数的函数
""4 或 t     查找本字符串""6 或 e     查找本 egrep 模式
""7 或 f     查找本文件""8 或 i     查找蕴含本文件的文件
"nmap <C-_>s :cs find s <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>g :cs find g <C-R>=expand("<cword>")<CR><CR>
"nmap <C-_>c :cs find c <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>t :cs find t <C-R>=expand("<cword>")<CR><CR>
"nmap <C-_>e :cs find e <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
"nmap <C-_>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>"nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>
"""""""""""""""""""""""""""""""""""""""""""""""""""""""
""头文件与源文件互相切换 a.vim settings"""""""""""""""""""""""""""""""""""""""""""""""""""""
""nnoremap <silent> <F12> :A<CR>""A         在新 Buffer 中切换到 c\h 文件
""AS     横向宰割窗口并关上 c\h 文件""AV     纵向宰割窗口并关上 c\h 文件
""AT     新建一个标签页并关上 c\h 文件"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""  F11 : set csto=1, F12 : set csto=0
""""""""""""""""""""""""""""""""""""""""""""""""""""""nnoremap <silent> <F11> :set csto=1 <CR>"nnoremap <silent> <F12> :set csto=0 <CR> 
"""" set cs hotkey
"nmap <C-_>s :cs find s <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>g :cs find g <C-R>=expand("<cword>")<CR><CR>
"nmap <C-_>c :cs find c <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>t :cs find t <C-R>=expand("<cword>")<CR><CR>
"nmap <C-_>e :cs find e <C-R>=expand("<cword>")<CR><CR>"nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
"nmap <C-_>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>"nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>
""" Using 'CTRL-spacebar' then a search type makes the vim window
""split horizontally, with search result displayed in"" the new window.
""nmap <S-Space>s :scs find s <C-R>=expand("<cword>")<CR><CR>"nmap <S-Space>g :scs find g <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space>c :scs find c <C-R>=expand("<cword>")<CR><CR>"nmap <S-Space>t :scs find t <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space>e :scs find e <C-R>=expand("<cword>")<CR><CR>"nmap <S-Space>f :scs find f <C-R>=expand("<cfile>")<CR><CR>
"nmap <S-Space>i :scs find i ^<C-R>=expand("<cfile>")<CR>$<CR>"nmap <S-Space>d :scs find d <C-R>=expand("<cword>")<CR><CR>
""" Hitting CTRL-space *twice* before the search type does a vertical
""split instead of a horizontal one"
"nmap <S-Space><S-Space>s"            \:vert scs find s <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space><S-Space>g"            \:vert scs find g <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space><S-Space>c"            \:vert scs find c <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space><S-Space>t"            \:vert scs find t <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space><S-Space>e"            \:vert scs find e <C-R>=expand("<cword>")<CR><CR>
"nmap <S-Space><S-Space>i"            \:vert scs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
"nmap <S-Space><S-Space>d"            \:vert scs find d <C-R>=expand("<cword>")<CR><CR>

function AddFileTitle()
call append(0," ")
call setline(1,"////////////////////////////////////////////////////////////////////////")
call append(1,"/// @Filename" . expand("%:p:t"))
call append(2,"/// @Description")
call append(3,"/// @Author           DingBin")
call append(4,"/// @Last modified" . strftime("%Y-%m-%d %H:%M"))
call append(5,"////////////////////////////////////////////////////////////////////////")
endfunction

function AddFileComment()
call append(line(".") -1," ")
call setline(line(".") -1,"////////////////////////////////////////////////////////////////////////")
call append(line(".") - 1,"/// @brief     :")
call append(line(".") - 1,"/// @param     :")
call append(line(".") - 1,"/// @return    :")
call append(line(".") - 1,"////////////////////////////////////////////////////////////////////////")
endfunction

function AddoaArrayFor()
call append(line(".") -1," ")
call setline(line(".") -1,"for (oaUInt4 i = 0; i < .getNumElements(); i++ )")
endfunction

map time :0,50/\/\/\/ *@Last modified/s#@Last modified.*$#\=strftime("@Last modified    %Y-%m-%d %H:%M")#c

map addt :call AddFileTitle()<cr>
map addc :call AddFileComment()<cr>
map addf :call AddoaArrayFor()<cr>

"nnoremap <C-1>  1gt"nnoremap <C-2>  2gt 
"nnoremap <A-3>  3gt"nnoremap <A-4>  4gt 
"nnoremap <A-5>  5gt"nnoremap <A-6>  6gt 
"nnoremap <A-7>  7gt"nnoremap <A-8>  8gt 
"nnoremap <A-9>  9gt"Mode Settings
let &t_SI.="\e[5 q" "SI = INSERT mode"let &t_SR.="\e[4 q" "SR = REPLACE mode
let &t_EI.="\e[1 q" "EI = NORMAL mode (ELSE)"Cursor settings:
"1 -> blinking block"  2 -> solid block
"3 -> blinking underscore"  4 -> solid underscore
"5 -> blinking vertical bar"  6 -> solid vertical bar

"let &t_SI ="\<Esc>]50;CursorShape=1\x7""let &t_SR ="\<Esc>]50;CursorShape=2\x7""let &t_EI ="\<Esc>]50;CursorShape=0\x7""-----------------------------------------------------" 对于状态行配置
" 总是显示状态行
set laststatus=2            "set ls=2"-----  状态栏设置_BEGIN_ -----
" 显示以后文件名,文件格式,文件类型
set statusline=%2*%n%m%r%h%w%*\ %F\ %1*[FORMAT=%2*%{&ff}:%{&fenc!=''?&fenc:&enc}%1*]\ [TYPE=%2*%Y%1*]\ [COL=%2*%03v%1*]\ [ROW=%2*%03l%1*/%3*%L(%p%%)%1*]\" 设置状态栏依据不同状态显示不同色彩
function! InsertStatuslineColor(mode)
    if a:mode == 'i'
        hi statusline guibg=peru
    elseif a:mode == 'r'
        hi statusline guibg=blue
    else
        hi statusline guibg=red
    endif
endfunction
au InsertEnter * call InsertStatuslineColor(v:insertmode)
au InsertLeave * hi statusline guibg=lightGreen guifg=black
hi statusline guibg=lightGreen
" 状态行色彩
highlight CursorLine cterm=NONE ctermbg=lightGray ctermfg=green 
highlight StatusLineNC cterm=NONE ctermbg=lightGray ctermfg=green 
"highlight CursorLine cterm=NONE ctermbg=lightGray ctermfg=green guifg=lightGray guibg=green"highlight StatusLineNC cterm=NONE ctermbg=lightGray ctermfg=green   guibg=lightGray guifg=green 
"highlight CursorLine cterm=NONE ctermbg=lightGray ctermfg=green guifg=red guibg=Green"highlight StatusLineNC cterm=NONE ctermbg=lightGray ctermfg=green guifg=Gray guibg=White
"highlight CursorLine cterm=NONE  guifg=red guibg=Green"highlight StatusLineNC cterm=NONE guifg=Gray guibg=White
"----- 状态栏设置_END_ -----"ycm configuration
let g:ycm_confirm_extra_conf = 0
let g:ycm_global_ycm_extra_conf='~/.ycm_extra_conf.py'

let g:ycm_key_list_select_completion = ['<TAB>','<C-n>','<Down>']
let g:ycm_key_list_previous_completion = ['<S-TAB>','<C-p>','<Up>']

let g:ycm_complete_in_comments = 1 " 在正文输出中也能补全
let g:ycm_complete_in_strings = 1 " 在字符串输出中也能补全
let g:ycm_collect_identifiers_from_comments_and_strings = 0 " 正文和字符串中的文字也会被支出补全
let g:ycm_collect_identifiers_from_tags_files=1 " 开启 YCM 基于标签引擎
let g:ycm_min_num_of_chars_for_completion=1 " 从第 1 个键入字符就开始列举匹配项
let g:ycm_cache_omnifunc=0 "禁止缓存匹配项, 每次都从新生成匹配项" 被动补全
"let g:ycm_key_invoke_completion ='<S-Space>'let g:ycm_key_invoke_completion ='<c-k>'let g:ycm_seed_identifiers_with_syntax=1" 语法关键字补全
"nnoremap <leader>lo :lopen<CR>"open locationlist
"nnoremap <leader>lc :lclose<CR>"close locationlist

"inoremap <leader><leader> <C-x><C-o>
let g:ycm_max_num_identifier_candidates = 50
let g:ycm_auto_trigger = 1
let g:ycm_error_symbol = '>>'
let g:ycm_warning_symbol = '>'


"YcmCompleter RefactorRename : 重命名"YcmCompleter GoToSymbol  

nnoremap <leader>jo :YcmCompleter GoTo<CR> " 跳转
nnoremap <leader>jd :YcmCompleter GoToDefinitionElseDeclaration<CR> " 跳转到定义或申明
nnoremap <leader>jf :YcmCompleter GoToDefinition<CR>  " 跳转到定义
nnoremap <leader>jl :YcmCompleter GoToDeclaration<CR> " 跳转到申明
nnoremap <leader>jt :YcmCompleter GetType<CR> "get 类型

nnoremap :js :YcmCompleter GoToSymbol 

nmap <leader>ji :YcmCompleter GoToInclude<CR>   " 跳转到 include、申明或定义
nmap <leader>jm :YcmCompleter GoToImprecise<CR> " 跳转到实现
nmap <leader>jr :YcmCompleter GoToReferences<CR> " 跳转到援用
nmap <leader>fi :YcmCompleter FixIt<CR> " 依据 Ycm 的倡议修复谬误

nnoremap <F6> :YcmForceCompileAndDiagnostics<CR> " 从新编译和诊断
nmap <F4> :YcmDiags<CR>  "F4 进行诊断

bash 配置文件.bashrc

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar

# make less more friendly for non-text input files, see lesspipe(1)
[-x /usr/bin/lesspipe] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [-z "${debian_chroot:-}" ] && [-r /etc/debian_chroot]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [-n "$force_color_prompt"]; then
    if [-x /usr/bin/tput] && tput setaf 1 >&/dev/null; then
    # We have color support; assume it's compliant with Ecma-48
    # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
    # a case would tend to support setf rather than setaf.)
    color_prompt=yes
    else
    color_prompt=
    fi
fi

if ["$color_prompt" = yes]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$'
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$'
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

# enable color support of ls and also add handy aliases
#if [-x /usr/bin/dircolors]; then
#    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
#    alias ls='ls --color=auto'
#    #alias dir='dir --color=auto'
#    #alias vdir='vdir --color=auto'
#
#    alias grep='grep --color=auto'
#    alias fgrep='fgrep --color=auto'
#    alias egrep='egrep --color=auto'
#fi

# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Add an "alert" alias for long running commands.  Use like so:
#   sleep 10; alert
alias alert='notify-send --urgency=low -i"$([$? = 0] && echo terminal || echo error)""$(history|tail -n1|sed -e'\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [-f ~/.bash_aliases]; then
    . ~/.bash_aliases
fi

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
  if [-f /usr/share/bash-completion/bash_completion]; then
    . /usr/share/bash-completion/bash_completion
  elif [-f /etc/bash_completion]; then
    . /etc/bash_completion
  fi
fi


###################################################################################
export EDITOR=vim
alias tmux="tmux -2"
myCdls()
{
    echo $@
    if [""$@"" == ""] ; then
        \cd $HOME
    else
        \cd "$@"
    fi
    pwd
    ls -lh
}
alias cd=myCdls

ycm 根底的数据库配置文件.ycm_extra_conf.py

# This file is NOT licensed under the GPLv3, which is the license for the rest
# of YouCompleteMe.
#
# Here's the license text for this file:
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>

from distutils.sysconfig import get_python_inc
import platform
import os
import subprocess
import ycm_core

DIR_OF_THIS_SCRIPT = os.path.abspath(os.path.dirname( __file__) )
DIR_OF_THIRD_PARTY = os.path.join(DIR_OF_THIS_SCRIPT, 'third_party')
SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm']

# These are the compilation flags that will be used in case there's no
# compilation database set (by default, one is not set).
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
flags = [
'-Wall',
'-Wextra',
'-Wno-long-long',
'-Wno-variadic-macros',
'-Wthread-safety',
'-Wthread-safety-beta',
'-fexceptions',
'-DNDEBUG',
'-D_GLIBCXX_USE_CXX11_ABI=0', # esearch uses old ABI
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
# language to use when compiling headers. So it will guess. Badly. So C++
# headers will be compiled as C headers. You don't want that so ALWAYS specify
# a "-std=<something>".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=c++17',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x', 'c++',
'-I', '/usr/local/include'
]


# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# You can get CMake to generate this file for you by adding:
#   set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
# to your CMakeLists.txt file.
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''

if os.path.exists(compilation_database_folder):
  database = ycm_core.CompilationDatabase(compilation_database_folder)
else:
  database = None


def IsHeaderFile(filename):
  extension = os.path.splitext(filename)[1]
  return extension in ['.h', '.hxx', '.hpp', '.hh']


def FindCorrespondingSourceFile(filename):
  if IsHeaderFile(filename):
    basename = os.path.splitext(filename)[0]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists(replacement_file):
        return replacement_file
  return filename


def Settings(**kwargs):
  if kwargs['language'] == 'cfamily':
    # If the file is a header, try to find the corresponding source file and
    # retrieve its flags from the compilation database if using one. This is
    # necessary since compilation databases don't have entries for header files.
    # In addition, use this source file as the translation unit. This makes it
    # possible to jump from a declaration in the header file to its definition
    # in the corresponding source file.
    filename = FindCorrespondingSourceFile(kwargs[ 'filename'] )

    if not database:
      return {
        'flags': flags,
        'include_paths_relative_to_dir': DIR_OF_THIS_SCRIPT,
        'override_filename': filename
      }

    compilation_info = database.GetCompilationInfoForFile(filename)
    if not compilation_info.compiler_flags_:
      return {}

    # Bear in mind that compilation_info.compiler_flags_ does NOT return a
    # python list, but a "list-like" StringVec object.
    final_flags = list(compilation_info.compiler_flags_)

    # NOTE: This is just for YouCompleteMe; it's highly likely that your project
    # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
    # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
    try:
      final_flags.remove('-stdlib=libc++')
    except ValueError:
      pass

    return {
      'flags': final_flags,
      'include_paths_relative_to_dir': compilation_info.compiler_working_dir_,
      'override_filename': filename
    }
  return {}


def GetStandardLibraryIndexInSysPath(sys_path):
  for path in sys_path:
    if os.path.isfile(os.path.join( path, 'os.py') ):
      return sys_path.index(path)
  raise RuntimeError('Could not find standard library path in Python path.')


def PythonSysPath(**kwargs):
  sys_path = kwargs['sys_path']
  for folder in os.listdir(DIR_OF_THIRD_PARTY):
    if folder == 'python-future':
      folder = os.path.join(folder, 'src')
      sys_path.insert(GetStandardLibraryIndexInSysPath( sys_path) + 1,
                       os.path.realpath( os.path.join( DIR_OF_THIRD_PARTY,
                                                       folder ) ) )
      continue

    if folder == 'cregex':
      interpreter_path = kwargs['interpreter_path']
      major_version = subprocess.check_output( [interpreter_path, '-c', 'import sys; print( sys.version_info[ 0] )' ]
      ).rstrip().decode( 'utf8')
      folder = os.path.join(folder, 'regex_{}'.format(major_version) )

    sys_path.insert( 0, os.path.realpath( os.path.join( DIR_OF_THIRD_PARTY,
                                                        folder ) ) )
  return sys_path

最初是 Dockerfile 编写如下:

##################################################################################################################docker build --no-cache -t xxx:1.0 #################################################################################################################FROM ubuntu:20.04

MAINTAINER dingbin dingbinthu@163.com


WORKDIR /root

COPY Dockerfile ./
COPY .bashrc ./
COPY .vimrc ./
COPY .ycm_extra_conf.py ./

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai

RUN set -ex && apt-get update && apt-get upgrade -y &&
apt-get install -y tzdata &&
apt-get install -y net-tools rsync inetutils-ping git curl wget unzip &&
apt-get install -y build-essential cmake vim-nox python3-dev &&
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim &&
vim -c PluginInstall -c q -c q && \ cd ~/.vim/bundle/YouCompleteMe &&
git submodule update --init --recursive && ./install.py --clangd-completer

CMD vim

将以上 4 个文件搁置一个目录下,在任意一台装置了 docker 的 x86_64 机器上该目录下执行命令:

docker build  --no-cache -t    ycm-base:1.0 

即可创立一个本地 docker 镜像名为:ycm-base:1.0

本文作者曾经按如上步骤创立好了一个可用的 ycm 根底镜像,并上传到了 hub.docker.com 名为:apollo008/vim8-ycm:3.0。地址是:https://hub.docker.com/repository/docker/apollo008/vim8-ycm-customize-user 读者可间接通过 docker 命令:docker pull apollo008/vim8-ycm:3.0 下载该镜像到本地应用即可。

创立定制用户的 docker 镜像

以上 docker 镜像创立的是 root 用户的。如果应用 root 账户登录进入 docker 容器中编辑文件后,必然是 root 用户所有,导致容器外其余用户没有权限编辑或浏览该文件。解决得方法是才上述根底 vim-ycm 镜像的根底上,用户本人在本地 docker 环境中迅速创立一个应用本人用户名(尤其是 uid)的账户的 ycm docker 镜像,而后本地以该特定用户拜访该 docker 容器即可。之所以分成两个容器,是因为根底容器制作费时,切可能依赖外网,导致装置难以胜利,所以制作好上传至公共镜像仓库,不同用户在即镜像根底上定制一下本人的特定 uid 和 username 的本地镜像即可,操作步骤如下。
Dockerfile 内容如下:

FROM apollo008/vim8-ycm:3.0

MAINTAINER dingbin dingbinthu@163.com

WORKDIR /root

ARG APP_UID
ARG APP_GID
ARG APP_USER
ARG APP_GROUP

RUN set -ex && apt-get install -y sudo openssh-server && \
    groupadd -o -g  ${APP_GID} ${APP_GROUP} && \
    useradd -m -s /bin/bash -o -u ${APP_UID} -g ${APP_GID}  ${APP_USER} && \
    mkdir -p /etc/sudoers.d && \
    echo root:123456 | chpasswd  && \
    echo ${APP_USER}:123456 | chpasswd  && \
    echo "${APP_USER} ALL=(ALL)   NOPASSWD: ALL" > /etc/sudoers.d/${APP_USER} && \ 
    chmod 0440 /etc/sudoers.d/${APP_USER}  && \
    cp /root/.vim  /home/${APP_USER}/ -rf && \
    cp /root/.vimrc  /home/${APP_USER}/ -rf && \
    cp /root/.ycm_extra_conf.py  /home/${APP_USER}/ -rf && \
    chown -R ${APP_USER}:${APP_GROUP}  /home/${APP_USER}/.vim && \
    chown -R ${APP_USER}:${APP_GROUP}  /home/${APP_USER}/.vimrc && \
    chown -R ${APP_USER}:${APP_GROUP}  /home/${APP_USER}/.ycm_extra_conf.py


    COPY --chown=${APP_USER}:${APP_GROUP}   Dockerfile  /home/${APP_USER}/
    COPY --chown=${APP_USER}:${APP_GROUP}   .bashrc    /home/${APP_USER}/

    WORKDIR /home/${APP_USER}
    USER ${APP_USER}


CMD vim

该 docker 镜像内置的 vim8.1 和 ycm 是 ubuntu 20.04 LTS 截至目前 2021.03.22 最新版的 vim 和 ycm。~/.vimrc 中相应的配置都已欠缺,包含较为正当好看的配色计划。成果如下图。


本镜像用法是:在本地执行如下命令 创立本人用户名比方 work/user 等的 docker 镜像。
docker build –no-cache -t myycm:latest –build-arg APP_USER=work –build-arg APP_GROUP=work –build-arg APP_UID=1000 –build-arg APP_GID=1001 .

镜像生成后举荐用法是:docker run -itd –name ycm1 -v hostPath:InDockerPath myycm:latest /bin/bash
docker exec -it ycm1 /bin/bash 而后在 docker 容器内的交互 bash 上执行 vim xxx.cpp 编辑文件。防止频繁关上 docker container 相应速度慢。

正文完
 0