Compare commits

...

4 commits

Author SHA1 Message Date
9cfec7d0d8 Make PlugClean interactive in install.sh
Previously install.sh ran `_vim_run 'PlugClean!'` unconditionally before
PlugInstall. PlugClean with bang removes any directory under
~/.vim/plugged not declared in the active profile's g:plugs, without
confirmation — silently nuking plugins a user has manually cloned to try
out, plus leftovers from older profile config (Goyo, Limelight, etc.).

Replace with a `list_extra_plugins` helper that runs a Vim subprocess
with all opt-in flags forced on and `$TMUX = '1'`, so the declared set
covers every plugin any chopsticks profile/flag combination could
register. Conditional plugins (vim-tmux-navigator, auto-pairs) are
therefore never flagged as extras.

When extras are detected:
- interactive: list them, ask before running PlugClean!
- --yes: leave in place, instruct the user to run :PlugClean manually
- otherwise (no extras): skip PlugClean entirely (saves an 80ms Vim
  launch on the common case)

Closes #64
2026-05-16 23:09:01 +08:00
002bc7bd3e
Make ,F full-file reindent opt-in (#69)
Some checks are pending
test / startup (macos-latest) (push) Waiting to run
test / startup (ubuntu-latest) (push) Waiting to run
test / shellcheck (push) Waiting to run
test / docs (push) Waiting to run
`,F` in normal mode mapped `gg=G\`\`` — reindent the entire file with
no confirmation. A muscle-typo of `,F` instead of `,f` (LSP format)
rewrites the whole buffer, and `=` does not always produce sensible
indentation for languages where Vim's internal indent expression is
poor.

Gate the normal-mode binding behind `g:chopsticks_enable_reindent_file`
(default off). The visual-mode binding (`vnoremap <leader>F =`) is
bounded by the user's selection and stays as default.

README's all-keybindings table now marks `,F re-indent (v)` to reflect
the visual-only default.

Closes #68
2026-05-16 23:08:26 +08:00
fc872918a1
Make project-local exrc opt-in (#63)
`set exrc` causes Vim to source `.vimrc`/`.exrc` from the current
working directory, which is a wider blast radius than the default
should accept for a config aimed at SSH/shared-host workflows.
`set secure` mitigates the most dangerous behaviors but still allows
arbitrary buffer state changes from an untrusted CWD.

Gate both behind `g:chopsticks_enable_exrc` (default off), following the
existing opt-in convention used for jk escape, Ctrl-S save, auto-pairs,
terminal keymaps, and completion keymaps.

Closes #62
2026-05-16 23:00:44 +08:00
8a36b41d66
Clarify the "no Node.js dependencies" rule (#71)
The original rule was easy to misread as "no npm tools anywhere",
which conflicts with install.sh installing prettier/eslint/etc. The
real boundary is the Vim runtime: no coc.nvim or Node-backed
completion engines. External CLIs that ALE shells out to are fine.

Update the README pointer line to match.

Closes #70
2026-05-16 22:59:40 +08:00
7 changed files with 94 additions and 9 deletions

View file

@ -23,6 +23,9 @@
### Fixed ### Fixed
- `install.sh` no longer silently `PlugClean!`s user-added plugins from
`~/.vim/plugged`; it now lists undeclared plugin directories first and
asks before removing them (`--yes` skips the removal entirely)
- `g:loaded_logipat` typo → `g:loaded_logiPat` — logiPat was loading fully (0.478ms wasted) - `g:loaded_logipat` typo → `g:loaded_logiPat` — logiPat was loading fully (0.478ms wasted)
- `get.sh` now refuses to update an existing `~/.vim` git repo unless its - `get.sh` now refuses to update an existing `~/.vim` git repo unless its
origin is chopsticks origin is chopsticks
@ -33,6 +36,12 @@
### Changed ### Changed
- `set exrc`/`set secure` are now opt-in via `g:chopsticks_enable_exrc = 1`;
Vim no longer sources project-local `.vimrc`/`.exrc` from the working
directory by default
- Normal-mode `,F` (reindent the entire file with `gg=G`) is now opt-in
via `g:chopsticks_enable_reindent_file = 1`; visual-mode `,F` (reindent
selection) stays as the default since it's bounded by the user's pick
- `,?` cheat sheet is now profile-aware and hides LSP/ALE/preview/UndoTree keys - `,?` cheat sheet is now profile-aware and hides LSP/ALE/preview/UndoTree keys
when those features are disabled when those features are disabled
- Module reload/source paths now use `fnameescape()` so installs in paths with - Module reload/source paths now use `fnameescape()` so installs in paths with

View file

@ -2,7 +2,7 @@
## Rules ## Rules
1. **No Node.js dependencies.** The LSP engine is pure VimScript. Some language servers need Node — that's fine. The config itself must not. 1. **No Node.js in the Vim runtime.** Plugins must work with pure VimScript — no coc.nvim or other Node-backed completion engines. External CLIs (prettier, eslint, markdownlint, stylelint, tsc) installed via npm are fine; ALE shells out to them as optional system tools, not as part of the Vim runtime.
2. **Startup matters.** Run `vim -u .vimrc -i NONE --startuptime /tmp/s.log -es -N -c qa!` before and after. If your change adds >1ms, it needs a good reason. 2. **Startup matters.** Run `vim -u .vimrc -i NONE --startuptime /tmp/s.log -es -N -c qa!` before and after. If your change adds >1ms, it needs a good reason.
3. **Works on TTY.** Test over SSH. If it breaks in a terminal without true color, fix it or gate it behind `g:is_tty`. 3. **Works on TTY.** Test over SSH. If it breaks in a terminal without true color, fix it or gate it behind `g:is_tty`.
4. **Native-first keymaps.** Enhance Vim's native behavior instead of replacing it. Do not override built-in motions, operators, text objects, or help-oriented keys for discoverability alone; prefer leader-prefixed or otherwise non-conflicting ergonomic mappings. 4. **Native-first keymaps.** Enhance Vim's native behavior instead of replacing it. Do not override built-in motions, operators, text objects, or help-oriented keys for discoverability alone; prefer leader-prefixed or otherwise non-conflicting ergonomic mappings.

View file

@ -87,6 +87,8 @@ let g:chopsticks_enable_sudo_save_bang = 1 " optional: :w!! sudo save
let g:chopsticks_enable_completion_keymaps = 1 " optional: Tab/Enter completion let g:chopsticks_enable_completion_keymaps = 1 " optional: Tab/Enter completion
let g:chopsticks_enable_auto_pairs = 1 " optional: automatic pair insertion let g:chopsticks_enable_auto_pairs = 1 " optional: automatic pair insertion
let g:chopsticks_enable_terminal_keymaps = 1 " optional: terminal Esc/Ctrl navigation let g:chopsticks_enable_terminal_keymaps = 1 " optional: terminal Esc/Ctrl navigation
let g:chopsticks_enable_exrc = 1 " optional: source project-local .vimrc/.exrc from CWD
let g:chopsticks_enable_reindent_file = 1 " optional: ,F reindents the entire file
``` ```
`minimal` avoids LSP, ALE, completion plugins, extra language syntax plugins, `minimal` avoids LSP, ALE, completion plugins, extra language syntax plugins,
@ -123,7 +125,7 @@ Esc exit insert mode ,? cheat sheet
### Edit ### Edit
`,S`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word | `,F` re-indent | `,W` strip whitespace | `[<Space>` `]<Space>` 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 | `[<Space>` `]<Space>` blank lines
### Git ### Git
@ -230,7 +232,7 @@ More in the [wiki](https://github.com/m1ngsama/chopsticks/wiki).
## Contributing ## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). The two rules that matter: no Node.js dependencies, and don't regress startup time. See [CONTRIBUTING.md](CONTRIBUTING.md). The two rules that matter: no Node.js in the Vim runtime, and don't regress startup time.
## License ## License

View file

@ -656,10 +656,59 @@ VIMEOF
fi fi
} }
if [[ -d "$HOME/.vim/plugged" ]] && [[ -n "$(find "$HOME/.vim/plugged" -mindepth 1 -maxdepth 1 2>/dev/null)" ]]; then # Echoes one name per line for each directory under ~/.vim/plugged that no
warn "PlugClean: removing plugins not listed in .vimrc from ~/.vim/plugged" # chopsticks profile/flag combination would declare. The detection script
# bypasses local config and forces every opt-in on, so a plugin that's only
# loaded inside tmux or behind a flag does NOT show up as "extra". Empty
# output means PlugClean would be a no-op for the user's tree.
list_extra_plugins() {
local declared_file="$_TMPDIR/declared-plugins.txt"
local declare_script="$_TMPDIR/declared-plugins.vim"
local plugged="$HOME/.vim/plugged"
[[ -d "$plugged" ]] || return 0
cat > "$declare_script" <<'VIMEOF'
let g:chopsticks_local_config = '/dev/null'
let $TMUX = '1'
let g:chopsticks_profile = 'full'
let g:chopsticks_enable_auto_pairs = 1
let g:chopsticks_enable_terminal_keymaps = 1
execute 'source ' . fnameescape($CHOPSTICKS_VIMRC)
if !exists('g:plugs')
cquit
endif
call writefile(sort(keys(g:plugs)), $CHOPSTICKS_DECLARED_PLUGINS)
qa!
VIMEOF
CHOPSTICKS_VIMRC="$SCRIPT_DIR/.vimrc" \
CHOPSTICKS_DECLARED_PLUGINS="$declared_file" \
"$VIM_BIN" -u NONE -i NONE -es -N -S "$declare_script" >/dev/null 2>&1 || return 1
[[ -e "$declared_file" ]] || return 0
local plugin name
while IFS= read -r plugin; do
[[ -d "$plugin" ]] || continue
name="$(basename "$plugin")"
if ! grep -Fxq "$name" "$declared_file"; then
printf '%s\n' "$name"
fi
done < <(find "$plugged" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort)
}
extras="$(list_extra_plugins || true)"
if [[ -n "$extras" ]]; then
warn "Plugins under ~/.vim/plugged that the active profile does not declare:"
while IFS= read -r ex; do
[[ -n "$ex" ]] && echo " - $ex"
done <<< "$extras"
if [[ $AUTO_YES -eq 1 ]]; then
info "Leaving them in place (--yes mode). Run :PlugClean inside Vim to remove."
elif ask "Remove these directories with PlugClean!?"; then
_vim_run 'PlugClean!' || true # plug.vim may exit non-zero after removal; harmless
else
info "Leaving them in place. Run :PlugClean inside Vim if you change your mind."
fi
fi fi
_vim_run 'PlugClean!' || true # remove plugins no longer in vimrc; ignore exit code (none expected)
_vim_run 'PlugInstall --sync' || true # fzf post-install hook may exit non-zero; harmless _vim_run 'PlugInstall --sync' || true # fzf post-install hook may exit non-zero; harmless
verify_plugins || die "Plugin installation failed — retry with a stable network connection." verify_plugins || die "Plugin installation failed — retry with a stable network connection."

View file

@ -183,8 +183,10 @@ endif
" ── Project-Local Config ──────────────────────────────────────────────────── " ── Project-Local Config ────────────────────────────────────────────────────
set exrc if get(g:, 'chopsticks_enable_exrc', 0)
set secure set exrc
set secure
endif
set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal
if has("patch-8.1.0360") if has("patch-8.1.0360")

View file

@ -21,7 +21,9 @@ endfunction
" ── Utilities ────────────────────────────────────────────────────────────── " ── Utilities ──────────────────────────────────────────────────────────────
nnoremap <leader>F gg=G`` if get(g:, 'chopsticks_enable_reindent_file', 0)
nnoremap <leader>F gg=G``
endif
vnoremap <leader>F = vnoremap <leader>F =
nnoremap <leader>wa :wa<CR> nnoremap <leader>wa :wa<CR>

View file

@ -236,6 +236,27 @@ check_vim() {
-c 'if has("terminal") && (maparg("<Esc><Esc>", "t") !~# "<C-\\\\><C-N>" || maparg("<C-h>", "t") !~# "<C-W>h" || maparg("<C-j>", "t") !~# "<C-W>j" || maparg("<C-k>", "t") !~# "<C-W>k" || maparg("<C-l>", "t") !~# "<C-W>l") | cquit | endif' \ -c 'if has("terminal") && (maparg("<Esc><Esc>", "t") !~# "<C-\\\\><C-N>" || maparg("<C-h>", "t") !~# "<C-W>h" || maparg("<C-j>", "t") !~# "<C-W>j" || maparg("<C-k>", "t") !~# "<C-W>k" || maparg("<C-l>", "t") !~# "<C-W>l") | cquit | endif' \
-c 'qa!' 2>&1 -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
XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \ XDG_CONFIG_HOME="$EMPTY_XDG" vim -u .vimrc -i NONE -es -N \
-c 'silent! delcommand LspStatus' \ -c 'silent! delcommand LspStatus' \
-c 'silent! delcommand LspInstallServer' \ -c 'silent! delcommand LspInstallServer' \