Watch
1
0
Fork
You've already forked dotfiles
0
dotfiles/.config/vim/vimrc
Alexander Hess 8f7cef086b
Add configuration for vim
- Add ~/.config/vim/vimrc
  + Configure basic stuff
  + Activate spell checks
  + Activate syntax highlighting and ruler
  + Show whitespace characters
  + Add various snippets for mouse handling,
    toggling line numbers, and search
  + Set `vim`-related directories inside
   ~/.config/vim and ~/.local/state/vim
- Integrate extra settings for Python files
  in ~/.config/vim/after/ftplugin/python.vim
  and ~/.config/vim/after/syntax/python.vim
- Add `vim` artifacts in ~/.config/git/ignore
2026-08-20 21:20:47 +02:00

440 lines
13 KiB
VimL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" Use VIM improved mode
set nocompatible
" Ensure we work with Unicode
set encoding=utf-8
scriptencoding utf-8
" Disable VIM's startup message
set shortmess+=I
" Number of remembered undo steps
set undolevels=1000
" Ensure the XDG variables exist even when `vim` is started
" outside a login shell (e.g., from a desktop launcher)
let $XDG_CONFIG_HOME = get(environ(), 'XDG_CONFIG_HOME', $HOME . '/.config')
let $XDG_STATE_HOME = get(environ(), 'XDG_STATE_HOME', $HOME . '/.local/state')
set runtimepath^=$XDG_CONFIG_HOME/vim
set runtimepath+=$XDG_CONFIG_HOME/vim/after
" Set environment variables for convenient usage
let $RC = expand('$XDG_CONFIG_HOME/vim/vimrc')
let $RTP=split(&runtimepath, ',')[0]
" Make :!cmd use `bash` and load the shell aliases
set shell=/bin/bash
let $BASH_ENV = expand("$XDG_CONFIG_HOME/shell/aliases")
" Detect the file's type and load the corresponding plugin and indent files
filetype plugin indent on
" Enable syntax highlighting
syntax on
" Configure tab behavior
set expandtab " Insert spaces instead of tab characters
set tabstop=4 " Width of an existing tab character
set shiftwidth=4 " Width of one >> or << indent step
set softtabstop=4 " Width inserted/removed by <tab> and <bs>
set shiftround " Round indents to a multiple of shiftwidth
set autoindent " Keep the previous line's indent on a new line
vnoremap <tab> >gv
vnoremap <s-tab> <gv
" Allow backspace to delete characters in insert mode
" beyond the start of the insertion and end of lines
set backspace=start,eol,indent
" Hide buffers instead of closing them, which means we can have
" unwritten changes to a file and open a new one with :e,
" without having to write the changes first
set hidden
" Set to the folder of the current file and its sub-folders
" (this may need to be adapted for large project folders)
set path=.,**
" Store all vim-related working files in the ~/.local/state/vim folder
"
" Note: `viminfo` is a plain string option, so `:set` does not expand
" environment variables in it (unlike the path options below)
" => Build the value via `execute` to expand $XDG_STATE_HOME
execute 'set viminfo+=n' . $XDG_STATE_HOME . '/vim/viminfo'
"
" Use dedicated folders to store temporary backup, swap, and undo files
" (Note: // means that `vim` adapts names automatically to avoid duplicates)
set backupdir=$XDG_STATE_HOME/vim/backup//
set directory=$XDG_STATE_HOME/vim/swap//
set undodir=$XDG_STATE_HOME/vim/undo//
set undofile
"
" To disable any of the temporary files, uncomment one of the following
" set nobackup
" set nowritebackup
" set noswapfile
" set noundofile
" Show the filename in the terminal window's title bar
set title
" Do not wrap lines when showing text
set nowrap
" This avoids a problem of losing data upon insertion in old VIMs
set wrapmargin=0
" Show spelling mistakes in italics
augroup spelling
autocmd!
autocmd FileType markdown,text,gitcommit setlocal spell spelllang=en_us,de_de
augroup END
augroup spell_highlight
autocmd!
autocmd ColorScheme * hi clear SpellBad | hi clear SpellCap
\ | hi clear SpellRare | hi clear SpellLocal
\ | hi SpellBad cterm=italic
augroup END
" Make search highlights readable
" => Explicit `ctermfg` with each `ctermbg`
" because the palette only guarantees contrast
" of each ANSI hue against the background
augroup search_highlight
autocmd!
autocmd ColorScheme * hi Search cterm=bold ctermfg=black ctermbg=yellow
\ | hi IncSearch cterm=bold,reverse ctermfg=yellow ctermbg=black
\ | hi CurSearch cterm=bold ctermfg=black ctermbg=cyan
augroup END
" Make warnings and errors in the status bar stand out
augroup message_highlight
autocmd!
autocmd ColorScheme * hi WarningMsg cterm=bold,reverse ctermfg=yellow ctermbg=black
\ | hi ErrorMsg cterm=bold,reverse ctermfg=red ctermbg=black
augroup END
" Apply all ColorScheme overrides above on startup
silent! doautocmd ColorScheme
" Show whitespace characters
set listchars=tab:»»,extends:›,precedes:‹,nbsp:·,trail:·
set list
" Highlight matching brackets
set showmatch
set matchpairs+=<:>
" Always show the status bar at the bottom
set laststatus=2
" Three lines for commands and messages, so that
" longer warnings fit without a "Press ENTER" prompt
set cmdheight=3
" Show current position in status bar
set ruler
set rulerformat=%=%l/%L\ %c\ (%P)
" Show commands in status bar
set showcmd
" If in non-normal mode, show the mode in the status bar
set showmode
" Better copy and paste behavior (needs vim-gtk3 installed)
if has('clipboard')
set clipboard=unnamed,unnamedplus
endif
" Make : and ; synonyms
nnoremap ; :
" Use \ and <space> as the <leader> keys and lower time to enter key sequences
let mapleader='\'
set timeoutlen=750
" Make <space> the <leader> in visual mode as well
nmap <space> \
vmap <space> \
" Q normally goes into Ex mode
nmap Q <Nop>
" Write with `sudo` rights with w!! or wq!!
function! SudoWrite() abort
" `silent` to skip the "Press ENTER" prompt
silent write !sudo tee % >/dev/null
if v:shell_error
" Repaint first, then show the error, so that it is not wiped
redraw!
echohl ErrorMsg | echomsg 'sudo write failed' | echohl None
else
" Keep the undo history intact
set nomodified
" Suppress the "File has changed ..." warning
" (Note: With `autoread` on, `checktime` syncs the timestamp silently;
" without it, a hidden but blocking W11 prompt would appear)
let s:autoread = &autoread
set autoread
silent! checktime %
let &autoread = s:autoread
" Repaint last to cancel any pending "Press ENTER" state
redraw!
echo ''
endif
endfunction
"
command! -bar SudoWrite call SudoWrite()
cnoreabbrev w!! silent SudoWrite
"
" Quit only if the `sudo` write did not fail
command! -bar SudoWriteQuit call SudoWrite() | if !v:shell_error | quit | endif
cnoreabbrev wq!! silent SudoWriteQuit
" Fix mouse issues with Alacritty terminal
" Source: https://wiki.archlinux.org/title/Alacritty#Mouse_not_working_properly_in_Vim
set ttymouse=sgr
" Make the cursor easier to see
let &t_EI = "\e[2 q" " normal mode: steady block
let &t_SI = "\e[1 q" " insert mode: blinking block
let &t_SR = "\e[2 q" " replace mode: steady block
augroup cursor_shape
autocmd!
autocmd VimEnter * silent execute "!echo -ne '\e[2 q'" | redraw!
autocmd VimLeave * silent execute "!echo -ne '\e[1 q'" | redraw!
augroup END
" Enable the mouse for selections, including a toggle for this mode
set mouse=a
let g:mouse_enabled=1
function! ToggleMouse()
if g:mouse_enabled == 1
echo "Mouse OFF"
set mouse=
let g:mouse_enabled=0
else
echo "Mouse ON"
set mouse=a
let g:mouse_enabled=1
endif
endfunction
noremap <silent><leader>m :call ToggleMouse()<cr>
" Enable toggling between:
" - Showing and hiding line numbers (<leader>l), and
" - Absolute and relative numbers (<leader>a) in normal mode
"
" The default is hidden and relative when shown
"
" Note: Both flags are buffer-local ("b:") with global ("g:") fallbacks,
" so that filetype plugins can enable numbers per buffer
" without leaking into other buffers
let g:show_numbers=0
let g:show_absolute_numbers=0
"
function! ShowLineNumbers()
if get(b:, 'show_numbers', get(g:, 'show_numbers', 0))
setlocal number
if get(b:, 'show_absolute_numbers', get(g:, 'show_absolute_numbers', 0))
setlocal norelativenumber
else
setlocal relativenumber
endif
else
setlocal nonumber
setlocal norelativenumber
endif
endfunction
"
function! ToggleLineNumbers()
let b:show_numbers = !get(b:, 'show_numbers', get(g:, 'show_numbers', 0))
call ShowLineNumbers()
endfunction
"
function! ToggleAbsoluteAndRelativeLineNumbers()
let b:show_absolute_numbers = !get(b:, 'show_absolute_numbers', get(g:, 'show_absolute_numbers', 0))
call ShowLineNumbers()
endfunction
"
" Auto-switch between absolute and relative numbering when switching modes
" where insert mode always shows absolute numbers when numbers are shown
augroup numbertoggle
autocmd!
autocmd BufEnter,FocusGained,InsertLeave * call ShowLineNumbers()
autocmd BufLeave,FocusLost,InsertEnter *
\ if get(b:, 'show_numbers', get(g:, 'show_numbers', 0))
\ | setlocal number norelativenumber
\ | endif
augroup END
"
" Key bindings
nnoremap <silent><leader>l :call ToggleLineNumbers()<cr>
nnoremap <silent><leader>a :call ToggleAbsoluteAndRelativeLineNumbers()<cr>
" Show all possible matches above command-line when tab completing
set wildmenu
set wildmode=longest:full,full
" Highlight search results
set hlsearch
" Shortcut to remove current highlighting
nnoremap <silent><leader>h :nohlsearch<cr>:echo<cr>
" Move cursor to result while typing immediately
set incsearch
" Ignore case when searching
set ignorecase
" Upper case search term => case sensitive search
set smartcase
" Highlight the next match in red for 0.25 seconds
function! HighlightNext()
let [bufnum, lnum, col, off] = getpos('.')
let matchlen = strlen(matchstr(strpart(getline('.'),col-1),@/))
let target_pat = '\c\%#\%('.@/.'\)'
let ring = matchadd('ErrorMsg', target_pat, 101)
redraw
exec 'sleep ' . float2nr(250) . 'm'
call matchdelete(ring)
redraw
endfunction
nnoremap <silent>n n:call HighlightNext()<cr>
nnoremap <silent>N N:call HighlightNext()<cr>
" Save and quit, in three symmetric flavors:
" - Quit => <c-q> / <leader>q (~ `:quit`)
" - Save => <c-s> / <leader>w (~ `:update`)
" - Save & Quit => <c-z> / <leader>z (~ `:exit`)
"
" The <c-*> chords work in normal, visual, and insert mode
" whereas the <leader> variants are chord-free alternatives in normal mode
"
" VIM's built-ins remain untouched and complete the picture:
" - ZZ => `:exit` => Save if changed, then quit (~ "Keep changes, and close")
" - ZQ => `:quit!` => Discard changes, then quit (~ "Never mind, just close")
"
" Notes:
" - <c-s> and <c-q> require flow control to be off
" (see `stty -ixon` in ~/.bashrc and ~/.zshrc),
" or they freeze the terminal instead
" - <c-z> no longer suspends VIM into a background job
" - `:exit` writes only if there are changes, then quits
"
nnoremap <c-q> :quit<cr>
vnoremap <c-q> <c-c>:quit<cr>
inoremap <c-q> <esc>:quit<cr>
nnoremap <leader>q :quit<cr>
"
nnoremap <c-s> :update<cr>
vnoremap <c-s> <c-c>:update<cr>
inoremap <c-s> <c-o>:update<cr>
nnoremap <leader>w :update<cr>
"
nnoremap <c-z> :exit<cr>
vnoremap <c-z> <c-c>:exit<cr>
inoremap <c-z> <esc>:exit<cr>
nnoremap <leader>z :exit<cr>
"
" Show a dialog to save changes instead of an error message
set confirm
" Easier switching between tabs
noremap <leader>, <esc>:tabprevious<cr>
noremap <leader>. <esc>:tabnext<cr>
" Arrow keys either (un)indent lines or move them up or down
" (same for blocks of lines in visual mode)
nnoremap <left> <<
nnoremap <right> >>
nnoremap <silent><up> :m-2<cr>
nnoremap <silent><down> :m+<cr>
vnoremap <left> <gv
vnoremap <right> >gv
vnoremap <up> :m'<-2<cr>gv=gv
vnoremap <down> :m'>+1<cr>gv=gv
" Make Y yank the rest of a line, just like C or D work
nnoremap Y y$
" Make X replace the character under the cursor with a space
nnoremap X r<space>
" Alphabetically sort a selection of lines
vnoremap <leader>s :sort<cr>
" Switch two words, just like xp switches two characters
nnoremap <leader>xp dwElp
" Warn if a file was changed on disk by some other process
" => The buffer is NOT reloaded automatically; instead:
" - `:DiffDisk` shows what differs (close with `:q` in the split)
" - `:e` takes the disk version, `:w` keeps the buffer
augroup checktime
autocmd!
autocmd FocusGained,BufEnter * silent! checktime
augroup END
"
" Show a diff between the buffer and its file on disk
" => Close the split with :q; diff mode ends automatically
command! DiffDisk vert new | set buftype=nofile | read ++edit # | 0d_
\ | diffthis | wincmd p | diffthis | wincmd p
\ | autocmd BufWinLeave <buffer> diffoff!
" Jump to the last known cursor position when reopening a file,
" skipping commit messages and invalid positions
augroup restore_position
autocmd!
autocmd BufReadPost * if line("'\"") >= 1 && line("'\"") <= line("$") && &filetype !~# 'commit'
\ | execute "normal! g`\""
\ | endif
augroup END
" Auto-reload ~/.config/vim/vimrc on write for a fast edit loop
" => NOTE: This adds to state rather than replacing it,
" so, for example, removed mappings and options persist
" until VIM is restarted
augroup vimrc
autocmd!
autocmd BufWritePost $MYVIMRC source % | redraw
augroup END
" Key binding to reload ~/.config/vim/vimrc manually
nnoremap <silent><leader>rc :so $MYVIMRC<cr>