From f38bdf6e57960602b0900eb8588f87d779f091e4 Mon Sep 17 00:00:00 2001 From: m1ngsama Date: Thu, 21 May 2026 12:02:55 +0800 Subject: [PATCH] Revert "Release v3.0.0 ergonomic keymap" This reverts commit d56ca80da7dab689dbb8fa074ff990e155ff4612. --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/demo.tape | 12 +- .vimrc | 8 - CHANGELOG.md | 51 ---- QUICKSTART.md | 71 ++--- README.md | 106 ++------ install.sh | 17 +- modules/buffers.vim | 18 -- modules/cheatsheet.vim | 267 ------------------ modules/core.vim | 64 +---- modules/editing.vim | 19 +- modules/env.vim | 6 - modules/files.vim | 54 ---- modules/git.vim | 8 +- modules/languages.vim | 14 +- modules/lint.vim | 12 +- modules/lsp.vim | 47 +--- modules/navigation.vim | 66 ++--- modules/quickfix.vim | 10 - modules/runner.vim | 28 -- modules/status.vim | 165 ------------ modules/tools.vim | 449 ++++++++++++++++++++++++++++++- modules/tutor.vim | 102 ------- modules/utilities.vim | 64 ----- scripts/test-common.sh | 28 -- scripts/test-quick.sh | 113 -------- scripts/test-vim.sh | 414 ---------------------------- scripts/test.sh | 408 +++++++++++++++++++++++++++- 28 files changed, 958 insertions(+), 1665 deletions(-) delete mode 100644 modules/buffers.vim delete mode 100644 modules/cheatsheet.vim delete mode 100644 modules/files.vim delete mode 100644 modules/quickfix.vim delete mode 100644 modules/runner.vim delete mode 100644 modules/status.vim delete mode 100644 modules/tutor.vim delete mode 100644 modules/utilities.vim delete mode 100644 scripts/test-common.sh delete mode 100755 scripts/test-quick.sh delete mode 100755 scripts/test-vim.sh diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 487deef..6b9731b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,4 +10,4 @@ - [ ] `vim --startuptime` shows no regression - [ ] Tested on macOS / Linux -- [ ] `SPC ?` cheat sheet still accurate +- [ ] `,?` cheat sheet still accurate diff --git a/.github/demo.tape b/.github/demo.tape index 74341d2..13bd710 100644 --- a/.github/demo.tape +++ b/.github/demo.tape @@ -24,16 +24,16 @@ Type "vim server.py" Enter Sleep 3.5s -# ── 2. Fuzzy find files (SPC SPC → type → select) ──────────────────────── -Type " " +# ── 2. Fuzzy find files (,ff → type → select) ──────────────────────────── +Type ",ff" Sleep 1.5s Type "route" Sleep 2.5s Enter Sleep 3s -# ── 3. Ripgrep project search (SPC / → query → select) ─────────────────── -Type " /" +# ── 3. Ripgrep project search (,rg → query → select) ────────────────────── +Type ",rg" Sleep 1.5s Type "def " Sleep 3s @@ -47,12 +47,12 @@ Sleep 4.5s Enter Sleep 1.5s -# ── 5. Cheat sheet (SPC ?) ──────────────────────────────────────────────── +# ── 5. Cheat sheet (,?) ─────────────────────────────────────────────────── # Reset to server.py so cheat sheet shows code on left, keys on right. Type ":edit server.py" Enter Sleep 1s -Type " ?" +Type ",?" Sleep 5.5s Type "q" Sleep 0.5s diff --git a/.vimrc b/.vimrc index b4dbd67..535c074 100644 --- a/.vimrc +++ b/.vimrc @@ -27,12 +27,4 @@ call s:load('lsp') call s:load('lint') call s:load('git') call s:load('languages') -call s:load('buffers') -call s:load('utilities') -call s:load('files') -call s:load('runner') -call s:load('quickfix') -call s:load('status') -call s:load('cheatsheet') -call s:load('tutor') call s:load('tools') diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b85cd..73c53b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,57 +2,6 @@ ## Unreleased -## 3.0.0 — 2026-05-21 - -### Breaking - -- Default keymap style is now `space`: `SPC` is the command leader and `,` - is reserved for filetype-local actions. Set - `let g:chopsticks_keymap_style = 'classic'` in - `${XDG_CONFIG_HOME:-~/.config}/chopsticks.vim` to keep the old comma layout -- In the default Space layout, Normal-mode `s` is now the fastest - EasyMotion over-window two-character jump. Use `cl` for native `s` - substitute and `cc` for native `S` substitute -- Git push and pull hotkeys are removed from both Space and classic layouts; - use `:Git push` / `:Git pull` explicitly for irreversible remote operations - -### Added - -- Canonical QWERTY/CapsLock-friendly Space leader layout: - `SPC SPC`, `SPC /`, `SPC ,`, `SPC w`, `SPC qx`, `SPC rr`, - `SPC gs`, `SPC gl`, `SPC ca`, `SPC cr`, `SPC cf`, and `SPC ?` -- Native LSP motions in the default layout: `gd`, `gr`, `gI`, `gy`, `K`, - `[d`, and `]d` -- `:ChopsticksTutor` guided practice buffer for learning the final keymap -- `:ChopsticksCheatSheet` command, with `SPC ?` as the discoverable default -- Dedicated modules for buffers, utilities, files, runner, quickfix, status, - cheat sheet, and tutor -- Split test runner: `scripts/test.sh` now dispatches to - `scripts/test-quick.sh` and `scripts/test-vim.sh` - -### Changed - -- README, QUICKSTART, installer onboarding text, PR template, and demo tape now - teach the Space layout first while keeping the legacy classic layout documented -- `SPC ?` / `,?` cheat sheet output is generated from the active keymap style - and profile, so minimal installs no longer display disabled features -- Markdown actions now use localleader maps in the Space layout: - `,mp` preview and `,mt` table of contents -- `SPC U` opens UndoTree, `SPC z` toggles maximize, `SPC bp` / `SPC bn` - move between buffers, and quickfix/location-list actions live under `SPC x` -- `tools.vim` is now a compatibility placeholder; runtime behavior lives in - smaller focused modules -- CI/local smoke coverage now asserts Space defaults, classic compatibility, - missing push/pull hotkeys, tutor and cheat-sheet content, runner behavior, - large-file protection, and startup budget - -### Fixed - -- `diffopt` enhancements now degrade safely on macOS system Vim builds that - report the required patch level but reject individual diff options -- Installer system-tool reporting now still detects already-installed tools on - Linux hosts where sudo is unavailable in non-interactive mode - ## 2.2.0 — 2026-05-17 ### Added diff --git a/QUICKSTART.md b/QUICKSTART.md index 1162cf8..5d014d6 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -18,14 +18,6 @@ without prompting. You can later put `let g:chopsticks_profile = 'minimal'` in `${XDG_CONFIG_HOME:-~/.config}/chopsticks.vim` for a smaller core-only setup, or use `full` for the heavier Markdown/LSP feedback. -The default keymap style is `space`: `SPC` is the command leader and `,` is -reserved for filetype-local actions. To use the legacy comma layout instead, -add this to `${XDG_CONFIG_HOME:-~/.config}/chopsticks.vim`: - -```vim -let g:chopsticks_keymap_style = 'classic' -``` - To switch later without reinstalling anything: ```bash @@ -42,16 +34,6 @@ cd ~/.vim && ./install.sh --configure-only --profile=full ## Survival -``` -Esc back to Normal -SPC w save -SPC qx save + quit -:q! force quit -SPC ? cheat sheet (toggle sidebar) -``` - -Classic layout equivalents: - ``` Esc back to Normal ,w save @@ -63,23 +45,23 @@ Esc back to Normal ## Find things ``` -SPC SPC fuzzy find file (git-aware) -SPC / ripgrep project -SPC , search buffers -SPC fr recent files -SPC e file browser -SPC Tab last file +,ff fuzzy find file (git-aware) +,rg ripgrep project +,b search buffers +,fh recent files +,e file browser +,, last file ``` ## Write code ``` -gd go to definition -K hover docs -SPC cr rename symbol -SPC ca code action -SPC cf format -SPC rr run current file +,dd go to definition +,dk hover docs +,rn rename symbol +,ca code action +,f format +,cr run current file Tab / S-Tab cycle completions ``` @@ -88,37 +70,31 @@ Tab / S-Tab cycle completions ## Git ``` -SPC gs status (s=stage, cc=commit) -SPC gd diff -SPC gb blame -SPC gl log graph +,gs status (s=stage, cc=commit) +,gd diff +,gb blame +,gp push ]x / [x conflict markers ``` ## Edit -In the default Space layout, Normal-mode `s` is a fast visible-text jump. -Use `cl` when you want Vim's original single-character substitute behavior, -and `cc` when you want Vim's original line substitute behavior. - ``` -s + 2 chars EasyMotion jump -SPC S + 2 chars same jump, discoverable fallback -cl / cc native s / S substitute replacements +,S + 2 chars EasyMotion jump gc toggle comment cs"' change surrounding " to ' Alt+j / Alt+k move line -SPC U undo tree -SPC y clipboard yank +,u undo tree +,y clipboard yank ``` ## Navigate ``` h/j/k/l splits -SPC bp / SPC bn prev / next buffer -SPC z maximize window -SPC tt / SPC th terminal +,h / ,l prev / next buffer +,z maximize window +,tv / ,th terminal ``` ## Markdown @@ -134,11 +110,10 @@ syntax. Enable the heavier Markdown tools only when you want them. ## Health check ``` -:ChopsticksTutor guided practice for the final keymap :ChopsticksStatus see what's installed and what's missing ``` -The `SPC ?` cheat sheet follows your active profile, so `minimal` users only see +The `,?` cheat sheet follows your active profile, so `minimal` users only see keys for features that are actually loaded. See [README](README.md) for the full reference. See the [wiki](https://github.com/m1ngsama/chopsticks/wiki) for deep dives. diff --git a/README.md b/README.md index 41e5da4..9529779 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ You SSH into a server. You need to edit code. You want LSP, fuzzy find, git inte chopsticks gives you a production-ready Vim config in one command. Pure VimScript — no Node.js for the core. Degrades gracefully on TTY. Works the same on your MacBook and your headless Arch box. -**23–25 plugins** (tmux-navigator loads only inside tmux; auto-pairs is opt-in), LSP, linting, and a hand-built statusline. No bloat, no decorations, just tools. +**24–25 plugins** (tmux-navigator loads only inside tmux), LSP, linting, and a hand-built statusline. No bloat, no decorations, just tools. ## What's in the box @@ -39,8 +39,8 @@ chopsticks gives you a production-ready Vim config in one command. Pure VimScrip | **LSP** | completion, go-to-def, hover, rename, code actions — pure VimScript ([vim-lsp](https://github.com/prabirshrestha/vim-lsp)) | | **Lint + format** | [ALE](https://github.com/dense-analysis/ale) runs black, prettier, goimports, rustfmt on save | | **Fuzzy find** | files, buffers, grep, tags, marks, commands — [FZF](https://github.com/junegunn/fzf.vim) | -| **Git** | status, diff, blame, commit, log, conflict markers — [fugitive](https://github.com/tpope/vim-fugitive) + [gitgutter](https://github.com/airblade/vim-gitgutter) | -| **Run file** | `SPC rr` — auto-detects Python, Go, Rust, JS, C, Shell, and more | +| **Git** | status, diff, blame, push, pull, conflict markers — [fugitive](https://github.com/tpope/vim-fugitive) + [gitgutter](https://github.com/airblade/vim-gitgutter) | +| **Run file** | `,cr` — auto-detects Python, Go, Rust, JS, C, Shell, and more | | **Markdown** | quiet writing defaults, browser preview (`,mp`), table of contents (`,mt`) | | **Diagnostics** | `:ChopsticksStatus` — see what's installed, what's missing, how to fix it | | **TTY-aware** | degrades gracefully on SSH, console, slow links — never breaks | @@ -81,8 +81,6 @@ profile or uses `engineer`. let g:chopsticks_profile = 'minimal' " core navigation/editing/git/markdown let g:chopsticks_profile = 'engineer' " default: LSP, ALE, syntax extras let g:chopsticks_profile = 'full' " engineer + heavier Markdown feedback -let g:chopsticks_keymap_style = 'space' " default: Space leader grouped layout -let g:chopsticks_keymap_style = 'classic' " optional: legacy comma leader layout let g:chopsticks_enable_jk_escape = 1 " optional: insert-mode jk exits insert let g:chopsticks_enable_ctrl_s_save = 1 " optional: Ctrl-S saves let g:chopsticks_enable_sudo_save_bang = 1 " optional: :w!! sudo save @@ -98,63 +96,44 @@ Startify, UndoTree, and browser Markdown preview. `full` keeps those and opts into Markdown lint, format, spell, conceal, Marksman, and LSP virtual text. Project updates leave `~/.config/chopsticks.vim` alone, so put local choices -there instead of editing the managed `.vimrc`. The `SPC ?` cheat sheet follows -the active profile and only shows keys for enabled features. +there instead of editing the managed `.vimrc`. The `,?` cheat sheet follows the +active profile and only shows keys for enabled features. ## Keys -Default layout: `space`, leader `SPC`, localleader `,`. - -This is the canonical layout for QWERTY keyboards with CapsLock mapped to -tap-Esc / hold-Ctrl. Escape and Ctrl stay at the system layer; Vim keeps the -native `` window model and standard LSP motions (`gd`, `gr`, `K`). -Git push/pull are intentionally not bound to default hotkeys. Normal-mode `s` -is a screen-local EasyMotion jump; use `cl` for native `s` substitute and `cc` -for native `S`. - -For onboarding, use `:ChopsticksTutor` for a guided practice page, `SPC ?` for -the active keymap, and `:ChopsticksStatus` for tool/LSP health. -`QUICKSTART.md` is the 5-minute path; this README is the full reference. +Leader: `,` ``` -SPC SPC fuzzy find file gd go to definition -SPC / ripgrep project K hover docs -SPC e toggle file sidebar SPC rr run current file -SPC gs git status SPC cf format -SPC w save SPC qq quit -Esc exit insert mode SPC ? cheat sheet +,ff fuzzy find file ,dd go to definition +,rg ripgrep project ,dk hover docs +,e toggle file sidebar ,cr run current file +,gs git status ,f format +,w save ,q quit +Esc exit insert mode ,? cheat sheet ```
-Canonical Space keybindings - -### Fast Path - -`SPC SPC` files | `SPC ,` buffers | `SPC /` grep | `SPC Tab` alternate buffer | `SPC e` browser | `SPC E` browser (file dir) +All keybindings ### Files -`SPC ff` files | `SPC fb` buffers | `SPC fg` git files | `SPC fr` recent | `SPC fl` buffer lines | `SPC fL` all lines | `SPC fv` edit vimrc | `SPC fV` reload vimrc - -### Search - -`SPC sg` grep | `SPC sw` grep word | `SPC s/` search history | `SPC s:` command history | `SPC sm` marks | `SPC st` tags | `SPC sr` replace word +`,ff` find | `,b` buffers | `,rg` grep | `,rG` grep word | `,fh` recent | `,fl` lines | `,e` browser | `,E` browser (file dir) | `,,` last file ### Code -`gd` def | `gr` refs | `gI` impl | `gy` type | `K` docs | `[d` `]d` LSP diagnostics | `[e` `]e` ALE errors | `SPC ca` action | `SPC cr` rename | `SPC cf` format | `SPC co` outline | `SPC ci` LSP status | `SPC rr` run +`,dd` def | `,dt` type | `,di` impl | `,dr` refs | `,dk` docs | `,dp` `,dn` diagnostics | `[e` `]e` ALE errors | `,rn` rename | `,ca` action | `,o` outline | `,cr` run ### Edit -`s`+2ch jump | `SPC S` jump fallback | `cl` native `s` substitute | `cc` native `S` substitute | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `SPC U` undo tree | `SPC y` clipboard | `SPC =` re-indent visual | `SPC cW` strip whitespace | `[` `]` blank lines +`,S`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word | `,F` re-indent (v) | `,W` strip whitespace | `[` `]` blank lines ### Git -`SPC gs` status | `SPC gd` diff | `SPC gb` blame | `SPC gc` commit | `SPC gl` log graph | `SPC gC` FZF commits | `SPC gB` buffer commits | `]x` `[x` conflict +`,gs` status | `,gd` diff | `,gb` blame | `,gc` commit | `,gp` push | `,gl` pull | `,gL` log graph | `,gC` FZF commits | `,gB` buffer commits | `]x` `[x` conflict ### Windows -`hjkl` navigate | `SPC z` maximize | `SPC bp` `SPC bn` buffers | `SPC bd` close buffer | `SPC bo` close other buffers | `SPC tt` `SPC th` terminal | `]q` `[q` quickfix | `SPC xq` `SPC xQ` open/close quickfix | `SPC xl` `SPC xL` open/close loclist +`hjkl` navigate | `,z` maximize | `,h` `,l` buffers | `,bd` close buffer | `,=` `,−` resize | `,tv` `,th` terminal ### Markdown @@ -162,43 +141,6 @@ Esc exit insert mode SPC ? cheat sheet ### Toggle -`F2` paste | `F3` line numbers | `F4` relative numbers | `F6` invisible chars | `SPC us` spell check | `SPC uf` format on save - -### Survival - -`SPC w` save | `SPC W` save all | `SPC qq` quit | `SPC qx` save and quit | `SPC ?` cheat sheet | `:ChopsticksTutor` practice | `:ChopsticksStatus` diagnostics - -
- -
-Legacy classic keybindings - -### Classic Files - -`,ff` find | `,b` buffers | `,rg` grep | `,rG` grep word | `,fh` recent | `,fl` lines | `,e` browser | `,E` browser (file dir) | `,,` last file - -### Classic Code - -`,dd` def | `,dt` type | `,di` impl | `,dr` refs | `,dk` docs | `,dp` `,dn` diagnostics | `[e` `]e` ALE errors | `,rn` rename | `,ca` action | `,o` outline | `,cr` run - -### Classic Edit - -`,S`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word | `,F` re-indent (v) | `,W` strip whitespace | `[` `]` blank lines - -### Classic Git - -`,gs` status | `,gd` diff | `,gb` blame | `,gc` commit | `,gL` log graph | `,gC` FZF commits | `,gB` buffer commits | `]x` `[x` conflict - -### Classic Windows - -`hjkl` navigate | `,z` maximize | `,h` `,l` buffers | `,bd` close buffer | `,=` `,−` resize | `,tv` `,th` terminal - -### Classic Markdown - -`,mp` preview in browser | `,mt` table of contents - -### Classic Toggle - `F2` paste | `F3` line numbers | `F4` relative numbers | `F6` invisible chars | `,ss` spell check | `,af` format on save ### Utilities @@ -252,7 +194,7 @@ For Markdown LSP, install or select `marksman` first. ├── .vimrc thin loader ├── modules/ │ ├── env.vim TTY detection, truecolor, skip built-in plugins -│ ├── plugins.vim vim-plug + 23–25 plugins +│ ├── plugins.vim vim-plug + 24–25 plugins │ ├── core.vim settings, keymaps, performance │ ├── ui.vim solarized, statusline, startify │ ├── editing.vim easymotion, yank highlight, blank lines @@ -261,15 +203,7 @@ For Markdown LSP, install or select `marksman` first. │ ├── lint.vim ale, format-on-save │ ├── git.vim fugitive, gitgutter, conflict nav │ ├── languages.vim vim-go, markdown, filetype settings -│ ├── buffers.vim buffer commands -│ ├── utilities.vim reindent, trim, clipboard, vimrc helpers -│ ├── files.vim auto mkdir, large-file protection -│ ├── runner.vim run current file -│ ├── quickfix.vim quickfix and location-list helpers -│ ├── status.vim :ChopsticksStatus diagnostics -│ ├── cheatsheet.vim SPC ? and :ChopsticksCheatSheet -│ ├── tutor.vim :ChopsticksTutor guided practice -│ └── tools.vim compatibility placeholder +│ └── tools.vim run file, quickfix, cheat sheet, diagnostics ``` Each module is self-contained. Comment out one line in `.vimrc` to disable it. Add your own with `call s:load('mine')`. diff --git a/install.sh b/install.sh index 8cfd327..38da9a4 100755 --- a/install.sh +++ b/install.sh @@ -741,22 +741,22 @@ _I_NPM=-1; _I_PYTHON=-1; _I_GO=-1; _I_TMUX=-1 # Is any package manager available? HAS_PKG_MGR=0 if [[ $HAS_BREW -eq 1 ]] || \ - [[ $HAS_APT -eq 1 || $HAS_PACMAN -eq 1 || $HAS_DNF -eq 1 ]]; then + { [[ $HAS_APT -eq 1 || $HAS_PACMAN -eq 1 || $HAS_DNF -eq 1 ]] && [[ $HAS_SUDO -eq 1 ]]; }; then HAS_PKG_MGR=1 fi # ── System tools ───────────────────────────────────────────────────────────── if [[ $HAS_PKG_MGR -eq 1 ]]; then _I_RIPGREP=$_idx - _ITEMS+=("ripgrep|SPC / project search · SPC sw word search · powers FZF preview|1") + _ITEMS+=("ripgrep|,rg / ,rG project-wide search · powers FZF preview|1") : $(( _idx++ )) _I_FZF=$_idx - _ITEMS+=("fzf|SPC SPC files · SPC , buffers · SPC st tag search|1") + _ITEMS+=("fzf|,ff fuzzy file search · ,b buffers · ,rt tag search|1") : $(( _idx++ )) _I_CTAGS=$_idx - _ITEMS+=("universal-ctags|Optional symbol index for SPC st tag jumps|0") + _ITEMS+=("universal-ctags|Optional symbol index for ,rt tag jumps|0") : $(( _idx++ )) if [[ $_PROFILE_TOOLING -eq 1 ]]; then @@ -848,11 +848,6 @@ _do_sys() { if command -v "$check" >/dev/null 2>&1; then ok "$name (already installed)"; return fi - if [[ $OS != "macos" && $HAS_SUDO -ne 1 ]]; then - skip "$name — sudo not available, install manually" - SKIPPED+=("$name") - return - fi if pkg_install "$brew_p" "$apt_p" "$pac_p" "$dnf_p"; then ok "$name"; INSTALLED+=("$name") else @@ -1206,9 +1201,9 @@ echo -e " ${CYAN}vim .${NC} Open dashboard in current directory" echo -e " ${CYAN}vim myfile${NC} Edit a specific file" echo "" echo -e "${BOLD} First steps inside Vim${NC}" -echo -e " ${CYAN}SPC ?${NC} Open cheat sheet — your map of every keybinding" +echo -e " ${CYAN},?${NC} Open cheat sheet — your map of every keybinding" echo -e " ${CYAN}Esc${NC} Exit insert mode → back to Normal" -echo -e " ${CYAN}SPC qx${NC} Save and quit" +echo -e " ${CYAN},x${NC} Save and quit" echo -e " ${CYAN}:q!${NC} + Enter Emergency quit without saving" if [[ $CONFIG_PROFILE != "minimal" ]]; then echo -e " ${CYAN}:LspInstallServer${NC} Install LSP for current filetype" diff --git a/modules/buffers.vim b/modules/buffers.vim deleted file mode 100644 index 9f43f9e..0000000 --- a/modules/buffers.vim +++ /dev/null @@ -1,18 +0,0 @@ -" buffers.vim — buffer commands - -command! Bclose call BufcloseCloseIt() -function! BufcloseCloseIt() - let l:currentBufNum = bufnr("%") - let l:alternateBufNum = bufnr("#") - if buflisted(l:alternateBufNum) - buffer # - else - bnext - endif - if bufnr("%") == l:currentBufNum - new - endif - if buflisted(l:currentBufNum) - execute("bdelete! " . l:currentBufNum) - endif -endfunction diff --git a/modules/cheatsheet.vim b/modules/cheatsheet.vim deleted file mode 100644 index 0fd4320..0000000 --- a/modules/cheatsheet.vim +++ /dev/null @@ -1,267 +0,0 @@ -" cheatsheet.vim — active keymap reference - -function! s:OpenCheatSheet(lines) abort - let l:name = '__ChopsticksCheatSheet__' - if bufwinnr(l:name) > 0 - execute bufwinnr(l:name) . 'wincmd w | bd' - return - endif - - execute 'vertical botright new ' . l:name - vertical resize 42 - setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile - setlocal nowrap nonumber norelativenumber signcolumn=no - setlocal winfixwidth - call setline(1, a:lines) - setlocal nomodifiable readonly - nnoremap q :bd - nnoremap ? :bd -endfunction - -function! s:CheatSheet() abort - let l:has_lsp = get(g:, 'chopsticks_enable_lsp', 1) - let l:has_lint = get(g:, 'chopsticks_enable_lint', 1) - let l:has_undotree = exists('g:plugs["undotree"]') - let l:has_previm = exists('g:plugs["previm"]') - - if g:chopsticks_space_keymaps - let l:lines = [ - \ ' chopsticks ? close', - \ ' ─────────────────────────────────', - \ '', - \ ' ── fast path ─────────────', - \ ' SPC SPC files', - \ ' SPC , buffers', - \ ' SPC / grep project', - \ ' SPC Tab last file', - \ ' SPC e sidebar (cwd)', - \ ' SPC E sidebar (file dir)', - \ '', - \ ' ── files/find ────────────', - \ ' SPC ff files', - \ ' SPC fb buffers', - \ ' SPC fg git files', - \ ' SPC fr recent files', - \ ' SPC fl lines in buffer', - \ ' SPC sc commands', - \ ' SPC sm marks', - \ ' SPC s/ search history', - \ ' SPC s: command history', - \ ' SPC sg grep project', - \ ' SPC sw grep word', - \ ' SPC st tags', - \ '', - \ ' ── code ──────────────────', - \ ] - - if l:has_lsp - call extend(l:lines, [ - \ ' gd definition', - \ ' gr references', - \ ' gI implementation', - \ ' gy type definition', - \ ' K hover docs', - \ ' [d ]d LSP diagnostics', - \ ' SPC ca code action', - \ ' SPC cr rename', - \ ' SPC cf format', - \ ' SPC ci LSP status', - \ ' SPC co outline', - \ ' SPC cS workspace symbols', - \ ' :LspInstallServer setup LSP', - \ ' :ChopsticksStatus check LSP setup', - \ ]) - endif - - call extend(l:lines, [ - \ ' SPC rr run file', - \ ' SPC cW strip trailing (v)', - \ ' SPC c= re-indent file (opt-in)', - \ ' SPC = re-indent (v)', - \ ]) - if l:has_previm - call add(l:lines, ' ,mp markdown preview') - endif - call add(l:lines, ' ,mt table of contents') - - if l:has_lint - call extend(l:lines, [ - \ ' [e ]e ALE errors', - \ ' SPC xd ALE detail', - \ ' SPC uf format on save', - \ ]) - endif - - call extend(l:lines, [ - \ '', - \ ' ── edit ──────────────────', - \ ' s+2ch easymotion jump', - \ ' gc comment', - \ ' cl / cc native s / S substitute', - \ ' SPC S+2ch jump fallback', - \ ' cs"'' surround', - \ ]) - - if l:has_undotree - call add(l:lines, ' SPC U undo tree') - endif - - call extend(l:lines, [ - \ ' SPC y/p clipboard y/p (v)', - \ ' Alt+j/k move line (v)', - \ ' SPC sr replace word (v)', - \ '', - \ ' ── git ───────────────────', - \ ' SPC gs status', - \ ' SPC gd diff', - \ ' SPC gb blame', - \ ' SPC gc commit', - \ ' SPC gl log graph', - \ ' SPC gC FZF commits', - \ ' SPC gB FZF buffer commits', - \ ' [x ]x conflict markers', - \ '', - \ ' ── windows ───────────────', - \ ' hjkl navigate splits', - \ ' SPC bp/bn prev / next buf', - \ ' SPC bd close buffer', - \ ' SPC bo close other buffers', - \ ' SPC z maximize toggle', - \ ' SPC tt/th terminal / split', - \ ' ]q [q next / prev qf', - \ ' SPC xq/xQ open / close qf', - \ ' SPC xl/xL open / close loclist', - \ '', - \ ' ── toggle ────────────────', - \ ' F2 paste mode', - \ ' F3 line numbers', - \ ' F4 relative numbers', - \ ' F6 invisible chars', - \ ' SPC us spell check', - \ '', - \ ' ── survival ──────────────', - \ ' SPC w save', - \ ' SPC W save all', - \ ' SPC qq quit', - \ ' SPC qx save + quit', - \ ' Esc exit insert', - \ ' SPC fv edit vimrc', - \ ' SPC fV reload vimrc', - \ ' :ChopsticksTutor practice', - \ ' :ChopsticksStatus health', - \ ]) - - call s:OpenCheatSheet(l:lines) - return - endif - - let l:lines = [ - \ ' chopsticks ,? close', - \ ' ─────────────────────────────', - \ '', - \ ' ── files ──────────────────', - \ ' ,ff files', - \ ' ,b buffers', - \ ' ,rg grep project', - \ ' ,rG grep word', - \ ' ,e sidebar (cwd)', - \ ' ,E sidebar (file dir)', - \ ' ,, last file', - \ ' ,fh recent files', - \ ' ,fl lines in buffer', - \ ' ,fc commands', - \ ' ,fm marks', - \ '', - \ ' ── code ──────────────────', - \ ] - - if l:has_lsp - call extend(l:lines, [ - \ ' ,dd definition', - \ ' ,dt type definition', - \ ' ,di implementation', - \ ' ,dr references', - \ ' ,dk hover docs', - \ ' ,rn rename', - \ ' ,ca code action', - \ ' ,f format', - \ ' ,o outline', - \ ' ,dp ,dn LSP diagnostics', - \ ' :LspInstallServer setup LSP', - \ ' :ChopsticksStatus check LSP setup', - \ ]) - endif - - call add(l:lines, ' ,cr run file') - if l:has_previm - call add(l:lines, ' ,mp markdown preview') - endif - call add(l:lines, ' ,mt table of contents') - - if l:has_lint - call extend(l:lines, [ - \ ' [e ]e ALE errors', - \ ' ,af format on save', - \ ]) - endif - - call extend(l:lines, [ - \ '', - \ ' ── edit ──────────────────', - \ ' gc comment', - \ ' ,S+2ch easymotion jump', - \ ' cs"'' surround', - \ ]) - - if l:has_undotree - call add(l:lines, ' ,u undo tree') - endif - - call extend(l:lines, [ - \ ' ,y ,p clipboard y/p (v)', - \ ' Alt+j/k move line (v)', - \ ' ,* replace word (v)', - \ ' ,F re-indent (v)', - \ ' ,W strip trailing (v)', - \ '', - \ ' ── git ───────────────────', - \ ' ,gs status', - \ ' ,gd diff', - \ ' ,gb blame', - \ ' ,gc commit', - \ ' ,gL log graph', - \ ' ,gC FZF commits', - \ ' [x ]x conflict markers', - \ '', - \ ' ── windows ───────────────', - \ ' hjkl navigate splits', - \ ' ,h ,l prev / next buf', - \ ' ,bd close buffer', - \ ' ,z maximize toggle', - \ ' ,= ,- resize height', - \ ' ,tv ,th terminal v / h', - \ ' ]q [q next / prev qf', - \ ' ,qo ,qc open / close qf', - \ '', - \ ' ── toggle ────────────────', - \ ' F2 paste mode', - \ ' F3 line numbers', - \ ' F4 relative numbers', - \ ' F6 invisible chars', - \ ' ,ss spell check', - \ '', - \ ' ── survival ──────────────', - \ ' ,w save', - \ ' ,q quit', - \ ' ,x save + quit', - \ ' Esc exit insert', - \ ' ,ev edit vimrc', - \ ' ,sv reload vimrc', - \ ' :ChopsticksTutor practice', - \ ' :ChopsticksStatus health', - \ ]) - - call s:OpenCheatSheet(l:lines) -endfunction -command! ChopsticksCheatSheet call s:CheatSheet() -nnoremap ? :ChopsticksCheatSheet diff --git a/modules/core.vim b/modules/core.vim index 81174dc..2194ff5 100644 --- a/modules/core.vim +++ b/modules/core.vim @@ -94,44 +94,22 @@ set smartindent " ── Leader ────────────────────────────────────────────────────────────────── -if g:chopsticks_space_keymaps - let mapleader = "\" - let maplocalleader = "," -else - let mapleader = "," -endif +let mapleader = "," " ── Basic Keymaps ─────────────────────────────────────────────────────────── -if g:chopsticks_space_keymaps - nnoremap w :w - nnoremap W :wa - nnoremap qq :q - nnoremap qx :x +nnoremap w :w +nnoremap q :q +nnoremap x :x - nnoremap uh :noh +nnoremap :noh - nnoremap bd :Bclose - nnoremap ba :bufdo bd - nnoremap bo :%bde#bd# - nnoremap bn :bnext - nnoremap bp :bprevious +nnoremap bd :Bclose +nnoremap ba :bufdo bd +nnoremap l :bnext +nnoremap h :bprevious - nnoremap fd :lcd %:p:h:pwd -else - nnoremap w :w - nnoremap q :q - nnoremap x :x - - nnoremap :noh - - nnoremap bd :Bclose - nnoremap ba :bufdo bd - nnoremap l :bnext - nnoremap h :bprevious - - nnoremap cd :lcd %:p:h:pwd -endif +nnoremap cd :lcd %:p:h:pwd nnoremap v `[v`] @@ -140,11 +118,7 @@ nnoremap :m .-2== vnoremap :m '>+1gv=gv vnoremap :m '<-2gv=gv -if g:chopsticks_space_keymaps - nnoremap us :setlocal spell!:echo 'Spell: ' . (&spell ? 'ON' : 'OFF') -else - nnoremap ss :setlocal spell!:echo 'Spell: ' . (&spell ? 'ON' : 'OFF') -endif +nnoremap ss :setlocal spell!:echo 'Spell: ' . (&spell ? 'ON' : 'OFF') nnoremap :set paste!:echo 'Paste: ' . (&paste ? 'ON' : 'OFF') nnoremap :set invnumber:echo 'Line numbers: ' . (&number ? 'ON' : 'OFF') @@ -183,15 +157,8 @@ if has('clipboard') vnoremap P "+P endif -if g:chopsticks_space_keymaps - nnoremap xq :copen - nnoremap xQ :cclose - nnoremap xl :lopen - nnoremap xL :lclose -else - nnoremap qo :copen - nnoremap qc :cclose -endif +nnoremap qo :copen +nnoremap qc :cclose augroup ChopstickResize autocmd! @@ -226,10 +193,7 @@ endif set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal if has("patch-8.1.0360") - silent! set diffopt+=internal - silent! set diffopt+=context:3 - silent! set diffopt+=algorithm:histogram - silent! set diffopt+=indent-heuristic + set diffopt=filler,internal,context:3,algorithm:histogram,indent-heuristic endif " ── Format Options ────────────────────────────────────────────────────────── diff --git a/modules/editing.vim b/modules/editing.vim index e434006..9a9dd0c 100644 --- a/modules/editing.vim +++ b/modules/editing.vim @@ -6,27 +6,16 @@ let g:EasyMotion_do_mapping = 0 let g:EasyMotion_smartcase = 1 if exists('g:plugs["vim-easymotion"]') - if g:chopsticks_space_keymaps - " In the canonical layout, cl/cc cover native s/S substitute behavior; - " s becomes the fastest screen-local jump entry. - nmap s (easymotion-overwin-f2) - nmap S (easymotion-overwin-f2) - else - nmap S (easymotion-overwin-f2) - nmap j (easymotion-j) - nmap k (easymotion-k) - endif + nmap S (easymotion-overwin-f2) + nmap j (easymotion-j) + nmap k (easymotion-k) endif " ── UndoTree ──────────────────────────────────────────────────────────────── if exists('g:plugs["undotree"]') nnoremap :UndotreeToggle - if g:chopsticks_space_keymaps - nnoremap U :UndotreeToggle - else - nnoremap u :UndotreeToggle - endif + nnoremap u :UndotreeToggle endif " ── Yank Highlight ────────────────────────────────────────────────────────── diff --git a/modules/env.vim b/modules/env.vim index 7fc42e9..6e0a3b6 100644 --- a/modules/env.vim +++ b/modules/env.vim @@ -11,12 +11,6 @@ if index(['minimal', 'engineer', 'full'], g:chopsticks_profile) < 0 let g:chopsticks_profile = 'engineer' endif -let g:chopsticks_keymap_style = get(g:, 'chopsticks_keymap_style', 'space') -if index(['classic', 'space'], g:chopsticks_keymap_style) < 0 - let g:chopsticks_keymap_style = 'space' -endif -let g:chopsticks_space_keymaps = g:chopsticks_keymap_style ==# 'space' - let s:profile_full = g:chopsticks_profile ==# 'full' let s:profile_minimal = g:chopsticks_profile ==# 'minimal' diff --git a/modules/files.vim b/modules/files.vim deleted file mode 100644 index 4f64bc1..0000000 --- a/modules/files.vim +++ /dev/null @@ -1,54 +0,0 @@ -" files.vim — file safety and large-file handling - -function! s:MkNonExDir(file, buf) - if empty(getbufvar(a:buf, '&buftype')) && a:file !~# '\v^\w+\:\/' - let dir = fnamemodify(a:file, ':h') - if !isdirectory(dir) - call mkdir(dir, 'p') - endif - endif -endfunction -augroup BWCCreateDir - autocmd! - autocmd BufWritePre * - \ if !empty(expand('')) | - \ call s:MkNonExDir(expand(''), +expand('')) | - \ endif -augroup END - -let g:LargeFile = get(g:, 'LargeFile', 1024 * 1024 * 10) -let s:tty_large = g:is_tty ? 512000 : g:LargeFile - -function! s:ApplyLargeFileSettings() abort - if get(b:, 'chopsticks_large_file', 0) - setlocal bufhidden=unload undolevels=-1 noswapfile - let b:ale_enabled = 0 - if &l:syntax !=# '' - setlocal syntax= - endif - elseif get(b:, 'chopsticks_tty_large_file', 0) - if &l:syntax !=# '' - setlocal syntax= - endif - endif -endfunction - -function! s:MarkLargeFile(file) abort - if empty(a:file) - return - endif - - let l:fsize = getfsize(a:file) - if l:fsize > g:LargeFile || l:fsize == -2 - let b:chopsticks_large_file = 1 - elseif g:is_tty && l:fsize > s:tty_large - let b:chopsticks_tty_large_file = 1 - endif - call s:ApplyLargeFileSettings() -endfunction - -augroup ChopstickLargeFile - autocmd! - autocmd BufReadPre * call s:MarkLargeFile(expand('')) - autocmd BufReadPost,FileType,Syntax * call s:ApplyLargeFileSettings() -augroup END diff --git a/modules/git.vim b/modules/git.vim index 7392897..3bd4b1d 100644 --- a/modules/git.vim +++ b/modules/git.vim @@ -14,13 +14,11 @@ let g:gitgutter_sign_modified_removed = '~' if exists('g:plugs["vim-fugitive"]') nnoremap gs :Git status nnoremap gc :Git commit + nnoremap gp :Git push + nnoremap gl :Git pull nnoremap gd :Gdiffsplit nnoremap gb :Git blame - if g:chopsticks_space_keymaps - nnoremap gl :Git log --oneline --graph -20 - else - nnoremap gL :Git log --oneline --graph -20 - endif + nnoremap gL :Git log --oneline --graph -20 endif " ── Conflict Navigation ──────────────────────────────────────────────────── diff --git a/modules/languages.vim b/modules/languages.vim index 11f1204..2c4688d 100644 --- a/modules/languages.vim +++ b/modules/languages.vim @@ -14,16 +14,7 @@ let g:vim_markdown_follow_anchor = 1 let g:vim_markdown_new_list_item_indent = 2 let g:vim_markdown_strikethrough = 1 -function! s:MarkdownKeymaps() abort - if exists('g:plugs["vim-markdown"]') - nnoremap mt :Toc - endif - if exists('g:plugs["previm"]') - nnoremap mp :PrevimOpen - endif -endfunction - -if exists('g:plugs["vim-markdown"]') && !g:chopsticks_space_keymaps +if exists('g:plugs["vim-markdown"]') nnoremap mt :Toc endif @@ -33,7 +24,7 @@ elseif executable('xdg-open') let g:previm_open_cmd = 'xdg-open' endif let g:previm_enable_realtime = get(g:, 'previm_enable_realtime', 0) -if exists('g:plugs["previm"]') && !g:chopsticks_space_keymaps +if exists('g:plugs["previm"]') nnoremap mp :PrevimOpen endif @@ -87,7 +78,6 @@ augroup ChopstickFiletype autocmd FileType yaml \ setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType markdown call s:MarkdownDefaults() - autocmd FileType markdown if g:chopsticks_space_keymaps | call s:MarkdownKeymaps() | endif autocmd FileType sh \ setlocal expandtab shiftwidth=2 tabstop=2 textwidth=80 autocmd FileType make diff --git a/modules/lint.vim b/modules/lint.vim index 4d4de28..fd01286 100644 --- a/modules/lint.vim +++ b/modules/lint.vim @@ -64,13 +64,7 @@ let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 'disabled') if exists('g:plugs["ale"]') nnoremap [e :ALEPrevious nnoremap ]e :ALENext - if g:chopsticks_space_keymaps - nnoremap xd :ALEDetail - nnoremap uf :let g:ale_fix_on_save = !g:ale_fix_on_save - \ echo 'Format on save: ' . (g:ale_fix_on_save ? 'ON' : 'OFF') - else - nnoremap aD :ALEDetail - nnoremap af :let g:ale_fix_on_save = !g:ale_fix_on_save - \ echo 'Format on save: ' . (g:ale_fix_on_save ? 'ON' : 'OFF') - endif + nnoremap aD :ALEDetail + nnoremap af :let g:ale_fix_on_save = !g:ale_fix_on_save + \ echo 'Format on save: ' . (g:ale_fix_on_save ? 'ON' : 'OFF') endif diff --git a/modules/lsp.vim b/modules/lsp.vim index 9919731..9ff421b 100644 --- a/modules/lsp.vim +++ b/modules/lsp.vim @@ -65,42 +65,23 @@ function! s:on_lsp_buffer_enabled() abort setlocal signcolumn=yes endif - if g:chopsticks_space_keymaps - nmap gd (lsp-definition) - nmap gr (lsp-references) - nmap gI (lsp-implementation) - nmap gy (lsp-type-definition) - nmap K (lsp-hover) - nmap [d (lsp-previous-diagnostic) - nmap ]d (lsp-next-diagnostic) + nmap dd (lsp-definition) + nmap dt (lsp-type-definition) + nmap di (lsp-implementation) + nmap dr (lsp-references) + nmap dp (lsp-previous-diagnostic) + nmap dn (lsp-next-diagnostic) - nmap ca (lsp-code-action) - nmap cr (lsp-rename) - nmap cf (lsp-document-format) - xmap cf (lsp-document-range-format) + nmap dk (lsp-hover) - nnoremap ci :LspStatus - nmap co (lsp-document-symbol-search) - nmap cS (lsp-workspace-symbol-search) - else - nmap dd (lsp-definition) - nmap dt (lsp-type-definition) - nmap di (lsp-implementation) - nmap dr (lsp-references) - nmap dp (lsp-previous-diagnostic) - nmap dn (lsp-next-diagnostic) + nmap rn (lsp-rename) + nmap ca (lsp-code-action) + nmap f (lsp-document-format) + xmap f (lsp-document-range-format) - nmap dk (lsp-hover) - - nmap rn (lsp-rename) - nmap ca (lsp-code-action) - nmap f (lsp-document-format) - xmap f (lsp-document-range-format) - - nmap o (lsp-document-symbol-search) - nmap ws (lsp-workspace-symbol-search) - nmap cD (lsp-document-diagnostics) - endif + nmap o (lsp-document-symbol-search) + nmap ws (lsp-workspace-symbol-search) + nmap cD (lsp-document-diagnostics) endfunction augroup lsp_install diff --git a/modules/navigation.vim b/modules/navigation.vim index d133dd4..45b2ad5 100644 --- a/modules/navigation.vim +++ b/modules/navigation.vim @@ -47,42 +47,21 @@ function! s:SmartFiles() abort endfunction if exists('g:plugs["fzf.vim"]') - if g:chopsticks_space_keymaps - nnoremap :call SmartFiles() - nnoremap , :Buffers - nnoremap / :Rg - nnoremap ff :call SmartFiles() - nnoremap fb :Buffers - nnoremap fg :GFiles - nnoremap fr :History - nnoremap fl :BLines - nnoremap fL :Lines - nnoremap s/ :History/ - nnoremap s: :History: - nnoremap sc :Commands - nnoremap sm :Marks - nnoremap sg :Rg - nnoremap sw :RgWord - nnoremap st :Tags - nnoremap gC :Commits - nnoremap gB :BCommits - else - nnoremap ff :call SmartFiles() - nnoremap b :Buffers - nnoremap rg :Rg - nnoremap rG :RgWord - nnoremap rt :Tags - nnoremap gF :GFiles - nnoremap fh :History - nnoremap fc :Commands - nnoremap fm :Marks - nnoremap fl :BLines - nnoremap fL :Lines - nnoremap f/ :History/ - nnoremap f: :History: - nnoremap gC :Commits - nnoremap gB :BCommits - endif + nnoremap ff :call SmartFiles() + nnoremap b :Buffers + nnoremap rg :Rg + nnoremap rG :RgWord + nnoremap rt :Tags + nnoremap gF :GFiles + nnoremap fh :History + nnoremap fc :Commands + nnoremap fm :Marks + nnoremap fl :BLines + nnoremap fL :Lines + nnoremap f/ :History/ + nnoremap f: :History: + nnoremap gC :Commits + nnoremap gB :BCommits endif let g:fzf_layout = { 'down': '40%' } @@ -120,22 +99,13 @@ function! s:ToggleMaximize() abort echo 'Window: MAXIMIZED' endif endfunction -if g:chopsticks_space_keymaps - nnoremap z :call ToggleMaximize() -else - nnoremap z :call ToggleMaximize() -endif +nnoremap z :call ToggleMaximize() " ── Terminal ──────────────────────────────────────────────────────────────── if has('terminal') - if g:chopsticks_space_keymaps - nnoremap tt :terminal - nnoremap th :terminal ++rows=10 - else - nnoremap tv :terminal - nnoremap th :terminal ++rows=10 - endif + nnoremap tv :terminal + nnoremap th :terminal ++rows=10 if g:chopsticks_enable_terminal_keymaps tnoremap tnoremap h diff --git a/modules/quickfix.vim b/modules/quickfix.vim deleted file mode 100644 index f7ffee3..0000000 --- a/modules/quickfix.vim +++ /dev/null @@ -1,10 +0,0 @@ -" quickfix.vim — quickfix and location-list helpers - -augroup ChopstickQF - autocmd! - autocmd QuickFixCmdPost [^l]* cwindow - autocmd QuickFixCmdPost l* lwindow -augroup END - -nnoremap ]q :cnext -nnoremap [q :cprev diff --git a/modules/runner.vim b/modules/runner.vim deleted file mode 100644 index 3618b24..0000000 --- a/modules/runner.vim +++ /dev/null @@ -1,28 +0,0 @@ -" runner.vim — run the current file by filetype - -function! s:RunFile() abort - write - let l:ft = &filetype - let l:file = shellescape(expand('%:p')) - if l:ft ==# 'python' | execute '!python3 ' . l:file - elseif l:ft ==# 'javascript' | execute '!node ' . l:file - elseif l:ft ==# 'typescript' | execute '!npx ts-node ' . l:file - elseif l:ft ==# 'go' | execute '!go run ' . l:file - elseif l:ft ==# 'rust' | execute '!cargo run' - elseif l:ft ==# 'sh' | execute '!bash ' . l:file - elseif l:ft ==# 'c' - let l:out_path = tempname() - let l:out = shellescape(l:out_path) - execute '!gcc -o ' . l:out . ' ' . l:file . ' && ' . l:out - call delete(l:out_path) - elseif l:ft ==# 'lua' | execute '!lua ' . l:file - elseif l:ft ==# 'ruby' | execute '!ruby ' . l:file - elseif l:ft ==# 'perl' | execute '!perl ' . l:file - else | echo 'No runner for filetype: ' . l:ft - endif -endfunction -if g:chopsticks_space_keymaps - nnoremap rr :call RunFile() -else - nnoremap cr :call RunFile() -endif diff --git a/modules/status.vim b/modules/status.vim deleted file mode 100644 index bafcf06..0000000 --- a/modules/status.vim +++ /dev/null @@ -1,165 +0,0 @@ -" status.vim — health diagnostics - -function! s:Check(name, cmd) abort - return executable(a:cmd) ? ' OK ' . a:name : ' -- ' . a:name . ' (missing: ' . a:cmd . ')' -endfunction - -function! s:Off(name, reason) abort - return ' off ' . a:name . ' (' . a:reason . ')' -endfunction - -function! s:PlugDir(name) abort - if !exists('g:plugs') || !has_key(g:plugs, a:name) - return '' - endif - return fnamemodify(get(g:plugs[a:name], 'dir', ''), ':p') -endfunction - -function! s:PlugInstalled(name) abort - let l:dir = s:PlugDir(a:name) - return !empty(l:dir) && isdirectory(l:dir) -endfunction - -function! s:LspStackIssue() abort - if !get(g:, 'chopsticks_enable_lsp', 1) - return 'LSP disabled by profile' - endif - if empty(s:PlugDir('vim-lsp')) - return 'vim-lsp not declared by this profile' - endif - if !s:PlugInstalled('vim-lsp') - return 'vim-lsp not installed; run :PlugInstall' - endif - if empty(s:PlugDir('vim-lsp-settings')) - return 'vim-lsp-settings not declared by this profile' - endif - if !s:PlugInstalled('vim-lsp-settings') - return 'vim-lsp-settings not installed; run :PlugInstall' - endif - return '' -endfunction - -function! s:LspStackCheck() abort - let l:issue = s:LspStackIssue() - if l:issue ==# 'LSP disabled by profile' - return s:Off('vim-lsp stack', l:issue) - endif - if !empty(l:issue) - return ' -- vim-lsp stack (' . l:issue . ')' - endif - if exists(':LspStatus') == 2 || exists(':LspInstallServer') == 2 - return ' OK vim-lsp stack (installed)' - endif - return ' OK vim-lsp stack (installed; not loaded yet)' -endfunction - -function! s:LspCheck(ft, server) abort - let l:issue = s:LspStackIssue() - if l:issue ==# 'LSP disabled by profile' - return s:Off(a:ft, l:issue) - endif - if !empty(l:issue) - return ' -- ' . a:ft . ' (' . l:issue . ')' - endif - let l:dir = expand('~/.local/share/vim-lsp-settings/servers/' . a:server) - if isdirectory(l:dir) - return ' OK ' . a:ft . ' (' . a:server . ')' - endif - return ' -- ' . a:ft . ' (:LspInstallServer in a ' . a:ft . ' file)' -endfunction - -function! s:ChopsticksStatus() abort - let l:lines = [] - call add(l:lines, 'chopsticks status') - call add(l:lines, repeat('─', 50)) - call add(l:lines, '') - - call add(l:lines, '── system tools ──') - call add(l:lines, s:Check('fzf', 'fzf')) - call add(l:lines, s:Check('ripgrep', 'rg')) - call add(l:lines, s:Check('git', 'git')) - call add(l:lines, s:Check('curl', 'curl')) - call add(l:lines, s:Check('node', 'node')) - call add(l:lines, s:Check('python3', 'python3')) - call add(l:lines, s:Check('go', 'go')) - call add(l:lines, '') - - call add(l:lines, '── lsp servers ── (:LspInstallServer to install)') - call add(l:lines, s:LspStackCheck()) - if get(g:, 'chopsticks_enable_lsp', 1) - call add(l:lines, ' LSP actions are buffer-local and start after a server attaches.') - call add(l:lines, ' Missing one? Open that filetype and run :LspInstallServer once.') - endif - call add(l:lines, s:LspCheck('python', 'pylsp')) - call add(l:lines, s:LspCheck('go', 'gopls')) - call add(l:lines, s:LspCheck('rust', 'rust-analyzer')) - call add(l:lines, s:LspCheck('typescript', 'typescript-language-server')) - call add(l:lines, s:LspCheck('c/c++', 'clangd')) - call add(l:lines, s:LspCheck('bash', 'bash-language-server')) - call add(l:lines, s:LspCheck('html', 'vscode-html-language-server')) - call add(l:lines, s:LspCheck('json', 'vscode-json-language-server')) - call add(l:lines, s:LspCheck('yaml', 'yaml-language-server')) - call add(l:lines, s:LspCheck('markdown', 'marksman')) - call add(l:lines, s:LspCheck('sql', 'sqls')) - call add(l:lines, '') - - call add(l:lines, '── linters ──') - if get(g:, 'chopsticks_enable_lint', 1) - call add(l:lines, s:Check('flake8 (python)', 'flake8')) - call add(l:lines, s:Check('pylint (python)', 'pylint')) - call add(l:lines, s:Check('eslint (js/ts)', 'eslint')) - call add(l:lines, s:Check('staticcheck (go)', 'staticcheck')) - call add(l:lines, s:Check('shellcheck (sh)', 'shellcheck')) - call add(l:lines, s:Check('yamllint (yaml)', 'yamllint')) - call add(l:lines, s:Check('hadolint (docker)', 'hadolint')) - if get(g:, 'chopsticks_markdown_lint', 0) - call add(l:lines, s:Check('markdownlint (md)', 'markdownlint')) - else - call add(l:lines, s:Off('markdownlint (md)', 'disabled by default')) - endif - else - call add(l:lines, s:Off('ALE linters', 'lint disabled by profile')) - endif - call add(l:lines, '') - - call add(l:lines, '── formatters ── (format-on-save is ' . (get(g:, 'ale_fix_on_save', 0) ? 'ON' : 'OFF') . ')') - if get(g:, 'chopsticks_enable_lint', 1) - call add(l:lines, s:Check('black (python)', 'black')) - call add(l:lines, s:Check('isort (python)', 'isort')) - call add(l:lines, s:Check('prettier (js/ts/json)', 'prettier')) - if get(g:, 'chopsticks_markdown_format_on_save', 0) - call add(l:lines, s:Check('prettier (md)', 'prettier')) - else - call add(l:lines, s:Off('prettier (md)', 'disabled by default')) - endif - call add(l:lines, s:Check('goimports (go)', 'goimports')) - call add(l:lines, s:Check('rustfmt (rust)', 'rustfmt')) - call add(l:lines, s:Check('clang-format (c)', 'clang-format')) - else - call add(l:lines, s:Off('ALE formatters', 'lint disabled by profile')) - endif - call add(l:lines, '') - - let l:ok = len(filter(copy(l:lines), 'v:val =~# " OK "')) - let l:miss = len(filter(copy(l:lines), 'v:val =~# " -- "')) - call add(l:lines, repeat('─', 50)) - call add(l:lines, ' ' . l:ok . ' ready, ' . l:miss . ' missing') - call add(l:lines, '') - call add(l:lines, ' Install missing tools with ./install.sh') - if get(g:, 'chopsticks_enable_lsp', 1) - call add(l:lines, ' Install LSP servers with :LspInstallServer') - endif - - let l:name = '__ChopsticksStatus__' - if bufwinnr(l:name) > 0 - execute bufwinnr(l:name) . 'wincmd w | bd' - endif - execute 'botright new ' . l:name - resize 45 - setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile - setlocal nowrap nonumber norelativenumber signcolumn=no - call setline(1, l:lines) - setlocal nomodifiable readonly - nnoremap q :bd -endfunction -command! ChopsticksStatus call s:ChopsticksStatus() diff --git a/modules/tools.vim b/modules/tools.vim index 9d2b120..8506389 100644 --- a/modules/tools.vim +++ b/modules/tools.vim @@ -1,4 +1,445 @@ -" tools.vim — compatibility placeholder -" -" Tooling was split into granular modules: -" buffers, utilities, files, runner, quickfix, status, cheatsheet, and tutor. +" tools.vim — run file, sudo save, quickfix, helpers + +" ── Buffer Close ─────────────────────────────────────────────────────────── + +command! Bclose call BufcloseCloseIt() +function! BufcloseCloseIt() + let l:currentBufNum = bufnr("%") + let l:alternateBufNum = bufnr("#") + if buflisted(l:alternateBufNum) + buffer # + else + bnext + endif + if bufnr("%") == l:currentBufNum + new + endif + if buflisted(l:currentBufNum) + execute("bdelete! " . l:currentBufNum) + endif +endfunction + +" ── Utilities ────────────────────────────────────────────────────────────── + +if get(g:, 'chopsticks_enable_reindent_file', 0) + nnoremap F gg=G`` +endif +vnoremap F = +nnoremap wa :wa + +nnoremap = :exe "resize " . (winheight(0) * 3/2) +nnoremap - :exe "resize " . (winheight(0) * 2/3) + +nnoremap + +nnoremap W :%s/\s\+$//:let @/='' +vnoremap W :s/\s\+$//:let @/=''gv + +nnoremap ev :edit $MYVIMRC +nnoremap sv :unlet! g:chopsticks_loaded:execute 'source ' . fnameescape($MYVIMRC):echo "vimrc reloaded" + +nnoremap * :%s/\<\>//g +vnoremap * :s///g + +if has('clipboard') + nnoremap cp :let @+ = expand("%:p"):echo "Copied: " . expand("%:p") + nnoremap cf :let @+ = expand("%:t"):echo "Copied: " . expand("%:t") +endif + +" ── Auto-Create Directories ───────────────────────────────────────────────── + +function! s:MkNonExDir(file, buf) + if empty(getbufvar(a:buf, '&buftype')) && a:file !~# '\v^\w+\:\/' + let dir = fnamemodify(a:file, ':h') + if !isdirectory(dir) + call mkdir(dir, 'p') + endif + endif +endfunction +augroup BWCCreateDir + autocmd! + autocmd BufWritePre * + \ if !empty(expand('')) | + \ call s:MkNonExDir(expand(''), +expand('')) | + \ endif +augroup END + +" ── Large File Handling ────────────────────────────────────────────────────── + +let g:LargeFile = get(g:, 'LargeFile', 1024 * 1024 * 10) +let s:tty_large = g:is_tty ? 512000 : g:LargeFile + +function! s:ApplyLargeFileSettings() abort + if get(b:, 'chopsticks_large_file', 0) + setlocal bufhidden=unload undolevels=-1 noswapfile + let b:ale_enabled = 0 + if &l:syntax !=# '' + setlocal syntax= + endif + elseif get(b:, 'chopsticks_tty_large_file', 0) + if &l:syntax !=# '' + setlocal syntax= + endif + endif +endfunction + +function! s:MarkLargeFile(file) abort + if empty(a:file) + return + endif + + let l:fsize = getfsize(a:file) + if l:fsize > g:LargeFile || l:fsize == -2 + let b:chopsticks_large_file = 1 + elseif g:is_tty && l:fsize > s:tty_large + let b:chopsticks_tty_large_file = 1 + endif + call s:ApplyLargeFileSettings() +endfunction + +augroup ChopstickLargeFile + autocmd! + autocmd BufReadPre * call s:MarkLargeFile(expand('')) + autocmd BufReadPost,FileType,Syntax * call s:ApplyLargeFileSettings() +augroup END + +" ── Run Current File (,cr) ────────────────────────────────────────────────── + +function! s:RunFile() abort + write + let l:ft = &filetype + let l:file = shellescape(expand('%:p')) + if l:ft ==# 'python' | execute '!python3 ' . l:file + elseif l:ft ==# 'javascript' | execute '!node ' . l:file + elseif l:ft ==# 'typescript' | execute '!npx ts-node ' . l:file + elseif l:ft ==# 'go' | execute '!go run ' . l:file + elseif l:ft ==# 'rust' | execute '!cargo run' + elseif l:ft ==# 'sh' | execute '!bash ' . l:file + elseif l:ft ==# 'c' + let l:out_path = tempname() + let l:out = shellescape(l:out_path) + execute '!gcc -o ' . l:out . ' ' . l:file . ' && ' . l:out + call delete(l:out_path) + elseif l:ft ==# 'lua' | execute '!lua ' . l:file + elseif l:ft ==# 'ruby' | execute '!ruby ' . l:file + elseif l:ft ==# 'perl' | execute '!perl ' . l:file + else | echo 'No runner for filetype: ' . l:ft + endif +endfunction +nnoremap cr :call RunFile() + +" ── Sudo Save ─────────────────────────────────────────────────────────────── + +if get(g:, 'chopsticks_enable_sudo_save_bang', 0) + cnoremap w!! w !sudo tee > /dev/null % +endif + +" ── QuickFix ──────────────────────────────────────────────────────────────── + +augroup ChopstickQF + autocmd! + autocmd QuickFixCmdPost [^l]* cwindow + autocmd QuickFixCmdPost l* lwindow +augroup END + +nnoremap ]q :cnext +nnoremap [q :cprev + +" ── Status Diagnostic (:ChopsticksStatus) ─────────────────────────────────── + +function! s:Check(name, cmd) abort + return executable(a:cmd) ? ' OK ' . a:name : ' -- ' . a:name . ' (missing: ' . a:cmd . ')' +endfunction + +function! s:Off(name, reason) abort + return ' off ' . a:name . ' (' . a:reason . ')' +endfunction + +function! s:PlugDir(name) abort + if !exists('g:plugs') || !has_key(g:plugs, a:name) + return '' + endif + return fnamemodify(get(g:plugs[a:name], 'dir', ''), ':p') +endfunction + +function! s:PlugInstalled(name) abort + let l:dir = s:PlugDir(a:name) + return !empty(l:dir) && isdirectory(l:dir) +endfunction + +function! s:LspStackIssue() abort + if !get(g:, 'chopsticks_enable_lsp', 1) + return 'LSP disabled by profile' + endif + if empty(s:PlugDir('vim-lsp')) + return 'vim-lsp not declared by this profile' + endif + if !s:PlugInstalled('vim-lsp') + return 'vim-lsp not installed; run :PlugInstall' + endif + if empty(s:PlugDir('vim-lsp-settings')) + return 'vim-lsp-settings not declared by this profile' + endif + if !s:PlugInstalled('vim-lsp-settings') + return 'vim-lsp-settings not installed; run :PlugInstall' + endif + return '' +endfunction + +function! s:LspStackCheck() abort + let l:issue = s:LspStackIssue() + if l:issue ==# 'LSP disabled by profile' + return s:Off('vim-lsp stack', l:issue) + endif + if !empty(l:issue) + return ' -- vim-lsp stack (' . l:issue . ')' + endif + if exists(':LspStatus') == 2 || exists(':LspInstallServer') == 2 + return ' OK vim-lsp stack (installed)' + endif + return ' OK vim-lsp stack (installed; not loaded yet)' +endfunction + +function! s:LspCheck(ft, server) abort + let l:issue = s:LspStackIssue() + if l:issue ==# 'LSP disabled by profile' + return s:Off(a:ft, l:issue) + endif + if !empty(l:issue) + return ' -- ' . a:ft . ' (' . l:issue . ')' + endif + let l:dir = expand('~/.local/share/vim-lsp-settings/servers/' . a:server) + if isdirectory(l:dir) + return ' OK ' . a:ft . ' (' . a:server . ')' + endif + return ' -- ' . a:ft . ' (:LspInstallServer in a ' . a:ft . ' file)' +endfunction + +function! s:ChopsticksStatus() abort + let l:lines = [] + call add(l:lines, 'chopsticks status') + call add(l:lines, repeat('─', 50)) + call add(l:lines, '') + + call add(l:lines, '── system tools ──') + call add(l:lines, s:Check('fzf', 'fzf')) + call add(l:lines, s:Check('ripgrep', 'rg')) + call add(l:lines, s:Check('git', 'git')) + call add(l:lines, s:Check('curl', 'curl')) + call add(l:lines, s:Check('node', 'node')) + call add(l:lines, s:Check('python3', 'python3')) + call add(l:lines, s:Check('go', 'go')) + call add(l:lines, '') + + call add(l:lines, '── lsp servers ── (:LspInstallServer to install)') + call add(l:lines, s:LspStackCheck()) + if get(g:, 'chopsticks_enable_lsp', 1) + call add(l:lines, ' LSP actions are buffer-local and start after a server attaches.') + call add(l:lines, ' Missing one? Open that filetype and run :LspInstallServer once.') + endif + call add(l:lines, s:LspCheck('python', 'pylsp')) + call add(l:lines, s:LspCheck('go', 'gopls')) + call add(l:lines, s:LspCheck('rust', 'rust-analyzer')) + call add(l:lines, s:LspCheck('typescript', 'typescript-language-server')) + call add(l:lines, s:LspCheck('c/c++', 'clangd')) + call add(l:lines, s:LspCheck('bash', 'bash-language-server')) + call add(l:lines, s:LspCheck('html', 'vscode-html-language-server')) + call add(l:lines, s:LspCheck('json', 'vscode-json-language-server')) + call add(l:lines, s:LspCheck('yaml', 'yaml-language-server')) + call add(l:lines, s:LspCheck('markdown', 'marksman')) + call add(l:lines, s:LspCheck('sql', 'sqls')) + call add(l:lines, '') + + call add(l:lines, '── linters ──') + if get(g:, 'chopsticks_enable_lint', 1) + call add(l:lines, s:Check('flake8 (python)', 'flake8')) + call add(l:lines, s:Check('pylint (python)', 'pylint')) + call add(l:lines, s:Check('eslint (js/ts)', 'eslint')) + call add(l:lines, s:Check('staticcheck (go)', 'staticcheck')) + call add(l:lines, s:Check('shellcheck (sh)', 'shellcheck')) + call add(l:lines, s:Check('yamllint (yaml)', 'yamllint')) + call add(l:lines, s:Check('hadolint (docker)', 'hadolint')) + if get(g:, 'chopsticks_markdown_lint', 0) + call add(l:lines, s:Check('markdownlint (md)', 'markdownlint')) + else + call add(l:lines, s:Off('markdownlint (md)', 'disabled by default')) + endif + else + call add(l:lines, s:Off('ALE linters', 'lint disabled by profile')) + endif + call add(l:lines, '') + + call add(l:lines, '── formatters ── (format-on-save is ' . (get(g:, 'ale_fix_on_save', 0) ? 'ON' : 'OFF') . ')') + if get(g:, 'chopsticks_enable_lint', 1) + call add(l:lines, s:Check('black (python)', 'black')) + call add(l:lines, s:Check('isort (python)', 'isort')) + call add(l:lines, s:Check('prettier (js/ts/json)', 'prettier')) + if get(g:, 'chopsticks_markdown_format_on_save', 0) + call add(l:lines, s:Check('prettier (md)', 'prettier')) + else + call add(l:lines, s:Off('prettier (md)', 'disabled by default')) + endif + call add(l:lines, s:Check('goimports (go)', 'goimports')) + call add(l:lines, s:Check('rustfmt (rust)', 'rustfmt')) + call add(l:lines, s:Check('clang-format (c)', 'clang-format')) + else + call add(l:lines, s:Off('ALE formatters', 'lint disabled by profile')) + endif + call add(l:lines, '') + + let l:ok = len(filter(copy(l:lines), 'v:val =~# " OK "')) + let l:miss = len(filter(copy(l:lines), 'v:val =~# " -- "')) + call add(l:lines, repeat('─', 50)) + call add(l:lines, ' ' . l:ok . ' ready, ' . l:miss . ' missing') + call add(l:lines, '') + call add(l:lines, ' Install missing tools with ./install.sh') + if get(g:, 'chopsticks_enable_lsp', 1) + call add(l:lines, ' Install LSP servers with :LspInstallServer') + endif + + let l:name = '__ChopsticksStatus__' + if bufwinnr(l:name) > 0 + execute bufwinnr(l:name) . 'wincmd w | bd' + endif + execute 'botright new ' . l:name + resize 45 + setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile + setlocal nowrap nonumber norelativenumber signcolumn=no + call setline(1, l:lines) + setlocal nomodifiable readonly + nnoremap q :bd +endfunction +command! ChopsticksStatus call s:ChopsticksStatus() + +" ── Cheat Sheet (,?) ──────────────────────────────────────────────────────── + +function! s:CheatSheet() abort + let l:name = '__ChopsticksCheatSheet__' + if bufwinnr(l:name) > 0 + execute bufwinnr(l:name) . 'wincmd w | bd' + return + endif + + let l:has_lsp = get(g:, 'chopsticks_enable_lsp', 1) + let l:has_lint = get(g:, 'chopsticks_enable_lint', 1) + let l:has_undotree = exists('g:plugs["undotree"]') + let l:has_previm = exists('g:plugs["previm"]') + + let l:lines = [ + \ ' chopsticks ,? close', + \ ' ─────────────────────────────', + \ '', + \ ' ── files ──────────────────', + \ ' ,ff files', + \ ' ,b buffers', + \ ' ,rg grep project', + \ ' ,rG grep word', + \ ' ,e sidebar (cwd)', + \ ' ,E sidebar (file dir)', + \ ' ,, last file', + \ ' ,fh recent files', + \ ' ,fl lines in buffer', + \ ' ,fc commands', + \ ' ,fm marks', + \ '', + \ ' ── code ──────────────────', + \ ] + + if l:has_lsp + call extend(l:lines, [ + \ ' ,dd definition', + \ ' ,dt type definition', + \ ' ,di implementation', + \ ' ,dr references', + \ ' ,dk hover docs', + \ ' ,rn rename', + \ ' ,ca code action', + \ ' ,f format', + \ ' ,o outline', + \ ' ,dp ,dn LSP diagnostics', + \ ' :LspInstallServer setup LSP', + \ ' :ChopsticksStatus check LSP setup', + \ ]) + endif + + call add(l:lines, ' ,cr run file') + if l:has_previm + call add(l:lines, ' ,mp markdown preview') + endif + call add(l:lines, ' ,mt table of contents') + + if l:has_lint + call extend(l:lines, [ + \ ' [e ]e ALE errors', + \ ' ,af format on save', + \ ]) + endif + + call extend(l:lines, [ + \ '', + \ ' ── edit ──────────────────', + \ ' gc comment', + \ ' ,S+2ch easymotion jump', + \ ' cs"'' surround', + \ ]) + + if l:has_undotree + call add(l:lines, ' ,u undo tree') + endif + + call extend(l:lines, [ + \ ' ,y ,p clipboard y/p (v)', + \ ' Alt+j/k move line (v)', + \ ' ,* replace word (v)', + \ ' ,F re-indent (v)', + \ ' ,W strip trailing (v)', + \ '', + \ ' ── git ───────────────────', + \ ' ,gs status', + \ ' ,gd diff', + \ ' ,gb blame', + \ ' ,gc commit', + \ ' ,gp push', + \ ' ,gl pull', + \ ' ,gL log graph', + \ ' ,gC FZF commits', + \ ' [x ]x conflict markers', + \ '', + \ ' ── windows ───────────────', + \ ' hjkl navigate splits', + \ ' ,h ,l prev / next buf', + \ ' ,bd close buffer', + \ ' ,z maximize toggle', + \ ' ,= ,- resize height', + \ ' ,tv ,th terminal v / h', + \ ' ]q [q next / prev qf', + \ ' ,qo ,qc open / close qf', + \ '', + \ ' ── toggle ────────────────', + \ ' F2 paste mode', + \ ' F3 line numbers', + \ ' F4 relative numbers', + \ ' F6 invisible chars', + \ ' ,ss spell check', + \ '', + \ ' ── survival ──────────────', + \ ' ,w save', + \ ' ,q quit', + \ ' ,x save + quit', + \ ' Esc exit insert', + \ ' ,ev edit vimrc', + \ ' ,sv reload vimrc', + \ ' :ChopsticksStatus health', + \ ]) + + execute 'vertical botright new ' . l:name + vertical resize 42 + setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile + setlocal nowrap nonumber norelativenumber signcolumn=no + setlocal winfixwidth + call setline(1, l:lines) + setlocal nomodifiable readonly + nnoremap q :bd + nnoremap ? :bd +endfunction +nnoremap ? :call CheatSheet() diff --git a/modules/tutor.vim b/modules/tutor.vim deleted file mode 100644 index 5d023b9..0000000 --- a/modules/tutor.vim +++ /dev/null @@ -1,102 +0,0 @@ -" tutor.vim — guided practice for chopsticks keymaps - -function! s:OpenTutor(lines) abort - let l:name = '__ChopsticksTutor__' - if bufwinnr(l:name) > 0 - execute bufwinnr(l:name) . 'wincmd w | bd' - return 0 - endif - - execute 'botright new ' . l:name - resize 38 - setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile - setlocal nowrap nonumber norelativenumber signcolumn=no - call setline(1, a:lines) - setlocal nomodifiable readonly - nnoremap q :bd - return 1 -endfunction - -function! s:ChopsticksTutor() abort - if g:chopsticks_space_keymaps - let l:lines = [ - \ ' chopsticks tutor q close', - \ ' ───────────────────────────────', - \ '', - \ ' 1. survival', - \ ' Esc Normal mode', - \ ' SPC ? active cheat sheet', - \ ' SPC w save', - \ ' SPC qx save and quit', - \ ' :ChopsticksStatus health check', - \ '', - \ ' 2. find and switch', - \ ' SPC SPC find files', - \ ' SPC / grep project', - \ ' SPC , buffers', - \ ' SPC Tab alternate buffer', - \ ' SPC e/E sidebar cwd / file dir', - \ '', - \ ' 3. jump and edit', - \ ' s + 2 chars visible jump', - \ ' SPC S same jump fallback', - \ ' cl / cc native s / S substitute', - \ ' gc comment', - \ ' SPC U undo tree', - \ '', - \ ' 4. code loop', - \ ' gd / gr / K definition / refs / docs', - \ ' gI / gy implementation / type', - \ ' [d ]d LSP diagnostics', - \ ' SPC ca/cr/cf action / rename / format', - \ ' SPC rr run current file', - \ '', - \ ' 5. git and windows', - \ ' SPC gs/gd/gb status / diff / blame', - \ ' SPC gl log graph', - \ ' hjkl split navigation', - \ ' SPC z maximize split', - \ '', - \ ' daily drill', - \ ' Open a project, run SPC SPC, jump with s, inspect with gd/K,', - \ ' edit with gc/SPC cf, check SPC gs, then save with SPC w.', - \ ] - else - let l:lines = [ - \ ' chopsticks tutor q close', - \ ' ───────────────────────────────', - \ '', - \ ' classic layout', - \ ' ,? active cheat sheet', - \ ' ,w / ,x save / save and quit', - \ ' ,ff find files', - \ ' ,rg grep project', - \ ' ,b buffers', - \ ' ,, alternate buffer', - \ '', - \ ' code loop', - \ ' ,dd / ,dr definition / refs', - \ ' ,dk hover docs', - \ ' ,ca / ,rn action / rename', - \ ' ,f format', - \ ' ,cr run current file', - \ '', - \ ' edit and git', - \ ' ,S + 2 chars EasyMotion jump', - \ ' gc comment', - \ ' ,u undo tree', - \ ' ,gs/,gd/,gb status / diff / blame', - \ ' hjkl split navigation', - \ '', - \ ' support', - \ ' :ChopsticksStatus health check', - \ ' README.md full reference', - \ ' QUICKSTART.md 5-minute path', - \ ] - endif - - if s:OpenTutor(l:lines) - nnoremap ? :ChopsticksCheatSheet - endif -endfunction -command! ChopsticksTutor call s:ChopsticksTutor() diff --git a/modules/utilities.vim b/modules/utilities.vim deleted file mode 100644 index 9988a42..0000000 --- a/modules/utilities.vim +++ /dev/null @@ -1,64 +0,0 @@ -" utilities.vim — small editing and config helpers - -if get(g:, 'chopsticks_enable_reindent_file', 0) - if g:chopsticks_space_keymaps - nnoremap c= gg=G`` - else - nnoremap F gg=G`` - endif -endif -if g:chopsticks_space_keymaps - vnoremap = = -else - vnoremap F = - nnoremap wa :wa -endif - -if !g:chopsticks_space_keymaps - nnoremap = :exe "resize " . (winheight(0) * 3/2) - nnoremap - :exe "resize " . (winheight(0) * 2/3) -endif - -if g:chopsticks_space_keymaps - nnoremap -else - nnoremap -endif - -if g:chopsticks_space_keymaps - nnoremap cW :%s/\s\+$//:let @/='' - vnoremap cW :s/\s\+$//:let @/=''gv -else - nnoremap W :%s/\s\+$//:let @/='' - vnoremap W :s/\s\+$//:let @/=''gv -endif - -if g:chopsticks_space_keymaps - nnoremap fv :edit $MYVIMRC - nnoremap fV :unlet! g:chopsticks_loaded:execute 'source ' . fnameescape($MYVIMRC):echo "vimrc reloaded" -else - nnoremap ev :edit $MYVIMRC - nnoremap sv :unlet! g:chopsticks_loaded:execute 'source ' . fnameescape($MYVIMRC):echo "vimrc reloaded" -endif - -if g:chopsticks_space_keymaps - nnoremap sr :%s/\<\>//g - vnoremap sr :s///g -else - nnoremap * :%s/\<\>//g - vnoremap * :s///g -endif - -if has('clipboard') - if g:chopsticks_space_keymaps - nnoremap fp :let @+ = expand("%:p"):echo "Copied: " . expand("%:p") - nnoremap fn :let @+ = expand("%:t"):echo "Copied: " . expand("%:t") - else - nnoremap cp :let @+ = expand("%:p"):echo "Copied: " . expand("%:p") - nnoremap cf :let @+ = expand("%:t"):echo "Copied: " . expand("%:t") - endif -endif - -if get(g:, 'chopsticks_enable_sudo_save_bang', 0) - cnoremap w!! w !sudo tee > /dev/null % -endif diff --git a/scripts/test-common.sh b/scripts/test-common.sh deleted file mode 100644 index 4de3988..0000000 --- a/scripts/test-common.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Shared setup for chopsticks test scripts. - -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/chopsticks-test-XXXXXX")" -EMPTY_XDG="$TMP_ROOT/xdg-empty" -STARTUP_LIMIT_MS="${STARTUP_LIMIT_MS:-150}" - -cleanup() { - rm -rf "$TMP_ROOT" -} -trap cleanup EXIT - -cd "$ROOT" -mkdir -p "$EMPTY_XDG" - -step() { - printf '\n==> %s\n' "$1" -} - -need() { - command -v "$1" >/dev/null 2>&1 || { - echo "Missing required command: $1" >&2 - exit 1 - } -} diff --git a/scripts/test-quick.sh b/scripts/test-quick.sh deleted file mode 100755 index 8942cbc..0000000 --- a/scripts/test-quick.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env bash -# Shell, docs, installer, and bootstrap checks. - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=scripts/test-common.sh -source "$SCRIPT_DIR/test-common.sh" - -check_shell() { - step "Shell syntax and lint" - need bash - bash -n install.sh - bash -n get.sh - bash -n scripts/test.sh - bash -n scripts/test-common.sh - bash -n scripts/test-quick.sh - bash -n scripts/test-vim.sh - test -x install.sh - test -x get.sh - test -x scripts/test.sh - - need shellcheck - shellcheck install.sh get.sh scripts/test.sh \ - scripts/test-common.sh scripts/test-quick.sh scripts/test-vim.sh -} - -check_docs() { - step "Markdown lint" - need markdownlint - markdownlint README.md QUICKSTART.md CONTRIBUTING.md CHANGELOG.md -} - -check_installer_modes() { - step "Installer profile-only modes" - XDG_CONFIG_HOME="$TMP_ROOT/dry" ./install.sh --dry-run --profile=full \ - | tee "$TMP_ROOT/install-dry-run.txt" - grep -q 'Profile: full' "$TMP_ROOT/install-dry-run.txt" - test ! -e "$TMP_ROOT/dry/chopsticks.vim" - - XDG_CONFIG_HOME="$TMP_ROOT/config" ./install.sh --configure-only --profile=minimal - grep -q "let g:chopsticks_profile = 'minimal'" "$TMP_ROOT/config/chopsticks.vim" - - XDG_CONFIG_HOME="$TMP_ROOT/config" ./install.sh --configure-only --profile=full - grep -q "let g:chopsticks_profile = 'full'" "$TMP_ROOT/config/chopsticks.vim" - - XDG_CONFIG_HOME="$TMP_ROOT/default" ./install.sh --configure-only --yes - grep -q "let g:chopsticks_profile = 'engineer'" "$TMP_ROOT/default/chopsticks.vim" -} - -check_bootstrap() { - step "Bootstrap dry-run safety" - CHOPSTICKS_DEST="$TMP_ROOT/bootstrap" ./get.sh --dry-run --profile=minimal \ - | tee "$TMP_ROOT/get-dry-run.txt" - grep -q 'Would clone' "$TMP_ROOT/get-dry-run.txt" - test ! -e "$TMP_ROOT/bootstrap" - - mkdir -p "$TMP_ROOT/no-git-bin" - printf '%s\n' \ - '#!/usr/bin/env bash' \ - "echo \"brew was called\" >> \"\$BREW_LOG\"" \ - 'exit 42' > "$TMP_ROOT/no-git-bin/brew" - chmod +x "$TMP_ROOT/no-git-bin/brew" - BREW_LOG="$TMP_ROOT/no-git-brew.log" \ - PATH="$TMP_ROOT/no-git-bin" \ - CHOPSTICKS_DEST="$TMP_ROOT/no-git-bootstrap" \ - /bin/bash ./get.sh --dry-run --profile=full \ - | tee "$TMP_ROOT/get-no-git-dry-run.txt" - grep -q 'Would require: git' "$TMP_ROOT/get-no-git-dry-run.txt" - grep -q 'Would clone' "$TMP_ROOT/get-no-git-dry-run.txt" - test ! -e "$TMP_ROOT/no-git-brew.log" - test ! -e "$TMP_ROOT/no-git-bootstrap" - - mkdir -p "$TMP_ROOT/not-chopsticks" - git -c init.defaultBranch=main init "$TMP_ROOT/not-chopsticks" >/dev/null - git -C "$TMP_ROOT/not-chopsticks" remote add origin https://github.com/example/not-chopsticks.git - if CHOPSTICKS_DEST="$TMP_ROOT/not-chopsticks" ./get.sh --dry-run; then - echo "Expected get.sh to reject non-chopsticks repo" >&2 - exit 1 - fi - - mkdir -p "$TMP_ROOT/chopsticks-existing" - git -c init.defaultBranch=main init "$TMP_ROOT/chopsticks-existing" >/dev/null - git -C "$TMP_ROOT/chopsticks-existing" remote add origin https://github.com/m1ngsama/chopsticks.git - touch "$TMP_ROOT/chopsticks-existing/install.sh" "$TMP_ROOT/chopsticks-existing/.vimrc" - CHOPSTICKS_DEST="$TMP_ROOT/chopsticks-existing" ./get.sh --dry-run --yes \ - | tee "$TMP_ROOT/get-existing.txt" - grep -q 'Would update existing chopsticks repo' "$TMP_ROOT/get-existing.txt" -} - -run_quick_group() { - case "$1" in - quick) - check_shell - check_docs - check_installer_modes - check_bootstrap - ;; - shell) check_shell ;; - docs) check_docs ;; - installer) check_installer_modes ;; - bootstrap) check_bootstrap ;; - *) - echo "Unknown quick test group: $1" >&2 - exit 1 ;; - esac -} - -if [[ $# -eq 0 ]]; then - set -- quick -fi - -for group in "$@"; do - run_quick_group "$group" -done diff --git a/scripts/test-vim.sh b/scripts/test-vim.sh deleted file mode 100755 index 9620fb2..0000000 --- a/scripts/test-vim.sh +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env bash -# Vim smoke tests. Requires plugins in ~/.vim/plugged. - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=scripts/test-common.sh -source "$SCRIPT_DIR/test-common.sh" - -check_plugin_dirs() { - step "Plugin directories" - for plugin in \ - fzf fzf.vim vim-fugitive vim-gitgutter ale vim-lsp vim-lsp-settings \ - asyncomplete.vim asyncomplete-lsp.vim vim-markdown - do - test -d "$HOME/.vim/plugged/$plugin" || { - echo "Missing plugin directory: $plugin" >&2 - exit 1 - } - done -} - -check_vim() { - step "Vim smoke tests" - need vim - check_plugin_dirs - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N -c 'qa!' 2>&1 - if [ -x /usr/bin/vim ] && [ "$(command -v vim)" != "/usr/bin/vim" ]; then - XDG_CONFIG_HOME="$EMPTY_XDG" /usr/bin/vim -u .vimrc -i NONE -es -N -c 'qa!' 2>&1 - fi - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c "redir! > $TMP_ROOT/plugs.txt" \ - -c 'silent echo len(g:plugs)' \ - -c 'redir END' \ - -c 'qa!' 2>/dev/null - PLUGS="$(tr -d '[:space:]' < "$TMP_ROOT/plugs.txt")" - echo "Plugins registered: $PLUGS" - if [ "$PLUGS" -lt 20 ]; then - echo "Expected 20+ plugins, got $PLUGS" >&2 - exit 1 - fi - - mkdir -p "$TMP_ROOT/chopsticks path/modules" - cp .vimrc "$TMP_ROOT/chopsticks path/.vimrc" - cp modules/*.vim "$TMP_ROOT/chopsticks path/modules/" - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u "$TMP_ROOT/chopsticks path/.vimrc" \ - -i NONE -es -N -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_profile = "minimal"' \ - -c 'source .vimrc' \ - -c 'if has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "vim-lsp-settings") || has_key(g:plugs, "asyncomplete.vim") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ - -c 'qa!' 2>&1 - - mkdir -p "$TMP_ROOT/local" - printf "%s\n" "let g:chopsticks_profile = 'minimal'" > "$TMP_ROOT/local/config.vim" - vim -u NONE -i NONE -es -N \ - -c "let g:chopsticks_local_config = '$TMP_ROOT/local/config.vim'" \ - -c 'source .vimrc' \ - -c 'if g:chopsticks_profile !=# "minimal" || has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ - -c 'qa!' 2>&1 - - mkdir -p "$TMP_ROOT/xdg" - printf "%s\n" "let g:chopsticks_profile = 'minimal'" > "$TMP_ROOT/xdg/chopsticks.vim" - XDG_CONFIG_HOME="$TMP_ROOT/xdg" vim -u NONE -i NONE -es -N \ - -c 'source .vimrc' \ - -c 'if g:chopsticks_profile !=# "minimal" || has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'ChopsticksStatus' \ - -c "redir! > $TMP_ROOT/status-default.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - if grep -Fq 'vim-lsp not loaded' "$TMP_ROOT/status-default.txt"; then - cat "$TMP_ROOT/status-default.txt" - exit 1 - fi - grep -Fq 'OK vim-lsp stack (installed)' "$TMP_ROOT/status-default.txt" - grep -Fq 'python (:LspInstallServer in a python file)' "$TMP_ROOT/status-default.txt" - grep -Fq 'LSP actions are buffer-local and start after a server attaches.' "$TMP_ROOT/status-default.txt" - grep -Fq 'Open that filetype and run :LspInstallServer once.' "$TMP_ROOT/status-default.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'let last_change_map = nr2char(96) . "[v" . nr2char(96) . "]"' \ - -c 'if maparg("0", "n") !=# "" || maparg("0", "v") !=# "" || maparg("Y", "n") !=# "" || maparg("Q", "n") !=# "" || maparg("", "n") !=# "" || maparg("//", "v") !=# "" || maparg("gV", "n") !=# "" || maparg("jk", "i") !=# "" || maparg("", "n") !=# "" || maparg("", "i") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "c") !=# "" || maparg("", "c") !=# "" || maparg("w!!", "c") !=# "" | cquit | endif' \ - -c 'if has_key(g:plugs, "auto-pairs") || maparg("", "i") =~# "pumvisible" || maparg("", "i") =~# "pumvisible" || maparg("", "i") =~# "asyncomplete#close_popup" || maparg("", "i") =~# "AutoPairs" | cquit | endif' \ - -c 'if maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" | cquit | endif' \ - -c 'if maparg("s", "n") !~# "easymotion-overwin-f2" | cquit | endif' \ - -c 'if maparg("/", "v") !~# "escape" || maparg("v", "n") !=# last_change_map || maparg("", "n") !~# "SmartFiles" | cquit | endif' \ - -c 'if maparg(",/", "v") !=# "" || maparg(",v", "n") !=# "" || maparg(",ff", "n") !=# "" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "classic"' \ - -c 'source .vimrc' \ - -c 'let last_change_map = nr2char(96) . "[v" . nr2char(96) . "]"' \ - -c 'if mapleader !=# "," || maparg("s", "n") !=# "" || maparg(",/", "v") !~# "escape" || maparg(",v", "n") !=# last_change_map || maparg(",ff", "n") !~# "SmartFiles" | cquit | endif' \ - -c 'if maparg(",gp", "n") !=# "" || maparg(",gl", "n") !=# "" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_jk_escape = 1' \ - -c 'source .vimrc' \ - -c 'if maparg("jk", "i") !~# "" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_ctrl_s_save = 1' \ - -c 'let g:chopsticks_enable_sudo_save_bang = 1' \ - -c 'let g:chopsticks_enable_completion_keymaps = 1' \ - -c 'source .vimrc' \ - -c 'if maparg("", "n") !~# ":w" || maparg("", "i") !~# ":w" || maparg("w!!", "c") !~# "sudo tee" | cquit | endif' \ - -c 'if maparg("", "i") !~# "pumvisible" || maparg("", "i") !~# "pumvisible" || maparg("", "i") !~# "asyncomplete#close_popup" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_auto_pairs = 1' \ - -c 'source .vimrc' \ - -c 'if !has_key(g:plugs, "auto-pairs") | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_terminal_keymaps = 1' \ - -c 'source .vimrc' \ - -c 'if has("terminal") && (maparg("", "t") !~# "" || maparg("", "t") !~# "h" || maparg("", "t") !~# "j" || maparg("", "t") !~# "k" || maparg("", "t") !~# "l") | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if &exrc || &secure | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_exrc = 1' \ - -c 'source .vimrc' \ - -c 'if !&exrc || !&secure | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if maparg("c=", "n") !=# "" | cquit | endif' \ - -c 'if maparg("=", "v") !~# "=" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_enable_reindent_file = 1' \ - -c 'source .vimrc' \ - -c 'if maparg("c=", "n") !~# "gg=G" | cquit | endif' \ - -c 'qa!' 2>&1 - - TERM=xterm-256color XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if g:is_tty || &ttimeoutlen != 10 | cquit | endif' \ - -c 'qa!' 2>&1 - - TERM=linux XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if !g:is_tty || &ttimeoutlen != 50 | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if !exists("loaded_gzip") || !exists("loaded_logiPat") || !exists("loaded_rrhelper") || !exists("loaded_spellfile_plugin") | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'silent! delcommand LspStatus' \ - -c 'silent! delcommand LspInstallServer' \ - -c 'ChopsticksStatus' \ - -c "redir! > $TMP_ROOT/status-lsp-not-loaded.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'OK vim-lsp stack (installed; not loaded yet)' "$TMP_ROOT/status-lsp-not-loaded.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_profile = "minimal"' \ - -c 'source .vimrc' \ - -c 'ChopsticksStatus' \ - -c "redir! > $TMP_ROOT/status-minimal.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'off vim-lsp stack (LSP disabled by profile)' "$TMP_ROOT/status-minimal.txt" - grep -Fq 'off python (LSP disabled by profile)' "$TMP_ROOT/status-minimal.txt" - if grep -Fq 'LSP actions are buffer-local' "$TMP_ROOT/status-minimal.txt"; then - cat "$TMP_ROOT/status-minimal.txt" - exit 1 - fi - - mkdir -p "$TMP_ROOT/missing-home/.vim/autoload" - cp "$HOME/.vim/autoload/plug.vim" "$TMP_ROOT/missing-home/.vim/autoload/plug.vim" - HOME="$TMP_ROOT/missing-home" XDG_CONFIG_HOME="$EMPTY_XDG" \ - vim -u .vimrc -i NONE -es -N \ - -c 'ChopsticksStatus' \ - -c "redir! > $TMP_ROOT/status-missing-plugin.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'vim-lsp not installed; run :PlugInstall' "$TMP_ROOT/status-missing-plugin.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'doautocmd User lsp_buffer_enabled' \ - -c 'if maparg("gd", "n") !~# "lsp-definition" || maparg("gr", "n") !~# "lsp-references" || maparg("gI", "n") !~# "lsp-implementation" || maparg("gy", "n") !~# "lsp-type-definition" || maparg("K", "n") !~# "lsp-hover" | cquit | endif' \ - -c 'if maparg("[d", "n") !~# "lsp-previous-diagnostic" || maparg("]d", "n") !~# "lsp-next-diagnostic" | cquit | endif' \ - -c 'if maparg("ca", "n") !~# "lsp-code-action" || maparg("cr", "n") !~# "lsp-rename" || maparg("cf", "n") !~# "lsp-document-format" | cquit | endif' \ - -c 'if maparg("ci", "n") !~# "LspStatus" || maparg("co", "n") !~# "lsp-document-symbol-search" | cquit | endif' \ - -c 'if maparg("cd", "n") !=# "" || maparg("ck", "n") !=# "" || maparg("cp", "n") !=# "" || maparg("cn", "n") !=# "" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "classic"' \ - -c 'source .vimrc' \ - -c 'doautocmd User lsp_buffer_enabled' \ - -c 'if maparg("gd", "n") !=# "" || maparg("K", "n") !=# "" || maparg("gI", "n") !=# "" || maparg("gr", "n") !=# "" | cquit | endif' \ - -c 'if maparg(",dd", "n") !~# "lsp-definition" || maparg(",dt", "n") !~# "lsp-type-definition" || maparg(",di", "n") !~# "lsp-implementation" || maparg(",dr", "n") !~# "lsp-references" || maparg(",dk", "n") !~# "lsp-hover" | cquit | endif' \ - -c 'if maparg(",dp", "n") !~# "lsp-previous-diagnostic" | cquit | endif' \ - -c 'if maparg(",dn", "n") !~# "lsp-next-diagnostic" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "space"' \ - -c 'source .vimrc' \ - -c 'if mapleader !=# "\" || maplocalleader !=# "," | cquit | endif' \ - -c 'if maparg(",ff", "n") !=# "" || maparg(",w", "n") !=# "" || maparg(",mt", "n") !=# "" || maparg(",gp", "n") !=# "" || maparg("gp", "n") !=# "" | cquit | endif' \ - -c 'if maparg("f", "n") !=# "" || maparg("q", "n") !=# "" || maparg("u", "n") !=# "" || maparg("c", "n") !=# "" || maparg("x", "n") !=# "" || maparg("wm", "n") !=# "" || maparg("w+", "n") !=# "" || maparg("w-", "n") !=# "" | cquit | endif' \ - -c 'if maparg("", "n") !~# "SmartFiles" || maparg("ff", "n") !~# "SmartFiles" || maparg(",", "n") !~# "Buffers" || maparg("bd", "n") !~# "Bclose" | cquit | endif' \ - -c 'if maparg("w", "n") !~# ":w" || maparg("W", "n") !~# ":wa" || maparg("qq", "n") !~# ":q" || maparg("qx", "n") !~# ":x" || maparg("U", "n") !~# "UndotreeToggle" || maparg("fs", "n") !=# "" || maparg("bu", "n") !=# "" | cquit | endif' \ - -c 'if maparg("gl", "n") !~# "Git log" || maparg("gC", "n") !~# "Commits" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "space"' \ - -c 'source .vimrc' \ - -c 'doautocmd User lsp_buffer_enabled' \ - -c 'if maparg("cf", "n") !~# "lsp-document-format" | cquit | endif' \ - -c 'if maparg("gd", "n") !~# "lsp-definition" || maparg("gr", "n") !~# "lsp-references" || maparg("K", "n") !~# "lsp-hover" | cquit | endif' \ - -c 'if maparg("cd", "n") !=# "" || maparg("ck", "n") !=# "" | cquit | endif' \ - -c 'if maparg("f", "n") !=# "" || maparg("c", "n") !=# "" | cquit | endif' \ - -c 'if maparg(",f", "n") !=# "" || maparg(",dd", "n") !=# "" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'call feedkeys("\?", "xt")' \ - -c "redir! > $TMP_ROOT/cheat-default.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq ':ChopsticksStatus check LSP setup' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'SPC SPC files' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'gd definition' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'K hover docs' "$TMP_ROOT/cheat-default.txt" - grep -Fq '[d ]d LSP diagnostics' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'hjkl navigate splits' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'SPC w save' "$TMP_ROOT/cheat-default.txt" - grep -Fq 's+2ch easymotion jump' "$TMP_ROOT/cheat-default.txt" - grep -Fq 'cl / cc native s / S substitute' "$TMP_ROOT/cheat-default.txt" - grep -Fq ':ChopsticksTutor practice' "$TMP_ROOT/cheat-default.txt" - if grep -Eq 'Ctrl\\+p find file|Ctrl\\+hjkl navigate splits|Ctrl\\+s save|jk exit insert|SPC fs save|SPC cd definition|SPC ck hover|SPC wm|SPC w\\+/-|\\[g \\]g LSP diagnostics' "$TMP_ROOT/cheat-default.txt"; then - cat "$TMP_ROOT/cheat-default.txt" - exit 1 - fi - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'ChopsticksCheatSheet' \ - -c "redir! > $TMP_ROOT/cheat-command.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'SPC SPC files' "$TMP_ROOT/cheat-command.txt" - grep -Fq ':ChopsticksTutor practice' "$TMP_ROOT/cheat-command.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "classic"' \ - -c 'source .vimrc' \ - -c 'normal ,?' \ - -c "redir! > $TMP_ROOT/cheat-classic.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq ',ff files' "$TMP_ROOT/cheat-classic.txt" - grep -Fq ',dd definition' "$TMP_ROOT/cheat-classic.txt" - grep -Fq ',dk hover docs' "$TMP_ROOT/cheat-classic.txt" - grep -Fq ',dp ,dn LSP diagnostics' "$TMP_ROOT/cheat-classic.txt" - if grep -Eq ',gp push|,gl pull' "$TMP_ROOT/cheat-classic.txt"; then - cat "$TMP_ROOT/cheat-classic.txt" - exit 1 - fi - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_profile = "minimal"' \ - -c 'source .vimrc' \ - -c 'call feedkeys("\?", "xt")' \ - -c "redir! > $TMP_ROOT/cheat.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - if grep -Eq 'definition|LspInstallServer|ALE errors|undo tree|markdown preview' "$TMP_ROOT/cheat.txt"; then - cat "$TMP_ROOT/cheat.txt" - exit 1 - fi - grep -q 'SPC rr run file' "$TMP_ROOT/cheat.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "space"' \ - -c 'source .vimrc' \ - -c 'call feedkeys("\?", "xt")' \ - -c "redir! > $TMP_ROOT/cheat-space.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'SPC w save' "$TMP_ROOT/cheat-space.txt" - grep -Fq 'gd definition' "$TMP_ROOT/cheat-space.txt" - grep -Fq 'SPC gl log graph' "$TMP_ROOT/cheat-space.txt" - grep -Fq 's+2ch easymotion jump' "$TMP_ROOT/cheat-space.txt" - if grep -Eq ',w save|,gp push|SPC gp push|SPC gl pull|SPC fs save|SPC cd definition|SPC f format' "$TMP_ROOT/cheat-space.txt"; then - cat "$TMP_ROOT/cheat-space.txt" - exit 1 - fi - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'ChopsticksTutor' \ - -c "redir! > $TMP_ROOT/tutor-default.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'chopsticks tutor' "$TMP_ROOT/tutor-default.txt" - grep -Fq 'SPC ? active cheat sheet' "$TMP_ROOT/tutor-default.txt" - grep -Fq 's + 2 chars visible jump' "$TMP_ROOT/tutor-default.txt" - grep -Fq 'cl / cc native s / S substitute' "$TMP_ROOT/tutor-default.txt" - grep -Fq 'gd / gr / K definition / refs / docs' "$TMP_ROOT/tutor-default.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:chopsticks_keymap_style = "classic"' \ - -c 'source .vimrc' \ - -c 'ChopsticksTutor' \ - -c "redir! > $TMP_ROOT/tutor-classic.txt" \ - -c 'silent %print' \ - -c 'redir END' \ - -c 'qa!' 2>&1 - grep -Fq 'classic layout' "$TMP_ROOT/tutor-classic.txt" - grep -Fq ',? active cheat sheet' "$TMP_ROOT/tutor-classic.txt" - grep -Fq ',S + 2 chars EasyMotion jump' "$TMP_ROOT/tutor-classic.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N README.md \ - -c 'let g:chopsticks_keymap_style = "space"' \ - -c 'source .vimrc' \ - -c 'set filetype=markdown' \ - -c 'if maparg(",mt", "n") !~# "Toc" || maparg(",mp", "n") !~# "PrevimOpen" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N README.md \ - -c 'set filetype=markdown' \ - -c 'if &l:spell || &l:conceallevel != 0 || &l:signcolumn !=# "no" || exists("g:lsp_settings_filetype_markdown") | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ - -c 'if maparg("s", "n") !~# "easymotion-overwin-f2" | cquit | endif' \ - -c 'if maparg("w", "n") =~# "!" | cquit | endif' \ - -c 'if !&swapfile || !&writebackup || &directory !~# "\.vim/.swap" | cquit | endif' \ - -c 'qa!' 2>&1 - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ - -c 'let g:ale_fix_on_save = 0' \ - -c 'source .vimrc' \ - -c 'if g:ale_fix_on_save != 0 | cquit | endif' \ - -c 'qa!' 2>&1 - - truncate -s 11000000 "$TMP_ROOT/large.py" - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N "$TMP_ROOT/large.py" \ - -c 'set filetype=python' \ - -c 'if &l:syntax !=# "" || &l:undolevels != -1 || &l:swapfile || get(b:, "ale_enabled", 1) != 0 | cquit | endif' \ - -c 'qa!' 2>&1 - - mkdir -p "$TMP_ROOT/fake-bin" "$TMP_ROOT/c runner" - cat > "$TMP_ROOT/fake-bin/gcc" <<'GCCEOF' -#!/usr/bin/env bash -set -eu -printf '%s\n' "$@" > "$GCC_ARGS" -out="" -while [ "$#" -gt 0 ]; do - if [ "$1" = "-o" ]; then - shift - out="$1" - fi - shift || true -done -test -n "$out" -printf '%s\n' '#!/usr/bin/env bash' 'exit 0' > "$out" -chmod +x "$out" -GCCEOF - chmod +x "$TMP_ROOT/fake-bin/gcc" - c_file="$TMP_ROOT/c runner/main.c" - c_file_real="$(cd "$TMP_ROOT/c runner" && pwd -P)/main.c" - printf '%s\n' 'int main(void) { return 0; }' > "$c_file" - GCC_ARGS="$TMP_ROOT/gcc-args.txt" \ - PATH="$TMP_ROOT/fake-bin:$PATH" \ - XDG_CONFIG_HOME="$EMPTY_XDG" \ - vim -u .vimrc -i NONE -es -N "$c_file" \ - -c 'set filetype=c' \ - -c 'call feedkeys("\rr", "xt")' \ - -c 'qa!' 2>&1 - c_out="$(sed -n '2p' "$TMP_ROOT/gcc-args.txt")" - test -n "$c_out" - test "$c_out" != "/tmp/a.out" - test ! -e "$c_out" - grep -Fxq "$c_file_real" "$TMP_ROOT/gcc-args.txt" - - XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE --startuptime "$TMP_ROOT/startup.log" \ - -es -N -c 'qa!' 2>/dev/null - tail -1 "$TMP_ROOT/startup.log" - STARTUP_MS="$(awk 'END { print $1 }' "$TMP_ROOT/startup.log")" - awk -v ms="$STARTUP_MS" -v limit="$STARTUP_LIMIT_MS" \ - 'BEGIN { if (ms > limit) exit 1 }' -} - -check_vim diff --git a/scripts/test.sh b/scripts/test.sh index 6bec396..41d9a7c 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,9 +1,31 @@ #!/usr/bin/env bash -# Project test runner. CI calls the same groups maintainers can run locally. +# Project test runner. CI calls the same groups that maintainers can run locally. set -euo pipefail -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/chopsticks-test-XXXXXX")" +EMPTY_XDG="$TMP_ROOT/xdg-empty" +STARTUP_LIMIT_MS="${STARTUP_LIMIT_MS:-150}" + +cleanup() { + rm -rf "$TMP_ROOT" +} +trap cleanup EXIT + +cd "$ROOT" +mkdir -p "$EMPTY_XDG" + +step() { + printf '\n==> %s\n' "$1" +} + +need() { + command -v "$1" >/dev/null 2>&1 || { + echo "Missing required command: $1" >&2 + exit 1 + } +} usage() { cat <<'EOF' @@ -28,17 +50,385 @@ list_groups() { printf '%s\n' quick shell docs installer bootstrap vim all } +check_shell() { + step "Shell syntax and lint" + need bash + bash -n install.sh + bash -n get.sh + bash -n scripts/test.sh + test -x install.sh + test -x get.sh + test -x scripts/test.sh + + need shellcheck + shellcheck install.sh get.sh scripts/test.sh +} + +check_docs() { + step "Markdown lint" + need markdownlint + markdownlint README.md QUICKSTART.md CONTRIBUTING.md CHANGELOG.md +} + +check_installer_modes() { + step "Installer profile-only modes" + XDG_CONFIG_HOME="$TMP_ROOT/dry" ./install.sh --dry-run --profile=full \ + | tee "$TMP_ROOT/install-dry-run.txt" + grep -q 'Profile: full' "$TMP_ROOT/install-dry-run.txt" + test ! -e "$TMP_ROOT/dry/chopsticks.vim" + + XDG_CONFIG_HOME="$TMP_ROOT/config" ./install.sh --configure-only --profile=minimal + grep -q "let g:chopsticks_profile = 'minimal'" "$TMP_ROOT/config/chopsticks.vim" + + XDG_CONFIG_HOME="$TMP_ROOT/config" ./install.sh --configure-only --profile=full + grep -q "let g:chopsticks_profile = 'full'" "$TMP_ROOT/config/chopsticks.vim" + + XDG_CONFIG_HOME="$TMP_ROOT/default" ./install.sh --configure-only --yes + grep -q "let g:chopsticks_profile = 'engineer'" "$TMP_ROOT/default/chopsticks.vim" +} + +check_bootstrap() { + step "Bootstrap dry-run safety" + CHOPSTICKS_DEST="$TMP_ROOT/bootstrap" ./get.sh --dry-run --profile=minimal \ + | tee "$TMP_ROOT/get-dry-run.txt" + grep -q 'Would clone' "$TMP_ROOT/get-dry-run.txt" + test ! -e "$TMP_ROOT/bootstrap" + + mkdir -p "$TMP_ROOT/no-git-bin" + printf '%s\n' \ + '#!/usr/bin/env bash' \ + "echo \"brew was called\" >> \"\$BREW_LOG\"" \ + 'exit 42' > "$TMP_ROOT/no-git-bin/brew" + chmod +x "$TMP_ROOT/no-git-bin/brew" + BREW_LOG="$TMP_ROOT/no-git-brew.log" \ + PATH="$TMP_ROOT/no-git-bin" \ + CHOPSTICKS_DEST="$TMP_ROOT/no-git-bootstrap" \ + /bin/bash ./get.sh --dry-run --profile=full \ + | tee "$TMP_ROOT/get-no-git-dry-run.txt" + grep -q 'Would require: git' "$TMP_ROOT/get-no-git-dry-run.txt" + grep -q 'Would clone' "$TMP_ROOT/get-no-git-dry-run.txt" + test ! -e "$TMP_ROOT/no-git-brew.log" + test ! -e "$TMP_ROOT/no-git-bootstrap" + + mkdir -p "$TMP_ROOT/not-chopsticks" + git -c init.defaultBranch=main init "$TMP_ROOT/not-chopsticks" >/dev/null + git -C "$TMP_ROOT/not-chopsticks" remote add origin https://github.com/example/not-chopsticks.git + if CHOPSTICKS_DEST="$TMP_ROOT/not-chopsticks" ./get.sh --dry-run; then + echo "Expected get.sh to reject non-chopsticks repo" >&2 + exit 1 + fi + + mkdir -p "$TMP_ROOT/chopsticks-existing" + git -c init.defaultBranch=main init "$TMP_ROOT/chopsticks-existing" >/dev/null + git -C "$TMP_ROOT/chopsticks-existing" remote add origin https://github.com/m1ngsama/chopsticks.git + touch "$TMP_ROOT/chopsticks-existing/install.sh" "$TMP_ROOT/chopsticks-existing/.vimrc" + CHOPSTICKS_DEST="$TMP_ROOT/chopsticks-existing" ./get.sh --dry-run --yes \ + | tee "$TMP_ROOT/get-existing.txt" + grep -q 'Would update existing chopsticks repo' "$TMP_ROOT/get-existing.txt" +} + +check_plugin_dirs() { + step "Plugin directories" + for plugin in \ + fzf fzf.vim vim-fugitive vim-gitgutter ale vim-lsp vim-lsp-settings \ + asyncomplete.vim asyncomplete-lsp.vim vim-markdown + do + test -d "$HOME/.vim/plugged/$plugin" || { + echo "Missing plugin directory: $plugin" >&2 + exit 1 + } + done +} + +check_vim() { + step "Vim smoke tests" + need vim + check_plugin_dirs + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c "redir! > $TMP_ROOT/plugs.txt" \ + -c 'silent echo len(g:plugs)' \ + -c 'redir END' \ + -c 'qa!' 2>/dev/null + PLUGS="$(tr -d '[:space:]' < "$TMP_ROOT/plugs.txt")" + echo "Plugins registered: $PLUGS" + if [ "$PLUGS" -lt 20 ]; then + echo "Expected 20+ plugins, got $PLUGS" >&2 + exit 1 + fi + + mkdir -p "$TMP_ROOT/chopsticks path/modules" + cp .vimrc "$TMP_ROOT/chopsticks path/.vimrc" + cp modules/*.vim "$TMP_ROOT/chopsticks path/modules/" + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u "$TMP_ROOT/chopsticks path/.vimrc" \ + -i NONE -es -N -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_profile = "minimal"' \ + -c 'source .vimrc' \ + -c 'if has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "vim-lsp-settings") || has_key(g:plugs, "asyncomplete.vim") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ + -c 'qa!' 2>&1 + + mkdir -p "$TMP_ROOT/local" + printf "%s\n" "let g:chopsticks_profile = 'minimal'" > "$TMP_ROOT/local/config.vim" + vim -u NONE -i NONE -es -N \ + -c "let g:chopsticks_local_config = '$TMP_ROOT/local/config.vim'" \ + -c 'source .vimrc' \ + -c 'if g:chopsticks_profile !=# "minimal" || has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ + -c 'qa!' 2>&1 + + mkdir -p "$TMP_ROOT/xdg" + printf "%s\n" "let g:chopsticks_profile = 'minimal'" > "$TMP_ROOT/xdg/chopsticks.vim" + XDG_CONFIG_HOME="$TMP_ROOT/xdg" vim -u NONE -i NONE -es -N \ + -c 'source .vimrc' \ + -c 'if g:chopsticks_profile !=# "minimal" || has_key(g:plugs, "ale") || has_key(g:plugs, "vim-lsp") || has_key(g:plugs, "auto-pairs") | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'ChopsticksStatus' \ + -c "redir! > $TMP_ROOT/status-default.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + if grep -Fq 'vim-lsp not loaded' "$TMP_ROOT/status-default.txt"; then + cat "$TMP_ROOT/status-default.txt" + exit 1 + fi + grep -Fq 'OK vim-lsp stack (installed)' "$TMP_ROOT/status-default.txt" + grep -Fq 'python (:LspInstallServer in a python file)' "$TMP_ROOT/status-default.txt" + grep -Fq 'LSP actions are buffer-local and start after a server attaches.' "$TMP_ROOT/status-default.txt" + grep -Fq 'Open that filetype and run :LspInstallServer once.' "$TMP_ROOT/status-default.txt" + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'let last_change_map = nr2char(96) . "[v" . nr2char(96) . "]"' \ + -c 'if maparg("0", "n") !=# "" || maparg("0", "v") !=# "" || maparg("Y", "n") !=# "" || maparg("Q", "n") !=# "" || maparg("", "n") !=# "" || maparg("//", "v") !=# "" || maparg("gV", "n") !=# "" || maparg("jk", "i") !=# "" || maparg("", "n") !=# "" || maparg("", "i") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "n") !=# "" || maparg("", "c") !=# "" || maparg("", "c") !=# "" || maparg("w!!", "c") !=# "" | cquit | endif' \ + -c 'if has_key(g:plugs, "auto-pairs") || maparg("", "i") =~# "pumvisible" || maparg("", "i") =~# "pumvisible" || maparg("", "i") =~# "asyncomplete#close_popup" || maparg("", "i") =~# "AutoPairs" | cquit | endif' \ + -c 'if maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" || maparg("", "t") !=# "" | cquit | endif' \ + -c 'if maparg(",/", "v") !~# "escape" || maparg(",v", "n") !=# last_change_map || maparg(",ff", "n") !~# "SmartFiles" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_jk_escape = 1' \ + -c 'source .vimrc' \ + -c 'if maparg("jk", "i") !~# "" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_ctrl_s_save = 1' \ + -c 'let g:chopsticks_enable_sudo_save_bang = 1' \ + -c 'let g:chopsticks_enable_completion_keymaps = 1' \ + -c 'source .vimrc' \ + -c 'if maparg("", "n") !~# ":w" || maparg("", "i") !~# ":w" || maparg("w!!", "c") !~# "sudo tee" | cquit | endif' \ + -c 'if maparg("", "i") !~# "pumvisible" || maparg("", "i") !~# "pumvisible" || maparg("", "i") !~# "asyncomplete#close_popup" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_auto_pairs = 1' \ + -c 'source .vimrc' \ + -c 'if !has_key(g:plugs, "auto-pairs") | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_terminal_keymaps = 1' \ + -c 'source .vimrc' \ + -c 'if has("terminal") && (maparg("", "t") !~# "" || maparg("", "t") !~# "h" || maparg("", "t") !~# "j" || maparg("", "t") !~# "k" || maparg("", "t") !~# "l") | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if &exrc || &secure | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_exrc = 1' \ + -c 'source .vimrc' \ + -c 'if !&exrc || !&secure | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if maparg(",F", "n") !=# "" | cquit | endif' \ + -c 'if maparg(",F", "v") !~# "=" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_enable_reindent_file = 1' \ + -c 'source .vimrc' \ + -c 'if maparg(",F", "n") !~# "gg=G" | cquit | endif' \ + -c 'qa!' 2>&1 + + TERM=xterm-256color XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if g:is_tty || &ttimeoutlen != 10 | cquit | endif' \ + -c 'qa!' 2>&1 + + TERM=linux XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if !g:is_tty || &ttimeoutlen != 50 | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if !exists("loaded_gzip") || !exists("loaded_logiPat") || !exists("loaded_rrhelper") || !exists("loaded_spellfile_plugin") | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'silent! delcommand LspStatus' \ + -c 'silent! delcommand LspInstallServer' \ + -c 'ChopsticksStatus' \ + -c "redir! > $TMP_ROOT/status-lsp-not-loaded.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + grep -Fq 'OK vim-lsp stack (installed; not loaded yet)' "$TMP_ROOT/status-lsp-not-loaded.txt" + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_profile = "minimal"' \ + -c 'source .vimrc' \ + -c 'ChopsticksStatus' \ + -c "redir! > $TMP_ROOT/status-minimal.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + grep -Fq 'off vim-lsp stack (LSP disabled by profile)' "$TMP_ROOT/status-minimal.txt" + grep -Fq 'off python (LSP disabled by profile)' "$TMP_ROOT/status-minimal.txt" + if grep -Fq 'LSP actions are buffer-local' "$TMP_ROOT/status-minimal.txt"; then + cat "$TMP_ROOT/status-minimal.txt" + exit 1 + fi + + mkdir -p "$TMP_ROOT/missing-home/.vim/autoload" + cp "$HOME/.vim/autoload/plug.vim" "$TMP_ROOT/missing-home/.vim/autoload/plug.vim" + HOME="$TMP_ROOT/missing-home" XDG_CONFIG_HOME="$EMPTY_XDG" \ + vim -u .vimrc -i NONE -es -N \ + -c 'ChopsticksStatus' \ + -c "redir! > $TMP_ROOT/status-missing-plugin.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + grep -Fq 'vim-lsp not installed; run :PlugInstall' "$TMP_ROOT/status-missing-plugin.txt" + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'doautocmd User lsp_buffer_enabled' \ + -c 'if maparg("gd", "n") !=# "" || maparg("K", "n") !=# "" || maparg("gi", "n") !=# "" || maparg("gr", "n") !=# "" | cquit | endif' \ + -c 'if maparg(",dd", "n") !~# "lsp-definition" | cquit | endif' \ + -c 'if maparg(",dt", "n") !~# "lsp-type-definition" | cquit | endif' \ + -c 'if maparg(",di", "n") !~# "lsp-implementation" | cquit | endif' \ + -c 'if maparg(",dr", "n") !~# "lsp-references" | cquit | endif' \ + -c 'if maparg(",dk", "n") !~# "lsp-hover" | cquit | endif' \ + -c 'if maparg(",dp", "n") !~# "lsp-previous-diagnostic" | cquit | endif' \ + -c 'if maparg(",dn", "n") !~# "lsp-next-diagnostic" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'normal ,?' \ + -c "redir! > $TMP_ROOT/cheat-default.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + grep -Fq ':ChopsticksStatus check LSP setup' "$TMP_ROOT/cheat-default.txt" + grep -Fq ',ff files' "$TMP_ROOT/cheat-default.txt" + grep -Fq ',dd definition' "$TMP_ROOT/cheat-default.txt" + grep -Fq ',dk hover docs' "$TMP_ROOT/cheat-default.txt" + grep -Fq ',dp ,dn LSP diagnostics' "$TMP_ROOT/cheat-default.txt" + grep -Fq 'hjkl navigate splits' "$TMP_ROOT/cheat-default.txt" + if grep -Eq 'Ctrl\\+p find file|Ctrl\\+hjkl navigate splits|Ctrl\\+s save|jk exit insert|gd definition|K hover docs|\\[g \\]g LSP diagnostics' "$TMP_ROOT/cheat-default.txt"; then + cat "$TMP_ROOT/cheat-default.txt" + exit 1 + fi + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:chopsticks_profile = "minimal"' \ + -c 'source .vimrc' \ + -c 'normal ,?' \ + -c "redir! > $TMP_ROOT/cheat.txt" \ + -c 'silent %print' \ + -c 'redir END' \ + -c 'qa!' 2>&1 + if grep -Eq 'definition|LspInstallServer|ALE errors|undo tree|markdown preview' "$TMP_ROOT/cheat.txt"; then + cat "$TMP_ROOT/cheat.txt" + exit 1 + fi + grep -q ',cr run file' "$TMP_ROOT/cheat.txt" + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N README.md \ + -c 'set filetype=markdown' \ + -c 'if &l:spell || &l:conceallevel != 0 || &l:signcolumn !=# "no" || exists("g:lsp_settings_filetype_markdown") | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ + -c 'if maparg("s", "n") !=# "" | cquit | endif' \ + -c 'if maparg(",w", "n") =~# "!" | cquit | endif' \ + -c 'if !&swapfile || !&writebackup || &directory !~# "\.vim/.swap" | cquit | endif' \ + -c 'qa!' 2>&1 + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u NONE -i NONE -es -N \ + -c 'let g:ale_fix_on_save = 0' \ + -c 'source .vimrc' \ + -c 'if g:ale_fix_on_save != 0 | cquit | endif' \ + -c 'qa!' 2>&1 + + truncate -s 11000000 "$TMP_ROOT/large.py" + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N "$TMP_ROOT/large.py" \ + -c 'set filetype=python' \ + -c 'if &l:syntax !=# "" || &l:undolevels != -1 || &l:swapfile || get(b:, "ale_enabled", 1) != 0 | cquit | endif' \ + -c 'qa!' 2>&1 + + mkdir -p "$TMP_ROOT/fake-bin" "$TMP_ROOT/c runner" + cat > "$TMP_ROOT/fake-bin/gcc" <<'GCCEOF' +#!/usr/bin/env bash +set -eu +printf '%s\n' "$@" > "$GCC_ARGS" +out="" +while [ "$#" -gt 0 ]; do + if [ "$1" = "-o" ]; then + shift + out="$1" + fi + shift || true +done +test -n "$out" +printf '%s\n' '#!/usr/bin/env bash' 'exit 0' > "$out" +chmod +x "$out" +GCCEOF + chmod +x "$TMP_ROOT/fake-bin/gcc" + c_file="$TMP_ROOT/c runner/main.c" + c_file_real="$(cd "$TMP_ROOT/c runner" && pwd -P)/main.c" + printf '%s\n' 'int main(void) { return 0; }' > "$c_file" + GCC_ARGS="$TMP_ROOT/gcc-args.txt" \ + PATH="$TMP_ROOT/fake-bin:$PATH" \ + XDG_CONFIG_HOME="$EMPTY_XDG" \ + vim -u .vimrc -i NONE -es -N "$c_file" \ + -c 'set filetype=c' \ + -c 'normal ,cr' \ + -c 'qa!' 2>&1 + c_out="$(sed -n '2p' "$TMP_ROOT/gcc-args.txt")" + test -n "$c_out" + test "$c_out" != "/tmp/a.out" + test ! -e "$c_out" + grep -Fxq "$c_file_real" "$TMP_ROOT/gcc-args.txt" + + XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE --startuptime "$TMP_ROOT/startup.log" \ + -es -N -c 'qa!' 2>/dev/null + tail -1 "$TMP_ROOT/startup.log" + STARTUP_MS="$(awk 'END { print $1 }' "$TMP_ROOT/startup.log")" + awk -v ms="$STARTUP_MS" -v limit="$STARTUP_LIMIT_MS" \ + 'BEGIN { if (ms > limit) exit 1 }' +} + run_group() { case "$1" in - quick | shell | docs | installer | bootstrap) - bash "$SCRIPT_DIR/test-quick.sh" "$1" - ;; - vim) - bash "$SCRIPT_DIR/test-vim.sh" + quick) + check_shell + check_docs + check_installer_modes + check_bootstrap ;; + shell) check_shell ;; + docs) check_docs ;; + installer) check_installer_modes ;; + bootstrap) check_bootstrap ;; + vim) check_vim ;; all) - bash "$SCRIPT_DIR/test-quick.sh" quick - bash "$SCRIPT_DIR/test-vim.sh" + run_group quick + check_vim ;; list | --list) list_groups ;; -h | --help) usage ;;