mirror of
https://oauth2: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@github.com/m1ngsama/chopsticks.git
synced 2026-06-26 12:14:38 +08:00
Compare commits
4 commits
9442aa0499
...
825633d623
| Author | SHA1 | Date | |
|---|---|---|---|
| 825633d623 | |||
| e3877edaeb | |||
| 74071f7464 | |||
| 23ad2e5b7a |
6 changed files with 1207 additions and 425 deletions
234
.vimrc
234
.vimrc
|
|
@ -73,9 +73,15 @@ set wildmenu
|
||||||
" Make wildmenu behave like similar to Bash completion
|
" Make wildmenu behave like similar to Bash completion
|
||||||
set wildmode=list:longest
|
set wildmode=list:longest
|
||||||
|
|
||||||
" There are certain files that we would never want to edit with Vim
|
" Case-insensitive filename completion in wildmenu (spf13, YADR)
|
||||||
" Wildmenu will ignore files with these extensions
|
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=*.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
|
" Enable mouse support
|
||||||
set mouse=a
|
set mouse=a
|
||||||
|
|
@ -119,6 +125,11 @@ set novisualbell
|
||||||
set t_vb=
|
set t_vb=
|
||||||
set tm=500
|
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
|
" Enable 256 colors palette in Gnome Terminal
|
||||||
if $COLORTERM == 'gnome-terminal'
|
if $COLORTERM == 'gnome-terminal'
|
||||||
set t_Co=256
|
set t_Co=256
|
||||||
|
|
@ -132,6 +143,9 @@ if has("gui_running")
|
||||||
set guitablabel=%M\ %t
|
set guitablabel=%M\ %t
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Show last line partially instead of replacing it with @@@ (vim-sensible)
|
||||||
|
set display+=lastline
|
||||||
|
|
||||||
" Use Unix as the standard file type
|
" Use Unix as the standard file type
|
||||||
set ffs=unix,dos,mac
|
set ffs=unix,dos,mac
|
||||||
|
|
||||||
|
|
@ -207,6 +221,7 @@ Plug 'dhruvasagar/vim-prosession' " Better session management
|
||||||
Plug 'tpope/vim-unimpaired' " Handy bracket mappings
|
Plug 'tpope/vim-unimpaired' " Handy bracket mappings
|
||||||
Plug 'wellle/targets.vim' " Additional text objects
|
Plug 'wellle/targets.vim' " Additional text objects
|
||||||
Plug 'honza/vim-snippets' " Snippet collection
|
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) =====
|
" ===== Native LSP (vim-lsp: works without Node.js, Vim 8.0+ only) =====
|
||||||
" Used as fallback when CoC/Node.js is unavailable
|
" Used as fallback when CoC/Node.js is unavailable
|
||||||
|
|
@ -287,6 +302,14 @@ endif
|
||||||
" => Text, Tab and Indent Related
|
" => Text, Tab and Indent Related
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
||||||
|
" Visible whitespace characters (toggled with <F6>)
|
||||||
|
" 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
|
" Use spaces instead of tabs
|
||||||
set expandtab
|
set expandtab
|
||||||
|
|
||||||
|
|
@ -323,11 +346,8 @@ nmap <leader>x :x<cr>
|
||||||
" Disable highlight when <leader><cr> is pressed
|
" Disable highlight when <leader><cr> is pressed
|
||||||
map <silent> <leader><cr> :noh<cr>
|
map <silent> <leader><cr> :noh<cr>
|
||||||
|
|
||||||
" Smart way to move between windows
|
" Window navigation — owned by vim-tmux-navigator plugin (Ctrl+h/j/k/l works
|
||||||
map <C-j> <C-W>j
|
" seamlessly across Vim splits and tmux panes; no manual maps needed here)
|
||||||
map <C-k> <C-W>k
|
|
||||||
map <C-h> <C-W>h
|
|
||||||
map <C-l> <C-W>l
|
|
||||||
|
|
||||||
" Close the current buffer (Bclose preserves window layout)
|
" Close the current buffer (Bclose preserves window layout)
|
||||||
map <leader>bd :Bclose<cr>
|
map <leader>bd :Bclose<cr>
|
||||||
|
|
@ -359,17 +379,30 @@ augroup END
|
||||||
" Opens a new tab with the current buffer's path
|
" Opens a new tab with the current buffer's path
|
||||||
map <leader>te :tabedit <C-r>=expand("%:p:h")<cr>/
|
map <leader>te :tabedit <C-r>=expand("%:p:h")<cr>/
|
||||||
|
|
||||||
" Switch CWD to the directory of the open buffer
|
" Change window-local CWD to current file's directory (lcd = local, safer than cd)
|
||||||
map <leader>wd :cd %:p:h<cr>:pwd<cr>
|
map <leader>cd :lcd %:p:h<cr>:pwd<cr>
|
||||||
|
|
||||||
|
" Open built-in file browser (works on any Vim, no plugins needed — tpope)
|
||||||
|
nnoremap <leader>e :Explore<CR>
|
||||||
|
|
||||||
" Remap VIM 0 to first non-blank character
|
" Remap VIM 0 to first non-blank character
|
||||||
map 0 ^
|
map 0 ^
|
||||||
|
|
||||||
" Move a line of text using ALT+[jk] or Command+[jk] on mac
|
" 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 <C-p> <Up>
|
||||||
|
cnoremap <C-n> <Down>
|
||||||
|
|
||||||
|
" Move a line of text using ALT+[jk] (normal mode)
|
||||||
nmap <M-j> mz:m+<cr>`z
|
nmap <M-j> mz:m+<cr>`z
|
||||||
nmap <M-k> mz:m-2<cr>`z
|
nmap <M-k> mz:m-2<cr>`z
|
||||||
vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
|
|
||||||
vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`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 '>+1<CR>gv=gv
|
||||||
|
vnoremap K :m '<-2<CR>gv=gv
|
||||||
|
|
||||||
" Pressing ,ss will toggle and untoggle spell checking
|
" Pressing ,ss will toggle and untoggle spell checking
|
||||||
map <leader>ss :setlocal spell!<cr>
|
map <leader>ss :setlocal spell!<cr>
|
||||||
|
|
@ -389,6 +422,9 @@ nnoremap <F3> :set invnumber<CR>
|
||||||
" Toggle relative line numbers
|
" Toggle relative line numbers
|
||||||
nnoremap <F4> :set invrelativenumber<CR>
|
nnoremap <F4> :set invrelativenumber<CR>
|
||||||
|
|
||||||
|
" Toggle visible whitespace (tabs, trailing spaces, non-breaking spaces)
|
||||||
|
nnoremap <F6> :set list!<CR>
|
||||||
|
|
||||||
" Enable folding with the spacebar
|
" Enable folding with the spacebar
|
||||||
nnoremap <space> za
|
nnoremap <space> za
|
||||||
|
|
||||||
|
|
@ -398,6 +434,9 @@ nnoremap Y y$
|
||||||
" Disable accidental Ex mode
|
" Disable accidental Ex mode
|
||||||
nnoremap Q <nop>
|
nnoremap Q <nop>
|
||||||
|
|
||||||
|
" Exit insert mode without reaching for Escape (community standard)
|
||||||
|
inoremap jk <Esc>
|
||||||
|
|
||||||
" Keep visual selection after indent
|
" Keep visual selection after indent
|
||||||
vnoremap < <gv
|
vnoremap < <gv
|
||||||
vnoremap > >gv
|
vnoremap > >gv
|
||||||
|
|
@ -406,15 +445,25 @@ vnoremap > >gv
|
||||||
nnoremap n nzzzv
|
nnoremap n nzzzv
|
||||||
nnoremap N Nzzzv
|
nnoremap N Nzzzv
|
||||||
|
|
||||||
|
" Search for visually selected text with // (hit // in visual mode)
|
||||||
|
vnoremap // y/\V<C-r>=escape(@",'/\')<CR><CR>
|
||||||
|
|
||||||
|
" <C-s> to save in normal and insert mode
|
||||||
|
" (for terminals: add 'stty -ixon' to your shell rc to disable XON/XOFF)
|
||||||
|
nnoremap <silent> <C-s> :w<CR>
|
||||||
|
inoremap <silent> <C-s> <Esc>:w<CR>a
|
||||||
|
|
||||||
" Center cursor after half-page scroll
|
" Center cursor after half-page scroll
|
||||||
nnoremap <C-d> <C-d>zz
|
nnoremap <C-d> <C-d>zz
|
||||||
nnoremap <C-u> <C-u>zz
|
nnoremap <C-u> <C-u>zz
|
||||||
|
|
||||||
" System clipboard yank (conditional: requires clipboard provider)
|
" System clipboard yank/paste (conditional: requires clipboard provider)
|
||||||
if has('clipboard')
|
if has('clipboard')
|
||||||
nnoremap <leader>y "+y
|
nnoremap <leader>y "+y
|
||||||
vnoremap <leader>y "+y
|
vnoremap <leader>y "+y
|
||||||
nnoremap <leader>Y "+Y
|
nnoremap <leader>Y "+Y
|
||||||
|
nnoremap <leader>p "+p
|
||||||
|
nnoremap <leader>P "+P
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Quickfix list shortcuts ([q/]q from vim-unimpaired handles navigation)
|
" Quickfix list shortcuts ([q/]q from vim-unimpaired handles navigation)
|
||||||
|
|
@ -485,6 +534,7 @@ endfunction
|
||||||
map <C-p> :call <SID>SmartFiles()<CR>
|
map <C-p> :call <SID>SmartFiles()<CR>
|
||||||
map <leader>b :Buffers<CR>
|
map <leader>b :Buffers<CR>
|
||||||
map <leader>rg :Rg<CR>
|
map <leader>rg :Rg<CR>
|
||||||
|
map <leader>rG :Rg -F <C-r><C-w><CR>
|
||||||
map <leader>rt :Tags<CR>
|
map <leader>rt :Tags<CR>
|
||||||
map <leader>gF :GFiles<CR>
|
map <leader>gF :GFiles<CR>
|
||||||
|
|
||||||
|
|
@ -583,9 +633,9 @@ let g:ale_fixers = {
|
||||||
let g:ale_fix_on_save = !g:use_vimlsp
|
let g:ale_fix_on_save = !g:use_vimlsp
|
||||||
let g:ale_sign_error = 'X'
|
let g:ale_sign_error = 'X'
|
||||||
let g:ale_sign_warning = '!'
|
let g:ale_sign_warning = '!'
|
||||||
let g:ale_lint_on_text_changed = 'never'
|
let g:ale_lint_on_text_changed = 'normal'
|
||||||
let g:ale_lint_on_insert_leave = 0
|
let g:ale_lint_on_insert_leave = 1
|
||||||
let g:ale_lint_on_enter = 0
|
let g:ale_lint_on_enter = 1
|
||||||
|
|
||||||
" --- vim-go: disable built-in LSP/gopls — CoC (coc-go) handles all Go intelligence ---
|
" --- 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
|
" vim-go's gopls conflicts with coc-go and causes E495 errors on startup
|
||||||
|
|
@ -602,16 +652,18 @@ let g:go_highlight_fields = 1
|
||||||
let g:go_highlight_functions = 1
|
let g:go_highlight_functions = 1
|
||||||
let g:go_highlight_function_calls = 1
|
let g:go_highlight_function_calls = 1
|
||||||
|
|
||||||
" Navigate between errors: [e/]e (unimpaired style), <leader>aD for detail
|
" Navigate between errors: [e/]e (unimpaired convention: [ = prev, ] = next)
|
||||||
nmap <silent> [e :ALENext<cr>
|
nmap <silent> [e :ALEPrevious<cr>
|
||||||
nmap <silent> ]e :ALEPrevious<cr>
|
nmap <silent> ]e :ALENext<cr>
|
||||||
nmap <silent> <leader>aD :ALEDetail<cr>
|
nmap <silent> <leader>aD :ALEDetail<cr>
|
||||||
|
|
||||||
" --- Tagbar ---
|
" --- Tagbar ---
|
||||||
nmap <F8> :TagbarToggle<CR>
|
nmap <F8> :TagbarToggle<CR>
|
||||||
|
nmap <leader>tt :TagbarToggle<CR>
|
||||||
|
|
||||||
" --- UndoTree ---
|
" --- UndoTree ---
|
||||||
nnoremap <F5> :UndotreeToggle<CR>
|
nnoremap <F5> :UndotreeToggle<CR>
|
||||||
|
nnoremap <leader>u :UndotreeToggle<CR>
|
||||||
|
|
||||||
" --- EasyMotion ---
|
" --- EasyMotion ---
|
||||||
let g:EasyMotion_do_mapping = 0 " Disable default mappings
|
let g:EasyMotion_do_mapping = 0 " Disable default mappings
|
||||||
|
|
@ -849,6 +901,19 @@ fun! CleanExtraSpaces()
|
||||||
call setreg('/', old_query)
|
call setreg('/', old_query)
|
||||||
endfun
|
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
|
augroup ChopstickCleanup
|
||||||
autocmd!
|
autocmd!
|
||||||
" Run for real files only; skip special buffers (NERDTree, Startify, terminal, etc.)
|
" Run for real files only; skip special buffers (NERDTree, Startify, terminal, etc.)
|
||||||
|
|
@ -871,13 +936,16 @@ augroup ChopstickFiletype
|
||||||
autocmd BufNewFile,BufRead *.tsx setlocal filetype=typescript.tsx
|
autocmd BufNewFile,BufRead *.tsx setlocal filetype=typescript.tsx
|
||||||
|
|
||||||
" Python specific settings
|
" Python specific settings
|
||||||
autocmd FileType python setlocal expandtab shiftwidth=4 tabstop=4 colorcolumn=88
|
autocmd FileType python setlocal expandtab shiftwidth=4 tabstop=4 textwidth=88 colorcolumn=+1
|
||||||
|
|
||||||
" JavaScript specific settings
|
" JavaScript / TypeScript specific settings
|
||||||
autocmd FileType javascript,typescript setlocal expandtab shiftwidth=2 tabstop=2
|
autocmd FileType javascript,typescript setlocal expandtab shiftwidth=2 tabstop=2 textwidth=100 colorcolumn=+1
|
||||||
|
|
||||||
" Go specific settings
|
" Go specific settings (standard: no textwidth limit, but 120 is common)
|
||||||
autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4
|
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
|
" HTML/CSS specific settings
|
||||||
autocmd FileType html,css setlocal expandtab shiftwidth=2 tabstop=2
|
autocmd FileType html,css setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
|
@ -885,11 +953,11 @@ augroup ChopstickFiletype
|
||||||
" YAML specific settings
|
" YAML specific settings
|
||||||
autocmd FileType yaml setlocal expandtab shiftwidth=2 tabstop=2
|
autocmd FileType yaml setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
|
||||||
" Markdown specific settings
|
" Markdown specific settings (no line-length limit; wrap at window edge)
|
||||||
autocmd FileType markdown setlocal wrap linebreak spell tw=0
|
autocmd FileType markdown setlocal wrap linebreak spell textwidth=0 colorcolumn=0
|
||||||
|
|
||||||
" Shell script settings
|
" Shell script settings
|
||||||
autocmd FileType sh setlocal expandtab shiftwidth=2 tabstop=2
|
autocmd FileType sh setlocal expandtab shiftwidth=2 tabstop=2 textwidth=80 colorcolumn=+1
|
||||||
|
|
||||||
" Makefile settings (must use tabs)
|
" Makefile settings (must use tabs)
|
||||||
autocmd FileType make setlocal noexpandtab shiftwidth=8 tabstop=8
|
autocmd FileType make setlocal noexpandtab shiftwidth=8 tabstop=8
|
||||||
|
|
@ -929,9 +997,6 @@ function! ToggleNumber()
|
||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Toggle paste mode
|
|
||||||
map <leader>pp :setlocal paste!<cr>
|
|
||||||
|
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
" => Performance Optimization
|
" => Performance Optimization
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
@ -940,6 +1005,9 @@ map <leader>pp :setlocal paste!<cr>
|
||||||
set synmaxcol=200
|
set synmaxcol=200
|
||||||
set ttyfast
|
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
|
" Reduce updatetime for better user experience
|
||||||
set updatetime=300
|
set updatetime=300
|
||||||
|
|
||||||
|
|
@ -967,6 +1035,10 @@ endif
|
||||||
set exrc
|
set exrc
|
||||||
set secure
|
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
|
" => Additional Engineering Utilities
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
@ -995,8 +1067,8 @@ nnoremap <leader>so :source %<CR>
|
||||||
" Edit vimrc quickly
|
" Edit vimrc quickly
|
||||||
nnoremap <leader>ev :edit $MYVIMRC<CR>
|
nnoremap <leader>ev :edit $MYVIMRC<CR>
|
||||||
|
|
||||||
" Reload vimrc
|
" Reload vimrc with confirmation echo
|
||||||
nnoremap <leader>sv :source $MYVIMRC<CR>
|
nnoremap <leader>sv :source $MYVIMRC<CR>:echo "vimrc reloaded"<CR>
|
||||||
|
|
||||||
" Search and replace word under cursor
|
" Search and replace word under cursor
|
||||||
nnoremap <leader>* :%s/\<<C-r><C-w>\>//g<Left><Left>
|
nnoremap <leader>* :%s/\<<C-r><C-w>\>//g<Left><Left>
|
||||||
|
|
@ -1020,6 +1092,85 @@ augroup BWCCreateDir
|
||||||
autocmd BufWritePre * if !empty(expand('<afile>')) | call s:MkNonExDir(expand('<afile>'), +expand('<abuf>')) | endif
|
autocmd BufWritePre * if !empty(expand('<afile>')) | call s:MkNonExDir(expand('<afile>'), +expand('<abuf>')) | endif
|
||||||
augroup END
|
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 <buffer> <silent> q :bd<CR>
|
||||||
|
endfunction
|
||||||
|
nnoremap <silent> <leader>? :call <SID>CheatSheet()<CR>
|
||||||
|
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
" => Debugging Helpers
|
" => Debugging Helpers
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
@ -1082,7 +1233,8 @@ function! LargeFileSettings()
|
||||||
setlocal eventignore+=FileType
|
setlocal eventignore+=FileType
|
||||||
setlocal noswapfile
|
setlocal noswapfile
|
||||||
setlocal syntax=OFF
|
setlocal syntax=OFF
|
||||||
echo "Large file (>10MB): syntax and undo disabled for performance."
|
let b:ale_enabled = 0
|
||||||
|
echo "Large file (>10MB): syntax, undo, and linting disabled for performance."
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
@ -1148,6 +1300,10 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
let g:which_key_map[','] = 'last-file'
|
let g:which_key_map[','] = 'last-file'
|
||||||
let g:which_key_map['y'] = 'clipboard-yank'
|
let g:which_key_map['y'] = 'clipboard-yank'
|
||||||
let g:which_key_map['Y'] = 'clipboard-yank-line'
|
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; <leader>aD for detail; <leader>ad for diagnostics)
|
" [a]LE lint group ([e/]e navigate; <leader>aD for detail; <leader>ad for diagnostics)
|
||||||
let g:which_key_map['a'] = {
|
let g:which_key_map['a'] = {
|
||||||
|
|
@ -1169,9 +1325,9 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
\ 'f': 'copy-filename',
|
\ 'f': 'copy-filename',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
" [e]dit group
|
" [e]dit / [e]xplore group
|
||||||
let g:which_key_map['e'] = {
|
let g:which_key_map['e'] = {
|
||||||
\ 'name': '+edit',
|
\ 'name': '+edit/explore',
|
||||||
\ 'v': 'edit-vimrc',
|
\ 'v': 'edit-vimrc',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
|
|
@ -1200,6 +1356,7 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
\ 'name': '+search/refactor',
|
\ 'name': '+search/refactor',
|
||||||
\ 'n': 'rename',
|
\ 'n': 'rename',
|
||||||
\ 'g': 'ripgrep',
|
\ 'g': 'ripgrep',
|
||||||
|
\ 'G': 'ripgrep-word-under-cursor',
|
||||||
\ 't': 'tags-search',
|
\ 't': 'tags-search',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
|
|
@ -1218,7 +1375,7 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
|
|
||||||
" [t]ab / [t]erminal group
|
" [t]ab / [t]erminal group
|
||||||
let g:which_key_map['t'] = {
|
let g:which_key_map['t'] = {
|
||||||
\ 'name': '+tab/terminal',
|
\ 'name': '+tab/terminal/tagbar',
|
||||||
\ 'n': 'new-tab',
|
\ 'n': 'new-tab',
|
||||||
\ 'o': 'tab-only',
|
\ 'o': 'tab-only',
|
||||||
\ 'c': 'close-tab',
|
\ 'c': 'close-tab',
|
||||||
|
|
@ -1227,6 +1384,7 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
\ 'e': 'edit-in-tab',
|
\ 'e': 'edit-in-tab',
|
||||||
\ 'v': 'terminal-vertical',
|
\ 'v': 'terminal-vertical',
|
||||||
\ 'h': 'terminal-horizontal',
|
\ 'h': 'terminal-horizontal',
|
||||||
|
\ 't': 'tagbar-toggle',
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
" [w]orkspace / [w]indow / save group (also: <leader>w = fast save)
|
" [w]orkspace / [w]indow / save group (also: <leader>w = fast save)
|
||||||
|
|
@ -1234,8 +1392,10 @@ if exists('g:plugs["vim-which-key"]')
|
||||||
\ 'name': '+save/window',
|
\ 'name': '+save/window',
|
||||||
\ 'a': 'save-all',
|
\ 'a': 'save-all',
|
||||||
\ 's': 'workspace-symbols',
|
\ 's': 'workspace-symbols',
|
||||||
\ 'd': 'change-dir',
|
|
||||||
\ }
|
\ }
|
||||||
|
|
||||||
|
" [c]hange-dir (standalone — <leader>cd changes window-local CWD)
|
||||||
|
let g:which_key_map['cd'] = 'change-local-dir'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" ============================================================================
|
" ============================================================================
|
||||||
|
|
|
||||||
88
CHANGELOG.md
88
CHANGELOG.md
|
|
@ -4,6 +4,94 @@ All notable changes to chopsticks are documented here.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [1.1.1] - 2026-04-09
|
||||||
|
|
||||||
|
Systematic absorption of best practices from amix/vimrc, tpope/vim-sensible,
|
||||||
|
ThePrimeagen, skwp/YADR, and spf13-vim — settings and mappings that appear
|
||||||
|
consistently across all top global configs but were missing here.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **`set ttimeoutlen=10`** — eliminates the ~500ms ESC lag in terminal Vim; separates
|
||||||
|
keycode timeout from leader-key timeout (`timeoutlen` unchanged at 500ms)
|
||||||
|
- **`set display+=lastline`** — shows truncated long lines instead of replacing them with `@@@`
|
||||||
|
- **`set complete-=i`** — `Ctrl+n/p` no longer scans all included files; completion is instant
|
||||||
|
- **`set wildignorecase`** — case-insensitive filename completion in wildmenu and `:find`
|
||||||
|
- **`set path+=**`** — recursive `:find` across the project; wildignore excludes
|
||||||
|
`node_modules`, `__pycache__`, `dist`, `build`, `.git`
|
||||||
|
- **`set sessionoptions`** — removes `options` from saved sessions (prevents stale plugin
|
||||||
|
settings from contaminating restored sessions)
|
||||||
|
- **`set listchars`** — defines visible whitespace characters; TTY uses ASCII symbols,
|
||||||
|
modern terminals use Unicode (tab `→`, trail `·`, extends `▸`)
|
||||||
|
- **`F6`** — toggle visible whitespace on/off
|
||||||
|
- **`formatoptions-=cro`** on `BufEnter` — disables automatic comment-leader insertion
|
||||||
|
when pressing Enter or `o/O`; runs on BufEnter to override filetype plugins
|
||||||
|
- **`InsertLeave * set nopaste`** — auto-disables paste mode on leaving insert, preventing
|
||||||
|
permanently broken auto-indent
|
||||||
|
- **`colorcolumn=+1`** for all languages via `textwidth`:
|
||||||
|
Python 88, Go 120, JS/TS 100, Rust 100, Shell 80 (Markdown disabled)
|
||||||
|
- **`vnoremap J/K`** with `gv=gv` — move selected lines down/up and re-indent (ThePrimeagen)
|
||||||
|
- **`gV`** — re-select last pasted text (`\`[v\`]` — spf13, YADR)
|
||||||
|
- **`cnoremap <C-p>/<C-n>`** — navigate command-line history matching typed prefix (amix, spf13)
|
||||||
|
- **`<leader>e :Explore`** — open built-in Netrw file browser; works on any Vim without plugins
|
||||||
|
- **`<leader>cd`** — change window-local CWD to current file's directory (was `<leader>wd`)
|
||||||
|
- **`<leader>sv`** — reloads vimrc and echoes confirmation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `<leader>wd` renamed to `<leader>cd`; now uses `lcd` (window-local) instead of `cd` (global)
|
||||||
|
- `wildignore` expanded with `*/node_modules/*`, `*/__pycache__/*`, `*/dist/*`, `*/build/*`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.1.0] - 2026-04-09
|
||||||
|
|
||||||
|
Ergonomics and automation overhaul: community-standard keybindings, seamless
|
||||||
|
tmux integration, an in-Vim cheat sheet, a beginner onboarding section, and
|
||||||
|
several correctness fixes from a systematic review.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **`jk` → `Esc`** in insert mode — ergonomic escape without reaching for the key
|
||||||
|
- **`Ctrl+s` save** in normal and insert mode (add `stty -ixon` to shell rc to enable
|
||||||
|
in terminals that use XON/XOFF flow control)
|
||||||
|
- **`//` visual search** — search for visually selected text using `\V` very-nomagic escaping
|
||||||
|
- **`<leader>p` / `<leader>P`** — paste from system clipboard after/before cursor
|
||||||
|
- **`<leader>rG`** — ripgrep word under cursor with `-F` (literal, not regex)
|
||||||
|
- **`<leader>u`** — leader-key alias for UndoTree (complements `F5`)
|
||||||
|
- **`<leader>tt`** — leader-key alias for Tagbar (complements `F8`)
|
||||||
|
- **`,?` in-Vim cheat sheet** — opens a read-only buffer covering modes, survival
|
||||||
|
commands, search, code intelligence, git, and clipboard; press `q` to close
|
||||||
|
- **vim-tmux-navigator** plugin — `Ctrl+h/j/k/l` navigates seamlessly across Vim
|
||||||
|
splits and tmux panes without a prefix key
|
||||||
|
- **`install.sh` tmux step** — detects tmux and optionally appends the four
|
||||||
|
navigator `bind-key` lines to `~/.tmux.conf`; warns about `C-l`/screen-clear tradeoff
|
||||||
|
- **`install.sh` survival guide** — post-install output now shows the 4 essential
|
||||||
|
commands for first-time Vim users, plus the `stty -ixon` advisory
|
||||||
|
- **QUICKSTART.md Step 0** — new first section explaining Vim modes (Normal/Insert/Visual)
|
||||||
|
and 4 survival commands; makes the guide usable by users who have never opened Vim
|
||||||
|
- **`let b:ale_enabled = 0`** in `LargeFileSettings()` — ALE no longer spawns
|
||||||
|
linter subprocesses for files over 10 MB
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **ALE lint triggers** — `ale_lint_on_text_changed` changed from `'never'` to `'normal'`;
|
||||||
|
`ale_lint_on_insert_leave` and `ale_lint_on_enter` changed from `0` to `1` — diagnostics
|
||||||
|
now refresh on buffer enter and after edits settle in normal mode
|
||||||
|
- **`<C-h/j/k/l>` manual maps removed** — vim-tmux-navigator owns these keys at
|
||||||
|
plugin load time; the previous hand-rolled `<C-W>` maps were unreachable dead code
|
||||||
|
- **`<leader>pp` paste-mode toggle removed** — functionally identical to the existing
|
||||||
|
`F2` pastetoggle; its presence caused a 500 ms delay on every `<leader>p` paste
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **ALE navigation direction reversed** — `[e` now correctly calls `ALEPrevious`
|
||||||
|
and `]e` calls `ALENext`, matching the vim-unimpaired `[`/`]` convention
|
||||||
|
- **`<leader>rG` regex metacharacter bug** — without `-F`, characters like `.` `*`
|
||||||
|
`(` in the cursor word were treated as regex, producing incorrect matches
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.0.0] - 2026-03-29
|
## [1.0.0] - 2026-03-29
|
||||||
|
|
||||||
First stable release. Full-stack engineering environment out of the box — automatic
|
First stable release. Full-stack engineering environment out of the box — automatic
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,39 @@
|
||||||
|
|
||||||
Five minutes from zero to a working Vim engineering environment.
|
Five minutes from zero to a working Vim engineering environment.
|
||||||
|
|
||||||
|
> **New to Vim?** Read Step 0 first — it takes 2 minutes and prevents the most
|
||||||
|
> common beginner frustration. Already know how Vim modes work? [Skip to Step 1](#step-1-install).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 0: Vim Basics
|
||||||
|
|
||||||
|
> **When confused, press `Esc` until things feel normal again — then keep reading.**
|
||||||
|
|
||||||
|
Vim is **modal**: the keyboard behaves differently depending on which mode you are in.
|
||||||
|
Most people get stuck because they try to type text while in Normal mode.
|
||||||
|
|
||||||
|
### The Three Modes
|
||||||
|
|
||||||
|
| Mode | Purpose | How to enter | How to leave |
|
||||||
|
|------|---------|--------------|--------------|
|
||||||
|
| **Normal** | Navigate and run commands | Startup default | — (you're already here) |
|
||||||
|
| **Insert** | Type text | `i` before cursor, `a` after, `o` new line below | `Esc` or `jk` |
|
||||||
|
| **Visual** | Select text | `v` char-by-char, `V` whole lines | `Esc` |
|
||||||
|
|
||||||
|
### 4 Survival Commands
|
||||||
|
|
||||||
|
Learn these before anything else. They will get you out of every stuck situation.
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
|---------|--------|
|
||||||
|
| `Esc` or `jk` | Exit insert/visual mode — return to Normal |
|
||||||
|
| `:q!` then `Enter` | Force quit without saving (emergency exit) |
|
||||||
|
| `,x` | Save and quit |
|
||||||
|
| `,w` or `Ctrl+s` | Save the file |
|
||||||
|
|
||||||
|
Once in Normal mode, press `,?` to open a cheat sheet covering everything else.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 1: Install
|
## Step 1: Install
|
||||||
|
|
@ -66,19 +99,22 @@ This auto-detects and installs the correct language server for the current filet
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The 10 Keys That Matter
|
## The 12 Keys That Matter
|
||||||
|
|
||||||
```
|
```
|
||||||
, (pause 500ms) Show all shortcuts
|
, (pause 500ms) Show all keybindings (which-key)
|
||||||
|
,? Open cheat sheet inside Vim
|
||||||
|
Esc / jk Exit insert mode → Normal (memorize this)
|
||||||
|
Ctrl+s Save (works in normal and insert mode)
|
||||||
Ctrl+p Fuzzy find file
|
Ctrl+p Fuzzy find file
|
||||||
Ctrl+n Toggle file tree
|
Ctrl+n Toggle file tree
|
||||||
gd Go to definition
|
gd Go to definition
|
||||||
K Show documentation
|
K Show documentation
|
||||||
[g / ]g Prev / next diagnostic
|
[g / ]g Prev / next LSP diagnostic
|
||||||
,rn Rename symbol
|
,rn Rename symbol
|
||||||
,rg Search project contents
|
,rG Search word under cursor (ripgrep)
|
||||||
,gs Git status
|
,gs Git status
|
||||||
,w / ,q Save / Quit
|
,w / ,x Save / Save+quit
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -197,38 +233,51 @@ colorscheme dracula " or: gruvbox, solarized, onedark
|
||||||
## Quick Reference Card
|
## Quick Reference Card
|
||||||
|
|
||||||
```
|
```
|
||||||
|
BASICS (learn these first)
|
||||||
|
Esc / jk Exit insert mode → Normal
|
||||||
|
Ctrl+s Save (normal + insert mode)
|
||||||
|
:q! + Enter Emergency quit without saving
|
||||||
|
,? Open cheat sheet
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
Ctrl+n File tree toggle
|
Ctrl+n File tree toggle
|
||||||
Ctrl+p Fuzzy find file (git-aware)
|
Ctrl+p Fuzzy find file (git-aware)
|
||||||
,b Search open buffers
|
,b Search open buffers
|
||||||
,rg Search file contents (ripgrep)
|
,rg Search file contents (ripgrep)
|
||||||
|
,rG Ripgrep word under cursor
|
||||||
,w Save | ,q Quit | ,x Save+quit
|
,w Save | ,q Quit | ,x Save+quit
|
||||||
,wa Save all buffers
|
,wa Save all buffers
|
||||||
|
,, Switch to last file
|
||||||
|
|
||||||
CODE
|
CODE
|
||||||
gd Go to definition
|
gd Go to definition
|
||||||
K Show documentation
|
K Show documentation
|
||||||
[g / ]g Prev/next diagnostic
|
[g / ]g Prev/next LSP diagnostic
|
||||||
|
[e / ]e Prev/next ALE error
|
||||||
,rn Rename symbol
|
,rn Rename symbol
|
||||||
,ca Code action
|
,ca Code action / auto-fix
|
||||||
,f Format selection
|
,f Format selection | ,F Format whole file
|
||||||
,F Format whole file
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
,gs Status | ,gd Diff | ,gb Blame
|
,gs Status | ,gd Diff | ,gb Blame
|
||||||
,gc Commit | ,gp Push | ,gl Pull
|
,gc Commit | ,gp Push | ,gl Pull
|
||||||
|
|
||||||
WINDOWS
|
WINDOWS / PANES
|
||||||
Ctrl+h/j/k/l Move between panes
|
Ctrl+h/j/k/l Move between Vim windows or tmux panes
|
||||||
|
,h / ,l Prev / next buffer
|
||||||
,tv Open terminal (vertical)
|
,tv Open terminal (vertical)
|
||||||
,th Open terminal (horizontal)
|
,th Open terminal (horizontal)
|
||||||
Esc Exit terminal mode
|
Esc Exit terminal mode
|
||||||
F5 Undo tree | F8 Tag browser
|
,u Undo tree | ,tt Tag browser
|
||||||
|
|
||||||
SEARCH
|
SEARCH & REPLACE
|
||||||
/text Search forward
|
/text Search forward | ?text backward
|
||||||
?text Search backward
|
// Search for visually selected text
|
||||||
,* Replace word under cursor (project-wide)
|
,* Replace word under cursor (file-wide)
|
||||||
|
|
||||||
|
CLIPBOARD
|
||||||
|
,y / ,Y Yank / yank line to system clipboard
|
||||||
|
,p / ,P Paste from system clipboard (after / before)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
552
README.md
552
README.md
|
|
@ -1,41 +1,71 @@
|
||||||
# chopsticks — Vim Configuration
|
# chopsticks
|
||||||
|
|
||||||
A native Vim configuration optimized for full-stack engineering workflows.
|
> A batteries-included Vim configuration for full-stack engineering.
|
||||||
Vim 8.0+ · Tiered LSP · TTY-aware · Zero icon fonts · 14 languages.
|
> Tiered LSP · 14 languages · TTY-aware · Zero icon fonts · One-command install.
|
||||||
|
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://www.vim.org/)
|
[](https://www.vim.org/)
|
||||||
|
[](#installation)
|
||||||
|
[](https://github.com/m1ngsama/chopsticks/releases)
|
||||||
|
[](https://github.com/m1ngsama/chopsticks/commits/main)
|
||||||
|
[](https://github.com/m1ngsama/chopsticks/stargazers)
|
||||||
|
[](https://github.com/m1ngsama/chopsticks/issues)
|
||||||
|
[](https://github.com/m1ngsama/chopsticks/pulls)
|
||||||
|
[](#plugins)
|
||||||
|
[](#language-support)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||||
cd ~/.vim && ./install.sh
|
cd ~/.vim && ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
See [QUICKSTART.md](QUICKSTART.md) for the 5-minute guide.
|
> **New to Vim?** Read [Step 0 in QUICKSTART.md](QUICKSTART.md#step-0-vim-basics) first —
|
||||||
|
> a 2-minute intro to modes and the 4 commands that get you out of any jam.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [Design Principles](#design-principles)
|
||||||
|
- [Requirements](#requirements)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [LSP: Tiered Backend](#lsp-tiered-backend)
|
||||||
|
- [Key Mappings](#key-mappings)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Language Support](#language-support)
|
||||||
|
- [Plugins](#plugins)
|
||||||
|
- [Customization](#customization)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Design Principles
|
## Design Principles
|
||||||
|
|
||||||
- **KISS** — No icon fonts, no unicode glyphs, plain ASCII throughout
|
| Principle | What it means |
|
||||||
- **Tiered LSP** — CoC (full) with vim-lsp fallback; works with or without Node.js
|
|-----------|--------------|
|
||||||
- **TTY-aware** — Automatic detection and optimization for console/SSH environments
|
| **KISS** | No icon fonts, no Nerd Font glyphs — plain ASCII everywhere |
|
||||||
- **Engineering-first** — Git workflow, session management, project-local config
|
| **Tiered LSP** | CoC (full) when Node.js is available; vim-lsp (pure VimScript) otherwise |
|
||||||
- **Batteries included** — `install.sh` handles all dependencies automatically
|
| **TTY-aware** | Automatically detects SSH/console environments and degrades gracefully |
|
||||||
|
| **Engineering-first** | Git workflow, persistent sessions, project-local config, large-file safety |
|
||||||
|
| **Batteries included** | `install.sh` handles vim-plug, plugins, system tools, and language servers |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
| Requirement | Minimum | Notes |
|
| Tool | Minimum | Role |
|
||||||
|-------------|---------|-------|
|
|------|---------|------|
|
||||||
| Vim | 8.0+ | vim9script not required |
|
| Vim | **8.0+** | Required |
|
||||||
| git | any | For cloning and fugitive |
|
| git | any | Cloning and vim-fugitive |
|
||||||
| curl | any | For vim-plug auto-install |
|
| curl | any | vim-plug bootstrap |
|
||||||
| Node.js | 14.14+ | Optional — enables CoC LSP |
|
| Node.js | 14.14+ | Optional — enables CoC LSP (recommended) |
|
||||||
| ripgrep (rg) | any | Optional — enables `:Rg` search |
|
| ripgrep | any | Optional — enables `,rg` / `,rG` project search |
|
||||||
| fzf | any | Optional — enables `Ctrl+p` fuzzy search |
|
| fzf | any | Optional — enables `Ctrl+p` fuzzy finder |
|
||||||
| ctags | any | Optional — enables `F8` tag browser |
|
| ctags | any | Optional — enables `,tt` tag browser |
|
||||||
|
| tmux | 1.8+ | Optional — enables seamless pane navigation |
|
||||||
|
|
||||||
|
All optional tools are installed automatically by `install.sh` when prompted.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -49,16 +79,20 @@ cd ~/.vim
|
||||||
./install.sh
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The installer:
|
The installer handles everything in sequence:
|
||||||
1. Checks Vim version and detects OS / package managers
|
|
||||||
2. Backs up any existing `~/.vimrc` (timestamped)
|
1. Verifies Vim 8.0+ and detects OS / package manager
|
||||||
3. Creates symlinks: `~/.vimrc -> ~/.vim/.vimrc` and `~/.vim/coc-settings.json`
|
2. Backs up any existing `~/.vimrc` with a timestamp
|
||||||
|
3. Symlinks `~/.vimrc → ~/.vim/.vimrc` and `~/.vim/coc-settings.json`
|
||||||
4. Installs vim-plug and runs `:PlugInstall`
|
4. Installs vim-plug and runs `:PlugInstall`
|
||||||
5. Optionally installs system tools, language tools, and CoC extensions
|
5. Optionally installs system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)
|
||||||
|
6. Optionally installs language tools (npm, pip, Go)
|
||||||
|
7. Optionally installs CoC language server extensions
|
||||||
|
8. Optionally configures tmux for seamless pane navigation
|
||||||
|
|
||||||
Supported platforms: **macOS** (Homebrew), **Debian/Ubuntu** (apt), **Arch Linux** (pacman), **Fedora** (dnf).
|
**Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch Linux (pacman), Fedora (dnf).
|
||||||
|
|
||||||
Use `--yes` for non-interactive / CI environments:
|
Use `--yes` for non-interactive or CI environments:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./install.sh --yes
|
./install.sh --yes
|
||||||
|
|
@ -77,21 +111,21 @@ vim +PlugInstall +qall </dev/null
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## LSP: Tiered Backend System
|
## LSP: Tiered Backend
|
||||||
|
|
||||||
Code intelligence is provided by one of two backends, selected automatically:
|
Code intelligence is provided by one of two backends, chosen automatically at startup:
|
||||||
|
|
||||||
| Condition | Backend | Features |
|
| Condition | Backend | Capabilities |
|
||||||
|-----------|---------|----------|
|
|-----------|---------|-------------|
|
||||||
| Vim 8.0.1453+ AND Node.js 14.14+ | **CoC** | Full LSP, snippets, extensions ecosystem |
|
| Vim 8.0.1453+ **and** Node.js 14.14+ | **CoC** | Full LSP, snippets, extension ecosystem |
|
||||||
| Vim 8.0+ (no Node.js) | **vim-lsp** | LSP via language server binaries, asyncomplete |
|
| Vim 8.0+ (no Node.js) | **vim-lsp** | LSP via language server binaries, asyncomplete |
|
||||||
| Any Vim | **ALE** | Linting and auto-fix (always active) |
|
| Any Vim | **ALE** | Async linting + auto-fix (always active, both backends) |
|
||||||
|
|
||||||
Both backends expose identical key mappings: `gd`, `K`, `[g`, `]g`, `<leader>rn`, `<leader>ca`.
|
Both CoC and vim-lsp expose the same key mappings so switching backends is transparent.
|
||||||
|
|
||||||
### CoC setup (with Node.js)
|
### With Node.js (CoC)
|
||||||
|
|
||||||
Install language server extensions from inside Vim:
|
Install language server extensions from inside Vim — or let `install.sh` do it automatically:
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
:CocInstall coc-pyright " Python
|
:CocInstall coc-pyright " Python
|
||||||
|
|
@ -99,64 +133,86 @@ Install language server extensions from inside Vim:
|
||||||
:CocInstall coc-go " Go
|
:CocInstall coc-go " Go
|
||||||
:CocInstall coc-rust-analyzer " Rust
|
:CocInstall coc-rust-analyzer " Rust
|
||||||
:CocInstall coc-json coc-yaml " JSON, YAML
|
:CocInstall coc-json coc-yaml " JSON, YAML
|
||||||
:CocInstall coc-html coc-css " HTML, CSS
|
:CocInstall coc-html coc-css " HTML, CSS/SCSS
|
||||||
:CocInstall coc-sh " Shell
|
:CocInstall coc-sh " Shell
|
||||||
:CocInstall coc-sql " SQL
|
:CocInstall coc-sql " SQL
|
||||||
```
|
```
|
||||||
|
|
||||||
`install.sh` installs all of the above automatically when prompted.
|
**Markdown LSP** uses `marksman` as an external binary (not a CoC extension):
|
||||||
|
|
||||||
**Markdown LSP** — `marksman` is configured via `coc-settings.json` (not a CoC
|
```bash
|
||||||
extension — install `marksman` binary via `brew install marksman` or download from
|
brew install marksman # macOS
|
||||||
[releases](https://github.com/artempyanykh/marksman/releases)).
|
sudo pacman -S marksman # Arch
|
||||||
|
# or: ./install.sh handles it automatically
|
||||||
### vim-lsp setup (without Node.js)
|
|
||||||
|
|
||||||
Install language server binaries for your languages, then run:
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:LspInstallServer " auto-installs the right server for the current filetype
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported languages: Python, Go, Rust, TypeScript, JavaScript, Shell, HTML,
|
### Without Node.js (vim-lsp)
|
||||||
CSS/SCSS, JSON, YAML, Markdown, SQL — via `vim-lsp-settings`.
|
|
||||||
|
Open a source file, then run:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:LspInstallServer " detects filetype and installs the correct server
|
||||||
|
:LspStatus " check server status
|
||||||
|
```
|
||||||
|
|
||||||
|
Supported: Python, Go, Rust, TypeScript/JavaScript, Shell, HTML, CSS/SCSS, JSON, YAML, Markdown, SQL.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Key Mappings
|
## Key Mappings
|
||||||
|
|
||||||
Leader key: `,` (comma)
|
**Leader key:** `,` (comma)
|
||||||
|
|
||||||
Press `,` and wait 500ms for an interactive guide to all bindings (vim-which-key).
|
Press `,` and wait 500 ms to see an interactive guide to all bindings (vim-which-key).
|
||||||
|
Press `,?` to open the built-in cheat sheet at any time.
|
||||||
|
|
||||||
|
### Survival
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `jk` | Exit insert mode → Normal (ergonomic Escape) |
|
||||||
|
| `Esc` | Exit insert / visual mode (standard) |
|
||||||
|
| `Ctrl+s` | Save file (normal and insert mode) |
|
||||||
|
| `,w` | Save file |
|
||||||
|
| `,x` | Save and quit |
|
||||||
|
| `,q` | Quit |
|
||||||
|
| `,?` | Open cheat sheet |
|
||||||
|
|
||||||
|
> **`Ctrl+s` note:** some terminals freeze on `Ctrl+s` (XON/XOFF). Add `stty -ixon`
|
||||||
|
> to your `~/.bashrc` / `~/.zshrc` to disable this permanently.
|
||||||
|
|
||||||
### Files and Buffers
|
### Files and Buffers
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
|
| `Ctrl+p` | Fuzzy file search — git-aware (FZF) |
|
||||||
| `Ctrl+n` | Toggle file tree (NERDTree) |
|
| `Ctrl+n` | Toggle file tree (NERDTree) |
|
||||||
| `,n` | Reveal current file in NERDTree |
|
| `,n` | Reveal current file in NERDTree |
|
||||||
| `Ctrl+p` | Fuzzy file search (FZF — git-aware) |
|
|
||||||
| `,b` | Search open buffers (FZF) |
|
| `,b` | Search open buffers (FZF) |
|
||||||
| `,rg` | Project-wide search (ripgrep+FZF) |
|
| `,rg` | Project-wide search (ripgrep + FZF) |
|
||||||
|
| `,rG` | Ripgrep for word under cursor (literal match) |
|
||||||
| `,rt` | Search tags (FZF) |
|
| `,rt` | Search tags (FZF) |
|
||||||
| `,gF` | Search git-tracked files (FZF) |
|
| `,gF` | Search git-tracked files (FZF) |
|
||||||
| `,l` | Next buffer |
|
| `,l` | Next buffer |
|
||||||
| `,h` | Previous buffer |
|
| `,h` | Previous buffer |
|
||||||
| `,bd` | Close current buffer |
|
| `,bd` | Close current buffer (preserves window layout) |
|
||||||
| `,,` | Switch to last file |
|
| `,,` | Switch to last file |
|
||||||
|
|
||||||
### Windows and Tabs
|
### Windows, Tabs, and tmux
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `Ctrl+h/j/k/l` | Navigate between windows |
|
| `Ctrl+h/j/k/l` | Navigate between Vim splits **and** tmux panes |
|
||||||
| `<Leader>=` | Increase window height |
|
| `,=` | Increase window height |
|
||||||
| `<Leader>-` | Decrease window height |
|
| `,-` | Decrease window height |
|
||||||
| `<Leader>+` | Increase window width |
|
| `,+` | Increase window width |
|
||||||
| `<Leader>_` | Decrease window width |
|
| `,_` | Decrease window width |
|
||||||
| `,tn` | New tab |
|
| `,tn` | New tab |
|
||||||
| `,tc` | Close tab |
|
| `,tc` | Close tab |
|
||||||
| `,tl` | Toggle to last tab |
|
| `,tl` | Toggle to last tab |
|
||||||
|
| `,tv` | Open terminal (vertical split) |
|
||||||
|
| `,th` | Open terminal (horizontal split) |
|
||||||
|
| `Esc Esc` | Exit terminal mode |
|
||||||
|
|
||||||
### Code Intelligence (CoC / vim-lsp)
|
### Code Intelligence (CoC / vim-lsp)
|
||||||
|
|
||||||
|
|
@ -165,123 +221,128 @@ Press `,` and wait 500ms for an interactive guide to all bindings (vim-which-key
|
||||||
| `gd` | Go to definition |
|
| `gd` | Go to definition |
|
||||||
| `gy` | Go to type definition |
|
| `gy` | Go to type definition |
|
||||||
| `gi` | Go to implementation |
|
| `gi` | Go to implementation |
|
||||||
| `gr` | Show references |
|
| `gr` | Show all references |
|
||||||
| `K` | Hover documentation |
|
| `K` | Hover documentation |
|
||||||
| `[g` | Previous diagnostic |
|
| `[g` | Previous diagnostic |
|
||||||
| `]g` | Next diagnostic |
|
| `]g` | Next diagnostic |
|
||||||
| `,rn` | Rename symbol |
|
| `,rn` | Rename symbol |
|
||||||
| `,f` | Format selection |
|
| `,f` | Format selection |
|
||||||
| `,ca` | Code action (cursor) |
|
| `,F` | Format whole file |
|
||||||
| `,o` | File outline |
|
| `,ca` | Code action (cursor position) |
|
||||||
|
| `,o` | File outline (symbols) |
|
||||||
| `,ws` | Workspace symbols |
|
| `,ws` | Workspace symbols |
|
||||||
| `,cD` | Diagnostics list |
|
| `,cD` | Diagnostics list |
|
||||||
| `,cr` | Resume last CoC list |
|
|
||||||
| `,qf` | Quick-fix current line (CoC) |
|
| `,qf` | Quick-fix current line (CoC) |
|
||||||
| `,cl` | Run code lens (CoC) |
|
|
||||||
| `Tab` | Next completion item |
|
| `Tab` | Next completion item |
|
||||||
| `Shift+Tab` | Previous completion item |
|
| `Shift+Tab` | Previous completion item |
|
||||||
| `Enter` | Confirm completion |
|
| `Enter` | Confirm completion |
|
||||||
|
|
||||||
Text objects (CoC only): `if`/`af` (function), `ic`/`ac` (class)
|
Text objects (CoC): `if`/`af` (function inner/around), `ic`/`ac` (class inner/around).
|
||||||
|
|
||||||
### Linting (ALE)
|
### Linting (ALE — always active)
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `[e` | Next error/warning |
|
| `[e` | Previous error / warning |
|
||||||
| `]e` | Previous error/warning |
|
| `]e` | Next error / warning |
|
||||||
| `,aD` | Show error details |
|
| `,aD` | Show error detail |
|
||||||
|
| `,ad` | Full diagnostics list |
|
||||||
|
|
||||||
Signs: `X` = error, `!` = warning
|
Signs in the gutter: `X` = error, `!` = warning.
|
||||||
|
|
||||||
### Git Workflow (fugitive)
|
### Git (vim-fugitive)
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `,gs` | Git status |
|
| `,gs` | Git status (stage with `s`, commit with `cc`) |
|
||||||
| `,gc` | Git commit |
|
| `,gc` | Git commit |
|
||||||
| `,gp` | Git push |
|
| `,gp` | Git push |
|
||||||
| `,gl` | Git pull |
|
| `,gl` | Git pull |
|
||||||
| `,gd` | Git diff |
|
| `,gd` | Git diff |
|
||||||
| `,gb` | Git blame |
|
| `,gb` | Git blame |
|
||||||
| `,gF` | Search git-tracked files (FZF) |
|
|
||||||
|
|
||||||
### Engineering Utilities
|
### Search and Replace
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `n` / `N` | Next / previous match (cursor centered) |
|
||||||
|
| `//` | Search for visually selected text |
|
||||||
|
| `,*` | Search and replace word under cursor (file-wide) |
|
||||||
|
| `,rG` | Ripgrep word under cursor across project |
|
||||||
|
| `,<CR>` | Clear search highlight |
|
||||||
|
|
||||||
|
### Clipboard
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `,y` | Yank to system clipboard |
|
||||||
|
| `,Y` | Yank line to system clipboard |
|
||||||
|
| `,p` | Paste from system clipboard (after cursor) |
|
||||||
|
| `,P` | Paste from system clipboard (before cursor) |
|
||||||
|
|
||||||
|
### Editing and Navigation
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `s` + 2 chars | EasyMotion — jump anywhere on screen |
|
||||||
|
| `Space` | Toggle code fold |
|
||||||
|
| `Y` | Yank to end of line (consistent with `D`, `C`) |
|
||||||
|
| `Ctrl+d/u` | Half-page scroll (cursor stays centered) |
|
||||||
|
| `>` / `<` | Indent / dedent (keeps visual selection) |
|
||||||
|
| `Alt+j/k` | Move current line down / up |
|
||||||
|
| `0` | Jump to first non-blank character |
|
||||||
|
| `[q` / `]q` | Previous / next quickfix entry (vim-unimpaired) |
|
||||||
|
| `,u` | Toggle undo tree (visual branch history) |
|
||||||
|
| `,tt` | Toggle tagbar (code structure) |
|
||||||
|
| `F2` | Toggle paste mode |
|
||||||
|
| `F3` | Toggle absolute line numbers |
|
||||||
|
| `F4` | Toggle relative line numbers |
|
||||||
|
|
||||||
|
### Config and Utilities
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
|-----|--------|
|
|-----|--------|
|
||||||
| `,ev` | Edit `~/.vimrc` |
|
| `,ev` | Edit `~/.vimrc` |
|
||||||
| `,sv` | Reload `~/.vimrc` |
|
| `,sv` | Reload `~/.vimrc` |
|
||||||
| `,F` | Format entire file |
|
|
||||||
| `,W` | Strip trailing whitespace |
|
|
||||||
| `,wa` | Save all open buffers |
|
| `,wa` | Save all open buffers |
|
||||||
| `,wd` | Change CWD to current buffer's dir |
|
| `,wd` | Change working directory to current file's location |
|
||||||
| `,cp` | Copy file path to clipboard |
|
| `,cp` | Copy absolute file path to clipboard |
|
||||||
| `,cf` | Copy filename to clipboard |
|
| `,cf` | Copy filename to clipboard |
|
||||||
| `,y` | Yank to system clipboard |
|
| `,qo` / `,qc` | Open / close quickfix list |
|
||||||
| `,Y` | Yank line to system clipboard |
|
|
||||||
| `,*` | Search+replace word under cursor |
|
|
||||||
| `,qo` | Open quickfix list |
|
|
||||||
| `,qc` | Close quickfix list |
|
|
||||||
| `,tv` | Open terminal (vertical split) |
|
|
||||||
| `,th` | Open terminal (horizontal, 10 rows) |
|
|
||||||
| `Esc` | Exit terminal mode |
|
|
||||||
|
|
||||||
### Navigation and Editing
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `s`+2ch | EasyMotion jump to any location |
|
|
||||||
| `Space` | Toggle code fold |
|
|
||||||
| `Y` | Yank to end of line (like `D`, `C`) |
|
|
||||||
| `n` / `N` | Search next/prev (cursor centered) |
|
|
||||||
| `Ctrl+d/u` | Half-page scroll (cursor centered) |
|
|
||||||
| `>` | Indent (keeps visual selection) |
|
|
||||||
| `<` | Dedent (keeps visual selection) |
|
|
||||||
| `[q` / `]q` | Previous/next quickfix (vim-unimpaired) |
|
|
||||||
| `[e` / `]e` | Previous/next ALE error/warning |
|
|
||||||
| `F2` | Toggle paste mode |
|
|
||||||
| `F3` | Toggle line numbers |
|
|
||||||
| `F4` | Toggle relative line numbers |
|
|
||||||
| `F5` | Toggle undo history (UndoTree) |
|
|
||||||
| `F8` | Toggle code tag browser (Tagbar) |
|
|
||||||
| `0` | Jump to first non-blank character |
|
|
||||||
| `Alt+j/k` | Move line up/down |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Startup Screen (vim-startify)
|
### Startup Dashboard
|
||||||
|
|
||||||
Opens when Vim is launched without a file argument. Shows:
|
Running `vim` (no arguments) opens a full-screen Startify dashboard showing recent
|
||||||
- Session list for current directory
|
files, sessions, and bookmarks. Running `vim .` opens NERDTree on the left with
|
||||||
- Recently opened files
|
the dashboard on the right.
|
||||||
- Bookmarks
|
|
||||||
|
|
||||||
Session auto-saves on quit. Auto-loads `Session.vim` if found in the current
|
### Keybinding Guide
|
||||||
directory. Auto-changes to git root on file open.
|
|
||||||
|
|
||||||
**`vim .` layout** — NERDTree on the left, Startify on the right.
|
Press `,` and pause for 500 ms. A popup (vim-which-key) lists all leader bindings
|
||||||
|
organized into groups. No need to memorize everything upfront.
|
||||||
|
|
||||||
### Keybinding Guide (vim-which-key)
|
### Built-in Cheat Sheet
|
||||||
|
|
||||||
Press `,` and pause for 500ms. A popup lists all available leader bindings
|
Press `,?` to open an inline reference covering modes, survival commands, search,
|
||||||
organized by group. Useful for onboarding and discovering shortcuts.
|
code intelligence, git, and clipboard — without leaving Vim.
|
||||||
|
|
||||||
### Session Management
|
### Session Management
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
:Obsess " Start tracking session
|
:Obsess " start tracking the current session
|
||||||
:Obsess! " Stop tracking
|
:Obsess! " stop tracking
|
||||||
```
|
```
|
||||||
|
|
||||||
Sessions stored in `~/.vim/sessions/` and automatically resumed by vim-prosession
|
Sessions are stored in `~/.vim/sessions/` and automatically restored by vim-prosession
|
||||||
on the next Vim launch in the same directory.
|
the next time you open Vim in the same directory.
|
||||||
|
|
||||||
### Project-Local Config
|
### Project-Local Config
|
||||||
|
|
||||||
Place a `.vimrc` in any project root:
|
Drop a `.vimrc` in any project root to override settings for that project:
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
" project/.vimrc
|
" project/.vimrc
|
||||||
|
|
@ -289,157 +350,244 @@ set shiftwidth=2
|
||||||
let g:ale_python_black_options = '--line-length=100'
|
let g:ale_python_black_options = '--line-length=100'
|
||||||
```
|
```
|
||||||
|
|
||||||
Loaded automatically. Security-restricted via `set secure`.
|
Loaded automatically via `set exrc`. Restricted to safe options via `set secure`.
|
||||||
|
|
||||||
|
### tmux Integration
|
||||||
|
|
||||||
|
`Ctrl+h/j/k/l` navigates seamlessly between Vim splits and tmux panes — no prefix
|
||||||
|
key, no mode switch.
|
||||||
|
|
||||||
|
**Vim side:** handled by vim-tmux-navigator (installed automatically).
|
||||||
|
|
||||||
|
**tmux side:** add to `~/.tmux.conf` (or let `install.sh` append it):
|
||||||
|
|
||||||
|
```tmux
|
||||||
|
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\S+\/)?g?(view|n?vim?x?)(diff)?$'"
|
||||||
|
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
|
||||||
|
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
|
||||||
|
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
|
||||||
|
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reload: `tmux source-file ~/.tmux.conf`
|
||||||
|
|
||||||
|
> **Note:** the `C-l` binding replaces the terminal's screen-clear shortcut inside
|
||||||
|
> tmux. To restore it, add `bind C-l send-keys 'C-l'` — then use `prefix + C-l`.
|
||||||
|
|
||||||
### Large File Handling
|
### Large File Handling
|
||||||
|
|
||||||
Files over 10 MB automatically disable syntax highlighting and undo history
|
Files over 10 MB automatically disable syntax highlighting, undo history, and
|
||||||
to prevent Vim from freezing.
|
linting to prevent Vim from stalling.
|
||||||
|
|
||||||
### TTY / Console Support
|
### TTY / Console Support
|
||||||
|
|
||||||
Detected automatically when `$TERM` is `linux` or `screen`. In TTY mode:
|
Detected automatically when `$TERM` is `linux` or `screen`. In TTY mode:
|
||||||
|
|
||||||
- True color and cursorline disabled
|
- True color and cursorline disabled
|
||||||
- Powerline separators replaced with plain ASCII
|
- Powerline separators replaced with plain ASCII
|
||||||
- FZF preview windows disabled
|
- FZF preview windows disabled
|
||||||
- NERDTree auto-open skipped
|
- IndentLine guides disabled
|
||||||
- Syntax column limit reduced to 120
|
- Syntax column limit reduced to 120 characters
|
||||||
- Simpler status line
|
- Simpler built-in status line used instead of airline
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Language Support
|
## Language Support
|
||||||
|
|
||||||
| Language | Indent | Formatter | Linter | LSP (CoC) |
|
| Language | Indent | Formatter | Linter | LSP |
|
||||||
|----------|--------|-----------|--------|-----------|
|
|----------|--------|-----------|--------|-----|
|
||||||
| Python | 4sp | black + isort | flake8, pylint | coc-pyright |
|
| Python | 4 sp | black, isort | flake8, pylint | coc-pyright |
|
||||||
| JavaScript | 2sp | prettier | eslint | coc-tsserver |
|
| JavaScript | 2 sp | prettier | eslint | coc-tsserver |
|
||||||
| TypeScript | 2sp | prettier | eslint, tsserver | coc-tsserver |
|
| TypeScript | 2 sp | prettier | eslint, tsserver | coc-tsserver |
|
||||||
| Go | tab | gofmt, goimports | staticcheck | coc-go |
|
| Go | tab | gofmt, goimports | staticcheck | coc-go |
|
||||||
| Rust | 4sp | rustfmt | cargo | coc-rust-analyzer |
|
| Rust | 4 sp | rustfmt | cargo | coc-rust-analyzer |
|
||||||
| Shell | 2sp | — | shellcheck | coc-sh |
|
| Shell | 2 sp | — | shellcheck | coc-sh |
|
||||||
| YAML | 2sp | prettier | yamllint | coc-yaml |
|
| YAML | 2 sp | prettier | yamllint | coc-yaml |
|
||||||
| HTML | 2sp | prettier | — | coc-html |
|
| HTML | 2 sp | prettier | — | coc-html |
|
||||||
| CSS / SCSS | 2sp | prettier | stylelint | coc-css |
|
| CSS / SCSS | 2 sp | prettier | stylelint | coc-css |
|
||||||
| Less | 2sp | prettier | — | — |
|
| Less | 2 sp | prettier | — | — |
|
||||||
| JSON | 2sp | prettier | — | coc-json |
|
| JSON | 2 sp | prettier | — | coc-json |
|
||||||
| Markdown | 2sp | prettier | markdownlint | marksman (coc-settings.json) |
|
| Markdown | 2 sp | prettier | markdownlint | marksman |
|
||||||
| SQL | 4sp | sqlfluff | sqlfluff | — |
|
| SQL | 4 sp | sqlfluff | sqlfluff | — |
|
||||||
| Dockerfile | 2sp | — | hadolint | — |
|
| Dockerfile | 2 sp | — | hadolint | — |
|
||||||
|
|
||||||
`install.sh` installs all linters and formatters automatically.
|
`install.sh` installs all formatters and linters automatically.
|
||||||
ALE runs them asynchronously; format-on-save active when using CoC.
|
ALE runs them asynchronously; format-on-save is active for all supported languages.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Plugin List
|
## Plugins
|
||||||
|
|
||||||
### Navigation
|
### Navigation
|
||||||
- **NERDTree** — File tree explorer
|
- **NERDTree** — file tree explorer
|
||||||
- **fzf + fzf.vim** — Fuzzy finder (file, buffer, tag, ripgrep)
|
- **fzf + fzf.vim** — fuzzy finder for files, buffers, tags, and ripgrep
|
||||||
|
|
||||||
### Git
|
### Git
|
||||||
- **vim-fugitive** — Git commands inside Vim
|
- **vim-fugitive** — full Git integration inside Vim
|
||||||
- **vim-gitgutter** — Diff signs in the sign column
|
- **vim-gitgutter** — diff signs in the sign column
|
||||||
|
|
||||||
### LSP and Completion
|
### LSP and Completion
|
||||||
- **coc.nvim** — Full LSP + completion (requires Node.js 14.14+)
|
- **coc.nvim** — full LSP + completion via Node.js (recommended)
|
||||||
- **vim-lsp** — Pure VimScript LSP client (fallback, no Node.js)
|
- **vim-lsp** — pure VimScript LSP client (Node.js-free fallback)
|
||||||
- **vim-lsp-settings** — Auto-configure language servers for vim-lsp
|
- **vim-lsp-settings** — auto-configures language servers for vim-lsp
|
||||||
- **asyncomplete.vim** — Async completion (used with vim-lsp)
|
- **asyncomplete.vim** — async completion engine (vim-lsp mode)
|
||||||
|
|
||||||
### Linting
|
### Linting
|
||||||
- **ALE** — Asynchronous Lint Engine (always active)
|
- **ALE** — asynchronous lint engine, always active regardless of LSP backend
|
||||||
|
|
||||||
### UI
|
### UI
|
||||||
- **vim-airline** — Status and tabline
|
- **vim-airline** — status line and tabline
|
||||||
- **vim-startify** — Startup screen with sessions
|
- **vim-startify** — startup dashboard with session management
|
||||||
- **vim-which-key** — Keybinding hint popup
|
- **vim-which-key** — keybinding hint popup on leader pause
|
||||||
- **indentLine** — Indent guide lines (non-TTY)
|
- **indentLine** — indent guide lines (non-TTY only)
|
||||||
- **undotree** — Undo history visualizer
|
- **undotree** — visual undo branch history
|
||||||
- **tagbar** — Code structure sidebar
|
- **tagbar** — code structure sidebar via ctags
|
||||||
|
|
||||||
### Editing
|
### Editing
|
||||||
- **vim-surround** — Change surrounding quotes, brackets, tags
|
- **vim-surround** — change surrounding quotes, brackets, and tags
|
||||||
- **vim-commentary** — `gc` to toggle comments
|
- **vim-commentary** — `gc` to toggle comments
|
||||||
- **auto-pairs** — Auto-close brackets and quotes
|
- **auto-pairs** — auto-close brackets and quotes
|
||||||
- **vim-easymotion** — Jump anywhere with 2 keystrokes
|
- **vim-easymotion** — jump anywhere on screen with 2 keystrokes (`s`)
|
||||||
- **vim-unimpaired** — Bracket shortcut pairs
|
- **vim-unimpaired** — bracket shortcut pairs (`[q`/`]q`, etc.)
|
||||||
- **targets.vim** — Extra text objects
|
- **targets.vim** — additional text objects
|
||||||
- **vim-snippets** — Snippet library (used with CoC/UltiSnips)
|
- **vim-snippets** — snippet library (used with CoC)
|
||||||
|
- **vim-tmux-navigator** — seamless `Ctrl+h/j/k/l` across Vim and tmux
|
||||||
|
|
||||||
### Language Packs
|
### Language Packs
|
||||||
- **vim-polyglot** — Syntax for 100+ languages
|
- **vim-polyglot** — syntax for 100+ languages
|
||||||
- **vim-go** — Go development tools (formatting + highlighting; LSP handled by coc-go)
|
- **vim-go** — Go syntax and tooling (LSP handled by coc-go)
|
||||||
|
|
||||||
### Session
|
### Session
|
||||||
- **vim-obsession** — Continuous session saving
|
- **vim-obsession** — continuous session saving
|
||||||
- **vim-prosession** — Project-level session management
|
- **vim-prosession** — project-level session management
|
||||||
|
|
||||||
### Color Schemes
|
### Color Schemes
|
||||||
- **gruvbox** (default), **dracula**, **solarized**, **onedark**
|
- **gruvbox** (default), **dracula**, **solarized**, **onedark**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Color Scheme
|
## Customization
|
||||||
|
|
||||||
Change in `.vimrc` (find the `colorscheme` line):
|
### Change the color scheme
|
||||||
|
|
||||||
|
In `~/.vimrc`, find and update the `colorscheme` line:
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
colorscheme dracula " or: gruvbox, solarized, onedark
|
colorscheme dracula " options: gruvbox, solarized, onedark
|
||||||
```
|
```
|
||||||
|
|
||||||
True color is enabled automatically when the terminal supports it
|
True color is enabled automatically when `$COLORTERM=truecolor`. Falls back to
|
||||||
(`$COLORTERM=truecolor`). Falls back to 256-color, then 16-color (TTY).
|
256-color, then 16-color in TTY.
|
||||||
|
|
||||||
|
### Per-project overrides
|
||||||
|
|
||||||
|
Create `.vimrc` in your project root. Anything placed here overrides the global
|
||||||
|
config for that directory:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
" my-project/.vimrc
|
||||||
|
set shiftwidth=2
|
||||||
|
let g:ale_python_black_options = '--line-length=120'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modify keybindings
|
||||||
|
|
||||||
|
Edit `~/.vimrc` directly (`,ev` opens it from inside Vim). Reload with `,sv`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
**Plugins not installed:**
|
**Plugins not loading**
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
:PlugInstall
|
:PlugInstall " install any missing plugins
|
||||||
:PlugUpdate
|
:PlugUpdate " update all plugins
|
||||||
```
|
```
|
||||||
|
|
||||||
**CoC not working:**
|
**CoC not working**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
node --version # must be >= 14.14
|
node --version # must be 14.14+
|
||||||
```
|
```
|
||||||
|
|
||||||
**Markdown LSP not starting:**
|
Inside Vim: `:CocInfo` for diagnostics, `:CocInstall <extension>` to add a language server.
|
||||||
```bash
|
|
||||||
marksman --version # must be installed separately
|
**vim-lsp server not starting**
|
||||||
brew install marksman # macOS
|
|
||||||
sudo pacman -S marksman # Arch
|
|
||||||
# or: ./install.sh (installs automatically)
|
|
||||||
```
|
|
||||||
|
|
||||||
**vim-lsp server not starting:**
|
|
||||||
```vim
|
```vim
|
||||||
:LspInstallServer " install server for current filetype
|
:LspInstallServer " install the correct server for the current filetype
|
||||||
:LspStatus " check server status
|
:LspStatus " check server status
|
||||||
```
|
```
|
||||||
|
|
||||||
**Colors look wrong:**
|
**Markdown LSP not starting**
|
||||||
|
|
||||||
|
`marksman` must be installed as a standalone binary (not a CoC extension):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install marksman # macOS
|
||||||
|
sudo pacman -S marksman # Arch
|
||||||
|
# or: ./install.sh handles it automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
**Colors look wrong**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export TERM=xterm-256color # add to ~/.bashrc or ~/.zshrc
|
export TERM=xterm-256color # add to ~/.bashrc or ~/.zshrc
|
||||||
```
|
```
|
||||||
|
|
||||||
**ALE not finding linters:**
|
For true color: `export COLORTERM=truecolor`.
|
||||||
|
|
||||||
|
**ALE linters not found**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
which flake8 black prettier eslint # confirm tools are on PATH
|
which flake8 black prettier eslint # verify tools are on PATH
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If tools were installed with `pip install --user` or `npm install -g`, make sure
|
||||||
|
the respective bin directories are on `$PATH`.
|
||||||
|
|
||||||
|
**`Ctrl+s` freezes the terminal**
|
||||||
|
|
||||||
|
Add `stty -ixon` to your `~/.bashrc`, `~/.zshrc`, or `~/.config/fish/config.fish`.
|
||||||
|
This disables XON/XOFF flow control permanently.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## References
|
## Contributing
|
||||||
|
|
||||||
- [vim-plug](https://github.com/junegunn/vim-plug)
|
Bug reports and pull requests are welcome. Please follow these guidelines:
|
||||||
- [coc.nvim](https://github.com/neoclide/coc.nvim)
|
|
||||||
- [vim-lsp](https://github.com/prabirshrestha/vim-lsp)
|
### Reporting a bug
|
||||||
- [vim-lsp-settings](https://github.com/mattn/vim-lsp-settings)
|
|
||||||
- [amix/vimrc](https://github.com/amix/vimrc)
|
1. Search [existing issues](https://github.com/m1ngsama/chopsticks/issues) before opening a new one.
|
||||||
|
2. Include your Vim version (`vim --version`), OS, and a minimal reproduction.
|
||||||
|
3. If the bug is plugin-specific, check whether it reproduces with a minimal config
|
||||||
|
(`vim -u NONE`) or only with chopsticks loaded.
|
||||||
|
|
||||||
|
### Proposing a change
|
||||||
|
|
||||||
|
1. Open an issue first to discuss the change, especially for non-trivial additions.
|
||||||
|
2. Keep the scope focused — one feature or fix per PR.
|
||||||
|
3. Follow existing conventions: augroups for autocmds, TTY guards for visual features,
|
||||||
|
conditional plugin loading where appropriate.
|
||||||
|
4. Update `CHANGELOG.md` with a summary of the change.
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
|
||||||
|
Chopsticks is an opinionated configuration. Changes should align with the design
|
||||||
|
principles above — in particular, KISS (no icon fonts, minimal dependencies) and
|
||||||
|
TTY-compatibility. Neovim-only features and Lua configs are out of scope.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
Inspired by [amix/vimrc](https://github.com/amix/vimrc).
|
||||||
|
Built with [vim-plug](https://github.com/junegunn/vim-plug),
|
||||||
|
[coc.nvim](https://github.com/neoclide/coc.nvim),
|
||||||
|
[vim-lsp](https://github.com/prabirshrestha/vim-lsp),
|
||||||
|
and the broader Vim plugin community.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
67
get.sh
Normal file
67
get.sh
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# get.sh - One-command bootstrap for chopsticks vim config
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||||
|
# curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
REPO="https://github.com/m1ngsama/chopsticks.git"
|
||||||
|
DEST="$HOME/.vim"
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; BOLD='\033[1m'; NC='\033[0m'
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||||
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||||
|
die() { echo -e "${RED}[FATAL]${NC} $1" >&2; exit 1; }
|
||||||
|
step() { echo -e "\n${BOLD}==> $1${NC}"; }
|
||||||
|
|
||||||
|
echo -e "${BOLD}chopsticks — One-command installer${NC}"
|
||||||
|
echo "----------------------------------"
|
||||||
|
echo " Repo: $REPO"
|
||||||
|
echo " Dest: $DEST"
|
||||||
|
|
||||||
|
# ── git ───────────────────────────────────────────────────────────────────────
|
||||||
|
step "Checking for git"
|
||||||
|
|
||||||
|
if ! command -v git >/dev/null 2>&1; then
|
||||||
|
warn "git not found — attempting to install"
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y git >/dev/null 2>&1
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then sudo pacman -S --noconfirm git >/dev/null 2>&1
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then sudo dnf install -y git >/dev/null 2>&1
|
||||||
|
elif command -v brew >/dev/null 2>&1; then brew install git >/dev/null 2>&1
|
||||||
|
else die "git is required. Install it manually then re-run."; fi
|
||||||
|
command -v git >/dev/null 2>&1 || die "git install failed. Try: sudo apt install git"
|
||||||
|
fi
|
||||||
|
ok "git $(git --version | awk '{print $3}')"
|
||||||
|
|
||||||
|
# ── Clone or update ───────────────────────────────────────────────────────────
|
||||||
|
step "Setting up $DEST"
|
||||||
|
|
||||||
|
if [[ -d "$DEST/.git" ]]; then
|
||||||
|
warn "$DEST already exists — pulling latest changes"
|
||||||
|
git -C "$DEST" pull --ff-only origin main 2>/dev/null || \
|
||||||
|
warn "Could not pull latest — using existing version (run: git -C ~/.vim pull)"
|
||||||
|
ok "Repository updated"
|
||||||
|
elif [[ -d "$DEST" ]]; then
|
||||||
|
die "$HOME/.vim exists but is not a chopsticks git repo.
|
||||||
|
Back it up first: mv ~/.vim ~/.vim.bak
|
||||||
|
Then re-run: curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash"
|
||||||
|
else
|
||||||
|
git clone --depth=1 "$REPO" "$DEST" || \
|
||||||
|
die "Clone failed — check your network connection"
|
||||||
|
ok "Cloned to $DEST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Run installer ─────────────────────────────────────────────────────────────
|
||||||
|
step "Running installer"
|
||||||
|
|
||||||
|
cd "$DEST"
|
||||||
|
|
||||||
|
# exec replaces this process with install.sh and reconnects stdin to /dev/tty
|
||||||
|
# so interactive prompts work correctly even when this script was piped from curl
|
||||||
|
if [[ -e /dev/tty ]]; then
|
||||||
|
exec bash install.sh "$@" </dev/tty
|
||||||
|
else
|
||||||
|
exec bash install.sh "$@"
|
||||||
|
fi
|
||||||
528
install.sh
528
install.sh
|
|
@ -4,12 +4,13 @@
|
||||||
#
|
#
|
||||||
# --yes non-interactive: install all optional components automatically
|
# --yes non-interactive: install all optional components automatically
|
||||||
|
|
||||||
set -e
|
set -eo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
AUTO_YES=0
|
AUTO_YES=0
|
||||||
[[ "${1:-}" == "--yes" ]] && AUTO_YES=1
|
[[ "${1:-}" == "--yes" ]] && AUTO_YES=1
|
||||||
|
|
||||||
|
# ── Colours ───────────────────────────────────────────────────────────────────
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
|
|
@ -21,8 +22,12 @@ ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||||
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||||
skip() { echo -e "${CYAN}[--]${NC} $1"; }
|
skip() { echo -e "${CYAN}[--]${NC} $1"; }
|
||||||
fail() { echo -e "${RED}[ERR]${NC} $1"; }
|
fail() { echo -e "${RED}[ERR]${NC} $1"; }
|
||||||
die() { echo -e "${RED}[ERR]${NC} $1" >&2; exit 1; }
|
die() { echo -e "${RED}[FATAL]${NC} $1" >&2
|
||||||
|
echo " Retry with: ./install.sh 2>&1 | tee /tmp/chopsticks-install.log" >&2
|
||||||
|
echo " Report issues: https://github.com/m1ngsama/chopsticks/issues" >&2
|
||||||
|
exit 1; }
|
||||||
step() { echo -e "\n${BOLD}==> $1${NC}"; }
|
step() { echo -e "\n${BOLD}==> $1${NC}"; }
|
||||||
|
info() { echo " $1"; }
|
||||||
|
|
||||||
# Track results for summary
|
# Track results for summary
|
||||||
INSTALLED=()
|
INSTALLED=()
|
||||||
|
|
@ -30,52 +35,89 @@ SKIPPED=()
|
||||||
FAILED=()
|
FAILED=()
|
||||||
|
|
||||||
# Ask yes/no; returns 0 for yes
|
# Ask yes/no; returns 0 for yes
|
||||||
|
# Reads from /dev/tty so interactive prompts work even under: curl | bash
|
||||||
ask() {
|
ask() {
|
||||||
[[ $AUTO_YES -eq 1 ]] && return 0
|
[[ $AUTO_YES -eq 1 ]] && return 0
|
||||||
|
if [[ -t 0 ]]; then
|
||||||
read -r -p "$1 [y/N] " reply
|
read -r -p "$1 [y/N] " reply
|
||||||
|
elif [[ -e /dev/tty ]]; then
|
||||||
|
read -r -p "$1 [y/N] " reply </dev/tty
|
||||||
|
else
|
||||||
|
# No terminal available — default to no (safe)
|
||||||
|
echo "$1 [y/N] N"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
[[ "$reply" =~ ^[Yy]$ ]]
|
[[ "$reply" =~ ^[Yy]$ ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try to install a single binary tool via a given command
|
# ── Error trap ────────────────────────────────────────────────────────────────
|
||||||
# Usage: try_install <display_name> <check_cmd> <install_cmd...>
|
on_error() {
|
||||||
try_install() {
|
local line="${BASH_LINENO[0]}"
|
||||||
local name="$1"; local check="$2"; shift 2
|
echo -e "\n${RED}[FATAL]${NC} Unexpected error at line $line." >&2
|
||||||
if command -v "$check" >/dev/null 2>&1; then
|
echo " To get a full debug log:" >&2
|
||||||
ok "$name (already installed: $(command -v "$check"))"
|
echo " ./install.sh 2>&1 | tee /tmp/chopsticks-install.log" >&2
|
||||||
|
echo " Report issues: https://github.com/m1ngsama/chopsticks/issues" >&2
|
||||||
|
}
|
||||||
|
trap on_error ERR
|
||||||
|
|
||||||
|
# Cleanup temp files on exit
|
||||||
|
trap 'rm -f /tmp/chopsticks-hadolint /tmp/chopsticks-marksman 2>/dev/null' EXIT
|
||||||
|
|
||||||
|
# ── Safe download helper ──────────────────────────────────────────────────────
|
||||||
|
# safe_download <url> <dest>
|
||||||
|
# Returns 1 if download fails or file is empty / HTML error page
|
||||||
|
safe_download() {
|
||||||
|
local url="$1" dest="$2"
|
||||||
|
curl -fsSL --connect-timeout 15 --retry 3 "$url" -o "$dest" 2>/dev/null || return 1
|
||||||
|
# Reject empty files
|
||||||
|
[[ -s "$dest" ]] || { rm -f "$dest"; return 1; }
|
||||||
|
# Reject HTML error pages (GitHub 404, rate limits, etc.)
|
||||||
|
if head -c 200 "$dest" 2>/dev/null | grep -qi "<!DOCTYPE\|<html"; then
|
||||||
|
rm -f "$dest"; return 1
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Cross-platform package install helper ─────────────────────────────────────
|
||||||
|
# pkg_install <brew> <apt> <pacman> <dnf> (pass "" to skip that pkg manager)
|
||||||
|
pkg_install() {
|
||||||
|
local brew_pkg="${1:-}" apt_pkg="${2:-}" pac_pkg="${3:-}" dnf_pkg="${4:-}"
|
||||||
|
if [[ $HAS_BREW -eq 1 && -n "$brew_pkg" ]]; then brew install "$brew_pkg" >/dev/null 2>&1
|
||||||
|
elif [[ $HAS_APT -eq 1 && -n "$apt_pkg" && $HAS_SUDO -eq 1 ]]; then sudo apt-get install -y "$apt_pkg" >/dev/null 2>&1
|
||||||
|
elif [[ $HAS_PACMAN -eq 1 && -n "$pac_pkg" && $HAS_SUDO -eq 1 ]]; then sudo pacman -S --noconfirm "$pac_pkg" >/dev/null 2>&1
|
||||||
|
elif [[ $HAS_DNF -eq 1 && -n "$dnf_pkg" && $HAS_SUDO -eq 1 ]]; then sudo dnf install -y "$dnf_pkg" >/dev/null 2>&1
|
||||||
|
else return 1
|
||||||
fi
|
fi
|
||||||
if "$@" >/dev/null 2>&1; then
|
}
|
||||||
ok "$name"
|
|
||||||
INSTALLED+=("$name")
|
# ── CPU architecture normalizer ───────────────────────────────────────────────
|
||||||
else
|
# Normalize uname -m to the naming convention used by GitHub releases
|
||||||
fail "$name — install failed (run manually: $*)"
|
arch_github() {
|
||||||
FAILED+=("$name")
|
case "$(uname -m)" in
|
||||||
fi
|
x86_64) echo "x86_64" ;;
|
||||||
|
aarch64|arm64) echo "arm64" ;;
|
||||||
|
armv7l) echo "armv7" ;;
|
||||||
|
*) echo "$(uname -m)" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
arch_linux_x64() {
|
||||||
|
# Returns x64 or arm64 style (used by marksman)
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64) echo "x64" ;;
|
||||||
|
aarch64|arm64) echo "arm64" ;;
|
||||||
|
*) echo "$(uname -m)" ;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
echo -e "${BOLD}chopsticks — Vim Configuration Installer${NC}"
|
echo -e "${BOLD}chopsticks — Vim Configuration Installer${NC}"
|
||||||
echo "----------------------------------------"
|
echo "----------------------------------------"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Preflight
|
# 1. OS + Package Manager Detection
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "Checking environment"
|
step "Detecting environment"
|
||||||
|
|
||||||
[ -f "$SCRIPT_DIR/.vimrc" ] || die ".vimrc not found in $SCRIPT_DIR"
|
|
||||||
|
|
||||||
command -v vim >/dev/null 2>&1 || die "vim not found.
|
|
||||||
Ubuntu/Debian: sudo apt install vim
|
|
||||||
Fedora: sudo dnf install vim
|
|
||||||
macOS: brew install vim"
|
|
||||||
|
|
||||||
VIM_VERSION=$(vim --version | head -n1)
|
|
||||||
ok "Found $VIM_VERSION"
|
|
||||||
|
|
||||||
vim --version | grep -q 'Vi IMproved 8\|Vi IMproved 9' || \
|
|
||||||
warn "Vim 8.0+ recommended for full LSP support."
|
|
||||||
|
|
||||||
# Detect OS
|
|
||||||
OS="unknown"
|
OS="unknown"
|
||||||
if [[ "$OSTYPE" == darwin* ]]; then
|
if [[ "$OSTYPE" == darwin* ]]; then
|
||||||
OS="macos"
|
OS="macos"
|
||||||
|
|
@ -88,89 +130,258 @@ elif [[ -f /etc/arch-release ]]; then
|
||||||
fi
|
fi
|
||||||
ok "OS: $OS"
|
ok "OS: $OS"
|
||||||
|
|
||||||
# Detect package managers
|
|
||||||
HAS_BREW=0; command -v brew >/dev/null 2>&1 && HAS_BREW=1
|
HAS_BREW=0; command -v brew >/dev/null 2>&1 && HAS_BREW=1
|
||||||
HAS_APT=0; command -v apt >/dev/null 2>&1 && HAS_APT=1
|
HAS_APT=0; command -v apt >/dev/null 2>&1 && HAS_APT=1
|
||||||
HAS_DNF=0; command -v dnf >/dev/null 2>&1 && HAS_DNF=1
|
HAS_DNF=0; command -v dnf >/dev/null 2>&1 && HAS_DNF=1
|
||||||
HAS_PACMAN=0; command -v pacman >/dev/null 2>&1 && HAS_PACMAN=1
|
HAS_PACMAN=0; command -v pacman >/dev/null 2>&1 && HAS_PACMAN=1
|
||||||
HAS_NODE=0; command -v node >/dev/null 2>&1 && HAS_NODE=1 && ok "Node.js $(node --version) detected"
|
|
||||||
|
# ── sudo ─────────────────────────────────────────────────────────────────────
|
||||||
|
HAS_SUDO=0
|
||||||
|
if [[ $OS == "macos" ]]; then
|
||||||
|
# brew handles its own privilege escalation; no sudo needed for system tools
|
||||||
|
HAS_SUDO=1
|
||||||
|
elif sudo -n true 2>/dev/null; then
|
||||||
|
HAS_SUDO=1
|
||||||
|
ok "sudo: available (passwordless)"
|
||||||
|
elif [[ $AUTO_YES -eq 1 ]]; then
|
||||||
|
warn "sudo requires a password but running non-interactively (--yes)"
|
||||||
|
warn "System package installations will be skipped"
|
||||||
|
else
|
||||||
|
# Prompt once for password now so later sudo calls don't interrupt flow
|
||||||
|
warn "Some steps require sudo. Authenticating now..."
|
||||||
|
if sudo true; then
|
||||||
|
HAS_SUDO=1
|
||||||
|
ok "sudo: authenticated"
|
||||||
|
else
|
||||||
|
warn "sudo not available — system package installations will be skipped"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Network ──────────────────────────────────────────────────────────────────
|
||||||
|
if curl -fsSL --connect-timeout 5 https://github.com -o /dev/null 2>/dev/null; then
|
||||||
|
ok "Network: github.com reachable"
|
||||||
|
else
|
||||||
|
warn "Network: cannot reach github.com — plugin and binary downloads may fail"
|
||||||
|
warn "Check your internet connection or proxy settings before continuing"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Homebrew (macOS) ─────────────────────────────────────────────────────────
|
||||||
|
if [[ $OS == "macos" && $HAS_BREW -eq 0 ]]; then
|
||||||
|
warn "Homebrew not found — it is the recommended package manager for macOS"
|
||||||
|
if ask "Install Homebrew now? (strongly recommended — required for system tools)"; then
|
||||||
|
info "This may take a few minutes and will prompt for your password..."
|
||||||
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || \
|
||||||
|
die "Homebrew installation failed. Install manually: https://brew.sh"
|
||||||
|
# Source brew for Apple Silicon and Intel paths
|
||||||
|
for brew_path in /opt/homebrew/bin/brew /usr/local/bin/brew; do
|
||||||
|
[[ -x "$brew_path" ]] && eval "$("$brew_path" shellenv)" && break
|
||||||
|
done
|
||||||
|
command -v brew >/dev/null 2>&1 && HAS_BREW=1 && ok "Homebrew installed"
|
||||||
|
else
|
||||||
|
warn "Homebrew skipped — system tools (ripgrep, fzf, etc.) will be unavailable"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── curl ─────────────────────────────────────────────────────────────────────
|
||||||
|
if ! command -v curl >/dev/null 2>&1; then
|
||||||
|
warn "curl not found — required to download plugins and tools"
|
||||||
|
if pkg_install curl curl curl curl 2>/dev/null; then
|
||||||
|
ok "curl installed"
|
||||||
|
else
|
||||||
|
die "curl is required but could not be installed automatically.
|
||||||
|
Ubuntu/Debian: sudo apt install curl
|
||||||
|
Arch: sudo pacman -S curl
|
||||||
|
Fedora: sudo dnf install curl
|
||||||
|
macOS: brew install curl"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── git ──────────────────────────────────────────────────────────────────────
|
||||||
|
if ! command -v git >/dev/null 2>&1; then
|
||||||
|
warn "git not found — required for vim-plug to install plugins"
|
||||||
|
if pkg_install git git git git 2>/dev/null; then
|
||||||
|
ok "git installed"
|
||||||
|
else
|
||||||
|
die "git is required but could not be installed automatically.
|
||||||
|
Ubuntu/Debian: sudo apt install git
|
||||||
|
Arch: sudo pacman -S git
|
||||||
|
Fedora: sudo dnf install git
|
||||||
|
macOS: brew install git (or: xcode-select --install)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── vim ──────────────────────────────────────────────────────────────────────
|
||||||
|
[ -f "$SCRIPT_DIR/.vimrc" ] || die ".vimrc not found in $SCRIPT_DIR — is this the chopsticks repo?"
|
||||||
|
|
||||||
|
if ! command -v vim >/dev/null 2>&1; then
|
||||||
|
warn "vim not found — attempting to install"
|
||||||
|
if pkg_install vim vim vim vim 2>/dev/null; then
|
||||||
|
ok "vim installed"
|
||||||
|
else
|
||||||
|
die "vim not found and could not be installed automatically.
|
||||||
|
Ubuntu/Debian: sudo apt install vim
|
||||||
|
Arch: sudo pacman -S vim
|
||||||
|
Fedora: sudo dnf install vim
|
||||||
|
macOS: brew install vim"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
VIM_VERSION=$(vim --version | head -n1)
|
||||||
|
ok "Found: $VIM_VERSION"
|
||||||
|
|
||||||
|
vim --version | grep -q 'Vi IMproved 8\|Vi IMproved 9' || \
|
||||||
|
warn "Vim 8.0+ recommended for full async/LSP support — some features may not work"
|
||||||
|
|
||||||
|
# ── Node.js ──────────────────────────────────────────────────────────────────
|
||||||
|
HAS_NODE=0; command -v node >/dev/null 2>&1 && HAS_NODE=1
|
||||||
|
|
||||||
|
if [[ $HAS_NODE -eq 0 ]]; then
|
||||||
|
warn "Node.js not found — CoC LSP and npm-based formatters will be unavailable"
|
||||||
|
info "Without Node.js, the config falls back to vim-lsp (pure VimScript)."
|
||||||
|
info ""
|
||||||
|
info "Install options:"
|
||||||
|
info " nvm (recommended): curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/install.sh | bash"
|
||||||
|
info " macOS: brew install node"
|
||||||
|
info " Ubuntu/Debian: curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -"
|
||||||
|
info " sudo apt-get install -y nodejs"
|
||||||
|
info " Arch: sudo pacman -S nodejs npm"
|
||||||
|
info ""
|
||||||
|
if ask "Install Node.js via nvm now? (recommended — manages multiple Node versions)"; then
|
||||||
|
info "Fetching latest nvm release..."
|
||||||
|
NVM_VER=$(curl -fsSL https://api.github.com/repos/nvm-sh/nvm/releases/latest \
|
||||||
|
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || NVM_VER="v0.40.1"
|
||||||
|
[[ -z "$NVM_VER" ]] && NVM_VER="v0.40.1"
|
||||||
|
info "Installing nvm $NVM_VER + Node.js LTS..."
|
||||||
|
if curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VER}/install.sh" | bash >/dev/null 2>&1; then
|
||||||
|
export NVM_DIR="$HOME/.nvm"
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
|
if command -v nvm >/dev/null 2>&1; then
|
||||||
|
nvm install --lts >/dev/null 2>&1 && nvm use --lts >/dev/null 2>&1 || true
|
||||||
|
command -v node >/dev/null 2>&1 && HAS_NODE=1 && ok "Node.js $(node --version) installed via nvm"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ $HAS_NODE -eq 0 ]]; then
|
||||||
|
warn "nvm install failed — CoC and npm tools will be skipped"
|
||||||
|
warn "After manually installing Node.js, re-run: ./install.sh"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
skip "Node.js — config will use vim-lsp fallback (no Node.js required)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ok "Node.js $(node --version) found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Python3 ──────────────────────────────────────────────────────────────────
|
||||||
HAS_PYTHON=0; command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1
|
HAS_PYTHON=0; command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1
|
||||||
HAS_PIP=0; command -v pip3 >/dev/null 2>&1 && HAS_PIP=1
|
HAS_PIP=0; command -v pip3 >/dev/null 2>&1 && HAS_PIP=1
|
||||||
HAS_GO=0; command -v go >/dev/null 2>&1 && HAS_GO=1 && ok "Go $(go version | awk '{print $3}') detected"
|
|
||||||
|
|
||||||
# Bootstrap pip3 when python3 exists but pip3 is absent (common on Ubuntu minimal images)
|
if [[ $HAS_PYTHON -eq 0 ]]; then
|
||||||
|
warn "python3 not found — Python formatters/linters will be unavailable"
|
||||||
|
if ask "Install Python 3?"; then
|
||||||
|
if pkg_install python3 python3 python3 python3 2>/dev/null; then
|
||||||
|
command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1 && ok "Python3 installed"
|
||||||
|
else
|
||||||
|
warn "Python3 install failed — Python tools will be skipped"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
skip "Python3"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bootstrap pip3 when python3 exists but pip3 is absent (common on Ubuntu minimal)
|
||||||
if [[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]]; then
|
if [[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]]; then
|
||||||
warn "python3 found but pip3 missing — attempting bootstrap"
|
warn "python3 found but pip3 missing — attempting bootstrap"
|
||||||
if python3 -m ensurepip --upgrade >/dev/null 2>&1 || \
|
if python3 -m ensurepip --upgrade >/dev/null 2>&1 || \
|
||||||
(command -v apt-get >/dev/null 2>&1 && sudo apt-get install -y python3-pip >/dev/null 2>&1) || \
|
pkg_install python3-pip python3-pip python-pip python3-pip >/dev/null 2>&1; then
|
||||||
(command -v pacman >/dev/null 2>&1 && sudo pacman -S --noconfirm python-pip >/dev/null 2>&1) || \
|
|
||||||
(command -v dnf >/dev/null 2>&1 && sudo dnf install -y python3-pip >/dev/null 2>&1); then
|
|
||||||
command -v pip3 >/dev/null 2>&1 && HAS_PIP=1 && ok "pip3 bootstrapped"
|
command -v pip3 >/dev/null 2>&1 && HAS_PIP=1 && ok "pip3 bootstrapped"
|
||||||
else
|
else
|
||||||
warn "pip3 bootstrap failed — Python tools will be skipped"
|
warn "pip3 bootstrap failed — Python tools will be skipped"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ $HAS_PIP -eq 1 ]] && ok "Python/pip3 detected"
|
[[ $HAS_PIP -eq 1 ]] && ok "Python/pip3 found"
|
||||||
[[ $HAS_NODE -eq 0 ]] && warn "Node.js not found — JS/TS/Markdown npm tools will be skipped"
|
[[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]] && warn "pip3 not available — Python tools will be skipped"
|
||||||
[[ $HAS_PIP -eq 0 ]] && warn "pip3 not found — Python tools will be skipped"
|
|
||||||
[[ $HAS_GO -eq 0 ]] && warn "Go not found — Go tools will be skipped"
|
# ── Go ───────────────────────────────────────────────────────────────────────
|
||||||
|
HAS_GO=0; command -v go >/dev/null 2>&1 && HAS_GO=1
|
||||||
|
[[ $HAS_GO -eq 1 ]] && ok "Go $(go version | awk '{print $3}') found"
|
||||||
|
[[ $HAS_GO -eq 0 ]] && warn "Go not found — Go tools will be skipped (see https://go.dev/dl/)"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Symlink
|
# 2. Symlinks
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "Setting up ~/.vimrc symlink"
|
step "Setting up symlinks"
|
||||||
|
|
||||||
if [ -f "$HOME/.vimrc" ] && [ ! -L "$HOME/.vimrc" ]; then
|
if [ -f "$HOME/.vimrc" ] && [ ! -L "$HOME/.vimrc" ]; then
|
||||||
TS=$(date +%Y%m%d_%H%M%S)
|
TS=$(date +%Y%m%d_%H%M%S)
|
||||||
warn "Backing up existing ~/.vimrc to ~/.vimrc.backup.$TS"
|
warn "Backing up existing ~/.vimrc → ~/.vimrc.backup.$TS"
|
||||||
mv "$HOME/.vimrc" "$HOME/.vimrc.backup.$TS"
|
mv "$HOME/.vimrc" "$HOME/.vimrc.backup.$TS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ln -sf "$SCRIPT_DIR/.vimrc" "$HOME/.vimrc"
|
ln -sf "$SCRIPT_DIR/.vimrc" "$HOME/.vimrc"
|
||||||
ok "~/.vimrc -> $SCRIPT_DIR/.vimrc"
|
# Verify symlink
|
||||||
|
[[ -L "$HOME/.vimrc" ]] && ok "~/.vimrc → $SCRIPT_DIR/.vimrc" || die "Failed to create ~/.vimrc symlink"
|
||||||
|
|
||||||
# CoC settings (marksman markdown LSP + format-on-save config)
|
|
||||||
mkdir -p "$HOME/.vim"
|
mkdir -p "$HOME/.vim"
|
||||||
COC_CFG="$HOME/.vim/coc-settings.json"
|
COC_CFG="$HOME/.vim/coc-settings.json"
|
||||||
if [ -f "$COC_CFG" ] && [ ! -L "$COC_CFG" ]; then
|
if [ -f "$COC_CFG" ] && [ ! -L "$COC_CFG" ]; then
|
||||||
TS=$(date +%Y%m%d_%H%M%S)
|
TS=$(date +%Y%m%d_%H%M%S)
|
||||||
warn "Backing up existing coc-settings.json to ~/.vim/coc-settings.json.backup.$TS"
|
warn "Backing up existing coc-settings.json → ~/.vim/coc-settings.json.backup.$TS"
|
||||||
mv "$COC_CFG" "$COC_CFG.backup.$TS"
|
mv "$COC_CFG" "$COC_CFG.backup.$TS"
|
||||||
fi
|
fi
|
||||||
ln -sf "$SCRIPT_DIR/coc-settings.json" "$COC_CFG"
|
ln -sf "$SCRIPT_DIR/coc-settings.json" "$COC_CFG"
|
||||||
ok "~/.vim/coc-settings.json -> $SCRIPT_DIR/coc-settings.json"
|
[[ -L "$COC_CFG" ]] && ok "~/.vim/coc-settings.json → $SCRIPT_DIR/coc-settings.json" || warn "coc-settings.json symlink failed (non-fatal)"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# vim-plug + plugins
|
# 3. vim-plug + Plugins
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "Installing vim-plug"
|
step "Installing vim-plug"
|
||||||
|
|
||||||
VIM_PLUG="$HOME/.vim/autoload/plug.vim"
|
VIM_PLUG="$HOME/.vim/autoload/plug.vim"
|
||||||
if [ ! -f "$VIM_PLUG" ]; then
|
if [ ! -f "$VIM_PLUG" ]; then
|
||||||
curl -fLo "$VIM_PLUG" --create-dirs \
|
mkdir -p "$HOME/.vim/autoload"
|
||||||
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
|
if safe_download "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" "$VIM_PLUG"; then
|
||||||
ok "vim-plug installed"
|
ok "vim-plug downloaded"
|
||||||
|
else
|
||||||
|
# Fallback: git clone
|
||||||
|
warn "curl download failed — trying git clone fallback"
|
||||||
|
if git clone --depth=1 https://github.com/junegunn/vim-plug.git /tmp/vim-plug-src 2>/dev/null; then
|
||||||
|
cp /tmp/vim-plug-src/plug.vim "$VIM_PLUG" && rm -rf /tmp/vim-plug-src
|
||||||
|
ok "vim-plug installed (via git)"
|
||||||
|
else
|
||||||
|
die "vim-plug installation failed. Check your network connection and try again."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
[[ -s "$VIM_PLUG" ]] || die "vim-plug file is empty after download — aborting"
|
||||||
else
|
else
|
||||||
ok "vim-plug already present"
|
ok "vim-plug already present"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
step "Installing Vim plugins"
|
step "Installing Vim plugins"
|
||||||
|
info "(Vim will open fullscreen to install plugins — screen may go dark for 10-30s, this is normal)"
|
||||||
# </dev/null prevents Vim from reading stdin in non-interactive/piped environments
|
# </dev/null prevents Vim from reading stdin in non-interactive/piped environments
|
||||||
vim +PlugInstall +qall </dev/null
|
if ! vim +PlugInstall +qall </dev/null; then
|
||||||
ok "Plugins installed"
|
warn "vim +PlugInstall exited non-zero — plugins may be partially installed"
|
||||||
|
warn "Run :PlugInstall manually inside Vim if something looks wrong"
|
||||||
|
else
|
||||||
|
ok "Plugins installed"
|
||||||
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# System tools (ripgrep, fzf, ctags, shellcheck, marksman)
|
# 4. System Tools
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "System tools"
|
step "System tools"
|
||||||
|
|
||||||
if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)?"; then
|
if [[ $OS == "macos" && $HAS_BREW -eq 0 ]]; then
|
||||||
|
skip "system tools (Homebrew not available — install brew first, then re-run)"
|
||||||
|
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||||
|
elif ask "Install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)?"; then
|
||||||
|
|
||||||
install_sys() {
|
install_sys() {
|
||||||
local name="$1"; local check="$2"; shift 2
|
local name="$1" check="$2"; shift 2
|
||||||
if command -v "$check" >/dev/null 2>&1; then
|
if command -v "$check" >/dev/null 2>&1; then
|
||||||
ok "$name (already installed)"
|
ok "$name (already installed)"
|
||||||
return
|
return
|
||||||
|
|
@ -180,92 +391,110 @@ if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksma
|
||||||
if eval "$cmd" >/dev/null 2>&1; then installed=1; break; fi
|
if eval "$cmd" >/dev/null 2>&1; then installed=1; break; fi
|
||||||
done
|
done
|
||||||
if [[ $installed -eq 1 ]]; then
|
if [[ $installed -eq 1 ]]; then
|
||||||
ok "$name"
|
ok "$name"; INSTALLED+=("$name")
|
||||||
INSTALLED+=("$name")
|
|
||||||
else
|
else
|
||||||
fail "$name — could not install automatically"
|
fail "$name — could not install automatically (install manually)"
|
||||||
FAILED+=("$name")
|
FAILED+=("$name")
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $OS == macos ]]; then
|
if [[ $OS == "macos" ]]; then
|
||||||
command -v brew >/dev/null 2>&1 || { warn "brew not found — skipping system tools"; }
|
|
||||||
install_sys "ripgrep" rg "brew install ripgrep"
|
install_sys "ripgrep" rg "brew install ripgrep"
|
||||||
install_sys "fzf" fzf "brew install fzf"
|
install_sys "fzf" fzf "brew install fzf"
|
||||||
install_sys "universal-ctags" ctags "brew install universal-ctags"
|
install_sys "universal-ctags" ctags "brew install universal-ctags"
|
||||||
install_sys "shellcheck" shellcheck "brew install shellcheck"
|
install_sys "shellcheck" shellcheck "brew install shellcheck"
|
||||||
install_sys "hadolint" hadolint "brew install hadolint"
|
install_sys "hadolint" hadolint "brew install hadolint"
|
||||||
install_sys "marksman" marksman "brew install marksman"
|
install_sys "marksman" marksman "brew install marksman"
|
||||||
|
|
||||||
elif [[ $HAS_APT -eq 1 ]]; then
|
elif [[ $HAS_APT -eq 1 ]]; then
|
||||||
|
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||||
|
warn "No sudo — skipping apt system tools"
|
||||||
|
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||||
|
else
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
install_sys "ripgrep" rg "sudo apt-get install -y ripgrep"
|
install_sys "ripgrep" rg "sudo apt-get install -y ripgrep"
|
||||||
install_sys "fzf" fzf "sudo apt-get install -y fzf"
|
install_sys "fzf" fzf "sudo apt-get install -y fzf"
|
||||||
install_sys "universal-ctags" ctags "sudo apt-get install -y universal-ctags"
|
install_sys "universal-ctags" ctags "sudo apt-get install -y universal-ctags"
|
||||||
install_sys "shellcheck" shellcheck "sudo apt-get install -y shellcheck"
|
install_sys "shellcheck" shellcheck "sudo apt-get install -y shellcheck"
|
||||||
# hadolint: no apt package, download binary
|
|
||||||
if ! command -v hadolint >/dev/null 2>&1; then
|
# hadolint: no apt package — download binary from GitHub releases
|
||||||
ARCH=$(uname -m)
|
if command -v hadolint >/dev/null 2>&1; then
|
||||||
[[ "$ARCH" == "x86_64" ]] && HARCH="x86_64" || HARCH="arm64"
|
|
||||||
HVER=$(curl -s https://api.github.com/repos/hadolint/hadolint/releases/latest \
|
|
||||||
| grep '"tag_name"' | cut -d'"' -f4)
|
|
||||||
if [[ -n "$HVER" ]]; then
|
|
||||||
curl -fsSL "https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \
|
|
||||||
-o /tmp/hadolint && chmod +x /tmp/hadolint && sudo mv /tmp/hadolint /usr/local/bin/hadolint
|
|
||||||
ok "hadolint"
|
|
||||||
INSTALLED+=("hadolint")
|
|
||||||
else
|
|
||||||
warn "hadolint: could not detect latest release, install manually"
|
|
||||||
SKIPPED+=("hadolint")
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
ok "hadolint (already installed)"
|
ok "hadolint (already installed)"
|
||||||
fi
|
|
||||||
# marksman: no apt package, download binary
|
|
||||||
if ! command -v marksman >/dev/null 2>&1; then
|
|
||||||
ARCH=$(uname -m)
|
|
||||||
[[ "$ARCH" == "x86_64" ]] && MARCH="x64" || MARCH="arm64"
|
|
||||||
MVER=$(curl -s https://api.github.com/repos/artempyanykh/marksman/releases/latest \
|
|
||||||
| grep '"tag_name"' | cut -d'"' -f4)
|
|
||||||
if [[ -n "$MVER" ]]; then
|
|
||||||
curl -fsSL "https://github.com/artempyanykh/marksman/releases/download/${MVER}/marksman-linux-${MARCH}" \
|
|
||||||
-o /tmp/marksman && chmod +x /tmp/marksman && sudo mv /tmp/marksman /usr/local/bin/marksman
|
|
||||||
ok "marksman"
|
|
||||||
INSTALLED+=("marksman")
|
|
||||||
else
|
else
|
||||||
warn "marksman: could not detect latest release, install manually"
|
HARCH=$(arch_github)
|
||||||
SKIPPED+=("marksman")
|
HVER=$(curl -fsSL https://api.github.com/repos/hadolint/hadolint/releases/latest \
|
||||||
fi
|
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || HVER=""
|
||||||
|
if [[ -n "$HVER" ]] && safe_download \
|
||||||
|
"https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \
|
||||||
|
/tmp/chopsticks-hadolint; then
|
||||||
|
chmod +x /tmp/chopsticks-hadolint && sudo mv /tmp/chopsticks-hadolint /usr/local/bin/hadolint
|
||||||
|
ok "hadolint"; INSTALLED+=("hadolint")
|
||||||
else
|
else
|
||||||
|
fail "hadolint — download failed (install manually: https://github.com/hadolint/hadolint/releases)"
|
||||||
|
FAILED+=("hadolint")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# marksman: no apt package — download binary from GitHub releases
|
||||||
|
if command -v marksman >/dev/null 2>&1; then
|
||||||
ok "marksman (already installed)"
|
ok "marksman (already installed)"
|
||||||
|
else
|
||||||
|
MARCH=$(arch_linux_x64)
|
||||||
|
MVER=$(curl -fsSL https://api.github.com/repos/artempyanykh/marksman/releases/latest \
|
||||||
|
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || MVER=""
|
||||||
|
if [[ -n "$MVER" ]] && safe_download \
|
||||||
|
"https://github.com/artempyanykh/marksman/releases/download/${MVER}/marksman-linux-${MARCH}" \
|
||||||
|
/tmp/chopsticks-marksman; then
|
||||||
|
chmod +x /tmp/chopsticks-marksman && sudo mv /tmp/chopsticks-marksman /usr/local/bin/marksman
|
||||||
|
ok "marksman"; INSTALLED+=("marksman")
|
||||||
|
else
|
||||||
|
fail "marksman — download failed (install manually: https://github.com/artempyanykh/marksman/releases)"
|
||||||
|
FAILED+=("marksman")
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
elif [[ $HAS_PACMAN -eq 1 ]]; then
|
elif [[ $HAS_PACMAN -eq 1 ]]; then
|
||||||
|
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||||
|
warn "No sudo — skipping pacman system tools"
|
||||||
|
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||||
|
else
|
||||||
install_sys "ripgrep" rg "sudo pacman -S --noconfirm ripgrep"
|
install_sys "ripgrep" rg "sudo pacman -S --noconfirm ripgrep"
|
||||||
install_sys "fzf" fzf "sudo pacman -S --noconfirm fzf"
|
install_sys "fzf" fzf "sudo pacman -S --noconfirm fzf"
|
||||||
install_sys "universal-ctags" ctags "sudo pacman -S --noconfirm ctags"
|
install_sys "universal-ctags" ctags "sudo pacman -S --noconfirm ctags"
|
||||||
install_sys "shellcheck" shellcheck "sudo pacman -S --noconfirm shellcheck"
|
install_sys "shellcheck" shellcheck "sudo pacman -S --noconfirm shellcheck"
|
||||||
install_sys "hadolint" hadolint "sudo pacman -S --noconfirm hadolint"
|
install_sys "hadolint" hadolint "sudo pacman -S --noconfirm hadolint"
|
||||||
install_sys "marksman" marksman "sudo pacman -S --noconfirm marksman"
|
install_sys "marksman" marksman "sudo pacman -S --noconfirm marksman"
|
||||||
|
fi
|
||||||
|
|
||||||
elif [[ $HAS_DNF -eq 1 ]]; then
|
elif [[ $HAS_DNF -eq 1 ]]; then
|
||||||
|
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||||
|
warn "No sudo — skipping dnf system tools"
|
||||||
|
SKIPPED+=("ripgrep" "fzf" "shellcheck" "ctags" "hadolint" "marksman")
|
||||||
|
else
|
||||||
install_sys "ripgrep" rg "sudo dnf install -y ripgrep"
|
install_sys "ripgrep" rg "sudo dnf install -y ripgrep"
|
||||||
install_sys "fzf" fzf "sudo dnf install -y fzf"
|
install_sys "fzf" fzf "sudo dnf install -y fzf"
|
||||||
install_sys "shellcheck" shellcheck "sudo dnf install -y ShellCheck"
|
install_sys "shellcheck" shellcheck "sudo dnf install -y ShellCheck"
|
||||||
skip "universal-ctags — install manually: sudo dnf install ctags"
|
skip "universal-ctags — install manually: sudo dnf install ctags"
|
||||||
SKIPPED+=("ctags")
|
SKIPPED+=("ctags")
|
||||||
skip "hadolint — install manually from https://github.com/hadolint/hadolint/releases"
|
skip "hadolint — install manually: https://github.com/hadolint/hadolint/releases"
|
||||||
SKIPPED+=("hadolint")
|
SKIPPED+=("hadolint")
|
||||||
skip "marksman — install manually from https://github.com/artempyanykh/marksman/releases"
|
skip "marksman — install manually: https://github.com/artempyanykh/marksman/releases"
|
||||||
SKIPPED+=("marksman")
|
SKIPPED+=("marksman")
|
||||||
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
warn "Unknown Linux distro — skipping system tools (install manually)"
|
warn "Unknown distro — skipping system tools (install manually)"
|
||||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
skip "system tools"
|
skip "system tools"
|
||||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# npm tools (prettier, markdownlint-cli, stylelint, eslint, typescript)
|
# 5. npm tools
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "npm tools (formatters + linters)"
|
step "npm tools (formatters + linters)"
|
||||||
|
|
@ -275,15 +504,12 @@ if [[ $HAS_NODE -eq 1 ]]; then
|
||||||
npm_install() {
|
npm_install() {
|
||||||
local pkg="$1"; local check="${2:-$1}"
|
local pkg="$1"; local check="${2:-$1}"
|
||||||
if command -v "$check" >/dev/null 2>&1; then
|
if command -v "$check" >/dev/null 2>&1; then
|
||||||
ok "$pkg (already installed)"
|
ok "$pkg (already installed)"; return
|
||||||
return
|
|
||||||
fi
|
fi
|
||||||
if npm install -g "$pkg" >/dev/null 2>&1; then
|
if npm install -g "$pkg" >/dev/null 2>&1; then
|
||||||
ok "$pkg"
|
ok "$pkg"; INSTALLED+=("$pkg")
|
||||||
INSTALLED+=("$pkg")
|
|
||||||
else
|
else
|
||||||
fail "$pkg"
|
fail "$pkg"; FAILED+=("$pkg")
|
||||||
FAILED+=("$pkg")
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
npm_install prettier
|
npm_install prettier
|
||||||
|
|
@ -302,7 +528,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# pip tools (black, isort, flake8, pylint, sqlfluff)
|
# 6. Python tools
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "Python tools (formatters + linters)"
|
step "Python tools (formatters + linters)"
|
||||||
|
|
@ -312,16 +538,13 @@ if [[ $HAS_PIP -eq 1 ]]; then
|
||||||
pip_install() {
|
pip_install() {
|
||||||
local pkg="$1"; local check="${2:-$1}"
|
local pkg="$1"; local check="${2:-$1}"
|
||||||
if command -v "$check" >/dev/null 2>&1; then
|
if command -v "$check" >/dev/null 2>&1; then
|
||||||
ok "$pkg (already installed)"
|
ok "$pkg (already installed)"; return
|
||||||
return
|
|
||||||
fi
|
fi
|
||||||
if pip3 install --quiet "$pkg" 2>/dev/null || \
|
if pip3 install --quiet "$pkg" 2>/dev/null || \
|
||||||
pip3 install --quiet --break-system-packages "$pkg" 2>/dev/null; then
|
pip3 install --quiet --break-system-packages "$pkg" 2>/dev/null; then
|
||||||
ok "$pkg"
|
ok "$pkg"; INSTALLED+=("$pkg")
|
||||||
INSTALLED+=("$pkg")
|
|
||||||
else
|
else
|
||||||
fail "$pkg"
|
fail "$pkg"; FAILED+=("$pkg")
|
||||||
FAILED+=("$pkg")
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
pip_install black
|
pip_install black
|
||||||
|
|
@ -340,65 +563,94 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Go tools (gopls, goimports, staticcheck)
|
# 7. Go tools
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "Go tools"
|
step "Go tools"
|
||||||
|
|
||||||
if [[ $HAS_GO -eq 1 ]]; then
|
if [[ $HAS_GO -eq 1 ]]; then
|
||||||
if ask "Install Go tools (gopls, goimports, staticcheck)?"; then
|
if ask "Install Go tools (gopls, goimports, staticcheck)?"; then
|
||||||
# Go installs binaries to $(go env GOPATH)/bin — add to PATH for this session
|
|
||||||
GOBIN="$(go env GOPATH)/bin"
|
GOBIN="$(go env GOPATH)/bin"
|
||||||
export PATH="$PATH:$GOBIN"
|
export PATH="$PATH:$GOBIN"
|
||||||
|
|
||||||
go_install() {
|
go_install() {
|
||||||
local name="$1"; local pkg="$2"; local check="$3"
|
local name="$1" pkg="$2" check="$3"
|
||||||
if command -v "$check" >/dev/null 2>&1 || [[ -x "$GOBIN/$check" ]]; then
|
if command -v "$check" >/dev/null 2>&1 || [[ -x "$GOBIN/$check" ]]; then
|
||||||
ok "$name (already installed)"
|
ok "$name (already installed)"; return
|
||||||
return
|
|
||||||
fi
|
fi
|
||||||
if go install "$pkg" >/dev/null 2>&1; then
|
if go install "$pkg" >/dev/null 2>&1; then
|
||||||
ok "$name"
|
ok "$name"; INSTALLED+=("$name")
|
||||||
INSTALLED+=("$name")
|
|
||||||
else
|
else
|
||||||
fail "$name"
|
fail "$name"; FAILED+=("$name")
|
||||||
FAILED+=("$name")
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
go_install gopls "golang.org/x/tools/gopls@latest" gopls
|
go_install gopls "golang.org/x/tools/gopls@latest" gopls
|
||||||
go_install goimports "golang.org/x/tools/cmd/goimports@latest" goimports
|
go_install goimports "golang.org/x/tools/cmd/goimports@latest" goimports
|
||||||
go_install staticcheck "honnef.co/go/tools/cmd/staticcheck@latest" staticcheck
|
go_install staticcheck "honnef.co/go/tools/cmd/staticcheck@latest" staticcheck
|
||||||
|
|
||||||
# Remind user to add GOPATH/bin to their shell profile
|
echo "$PATH" | grep -q "$GOBIN" || \
|
||||||
if ! echo "$PATH" | grep -q "$GOBIN"; then
|
|
||||||
warn "Add Go binaries to PATH: export PATH=\"\$PATH:$GOBIN\""
|
warn "Add Go binaries to PATH: export PATH=\"\$PATH:$GOBIN\""
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
skip "Go tools"
|
skip "Go tools"
|
||||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
skip "Go tools (go not installed)"
|
skip "Go tools (go not installed — see https://go.dev/dl/)"
|
||||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# CoC language server extensions
|
# 8. tmux: vim-tmux-navigator integration
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
step "tmux: vim-tmux-navigator integration"
|
||||||
|
|
||||||
|
if command -v tmux >/dev/null 2>&1; then
|
||||||
|
TMUX_CONF="$HOME/.tmux.conf"
|
||||||
|
if grep -q 'vim-tmux-navigator' "$TMUX_CONF" 2>/dev/null; then
|
||||||
|
ok "vim-tmux-navigator bindings already present in ~/.tmux.conf"
|
||||||
|
elif ask "Append vim-tmux-navigator bindings to ~/.tmux.conf (enables seamless Ctrl+h/j/k/l across vim and tmux)?"; then
|
||||||
|
cat >> "$TMUX_CONF" << 'TMUXEOF'
|
||||||
|
|
||||||
|
# vim-tmux-navigator: seamless Ctrl+h/j/k/l navigation between vim and tmux
|
||||||
|
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\S+\/)?g?(view|n?vim?x?)(diff)?$'"
|
||||||
|
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
|
||||||
|
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
|
||||||
|
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
|
||||||
|
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
|
||||||
|
TMUXEOF
|
||||||
|
ok "vim-tmux-navigator bindings appended to ~/.tmux.conf"
|
||||||
|
warn "Reload tmux config now: tmux source-file ~/.tmux.conf"
|
||||||
|
warn "Note: C-l now navigates panes instead of clearing the screen."
|
||||||
|
warn " To restore clear: add 'bind C-l send-keys C-l' to ~/.tmux.conf"
|
||||||
|
INSTALLED+=("tmux-navigator-config")
|
||||||
|
else
|
||||||
|
skip "tmux navigator config"
|
||||||
|
SKIPPED+=("tmux-navigator-config")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
skip "tmux not found — skipping navigator config"
|
||||||
|
SKIPPED+=("tmux-navigator-config")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 9. CoC language server extensions
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
step "CoC language server extensions"
|
step "CoC language server extensions"
|
||||||
|
|
||||||
if [[ $HAS_NODE -eq 1 ]]; then
|
if [[ $HAS_NODE -eq 1 ]]; then
|
||||||
if ask "Install CoC language servers (LSP for all configured languages)?"; then
|
if ask "Install CoC language servers (LSP for all configured languages)?"; then
|
||||||
|
info "(Downloading CoC extensions via npm — screen may go dark for 1-3 minutes, this is normal)"
|
||||||
# Note: coc-marksman doesn't exist on npm — markdown LSP is handled via coc-settings.json
|
# Note: coc-marksman doesn't exist on npm — markdown LSP is handled via coc-settings.json
|
||||||
vim +'CocInstall -sync coc-json coc-tsserver coc-pyright coc-sh coc-html coc-css coc-yaml coc-go coc-rust-analyzer coc-sql' +qall </dev/null
|
vim +'CocInstall -sync coc-json coc-tsserver coc-pyright coc-sh coc-html coc-css coc-yaml coc-go coc-rust-analyzer coc-sql' +qall </dev/null
|
||||||
ok "CoC language servers installed"
|
ok "CoC language servers installed"
|
||||||
else
|
else
|
||||||
skip "CoC language servers"
|
skip "CoC language servers"
|
||||||
echo " Install later with :CocInstall <name> inside Vim"
|
info "Install later with :CocInstall <name> inside Vim"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
warn "Node.js not found — using vim-lsp fallback (run :LspInstallServer inside Vim)"
|
warn "Node.js not found — using vim-lsp fallback (run :LspInstallServer inside Vim for each language)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
@ -421,8 +673,26 @@ fi
|
||||||
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
if [[ ${#FAILED[@]} -gt 0 ]]; then
|
||||||
echo -e "\n${RED}Failed (install manually):${NC}"
|
echo -e "\n${RED}Failed (install manually):${NC}"
|
||||||
for t in "${FAILED[@]}"; do echo " ! $t"; done
|
for t in "${FAILED[@]}"; do echo " ! $t"; done
|
||||||
|
echo ""
|
||||||
|
echo " To debug failures: ./install.sh 2>&1 | tee /tmp/chopsticks-install.log"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Run 'vim' and press ',' then wait 500ms for keybinding hints."
|
echo -e "${BOLD}---------------------------------------${NC}"
|
||||||
|
echo -e "${BOLD} You're ready. Open Vim with:${NC}"
|
||||||
|
echo -e "${BOLD}---------------------------------------${NC}"
|
||||||
|
echo -e " ${CYAN}vim${NC} Launch startup dashboard"
|
||||||
|
echo -e " ${CYAN}vim .${NC} Open file tree + dashboard"
|
||||||
|
echo -e " ${CYAN}vim myfile${NC} Edit a specific file"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BOLD} Survival Guide (first-time Vim users)${NC}"
|
||||||
|
echo -e " ${CYAN}Esc${NC} or ${CYAN}jk${NC} Exit insert mode → back to Normal"
|
||||||
|
echo -e " ${CYAN}:q!${NC} + Enter Emergency quit without saving"
|
||||||
|
echo -e " ${CYAN},x${NC} Save and quit"
|
||||||
|
echo -e " ${CYAN},?${NC} Open cheat sheet inside Vim"
|
||||||
|
echo -e " ${CYAN},${NC} + pause Interactive keybinding guide"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}[!]${NC} Ctrl+s is mapped to save in Vim."
|
||||||
|
echo " If it freezes your terminal, add this to ~/.bashrc or ~/.zshrc:"
|
||||||
|
echo -e " ${CYAN}stty -ixon${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue