install.sh: - set -eo pipefail + trap ERR with line number and debug hint - Network connectivity check before any downloads - curl and git preflight: auto-install or die with clear instructions - vim auto-install attempt before dying - sudo availability check (one-time auth, graceful skip when unavailable) - macOS: offer to install Homebrew if missing - Node.js: offer nvm install if missing (with fallback to vim-lsp) - Python3: offer install if missing - ask() reads from /dev/tty — interactive prompts work under curl | bash - safe_download(): verifies file non-empty and not an HTML error page - pkg_install(): unified cross-platform helper (brew/apt/pacman/dnf) - arch_github()/arch_linux_x64(): normalize uname -m (handles aarch64) - Temp files cleaned up via EXIT trap - Symlink creation verified after ln -sf - vim-plug: fallback to git clone if curl fails; verify file non-empty - vim +PlugInstall: warn on failure instead of silent continue - Binary downloads (hadolint, marksman) use named temp files get.sh (new): - One-command bootstrap: curl | bash - Installs git if missing - Clones repo to ~/.vim (or git pull if already present) - exec bash install.sh </dev/tty so interactive prompts work correctly |
||
|---|---|---|
| .gitignore | ||
| .vimrc | ||
| CHANGELOG.md | ||
| coc-settings.json | ||
| get.sh | ||
| install.sh | ||
| LICENSE | ||
| QUICKSTART.md | ||
| README.md | ||
chopsticks
A batteries-included Vim configuration for full-stack engineering. Tiered LSP · 14 languages · TTY-aware · Zero icon fonts · One-command install.
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
cd ~/.vim && ./install.sh
New to Vim? Read Step 0 in QUICKSTART.md first — a 2-minute intro to modes and the 4 commands that get you out of any jam.
Contents
- Design Principles
- Requirements
- Installation
- LSP: Tiered Backend
- Key Mappings
- Features
- Language Support
- Plugins
- Customization
- Troubleshooting
- Contributing
Design Principles
| Principle | What it means |
|---|---|
| KISS | No icon fonts, no Nerd Font glyphs — plain ASCII everywhere |
| Tiered LSP | CoC (full) when Node.js is available; vim-lsp (pure VimScript) otherwise |
| 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
| Tool | Minimum | Role |
|---|---|---|
| Vim | 8.0+ | Required |
| git | any | Cloning and vim-fugitive |
| curl | any | vim-plug bootstrap |
| Node.js | 14.14+ | Optional — enables CoC LSP (recommended) |
| ripgrep | any | Optional — enables ,rg / ,rG project search |
| fzf | any | Optional — enables Ctrl+p fuzzy finder |
| 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.
Installation
Automatic (recommended)
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
cd ~/.vim
./install.sh
The installer handles everything in sequence:
- Verifies Vim 8.0+ and detects OS / package manager
- Backs up any existing
~/.vimrcwith a timestamp - Symlinks
~/.vimrc → ~/.vim/.vimrcand~/.vim/coc-settings.json - Installs vim-plug and runs
:PlugInstall - Optionally installs system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)
- Optionally installs language tools (npm, pip, Go)
- Optionally installs CoC language server extensions
- Optionally configures tmux for seamless pane navigation
Supported platforms: macOS (Homebrew), Debian/Ubuntu (apt), Arch Linux (pacman), Fedora (dnf).
Use --yes for non-interactive or CI environments:
./install.sh --yes
Manual
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
ln -sf ~/.vim/.vimrc ~/.vimrc
ln -sf ~/.vim/coc-settings.json ~/.vim/coc-settings.json
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
vim +PlugInstall +qall </dev/null
LSP: Tiered Backend
Code intelligence is provided by one of two backends, chosen automatically at startup:
| Condition | Backend | Capabilities |
|---|---|---|
| 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 |
| Any Vim | ALE | Async linting + auto-fix (always active, both backends) |
Both CoC and vim-lsp expose the same key mappings so switching backends is transparent.
With Node.js (CoC)
Install language server extensions from inside Vim — or let install.sh do it automatically:
:CocInstall coc-pyright " Python
:CocInstall coc-tsserver " JavaScript / TypeScript
:CocInstall coc-go " Go
:CocInstall coc-rust-analyzer " Rust
:CocInstall coc-json coc-yaml " JSON, YAML
:CocInstall coc-html coc-css " HTML, CSS/SCSS
:CocInstall coc-sh " Shell
:CocInstall coc-sql " SQL
Markdown LSP uses marksman as an external binary (not a CoC extension):
brew install marksman # macOS
sudo pacman -S marksman # Arch
# or: ./install.sh handles it automatically
Without Node.js (vim-lsp)
Open a source file, then run:
: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
Leader key: , (comma)
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+snote: some terminals freeze onCtrl+s(XON/XOFF). Addstty -ixonto your~/.bashrc/~/.zshrcto disable this permanently.
Files and Buffers
| Key | Action |
|---|---|
Ctrl+p |
Fuzzy file search — git-aware (FZF) |
Ctrl+n |
Toggle file tree (NERDTree) |
,n |
Reveal current file in NERDTree |
,b |
Search open buffers (FZF) |
,rg |
Project-wide search (ripgrep + FZF) |
,rG |
Ripgrep for word under cursor (literal match) |
,rt |
Search tags (FZF) |
,gF |
Search git-tracked files (FZF) |
,l |
Next buffer |
,h |
Previous buffer |
,bd |
Close current buffer (preserves window layout) |
,, |
Switch to last file |
Windows, Tabs, and tmux
| Key | Action |
|---|---|
Ctrl+h/j/k/l |
Navigate between Vim splits and tmux panes |
,= |
Increase window height |
,- |
Decrease window height |
,+ |
Increase window width |
,_ |
Decrease window width |
,tn |
New tab |
,tc |
Close 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)
| Key | Action |
|---|---|
gd |
Go to definition |
gy |
Go to type definition |
gi |
Go to implementation |
gr |
Show all references |
K |
Hover documentation |
[g |
Previous diagnostic |
]g |
Next diagnostic |
,rn |
Rename symbol |
,f |
Format selection |
,F |
Format whole file |
,ca |
Code action (cursor position) |
,o |
File outline (symbols) |
,ws |
Workspace symbols |
,cD |
Diagnostics list |
,qf |
Quick-fix current line (CoC) |
Tab |
Next completion item |
Shift+Tab |
Previous completion item |
Enter |
Confirm completion |
Text objects (CoC): if/af (function inner/around), ic/ac (class inner/around).
Linting (ALE — always active)
| Key | Action |
|---|---|
[e |
Previous error / warning |
]e |
Next error / warning |
,aD |
Show error detail |
,ad |
Full diagnostics list |
Signs in the gutter: X = error, ! = warning.
Git (vim-fugitive)
| Key | Action |
|---|---|
,gs |
Git status (stage with s, commit with cc) |
,gc |
Git commit |
,gp |
Git push |
,gl |
Git pull |
,gd |
Git diff |
,gb |
Git blame |
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 |
|---|---|
,ev |
Edit ~/.vimrc |
,sv |
Reload ~/.vimrc |
,wa |
Save all open buffers |
,wd |
Change working directory to current file's location |
,cp |
Copy absolute file path to clipboard |
,cf |
Copy filename to clipboard |
,qo / ,qc |
Open / close quickfix list |
Features
Startup Dashboard
Running vim (no arguments) opens a full-screen Startify dashboard showing recent
files, sessions, and bookmarks. Running vim . opens NERDTree on the left with
the dashboard on the right.
Keybinding Guide
Press , and pause for 500 ms. A popup (vim-which-key) lists all leader bindings
organized into groups. No need to memorize everything upfront.
Built-in Cheat Sheet
Press ,? to open an inline reference covering modes, survival commands, search,
code intelligence, git, and clipboard — without leaving Vim.
Session Management
:Obsess " start tracking the current session
:Obsess! " stop tracking
Sessions are stored in ~/.vim/sessions/ and automatically restored by vim-prosession
the next time you open Vim in the same directory.
Project-Local Config
Drop a .vimrc in any project root to override settings for that project:
" project/.vimrc
set shiftwidth=2
let g:ale_python_black_options = '--line-length=100'
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):
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-lbinding replaces the terminal's screen-clear shortcut inside tmux. To restore it, addbind C-l send-keys 'C-l'— then useprefix + C-l.
Large File Handling
Files over 10 MB automatically disable syntax highlighting, undo history, and linting to prevent Vim from stalling.
TTY / Console Support
Detected automatically when $TERM is linux or screen. In TTY mode:
- True color and cursorline disabled
- Powerline separators replaced with plain ASCII
- FZF preview windows disabled
- IndentLine guides disabled
- Syntax column limit reduced to 120 characters
- Simpler built-in status line used instead of airline
Language Support
| Language | Indent | Formatter | Linter | LSP |
|---|---|---|---|---|
| Python | 4 sp | black, isort | flake8, pylint | coc-pyright |
| JavaScript | 2 sp | prettier | eslint | coc-tsserver |
| TypeScript | 2 sp | prettier | eslint, tsserver | coc-tsserver |
| Go | tab | gofmt, goimports | staticcheck | coc-go |
| Rust | 4 sp | rustfmt | cargo | coc-rust-analyzer |
| Shell | 2 sp | — | shellcheck | coc-sh |
| YAML | 2 sp | prettier | yamllint | coc-yaml |
| HTML | 2 sp | prettier | — | coc-html |
| CSS / SCSS | 2 sp | prettier | stylelint | coc-css |
| Less | 2 sp | prettier | — | — |
| JSON | 2 sp | prettier | — | coc-json |
| Markdown | 2 sp | prettier | markdownlint | marksman |
| SQL | 4 sp | sqlfluff | sqlfluff | — |
| Dockerfile | 2 sp | — | hadolint | — |
install.sh installs all formatters and linters automatically.
ALE runs them asynchronously; format-on-save is active for all supported languages.
Plugins
Navigation
- NERDTree — file tree explorer
- fzf + fzf.vim — fuzzy finder for files, buffers, tags, and ripgrep
Git
- vim-fugitive — full Git integration inside Vim
- vim-gitgutter — diff signs in the sign column
LSP and Completion
- coc.nvim — full LSP + completion via Node.js (recommended)
- vim-lsp — pure VimScript LSP client (Node.js-free fallback)
- vim-lsp-settings — auto-configures language servers for vim-lsp
- asyncomplete.vim — async completion engine (vim-lsp mode)
Linting
- ALE — asynchronous lint engine, always active regardless of LSP backend
UI
- vim-airline — status line and tabline
- vim-startify — startup dashboard with session management
- vim-which-key — keybinding hint popup on leader pause
- indentLine — indent guide lines (non-TTY only)
- undotree — visual undo branch history
- tagbar — code structure sidebar via ctags
Editing
- vim-surround — change surrounding quotes, brackets, and tags
- vim-commentary —
gcto toggle comments - auto-pairs — auto-close brackets and quotes
- vim-easymotion — jump anywhere on screen with 2 keystrokes (
s) - vim-unimpaired — bracket shortcut pairs (
[q/]q, etc.) - targets.vim — additional text objects
- vim-snippets — snippet library (used with CoC)
- vim-tmux-navigator — seamless
Ctrl+h/j/k/lacross Vim and tmux
Language Packs
- vim-polyglot — syntax for 100+ languages
- vim-go — Go syntax and tooling (LSP handled by coc-go)
Session
- vim-obsession — continuous session saving
- vim-prosession — project-level session management
Color Schemes
- gruvbox (default), dracula, solarized, onedark
Customization
Change the color scheme
In ~/.vimrc, find and update the colorscheme line:
colorscheme dracula " options: gruvbox, solarized, onedark
True color is enabled automatically when $COLORTERM=truecolor. Falls back to
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:
" 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
Plugins not loading
:PlugInstall " install any missing plugins
:PlugUpdate " update all plugins
CoC not working
node --version # must be 14.14+
Inside Vim: :CocInfo for diagnostics, :CocInstall <extension> to add a language server.
vim-lsp server not starting
:LspInstallServer " install the correct server for the current filetype
:LspStatus " check server status
Markdown LSP not starting
marksman must be installed as a standalone binary (not a CoC extension):
brew install marksman # macOS
sudo pacman -S marksman # Arch
# or: ./install.sh handles it automatically
Colors look wrong
export TERM=xterm-256color # add to ~/.bashrc or ~/.zshrc
For true color: export COLORTERM=truecolor.
ALE linters not found
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.
Contributing
Bug reports and pull requests are welcome. Please follow these guidelines:
Reporting a bug
- Search existing issues before opening a new one.
- Include your Vim version (
vim --version), OS, and a minimal reproduction. - 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
- Open an issue first to discuss the change, especially for non-trivial additions.
- Keep the scope focused — one feature or fix per PR.
- Follow existing conventions: augroups for autocmds, TTY guards for visual features, conditional plugin loading where appropriate.
- Update
CHANGELOG.mdwith 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. Built with vim-plug, coc.nvim, vim-lsp, and the broader Vim plugin community.
Changelog
See CHANGELOG.md.
License
MIT © m1ng