The date of The author version note
2021-03-24 dingbin V1.0

In daily development, C++ programmers inevitably encounter changes to computers, servers and other things. It is too heavy to rebuild and build the C++ development environment, which requires a lot of unnecessary and precious time. Vim’s YouCompleteme (YCM for short) plug-in can realize the function of automatic complete jump in C/C++ language, and is one of the necessary tools for C/C++ code editing by Vim. However, the actual installation of YCM is extremely complex, relying not only on the Python dynamic link library, but also on certain high-level versions of GCC and clang, or clangd and cmake, etc. Preparing these precomponents is also time-consuming and laborious. In view of this, this paper introduces a new way of playing and gives practical operation details as well as directly available Docker mirror-image results. That is, build a Docker mirror-image of YouCompleteme, a C++ completion jump plug-in based on Vim, and complete the building of C++ development environment on any machine with one key. The specific operation method is described as follows.

Environment to prepare

Time: 2021-03-24

CentOS Linux Release 7.5.1804 (Core), 8-core 12G

Create the underlying Docker image

Consider installing the latest version of Vim and YouCompleteme plug-ins at the current time. Reference website YouCompleteMe installation method for vim/GCC/clang/clangd/cmake/python under higher version to install successfully. We were making Docker images, so it was impossible to pick a very old base OS. Referring to the advice on YCM’s official website, we chose Ubuntu 20.04 LTS for the basic OS. Direct ready-made image files at hub.docker.com. The following three configuration files should be prepared for the configuration file.

Vim configuration file.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进行诊断

The bash configuration file.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’s underlying database configuration file.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

Finally, the Dockerfile is written as follows:

##################################################################################################################docker Build - no cache - t XXX: 1.0 #################################################################################################################FROM Ubuntu :20.04 Maintainer dingbin [email protected] 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

Place the above 4 files in a directory and execute the command on any x86_64 machine where Docker is installed:

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

Create a local Docker image named: ycm-base:1.0

The author of this article has created a working YCM base image as described above and uploaded it to hub.docker.com as APOLLO008 / VIM8-YCM :3.0. The address is: https://hub.docker.com/repository/docker/apollo008/vim8-ycm-customize-user readers can be directly through the docker command: Docker pull apollo008/vim8-ycm:3.0 Just download the image and use it locally.

Create a Docker image of the custom user

The above docker image is created for user root. If you log in with the root account to edit a file in the docker container, it must be owned by the root user, so that other users outside the container do not have permission to edit or read the file. The solution is that based on the basic Vim-YCM image above, the user can create a YCM Docker image with his/her user name (especially UID) in the local Docker environment quickly, and then access the Docker container locally as that specific user. The reason is divided into two containers, because the basic container production time, cut may rely on the external network, resulting in the installation is difficult to succeed, so make good upload to the public mirror warehouse, different users in the mirror based on customized their own specific UID and Username of the local mirror, the operation steps are as follows. Dockerfile contents are as follows:

From apollo008/vim8-ycm:3.0 MAINTAINER dingbin [email protected] 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

The Docker image with built-in VIM8.1 and YCM is Ubuntu 20.04 LTS as of 2021.03.22 the latest version of Vim and YCM. The corresponding configuration in ~/. Vimrc has been improved, including a more reasonable and beautiful color scheme. The effect is shown below.



Create a Docker image of your own user name such as work/user.

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 .

The recommended usage after mirroring is generated is: docker run -itd –name ycm1 -v hostPath:InDockerPath myycm:latest /bin/bash docker exec -it ycm1 /bin/bash Then execute the Vim xxx.cpp edit file on the interactive bash inside the Docker container. Avoid frequent opening of Docker Container, which is slow.