Files
infra/dotfiles/common/.vimrc
2026-04-04 23:02:05 +02:00

489 lines
14 KiB
VimL

" ==========================================================
" Vim configuration - Sysdev Portable
" Optimized for Linux kernel development
" ==========================================================
set nocompatible
set encoding=utf-8
scriptencoding utf-8
" --- leader MUST be set before any mapping
let mapleader=" "
let maplocalleader="\\"
" ----------------------------------------------------------
" UI
" ----------------------------------------------------------
set number
set relativenumber
set ruler
set showcmd
set nowrap
set splitbelow
set splitright
set signcolumn=yes
set laststatus=2
set scrolloff=4
set sidescrolloff=8
set wildmenu
set wildmode=longest:full,full
set mouse=
set ttyfast
set lazyredraw
" ----------------------------------------------------------
" Editing
" ----------------------------------------------------------
set hidden
set backspace=indent,eol,start
set tabstop=8
set shiftwidth=8
set softtabstop=8
set noexpandtab
set autoindent
" NOTE: cindent supersedes smartindent — smartindent removed (obsolete + redundant)
set cindent
set cinoptions=:0,l1,g0,t0,(0,Ws,m1
set textwidth=80
set colorcolumn=81
" j: remove comment leader when joining lines (Vim >= 7.4)
set formatoptions+=croqnj
set formatoptions-=t
" C syntax tweaks (kernel-friendly)
let c_comment_strings=1
let c_no_curly_error=1
" ----------------------------------------------------------
" Whitespace (OFF by default, toggle with <leader>l)
" ----------------------------------------------------------
set nolist
set listchars=tab:>-,trail,extends,precedes,nbsp:␣
nnoremap <silent> <leader>l :set list!<CR>
" ----------------------------------------------------------
" Search
" ----------------------------------------------------------
set incsearch
set hlsearch
set ignorecase
set smartcase
" NOTE: gdefault removed — it breaks muscle memory and is
" confusing when reading others' vimrc. Use /g explicitly.
nnoremap <silent> <leader>h :set hlsearch!<CR>
" ----------------------------------------------------------
" Performance
" ----------------------------------------------------------
set updatetime=250
set timeoutlen=400
set ttimeoutlen=10
set shortmess+=c
" ----------------------------------------------------------
" Undo (XDG-aware, robust)
" ----------------------------------------------------------
set undofile
set undolevels=1000
if has("unix")
if exists("$XDG_CACHE_HOME") && !empty($XDG_CACHE_HOME)
let s:cache=$XDG_CACHE_HOME
else
let s:cache=expand("~/.cache")
endif
let s:undodir=s:cache . "/vim/undo//"
if !isdirectory(s:undodir)
silent! call mkdir(s:undodir, "p")
endif
execute "set undodir=" . fnameescape(s:undodir)
endif
" ----------------------------------------------------------
" Swap files (centralized — no .swp in source trees)
" ----------------------------------------------------------
if has("unix")
if exists("$XDG_CACHE_HOME") && !empty($XDG_CACHE_HOME)
let s:cache2=$XDG_CACHE_HOME
else
let s:cache2=expand("~/.cache")
endif
let s:swpdir=s:cache2 . "/vim/swap//"
if !isdirectory(s:swpdir)
silent! call mkdir(s:swpdir, "p")
endif
execute "set directory=" . fnameescape(s:swpdir)
set nobackup
set nowritebackup
endif
" ----------------------------------------------------------
" Grep integration
" ----------------------------------------------------------
if executable("rg")
set grepprg=rg\ --vimgrep\ --no-heading\ --smart-case
set grepformat=%f:%l:%c:%m
elseif executable("grep")
set grepprg=grep\ -nH\ $*
set grepformat=%f:%l:%m
endif
nnoremap <silent> <leader>g :silent grep! <C-R><C-W> .<CR>:copen<CR>
nnoremap <leader>/ :silent grep!<Space>
" ----------------------------------------------------------
" Quickfix / location list
" ----------------------------------------------------------
nnoremap <silent> ]q :cnext<CR>
nnoremap <silent> [q :cprev<CR>
nnoremap <silent> <leader>qo :copen<CR>
nnoremap <silent> <leader>qc :cclose<CR>
nnoremap <silent> ]l :lnext<CR>
nnoremap <silent> [l :lprev<CR>
nnoremap <silent> <leader>lo :lopen<CR>
nnoremap <silent> <leader>lc :lclose<CR>
" ----------------------------------------------------------
" Window navigation
" ----------------------------------------------------------
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" ----------------------------------------------------------
" Basic shortcuts
" ----------------------------------------------------------
nnoremap <silent> <leader>w :w<CR>
nnoremap <silent> <leader>q :q<CR>
nnoremap <silent> <leader>x :x<CR>
" Fold toggle
nnoremap <silent> <leader>z za
" Diff helpers
set diffopt=filler,internal,algorithm:histogram,indent-heuristic
nnoremap <silent> <leader>df :windo diffthis<CR>
nnoremap <silent> <leader>do :windo diffoff<CR>
" ----------------------------------------------------------
" Folding
" ----------------------------------------------------------
set foldmethod=syntax
set foldlevelstart=99 " start with all folds open
set foldnestmax=3
" ----------------------------------------------------------
" Tags (ctags)
" ----------------------------------------------------------
set tags=./tags;,tags;
if filereadable(expand('~/.tags'))
set tags+=~/.tags
endif
nnoremap <silent> <leader>t :tag <C-R><C-W><CR>
nnoremap <silent> <leader>pt :ptag <C-R><C-W><CR>
nnoremap <silent> <leader>po :popen<CR>
nnoremap <silent> <leader>pc :pclose<CR>
" ----------------------------------------------------------
" cscope (essential for kernel navigation)
" ----------------------------------------------------------
if has("cscope")
set cscopetag " use cscope for :tag and <C-]>
set cscoperelative " use cscope.out location as prefix
set cscopeverbose
" Auto-load cscope.out walking up the directory tree
function! s:LoadCscope() abort
let l:db=findfile("cscope.out", ".;")
if !empty(l:db)
let l:path=strpart(l:db, 0, match(l:db, "/cscope.out$"))
if empty(l:path) | let l:path="." | endif
silent! execute "cs add " . l:db . " " . l:path
endif
endfunction
autocmd BufEnter /* call s:LoadCscope()
" cscope query mappings
" s: symbol g: definition d: called-by c: callers
" t: text e: egrep f: file i: #includes
nnoremap <silent> <leader>cs :cs find s <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>cg :cs find g <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>cd :cs find d <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>cc :cs find c <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>ct :cs find t <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>ce :cs find e <C-R>=expand("<cword>")<CR><CR>
nnoremap <silent> <leader>cf :cs find f <C-R>=expand("<cfile>")<CR><CR>
nnoremap <silent> <leader>ci :cs find i <C-R>=expand("<cfile>")<CR><CR>
endif
" ----------------------------------------------------------
" Man page (K over word)
" ----------------------------------------------------------
function! s:Man() abort
let l:word=expand("<cword>")
if exists(":Man")
execute "Man " . l:word
else
execute "!man " . l:word
endif
endfunction
nnoremap <silent> K :call <SID>Man()<CR>
" ----------------------------------------------------------
" ClangFormat
" ----------------------------------------------------------
function! s:ClangFormatRange(line1, line2) abort
if !executable("clang-format")
echohl WarningMsg | echo "clang-format not found in PATH" | echohl None
return
endif
let l:view=winsaveview()
silent execute a:line1 . "," . a:line2 . "!clang-format"
call winrestview(l:view)
endfunction
command! -range=% ClangFormat call <SID>ClangFormatRange(<line1>, <line2>)
nnoremap <silent> <leader>cf :ClangFormat<CR>
xnoremap <silent> <leader>cf :ClangFormat<CR>
" ----------------------------------------------------------
" Project root detection
" ----------------------------------------------------------
function! s:GitRoot() abort
if executable("git")
let l:r=systemlist("git rev-parse --show-toplevel 2>/dev/null")
if v:shell_error==0 && len(l:r)>0
return l:r[0]
endif
endif
return ""
endfunction
function! s:FindProjectRoot() abort
let l:root=s:GitRoot()
return !empty(l:root) ? l:root : getcwd()
endfunction
" ----------------------------------------------------------
" Smart build (ninja > cmake > make)
" ----------------------------------------------------------
function! s:SmartMake() abort
let l:root=s:FindProjectRoot()
if filereadable(l:root . "/build.ninja")
let &makeprg="ninja -C " . fnameescape(l:root)
elseif filereadable(l:root . "/CMakeLists.txt")
let &makeprg="cmake --build build"
elseif filereadable(l:root . "/Makefile")
let &makeprg="make -C " . fnameescape(l:root)
else
let &makeprg="make"
endif
silent make!
copen
endfunction
command! Make call <SID>SmartMake()
nnoremap <silent> <leader>m :Make<CR>
" ----------------------------------------------------------
" Run single file (errors in quickfix, output in terminal)
" ----------------------------------------------------------
function! s:Run() abort
write
if &filetype=="c"
let l:src=expand("%")
let l:exe=expand("%:r")
let l:saved=&makeprg
execute "set makeprg=cc\\ -std=c11\\ -Wall\\ -Wextra\\ -g\\ "
\ . fnameescape(l:src) . "\\ -o\\ " . fnameescape(l:exe)
silent make!
let &makeprg=l:saved
" Run only if no errors
if empty(filter(getqflist(), 'v:val.valid'))
execute "!" . fnameescape(l:exe)
else
copen
endif
elseif &filetype=="python"
execute "!python3 " . fnameescape(expand("%"))
elseif &filetype=="sh"
execute "!sh " . fnameescape(expand("%"))
else
echohl WarningMsg | echo "Run not supported for filetype: " . &filetype | echohl None
endif
endfunction
command! Run call <SID>Run()
nnoremap <silent> <leader>r :Run<CR>
" ----------------------------------------------------------
" Filetypes + syntax
" ----------------------------------------------------------
filetype plugin indent on
syntax on
" ----------------------------------------------------------
" Autocommands
" ----------------------------------------------------------
augroup sysdev_ft
autocmd!
" Trim trailing whitespace on save
autocmd BufWritePre * silent! %s/\s\+$//e
" Restore last cursor position
autocmd BufReadPost *
\ if line("'\"")>0 && line("'\"")<=line("$") |
\ execute "normal! g`\"" |
\ endif
" C/C++: kernel style, no list (tabs are intentional)
autocmd FileType c,cpp
\ setlocal tabstop=8 shiftwidth=8 softtabstop=8 noexpandtab
\ textwidth=80 colorcolumn=81 cindent
\ cinoptions=:0,l1,g0,t0,(0,Ws,m1 nolist
" Makefiles: tabs are mandatory
autocmd FileType make setlocal noexpandtab tabstop=8 shiftwidth=8
" Assembly: kernel asm style
autocmd FileType asm,s
\ setlocal tabstop=8 shiftwidth=8 noexpandtab nolist
" Kconfig / Kbuild
autocmd BufRead,BufNewFile Kconfig*,Kbuild*
\ setlocal filetype=kconfig noexpandtab tabstop=8
" Patch/diff: never touch whitespace
autocmd FileType diff,patch setlocal nolist
" Python: PEP8 (scripts/tooling)
autocmd FileType python
\ setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=79
" Highlight TODO/FIXME/HACK/BUG/XXX/NOTE in all files
autocmd Syntax *
\ call matchadd('Todo', '\v\c<(TODO|FIXME|HACK|BUG|XXX|NOTE|WARN|WARNING)>')
augroup END
" ----------------------------------------------------------
" Statusline (no plugins)
" ----------------------------------------------------------
set statusline=
set statusline+=%#PmenuSel#
set statusline+=\ %f\
set statusline+=%#LineNr#
set statusline+=\ %m%r%h%w\
set statusline+=%=
set statusline+=\ %{&filetype}\
set statusline+=\ %{&fileencoding?&fileencoding:&encoding}\
set statusline+=\ %{&fileformat}\
set statusline+=\ %l:%c\
set statusline+=\ %p%%\
" ==========================================================
" Embedded colorscheme: sysdev_black
" Self-contained — no external files needed
" ==========================================================
if &t_Co>=256
highlight clear
if exists("syntax_on")
syntax reset
endif
let g:colors_name="sysdev_black"
set background=dark
" Base
hi Normal ctermfg=252 ctermbg=NONE
hi Comment ctermfg=244
hi Constant ctermfg=173
hi String ctermfg=150
hi Identifier ctermfg=81
hi Function ctermfg=110
hi Statement ctermfg=161
hi Type ctermfg=149
hi PreProc ctermfg=179
hi Special ctermfg=215
hi Operator ctermfg=252
" Selection / search
hi Visual ctermbg=238
hi Search ctermfg=16 ctermbg=220
hi IncSearch ctermfg=16 ctermbg=214
" Diff
hi DiffAdd ctermfg=150 ctermbg=22
hi DiffDelete ctermfg=203 ctermbg=52
hi DiffChange ctermfg=110 ctermbg=17
hi DiffText ctermfg=255 ctermbg=24 cterm=bold
" UI chrome
hi LineNr ctermfg=240
hi CursorLineNr ctermfg=220
hi CursorLine ctermbg=236 cterm=NONE
hi ColorColumn ctermbg=235
hi SignColumn ctermfg=240 ctermbg=NONE
hi VertSplit ctermfg=238 ctermbg=NONE
hi StatusLine ctermfg=252 ctermbg=238 cterm=NONE
hi StatusLineNC ctermfg=240 ctermbg=234 cterm=NONE
hi Folded ctermfg=244 ctermbg=234
hi MatchParen ctermfg=220 ctermbg=NONE cterm=bold,underline
" Completion menu
hi Pmenu ctermfg=252 ctermbg=236
hi PmenuSel ctermfg=16 ctermbg=220
hi PmenuSbar ctermbg=238
hi PmenuThumb ctermbg=244
" Errors / warnings / todos
hi Error ctermfg=255 ctermbg=160 cterm=bold
hi ErrorMsg ctermfg=255 ctermbg=160
hi WarningMsg ctermfg=214
hi Todo ctermfg=16 ctermbg=220 cterm=bold
endif