fix: correct 13 bugs across .vimrc, install.sh, and docs

.vimrc:
- Fix syntax=OFF no-op in large file handler (syntax= is correct)
- Fix <leader>rG broken -F flag (new RgWord command with -F before --)
- Fix :Gdiff → :Gdiffsplit (fugitive v3+ compat)
- Fix go_def_mode/go_info_mode conflicting with go_gopls_enabled=0
- Fix <leader>m prefix collision with mt/mp (renamed to <leader>ms)
- Wrap PlugInstall autocmd in augroup (prevent doubling on re-source)

install.sh:
- Guard against empty version string in hadolint/marksman downloads
- Add HAS_SUDO check in _do_binary_apt before sudo mv
- Add PlugClean warning when existing plugins directory is non-empty
- Fix pkg_install brew-first priority (macOS-only now, Linux fallback)
- Fix menu double-draw flicker on first render
- Fix Fedora deselected tools not tracked in SKIPPED array

docs:
- Remove nonexistent nvm install step from README
- Fix TOC description (side window, not quickfix) in README/QUICKSTART
- Fix TTY detection description (add dumb, empty, builtin)
- Add missing ,cd and ,wa mappings to README
- Remove dead CoC formatOnSaveFiletypes from coc-settings.json
This commit is contained in:
m1ngsama 2026-04-15 09:57:26 +08:00
parent 0b3f631e98
commit 0ba2e84e0c
5 changed files with 92 additions and 43 deletions

30
.vimrc
View file

@ -96,7 +96,10 @@ let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim'
if empty(glob(data_dir . '/autoload/plug.vim')) if empty(glob(data_dir . '/autoload/plug.vim'))
silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs ' silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs '
\ . 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' \ . 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
augroup PlugBootstrap
autocmd!
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
augroup END
endif endif
call plug#begin('~/.vim/plugged') call plug#begin('~/.vim/plugged')
@ -358,7 +361,7 @@ endfunction
map <C-p> :call <SID>SmartFiles()<CR> map <C-p> :call <SID>SmartFiles()<CR>
map <leader>b :Buffers<CR> map <leader>b :Buffers<CR>
map <leader>rg :Rg<CR> map <leader>rg :Rg<CR>
map <leader>rG :Rg -F <C-r><C-w><CR> map <leader>rG :RgWord<CR>
map <leader>rt :Tags<CR> map <leader>rt :Tags<CR>
map <leader>gF :GFiles<CR> map <leader>gF :GFiles<CR>
@ -384,6 +387,19 @@ else
command! -bang GFiles call fzf#vim#gitfiles('', fzf#vim#with_preview(), <bang>0) command! -bang GFiles call fzf#vim#gitfiles('', fzf#vim#with_preview(), <bang>0)
endif endif
" RgWord: fixed-string search for word under cursor (flags before --)
if g:is_tty
command! -bang -nargs=* RgWord
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always --smart-case -F -- '
\ .shellescape(expand('<cword>')), 1, <bang>0)
else
command! -bang -nargs=* RgWord
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always --smart-case -F -- '
\ .shellescape(expand('<cword>')), 1, fzf#vim#with_preview(), <bang>0)
endif
" ============================================================================ " ============================================================================
" => GitGutter " => GitGutter
" ============================================================================ " ============================================================================
@ -450,8 +466,8 @@ nmap <silent> <leader>aD :ALEDetail<cr>
" vim-lsp (gopls) handles all Go intelligence; disable vim-go's own LSP layer " vim-lsp (gopls) handles all Go intelligence; disable vim-go's own LSP layer
let g:go_gopls_enabled = 0 let g:go_gopls_enabled = 0
let g:go_code_completion_enabled = 0 let g:go_code_completion_enabled = 0
let g:go_def_mode = 'gopls' let g:go_def_mode = 'godef'
let g:go_info_mode = 'gopls' let g:go_info_mode = 'godef'
let g:go_fmt_autosave = 0 " ALE handles format-on-save let g:go_fmt_autosave = 0 " ALE handles format-on-save
let g:go_imports_autosave = 0 let g:go_imports_autosave = 0
let g:go_highlight_types = 1 let g:go_highlight_types = 1
@ -903,7 +919,7 @@ nnoremap <leader>cp :let @+ = expand("%:p")<CR>:echo "Copied: " . expand("%:p")<
nnoremap <leader>cf :let @+ = expand("%:t")<CR>:echo "Copied: " . expand("%:t")<CR> nnoremap <leader>cf :let @+ = expand("%:t")<CR>:echo "Copied: " . expand("%:t")<CR>
" Scratch markdown buffer " Scratch markdown buffer
map <leader>m :e ~/buffer.md<cr> nnoremap <leader>ms :e ~/buffer.md<cr>
" Auto-create parent directories on save " Auto-create parent directories on save
function! s:MkNonExDir(file, buf) function! s:MkNonExDir(file, buf)
@ -930,7 +946,7 @@ nnoremap <leader>gs :Git status<CR>
nnoremap <leader>gc :Git commit<CR> nnoremap <leader>gc :Git commit<CR>
nnoremap <leader>gp :Git push<CR> nnoremap <leader>gp :Git push<CR>
nnoremap <leader>gl :Git pull<CR> nnoremap <leader>gl :Git pull<CR>
nnoremap <leader>gd :Gdiff<CR> nnoremap <leader>gd :Gdiffsplit<CR>
nnoremap <leader>gb :Git blame<CR> nnoremap <leader>gb :Git blame<CR>
" ============================================================================ " ============================================================================
@ -967,7 +983,7 @@ function! LargeFileSettings()
setlocal undolevels=-1 setlocal undolevels=-1
setlocal eventignore+=FileType setlocal eventignore+=FileType
setlocal noswapfile setlocal noswapfile
setlocal syntax=OFF setlocal syntax=
let b:ale_enabled = 0 let b:ale_enabled = 0
echo "Large file (>10 MB): syntax, undo, and linting disabled." echo "Large file (>10 MB): syntax, undo, and linting disabled."
endfunction endfunction
@ -977,7 +993,7 @@ if g:is_tty
autocmd! autocmd!
autocmd BufReadPre * autocmd BufReadPre *
\ if !empty(expand('<afile>')) && getfsize(expand('<afile>')) > 512000 | \ if !empty(expand('<afile>')) && getfsize(expand('<afile>')) > 512000 |
\ setlocal syntax=OFF | \ setlocal syntax= |
\ endif \ endif
augroup END augroup END

View file

@ -142,7 +142,7 @@ K Show documentation
| Key | Action | | Key | Action |
|-----|--------| |-----|--------|
| `,mp` | Open live preview in browser | | `,mp` | Open live preview in browser |
| `,mt` | Table of contents | | `,mt` | Table of contents (side window) |
| `zr` / `zm` | Unfold / fold all headings | | `zr` / `zm` | Unfold / fold all headings |
Formatting in the buffer is live: `**bold**` renders as bold, Formatting in the buffer is live: `**bold**` renders as bold,

View file

@ -86,11 +86,10 @@ cd ~/.vim && ./install.sh
3. Backs up existing `~/.vimrc`, then symlinks `~/.vimrc → ~/.vim/.vimrc` 3. Backs up existing `~/.vimrc`, then symlinks `~/.vimrc → ~/.vim/.vimrc`
4. Installs vim-plug and runs `:PlugInstall` 4. Installs vim-plug and runs `:PlugInstall`
5. Offers to install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman) 5. Offers to install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)
6. Offers to install Node.js via nvm (for npm formatters — optional) 6. Offers to install npm formatters (prettier, eslint, etc.) — requires Node.js
7. Offers to install npm formatters (prettier, eslint, etc.) 7. Offers to install Python formatters/linters (black, isort, flake8, etc.)
8. Offers to install Python formatters/linters (black, isort, flake8, etc.) 8. Offers to install Go tools (gopls, goimports, staticcheck)
9. Offers to install Go tools (gopls, goimports, staticcheck) 9. Offers to append vim-tmux-navigator bindings to `~/.tmux.conf`
10. Offers to append vim-tmux-navigator bindings to `~/.tmux.conf`
**Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf). **Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf).
@ -150,10 +149,12 @@ Press `,?` at any time to open the built-in cheat sheet.
| `,E` | Open netrw in vertical split | | `,E` | Open netrw in vertical split |
| `,b` | Search open buffers (FZF) | | `,b` | Search open buffers (FZF) |
| `,rg` | Project-wide search (ripgrep + FZF) | | `,rg` | Project-wide search (ripgrep + FZF) |
| `,rG` | Ripgrep for word under cursor | | `,rG` | Ripgrep word under cursor (fixed-string) |
| `,,` | Switch to last file | | `,,` | Switch to last file |
| `,l` / `,h` | Next / previous buffer | | `,l` / `,h` | Next / previous buffer |
| `,bd` | Close current buffer (preserves window layout) | | `,bd` | Close current buffer (preserves window layout) |
| `,wa` | Save all open buffers |
| `,cd` | Change working directory to current file's directory |
### Code Intelligence (vim-lsp) ### Code Intelligence (vim-lsp)
@ -179,7 +180,7 @@ Press `,?` at any time to open the built-in cheat sheet.
| Key | Action | | Key | Action |
|-----|--------| |-----|--------|
| `,mp` | Open live preview in browser (previm) | | `,mp` | Open live preview in browser (previm) |
| `,mt` | Table of contents | | `,mt` | Table of contents (side window) |
| `zr` / `zm` | Unfold / fold all headings | | `zr` / `zm` | Unfold / fold all headings |
### Git (vim-fugitive) ### Git (vim-fugitive)
@ -253,7 +254,7 @@ No Node.js required. Uses `open` (macOS) or `xdg-open` (Linux).
### Table of contents ### Table of contents
```vim ```vim
,mt " open TOC in a quickfix window — press Enter to jump to heading ,mt " open TOC in a side window — press Enter to jump to heading
``` ```
--- ---
@ -307,7 +308,7 @@ bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
### TTY / SSH Support ### TTY / SSH Support
Detected automatically when `$TERM` is `linux` or `screen`. In TTY mode: Detected automatically when `$TERM` is unset, `dumb`, `linux`, `screen`, or contains `builtin`. In TTY mode:
- True colour and cursorline disabled - True colour and cursorline disabled
- FZF preview windows disabled - FZF preview windows disabled

View file

@ -6,8 +6,5 @@
"filetypes": ["markdown"], "filetypes": ["markdown"],
"rootPatterns": [".git", ".marksman.toml"] "rootPatterns": [".git", ".marksman.toml"]
} }
}, }
"coc.preferences.formatOnSaveFiletypes": [
"markdown"
]
} }

View file

@ -72,10 +72,11 @@ safe_download() {
# ── Cross-platform package install helper ───────────────────────────────────── # ── Cross-platform package install helper ─────────────────────────────────────
pkg_install() { pkg_install() {
local brew_pkg="${1:-}" apt_pkg="${2:-}" pac_pkg="${3:-}" dnf_pkg="${4:-}" local brew_pkg="${1:-}" apt_pkg="${2:-}" pac_pkg="${3:-}" dnf_pkg="${4:-}"
if [[ $HAS_BREW -eq 1 && -n "$brew_pkg" ]]; then brew install "$brew_pkg" >/dev/null 2>&1 if [[ $OS == "macos" && $HAS_BREW -eq 1 && -n "$brew_pkg" ]]; then brew install "$brew_pkg" >/dev/null 2>&1
elif [[ $HAS_APT -eq 1 && -n "$apt_pkg" && $HAS_SUDO -eq 1 ]]; then sudo apt-get install -y "$apt_pkg" >/dev/null 2>&1 elif [[ $HAS_APT -eq 1 && -n "$apt_pkg" && $HAS_SUDO -eq 1 ]]; then sudo apt-get install -y "$apt_pkg" >/dev/null 2>&1
elif [[ $HAS_PACMAN -eq 1 && -n "$pac_pkg" && $HAS_SUDO -eq 1 ]]; then sudo pacman -S --noconfirm "$pac_pkg" >/dev/null 2>&1 elif [[ $HAS_PACMAN -eq 1 && -n "$pac_pkg" && $HAS_SUDO -eq 1 ]]; then sudo pacman -S --noconfirm "$pac_pkg" >/dev/null 2>&1
elif [[ $HAS_DNF -eq 1 && -n "$dnf_pkg" && $HAS_SUDO -eq 1 ]]; then sudo dnf install -y "$dnf_pkg" >/dev/null 2>&1 elif [[ $HAS_DNF -eq 1 && -n "$dnf_pkg" && $HAS_SUDO -eq 1 ]]; then sudo dnf install -y "$dnf_pkg" >/dev/null 2>&1
elif [[ $HAS_BREW -eq 1 && -n "$brew_pkg" ]]; then brew install "$brew_pkg" >/dev/null 2>&1
else return 1 else return 1
fi fi
} }
@ -164,11 +165,14 @@ _menu_checkbox() {
local _key _esc _i local _key _esc _i
tput civis 2>/dev/null # hide cursor tput civis 2>/dev/null # hide cursor
_menu_draw local _first=1
while true; do while true; do
if [[ $_first -eq 0 ]]; then
tput cuu "$_lines" 2>/dev/null # move back to top of menu tput cuu "$_lines" 2>/dev/null # move back to top of menu
fi
_menu_draw _menu_draw
_first=0
IFS= read -r -s -n1 _key </dev/tty IFS= read -r -s -n1 _key </dev/tty
if [[ $_key == $'\x1b' ]]; then if [[ $_key == $'\x1b' ]]; then
@ -412,6 +416,9 @@ _vim_run() {
vim --not-a-term "$@" 2>/dev/null vim --not-a-term "$@" 2>/dev/null
fi fi
} }
if [[ -d "$HOME/.vim/plugged" ]] && [[ -n "$(ls -A "$HOME/.vim/plugged" 2>/dev/null)" ]]; then
warn "PlugClean: removing plugins not listed in .vimrc from ~/.vim/plugged"
fi
_vim_run +'PlugClean!' +qall || true # remove plugins no longer in vimrc; ignore exit code (none expected) _vim_run +'PlugClean!' +qall || true # remove plugins no longer in vimrc; ignore exit code (none expected)
_vim_run +'PlugInstall --sync' +qall || true # fzf post-install hook may exit non-zero; harmless _vim_run +'PlugInstall --sync' +qall || true # fzf post-install hook may exit non-zero; harmless
@ -558,6 +565,10 @@ _do_binary_apt() {
if command -v "$check" >/dev/null 2>&1; then if command -v "$check" >/dev/null 2>&1; then
ok "$name (already installed)"; return ok "$name (already installed)"; return
fi fi
if [[ $HAS_SUDO -ne 1 ]]; then
fail "$name — sudo not available, cannot install to /usr/local/bin"
FAILED+=("$name"); return
fi
if safe_download "$url" "$tmp"; then if safe_download "$url" "$tmp"; then
chmod +x "$tmp" && sudo mv "$tmp" /usr/local/bin/"$check" chmod +x "$tmp" && sudo mv "$tmp" /usr/local/bin/"$check"
ok "$name"; INSTALLED+=("$name") ok "$name"; INSTALLED+=("$name")
@ -583,20 +594,38 @@ elif [[ $HAS_APT -eq 1 ]]; then
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" shellcheck "" "" _do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" shellcheck "" ""
# hadolint: no apt package — binary from GitHub releases # hadolint: no apt package — binary from GitHub releases
if [[ $_I_HADOLINT -ge 0 ]] && _selected "$_I_HADOLINT"; then
HARCH=$(arch_github) HARCH=$(arch_github)
HVER=$(curl -fsSL https://api.github.com/repos/hadolint/hadolint/releases/latest \ HVER=$(curl -fsSL https://api.github.com/repos/hadolint/hadolint/releases/latest \
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || HVER="" | grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || HVER=""
if [[ -z "$HVER" ]]; then
fail "hadolint — could not determine latest release version"
FAILED+=("hadolint")
else
_do_binary_apt "hadolint" hadolint "$_I_HADOLINT" \ _do_binary_apt "hadolint" hadolint "$_I_HADOLINT" \
"https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \ "https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \
/tmp/chopsticks-hadolint /tmp/chopsticks-hadolint
fi
else
skip "hadolint"; SKIPPED+=("hadolint")
fi
# marksman: no apt package — binary from GitHub releases # marksman: no apt package — binary from GitHub releases
if [[ $_I_MARKSMAN -ge 0 ]] && _selected "$_I_MARKSMAN"; then
MARCH=$(arch_linux_x64) MARCH=$(arch_linux_x64)
MVER=$(curl -fsSL https://api.github.com/repos/artempyanykh/marksman/releases/latest \ MVER=$(curl -fsSL https://api.github.com/repos/artempyanykh/marksman/releases/latest \
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || MVER="" | grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || MVER=""
if [[ -z "$MVER" ]]; then
fail "marksman — could not determine latest release version"
FAILED+=("marksman")
else
_do_binary_apt "marksman" marksman "$_I_MARKSMAN" \ _do_binary_apt "marksman" marksman "$_I_MARKSMAN" \
"https://github.com/artempyanykh/marksman/releases/download/${MVER}/marksman-linux-${MARCH}" \ "https://github.com/artempyanykh/marksman/releases/download/${MVER}/marksman-linux-${MARCH}" \
/tmp/chopsticks-marksman /tmp/chopsticks-marksman
fi
else
skip "marksman"; SKIPPED+=("marksman")
fi
elif [[ $HAS_PACMAN -eq 1 ]]; then elif [[ $HAS_PACMAN -eq 1 ]]; then
_do_sys "ripgrep" rg "$_I_RIPGREP" "" "" ripgrep "" _do_sys "ripgrep" rg "$_I_RIPGREP" "" "" ripgrep ""
@ -610,16 +639,22 @@ elif [[ $HAS_DNF -eq 1 ]]; then
_do_sys "ripgrep" rg "$_I_RIPGREP" "" "" "" ripgrep _do_sys "ripgrep" rg "$_I_RIPGREP" "" "" "" ripgrep
_do_sys "fzf" fzf "$_I_FZF" "" "" "" fzf _do_sys "fzf" fzf "$_I_FZF" "" "" "" fzf
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" "" "" ShellCheck _do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" "" "" ShellCheck
if [[ $_I_CTAGS -ge 0 ]] && _selected "$_I_CTAGS"; then if [[ $_I_CTAGS -ge 0 ]]; then
if _selected "$_I_CTAGS"; then
skip "universal-ctags — Fedora: install manually: sudo dnf install ctags" skip "universal-ctags — Fedora: install manually: sudo dnf install ctags"
fi
SKIPPED+=("universal-ctags") SKIPPED+=("universal-ctags")
fi fi
if [[ $_I_HADOLINT -ge 0 ]] && _selected "$_I_HADOLINT"; then if [[ $_I_HADOLINT -ge 0 ]]; then
if _selected "$_I_HADOLINT"; then
skip "hadolint — Fedora: install manually: https://github.com/hadolint/hadolint/releases" skip "hadolint — Fedora: install manually: https://github.com/hadolint/hadolint/releases"
fi
SKIPPED+=("hadolint") SKIPPED+=("hadolint")
fi fi
if [[ $_I_MARKSMAN -ge 0 ]] && _selected "$_I_MARKSMAN"; then if [[ $_I_MARKSMAN -ge 0 ]]; then
if _selected "$_I_MARKSMAN"; then
skip "marksman — Fedora: install manually: https://github.com/artempyanykh/marksman/releases" skip "marksman — Fedora: install manually: https://github.com/artempyanykh/marksman/releases"
fi
SKIPPED+=("marksman") SKIPPED+=("marksman")
fi fi
else else