Vim 从零开始配置

 

配置

mkdir -p ~/.vim/autoload/
vi ~/.vim/autoload/plug.vim
## add https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
" use space as leader key
let mapleader = " "
set wildmenu
set wildmode=full
" 模拟 Bash 的快捷键
cnoremap <C-a> <Home>   " 跳到命令开头
cnoremap <C-e> <End>    " 跳到命令末尾
cnoremap <C-k> <C-\>e getcmdline()[:getcmdpos()-2]<CR> " 删除光标到行尾的内容
cnoremap <C-u> <C-\>e getcmdline()[:getcmdpos()-1]<CR> " 删除光标到行首的内容

let g:undo_dir = expand('~/.vim/undodir')
if !isdirectory(g:undo_dir)
    silent! call mkdir(g:undo_dir, 'p')
endif
set undofile
execute 'set undodir=' . g:undo_dir

" fast completion absolute path"
cnoremap <expr> %% getcmdtype( ) == ':' ? expand('%:h').'/' : '%%'

" viminfo save mouse history
au BufReadPost * if line("'\"") > 0 | if line("'\"") <= line("$") | exe("norm '\"") | else | exe "norm $"| endif | endif
" set viminfo='1000,<50,s10,h " not useful

if executable('vimscript-language-server')
    au User lsp_setup call lsp#register_server({
                \ 'name': 'vimscript-language-server',
                \ 'cmd': {server_info->['vimscript-language-server']},
                \ 'whitelist': ['vim'],
                \ })
endif

" for formatter
let g:python3_host_prog="$HOME/local/bin/python3"
"let g:formatterpath = ['~/local/opt/clang15/bin/clang-format', '~/local/bin/autopep8', '~/go/bin/shfmt']
let g:formatterpath = ['~/local/opt/llvm21/clang/bin/clang-format', '~/.local/bin/autopep8', '~/go/bin/shfmt']

" gf search path, such as c/cpp head file
set path=.,/usr/include,$HOME/local/include/**

" use plugin
set nocompatible
let g:polyglot_disabled = ['sensible']
filetype plugin indent on
call plug#begin('~/.vim/plugged')
Plug 'Valloric/YouCompleteMe'
Plug 'vim-autoformat/vim-autoformat'
"Plug 'vim-airline/vim-airline'
Plug 'preservim/nerdtree'
" Plug 'ludovicchabant/vim-gutentags'
Plug 'skywind3000/asyncrun.vim'
" Plug 'dense-analysis/ale'
Plug 'sheerun/vim-polyglot'
Plug 'joshdick/onedark.vim'
Plug 'preservim/tagbar'

"Plug 'prabirshrestha/vim-lsp'
"Plug 'mattn/vim-lsp-settings'
Plug 'llvm/llvm.vim'

call plug#end()

if executable('clangd')
    augroup lsp_clangd
        autocmd!
        autocmd User lsp_setup call lsp#register_server({
            \ 'name': 'clangd',
            \ 'cmd': {server_info->['clangd']},
            \ 'allowlist': ['c', 'cpp', 'objc', 'objcpp'],
            \ })
    augroup END
endif

"" YCM配置
" 全局YCM配置文件路径
let g:ycm_keep_logfiles = 1
let g:ycm_log_level = 'debug'
let g:ycm_global_ycm_extra_conf = '~/.vim/plugged/YouCompleteMe/.ycm_extra_conf.py'
let g:ycm_confirm_extra_conf = 0  " 不提示是否载入本地ycm_extra_conf文件
let g:ycm_min_num_of_chars_for_completion = 2  " 输入第2个字符就罗列匹配项

" Ctrl+J跳转至定义、声明或文件
nnoremap <c-j> :YcmCompleter GoToDefinitionElseDeclaration<CR>|

" 语法关键字、注释、字符串补全
let g:ycm_seed_identifiers_with_syntax = 1
let g:ycm_complete_in_comments = 1
let g:ycm_complete_in_strings = 1
" 从注释、字符串、tag文件中收集用于补全信息
let g:ycm_collect_identifiers_from_comments_and_strings = 1
let g:ycm_collect_identifiers_from_tags_files = 1

" 禁止快捷键触发补全
let g:ycm_key_invoke_completion = '<c-z>'  " 主动补全(默认<c-space>)
noremap <c-z> <NOP>

" 输入2个字符就触发补全
let g:ycm_semantic_triggers = {
            \ 'c,cpp,python,java,go,erlang,perl': ['re!\w{2}'],
            \ 'cs,lua,javascript': ['re!\w{2}'],
            \ }

let g:ycm_show_diagnostics_ui = 0  " 禁用YCM自带语法检查(使用ale)

" 防止YCM和Ultisnips的TAB键冲突,禁止YCM的TAB
"let g:ycm_key_list_select_completion = ['<C-n>', '<Down>']
"let g:ycm_key_list_previous_completion = ['<C-p>', '<Up>']

function! JumpToLogFileAndLine()
    " Get the current line under the cursor
    let l:line = getline('.')
    "echo "Current line: " . l:line

    " Define a regex pattern to match the log format: [timestamp][module][log_level][file_name:line_number]
    let l:pattern = '\v\[(.{-})\]\[(.{-})\]\[(.{-})\]\[(.{-}):(\d+)\]'
    "echo "Regex pattern: " . l:pattern

    " Search for the pattern in the current line
    if l:line =~ l:pattern
        "echo "Pattern matched"

        let l:matches = matchlist(l:line, l:pattern)
        " Extract the file path and line number
        let l:file = "src/" . l:matches[4]
        let l:line_num = l:matches[5]
        "echo "File: " . l:file
        "echo "Line number: " . l:line_num

        " Open the file and go to the specific line
        execute 'edit ' . l:file
        execute l:line_num
    else
        echo "No file and line number found on this line."
    endif
endfunction

" Map a key to jump to the file and line number
nnoremap <leader>j :call JumpToLogFileAndLine()<CR>


colorscheme onedark
noremap <leader>f :Autoformat<CR>

" open vimrc config by ctrl,
nnoremap <silent> <C-,> :e ~/.vimrc<CR>
inoremap <silent> <C-,> <Esc>:e ~/.vimrc<CR>

"set fold by syntax
set foldmethod=syntax
set foldlevel=99

" for save file
inoremap <C-s> <Esc>:w<CR>a
nnoremap <C-s> :w<CR>
vnoremap <C-s> <Esc>:w<CR>gv


" make vim paste <==> physic machine
"autocmd TextYankPost * echo v:event
function! s:raw_echo(str)
    if has('win32') && has('nvim')
        call chansend(v:stderr, a:str)
    else
        if filewritable('/dev/fd/2')
            call writefile([a:str], '/dev/fd/2', 'b')
        else
            exec("silent! !echo " . shellescape(a:str))
            redraw!
        endif
    endif
endfunction


"function Copy()
"    let c = join(v:event.regcontents,"\n")
"    let c64 = system("base64 -w 0", c)
"    let str1 = "\e]52;c;" . trim(c64) . "\x07"
"    call s:raw_echo(str1)
"endfunction
function! Copy()
  " 仅在 yank 操作时执行复制逻辑
  if v:event.operator ==# 'y'
    let c = join(v:event.regcontents, "\n")
    let c64 = system("base64 -w 0", c)
    let str1 = "\e]52;c;" . trim(c64) . "\x07"
    call s:raw_echo(str1)
  endif
endfunction

autocmd TextYankPost * call Copy()
""nnoremap <F5> :autocmd! TextYankPost *<CR>
""nnoremap <F6> :autocmd TextYankPost * call Copy()<CR>


" show space and line eof char
" set list listchars+=space:. listchars-=eol:$

"statusline
set laststatus=2
function! GitBranch()
    return system("git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n'")
endfunction
let branch=GitBranch()

function! ShortFileName()
    let a=bufname("")
    let filename = fnamemodify(a, ':t')
    return filename
endfunction

map <Leader>r <ESC>:w <CR> :source $MYVIMRC<CR>
map <leader>t :TagbarToggle <CR>

set statusline=%1*%{branch}\ %{ShortFileName()}\ %m%r%h%w%2*%{tagbar#currenttag('%s','','f')}\ %=%3*\ %Y\ %4*%{\"\".(\"\"?&enc:&fenc).((exists(\"+bomb\")\ &&\ &bomb)?\"+\":\"\").\"\"}\ %5*%p%%\ %7*%LL%<'

"set statusline=
"set statusline+=%1*%{branch}\ %{ShortFileName()}\ %m%r%h%w\
"set statusline+=%2*%{tagbar#currenttag('%s','','f')}\ %=
"set statusline+=%3*\ %Y\
"set statusline+=%4*%{\"\".(\"\"?&enc:&fenc).((exists(\"+bomb\")\ &&\ &bomb)?\"+\":\"\").\"\"}\
"set statusline+=%5*[%p%%]\ \
"set statusline+=%7*%LL%<\


""" for ale config
"let g:ale_linters_explicit = 1
"let g:ale_completion_delay = 500
"let g:ale_echo_delay = 20
"let g:ale_lint_delay = 500
"let g:ale_echo_msg_format = '[%linter%] %code: %%s'
"let g:ale_lint_on_text_changed = 'normal'
"let g:ale_lint_on_insert_leave = 1
"let g:airline#extensions#ale#enabled = 1
"let g:ale_c_gcc_options = '-Wall -O2 -std=c99
"            \ -I .
"            \ -I /usr/include'
"let g:ale_cpp_gcc_options = '-Wall -O2 -std=c++17
"            \ -I .
"            \ -I /usr/include
"            \ -I /opt/compiler/gcc-8.2/include/c++/8.2.0'
"let g:ale_linters = {
"            \ 'c': ['gcc', 'cppcheck'],
"            \ 'cpp': ['g++', 'cppcheck'],
"            \ }
"let g:ale_c_cppcheck_options = ''
"let g:ale_cpp_cppcheck_options = '--check-level=exhaustive'
"
"" let g:ale_sign_error = "\ue009\ue009"
"hi! clear SpellBad
"hi! clear SpellCap
"hi! clear SpellRare
"hi! SpellBad gui=undercurl guisp=red
"hi! SpellCap gui=undercurl guisp=blue
"hi! SpellRare gui=undercurl guisp=magenta
""""""""""""""""end ale config

"nnoremap <leader>n :NERDTreeFocus<CR>
"nnoremap <C-n> :NERDTree<CR>
nnoremap <C-n> :NERDTreeToggle<CR>
"nnoremap <C-f> :NERDTreeFind<CR>


"for asyncRun
" open  quickfix window auto,height
let g:asyncrun_open = 9

" bell when task done.
let g:asyncrun_bell = 1

" set open/close Quickfix window
nnoremap <leader>c :call asyncrun#quickfix_toggle(6)<cr>


" Map Alt-q to close the window
nnoremap <silent> <leader>q :q<CR>

"
"nnoremap <silent> <F8> :AsyncRun gcc -Wall "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
"nnoremap <silent> <F5> :AsyncRun -raw -cwd=$(VIM_FILEDIR) "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>

set termwinsize=20x120

" Define a function to set key mappings for shell files
function! SetShellKeymaps()
    nnoremap <F8> :w<CR>:AsyncRun bash %:p <CR>
    inoremap <F8> <ESC>:w<CR>:AsyncRun bash %:p<CR>
endfunction

" Set up an autocmd for the FileType event for shell files
autocmd FileType sh call SetShellKeymaps()
autocmd FileType bash call SetShellKeymaps()
" autocmd FileType zsh call SetShellKeymaps()

" Define a function to set key mappings for Python files
function! SetPythonKeymaps()
    nnoremap <F8> :w<CR>:AsyncRun python3 %:p <CR>
    inoremap <F8> <ESC>:w<CR>:AsyncRun python3 %:p<CR>
endfunction

" Set up an autocmd for the FileType event for Python files
autocmd FileType python call SetPythonKeymaps()

function! SetCKeymaps()
    nnoremap  <F7> :w<CR>:AsyncRun gcc -Wshadow -Wall  -o %:p:r.out %:p  <CR>
    inoremap  <F7> <ESC>:w<CR>:AsyncRun gcc -Wshadow -Wall  -o %:p:r.out %:p  <CR>
    nnoremap  <F8> :AsyncRun %:p:r.out <CR>
endfunction
autocmd FileType c call SetCKeymaps()

function! SetCXXKeymaps()
    nnoremap  <F7> :w<CR>:AsyncRun /opt/compiler/gcc-8.2/bin/g++ -Wshadow -Wall -std=c++2a -o %:p:r.out %:p  <CR>
    inoremap  <F7> <ESC>:w<CR>:AsyncRun /opt/compiler/gcc-8.2/bin/g++ -Wshadow -Wall -std=c++2a -o %:p:r.out %:p  <CR>
    nnoremap  <F8> :AsyncRun %:p:r.out <CR>
endfunction
autocmd FileType cpp call SetCXXKeymaps()

" for tags
set tags=./.tags;,.tags

let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project']

let g:gutentags_ctags_tagfile = '.tags'

let s:vim_tags = expand('~/.cache/tags')
let g:gutentags_cache_dir = s:vim_tags

let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']
let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']
let g:gutentags_ctags_extra_args += ['--c-kinds=+px']

if !isdirectory(s:vim_tags)
    silent! call mkdir(s:vim_tags, 'p')
endif


" syntax highlight
syntax on

" show line number and relative number
set number
" set relativenumber

" indent when newline
set smartindent

" allow backspace delete char in different mode
set backspace=indent,eol,start

" mouse mode
set mouse=n

" focus window by Ctrl + hjkl
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-h> <C-w>h
nnoremap <C-l> <C-w>l


" use ag as grep program
if executable('ag')
    set grepprg=ag\ --vimgrep\ $* " receive other parameter
    set grepformat=%f:%l:%c:%m   " file:line:column:message
endif

" just for best search
function! MySearch()
    let grep_term = input("Search=> ")
    if !empty(grep_term)
        execute 'silent grep' grep_term | copen
    else
        echo "Empty search term"
    endif
    redraw!
endfunction

command! Search call MySearch()
nnoremap <leader>s :Search<CR>

" cancel backup and no generate swp file
set nobackup
set nowb
set noswapfile

" tab width =4
set tabstop=4

" indent = 4
set softtabstop=4
set shiftwidth=4
set expandtab


" use search highlight
set hlsearch

" increase search by result
set incsearch

" ignore but not always ignore
set ignorecase
set smartcase

" show n/N/*/# search index in status bar
set shortmess-=S

" set file encoding
set enc=utf-8
set fencs=utf-8,gbk,big5,cp936,gb18030,gb2312
set fenc=utf-8
"let &termencoding=&encoding
"set fileencodings=gbk,utf-8,gb18030,gb2312,big5

" jk -> <ESC>
inoremap jk <ESC>
" v as visual and select mode
"vnoremap jk <ESC>

" use emacs keymap in insert mode
inoremap <C-B> <LEFT>
inoremap <C-F> <RIGHT>
inoremap <C-A> <HOME>
inoremap <C-E> <END>
inoremap <C-D> <DEL>
inoremap <C-H> <BACKSPACE>


" cn to change multi place
nnoremap cn *``cgn
nnoremap cN *``cgN


" for multi line micro
imap <C-E> <ESC>A
xnoremap @ :<C-u>call ExecuteMacroOverVisualRange()<CR>
function! ExecuteMacroOverVisualRange()
    echo "@".getcmdline()
    execute ":'<,'>normal @".nr2char(getchar())
endfunction

" for brackets
inoremap ( ()<ESC>i
inoremap [ []<LEFT>
inoremap " ""<ESC>i
inoremap ' ''<ESC>i
inoremap { {}<ESC>i
inoremap {<CR> {<CR>}<ESC>O

function! ClosePair(char)
    if getline('.')[col('.') - 1] == a:char
        return "\<Right>"
    else
        return a:char
    endif
endfunction

inoremap ) <c-r>=ClosePair(')')<CR>
inoremap } <c-r>=ClosePair('}')<CR>
inoremap ] <c-r>=ClosePair(']')<CR>
" add bracket on visual model
xnoremap ( <Esc>`<i(<Esc>`><RIGHT>a)<Esc>
xnoremap [ <Esc>`<i[<Esc>`><RIGHT>a]<Esc>
xnoremap { <Esc>`<i{<Esc>`><RIGHT>a}<Esc>
xnoremap " <Esc>`<i"<Esc>`><RIGHT>a"<Esc>

function! InsertFileHeader()
    " 获取当前文件名
    let filename = expand('%:t')
    " 获取当前用户名
    let author = $USER
    " 获取邮箱地址(可以根据需要修改)
    let email = author . '@baidu.com'
    " 获取当前时间
    let created_time = strftime('%a %m/%d %H:%M:%S %Y')

    " 定义文件头模板
    let header = "/*************************************************************************\n"
    \ . "    > File Name: " . filename . "\n"
    \ . "    > Author: " . author . "\n"
    \ . "    > Mail: " . email . "\n"
    \ . "    > Created Time: " . created_time . "\n"
    \ . " ************************************************************************/\n\n"

    " 定义代码模板
    let template_code = "#include <bits/stdc++.h>\n"
    \ . "using namespace std;\n\n"
    \ . "void t1() {\n"
    \ . "    //\n"
    \ . "}\n\n"
    \ . "int main() {\n"
    \ . "    t1();\n"
    \ . "    return 0;\n"
    \ . "}\n"

    " 如果文件为空,则插入文件头和代码模板
    if getline(1) == ''
        call append(0, split(header . template_code, '\n'))
    endif

    " 找到包含注释 "// 指针放在这里" 的行号
    let target_line = search("//", 'n') " 'n' 表示不移动光标

    " 如果找到了目标行,则将光标移动到该行
    if target_line > 0
        call cursor(target_line, 1) " 移动光标到目标行的第一列
    endif
endfunction

" 设置自动命令,在打开或创建文件时调用函数
autocmd BufNewFile,BufRead *.h,*.cc,*.cpp call InsertFileHeader()

快捷键

  • Ctrl+x Ctrl+f: 进入路径补全