set nocompatible " Disable vi compatibility set noloadplugins " Disable automatic loading of all plugins on startup set encoding=utf-8 " Use UTF-8 set showmatch " Show matching brackets set ignorecase " Case insensitive matching set incsearch " Show partial matches for a search phrase set number " Show numbers set relativenumber " Show relative numbers set tabstop=4 " Tab size set shiftwidth=4 " Indentation size set softtabstop=4 " Tabs/Spaces interop set expandtab " Expands tab to spaces set nomodeline " Disable modeline as a security precaution set mouse=a " Enable mouse mode set hlsearch " Enable search highlight set path+=** " Search recursively with :find set splitbelow " Natural splits set splitright set autoindent " Enable autoindent set complete-=i " Better completion set smarttab " Better tabs set ttimeout " Set timeout set ttimeoutlen=100 set synmaxcol=500 " Syntax limit set laststatus=2 " Always show status line set scrolloff=10 " Scroll offset set sidescrolloff=8 set completeopt=menu,menuone,noselect " Better popup completion set wildmode=longest:full,full " Better commandline autocomplete set autoread " Reload files on change set smartcase " Case-sensitive search if capital letter is typed set confirm " Ask to save changes on exiting modified buffer set breakindent " Wrapped lines preserve indentation set whichwrap+=<,>,h,l,[,] " Allow keys to wrap lines set iskeyword+=- " Treat dash-separated words as a single word set tabpagemax=50 " More tabs set history=1000 " More history set viminfo^=! " Better viminfo set formatoptions+=j " Delete comment character when joining set listchars=tab:,nbsp:_,trail:,extends:>,precedes:< set list " Highlight non whitespace characters set fillchars=eob:\ " Clean trailing tildes set nrformats-=octal " 007 != 010 set sessionoptions-=options set viewoptions-=options set cursorline " Highlight current line set exrc " Use vimrc from local dir set secure " Disable shell/write commands in local vimrc set hidden " Enable switching with modified buffers set undodir=$HOME/.local/state/vim/undo " Enable undo dir set undofile " Enable persistent undos across files set tabline=%!BufferTabLine() set showtabline=2 " Always show the buffer list at the top set clipboard=unnamedplus " Copy Paste from System Clipboard, gvim package might be needed, run vim --version | grep clipboard set statusline=\ %{StatuslineMode()}\ \ \ \ %l:%c\ \ \ \ %p%%\ \ \ \ %f\ %m\ %r%=%{&filetype}\ \ \ \ %{StatuslineFileSize()}\ \ \ \ %{&fileencoding?&fileencoding:&encoding} set background=dark " Use dark background syntax enable " Turn on syntax highlighting let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.8 } } " FZF Floating Window Layout " Auto-create parent directory if it does not exist function! s:AutoCreateDir() abort let l:d = expand(':p:h') if !isdirectory(l:d) call mkdir(l:d, 'p') endif endfunction augroup GeneralAutocmds autocmd! " Go to last position when reopening a file autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif " Remove trailing whitespace and auto-create directory on write autocmd BufWritePre * %s/\s\+$//e | call s:AutoCreateDir() " Close help, quickfix, and man buffers with 'q' autocmd FileType help,qf,man,netrw,gitcommit nnoremap q :close " Resize splits if window got resized autocmd VimResized * tabdo wincmd = " Wrap and check spell in text filetypes autocmd FileType gitcommit,markdown setlocal wrap spell " Disable formatoptions comment continuation on new lines autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o augroup END " Highlight on yank (copy) function! s:HighlightYank() abort if v:event.operator ==# 'y' && exists('*matchaddpos') let l:id = matchaddpos('Visual', range(line("'["), line("']"))) call timer_start(150, {-> execute('silent! call matchdelete(' . l:id . ')')}) endif endfunction augroup HighlightYank autocmd! autocmd TextYankPost * call s:HighlightYank() augroup END " Fuzzy search open buffers function! s:FzfBuffers() abort let l:bufs = filter(range(1, bufnr('$')), 'buflisted(v:val)') let l:lines = map(l:bufs, {_, b -> printf('%d: %s%s', b, \ empty(bufname(b)) ? '[No Name]' : bufname(b), \ getbufvar(b, '&modified') ? ' *' : '')}) call fzf#run(fzf#wrap({ \ 'source': l:lines, \ 'sink': {line -> execute('buffer ' . split(line, ':')[0])}, \ 'options': '--prompt="Buffers> "' \ })) endfunction " Fuzzy search text using Ripgrep function! s:FzfGrep(w, is_word) abort if a:is_word && empty(a:w) return endif let l:rg_base = 'rg --column --line-number --no-heading --color=always --smart-case --hidden --glob "!.git/*"' let l:query = empty(a:w) ? ' ""' : ' ' . shellescape(a:w) let l:prompt = empty(a:w) ? 'Grep> ' : 'GrepWord: ' . a:w . '> ' let l:sink = {line -> execute([ \ 'let l:m = matchlist(line, ''^\(.\{-}\):\(\d\+\)\%(:\(\d\+\)\)\?:'')', \ 'if !empty(l:m)', \ ' execute "edit +" . l:m[2] . " " . fnameescape(l:m[1])', \ ' execute "normal! " . (empty(l:m[3]) ? 1 : l:m[3]) . "|"', \ 'endif' \ ])} call fzf#run(fzf#wrap({ \ 'source': l:rg_base . l:query, \ 'sink': l:sink, \ 'options': '--ansi --delimiter : --nth 4.. --prompt="' . l:prompt . '"' \ })) endfunction " Fuzzy search git files (using git ls-files) function! s:FzfGitFiles() abort if isdirectory('.git') || system('git rev-parse --is-inside-work-tree') =~# 'true' call fzf#run(fzf#wrap({'source': 'git ls-files --exclude-standard --cached --others', 'options': '--prompt="GitFiles> "'})) else call fzf#run(fzf#wrap({'options': '--prompt="Files> "'})) endif endfunction " Fuzzy search old files history function! s:FzfHistory() abort call fzf#run(fzf#wrap({'source': filter(copy(v:oldfiles), 'filereadable(expand(v:val))'), 'options': '--prompt="History> "'})) endfunction " Run ranger to edit a file (hijacks directories to replace netrw) function! s:RangerChooser(...) abort let t = tempname() exec 'silent !ranger --choosefile='.shellescape(t).(a:0 ? ' '.shellescape(a:1) : '') if filereadable(t) exec 'edit '.fnameescape(readfile(t)[0]) | call delete(t) endif redraw! endfunction augroup RangerHijack au! au VimEnter * silent! au! FileExplorer au BufEnter * if isdirectory(expand("")) | call s:RangerChooser(expand("")) | endif augroup END " Helper to get current mode for statusline function! StatuslineMode() abort return get({'n':'N','v':'V','V':'VL',"\":'VB','i':'I','R':'R','c':'C','t':'T'}, mode(), mode()) endfunction " Helper to get current file size for statusline function! StatuslineFileSize() abort let l:b = getfsize(expand('%:p')) return l:b <= 0 ? '' : l:b < 1024 ? l:b.'B' : l:b < 1048576 ? printf('%.1fKiB', l:b/1024.0) : printf('%.1fMiB', l:b/1048576.0) endfunction " Native Buffer Tabline at the top (replaces standard tabline) function! BufferTabLine() abort let l:s = '' let l:cur = bufnr('%') let l:bufs = filter(range(1, bufnr('$')), 'buflisted(v:val)') for l:b in l:bufs let l:s .= (l:b == l:cur) ? '%#TabLineSel#' : '%#TabLine#' let l:name = empty(bufname(l:b)) ? '[No Name]' : fnamemodify(bufname(l:b), ':t') let l:mod = getbufvar(l:b, '&modified') ? '*' : '' let l:s .= ' ' . l:b . ' ' . l:name . l:mod . ' ' endfor return l:s . '%#TabLineFill#%T' endfunction " Project-wide search and replace via Ripgrep and Quickfix function! s:Replace(query) abort let l:find = empty(a:query) ? input('Find: ') : a:query if empty(l:find) return endif let l:replace = input('Replace with: ') let l:output = system('rg --vimgrep --smart-case ' . shellescape(l:find)) if v:shell_error != 0 || empty(l:output) echohl WarningMsg | echo 'No matches found for: ' . l:find | echohl None return endif call setqflist([], 'r', {'title': 'Search: ' . l:find, 'lines': split(l:output, "\n")}) let l:original_buf = bufnr('%') copen let l:choice = confirm('Replace all occurrences?', "&Yes\n&Confirm each\n&Cancel", 1) if l:choice == 1 try execute 'cfdo %s/' . escape(l:find, '/') . '/' . escape(l:replace, '/') . '/g | update' execute 'buffer ' . l:original_buf echo 'Replaced all occurrences of "' . l:find . '" with "' . l:replace . '"' catch echohl ErrorMsg | echo 'Replacement failed: ' . v:exception | echohl None endtry elseif l:choice == 2 call feedkeys(':cfdo %s/' . escape(l:find, '/') . '/' . escape(l:replace, '/') . '/gc | update', 'n') endif endfunction command! -nargs=? Replace call s:Replace() " Copy text to clipboard (works on Wayland/X11 with native +clipboard, or WSL via win32yank) function! s:CopyToClipboard(text) abort if executable('win32yank.exe') call system('win32yank.exe -i', a:text) elseif has('clipboard') let @+ = a:text else let @" = a:text endif endfunction " Copy GitHub URL for the current line or visual selection function! s:CopyGitUrl(line1, line2) abort let l:f = expand('%:.') if empty(l:f) return endif let l:u = trim(system('git config --get remote.origin.url')) let l:u = substitute(l:u, '\.git$', '', '') if empty(l:u) echohl WarningMsg | echo 'Not a git repository' | echohl None return endif " Convert SSH git@github.com:user/repo to HTTPS URL (GitHub only) let l:u = substitute(l:u, 'git@github\.com:', 'https://github.com/', '') let l:u = substitute(l:u, 'ssh://git@github\.com/', 'https://github.com/', '') let l:b = trim(system('git branch --show-current')) let l:b = empty(l:b) ? trim(system('git rev-parse --short HEAD')) : l:b let l:url = printf('%s/blob/%s/%s#L%d', l:u, l:b, l:f, a:line1) if a:line1 != a:line2 let l:url .= '-L' . a:line2 endif call s:CopyToClipboard(l:url) echo 'Copied Git URL to clipboard: ' . l:url endfunction command! -range CopyGitUrl call s:CopyGitUrl(, ) " Lightweight Autopairs function! s:ClosePair(c) abort return getline('.')[col('.') - 1] == a:c ? "\" : a:c endfunction function! s:CloseQuote(c) abort let l:col = col('.') let l:line = getline('.') if l:line[l:col - 1] == a:c return "\" endif " Special case for single quote: don't pair if preceded by a letter/number if a:c ==# "'" && l:col > 1 && l:line[l:col - 2] =~# '[a-zA-Z0-9]' return "'" endif return a:c . a:c . "\" endfunction function! s:BackspacePair() abort let l:col = col('.') let l:line = getline('.') if l:col > 1 let l:prev = l:line[l:col - 2] let l:next = l:line[l:col - 1] let l:pairs = {'(': ')', '[': ']', '{': '}', '"': '"', "'": "'", '`': '`'} if get(l:pairs, l:prev, '') == l:next return "\\" endif endif return "\" endfunction " Seamless Vim/Tmux Split Navigation function! s:TmuxNavigate(dir) abort let l:w = winnr() execute 'wincmd ' . a:dir if l:w == winnr() && exists('$TMUX') call system('tmux select-pane -' . get({'h':'L','j':'D','k':'U','l':'R'}, a:dir)) endif endfunction " Autopair keybindings inoremap ( () inoremap [ [] inoremap { {} inoremap ) ClosePair(')') inoremap ] ClosePair(']') inoremap } ClosePair('}') inoremap " CloseQuote('"') inoremap ' CloseQuote("'") inoremap ` CloseQuote('`') inoremap BackspacePair() " Centered search result scrolling nnoremap zz nnoremap zz nnoremap n (v:searchforward ? 'nzzzv' : 'Nzzzv') nnoremap N (v:searchforward ? 'Nzzzv' : 'nzzzv') " Blackhole deletes (prevent character deletions from polluting clipboard) nnoremap x "_x vnoremap x "_x nnoremap X "_D vnoremap X "_d " Visual overwrite paste (prevent visual paste from replacing default register) vnoremap p "_dP " Persist visual selection when indenting vnoremap < >gv " Easy home-row line start and end navigation nnoremap gh ^ vnoremap gh ^ nnoremap gl $ vnoremap gl $ " Keep cursor position when joining lines nnoremap J mzJ`z " Drag Visual selections vnoremap K xkP`[V`] vnoremap J xp`[V`] vnoremap L >gv vnoremap H [j nnoremap ]j nnoremap [l :lprev nnoremap ]l :lnext nnoremap ]q :cnext nnoremap [q :cprev " Math increments (matches Neovim) nnoremap - nnoremap = " Undo split breakpoints inoremap , ,u inoremap . .u inoremap ; ;u " General Keybindings let mapleader = ' ' inoremap jj tnoremap JJ nnoremap H :bprevious nnoremap L :bnext nnoremap s :setlocal spell! nnoremap t :term nnoremap ww :w nnoremap :nohlsearch " Edit Files nnoremap ea :b# nnoremap ec :call fzf#run(fzf#wrap({'dir': expand('~/.config'), 'options': '--prompt="Config> "'})) nnoremap ee :call RangerChooser() nnoremap en :enew nnoremap es :source $MYVIMRC:echo "Vimrc sourced!" nnoremap ev :edit $MYVIMRC " Fuzzy search maps matching pickme.nvim / Seeker nnoremap :FZF nnoremap fa :call fzf#run(fzf#wrap({'options': '--prompt="Files> "'})) nnoremap fb :call FzfBuffers() nnoremap ff :call FzfGitFiles() nnoremap fg :call FzfGrep('', 0) nnoremap fr :call FzfHistory() nnoremap fw :call FzfGrep(expand(''), 1) " Replace / substitution helper mappings nnoremap ra :Replace nnoremap rb :%s///gc nnoremap rs :%s/\<\>/\\/gI nnoremap rw :Replace " Sort / text processing mappings vnoremap ci :sort i vnoremap cS :sort! vnoremap cs :sort vnoremap cu :!uniq " Insertion helper mappings nnoremap id :put =strftime('## %a, %d %b, %Y, %r') nnoremap if :put =expand('%:t') nnoremap iP :put %:p nnoremap ip :put % nnoremap it :put =strftime('## %r') " Git Search Keymaps (Lazygit & Shell Git Integration) nnoremap :silent !lazygit:redraw! nnoremap gg :silent !lazygit:redraw! " Split Creation and Navigation nnoremap s` p nnoremap sa :split nnoremap sH :vertical resize -10 nnoremap sh h nnoremap sJ :resize -10 nnoremap sj j nnoremap sK :resize +10 nnoremap sk k nnoremap sL :vertical resize +10 nnoremap sl l nnoremap ss :vsplit " Seamless Vim/Tmux Navigation nnoremap :call TmuxNavigate('h') nnoremap :call TmuxNavigate('j') nnoremap :call TmuxNavigate('k') nnoremap :call TmuxNavigate('l') " Buffer Control & Quit Operations nnoremap qa :qall nnoremap qd :b#\|bd# nnoremap qo :%bdelete\|b#\|bdelete# nnoremap qq :q nnoremap qs c nnoremap x :x nnoremap Q :qa! " Yank bindings nnoremap ya :%y+ nnoremap yf :call CopyToClipboard(expand('%:t')) nnoremap yg :CopyGitUrl nnoremap yl :call CopyToClipboard(expand('%') . ':' . line('.')) nnoremap yL :call CopyToClipboard(expand('%:p') . ':' . line('.')) nnoremap yp :call CopyToClipboard(expand('%')) nnoremap yP :call CopyToClipboard(expand('%:p')) vnoremap yg :CopyGitUrl " tmux true color fix if has("termguicolors") | set termguicolors | endif augroup ColorOverrides autocmd! autocmd ColorScheme * highlight! Normal ctermbg=NONE guibg=NONE \ | highlight! Terminal ctermbg=NONE guibg=NONE \ | highlight CursorLine cterm=NONE ctermbg=235 guibg=#222530 \ | highlight StatusLine cterm=NONE ctermfg=14 ctermbg=0 guifg=#89b4fa guibg=#000000 \ | highlight StatusLineNC cterm=NONE ctermfg=8 ctermbg=0 guifg=#585b70 guibg=#000000 \ | highlight TabLineSel cterm=NONE ctermfg=15 ctermbg=235 guifg=#ffffff guibg=#252535 \ | highlight TabLine cterm=NONE ctermfg=244 ctermbg=234 guifg=#a6adc8 guibg=#181825 \ | highlight TabLineFill cterm=NONE ctermbg=0 guibg=#000000 \ | highlight MsgArea ctermfg=15 guifg=#ffffff augroup END augroup StatuslineColors autocmd! autocmd ModeChanged *:i,*:R highlight StatusLine ctermfg=10 guifg=#a6e3a1 execute "autocmd ModeChanged *:\,*:v,*:V highlight StatusLine ctermfg=3 guifg=#f9e2af" autocmd ModeChanged *:t highlight StatusLine ctermfg=9 guifg=#f38ba8 autocmd ModeChanged *:n highlight StatusLine ctermfg=14 guifg=#89b4fa augroup END " Load colorscheme with fallback to built-in 'slate' try colorscheme catppuccin catch /^Vim\%((\a\+)\)\=:E185/ colorscheme slate endtry " Manually load required plugins since noloadplugins is set silent! runtime plugin/matchparen.vim " Highlight matching parentheses silent! packadd! matchit " Extended % matching for HTML tags, etc. silent! runtime plugin/spellfile.vim " Auto-download missing spellfiles silent! runtime ftplugin/man.vim " Enable :Man command to view man pages silent! runtime plugin/logiPat.vim " Boolean logical search patterns (:LogiPat) silent! runtime plugin/fzf.vim " Fuzzy finder integration