" ============================================================================ " Vim Configuration - The Ultimate vimrc " Inspired by the best practices from the Vim community " ============================================================================ " ============================================================================ " => General Settings " ============================================================================ " Disable compatibility with vi which can cause unexpected issues set nocompatible " Detect terminal type and capabilities (must be early for conditional configs) let g:is_tty = empty($TERM) || $TERM ==# 'dumb' || $TERM =~# 'linux' || $TERM =~# 'screen' || &term =~# 'builtin' let g:has_true_color = ($COLORTERM == 'truecolor' || $COLORTERM == '24bit') " Enable type file detection. Vim will be able to try to detect the type of file in use filetype on " Enable plugins and load plugin for the detected file type filetype plugin on " Load an indent file for the detected file type filetype indent on " Turn syntax highlighting on syntax on " Add numbers to each line on the left-hand side set number " Show relative line numbers set relativenumber " Highlight cursor line (disabled in TTY for performance) if !g:is_tty set cursorline endif " Do not save backup files set nobackup " Do not let cursor scroll below or above N number of lines when scrolling set scrolloff=10 " Do not wrap lines. Allow long lines to extend as far as the line goes set nowrap " While searching though a file incrementally highlight matching characters as you type set incsearch " Ignore capital letters during search set ignorecase " Override the ignorecase option if searching for capital letters set smartcase " Show partial command you type in the last line of the screen set showcmd " Show the mode you are on the last line set showmode " Use highlighting when doing a search set hlsearch " Set the commands to save in history default number is 20 set history=1000 " Enable auto completion menu after pressing TAB set wildmenu " Make wildmenu behave like similar to Bash completion set wildmode=list:longest " Case-insensitive filename completion in wildmenu (spf13, YADR) set wildignorecase " Files and directories to exclude from wildmenu and :find set wildignore=*.docx,*.jpg,*.png,*.gif,*.pdf,*.pyc,*.exe,*.flv,*.img,*.xlsx set wildignore+=*/node_modules/*,*/.git/*,*/__pycache__/*,*/dist/*,*/build/* " Recursive :find across the project tree (works with wildignore above) set path+=** " Enable mouse support set mouse=a " Set encoding set encoding=utf-8 " Enable folding set foldmethod=indent set foldlevel=99 " Split window settings set splitbelow set splitright " Better backspace behavior set backspace=indent,eol,start " Auto read when file is changed from outside set autoread " Height of the command bar set cmdheight=1 " A buffer becomes hidden when it is abandoned set hid " Configure backspace so it acts as it should act (enhanced from earlier basic setting) set whichwrap+=<,>,h,l " For regular expressions turn magic on set magic " Show matching brackets and how many tenths of a second to blink set showmatch set mat=2 " No annoying sound on errors set noerrorbells set novisualbell set t_vb= set tm=500 " Separate timeout for keycodes (arrow keys, Esc) vs leader sequences " ttimeoutlen=10 eliminates the ~500ms ESC lag in terminal Vim (vim-sensible) set ttimeout set ttimeoutlen=10 " Enable 256 colors palette in Gnome Terminal if $COLORTERM == 'gnome-terminal' set t_Co=256 endif " Set extra options when running in GUI mode if has("gui_running") set guioptions-=T set guioptions-=e set t_Co=256 set guitablabel=%M\ %t endif " Show last line partially instead of replacing it with @@@ (vim-sensible) set display+=lastline " Use Unix as the standard file type set ffs=unix,dos,mac set nowb set noswapfile " Persistent undo across sessions if has('persistent_undo') set undofile let &undodir = expand('~/.vim/.undo') silent! call mkdir(&undodir, 'p', 0700) endif " ============================================================================ " => Vim-Plug Plugin Manager " ============================================================================ " Auto-install vim-plug let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim' if empty(glob(data_dir . '/autoload/plug.vim')) silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' autocmd VimEnter * PlugInstall --sync | source $MYVIMRC endif " Plugin list call plug#begin('~/.vim/plugged') " ===== File Navigation & Search ===== Plug 'preservim/nerdtree' " File explorer Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim' " Fuzzy finder " ===== Git Integration ===== Plug 'tpope/vim-fugitive' " Git wrapper Plug 'airblade/vim-gitgutter' " Show git diff in gutter " ===== Status Line & UI ===== Plug 'vim-airline/vim-airline' " Status bar Plug 'vim-airline/vim-airline-themes' " Airline themes " ===== Code Editing & Completion ===== Plug 'tpope/vim-surround' " Surround text objects Plug 'tpope/vim-commentary' " Comment stuff out Plug 'tpope/vim-repeat' " Repeat plugin maps Plug 'jiangmiao/auto-pairs' " Auto close brackets Plug 'dense-analysis/ale' " Async linting engine " ===== Language Support ===== Plug 'sheerun/vim-polyglot' " Language pack Plug 'fatih/vim-go' " Go support (run :GoUpdateBinaries manually if needed) " ===== Color Schemes ===== Plug 'morhetz/gruvbox' " Gruvbox theme Plug 'dracula/vim', { 'as': 'dracula' } " Dracula theme Plug 'altercation/vim-colors-solarized' " Solarized theme Plug 'joshdick/onedark.vim' " One Dark theme " ===== Productivity ===== Plug 'mbbill/undotree' " Undo history visualizer Plug 'preservim/tagbar' " Tag browser Plug 'easymotion/vim-easymotion' " Easy motion " ===== Code Intelligence (CoC: requires Vim 8.0.1453+ and Node.js) ===== if (has('nvim') || has('patch-8.0.1453')) && executable('node') Plug 'neoclide/coc.nvim', {'branch': 'release'} " Full LSP + completion via Node.js endif " ===== Session Management ===== Plug 'tpope/vim-obsession' " Continuous session save Plug 'dhruvasagar/vim-prosession' " Better session management " ===== Additional Utilities ===== Plug 'tpope/vim-unimpaired' " Handy bracket mappings Plug 'wellle/targets.vim' " Additional text objects Plug 'honza/vim-snippets' " Snippet collection Plug 'christoomey/vim-tmux-navigator' " Seamless vim/tmux pane navigation " ===== Native LSP (vim-lsp: works without Node.js, Vim 8.0+ only) ===== " Used as fallback when CoC/Node.js is unavailable if !((has('nvim') || has('patch-8.0.1453')) && executable('node')) Plug 'prabirshrestha/vim-lsp' " Pure VimScript LSP client Plug 'mattn/vim-lsp-settings' " Auto-configure language servers Plug 'prabirshrestha/asyncomplete.vim' " Async completion framework Plug 'prabirshrestha/asyncomplete-lsp.vim' " LSP completion source for asyncomplete endif " ===== Enhanced UI Experience ===== Plug 'mhinz/vim-startify' " Startup screen with recent files Plug 'liuchengxu/vim-which-key' " Show keybindings on leader pause if !g:is_tty Plug 'Yggdroot/indentLine' " Indent guide lines endif call plug#end() " ============================================================================ " => LSP Backend Detection & Completion Settings " ============================================================================ " Detect which LSP backend is active " Priority: CoC (full-featured, needs Node.js) > vim-lsp (lightweight fallback) let g:use_coc = (has('nvim') || has('patch-8.0.1453')) && executable('node') && exists('g:plugs["coc.nvim"]') let g:use_vimlsp = !g:use_coc && has('patch-8.0.0') && exists('g:plugs["vim-lsp"]') " Suppress coc.nvim's blocking startup warning on Vim < 9.0.0438 " (the guard above already prevents coc from loading, but the warning " fires from the plugin file itself if coc.nvim is in runtimepath) if !g:use_coc let g:coc_start_at_startup = 0 let g:coc_disable_startup_warning = 1 endif " Limit popup menu height (applies to all completion) set pumheight=15 " ============================================================================ " => Colors and Fonts " ============================================================================ " Enable true colors support only if terminal supports it if g:has_true_color && has('termguicolors') && !g:is_tty set termguicolors endif " Set colorscheme with proper fallbacks if &t_Co >= 256 && !g:is_tty " 256-color terminals try colorscheme gruvbox set background=dark catch try colorscheme desert catch colorscheme default endtry endtry else " Basic 16-color terminals (TTY, console) colorscheme default set background=dark endif " Set font for GUI if has("gui_running") if has("gui_gtk2") || has("gui_gtk3") set guifont=Hack\ 12,Source\ Code\ Pro\ 12,Monospace\ 12 elseif has("gui_win32") set guifont=Consolas:h11:cANSI endif endif " ============================================================================ " => Text, Tab and Indent Related " ============================================================================ " Visible whitespace characters (toggled with ) " TTY: ASCII equivalents; GUI/modern terminal: Unicode symbols if g:is_tty set listchars=tab:>-,trail:.,extends:>,precedes:<,nbsp:_ else set listchars=tab:→\ ,trail:·,extends:▸,precedes:◂,nbsp:· endif " Use spaces instead of tabs set expandtab " Be smart when using tabs set smarttab " 1 tab == 4 spaces set shiftwidth=4 set tabstop=4 " Linebreak on 500 characters set lbr set tw=500 set autoindent set smartindent " ============================================================================ " => Key Mappings " ============================================================================ " Set leader key to comma let mapleader = "," " Fast saving nmap w :w! " Fast quitting nmap q :q " Fast save and quit nmap x :x " Disable highlight when is pressed map :noh " Window navigation — owned by vim-tmux-navigator plugin (Ctrl+h/j/k/l works " seamlessly across Vim splits and tmux panes; no manual maps needed here) " Close the current buffer (Bclose preserves window layout) map bd :Bclose " Close all the buffers map ba :bufdo bd " Next buffer map l :bnext " Previous buffer map h :bprevious " Useful mappings for managing tabs map tn :tabnew map to :tabonly map tc :tabclose map tm :tabmove map t :tabnext " Let 'tl' toggle between this and the last accessed tab let g:lasttab = 1 nmap tl :exe "tabn ".g:lasttab augroup ChopstickTabHistory autocmd! autocmd TabLeave * let g:lasttab = tabpagenr() augroup END " Opens a new tab with the current buffer's path map te :tabedit =expand("%:p:h")/ " Change window-local CWD to current file's directory (lcd = local, safer than cd) map cd :lcd %:p:h:pwd " Open built-in file browser (works on any Vim, no plugins needed — tpope) nnoremap e :Explore " Remap VIM 0 to first non-blank character map 0 ^ " Reselect last pasted text (gV = visual select last paste) — spf13, YADR nnoremap gV `[v`] " Command-line history navigation with Ctrl+p/n (amix, spf13) cnoremap cnoremap " Move a line of text using ALT+[jk] (normal mode) nmap mz:m+`z nmap mz:m-2`z " Move selected lines up/down and re-indent (visual mode) — ThePrimeagen " Overrides visual-J (join) and visual-K (keywordprg) — use normal mode for those vnoremap J :m '>+1gv=gv vnoremap K :m '<-2gv=gv " Pressing ,ss will toggle and untoggle spell checking map ss :setlocal spell! " Shortcuts using map sn ]s map sp [s map sa zg map s? z= " Toggle paste mode set pastetoggle= " Toggle line numbers nnoremap :set invnumber " Toggle relative line numbers nnoremap :set invrelativenumber " Toggle visible whitespace (tabs, trailing spaces, non-breaking spaces) nnoremap :set list! " Enable folding with the spacebar nnoremap za " Y yanks to end of line (consistent with D, C) nnoremap Y y$ " Disable accidental Ex mode nnoremap Q " Exit insert mode without reaching for Escape (community standard) inoremap jk " Keep visual selection after indent vnoremap < >gv " Center cursor when jumping through search results nnoremap n nzzzv nnoremap N Nzzzv " Search for visually selected text with // (hit // in visual mode) vnoremap // y/\V=escape(@",'/\') " to save in normal and insert mode " (for terminals: add 'stty -ixon' to your shell rc to disable XON/XOFF) nnoremap :w inoremap :wa " Center cursor after half-page scroll nnoremap zz nnoremap zz " System clipboard yank/paste (conditional: requires clipboard provider) if has('clipboard') nnoremap y "+y vnoremap y "+y nnoremap Y "+Y nnoremap p "+p nnoremap P "+P endif " Quickfix list shortcuts ([q/]q from vim-unimpaired handles navigation) nnoremap qo :copen nnoremap qc :cclose " Auto-equalize splits when terminal window is resized augroup ChopstickResize autocmd! autocmd VimResized * wincmd = augroup END " ============================================================================ " => Plugin Settings " ============================================================================ " --- NERDTree --- map :NERDTreeToggle map n :NERDTreeFind " Close vim if the only window left open is a NERDTree augroup NERDTreeAutoClose autocmd! autocmd BufEnter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif augroup END " Show hidden files let NERDTreeShowHidden=1 " Ignore files in NERDTree let NERDTreeIgnore=['\.pyc$', '\~$', '\.swp$', '\.git$', '\.DS_Store', 'node_modules', '__pycache__', '\.egg-info$'] " NERDTree window size let NERDTreeWinSize=35 " Track stdin reads so startup autocmds can skip pipe/heredoc input augroup ChopstickStdin autocmd! autocmd StdinReadPre * let s:std_in=1 augroup END " Startup layout (non-TTY only — keeps TTY startup instant) if !g:is_tty augroup ChopstickStartup autocmd! " vim → NERDTree on left + Startify (or blank buffer) on right autocmd VimEnter * \ if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') | \ exe 'NERDTree ' . fnameescape(argv()[0]) | \ exe 'cd ' . fnameescape(argv()[0]) | \ wincmd p | \ if exists(':Startify') == 2 | Startify | else | enew | endif | \ endif " vim (no args) → Startify fullscreen dashboard, no auto NERDTree " Use Ctrl+n to open NERDTree when needed augroup END endif " --- FZF --- " Smart file search: use GFiles (respects .gitignore) inside git repos, Files elsewhere function! s:SmartFiles() abort if !empty(system('git rev-parse --show-toplevel 2>/dev/null')) GFiles else Files endif endfunction map :call SmartFiles() map b :Buffers map rg :Rg map rG :Rg -F map rt :Tags map gF :GFiles " FZF customization for better project search let g:fzf_layout = { 'down': '40%' } " Disable preview in TTY for better performance if g:is_tty let g:fzf_preview_window = [] else let g:fzf_preview_window = ['right:50%', 'ctrl-/'] endif " Advanced FZF commands " Conditionally enable preview based on terminal type if g:is_tty command! -bang -nargs=* Rg \ call fzf#vim#grep( \ 'rg --column --line-number --no-heading --color=always --smart-case -- '.shellescape(), 1, \ 0) command! -bang GFiles call fzf#vim#gitfiles('', 0) else command! -bang -nargs=* Rg \ call fzf#vim#grep( \ 'rg --column --line-number --no-heading --color=always --smart-case -- '.shellescape(), 1, \ fzf#vim#with_preview(), 0) command! -bang GFiles call fzf#vim#gitfiles('', fzf#vim#with_preview(), 0) endif " --- Airline --- " Disable powerline fonts in TTY for compatibility if g:is_tty let g:airline_powerline_fonts = 0 let g:airline_left_sep = '' let g:airline_right_sep = '' let g:airline#extensions#tabline#left_sep = ' ' let g:airline#extensions#tabline#left_alt_sep = '|' else let g:airline_powerline_fonts = 1 endif let g:airline#extensions#tabline#enabled = 1 let g:airline#extensions#tabline#formatter = 'unique_tail' " Set theme based on terminal capabilities if &t_Co >= 256 && !g:is_tty let g:airline_theme='gruvbox' else let g:airline_theme='dark' endif " --- GitGutter --- let g:gitgutter_sign_added = '+' let g:gitgutter_sign_modified = '~' let g:gitgutter_sign_removed = '-' let g:gitgutter_sign_removed_first_line = '^' let g:gitgutter_sign_modified_removed = '~' " --- ALE (Asynchronous Lint Engine) --- let g:ale_linters = { \ 'python': ['flake8', 'pylint'], \ 'javascript': ['eslint'], \ 'typescript': ['eslint', 'tsserver'], \ 'go': ['gopls', 'staticcheck'], \ 'rust': ['cargo'], \ 'sh': ['shellcheck'], \ 'yaml': ['yamllint'], \ 'dockerfile': ['hadolint'], \ 'css': ['stylelint'], \ 'scss': ['stylelint'], \ 'markdown': ['markdownlint'], \ 'sql': ['sqlfluff'], \} let g:ale_fixers = { \ '*': ['remove_trailing_lines', 'trim_whitespace'], \ 'python': ['black', 'isort'], \ 'javascript': ['prettier', 'eslint'], \ 'typescript': ['prettier', 'eslint'], \ 'go': ['gofmt', 'goimports'], \ 'rust': ['rustfmt'], \ 'json': ['prettier'], \ 'yaml': ['prettier'], \ 'html': ['prettier'], \ 'css': ['prettier'], \ 'scss': ['prettier'], \ 'less': ['prettier'], \ 'markdown': ['prettier'], \ 'sql': ['sqlfluff'], \} " Don't fix on save if LSP is handling formatting (avoids double-format) let g:ale_fix_on_save = !g:use_vimlsp let g:ale_sign_error = 'X' let g:ale_sign_warning = '!' let g:ale_lint_on_text_changed = 'normal' let g:ale_lint_on_insert_leave = 1 let g:ale_lint_on_enter = 1 " --- vim-go: disable built-in LSP/gopls — CoC (coc-go) handles all Go intelligence --- " vim-go's gopls conflicts with coc-go and causes E495 errors on startup " (BufWinEnter afile expand fails for non-file buffers like NERDTree/Startify) let g:go_gopls_enabled = 0 " disable vim-go's own gopls — coc-go handles LSP let g:go_code_completion_enabled = 0 " let CoC handle completion " Use godef as fallback for jump-to-def when CoC unavailable; gopls+disabled = error let g:go_def_mode = g:use_coc ? 'gopls' : 'godef' let g:go_info_mode = g:use_coc ? 'gopls' : 'godef' let g:go_fmt_autosave = 0 " CoC/ALE handle format-on-save let g:go_imports_autosave = 0 let g:go_highlight_types = 1 " keep syntax features let g:go_highlight_fields = 1 let g:go_highlight_functions = 1 let g:go_highlight_function_calls = 1 " Navigate between errors: [e/]e (unimpaired convention: [ = prev, ] = next) nmap [e :ALEPrevious nmap ]e :ALENext nmap aD :ALEDetail " --- Tagbar --- nmap :TagbarToggle nmap tt :TagbarToggle " --- UndoTree --- nnoremap :UndotreeToggle nnoremap u :UndotreeToggle " --- EasyMotion --- let g:EasyMotion_do_mapping = 0 " Disable default mappings " Jump to anywhere you want with minimal keystrokes nmap s (easymotion-overwin-f2) " Turn on case-insensitive feature let g:EasyMotion_smartcase = 1 " JK motions: Line motions map j (easymotion-j) map k (easymotion-k) " --- CoC (Conquer of Completion) - Full LSP via Node.js --- if g:use_coc " Tab for trigger completion / navigate popup inoremap \ coc#pum#visible() ? coc#pum#next(1) : \ CheckBackspace() ? "\" : \ coc#refresh() inoremap coc#pum#visible() ? coc#pum#prev(1) : "\" " CR to confirm selected completion item inoremap coc#pum#visible() ? coc#pum#confirm() \: "\u\\=coc#on_enter()\" function! CheckBackspace() abort let col = col('.') - 1 return !col || getline('.')[col - 1] =~# '\s' endfunction " to trigger completion manually inoremap coc#refresh() " Diagnostic navigation nmap [g (coc-diagnostic-prev) nmap ]g (coc-diagnostic-next) nmap ad :CocDiagnostics " GoTo code navigation nmap gd (coc-definition) nmap gy (coc-type-definition) nmap gi (coc-implementation) nmap gr (coc-references) " Hover documentation nnoremap K :call ShowDocumentation() function! ShowDocumentation() if CocAction('hasProvider', 'hover') call CocActionAsync('doHover') else call feedkeys('K', 'in') endif endfunction " Highlight symbol and its references on cursor hold augroup CocHighlight autocmd! autocmd CursorHold * silent call CocActionAsync('highlight') augroup END " Symbol renaming nmap rn (coc-rename) " Format selected code xmap f (coc-format-selected) nmap f (coc-format-selected) " Code actions (cursor, file, selected range) nmap ca (coc-codeaction-cursor) nmap cA (coc-codeaction-source) xmap ca (coc-codeaction-selected) " Apply auto-fix for current line nmap qf (coc-fix-current) " Run code lens action on current line nmap cl (coc-codelens-action) " Workspace symbols and outline nnoremap ws :CocList -I symbols nnoremap o :CocList outline " Search recently used commands nnoremap cc :CocList commands " Resume latest CoC list nnoremap cr :CocListResume " Show all diagnostics nnoremap cD :CocList diagnostics " Text object for function/class (requires language server support) xmap if (coc-funcobj-i) omap if (coc-funcobj-i) xmap af (coc-funcobj-a) omap af (coc-funcobj-a) xmap ic (coc-classobj-i) omap ic (coc-classobj-i) xmap ac (coc-classobj-a) omap ac (coc-classobj-a) " Scroll float windows if has('nvim-0.4.0') || has('patch-8.2.0750') nnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\" nnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\" inoremap coc#float#has_scroll() ? "\=coc#float#scroll(1)\" : "\" inoremap coc#float#has_scroll() ? "\=coc#float#scroll(0)\" : "\" endif " Status line integration set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')} endif " --- vim-lsp (Native VimScript LSP - fallback when Node.js unavailable) --- if g:use_vimlsp " Auto-configure language servers via vim-lsp-settings let g:lsp_settings_filetype_python = ['pylsp', 'pyright-langserver'] let g:lsp_settings_filetype_go = ['gopls'] let g:lsp_settings_filetype_rust = ['rust-analyzer'] let g:lsp_settings_filetype_typescript = ['typescript-language-server'] let g:lsp_settings_filetype_javascript = ['typescript-language-server'] let g:lsp_settings_filetype_sh = ['bash-language-server'] let g:lsp_settings_filetype_html = ['vscode-html-language-server'] let g:lsp_settings_filetype_css = ['vscode-css-language-server'] let g:lsp_settings_filetype_scss = ['vscode-css-language-server'] let g:lsp_settings_filetype_json = ['vscode-json-language-server'] let g:lsp_settings_filetype_yaml = ['yaml-language-server'] let g:lsp_settings_filetype_markdown = ['marksman'] let g:lsp_settings_filetype_sql = ['sqls'] " Performance: disable virtual text diagnostics in TTY let g:lsp_diagnostics_virtual_text_enabled = !g:is_tty let g:lsp_diagnostics_highlights_enabled = !g:is_tty let g:lsp_document_highlight_enabled = !g:is_tty let g:lsp_signs_enabled = 1 let g:lsp_diagnostics_echo_cursor = 1 let g:lsp_completion_documentation_enabled = 1 " Diagnostic signs (ASCII, KISS) let g:lsp_signs_error = {'text': 'X'} let g:lsp_signs_warning = {'text': '!'} let g:lsp_signs_information = {'text': 'i'} let g:lsp_signs_hint = {'text': '>'} " asyncomplete manages completeopt for vim-lsp mode set completeopt=menuone,noinsert,noselect let g:asyncomplete_auto_popup = 1 let g:asyncomplete_auto_completeopt = 1 let g:asyncomplete_popup_delay = 200 " Tab to navigate completion popup (mirrors CoC behavior) inoremap pumvisible() ? "\" : "\" inoremap pumvisible() ? "\" : "\" inoremap pumvisible() ? asyncomplete#close_popup() : "\" " Key mappings (mirror CoC's gd/gy/gi/gr/K/rn layout) function! s:on_lsp_buffer_enabled() abort setlocal omnifunc=lsp#complete setlocal signcolumn=yes " Navigation nmap gd (lsp-definition) nmap gy (lsp-type-definition) nmap gi (lsp-implementation) nmap gr (lsp-references) nmap [g (lsp-previous-diagnostic) nmap ]g (lsp-next-diagnostic) " Hover documentation nmap K (lsp-hover) " Refactoring nmap rn (lsp-rename) nmap ca (lsp-code-action) nmap f (lsp-document-format) " Workspace nmap ws (lsp-workspace-symbol-search) nmap o (lsp-document-symbol-search) nmap cD (lsp-document-diagnostics) " Enable auto-format on save for filetypes with reliable LSP formatters if index(['python', 'go', 'rust', 'typescript', 'javascript', 'sh'], &filetype) >= 0 autocmd BufWritePre LspDocumentFormatSync endif endfunction augroup lsp_install autocmd! autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled() augroup END endif " ============================================================================ " => Helper Functions " ============================================================================ " Returns true if paste mode is enabled function! HasPaste() if &paste return 'PASTE MODE ' endif return '' endfunction " Don't close window, when deleting a buffer command! Bclose call BufcloseCloseIt() function! BufcloseCloseIt() let l:currentBufNum = bufnr("%") let l:alternateBufNum = bufnr("#") if buflisted(l:alternateBufNum) buffer # else bnext endif if bufnr("%") == l:currentBufNum new endif if buflisted(l:currentBufNum) execute("bdelete! ".l:currentBufNum) endif endfunction " Delete trailing white space on save fun! CleanExtraSpaces() let save_cursor = getpos(".") let old_query = getreg('/') silent! %s/\s\+$//e call setpos('.', save_cursor) call setreg('/', old_query) endfun " Disable auto-insertion of comment leaders when pressing Enter or o/O " Must run at BufEnter because filetype plugins reset formatoptions per buffer augroup ChopstickFormatOptions autocmd! autocmd BufEnter * setlocal formatoptions-=c formatoptions-=r formatoptions-=o augroup END " Auto-disable paste mode when leaving insert mode (prevents broken indentation) augroup ChopstickPaste autocmd! autocmd InsertLeave * set nopaste augroup END augroup ChopstickCleanup autocmd! " Run for real files only; skip special buffers (NERDTree, Startify, terminal, etc.) autocmd BufWritePre * if empty(&buftype) && !empty(expand('')) | call CleanExtraSpaces() | endif augroup END " ============================================================================ " => Auto Commands " ============================================================================ augroup ChopstickFiletype autocmd! " Return to last edit position when opening files autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif " Set specific file types autocmd BufNewFile,BufRead *.json setlocal filetype=json autocmd BufNewFile,BufRead *.md setlocal filetype=markdown autocmd BufNewFile,BufRead *.jsx setlocal filetype=javascript.jsx autocmd BufNewFile,BufRead *.tsx setlocal filetype=typescript.tsx " Python specific settings autocmd FileType python setlocal expandtab shiftwidth=4 tabstop=4 textwidth=88 colorcolumn=+1 " JavaScript / TypeScript specific settings autocmd FileType javascript,typescript setlocal expandtab shiftwidth=2 tabstop=2 textwidth=100 colorcolumn=+1 " Go specific settings (standard: no textwidth limit, but 120 is common) autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4 textwidth=120 colorcolumn=+1 " Rust specific settings autocmd FileType rust setlocal expandtab shiftwidth=4 tabstop=4 textwidth=100 colorcolumn=+1 " HTML/CSS specific settings autocmd FileType html,css setlocal expandtab shiftwidth=2 tabstop=2 " YAML specific settings autocmd FileType yaml setlocal expandtab shiftwidth=2 tabstop=2 " Markdown specific settings (no line-length limit; wrap at window edge) autocmd FileType markdown setlocal wrap linebreak spell textwidth=0 colorcolumn=0 " Shell script settings autocmd FileType sh setlocal expandtab shiftwidth=2 tabstop=2 textwidth=80 colorcolumn=+1 " Makefile settings (must use tabs) autocmd FileType make setlocal noexpandtab shiftwidth=8 tabstop=8 " JSON specific settings autocmd FileType json setlocal expandtab shiftwidth=2 tabstop=2 " Docker specific settings autocmd BufNewFile,BufRead Dockerfile* setlocal filetype=dockerfile autocmd FileType dockerfile setlocal expandtab shiftwidth=2 tabstop=2 augroup END " ============================================================================ " => Status Line " ============================================================================ " Always show the status line set laststatus=2 " Format the status line (if not using airline) " set statusline=\ %{HasPaste()}%F%m%r%h\ %w\ \ CWD:\ %r%{getcwd()}%h\ \ \ Line:\ %l\ \ Column:\ %c " ============================================================================ " => Misc " ============================================================================ " Quickly open a markdown buffer for scribble map m :e ~/buffer.md " Toggle between number and relativenumber function! ToggleNumber() if(&relativenumber == 1) set norelativenumber set number else set relativenumber endif endfunc " ============================================================================ " => Performance Optimization " ============================================================================ " Optimize for large files set synmaxcol=200 set ttyfast " Don't scan included files for completion — makes Ctrl+n/p much faster (vim-sensible) set complete-=i " Reduce updatetime for better user experience set updatetime=300 " Don't pass messages to |ins-completion-menu| set shortmess+=c " Always show the signcolumn (simplified for TTY) if g:is_tty " In TTY, only show signcolumn when there are signs set signcolumn=auto else if has("patch-8.1.1564") set signcolumn=number else set signcolumn=yes endif endif " ============================================================================ " => Project-Specific Settings " ============================================================================ " Load project-specific vimrc if it exists " This allows per-project customization set exrc set secure " Session options: exclude 'options' (stale plugin settings) and 'globals'; " include terminal buffers — compatible with vim-obsession/vim-prosession set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal " ============================================================================ " => Additional Engineering Utilities " ============================================================================ " Quick format entire file nnoremap F gg=G`` " Quick save all buffers nnoremap wa :wa " Easier window resizing nnoremap = :exe "resize " . (winheight(0) * 3/2) nnoremap - :exe "resize " . (winheight(0) * 2/3) nnoremap + :exe "vertical resize " . (winwidth(0) * 3/2) nnoremap _ :exe "vertical resize " . (winwidth(0) * 2/3) " Quick switch between last two files nnoremap " Clear whitespace on empty lines nnoremap W :%s/\s\+$//:let @/='' " Source current file nnoremap so :source % " Edit vimrc quickly nnoremap ev :edit $MYVIMRC " Reload vimrc with confirmation echo nnoremap sv :source $MYVIMRC:echo "vimrc reloaded" " Search and replace word under cursor nnoremap * :%s/\<\>//g " Copy file path to clipboard nnoremap cp :let @+ = expand("%:p"):echo "Copied path: " . expand("%:p") nnoremap cf :let @+ = expand("%:t"):echo "Copied filename: " . expand("%:t") " Create parent directories on save if they don't exist function! s:MkNonExDir(file, buf) if empty(getbufvar(a:buf, '&buftype')) && a:file!~#'\v^\w+\:\/' let dir=fnamemodify(a:file, ':h') if !isdirectory(dir) call mkdir(dir, 'p') endif endif endfunction augroup BWCCreateDir autocmd! " Guard: is empty for special buffers (NERDTree, Startify, etc.) autocmd BufWritePre * if !empty(expand('')) | call s:MkNonExDir(expand(''), +expand('')) | endif augroup END " In-Vim quick reference cheat sheet — ,? opens it, q closes it function! s:CheatSheet() abort let l:name = '__ChopsticksCheatSheet__' let l:winnr = bufwinnr(l:name) if l:winnr > 0 execute l:winnr . 'wincmd w' return endif execute 'botright new ' . l:name setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile call setline(1, [ \ '=== chopsticks — Quick Reference ===', \ '', \ 'MODES (Vim is modal — the most important concept)', \ ' Normal Default state. Navigate and run commands.', \ ' Insert Type text. Enter: i/a/o Leave: Esc or jk', \ ' Visual Select text. Enter: v/V Leave: Esc', \ '', \ 'SURVIVAL (learn these 4 first)', \ ' Esc / jk Exit insert or visual mode — back to Normal', \ ' :q! + Enter Quit without saving (emergency exit)', \ ' ,x Save and quit', \ ' ,w Save file | Ctrl+s Save (normal + insert)', \ '', \ 'NAVIGATION', \ ' h j k l Left / Down / Up / Right', \ ' Ctrl+p Fuzzy find file | Ctrl+n File tree', \ ' Ctrl+o/i Jump back / forward in history', \ ' ,, Switch to last file', \ '', \ 'SEARCH', \ ' /text Search forward | n next | N prev', \ ' // Search for visually selected text', \ ' ,rg Search project contents (ripgrep)', \ ' ,rG Ripgrep word under cursor', \ ' ,* Replace word under cursor (file-wide)', \ '', \ 'CODE INTELLIGENCE', \ ' gd Go to definition', \ ' K Hover documentation', \ ' [g / ]g Prev / next diagnostic (LSP)', \ ' [e / ]e Prev / next ALE error', \ ' ,ca Code action / auto-fix', \ ' ,rn Rename symbol', \ ' ,f Format selection | ,F Format whole file', \ '', \ 'EDITING', \ ' i / a / o Insert before / after / on new line', \ ' gc Toggle comment (works in visual too)', \ ' u / Ctrl+r Undo / Redo', \ ' ,p / ,P Paste from system clipboard', \ ' ,y / ,Y Yank / line-yank to system clipboard', \ ' s + 2 chars EasyMotion jump anywhere on screen', \ '', \ 'GIT', \ ' ,gs Git status | ,gd Diff | ,gb Blame', \ ' ,gc Commit | ,gp Push | ,gl Pull', \ '', \ 'WINDOWS / PANES', \ ' Ctrl+h/j/k/l Move between Vim windows or tmux panes', \ ' ,h / ,l Prev / next buffer', \ ' ,tv / ,th Open terminal (vertical / horizontal)', \ '', \ 'TOOLS', \ ' ,u Undo tree (visual history)', \ ' ,tt Tagbar (code structure)', \ ' ,o File outline (LSP symbols)', \ '', \ 'TIP: When confused, press Esc. Then press , and wait 500ms', \ ' for an interactive guide to ALL keybindings.', \ ' Re-open this sheet with ,?', \ '', \ '(press q to close)', \ ]) setlocal nomodifiable readonly nnoremap q :bd endfunction nnoremap ? :call CheatSheet() " ============================================================================ " => Debugging Helpers " ============================================================================ " Show syntax highlighting groups for word under cursor nmap sh :call SynStack() function! SynStack() if !exists("*synstack") return endif echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")') endfunc " ============================================================================ " => Git Workflow Enhancements " ============================================================================ " Git shortcuts nnoremap gs :Git status nnoremap gc :Git commit nnoremap gp :Git push nnoremap gl :Git pull nnoremap gd :Gdiff nnoremap gb :Git blame " ============================================================================ " => Terminal Integration " ============================================================================ " Better terminal navigation if has('terminal') " Open terminal in split nnoremap tv :terminal nnoremap th :terminal ++rows=10 " Terminal mode mappings " Double-Esc to exit terminal mode (single Esc passes through to the running program) tnoremap tnoremap h tnoremap j tnoremap k tnoremap l endif " ============================================================================ " => Large File Handling " ============================================================================ " Disable syntax highlighting and other features for large files (>10MB) let g:LargeFile = 1024 * 1024 * 10 augroup LargeFile autocmd! " Guard: is empty for special buffers autocmd BufReadPre * if !empty(expand('')) | let f=getfsize(expand('')) | if f > g:LargeFile || f == -2 | call LargeFileSettings() | endif | endif augroup END function! LargeFileSettings() setlocal bufhidden=unload setlocal undolevels=-1 setlocal eventignore+=FileType setlocal noswapfile setlocal syntax=OFF let b:ale_enabled = 0 echo "Large file (>10MB): syntax, undo, and linting disabled for performance." endfunction " ============================================================================ " => TTY and Basic Terminal Optimizations " ============================================================================ " Additional optimizations for TTY/basic terminals if g:is_tty " Disable syntax highlighting for very large files in TTY augroup ChopstickTTYLargeFile autocmd! autocmd BufReadPre * if !empty(expand('')) && getfsize(expand('')) > 512000 | setlocal syntax=OFF | endif augroup END " Simpler status line for TTY set statusline=%f\ %h%w%m%r\ %=%(%l,%c%V\ %=\ %P%) " Reduce syntax highlighting complexity in TTY (global is 200, lower here) set synmaxcol=120 " lazyredraw is safe in TTY; avoid globally as it causes CoC float flicker set lazyredraw endif " Provide helpful message on first run in TTY if g:is_tty && !exists("g:tty_message_shown") augroup TTYMessage autocmd! autocmd VimEnter * echom "Running in TTY mode - some features disabled for performance" augroup END let g:tty_message_shown = 1 endif " ============================================================================ " => Which-Key: Keybinding Hints " ============================================================================ " Show available bindings after with a 500ms pause set timeoutlen=500 if exists('g:plugs["vim-which-key"]') " Register after plugins are loaded (autoload functions available at VimEnter) augroup ChopstickWhichKey autocmd! autocmd VimEnter * call which_key#register(',', 'g:which_key_map') augroup END nnoremap :WhichKey ',' vnoremap :WhichKeyVisual ',' " Top-level single-key bindings (w and q also have sub-groups below) let g:which_key_map = {} let g:which_key_map['x'] = 'save-and-quit' let g:which_key_map['F'] = 'format-file' let g:which_key_map['W'] = 'strip-trailing-whitespace' let g:which_key_map['m'] = 'scratch-markdown' let g:which_key_map['n'] = 'nerdtree-find' let g:which_key_map['o'] = 'outline' let g:which_key_map['b'] = 'buffers' let g:which_key_map['h'] = 'prev-buffer' let g:which_key_map['l'] = 'next-buffer' let g:which_key_map['*'] = 'search-replace-word' let g:which_key_map[','] = 'last-file' let g:which_key_map['y'] = 'clipboard-yank' let g:which_key_map['Y'] = 'clipboard-yank-line' let g:which_key_map['p'] = 'clipboard-paste-after' let g:which_key_map['P'] = 'clipboard-paste-before' let g:which_key_map['u'] = 'undotree-toggle' let g:which_key_map['?'] = 'cheat-sheet' " [a]LE lint group ([e/]e navigate; aD for detail; ad for diagnostics) let g:which_key_map['a'] = { \ 'name': '+ale-lint', \ 'D': 'ale-detail', \ 'd': 'diagnostics', \ } " [c]ode / [c]opy group let g:which_key_map['c'] = { \ 'name': '+code/copy', \ 'a': 'code-action-cursor', \ 'A': 'code-action-source', \ 'c': 'coc-commands', \ 'D': 'diagnostics-list', \ 'l': 'code-lens', \ 'r': 'coc-list-resume', \ 'p': 'copy-filepath', \ 'f': 'copy-filename', \ } " [e]dit / [e]xplore group let g:which_key_map['e'] = { \ 'name': '+edit/explore', \ 'v': 'edit-vimrc', \ } " [g]it group let g:which_key_map['g'] = { \ 'name': '+git', \ 's': 'status', \ 'c': 'commit', \ 'p': 'push', \ 'l': 'pull', \ 'd': 'diff', \ 'b': 'blame', \ 'F': 'git-files-fzf', \ } " [q]uickfix group (also: q = fast quit) let g:which_key_map['q'] = { \ 'name': '+quickfix', \ 'f': 'lsp-fix-current', \ 'o': 'open-quickfix', \ 'c': 'close-quickfix', \ } " [r]efactor / [r]ipgrep / [r]eplace group let g:which_key_map['r'] = { \ 'name': '+search/refactor', \ 'n': 'rename', \ 'g': 'ripgrep', \ 'G': 'ripgrep-word-under-cursor', \ 't': 'tags-search', \ } " [s]pell / [s]ource group let g:which_key_map['s'] = { \ 'name': '+spell/source', \ 's': 'toggle-spell', \ 'n': 'next-spell', \ 'p': 'prev-spell', \ 'a': 'add-word', \ '?': 'suggest', \ 'v': 'source-vimrc', \ 'o': 'source-file', \ 'h': 'syntax-highlight-stack', \ } " [t]ab / [t]erminal group let g:which_key_map['t'] = { \ 'name': '+tab/terminal/tagbar', \ 'n': 'new-tab', \ 'o': 'tab-only', \ 'c': 'close-tab', \ 'm': 'move-tab', \ 'l': 'last-tab', \ 'e': 'edit-in-tab', \ 'v': 'terminal-vertical', \ 'h': 'terminal-horizontal', \ 't': 'tagbar-toggle', \ } " [w]orkspace / [w]indow / save group (also: w = fast save) let g:which_key_map['w'] = { \ 'name': '+save/window', \ 'a': 'save-all', \ 's': 'workspace-symbols', \ } " [c]hange-dir (standalone — cd changes window-local CWD) let g:which_key_map['cd'] = 'change-local-dir' endif " ============================================================================ " => Startify: Startup Screen " ============================================================================ if exists('g:plugs["vim-startify"]') " Plain ASCII header — no Unicode, no system() calls, instant render let g:startify_custom_header = [ \ ' __ __ ___ ___ __ __ ____ ____ __ _ __ __ __ ', \ ' / \/ \/ _ \/ _ \ / \/ \/ ___)/ ___)/__\ / |/ \/ \/ \ ', \ ' ) )( ( ) (_) )(_) ) )( ( \___ \\__ ( _/ ) |( _)( __/ /\ \ ', \ ' /_/ \__/ \___/\___//_/ \__/ (____/(____/\___)_/ \_/\_/ \_/ \/ \/', \ '', \ ] " Sessions first, then recent files — mirrors dashboard plugin ordering let g:startify_lists = [ \ { 'type': 'sessions', 'header': [' Sessions'] }, \ { 'type': 'files', 'header': [' Recent Files'] }, \ { 'type': 'dir', 'header': [' Current Dir'] }, \ { 'type': 'bookmarks', 'header': [' Bookmarks'] }, \ ] " Quick-access bookmarks for common config files let g:startify_bookmarks = [ \ {'v': '~/.vimrc'}, \ {'z': '~/.zshrc'}, \ {'b': '~/.bashrc'}, \ ] " Session integration let g:startify_session_persistence = 1 " Auto-save session on quit let g:startify_session_autoload = 1 " Auto-load Session.vim if present let g:startify_change_to_vcs_root = 1 " cd to git root on open let g:startify_fortune_use_unicode = 0 " ASCII only (KISS) let g:startify_enable_special = 0 " Hide / clutter " Show more recent files let g:startify_files_number = 8 " Left padding for list items (gives visual breathing room) let g:startify_padding_left = 4 " Required for NERDTree compatibility (prevents buftype conflicts) augroup ChopstickStartify autocmd! autocmd User Startified setlocal buftype= augroup END endif " ============================================================================ " => IndentLine: Indent Guide Lines (non-TTY only) " ============================================================================ if !g:is_tty && exists('g:plugs["indentLine"]') " Use simple ASCII bar as indent guide let g:indentLine_char = '|' let g:indentLine_first_char = '|' let g:indentLine_showFirstIndentLevel = 1 " Disable in certain filetypes where it causes issues let g:indentLine_fileTypeExclude = ['text', 'help', 'startify', 'nerdtree', 'markdown'] let g:indentLine_bufTypeExclude = ['help', 'terminal', 'nofile'] " Conceal level settings (prevent hiding quotes in JSON/markdown) let g:indentLine_setConceal = 2 let g:indentLine_concealcursor = '' endif " ============================================================================ " End of Configuration " ============================================================================