audit: wrap loose autocmds in augroups, fix install.sh robustness (#13)

.vimrc:
- Wrap all loose autocmds in named augroups with autocmd! (prevents
  doubling on :source $MYVIMRC): ChopstickTabHistory, ChopstickResize,
  ChopstickStdin, CocHighlight, ChopstickCleanup, ChopstickFiletype,
  ChopstickTTYLargeFile, ChopstickWhichKey, ChopstickStartify

install.sh:
- Add Arch Linux (pacman) branch for system tools
- Add hadolint to system tools (brew/apt binary download/pacman)
- Add staticcheck to Go tools
- Add yamllint to pip tools
- Remove sqlfmt from npm (SQL unified to sqlfluff via pip)
- Remove coc-marksman (package does not exist on npm)
- Add coc-settings.json symlink step with backup
- Add pip3 bootstrap when python3 present but pip3 absent
- Fix PlugInstall and CocInstall to use </dev/null (TTY-safe)

coc-settings.json:
- New file: configures marksman as Markdown LSP server for CoC
  (replaces the broken coc-marksman npm package approach)
This commit is contained in:
m1ngsama 2026-03-29 16:36:43 +08:00 committed by GitHub
parent db16c2f8fc
commit 3daf725ad8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 174 additions and 69 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
*.json *.json
!coc-settings.json

118
.vimrc
View file

@ -235,6 +235,14 @@ call plug#end()
let g:use_coc = (has('nvim') || has('patch-8.0.1453')) && executable('node') && exists('g:plugs["coc.nvim"]') let g:use_coc = (has('nvim') || has('patch-8.0.1453')) && executable('node') && exists('g:plugs["coc.nvim"]')
let g:use_vimlsp = !g:use_coc && has('patch-8.0.0') && exists('g:plugs["vim-lsp"]') let g:use_vimlsp = !g:use_coc && has('patch-8.0.0') && exists('g:plugs["vim-lsp"]')
" Suppress coc.nvim's blocking startup warning on Vim < 9.0.0438
" (the guard above already prevents coc from loading, but the warning
" fires from the plugin file itself if coc.nvim is in runtimepath)
if !g:use_coc
let g:coc_start_at_startup = 0
let g:coc_disable_startup_warning = 1
endif
" Limit popup menu height (applies to all completion) " Limit popup menu height (applies to all completion)
set pumheight=15 set pumheight=15
@ -343,7 +351,10 @@ map <leader>t<leader> :tabnext<cr>
" Let 'tl' toggle between this and the last accessed tab " Let 'tl' toggle between this and the last accessed tab
let g:lasttab = 1 let g:lasttab = 1
nmap <Leader>tl :exe "tabn ".g:lasttab<CR> nmap <Leader>tl :exe "tabn ".g:lasttab<CR>
au TabLeave * let g:lasttab = tabpagenr() augroup ChopstickTabHistory
autocmd!
autocmd TabLeave * let g:lasttab = tabpagenr()
augroup END
" Opens a new tab with the current buffer's path " Opens a new tab with the current buffer's path
map <leader>te :tabedit <C-r>=expand("%:p:h")<cr>/ map <leader>te :tabedit <C-r>=expand("%:p:h")<cr>/
@ -411,7 +422,10 @@ nnoremap <leader>qo :copen<CR>
nnoremap <leader>qc :cclose<CR> nnoremap <leader>qc :cclose<CR>
" Auto-equalize splits when terminal window is resized " Auto-equalize splits when terminal window is resized
autocmd VimResized * wincmd = augroup ChopstickResize
autocmd!
autocmd VimResized * wincmd =
augroup END
" ============================================================================ " ============================================================================
" => Plugin Settings " => Plugin Settings
@ -437,7 +451,10 @@ let NERDTreeIgnore=['\.pyc$', '\~$', '\.swp$', '\.git$', '\.DS_Store', 'node_mod
let NERDTreeWinSize=35 let NERDTreeWinSize=35
" Track stdin reads so startup autocmds can skip pipe/heredoc input " Track stdin reads so startup autocmds can skip pipe/heredoc input
autocmd StdinReadPre * let s:std_in=1 augroup ChopstickStdin
autocmd!
autocmd StdinReadPre * let s:std_in=1
augroup END
" Startup layout (non-TTY only — keeps TTY startup instant) " Startup layout (non-TTY only — keeps TTY startup instant)
if !g:is_tty if !g:is_tty
@ -538,7 +555,7 @@ let g:ale_linters = {
\ 'python': ['flake8', 'pylint'], \ 'python': ['flake8', 'pylint'],
\ 'javascript': ['eslint'], \ 'javascript': ['eslint'],
\ 'typescript': ['eslint', 'tsserver'], \ 'typescript': ['eslint', 'tsserver'],
\ 'go': ['gopls', 'golint'], \ 'go': ['gopls', 'staticcheck'],
\ 'rust': ['cargo'], \ 'rust': ['cargo'],
\ 'sh': ['shellcheck'], \ 'sh': ['shellcheck'],
\ 'yaml': ['yamllint'], \ 'yaml': ['yamllint'],
@ -563,7 +580,7 @@ let g:ale_fixers = {
\ 'scss': ['prettier'], \ 'scss': ['prettier'],
\ 'less': ['prettier'], \ 'less': ['prettier'],
\ 'markdown': ['prettier'], \ 'markdown': ['prettier'],
\ 'sql': ['sqlfmt'], \ 'sql': ['sqlfluff'],
\} \}
" Don't fix on save if LSP is handling formatting (avoids double-format) " Don't fix on save if LSP is handling formatting (avoids double-format)
@ -577,10 +594,11 @@ let g:ale_lint_on_enter = 0
" --- vim-go: disable built-in LSP/gopls — CoC (coc-go) handles all Go intelligence --- " --- vim-go: disable built-in LSP/gopls — CoC (coc-go) handles all Go intelligence ---
" vim-go's gopls conflicts with coc-go and causes E495 errors on startup " vim-go's gopls conflicts with coc-go and causes E495 errors on startup
" (BufWinEnter afile expand fails for non-file buffers like NERDTree/Startify) " (BufWinEnter afile expand fails for non-file buffers like NERDTree/Startify)
let g:go_gopls_enabled = 0 " disable vim-go's own gopls client let g:go_gopls_enabled = 0 " disable vim-go's own gopls — coc-go handles LSP
let g:go_code_completion_enabled = 0 " let CoC handle completion let g:go_code_completion_enabled = 0 " let CoC handle completion
let g:go_def_mode = 'gopls' " fallback if CoC unavailable (won't start without g:go_gopls_enabled) " Use godef as fallback for jump-to-def when CoC unavailable; gopls+disabled = error
let g:go_info_mode = 'gopls' let g:go_def_mode = g:use_coc ? 'gopls' : 'godef'
let g:go_info_mode = g:use_coc ? 'gopls' : 'godef'
let g:go_fmt_autosave = 0 " CoC/ALE handle format-on-save let g:go_fmt_autosave = 0 " CoC/ALE handle format-on-save
let g:go_imports_autosave = 0 let g:go_imports_autosave = 0
let g:go_highlight_types = 1 " keep syntax features let g:go_highlight_types = 1 " keep syntax features
@ -655,7 +673,10 @@ if g:use_coc
endfunction endfunction
" Highlight symbol and its references on cursor hold " Highlight symbol and its references on cursor hold
autocmd CursorHold * silent call CocActionAsync('highlight') augroup CocHighlight
autocmd!
autocmd CursorHold * silent call CocActionAsync('highlight')
augroup END
" Symbol renaming " Symbol renaming
nmap <leader>rn <Plug>(coc-rename) nmap <leader>rn <Plug>(coc-rename)
@ -832,54 +853,58 @@ fun! CleanExtraSpaces()
call setreg('/', old_query) call setreg('/', old_query)
endfun endfun
if has("autocmd") augroup ChopstickCleanup
autocmd!
" Run for real files only; skip special buffers (NERDTree, Startify, terminal, etc.) " Run for real files only; skip special buffers (NERDTree, Startify, terminal, etc.)
autocmd BufWritePre * if empty(&buftype) && !empty(expand('<afile>')) | call CleanExtraSpaces() | endif autocmd BufWritePre * if empty(&buftype) && !empty(expand('<afile>')) | call CleanExtraSpaces() | endif
endif augroup END
" ============================================================================ " ============================================================================
" => Auto Commands " => Auto Commands
" ============================================================================ " ============================================================================
" Return to last edit position when opening files augroup ChopstickFiletype
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif autocmd!
" Return to last edit position when opening files
autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
" Set specific file types " Set specific file types
autocmd BufNewFile,BufRead *.json setlocal filetype=json autocmd BufNewFile,BufRead *.json setlocal filetype=json
autocmd BufNewFile,BufRead *.md setlocal filetype=markdown autocmd BufNewFile,BufRead *.md setlocal filetype=markdown
autocmd BufNewFile,BufRead *.jsx setlocal filetype=javascript.jsx autocmd BufNewFile,BufRead *.jsx setlocal filetype=javascript.jsx
autocmd BufNewFile,BufRead *.tsx setlocal filetype=typescript.tsx autocmd BufNewFile,BufRead *.tsx setlocal filetype=typescript.tsx
" Python specific settings " Python specific settings
autocmd FileType python setlocal expandtab shiftwidth=4 tabstop=4 colorcolumn=88 autocmd FileType python setlocal expandtab shiftwidth=4 tabstop=4 colorcolumn=88
" JavaScript specific settings " JavaScript specific settings
autocmd FileType javascript,typescript setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType javascript,typescript setlocal expandtab shiftwidth=2 tabstop=2
" Go specific settings " Go specific settings
autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4 autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4
" HTML/CSS specific settings " HTML/CSS specific settings
autocmd FileType html,css setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType html,css setlocal expandtab shiftwidth=2 tabstop=2
" YAML specific settings " YAML specific settings
autocmd FileType yaml setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType yaml setlocal expandtab shiftwidth=2 tabstop=2
" Markdown specific settings " Markdown specific settings
autocmd FileType markdown setlocal wrap linebreak spell tw=0 autocmd FileType markdown setlocal wrap linebreak spell tw=0
" Shell script settings " Shell script settings
autocmd FileType sh setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType sh setlocal expandtab shiftwidth=2 tabstop=2
" Makefile settings (must use tabs) " Makefile settings (must use tabs)
autocmd FileType make setlocal noexpandtab shiftwidth=8 tabstop=8 autocmd FileType make setlocal noexpandtab shiftwidth=8 tabstop=8
" JSON specific settings " JSON specific settings
autocmd FileType json setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType json setlocal expandtab shiftwidth=2 tabstop=2
" Docker specific settings " Docker specific settings
autocmd BufNewFile,BufRead Dockerfile* setlocal filetype=dockerfile autocmd BufNewFile,BufRead Dockerfile* setlocal filetype=dockerfile
autocmd FileType dockerfile setlocal expandtab shiftwidth=2 tabstop=2 autocmd FileType dockerfile setlocal expandtab shiftwidth=2 tabstop=2
augroup END
" ============================================================================ " ============================================================================
" => Status Line " => Status Line
@ -1071,7 +1096,10 @@ endfunction
" Additional optimizations for TTY/basic terminals " Additional optimizations for TTY/basic terminals
if g:is_tty if g:is_tty
" Disable syntax highlighting for very large files in TTY " Disable syntax highlighting for very large files in TTY
autocmd BufReadPre * if !empty(expand('<afile>')) && getfsize(expand('<afile>')) > 512000 | setlocal syntax=OFF | endif augroup ChopstickTTYLargeFile
autocmd!
autocmd BufReadPre * if !empty(expand('<afile>')) && getfsize(expand('<afile>')) > 512000 | setlocal syntax=OFF | endif
augroup END
" Simpler status line for TTY " Simpler status line for TTY
set statusline=%f\ %h%w%m%r\ %=%(%l,%c%V\ %=\ %P%) set statusline=%f\ %h%w%m%r\ %=%(%l,%c%V\ %=\ %P%)
@ -1101,7 +1129,10 @@ set timeoutlen=500
if exists('g:plugs["vim-which-key"]') if exists('g:plugs["vim-which-key"]')
" Register after plugins are loaded (autoload functions available at VimEnter) " Register after plugins are loaded (autoload functions available at VimEnter)
autocmd VimEnter * call which_key#register(',', 'g:which_key_map') augroup ChopstickWhichKey
autocmd!
autocmd VimEnter * call which_key#register(',', 'g:which_key_map')
augroup END
nnoremap <silent> <leader> :<C-u>WhichKey ','<CR> nnoremap <silent> <leader> :<C-u>WhichKey ','<CR>
vnoremap <silent> <leader> :<C-u>WhichKeyVisual ','<CR> vnoremap <silent> <leader> :<C-u>WhichKeyVisual ','<CR>
@ -1262,7 +1293,10 @@ if exists('g:plugs["vim-startify"]')
let g:startify_files_number = 10 let g:startify_files_number = 10
" Required for NERDTree compatibility (prevents buftype conflicts) " Required for NERDTree compatibility (prevents buftype conflicts)
autocmd User Startified setlocal buftype= augroup ChopstickStartify
autocmd!
autocmd User Startified setlocal buftype=
augroup END
endif endif
" ============================================================================ " ============================================================================

13
coc-settings.json Normal file
View file

@ -0,0 +1,13 @@
{
"languageserver": {
"marksman": {
"command": "marksman",
"args": ["server"],
"filetypes": ["markdown"],
"rootPatterns": [".git", ".marksman.toml"]
}
},
"coc.preferences.formatOnSaveFiletypes": [
"markdown"
]
}

View file

@ -93,13 +93,28 @@ HAS_BREW=0; command -v brew >/dev/null 2>&1 && HAS_BREW=1
HAS_APT=0; command -v apt >/dev/null 2>&1 && HAS_APT=1 HAS_APT=0; command -v apt >/dev/null 2>&1 && HAS_APT=1
HAS_DNF=0; command -v dnf >/dev/null 2>&1 && HAS_DNF=1 HAS_DNF=0; command -v dnf >/dev/null 2>&1 && HAS_DNF=1
HAS_PACMAN=0; command -v pacman >/dev/null 2>&1 && HAS_PACMAN=1 HAS_PACMAN=0; command -v pacman >/dev/null 2>&1 && HAS_PACMAN=1
HAS_NODE=0; command -v node >/dev/null 2>&1 && HAS_NODE=1 && ok "Node.js $(node --version) detected" HAS_NODE=0; command -v node >/dev/null 2>&1 && HAS_NODE=1 && ok "Node.js $(node --version) detected"
HAS_PIP=0; command -v pip3 >/dev/null 2>&1 && HAS_PIP=1 && ok "Python/pip3 detected" HAS_PYTHON=0; command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1
HAS_GO=0; command -v go >/dev/null 2>&1 && HAS_GO=1 && ok "Go $(go version | awk '{print $3}') detected" HAS_PIP=0; command -v pip3 >/dev/null 2>&1 && HAS_PIP=1
HAS_GO=0; command -v go >/dev/null 2>&1 && HAS_GO=1 && ok "Go $(go version | awk '{print $3}') detected"
[[ $HAS_NODE -eq 0 ]] && warn "Node.js not found — JS/TS/Markdown npm tools will be skipped" # Bootstrap pip3 when python3 exists but pip3 is absent (common on Ubuntu minimal images)
[[ $HAS_PIP -eq 0 ]] && warn "pip3 not found — Python tools will be skipped" if [[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]]; then
[[ $HAS_GO -eq 0 ]] && warn "Go not found — Go tools will be skipped" warn "python3 found but pip3 missing — attempting bootstrap"
if python3 -m ensurepip --upgrade >/dev/null 2>&1 || \
(command -v apt-get >/dev/null 2>&1 && sudo apt-get install -y python3-pip >/dev/null 2>&1) || \
(command -v pacman >/dev/null 2>&1 && sudo pacman -S --noconfirm python-pip >/dev/null 2>&1) || \
(command -v dnf >/dev/null 2>&1 && sudo dnf install -y python3-pip >/dev/null 2>&1); then
command -v pip3 >/dev/null 2>&1 && HAS_PIP=1 && ok "pip3 bootstrapped"
else
warn "pip3 bootstrap failed — Python tools will be skipped"
fi
fi
[[ $HAS_PIP -eq 1 ]] && ok "Python/pip3 detected"
[[ $HAS_NODE -eq 0 ]] && warn "Node.js not found — JS/TS/Markdown npm tools will be skipped"
[[ $HAS_PIP -eq 0 ]] && warn "pip3 not found — Python tools will be skipped"
[[ $HAS_GO -eq 0 ]] && warn "Go not found — Go tools will be skipped"
# ============================================================================ # ============================================================================
# Symlink # Symlink
@ -116,6 +131,17 @@ fi
ln -sf "$SCRIPT_DIR/.vimrc" "$HOME/.vimrc" ln -sf "$SCRIPT_DIR/.vimrc" "$HOME/.vimrc"
ok "~/.vimrc -> $SCRIPT_DIR/.vimrc" ok "~/.vimrc -> $SCRIPT_DIR/.vimrc"
# CoC settings (marksman markdown LSP + format-on-save config)
mkdir -p "$HOME/.vim"
COC_CFG="$HOME/.vim/coc-settings.json"
if [ -f "$COC_CFG" ] && [ ! -L "$COC_CFG" ]; then
TS=$(date +%Y%m%d_%H%M%S)
warn "Backing up existing coc-settings.json to ~/.vim/coc-settings.json.backup.$TS"
mv "$COC_CFG" "$COC_CFG.backup.$TS"
fi
ln -sf "$SCRIPT_DIR/coc-settings.json" "$COC_CFG"
ok "~/.vim/coc-settings.json -> $SCRIPT_DIR/coc-settings.json"
# ============================================================================ # ============================================================================
# vim-plug + plugins # vim-plug + plugins
# ============================================================================ # ============================================================================
@ -132,7 +158,8 @@ else
fi fi
step "Installing Vim plugins" step "Installing Vim plugins"
vim +PlugInstall +qall # </dev/null prevents Vim from reading stdin in non-interactive/piped environments
vim +PlugInstall +qall </dev/null
ok "Plugins installed" ok "Plugins installed"
# ============================================================================ # ============================================================================
@ -141,7 +168,7 @@ ok "Plugins installed"
step "System tools" step "System tools"
if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, marksman)?"; then if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)?"; then
install_sys() { install_sys() {
local name="$1"; local check="$2"; shift 2 local name="$1"; local check="$2"; shift 2
if command -v "$check" >/dev/null 2>&1; then if command -v "$check" >/dev/null 2>&1; then
@ -163,17 +190,36 @@ if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, marksman)?"; then
if [[ $OS == macos ]]; then if [[ $OS == macos ]]; then
command -v brew >/dev/null 2>&1 || { warn "brew not found — skipping system tools"; } command -v brew >/dev/null 2>&1 || { warn "brew not found — skipping system tools"; }
install_sys "ripgrep" rg "brew install ripgrep" install_sys "ripgrep" rg "brew install ripgrep"
install_sys "fzf" fzf "brew install fzf" install_sys "fzf" fzf "brew install fzf"
install_sys "universal-ctags" ctags "brew install universal-ctags" install_sys "universal-ctags" ctags "brew install universal-ctags"
install_sys "shellcheck" shellcheck "brew install shellcheck" install_sys "shellcheck" shellcheck "brew install shellcheck"
install_sys "marksman" marksman "brew install marksman" install_sys "hadolint" hadolint "brew install hadolint"
install_sys "marksman" marksman "brew install marksman"
elif [[ $HAS_APT -eq 1 ]]; then elif [[ $HAS_APT -eq 1 ]]; then
sudo apt-get update -qq sudo apt-get update -qq
install_sys "ripgrep" rg "sudo apt-get install -y ripgrep" install_sys "ripgrep" rg "sudo apt-get install -y ripgrep"
install_sys "fzf" fzf "sudo apt-get install -y fzf" install_sys "fzf" fzf "sudo apt-get install -y fzf"
install_sys "universal-ctags" ctags "sudo apt-get install -y universal-ctags" install_sys "universal-ctags" ctags "sudo apt-get install -y universal-ctags"
install_sys "shellcheck" shellcheck "sudo apt-get install -y shellcheck" install_sys "shellcheck" shellcheck "sudo apt-get install -y shellcheck"
# hadolint: no apt package, download binary
if ! command -v hadolint >/dev/null 2>&1; then
ARCH=$(uname -m)
[[ "$ARCH" == "x86_64" ]] && HARCH="x86_64" || HARCH="arm64"
HVER=$(curl -s https://api.github.com/repos/hadolint/hadolint/releases/latest \
| grep '"tag_name"' | cut -d'"' -f4)
if [[ -n "$HVER" ]]; then
curl -fsSL "https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \
-o /tmp/hadolint && chmod +x /tmp/hadolint && sudo mv /tmp/hadolint /usr/local/bin/hadolint
ok "hadolint"
INSTALLED+=("hadolint")
else
warn "hadolint: could not detect latest release, install manually"
SKIPPED+=("hadolint")
fi
else
ok "hadolint (already installed)"
fi
# marksman: no apt package, download binary # marksman: no apt package, download binary
if ! command -v marksman >/dev/null 2>&1; then if ! command -v marksman >/dev/null 2>&1; then
ARCH=$(uname -m) ARCH=$(uname -m)
@ -192,21 +238,30 @@ if ask "Install system tools (ripgrep, fzf, ctags, shellcheck, marksman)?"; then
else else
ok "marksman (already installed)" ok "marksman (already installed)"
fi fi
elif [[ $HAS_PACMAN -eq 1 ]]; then
install_sys "ripgrep" rg "sudo pacman -S --noconfirm ripgrep"
install_sys "fzf" fzf "sudo pacman -S --noconfirm fzf"
install_sys "universal-ctags" ctags "sudo pacman -S --noconfirm ctags"
install_sys "shellcheck" shellcheck "sudo pacman -S --noconfirm shellcheck"
install_sys "hadolint" hadolint "sudo pacman -S --noconfirm hadolint"
install_sys "marksman" marksman "sudo pacman -S --noconfirm marksman"
elif [[ $HAS_DNF -eq 1 ]]; then elif [[ $HAS_DNF -eq 1 ]]; then
install_sys "ripgrep" rg "sudo dnf install -y ripgrep" install_sys "ripgrep" rg "sudo dnf install -y ripgrep"
install_sys "fzf" fzf "sudo dnf install -y fzf" install_sys "fzf" fzf "sudo dnf install -y fzf"
install_sys "shellcheck" shellcheck "sudo dnf install -y ShellCheck" install_sys "shellcheck" shellcheck "sudo dnf install -y ShellCheck"
skip "universal-ctags — install manually: sudo dnf install ctags" skip "universal-ctags — install manually: sudo dnf install ctags"
SKIPPED+=("ctags") SKIPPED+=("ctags")
skip "hadolint — install manually from https://github.com/hadolint/hadolint/releases"
SKIPPED+=("hadolint")
skip "marksman — install manually from https://github.com/artempyanykh/marksman/releases" skip "marksman — install manually from https://github.com/artempyanykh/marksman/releases"
SKIPPED+=("marksman") SKIPPED+=("marksman")
else else
warn "Unknown Linux distro — skipping system tools (install manually)" warn "Unknown Linux distro — skipping system tools (install manually)"
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "marksman") SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
fi fi
else else
skip "system tools" skip "system tools"
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "marksman") SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
fi fi
# ============================================================================ # ============================================================================
@ -237,7 +292,6 @@ if [[ $HAS_NODE -eq 1 ]]; then
npm_install stylelint-config-standard npm_install stylelint-config-standard
npm_install eslint npm_install eslint
npm_install typescript tsc npm_install typescript tsc
npm_install sqlfmt
else else
skip "npm tools" skip "npm tools"
SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript") SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript")
@ -254,7 +308,7 @@ fi
step "Python tools (formatters + linters)" step "Python tools (formatters + linters)"
if [[ $HAS_PIP -eq 1 ]]; then if [[ $HAS_PIP -eq 1 ]]; then
if ask "Install Python tools (black, isort, flake8, pylint, sqlfluff)?"; then if ask "Install Python tools (black, isort, flake8, pylint, yamllint, sqlfluff)?"; then
pip_install() { pip_install() {
local pkg="$1"; local check="${2:-$1}" local pkg="$1"; local check="${2:-$1}"
if command -v "$check" >/dev/null 2>&1; then if command -v "$check" >/dev/null 2>&1; then
@ -274,24 +328,25 @@ if [[ $HAS_PIP -eq 1 ]]; then
pip_install isort pip_install isort
pip_install flake8 pip_install flake8
pip_install pylint pip_install pylint
pip_install yamllint
pip_install sqlfluff pip_install sqlfluff
else else
skip "Python tools" skip "Python tools"
SKIPPED+=("black" "isort" "flake8" "pylint" "sqlfluff") SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
fi fi
else else
skip "Python tools (pip3 not installed)" skip "Python tools (pip3 not installed)"
SKIPPED+=("black" "isort" "flake8" "pylint" "sqlfluff") SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
fi fi
# ============================================================================ # ============================================================================
# Go tools (gopls, goimports) # Go tools (gopls, goimports, staticcheck)
# ============================================================================ # ============================================================================
step "Go tools" step "Go tools"
if [[ $HAS_GO -eq 1 ]]; then if [[ $HAS_GO -eq 1 ]]; then
if ask "Install Go tools (gopls, goimports)?"; then if ask "Install Go tools (gopls, goimports, staticcheck)?"; then
# Go installs binaries to $(go env GOPATH)/bin — add to PATH for this session # Go installs binaries to $(go env GOPATH)/bin — add to PATH for this session
GOBIN="$(go env GOPATH)/bin" GOBIN="$(go env GOPATH)/bin"
export PATH="$PATH:$GOBIN" export PATH="$PATH:$GOBIN"
@ -310,8 +365,9 @@ if [[ $HAS_GO -eq 1 ]]; then
FAILED+=("$name") FAILED+=("$name")
fi fi
} }
go_install gopls "golang.org/x/tools/gopls@latest" gopls go_install gopls "golang.org/x/tools/gopls@latest" gopls
go_install goimports "golang.org/x/tools/cmd/goimports@latest" goimports go_install goimports "golang.org/x/tools/cmd/goimports@latest" goimports
go_install staticcheck "honnef.co/go/tools/cmd/staticcheck@latest" staticcheck
# Remind user to add GOPATH/bin to their shell profile # Remind user to add GOPATH/bin to their shell profile
if ! echo "$PATH" | grep -q "$GOBIN"; then if ! echo "$PATH" | grep -q "$GOBIN"; then
@ -319,11 +375,11 @@ if [[ $HAS_GO -eq 1 ]]; then
fi fi
else else
skip "Go tools" skip "Go tools"
SKIPPED+=("gopls" "goimports") SKIPPED+=("gopls" "goimports" "staticcheck")
fi fi
else else
skip "Go tools (go not installed)" skip "Go tools (go not installed)"
SKIPPED+=("gopls" "goimports") SKIPPED+=("gopls" "goimports" "staticcheck")
fi fi
# ============================================================================ # ============================================================================
@ -334,7 +390,8 @@ step "CoC language server extensions"
if [[ $HAS_NODE -eq 1 ]]; then if [[ $HAS_NODE -eq 1 ]]; then
if ask "Install CoC language servers (LSP for all configured languages)?"; then if ask "Install CoC language servers (LSP for all configured languages)?"; then
vim +'CocInstall -sync coc-json coc-tsserver coc-pyright coc-sh coc-html coc-css coc-yaml coc-go coc-rust-analyzer coc-marksman coc-sql' +qall # Note: coc-marksman doesn't exist on npm — markdown LSP is handled via coc-settings.json
vim +'CocInstall -sync coc-json coc-tsserver coc-pyright coc-sh coc-html coc-css coc-yaml coc-go coc-rust-analyzer coc-sql' +qall </dev/null
ok "CoC language servers installed" ok "CoC language servers installed"
else else
skip "CoC language servers" skip "CoC language servers"