diff --git a/.vimrc b/.vimrc index e12c497..037d62a 100644 --- a/.vimrc +++ b/.vimrc @@ -207,6 +207,7 @@ Plug 'dhruvasagar/vim-prosession' " Better session management Plug 'tpope/vim-unimpaired' " Handy bracket mappings Plug 'wellle/targets.vim' " Additional text objects Plug 'honza/vim-snippets' " Snippet collection +Plug 'christoomey/vim-tmux-navigator' " Seamless vim/tmux pane navigation " ===== Native LSP (vim-lsp: works without Node.js, Vim 8.0+ only) ===== " Used as fallback when CoC/Node.js is unavailable @@ -323,11 +324,8 @@ nmap x :x " Disable highlight when is pressed map :noh -" Smart way to move between windows -map j -map k -map h -map l +" Window navigation — owned by vim-tmux-navigator plugin (Ctrl+h/j/k/l works +" seamlessly across Vim splits and tmux panes; no manual maps needed here) " Close the current buffer (Bclose preserves window layout) map bd :Bclose @@ -398,6 +396,9 @@ nnoremap Y y$ " Disable accidental Ex mode nnoremap Q +" Exit insert mode without reaching for Escape (community standard) +inoremap jk + " Keep visual selection after indent vnoremap < >gv @@ -406,15 +407,25 @@ vnoremap > >gv nnoremap n nzzzv nnoremap N Nzzzv +" Search for visually selected text with // (hit // in visual mode) +vnoremap // y/\V=escape(@",'/\') + +" to save in normal and insert mode +" (for terminals: add 'stty -ixon' to your shell rc to disable XON/XOFF) +nnoremap :w +inoremap :wa + " Center cursor after half-page scroll nnoremap zz nnoremap zz -" System clipboard yank (conditional: requires clipboard provider) +" System clipboard yank/paste (conditional: requires clipboard provider) if has('clipboard') nnoremap y "+y vnoremap y "+y nnoremap Y "+Y + nnoremap p "+p + nnoremap P "+P endif " Quickfix list shortcuts ([q/]q from vim-unimpaired handles navigation) @@ -485,6 +496,7 @@ endfunction map :call SmartFiles() map b :Buffers map rg :Rg +map rG :Rg -F map rt :Tags map gF :GFiles @@ -583,9 +595,9 @@ let g:ale_fixers = { let g:ale_fix_on_save = !g:use_vimlsp let g:ale_sign_error = 'X' let g:ale_sign_warning = '!' -let g:ale_lint_on_text_changed = 'never' -let g:ale_lint_on_insert_leave = 0 -let g:ale_lint_on_enter = 0 +let g:ale_lint_on_text_changed = 'normal' +let g:ale_lint_on_insert_leave = 1 +let g:ale_lint_on_enter = 1 " --- vim-go: disable built-in LSP/gopls — CoC (coc-go) handles all Go intelligence --- " vim-go's gopls conflicts with coc-go and causes E495 errors on startup @@ -602,16 +614,18 @@ let g:go_highlight_fields = 1 let g:go_highlight_functions = 1 let g:go_highlight_function_calls = 1 -" Navigate between errors: [e/]e (unimpaired style), aD for detail -nmap [e :ALENext -nmap ]e :ALEPrevious +" Navigate between errors: [e/]e (unimpaired convention: [ = prev, ] = next) +nmap [e :ALEPrevious +nmap ]e :ALENext nmap aD :ALEDetail " --- Tagbar --- nmap :TagbarToggle +nmap tt :TagbarToggle " --- UndoTree --- nnoremap :UndotreeToggle +nnoremap u :UndotreeToggle " --- EasyMotion --- let g:EasyMotion_do_mapping = 0 " Disable default mappings @@ -929,9 +943,6 @@ function! ToggleNumber() endif endfunc -" Toggle paste mode -map pp :setlocal paste! - " ============================================================================ " => Performance Optimization " ============================================================================ @@ -1020,6 +1031,85 @@ augroup BWCCreateDir autocmd BufWritePre * if !empty(expand('')) | call s:MkNonExDir(expand(''), +expand('')) | endif augroup END +" In-Vim quick reference cheat sheet — ,? opens it, q closes it +function! s:CheatSheet() abort + let l:name = '__ChopsticksCheatSheet__' + let l:winnr = bufwinnr(l:name) + if l:winnr > 0 + execute l:winnr . 'wincmd w' + return + endif + execute 'botright new ' . l:name + setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile + call setline(1, [ + \ '=== chopsticks — Quick Reference ===', + \ '', + \ 'MODES (Vim is modal — the most important concept)', + \ ' Normal Default state. Navigate and run commands.', + \ ' Insert Type text. Enter: i/a/o Leave: Esc or jk', + \ ' Visual Select text. Enter: v/V Leave: Esc', + \ '', + \ 'SURVIVAL (learn these 4 first)', + \ ' Esc / jk Exit insert or visual mode — back to Normal', + \ ' :q! + Enter Quit without saving (emergency exit)', + \ ' ,x Save and quit', + \ ' ,w Save file | Ctrl+s Save (normal + insert)', + \ '', + \ 'NAVIGATION', + \ ' h j k l Left / Down / Up / Right', + \ ' Ctrl+p Fuzzy find file | Ctrl+n File tree', + \ ' Ctrl+o/i Jump back / forward in history', + \ ' ,, Switch to last file', + \ '', + \ 'SEARCH', + \ ' /text Search forward | n next | N prev', + \ ' // Search for visually selected text', + \ ' ,rg Search project contents (ripgrep)', + \ ' ,rG Ripgrep word under cursor', + \ ' ,* Replace word under cursor (file-wide)', + \ '', + \ 'CODE INTELLIGENCE', + \ ' gd Go to definition', + \ ' K Hover documentation', + \ ' [g / ]g Prev / next diagnostic (LSP)', + \ ' [e / ]e Prev / next ALE error', + \ ' ,ca Code action / auto-fix', + \ ' ,rn Rename symbol', + \ ' ,f Format selection | ,F Format whole file', + \ '', + \ 'EDITING', + \ ' i / a / o Insert before / after / on new line', + \ ' gc Toggle comment (works in visual too)', + \ ' u / Ctrl+r Undo / Redo', + \ ' ,p / ,P Paste from system clipboard', + \ ' ,y / ,Y Yank / line-yank to system clipboard', + \ ' s + 2 chars EasyMotion jump anywhere on screen', + \ '', + \ 'GIT', + \ ' ,gs Git status | ,gd Diff | ,gb Blame', + \ ' ,gc Commit | ,gp Push | ,gl Pull', + \ '', + \ 'WINDOWS / PANES', + \ ' Ctrl+h/j/k/l Move between Vim windows or tmux panes', + \ ' ,h / ,l Prev / next buffer', + \ ' ,tv / ,th Open terminal (vertical / horizontal)', + \ '', + \ 'TOOLS', + \ ' ,u Undo tree (visual history)', + \ ' ,tt Tagbar (code structure)', + \ ' ,o File outline (LSP symbols)', + \ '', + \ 'TIP: When confused, press Esc. Then press , and wait 500ms', + \ ' for an interactive guide to ALL keybindings.', + \ ' Re-open this sheet with ,?', + \ '', + \ '(press q to close)', + \ ]) + setlocal nomodifiable readonly + nnoremap q :bd +endfunction +nnoremap ? :call CheatSheet() + " ============================================================================ " => Debugging Helpers " ============================================================================ @@ -1082,7 +1172,8 @@ function! LargeFileSettings() setlocal eventignore+=FileType setlocal noswapfile 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 " ============================================================================ @@ -1148,6 +1239,10 @@ if exists('g:plugs["vim-which-key"]') let g:which_key_map[','] = 'last-file' let g:which_key_map['y'] = 'clipboard-yank' let g:which_key_map['Y'] = 'clipboard-yank-line' + let g:which_key_map['p'] = 'clipboard-paste-after' + let g:which_key_map['P'] = 'clipboard-paste-before' + let g:which_key_map['u'] = 'undotree-toggle' + let g:which_key_map['?'] = 'cheat-sheet' " [a]LE lint group ([e/]e navigate; aD for detail; ad for diagnostics) let g:which_key_map['a'] = { @@ -1200,6 +1295,7 @@ if exists('g:plugs["vim-which-key"]') \ 'name': '+search/refactor', \ 'n': 'rename', \ 'g': 'ripgrep', + \ 'G': 'ripgrep-word-under-cursor', \ 't': 'tags-search', \ } @@ -1218,7 +1314,7 @@ if exists('g:plugs["vim-which-key"]') " [t]ab / [t]erminal group let g:which_key_map['t'] = { - \ 'name': '+tab/terminal', + \ 'name': '+tab/terminal/tagbar', \ 'n': 'new-tab', \ 'o': 'tab-only', \ 'c': 'close-tab', @@ -1227,6 +1323,7 @@ if exists('g:plugs["vim-which-key"]') \ 'e': 'edit-in-tab', \ 'v': 'terminal-vertical', \ 'h': 'terminal-horizontal', + \ 't': 'tagbar-toggle', \ } " [w]orkspace / [w]indow / save group (also: w = fast save) diff --git a/CHANGELOG.md b/CHANGELOG.md index d327e3a..4c38e1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,54 @@ All notable changes to chopsticks are documented here. --- +## [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 +- **`p` / `P`** — paste from system clipboard after/before cursor +- **`rG`** — ripgrep word under cursor with `-F` (literal, not regex) +- **`u`** — leader-key alias for UndoTree (complements `F5`) +- **`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 +- **`` manual maps removed** — vim-tmux-navigator owns these keys at + plugin load time; the previous hand-rolled `` maps were unreachable dead code +- **`pp` paste-mode toggle removed** — functionally identical to the existing + `F2` pastetoggle; its presence caused a 500 ms delay on every `p` paste + +### Fixed + +- **ALE navigation direction reversed** — `[e` now correctly calls `ALEPrevious` + and `]e` calls `ALENext`, matching the vim-unimpaired `[`/`]` convention +- **`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 First stable release. Full-stack engineering environment out of the box — automatic diff --git a/QUICKSTART.md b/QUICKSTART.md index 0b01fb2..d40664c 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -2,6 +2,39 @@ 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 @@ -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+n Toggle file tree gd Go to definition K Show documentation -[g / ]g Prev / next diagnostic +[g / ]g Prev / next LSP diagnostic ,rn Rename symbol -,rg Search project contents +,rG Search word under cursor (ripgrep) ,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 ``` +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 - Ctrl+n File tree toggle - Ctrl+p Fuzzy find file (git-aware) - ,b Search open buffers - ,rg Search file contents (ripgrep) - ,w Save | ,q Quit | ,x Save+quit - ,wa Save all buffers + Ctrl+n File tree toggle + Ctrl+p Fuzzy find file (git-aware) + ,b Search open buffers + ,rg Search file contents (ripgrep) + ,rG Ripgrep word under cursor + ,w Save | ,q Quit | ,x Save+quit + ,wa Save all buffers + ,, Switch to last file CODE gd Go to definition K Show documentation - [g / ]g Prev/next diagnostic + [g / ]g Prev/next LSP diagnostic + [e / ]e Prev/next ALE error ,rn Rename symbol - ,ca Code action - ,f Format selection - ,F Format whole file + ,ca Code action / auto-fix + ,f Format selection | ,F Format whole file GIT ,gs Status | ,gd Diff | ,gb Blame ,gc Commit | ,gp Push | ,gl Pull -WINDOWS - Ctrl+h/j/k/l Move between panes +WINDOWS / PANES + Ctrl+h/j/k/l Move between Vim windows or tmux panes + ,h / ,l Prev / next buffer ,tv Open terminal (vertical) ,th Open terminal (horizontal) Esc Exit terminal mode - F5 Undo tree | F8 Tag browser + ,u Undo tree | ,tt Tag browser -SEARCH - /text Search forward - ?text Search backward - ,* Replace word under cursor (project-wide) +SEARCH & REPLACE + /text Search forward | ?text backward + // Search for visually selected text + ,* Replace word under cursor (file-wide) + +CLIPBOARD + ,y / ,Y Yank / yank line to system clipboard + ,p / ,P Paste from system clipboard (after / before) ``` --- diff --git a/README.md b/README.md index fe1694c..99f2368 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,71 @@ -# chopsticks — Vim Configuration +# chopsticks -A native Vim configuration optimized for full-stack engineering workflows. -Vim 8.0+ · Tiered LSP · TTY-aware · Zero icon fonts · 14 languages. +> A batteries-included Vim configuration for full-stack engineering. +> Tiered LSP · 14 languages · TTY-aware · Zero icon fonts · One-command install. -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -[![Vim 8.0+](https://img.shields.io/badge/Vim-8.0%2B-brightgreen.svg)](https://www.vim.org/) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE) +[![Vim 8.0+](https://img.shields.io/badge/Vim-8.0%2B-brightgreen?style=flat-square)](https://www.vim.org/) +[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux-lightgrey?style=flat-square)](#installation) +[![Release](https://img.shields.io/github/v/release/m1ngsama/chopsticks?style=flat-square&label=release&color=orange)](https://github.com/m1ngsama/chopsticks/releases) +[![Last Commit](https://img.shields.io/github/last-commit/m1ngsama/chopsticks?style=flat-square)](https://github.com/m1ngsama/chopsticks/commits/main) +[![Stars](https://img.shields.io/github/stars/m1ngsama/chopsticks?style=flat-square)](https://github.com/m1ngsama/chopsticks/stargazers) +[![Issues](https://img.shields.io/github/issues/m1ngsama/chopsticks?style=flat-square)](https://github.com/m1ngsama/chopsticks/issues) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](https://github.com/m1ngsama/chopsticks/pulls) +[![Plugins](https://img.shields.io/badge/plugins-30%2B-blueviolet?style=flat-square)](#plugins) +[![Languages](https://img.shields.io/badge/languages-14-informational?style=flat-square)](#language-support) ```bash git clone https://github.com/m1ngsama/chopsticks.git ~/.vim 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 -- **KISS** — No icon fonts, no unicode glyphs, plain ASCII throughout -- **Tiered LSP** — CoC (full) with vim-lsp fallback; works with or without Node.js -- **TTY-aware** — Automatic detection and optimization for console/SSH environments -- **Engineering-first** — Git workflow, session management, project-local config -- **Batteries included** — `install.sh` handles all dependencies automatically +| 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 -| Requirement | Minimum | Notes | -|-------------|---------|-------| -| Vim | 8.0+ | vim9script not required | -| git | any | For cloning and fugitive | -| curl | any | For vim-plug auto-install | -| Node.js | 14.14+ | Optional — enables CoC LSP | -| ripgrep (rg) | any | Optional — enables `:Rg` search | -| fzf | any | Optional — enables `Ctrl+p` fuzzy search | -| ctags | any | Optional — enables `F8` tag browser | +| 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. --- @@ -49,16 +79,20 @@ cd ~/.vim ./install.sh ``` -The installer: -1. Checks Vim version and detects OS / package managers -2. Backs up any existing `~/.vimrc` (timestamped) -3. Creates symlinks: `~/.vimrc -> ~/.vim/.vimrc` and `~/.vim/coc-settings.json` +The installer handles everything in sequence: + +1. Verifies Vim 8.0+ and detects OS / package manager +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` -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 ./install.sh --yes @@ -77,21 +111,21 @@ vim +PlugInstall +qall rn`, `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 :CocInstall coc-pyright " Python @@ -99,64 +133,86 @@ Install language server extensions from inside Vim: :CocInstall coc-go " Go :CocInstall coc-rust-analyzer " Rust :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-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 -extension — install `marksman` binary via `brew install marksman` or download from -[releases](https://github.com/artempyanykh/marksman/releases)). - -### 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 +```bash +brew install marksman # macOS +sudo pacman -S marksman # Arch +# or: ./install.sh handles it automatically ``` -Supported languages: Python, Go, Rust, TypeScript, JavaScript, Shell, HTML, -CSS/SCSS, JSON, YAML, Markdown, SQL — via `vim-lsp-settings`. +### Without Node.js (vim-lsp) + +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 -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 | Key | Action | |-----|--------| +| `Ctrl+p` | Fuzzy file search — git-aware (FZF) | | `Ctrl+n` | Toggle file tree (NERDTree) | | `,n` | Reveal current file in NERDTree | -| `Ctrl+p` | Fuzzy file search (FZF — git-aware) | | `,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) | | `,gF` | Search git-tracked files (FZF) | | `,l` | Next buffer | | `,h` | Previous buffer | -| `,bd` | Close current buffer | +| `,bd` | Close current buffer (preserves window layout) | | `,,` | Switch to last file | -### Windows and Tabs +### Windows, Tabs, and tmux | Key | Action | |-----|--------| -| `Ctrl+h/j/k/l` | Navigate between windows | -| `=` | Increase window height | -| `-` | Decrease window height | -| `+` | Increase window width | -| `_` | Decrease window width | +| `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) @@ -165,123 +221,128 @@ Press `,` and wait 500ms for an interactive guide to all bindings (vim-which-key | `gd` | Go to definition | | `gy` | Go to type definition | | `gi` | Go to implementation | -| `gr` | Show references | +| `gr` | Show all references | | `K` | Hover documentation | | `[g` | Previous diagnostic | | `]g` | Next diagnostic | | `,rn` | Rename symbol | | `,f` | Format selection | -| `,ca` | Code action (cursor) | -| `,o` | File outline | +| `,F` | Format whole file | +| `,ca` | Code action (cursor position) | +| `,o` | File outline (symbols) | | `,ws` | Workspace symbols | | `,cD` | Diagnostics list | -| `,cr` | Resume last CoC list | | `,qf` | Quick-fix current line (CoC) | -| `,cl` | Run code lens (CoC) | | `Tab` | Next completion item | | `Shift+Tab` | Previous completion item | | `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 | |-----|--------| -| `[e` | Next error/warning | -| `]e` | Previous error/warning | -| `,aD` | Show error details | +| `[e` | Previous error / warning | +| `]e` | Next error / warning | +| `,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 | |-----|--------| -| `,gs` | Git status | +| `,gs` | Git status (stage with `s`, commit with `cc`) | | `,gc` | Git commit | | `,gp` | Git push | | `,gl` | Git pull | | `,gd` | Git diff | | `,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 | +| `,` | 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` | -| `,F` | Format entire file | -| `,W` | Strip trailing whitespace | | `,wa` | Save all open buffers | -| `,wd` | Change CWD to current buffer's dir | -| `,cp` | Copy file path to clipboard | +| `,wd` | Change working directory to current file's location | +| `,cp` | Copy absolute file path to clipboard | | `,cf` | Copy filename to clipboard | -| `,y` | Yank to system clipboard | -| `,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 | +| `,qo` / `,qc` | Open / close quickfix list | --- ## Features -### Startup Screen (vim-startify) +### Startup Dashboard -Opens when Vim is launched without a file argument. Shows: -- Session list for current directory -- Recently opened files -- Bookmarks +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. -Session auto-saves on quit. Auto-loads `Session.vim` if found in the current -directory. Auto-changes to git root on file open. +### Keybinding Guide -**`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 -organized by group. Useful for onboarding and discovering shortcuts. +Press `,?` to open an inline reference covering modes, survival commands, search, +code intelligence, git, and clipboard — without leaving Vim. ### Session Management ```vim -:Obsess " Start tracking session -:Obsess! " Stop tracking +:Obsess " start tracking the current session +:Obsess! " stop tracking ``` -Sessions stored in `~/.vim/sessions/` and automatically resumed by vim-prosession -on the next Vim launch in the same directory. +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 -Place a `.vimrc` in any project root: +Drop a `.vimrc` in any project root to override settings for that project: ```vim " project/.vimrc @@ -289,157 +350,244 @@ set shiftwidth=2 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 -Files over 10 MB automatically disable syntax highlighting and undo history -to prevent Vim from freezing. +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 -- NERDTree auto-open skipped -- Syntax column limit reduced to 120 -- Simpler status line +- 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 (CoC) | -|----------|--------|-----------|--------|-----------| -| Python | 4sp | black + isort | flake8, pylint | coc-pyright | -| JavaScript | 2sp | prettier | eslint | coc-tsserver | -| TypeScript | 2sp | prettier | eslint, tsserver | coc-tsserver | +| 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 | 4sp | rustfmt | cargo | coc-rust-analyzer | -| Shell | 2sp | — | shellcheck | coc-sh | -| YAML | 2sp | prettier | yamllint | coc-yaml | -| HTML | 2sp | prettier | — | coc-html | -| CSS / SCSS | 2sp | prettier | stylelint | coc-css | -| Less | 2sp | prettier | — | — | -| JSON | 2sp | prettier | — | coc-json | -| Markdown | 2sp | prettier | markdownlint | marksman (coc-settings.json) | -| SQL | 4sp | sqlfluff | sqlfluff | — | -| Dockerfile | 2sp | — | hadolint | — | +| 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 linters and formatters automatically. -ALE runs them asynchronously; format-on-save active when using CoC. +`install.sh` installs all formatters and linters automatically. +ALE runs them asynchronously; format-on-save is active for all supported languages. --- -## Plugin List +## Plugins ### Navigation -- **NERDTree** — File tree explorer -- **fzf + fzf.vim** — Fuzzy finder (file, buffer, tag, ripgrep) +- **NERDTree** — file tree explorer +- **fzf + fzf.vim** — fuzzy finder for files, buffers, tags, and ripgrep ### Git -- **vim-fugitive** — Git commands inside Vim -- **vim-gitgutter** — Diff signs in the sign column +- **vim-fugitive** — full Git integration inside Vim +- **vim-gitgutter** — diff signs in the sign column ### LSP and Completion -- **coc.nvim** — Full LSP + completion (requires Node.js 14.14+) -- **vim-lsp** — Pure VimScript LSP client (fallback, no Node.js) -- **vim-lsp-settings** — Auto-configure language servers for vim-lsp -- **asyncomplete.vim** — Async completion (used with vim-lsp) +- **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) +- **ALE** — asynchronous lint engine, always active regardless of LSP backend ### UI -- **vim-airline** — Status and tabline -- **vim-startify** — Startup screen with sessions -- **vim-which-key** — Keybinding hint popup -- **indentLine** — Indent guide lines (non-TTY) -- **undotree** — Undo history visualizer -- **tagbar** — Code structure sidebar +- **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, tags +- **vim-surround** — change surrounding quotes, brackets, and tags - **vim-commentary** — `gc` to toggle comments -- **auto-pairs** — Auto-close brackets and quotes -- **vim-easymotion** — Jump anywhere with 2 keystrokes -- **vim-unimpaired** — Bracket shortcut pairs -- **targets.vim** — Extra text objects -- **vim-snippets** — Snippet library (used with CoC/UltiSnips) +- **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/l` across Vim and tmux ### Language Packs -- **vim-polyglot** — Syntax for 100+ languages -- **vim-go** — Go development tools (formatting + highlighting; LSP handled by coc-go) +- **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 +- **vim-obsession** — continuous session saving +- **vim-prosession** — project-level session management ### Color Schemes - **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 -colorscheme dracula " or: gruvbox, solarized, onedark +colorscheme dracula " options: gruvbox, solarized, onedark ``` -True color is enabled automatically when the terminal supports it -(`$COLORTERM=truecolor`). Falls back to 256-color, then 16-color (TTY). +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: + +```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 -**Plugins not installed:** +**Plugins not loading** + ```vim -:PlugInstall -:PlugUpdate +:PlugInstall " install any missing plugins +:PlugUpdate " update all plugins ``` -**CoC not working:** +**CoC not working** + ```bash -node --version # must be >= 14.14 +node --version # must be 14.14+ ``` -**Markdown LSP not starting:** -```bash -marksman --version # must be installed separately -brew install marksman # macOS -sudo pacman -S marksman # Arch -# or: ./install.sh (installs automatically) -``` +Inside Vim: `:CocInfo` for diagnostics, `:CocInstall ` to add a language server. + +**vim-lsp server not starting** -**vim-lsp server not starting:** ```vim -:LspInstallServer " install server for current filetype -:LspStatus " check server status +:LspInstallServer " install the correct server for the current filetype +: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 export TERM=xterm-256color # add to ~/.bashrc or ~/.zshrc ``` -**ALE not finding linters:** +For true color: `export COLORTERM=truecolor`. + +**ALE linters not found** + ```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) -- [coc.nvim](https://github.com/neoclide/coc.nvim) -- [vim-lsp](https://github.com/prabirshrestha/vim-lsp) -- [vim-lsp-settings](https://github.com/mattn/vim-lsp-settings) -- [amix/vimrc](https://github.com/amix/vimrc) +Bug reports and pull requests are welcome. Please follow these guidelines: + +### Reporting a bug + +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. --- diff --git a/install.sh b/install.sh index 0217028..73d18b5 100755 --- a/install.sh +++ b/install.sh @@ -382,6 +382,43 @@ else SKIPPED+=("gopls" "goimports" "staticcheck") fi +# ============================================================================ +# 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" + # Check if already configured + if grep -q 'vim-tmux-navigator' "$TMUX_CONF" 2>/dev/null; then + ok "vim-tmux-navigator bindings already present in ~/.tmux.conf" + else + if 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 + fi +else + skip "tmux not found — skipping navigator config" + SKIPPED+=("tmux-navigator-config") +fi + # ============================================================================ # CoC language server extensions # ============================================================================ @@ -424,5 +461,21 @@ if [[ ${#FAILED[@]} -gt 0 ]]; then fi 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 ""