mirror of
https://oauth2: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@github.com/m1ngsama/chopsticks.git
synced 2026-05-10 19:10:59 +08:00
fix: correct non-TTY vim-plug install; add real plugin count check
- _vim_run non-TTY branch: remove </dev/null (caused "Error reading input, exiting" before downloads finished → 0 plugins installed) and >/dev/null (broke async job callbacks → partial install of ~13/26). Now only redirects stderr; stdin inherits from caller so vim's event loop runs to completion. - Add post-install verification: count ~/.vim/plugged entries and die if empty, replacing the unconditional "ok Plugins installed" that masked failures silently. - .vimrc, install.sh, QUICKSTART.md, README.md: carry forward the full v1.2 rewrite (checkbox module selection, solarized palette, LSP stack) that accumulated in the previous session. Tested: macOS (27 plugins, exit 0) and Arch Linux SSH (26 plugins, exit 0). shellcheck: zero warnings.
This commit is contained in:
parent
716e7e5808
commit
0b3f631e98
4 changed files with 1363 additions and 1887 deletions
230
QUICKSTART.md
230
QUICKSTART.md
|
|
@ -1,63 +1,47 @@
|
|||
# Quick Start
|
||||
|
||||
Five minutes from zero to a working Vim engineering environment.
|
||||
|
||||
> **New to Vim?** Read Step 0 first — it takes 2 minutes and prevents the most
|
||||
> common beginner frustration. Already know how Vim modes work? [Skip to Step 1](#step-1-install).
|
||||
Five minutes from zero to a working Vim environment.
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Vim Basics
|
||||
## Step 0: Vim Basics (2 minutes)
|
||||
|
||||
> **When confused, press `Esc` until things feel normal again — then keep reading.**
|
||||
> **When confused, press `Esc` until things feel normal again.**
|
||||
|
||||
Vim is **modal**: the keyboard behaves differently depending on which mode you are in.
|
||||
Most people get stuck because they try to type text while in Normal mode.
|
||||
Vim is **modal** — the keyboard behaves differently depending on which mode you are in.
|
||||
|
||||
### The Three Modes
|
||||
| Mode | Purpose | Enter | Leave |
|
||||
|------|---------|-------|-------|
|
||||
| **Normal** | Navigate and run commands | default on startup | — |
|
||||
| **Insert** | Type text | `i` before / `a` after / `o` new line | `Esc` or `jk` |
|
||||
| **Visual** | Select text | `v` char / `V` line | `Esc` |
|
||||
|
||||
| Mode | Purpose | How to enter | How to leave |
|
||||
|------|---------|--------------|--------------|
|
||||
| **Normal** | Navigate and run commands | Startup default | — (you're already here) |
|
||||
| **Insert** | Type text | `i` before cursor, `a` after, `o` new line below | `Esc` or `jk` |
|
||||
| **Visual** | Select text | `v` char-by-char, `V` whole lines | `Esc` |
|
||||
|
||||
### 4 Survival Commands
|
||||
|
||||
Learn these before anything else. They will get you out of every stuck situation.
|
||||
### 4 commands that get you out of any jam
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| `Esc` or `jk` | Exit insert/visual mode — return to Normal |
|
||||
| `:q!` then `Enter` | Force quit without saving (emergency exit) |
|
||||
| `Esc` or `jk` | Exit insert / visual mode → Normal |
|
||||
| `:q!` then `Enter` | Force quit without saving |
|
||||
| `,x` | Save and quit |
|
||||
| `,w` or `Ctrl+s` | Save the file |
|
||||
| `,w` or `Ctrl+s` | Save |
|
||||
|
||||
Once in Normal mode, press `,?` to open a cheat sheet covering everything else.
|
||||
Once in Normal mode, press `,?` to open the cheat sheet.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Install
|
||||
|
||||
**One command — works on macOS and Linux:**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||
```
|
||||
|
||||
This clones the repo to `~/.vim` and runs the full installer. Interactive prompts
|
||||
let you choose which optional tools to install (ripgrep, Node.js, Python tools, etc.).
|
||||
|
||||
The installer automatically handles missing dependencies — it will offer to install
|
||||
`git`, Homebrew (macOS), or Node.js via nvm if they are not found.
|
||||
|
||||
**Traditional install:**
|
||||
Traditional:
|
||||
```bash
|
||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||
cd ~/.vim && ./install.sh
|
||||
```
|
||||
|
||||
**Non-interactive (CI / server / scripting):**
|
||||
Non-interactive / CI:
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
||||
```
|
||||
|
|
@ -67,37 +51,14 @@ curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | b
|
|||
## Step 2: Open Vim
|
||||
|
||||
```bash
|
||||
vim
|
||||
```
|
||||
|
||||
The startup screen (vim-startify) shows recent files and sessions.
|
||||
Press `Ctrl+p` to find a file, or just type a path.
|
||||
|
||||
To open a project:
|
||||
```bash
|
||||
vim . # NERDTree on left, Startify on right
|
||||
vim myfile # opens file directly
|
||||
vim # startup dashboard (recent files + sessions)
|
||||
vim . # startup dashboard, current directory listed
|
||||
vim myfile # edit a specific file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Set Up LSP (pick your path)
|
||||
|
||||
### Path A: With Node.js (CoC — full LSP)
|
||||
|
||||
```bash
|
||||
node --version # must be >= 14.14
|
||||
```
|
||||
|
||||
Inside Vim, install language servers for your stack:
|
||||
|
||||
```vim
|
||||
:CocInstall coc-pyright coc-tsserver coc-go coc-rust-analyzer
|
||||
```
|
||||
|
||||
Or let `install.sh` do it — it asks during setup.
|
||||
|
||||
### Path B: Without Node.js (vim-lsp — no dependencies)
|
||||
## Step 3: Set Up LSP
|
||||
|
||||
Open a source file, then run:
|
||||
|
||||
|
|
@ -105,25 +66,38 @@ Open a source file, then run:
|
|||
:LspInstallServer
|
||||
```
|
||||
|
||||
This auto-detects and installs the correct language server for the current filetype.
|
||||
This auto-detects the filetype and installs the correct language server.
|
||||
No Node.js required — vim-lsp runs on pure VimScript.
|
||||
|
||||
Check status:
|
||||
```vim
|
||||
:LspStatus
|
||||
```
|
||||
|
||||
**Markdown LSP** (`marksman`) needs a standalone binary:
|
||||
```bash
|
||||
brew install marksman # macOS
|
||||
sudo pacman -S marksman # Arch
|
||||
# install.sh handles this automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The 12 Keys That Matter
|
||||
## The Keys That Matter
|
||||
|
||||
```
|
||||
, (pause 500ms) Show all keybindings (which-key)
|
||||
,? Open cheat sheet inside Vim
|
||||
Esc / jk Exit insert mode → Normal (memorize this)
|
||||
Ctrl+s Save (works in normal and insert mode)
|
||||
,? Open cheat sheet (all bindings in one place)
|
||||
Esc / jk Exit insert mode → Normal
|
||||
Ctrl+s Save
|
||||
Ctrl+p Fuzzy find file
|
||||
Ctrl+n Toggle file tree
|
||||
,e File browser (netrw)
|
||||
gd Go to definition
|
||||
K Show documentation
|
||||
[g / ]g Prev / next LSP diagnostic
|
||||
,rn Rename symbol
|
||||
,rG Search word under cursor (ripgrep)
|
||||
,gs Git status
|
||||
,mp Markdown live preview in browser
|
||||
,w / ,x Save / Save+quit
|
||||
```
|
||||
|
||||
|
|
@ -138,8 +112,8 @@ K Show documentation
|
|||
| `gd` | Go to definition |
|
||||
| `gy` | Go to type definition |
|
||||
| `gi` | Go to implementation |
|
||||
| `gr` | List all references |
|
||||
| `K` | Show docs for symbol under cursor |
|
||||
| `gr` | List references |
|
||||
| `K` | Docs for symbol under cursor |
|
||||
| `Ctrl+o` | Jump back |
|
||||
| `Ctrl+i` | Jump forward |
|
||||
|
||||
|
|
@ -152,23 +126,35 @@ K Show documentation
|
|||
| `gc` | Toggle comment (visual mode too) |
|
||||
| `cs"'` | Change surrounding `"` to `'` |
|
||||
| `ds(` | Delete surrounding `(` |
|
||||
| `s`+2ch | EasyMotion: jump anywhere |
|
||||
| `s` + 2 chars | EasyMotion: jump anywhere |
|
||||
|
||||
### Manage Errors
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `]g` | Jump to next diagnostic |
|
||||
| `]g` | Jump to next LSP diagnostic |
|
||||
| `[g` | Jump to previous diagnostic |
|
||||
| `K` | Read the error message |
|
||||
| `,ca` | Apply code action / auto-fix |
|
||||
|
||||
### Markdown
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `,mp` | Open live preview in browser |
|
||||
| `,mt` | Table of contents |
|
||||
| `zr` / `zm` | Unfold / fold all headings |
|
||||
|
||||
Formatting in the buffer is live: `**bold**` renders as bold,
|
||||
headings hide their `#` markers. Raw syntax reappears when
|
||||
the cursor enters that line.
|
||||
|
||||
### Git Workflow
|
||||
|
||||
```
|
||||
,gs git status (stage with 's', commit with 'cc')
|
||||
,gd diff current file
|
||||
,gb blame current file
|
||||
,gb blame
|
||||
,gc commit
|
||||
,gp push
|
||||
,gl pull
|
||||
|
|
@ -176,82 +162,18 @@ K Show documentation
|
|||
|
||||
---
|
||||
|
||||
## Language Workflows
|
||||
|
||||
### Python
|
||||
|
||||
```bash
|
||||
# tools installed by install.sh; or manually:
|
||||
pip install black flake8 pylint isort
|
||||
```
|
||||
|
||||
Auto-formats with `black` + `isort` on save. Lint errors show as `X`/`!` in the sign column.
|
||||
|
||||
### JavaScript / TypeScript
|
||||
|
||||
```bash
|
||||
npm install -g prettier eslint typescript
|
||||
```
|
||||
|
||||
Auto-formats with `prettier` on save.
|
||||
|
||||
### Go
|
||||
|
||||
```bash
|
||||
# tools installed by install.sh; or manually:
|
||||
go install golang.org/x/tools/gopls@latest
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
```
|
||||
|
||||
`gofmt` + `goimports` run on save automatically.
|
||||
|
||||
### Markdown
|
||||
|
||||
Install `marksman` for LSP support (completions, link checking):
|
||||
|
||||
```bash
|
||||
brew install marksman # macOS
|
||||
sudo pacman -S marksman # Arch
|
||||
# or: ./install.sh (handles it automatically)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Customize
|
||||
|
||||
Edit config live:
|
||||
```vim
|
||||
,ev " opens ~/.vimrc in Vim
|
||||
,sv " reloads config without restarting
|
||||
```
|
||||
|
||||
Per-project settings: create `.vimrc` in your project root.
|
||||
```vim
|
||||
" project/.vimrc
|
||||
set shiftwidth=2
|
||||
let g:ale_python_black_options = '--line-length=100'
|
||||
```
|
||||
|
||||
Change color scheme in `~/.vimrc`:
|
||||
```vim
|
||||
colorscheme dracula " or: gruvbox, solarized, onedark
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
```
|
||||
BASICS (learn these first)
|
||||
BASICS
|
||||
Esc / jk Exit insert mode → Normal
|
||||
Ctrl+s Save (normal + insert mode)
|
||||
:q! + Enter Emergency quit without saving
|
||||
Ctrl+s Save
|
||||
:q! + Enter Emergency quit
|
||||
,? Open cheat sheet
|
||||
|
||||
FILES
|
||||
Ctrl+n File tree toggle
|
||||
Ctrl+p Fuzzy find file (git-aware)
|
||||
,e File browser (netrw)
|
||||
,b Search open buffers
|
||||
,rg Search file contents (ripgrep)
|
||||
,rG Ripgrep word under cursor
|
||||
|
|
@ -260,13 +182,16 @@ FILES
|
|||
,, Switch to last file
|
||||
|
||||
CODE
|
||||
gd Go to definition
|
||||
gd Definition | gy Type def | gi Impl | gr References
|
||||
K Show documentation
|
||||
[g / ]g Prev/next LSP diagnostic
|
||||
[e / ]e Prev/next ALE error
|
||||
[g / ]g Prev / next LSP diagnostic
|
||||
[e / ]e Prev / next ALE error
|
||||
,rn Rename symbol
|
||||
,ca Code action / auto-fix
|
||||
,f Format selection | ,F Format whole file
|
||||
,ca Code action
|
||||
,f Format buffer / selection
|
||||
|
||||
MARKDOWN
|
||||
,mp Live preview | ,mt Table of contents
|
||||
|
||||
GIT
|
||||
,gs Status | ,gd Diff | ,gb Blame
|
||||
|
|
@ -275,19 +200,14 @@ GIT
|
|||
WINDOWS / PANES
|
||||
Ctrl+h/j/k/l Move between Vim windows or tmux panes
|
||||
,h / ,l Prev / next buffer
|
||||
,tv Open terminal (vertical)
|
||||
,th Open terminal (horizontal)
|
||||
Esc Exit terminal mode
|
||||
,u Undo tree | ,tt Tag browser
|
||||
,tv / ,th Terminal (vertical / horizontal)
|
||||
Esc Esc Exit terminal mode
|
||||
,u Undo tree
|
||||
|
||||
SEARCH & REPLACE
|
||||
/text Search forward | ?text backward
|
||||
// Search for visually selected text
|
||||
SEARCH
|
||||
/text Forward | ?text Backward | n next | N prev
|
||||
// Search visually selected text
|
||||
,* Replace word under cursor (file-wide)
|
||||
|
||||
CLIPBOARD
|
||||
,y / ,Y Yank / yank line to system clipboard
|
||||
,p / ,P Paste from system clipboard (after / before)
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
554
README.md
554
README.md
|
|
@ -1,7 +1,7 @@
|
|||
# chopsticks
|
||||
|
||||
> A batteries-included Vim configuration for full-stack engineering.
|
||||
> Tiered LSP · 14 languages · TTY-aware · Zero icon fonts · One-command install.
|
||||
> Flowing vim for any machine — SSH servers included.
|
||||
> Solarized · vim-lsp (no Node.js) · Markdown-first · One-command install.
|
||||
|
||||
[](LICENSE)
|
||||
[](https://www.vim.org/)
|
||||
|
|
@ -9,18 +9,11 @@
|
|||
[](https://github.com/m1ngsama/chopsticks/releases)
|
||||
[](https://github.com/m1ngsama/chopsticks/commits/main)
|
||||
[](https://github.com/m1ngsama/chopsticks/stargazers)
|
||||
[](https://github.com/m1ngsama/chopsticks/issues)
|
||||
[](https://github.com/m1ngsama/chopsticks/pulls)
|
||||
[](#plugins)
|
||||
[](#language-support)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||
```
|
||||
|
||||
> **New to Vim?** Read [Step 0 in QUICKSTART.md](QUICKSTART.md#step-0-vim-basics) first —
|
||||
> a 2-minute intro to modes and the 4 commands that get you out of any jam.
|
||||
|
||||
---
|
||||
|
||||
## Contents
|
||||
|
|
@ -28,14 +21,13 @@ curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | b
|
|||
- [Design Principles](#design-principles)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [LSP: Tiered Backend](#lsp-tiered-backend)
|
||||
- [LSP](#lsp)
|
||||
- [Key Mappings](#key-mappings)
|
||||
- [Markdown](#markdown)
|
||||
- [Features](#features)
|
||||
- [Language Support](#language-support)
|
||||
- [Plugins](#plugins)
|
||||
- [Customization](#customization)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -43,51 +35,44 @@ curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | b
|
|||
|
||||
| Principle | What it means |
|
||||
|-----------|--------------|
|
||||
| **KISS** | No icon fonts, no Nerd Font glyphs — plain ASCII everywhere |
|
||||
| **Tiered LSP** | CoC (full) when Node.js is available; vim-lsp (pure VimScript) otherwise |
|
||||
| **TTY-aware** | Automatically detects SSH/console environments and degrades gracefully |
|
||||
| **Engineering-first** | Git workflow, persistent sessions, project-local config, large-file safety |
|
||||
| **Batteries included** | `install.sh` handles vim-plug, plugins, system tools, and language servers |
|
||||
| **Flowing writing** | Every plugin earns its place by reducing interruptions to thought |
|
||||
| **No Node.js** | vim-lsp runs on pure VimScript — works on any machine, including SSH servers |
|
||||
| **Solarized** | One palette, everywhere — vim statusline matches tmux bar exactly |
|
||||
| **TTY-aware** | SSH and console environments degrade gracefully without breaking |
|
||||
| **KISS** | No icon fonts, no Nerd Font glyphs — plain ASCII throughout |
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
| Tool | Minimum | Role |
|
||||
|------|---------|------|
|
||||
| Vim | **8.0+** | Required — `install.sh` installs it if missing |
|
||||
| git | any | Required — `install.sh` installs it if missing |
|
||||
| curl | any | Required — `install.sh` installs it if missing |
|
||||
| Node.js | 14.14+ | Optional — enables CoC LSP; `install.sh` offers nvm install |
|
||||
| ripgrep | any | Optional — enables `,rg` / `,rG` project search |
|
||||
| fzf | any | Optional — enables `Ctrl+p` fuzzy finder |
|
||||
| ctags | any | Optional — enables `,tt` tag browser |
|
||||
| tmux | 1.8+ | Optional — enables seamless pane navigation |
|
||||
| Tool | Role |
|
||||
|------|------|
|
||||
| Vim 8.0+ | Required — `install.sh` installs it if missing |
|
||||
| git | Required |
|
||||
| curl | Required |
|
||||
| ripgrep | Recommended — enables `,rg` project search |
|
||||
| fzf | Recommended — enables `Ctrl+p` fuzzy finder |
|
||||
| Node.js | Optional — enables npm formatters (prettier, eslint) |
|
||||
|
||||
`install.sh` detects your environment and installs missing dependencies automatically.
|
||||
On macOS it will offer to install Homebrew if not present. On any platform it will
|
||||
offer to install Node.js via nvm if missing.
|
||||
`install.sh` detects your environment and installs missing dependencies.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### One command (recommended)
|
||||
### One command
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||
```
|
||||
|
||||
This bootstrap script clones the repo to `~/.vim`, then runs the full installer.
|
||||
It works correctly even when piped from curl — interactive prompts use `/dev/tty`.
|
||||
|
||||
For non-interactive or CI environments:
|
||||
Non-interactive / CI:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
||||
```
|
||||
|
||||
### Traditional (git clone)
|
||||
### Git clone
|
||||
|
||||
```bash
|
||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||
|
|
@ -96,250 +81,196 @@ cd ~/.vim && ./install.sh
|
|||
|
||||
### What the installer does
|
||||
|
||||
1. **Preflight** — checks network, detects OS and package manager, verifies or installs `curl`, `git`, and `vim`
|
||||
2. **sudo** — authenticates once upfront; gracefully skips system packages when unavailable
|
||||
3. **macOS** — offers to install Homebrew if `brew` is not found
|
||||
4. **Node.js** — offers to install via nvm if not found (falls back to vim-lsp if declined)
|
||||
5. **Python** — offers to install Python 3 if missing; bootstraps pip3 if only python3 is present
|
||||
6. **Symlinks** — backs up any existing `~/.vimrc` with a timestamp, then symlinks `~/.vimrc → ~/.vim/.vimrc`
|
||||
7. **Plugins** — installs vim-plug and runs `:PlugInstall` (with a progress notice during the black-screen period)
|
||||
8. **System tools** — ripgrep, fzf, ctags, shellcheck, hadolint, marksman (verified downloads)
|
||||
9. **Language tools** — npm formatters, pip formatters/linters, Go tools
|
||||
10. **CoC extensions** — all language servers in one step
|
||||
11. **tmux** — optionally appends vim-tmux-navigator bindings to `~/.tmux.conf`
|
||||
1. Detects OS and package manager
|
||||
2. Verifies or installs `curl`, `git`, `vim`
|
||||
3. Backs up existing `~/.vimrc`, then symlinks `~/.vimrc → ~/.vim/.vimrc`
|
||||
4. Installs vim-plug and runs `:PlugInstall`
|
||||
5. Offers to install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)
|
||||
6. Offers to install Node.js via nvm (for npm formatters — optional)
|
||||
7. Offers to install npm formatters (prettier, eslint, etc.)
|
||||
8. Offers to install Python formatters/linters (black, isort, flake8, etc.)
|
||||
9. Offers to install Go tools (gopls, goimports, staticcheck)
|
||||
10. Offers to append vim-tmux-navigator bindings to `~/.tmux.conf`
|
||||
|
||||
**Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch Linux (pacman), Fedora (dnf).
|
||||
|
||||
### Manual
|
||||
|
||||
```bash
|
||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||
ln -sf ~/.vim/.vimrc ~/.vimrc
|
||||
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
|
||||
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
|
||||
vim +PlugInstall +qall </dev/null
|
||||
```
|
||||
**Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf).
|
||||
|
||||
---
|
||||
|
||||
## LSP: Tiered Backend
|
||||
## LSP
|
||||
|
||||
Code intelligence is provided by one of two backends, chosen automatically at startup:
|
||||
Code intelligence is provided by **vim-lsp** — a pure VimScript LSP client with no
|
||||
Node.js dependency. It works on any machine, including servers accessed via SSH.
|
||||
|
||||
| Condition | Backend | Capabilities |
|
||||
|-----------|---------|-------------|
|
||||
| Vim 8.0.1453+ **and** Node.js 14.14+ | **CoC** | Full LSP, snippets, extension ecosystem |
|
||||
| Vim 8.0+ (no Node.js) | **vim-lsp** | LSP via language server binaries, asyncomplete |
|
||||
| Any Vim | **ALE** | Async linting + auto-fix (always active, both backends) |
|
||||
|
||||
Both CoC and vim-lsp expose the same key mappings so switching backends is transparent.
|
||||
|
||||
### With Node.js (CoC)
|
||||
|
||||
Install language server extensions from inside Vim — or let `install.sh` do it automatically:
|
||||
Install a language server for the current file:
|
||||
|
||||
```vim
|
||||
:CocInstall coc-pyright " Python
|
||||
:CocInstall coc-tsserver " JavaScript / TypeScript
|
||||
:CocInstall coc-go " Go
|
||||
:CocInstall coc-rust-analyzer " Rust
|
||||
:CocInstall coc-json coc-yaml " JSON, YAML
|
||||
:CocInstall coc-html coc-css " HTML, CSS/SCSS
|
||||
:CocInstall coc-sh " Shell
|
||||
:CocInstall coc-sql " SQL
|
||||
:LspInstallServer " auto-detects filetype and installs the correct server
|
||||
:LspStatus " check server status
|
||||
```
|
||||
|
||||
**Markdown LSP** uses `marksman` as an external binary (not a CoC extension):
|
||||
Supported languages and their servers:
|
||||
|
||||
| Language | Server |
|
||||
|----------|--------|
|
||||
| Python | pylsp / pyright |
|
||||
| JavaScript / TypeScript | typescript-language-server |
|
||||
| Go | gopls |
|
||||
| Rust | rust-analyzer |
|
||||
| C / C++ | clangd |
|
||||
| Shell | bash-language-server |
|
||||
| HTML | vscode-html-language-server |
|
||||
| CSS / SCSS | vscode-css-language-server |
|
||||
| JSON | vscode-json-language-server |
|
||||
| YAML | yaml-language-server |
|
||||
| Markdown | marksman |
|
||||
| SQL | sqls |
|
||||
|
||||
**Markdown LSP** requires `marksman` as a standalone binary:
|
||||
|
||||
```bash
|
||||
brew install marksman # macOS
|
||||
sudo pacman -S marksman # Arch
|
||||
# or: ./install.sh handles it automatically
|
||||
# or: install.sh handles it automatically
|
||||
```
|
||||
|
||||
### Without Node.js (vim-lsp)
|
||||
|
||||
Open a source file, then run:
|
||||
|
||||
```vim
|
||||
:LspInstallServer " detects filetype and installs the correct server
|
||||
:LspStatus " check server status
|
||||
```
|
||||
|
||||
Supported: Python, Go, Rust, TypeScript/JavaScript, Shell, HTML, CSS/SCSS, JSON, YAML, Markdown, SQL.
|
||||
|
||||
---
|
||||
|
||||
## Key Mappings
|
||||
|
||||
**Leader key:** `,` (comma)
|
||||
|
||||
Press `,` and wait 500 ms to see an interactive guide to all bindings (vim-which-key).
|
||||
Press `,?` to open the built-in cheat sheet at any time.
|
||||
|
||||
### Survival
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `jk` | Exit insert mode → Normal (ergonomic Escape) |
|
||||
| `Esc` | Exit insert / visual mode (standard) |
|
||||
| `Ctrl+s` | Save file (normal and insert mode) |
|
||||
| `,w` | Save file |
|
||||
| `,x` | Save and quit |
|
||||
| `,q` | Quit |
|
||||
| `,?` | Open cheat sheet |
|
||||
|
||||
> **`Ctrl+s` note:** some terminals freeze on `Ctrl+s` (XON/XOFF). Add `stty -ixon`
|
||||
> to your `~/.bashrc` / `~/.zshrc` to disable this permanently.
|
||||
Press `,?` at any time to open the built-in cheat sheet.
|
||||
|
||||
### Files and Buffers
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `Ctrl+p` | Fuzzy file search — git-aware (FZF) |
|
||||
| `Ctrl+n` | Toggle file tree (NERDTree) |
|
||||
| `,n` | Reveal current file in NERDTree |
|
||||
| `,e` | Open netrw file browser |
|
||||
| `,E` | Open netrw in vertical split |
|
||||
| `,b` | Search open buffers (FZF) |
|
||||
| `,rg` | Project-wide search (ripgrep + FZF) |
|
||||
| `,rG` | Ripgrep for word under cursor (literal match) |
|
||||
| `,rt` | Search tags (FZF) |
|
||||
| `,gF` | Search git-tracked files (FZF) |
|
||||
| `,l` | Next buffer |
|
||||
| `,h` | Previous buffer |
|
||||
| `,bd` | Close current buffer (preserves window layout) |
|
||||
| `,rG` | Ripgrep for word under cursor |
|
||||
| `,,` | Switch to last file |
|
||||
| `,l` / `,h` | Next / previous buffer |
|
||||
| `,bd` | Close current buffer (preserves window layout) |
|
||||
|
||||
### Windows, Tabs, and tmux
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `Ctrl+h/j/k/l` | Navigate between Vim splits **and** tmux panes |
|
||||
| `,=` | Increase window height |
|
||||
| `,-` | Decrease window height |
|
||||
| `,+` | Increase window width |
|
||||
| `,_` | Decrease window width |
|
||||
| `,tn` | New tab |
|
||||
| `,tc` | Close tab |
|
||||
| `,tl` | Toggle to last tab |
|
||||
| `,tv` | Open terminal (vertical split) |
|
||||
| `,th` | Open terminal (horizontal split) |
|
||||
| `Esc Esc` | Exit terminal mode |
|
||||
|
||||
### Code Intelligence (CoC / vim-lsp)
|
||||
### Code Intelligence (vim-lsp)
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `gd` | Go to definition |
|
||||
| `gy` | Go to type definition |
|
||||
| `gi` | Go to implementation |
|
||||
| `gr` | Show all references |
|
||||
| `gr` | Show references |
|
||||
| `K` | Hover documentation |
|
||||
| `[g` | Previous diagnostic |
|
||||
| `]g` | Next diagnostic |
|
||||
| `[g` / `]g` | Previous / next LSP diagnostic |
|
||||
| `[e` / `]e` | Previous / next ALE error |
|
||||
| `,rn` | Rename symbol |
|
||||
| `,f` | Format selection |
|
||||
| `,F` | Format whole file |
|
||||
| `,ca` | Code action (cursor position) |
|
||||
| `,f` | Format buffer / selection |
|
||||
| `,ca` | Code action |
|
||||
| `,o` | File outline (symbols) |
|
||||
| `,ws` | Workspace symbols |
|
||||
| `,cD` | Diagnostics list |
|
||||
| `,qf` | Quick-fix current line (CoC) |
|
||||
| `Tab` | Next completion item |
|
||||
| `Shift+Tab` | Previous completion item |
|
||||
| `Tab` / `Shift+Tab` | Navigate completion popup |
|
||||
| `Enter` | Confirm completion |
|
||||
|
||||
Text objects (CoC): `if`/`af` (function inner/around), `ic`/`ac` (class inner/around).
|
||||
|
||||
### Linting (ALE — always active)
|
||||
### Markdown
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `[e` | Previous error / warning |
|
||||
| `]e` | Next error / warning |
|
||||
| `,aD` | Show error detail |
|
||||
| `,ad` | Full diagnostics list |
|
||||
|
||||
Signs in the gutter: `X` = error, `!` = warning.
|
||||
| `,mp` | Open live preview in browser (previm) |
|
||||
| `,mt` | Table of contents |
|
||||
| `zr` / `zm` | Unfold / fold all headings |
|
||||
|
||||
### Git (vim-fugitive)
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `,gs` | Git status (stage with `s`, commit with `cc`) |
|
||||
| `,gs` | Git status |
|
||||
| `,gc` | Git commit |
|
||||
| `,gp` | Git push |
|
||||
| `,gl` | Git pull |
|
||||
| `,gd` | Git diff |
|
||||
| `,gb` | Git blame |
|
||||
|
||||
### Search and Replace
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `n` / `N` | Next / previous match (cursor centered) |
|
||||
| `//` | Search for visually selected text |
|
||||
| `,*` | Search and replace word under cursor (file-wide) |
|
||||
| `,rG` | Ripgrep word under cursor across project |
|
||||
| `,<CR>` | Clear search highlight |
|
||||
|
||||
### Clipboard
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `,y` | Yank to system clipboard |
|
||||
| `,Y` | Yank line to system clipboard |
|
||||
| `,p` | Paste from system clipboard (after cursor) |
|
||||
| `,P` | Paste from system clipboard (before cursor) |
|
||||
|
||||
### Editing and Navigation
|
||||
### Editing
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `s` + 2 chars | EasyMotion — jump anywhere on screen |
|
||||
| `gc` | Toggle comment (visual mode too) |
|
||||
| `Space` | Toggle code fold |
|
||||
| `Y` | Yank to end of line (consistent with `D`, `C`) |
|
||||
| `Ctrl+d/u` | Half-page scroll (cursor stays centered) |
|
||||
| `>` / `<` | Indent / dedent (keeps visual selection) |
|
||||
| `Alt+j/k` | Move current line down / up |
|
||||
| `0` | Jump to first non-blank character |
|
||||
| `[q` / `]q` | Previous / next quickfix entry (vim-unimpaired) |
|
||||
| `,u` | Toggle undo tree (visual branch history) |
|
||||
| `,tt` | Toggle tagbar (code structure) |
|
||||
| `F2` | Toggle paste mode |
|
||||
| `F3` | Toggle absolute line numbers |
|
||||
| `F4` | Toggle relative line numbers |
|
||||
| `Y` | Yank to end of line |
|
||||
| `Ctrl+d` / `Ctrl+u` | Half-page scroll, cursor centred |
|
||||
| `Alt+j` / `Alt+k` | Move line down / up |
|
||||
| `,u` | Undo tree (visual branch history) |
|
||||
|
||||
### Config and Utilities
|
||||
### Survival
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `,ev` | Edit `~/.vimrc` |
|
||||
| `,sv` | Reload `~/.vimrc` |
|
||||
| `,wa` | Save all open buffers |
|
||||
| `,wd` | Change working directory to current file's location |
|
||||
| `,cp` | Copy absolute file path to clipboard |
|
||||
| `,cf` | Copy filename to clipboard |
|
||||
| `,qo` / `,qc` | Open / close quickfix list |
|
||||
| `jk` | Exit insert mode |
|
||||
| `Esc` | Exit insert / visual mode |
|
||||
| `Ctrl+s` | Save |
|
||||
| `,w` | Save |
|
||||
| `,x` | Save and quit |
|
||||
| `,q` | Quit |
|
||||
| `,?` | Open cheat sheet |
|
||||
|
||||
### Windows, Tabs, tmux
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `Ctrl+h/j/k/l` | Navigate Vim splits **and** tmux panes |
|
||||
| `,tv` / `,th` | Open terminal (vertical / horizontal split) |
|
||||
| `Esc Esc` | Exit terminal mode |
|
||||
| `,tn` / `,tc` | New tab / close tab |
|
||||
| `,tl` | Toggle to last tab |
|
||||
|
||||
---
|
||||
|
||||
## Markdown
|
||||
|
||||
chopsticks treats Markdown as a first-class language.
|
||||
|
||||
### In-buffer rendering (concealment)
|
||||
|
||||
`vim-markdown` hides syntax markers and renders formatting inline:
|
||||
- `**bold**` displays as bold text
|
||||
- `# Heading` hides the `#` characters
|
||||
- Tables align automatically
|
||||
|
||||
The raw syntax reappears when the cursor enters that line.
|
||||
|
||||
### Live browser preview (previm)
|
||||
|
||||
```vim
|
||||
,mp " open rendered preview in browser — updates on every save
|
||||
```
|
||||
|
||||
No Node.js required. Uses `open` (macOS) or `xdg-open` (Linux).
|
||||
|
||||
### Table of contents
|
||||
|
||||
```vim
|
||||
,mt " open TOC in a quickfix window — press Enter to jump to heading
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Startup Dashboard
|
||||
### Statusline
|
||||
|
||||
Running `vim` (no arguments) opens a full-screen Startify dashboard showing recent
|
||||
files, sessions, and bookmarks. Running `vim .` opens NERDTree on the left with
|
||||
the dashboard on the right.
|
||||
A native, hand-written statusline using the Solarized palette:
|
||||
|
||||
### Keybinding Guide
|
||||
```
|
||||
N ~/.vimrc [+] main [vim] 42:7 68%
|
||||
```
|
||||
|
||||
Press `,` and pause for 500 ms. A popup (vim-which-key) lists all leader bindings
|
||||
organized into groups. No need to memorize everything upfront.
|
||||
|
||||
### Built-in Cheat Sheet
|
||||
|
||||
Press `,?` to open an inline reference covering modes, survival commands, search,
|
||||
code intelligence, git, and clipboard — without leaving Vim.
|
||||
- Mode block changes colour by mode (Normal=yellow, Insert=blue, Visual=magenta, Replace=red)
|
||||
- Git branch via vim-fugitive
|
||||
- Background matches tmux status bar for a seamless bottom band
|
||||
|
||||
### Session Management
|
||||
|
||||
|
|
@ -348,29 +279,23 @@ code intelligence, git, and clipboard — without leaving Vim.
|
|||
:Obsess! " stop tracking
|
||||
```
|
||||
|
||||
Sessions are stored in `~/.vim/sessions/` and automatically restored by vim-prosession
|
||||
the next time you open Vim in the same directory.
|
||||
Sessions auto-restore when you open Vim in the same directory.
|
||||
|
||||
### Project-Local Config
|
||||
|
||||
Drop a `.vimrc` in any project root to override settings for that project:
|
||||
Drop a `.vimrc` in any project root to override settings:
|
||||
|
||||
```vim
|
||||
" project/.vimrc
|
||||
" my-project/.vimrc
|
||||
set shiftwidth=2
|
||||
let g:ale_python_black_options = '--line-length=100'
|
||||
```
|
||||
|
||||
Loaded automatically via `set exrc`. Restricted to safe options via `set secure`.
|
||||
|
||||
### tmux Integration
|
||||
|
||||
`Ctrl+h/j/k/l` navigates seamlessly between Vim splits and tmux panes — no prefix
|
||||
key, no mode switch.
|
||||
`Ctrl+h/j/k/l` navigates seamlessly between Vim splits and tmux panes.
|
||||
|
||||
**Vim side:** handled by vim-tmux-navigator (installed automatically).
|
||||
|
||||
**tmux side:** add to `~/.tmux.conf` (or let `install.sh` append it):
|
||||
Add to `~/.tmux.conf` (or let `install.sh` append it):
|
||||
|
||||
```tmux
|
||||
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\S+\/)?g?(view|n?vim?x?)(diff)?$'"
|
||||
|
|
@ -380,123 +305,79 @@ bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
|
|||
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
|
||||
```
|
||||
|
||||
Then reload: `tmux source-file ~/.tmux.conf`
|
||||
### TTY / SSH Support
|
||||
|
||||
> **Note:** the `C-l` binding replaces the terminal's screen-clear shortcut inside
|
||||
> tmux. To restore it, add `bind C-l send-keys 'C-l'` — then use `prefix + C-l`.
|
||||
Detected automatically when `$TERM` is `linux` or `screen`. In TTY mode:
|
||||
|
||||
- True colour and cursorline disabled
|
||||
- FZF preview windows disabled
|
||||
- IndentLine guides disabled
|
||||
- Simplified statusline (no colour)
|
||||
- Syntax column limit reduced to 120 characters
|
||||
|
||||
### Large File Handling
|
||||
|
||||
Files over 10 MB automatically disable syntax highlighting, undo history, and
|
||||
linting to prevent Vim from stalling.
|
||||
|
||||
### TTY / Console Support
|
||||
|
||||
Detected automatically when `$TERM` is `linux` or `screen`. In TTY mode:
|
||||
|
||||
- True color and cursorline disabled
|
||||
- Powerline separators replaced with plain ASCII
|
||||
- FZF preview windows disabled
|
||||
- IndentLine guides disabled
|
||||
- Syntax column limit reduced to 120 characters
|
||||
- Simpler built-in status line used instead of airline
|
||||
|
||||
---
|
||||
|
||||
## Language Support
|
||||
|
||||
| Language | Indent | Formatter | Linter | LSP |
|
||||
|----------|--------|-----------|--------|-----|
|
||||
| Python | 4 sp | black, isort | flake8, pylint | coc-pyright |
|
||||
| JavaScript | 2 sp | prettier | eslint | coc-tsserver |
|
||||
| TypeScript | 2 sp | prettier | eslint, tsserver | coc-tsserver |
|
||||
| Go | tab | gofmt, goimports | staticcheck | coc-go |
|
||||
| Rust | 4 sp | rustfmt | cargo | coc-rust-analyzer |
|
||||
| Shell | 2 sp | — | shellcheck | coc-sh |
|
||||
| YAML | 2 sp | prettier | yamllint | coc-yaml |
|
||||
| HTML | 2 sp | prettier | — | coc-html |
|
||||
| CSS / SCSS | 2 sp | prettier | stylelint | coc-css |
|
||||
| Less | 2 sp | prettier | — | — |
|
||||
| JSON | 2 sp | prettier | — | coc-json |
|
||||
| Markdown | 2 sp | prettier | markdownlint | marksman |
|
||||
| SQL | 4 sp | sqlfluff | sqlfluff | — |
|
||||
| Dockerfile | 2 sp | — | hadolint | — |
|
||||
|
||||
`install.sh` installs all formatters and linters automatically.
|
||||
ALE runs them asynchronously; format-on-save is active for all supported languages.
|
||||
linting to prevent stalling.
|
||||
|
||||
---
|
||||
|
||||
## Plugins
|
||||
|
||||
### Navigation
|
||||
- **NERDTree** — file tree explorer
|
||||
- **fzf + fzf.vim** — fuzzy finder for files, buffers, tags, and ripgrep
|
||||
- **fzf + fzf.vim** — fuzzy finder for files, buffers, tags, ripgrep
|
||||
|
||||
### Git
|
||||
- **vim-fugitive** — full Git integration inside Vim
|
||||
- **vim-fugitive** — full Git integration
|
||||
- **vim-gitgutter** — diff signs in the sign column
|
||||
|
||||
### LSP and Completion
|
||||
- **coc.nvim** — full LSP + completion via Node.js (recommended)
|
||||
- **vim-lsp** — pure VimScript LSP client (Node.js-free fallback)
|
||||
- **vim-lsp-settings** — auto-configures language servers for vim-lsp
|
||||
- **asyncomplete.vim** — async completion engine (vim-lsp mode)
|
||||
- **vim-lsp** — pure VimScript LSP client
|
||||
- **vim-lsp-settings** — auto-configures language servers
|
||||
- **asyncomplete.vim** — async completion engine
|
||||
- **asyncomplete-lsp.vim** — LSP completion source
|
||||
|
||||
### Linting
|
||||
- **ALE** — asynchronous lint engine, always active regardless of LSP backend
|
||||
### Linting and Formatting
|
||||
- **ALE** — async linting and format-on-save
|
||||
|
||||
### UI
|
||||
- **vim-airline** — status line and tabline
|
||||
- **vim-startify** — startup dashboard with session management
|
||||
- **vim-which-key** — keybinding hint popup on leader pause
|
||||
- **indentLine** — indent guide lines (non-TTY only)
|
||||
- **undotree** — visual undo branch history
|
||||
- **tagbar** — code structure sidebar via ctags
|
||||
### Markdown
|
||||
- **vim-markdown** — folding, concealment, table alignment
|
||||
- **previm** — live browser preview
|
||||
|
||||
### Language Syntax
|
||||
- **vim-javascript** — enhanced JS syntax
|
||||
- **yats.vim** — TypeScript syntax
|
||||
- **vim-go** — Go syntax and tooling
|
||||
|
||||
### Editing
|
||||
- **vim-surround** — change surrounding quotes, brackets, and tags
|
||||
- **vim-surround** — change/delete/add surroundings
|
||||
- **vim-commentary** — `gc` to toggle comments
|
||||
- **auto-pairs** — auto-close brackets and quotes
|
||||
- **vim-easymotion** — jump anywhere on screen with 2 keystrokes (`s`)
|
||||
- **vim-unimpaired** — bracket shortcut pairs (`[q`/`]q`, etc.)
|
||||
- **vim-repeat** — repeat plugin maps with `.`
|
||||
- **vim-unimpaired** — bracket shortcut pairs
|
||||
- **targets.vim** — additional text objects
|
||||
- **vim-snippets** — snippet library (used with CoC)
|
||||
- **vim-tmux-navigator** — seamless `Ctrl+h/j/k/l` across Vim and tmux
|
||||
- **auto-pairs** — auto-close brackets and quotes
|
||||
- **vim-easymotion** — `s` + 2 chars to jump anywhere
|
||||
|
||||
### Language Packs
|
||||
- **vim-polyglot** — syntax for 100+ languages
|
||||
- **vim-go** — Go syntax and tooling (LSP handled by coc-go)
|
||||
### UI
|
||||
- **vim-colors-solarized** — color scheme
|
||||
- **undotree** — visual undo branch history
|
||||
- **vim-startify** — startup dashboard and session list
|
||||
- **indentLine** — indent guides (non-TTY)
|
||||
|
||||
### Session
|
||||
- **vim-obsession** — continuous session saving
|
||||
- **vim-prosession** — project-level session management
|
||||
|
||||
### Color Schemes
|
||||
- **gruvbox** (default), **dracula**, **solarized**, **onedark**
|
||||
### Session and Navigation
|
||||
- **vim-obsession** — session tracking
|
||||
- **vim-tmux-navigator** — seamless Vim/tmux pane navigation
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
### Change the color scheme
|
||||
|
||||
In `~/.vimrc`, find and update the `colorscheme` line:
|
||||
|
||||
```vim
|
||||
colorscheme dracula " options: gruvbox, solarized, onedark
|
||||
```
|
||||
|
||||
True color is enabled automatically when `$COLORTERM=truecolor`. Falls back to
|
||||
256-color, then 16-color in TTY.
|
||||
|
||||
### Per-project overrides
|
||||
|
||||
Create `.vimrc` in your project root. Anything placed here overrides the global
|
||||
config for that directory:
|
||||
Create `.vimrc` in your project root:
|
||||
|
||||
```vim
|
||||
" my-project/.vimrc
|
||||
" project/.vimrc
|
||||
set shiftwidth=2
|
||||
let g:ale_python_black_options = '--line-length=120'
|
||||
```
|
||||
|
|
@ -512,100 +393,41 @@ Edit `~/.vimrc` directly (`,ev` opens it from inside Vim). Reload with `,sv`.
|
|||
**Plugins not loading**
|
||||
|
||||
```vim
|
||||
:PlugInstall " install any missing plugins
|
||||
:PlugInstall " install missing plugins
|
||||
:PlugUpdate " update all plugins
|
||||
```
|
||||
|
||||
**CoC not working**
|
||||
|
||||
```bash
|
||||
node --version # must be 14.14+
|
||||
```
|
||||
|
||||
Inside Vim: `:CocInfo` for diagnostics, `:CocInstall <extension>` to add a language server.
|
||||
|
||||
**vim-lsp server not starting**
|
||||
**LSP server not starting**
|
||||
|
||||
```vim
|
||||
:LspInstallServer " install the correct server for the current filetype
|
||||
:LspInstallServer " install server for current filetype
|
||||
:LspStatus " check server status
|
||||
```
|
||||
|
||||
**Markdown LSP not starting**
|
||||
**Markdown preview not opening**
|
||||
|
||||
`marksman` must be installed as a standalone binary (not a CoC extension):
|
||||
|
||||
```bash
|
||||
brew install marksman # macOS
|
||||
sudo pacman -S marksman # Arch
|
||||
# or: ./install.sh handles it automatically
|
||||
```
|
||||
`previm` uses `open` (macOS) or `xdg-open` (Linux). Make sure a browser is
|
||||
set as the default handler for HTML files.
|
||||
|
||||
**Colors look wrong**
|
||||
|
||||
```bash
|
||||
export TERM=xterm-256color # add to ~/.bashrc or ~/.zshrc
|
||||
export COLORTERM=truecolor # for true colour
|
||||
```
|
||||
|
||||
For true color: `export COLORTERM=truecolor`.
|
||||
|
||||
**ALE linters not found**
|
||||
|
||||
```bash
|
||||
which flake8 black prettier eslint # verify tools are on PATH
|
||||
```
|
||||
|
||||
If tools were installed with `pip install --user` or `npm install -g`, make sure
|
||||
the respective bin directories are on `$PATH`.
|
||||
|
||||
**`Ctrl+s` freezes the terminal**
|
||||
|
||||
Add `stty -ixon` to your `~/.bashrc`, `~/.zshrc`, or `~/.config/fish/config.fish`.
|
||||
This disables XON/XOFF flow control permanently.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and pull requests are welcome. Please follow these guidelines:
|
||||
|
||||
### Reporting a bug
|
||||
|
||||
1. Search [existing issues](https://github.com/m1ngsama/chopsticks/issues) before opening a new one.
|
||||
2. Include your Vim version (`vim --version`), OS, and a minimal reproduction.
|
||||
3. If the bug is plugin-specific, check whether it reproduces with a minimal config
|
||||
(`vim -u NONE`) or only with chopsticks loaded.
|
||||
|
||||
### Proposing a change
|
||||
|
||||
1. Open an issue first to discuss the change, especially for non-trivial additions.
|
||||
2. Keep the scope focused — one feature or fix per PR.
|
||||
3. Follow existing conventions: augroups for autocmds, TTY guards for visual features,
|
||||
conditional plugin loading where appropriate.
|
||||
4. Update `CHANGELOG.md` with a summary of the change.
|
||||
|
||||
### Scope
|
||||
|
||||
Chopsticks is an opinionated configuration. Changes should align with the design
|
||||
principles above — in particular, KISS (no icon fonts, minimal dependencies) and
|
||||
TTY-compatibility. Neovim-only features and Lua configs are out of scope.
|
||||
|
||||
---
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Inspired by [amix/vimrc](https://github.com/amix/vimrc).
|
||||
Built with [vim-plug](https://github.com/junegunn/vim-plug),
|
||||
[coc.nvim](https://github.com/neoclide/coc.nvim),
|
||||
[vim-lsp](https://github.com/prabirshrestha/vim-lsp),
|
||||
and the broader Vim plugin community.
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE) © m1ng
|
||||
|
|
|
|||
655
install.sh
655
install.sh
|
|
@ -16,6 +16,7 @@ YELLOW='\033[1;33m'
|
|||
RED='\033[0;31m'
|
||||
BOLD='\033[1m'
|
||||
CYAN='\033[0;36m'
|
||||
DIM='\033[2m'
|
||||
NC='\033[0m'
|
||||
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
|
|
@ -29,13 +30,11 @@ die() { echo -e "${RED}[FATAL]${NC} $1" >&2
|
|||
step() { echo -e "\n${BOLD}==> $1${NC}"; }
|
||||
info() { echo " $1"; }
|
||||
|
||||
# Track results for summary
|
||||
INSTALLED=()
|
||||
SKIPPED=()
|
||||
FAILED=()
|
||||
|
||||
# Ask yes/no; returns 0 for yes
|
||||
# Reads from /dev/tty so interactive prompts work even under: curl | bash
|
||||
# Ask yes/no; reads from /dev/tty so it works under: curl | bash
|
||||
ask() {
|
||||
[[ $AUTO_YES -eq 1 ]] && return 0
|
||||
if [[ -t 0 ]]; then
|
||||
|
|
@ -43,7 +42,6 @@ ask() {
|
|||
elif { true </dev/tty; } 2>/dev/null; then
|
||||
read -r -p "$1 [y/N] " reply </dev/tty
|
||||
else
|
||||
# No terminal available — default to no (safe)
|
||||
echo "$1 [y/N] N"
|
||||
return 1
|
||||
fi
|
||||
|
|
@ -52,26 +50,19 @@ ask() {
|
|||
|
||||
# ── Error trap ────────────────────────────────────────────────────────────────
|
||||
on_error() {
|
||||
local line="${BASH_LINENO[0]}"
|
||||
echo -e "\n${RED}[FATAL]${NC} Unexpected error at line $line." >&2
|
||||
echo -e "\n${RED}[FATAL]${NC} Unexpected error at line ${BASH_LINENO[0]}." >&2
|
||||
echo " To get a full debug log:" >&2
|
||||
echo " ./install.sh 2>&1 | tee /tmp/chopsticks-install.log" >&2
|
||||
echo " Report issues: https://github.com/m1ngsama/chopsticks/issues" >&2
|
||||
}
|
||||
trap on_error ERR
|
||||
|
||||
# Cleanup temp files on exit
|
||||
trap 'rm -f /tmp/chopsticks-hadolint /tmp/chopsticks-marksman 2>/dev/null' EXIT
|
||||
|
||||
# ── Safe download helper ──────────────────────────────────────────────────────
|
||||
# safe_download <url> <dest>
|
||||
# Returns 1 if download fails or file is empty / HTML error page
|
||||
safe_download() {
|
||||
local url="$1" dest="$2"
|
||||
curl -fsSL --connect-timeout 15 --retry 3 "$url" -o "$dest" 2>/dev/null || return 1
|
||||
# Reject empty files
|
||||
[[ -s "$dest" ]] || { rm -f "$dest"; return 1; }
|
||||
# Reject HTML error pages (GitHub 404, rate limits, etc.)
|
||||
if head -c 200 "$dest" 2>/dev/null | grep -qi "<!DOCTYPE\|<html"; then
|
||||
rm -f "$dest"; return 1
|
||||
fi
|
||||
|
|
@ -79,7 +70,6 @@ safe_download() {
|
|||
}
|
||||
|
||||
# ── Cross-platform package install helper ─────────────────────────────────────
|
||||
# pkg_install <brew> <apt> <pacman> <dnf> (pass "" to skip that pkg manager)
|
||||
pkg_install() {
|
||||
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
|
||||
|
|
@ -90,25 +80,122 @@ pkg_install() {
|
|||
fi
|
||||
}
|
||||
|
||||
# ── CPU architecture normalizer ───────────────────────────────────────────────
|
||||
# Normalize uname -m to the naming convention used by GitHub releases
|
||||
# ── CPU architecture helpers ──────────────────────────────────────────────────
|
||||
arch_github() {
|
||||
case "$(uname -m)" in
|
||||
x86_64) echo "x86_64" ;;
|
||||
aarch64|arm64) echo "arm64" ;;
|
||||
armv7l) echo "armv7" ;;
|
||||
*) echo "$(uname -m)" ;;
|
||||
*) uname -m ;;
|
||||
esac
|
||||
}
|
||||
arch_linux_x64() {
|
||||
# Returns x64 or arm64 style (used by marksman)
|
||||
case "$(uname -m)" in
|
||||
x86_64) echo "x64" ;;
|
||||
aarch64|arm64) echo "arm64" ;;
|
||||
*) echo "$(uname -m)" ;;
|
||||
*) uname -m ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Checkbox selection menu
|
||||
# ============================================================================
|
||||
#
|
||||
# Usage:
|
||||
# _menu_checkbox "Title" "label|description|default(0/1)" ...
|
||||
#
|
||||
# Result: global MENU_SEL array — MENU_SEL[i]=1 means item i was selected.
|
||||
# Globals _MENU_LABELS / _MENU_DESCS remain populated after return.
|
||||
#
|
||||
# In --yes mode or non-TTY: uses defaults silently.
|
||||
# Controls: ↑↓ navigate · Space toggle · a all · n none · Enter confirm
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
_MENU_LABELS=()
|
||||
_MENU_DESCS=()
|
||||
_MENU_SELS=()
|
||||
_MENU_N=0
|
||||
_MENU_TITLE=""
|
||||
_MENU_CUR=0
|
||||
MENU_SEL=()
|
||||
|
||||
_menu_draw() {
|
||||
local i mark
|
||||
printf "\033[2K${BOLD}%s${NC}\n" "$_MENU_TITLE"
|
||||
printf "\033[2K %b%b\n" "$DIM" "↑/↓ move Space toggle a all n none Enter confirm${NC}"
|
||||
printf "\033[2K\n"
|
||||
for ((i = 0; i < _MENU_N; i++)); do
|
||||
if [[ ${_MENU_SELS[$i]} -eq 1 ]]; then
|
||||
mark="${GREEN}✓${NC}"
|
||||
else
|
||||
mark=" "
|
||||
fi
|
||||
if [[ $i -eq $_MENU_CUR ]]; then
|
||||
printf "\033[2K ${BOLD}▶ [%b] %s${NC}\n" "$mark" "${_MENU_LABELS[$i]}"
|
||||
else
|
||||
printf "\033[2K [%b] %s\n" "$mark" "${_MENU_LABELS[$i]}"
|
||||
fi
|
||||
printf "\033[2K ${CYAN}%s${NC}\n" "${_MENU_DESCS[$i]}"
|
||||
done
|
||||
}
|
||||
|
||||
_menu_checkbox() {
|
||||
_MENU_TITLE="$1"; shift
|
||||
_MENU_LABELS=(); _MENU_DESCS=(); _MENU_SELS=()
|
||||
_MENU_N=0; _MENU_CUR=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
IFS='|' read -r \
|
||||
"_MENU_LABELS[$_MENU_N]" \
|
||||
"_MENU_DESCS[$_MENU_N]" \
|
||||
"_MENU_SELS[$_MENU_N]" <<< "$1"
|
||||
shift; : $(( _MENU_N++ ))
|
||||
done
|
||||
|
||||
# Non-interactive or --yes: use defaults, no UI
|
||||
if [[ $AUTO_YES -eq 1 ]] || ! { true </dev/tty; } 2>/dev/null; then
|
||||
MENU_SEL=("${_MENU_SELS[@]}")
|
||||
[[ $AUTO_YES -eq 1 ]] && info "(--yes mode: using all defaults)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Lines printed per _menu_draw call: 3 header + 2 per item
|
||||
local _lines=$(( 3 + 2 * _MENU_N ))
|
||||
local _key _esc _i
|
||||
|
||||
tput civis 2>/dev/null # hide cursor
|
||||
_menu_draw
|
||||
|
||||
while true; do
|
||||
tput cuu "$_lines" 2>/dev/null # move back to top of menu
|
||||
_menu_draw
|
||||
|
||||
IFS= read -r -s -n1 _key </dev/tty
|
||||
if [[ $_key == $'\x1b' ]]; then
|
||||
IFS= read -r -s -n2 _esc </dev/tty
|
||||
case "$_esc" in
|
||||
'[A') ((_MENU_CUR > 0)) && ((_MENU_CUR--)) ;;
|
||||
'[B') ((_MENU_CUR < _MENU_N - 1)) && ((_MENU_CUR++)) ;;
|
||||
esac
|
||||
elif [[ $_key == ' ' ]]; then
|
||||
_MENU_SELS[_MENU_CUR]=$(( 1 - _MENU_SELS[_MENU_CUR] ))
|
||||
elif [[ $_key == 'a' || $_key == 'A' ]]; then
|
||||
for ((_i = 0; _i < _MENU_N; _i++)); do _MENU_SELS[_i]=1; done
|
||||
elif [[ $_key == 'n' || $_key == 'N' ]]; then
|
||||
for ((_i = 0; _i < _MENU_N; _i++)); do _MENU_SELS[_i]=0; done
|
||||
elif [[ -z $_key ]]; then # Enter
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
tput cnorm 2>/dev/null # restore cursor
|
||||
echo ""
|
||||
MENU_SEL=("${_MENU_SELS[@]}")
|
||||
}
|
||||
|
||||
# Helper: was menu item at index $1 selected?
|
||||
_selected() { [[ ${MENU_SEL[${1:-999}]:-0} -eq 1 ]]; }
|
||||
|
||||
echo -e "${BOLD}chopsticks — Vim Configuration Installer${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
|
|
@ -119,14 +206,10 @@ echo "----------------------------------------"
|
|||
step "Detecting environment"
|
||||
|
||||
OS="unknown"
|
||||
if [[ "$OSTYPE" == darwin* ]]; then
|
||||
OS="macos"
|
||||
elif [[ -f /etc/debian_version ]]; then
|
||||
OS="debian"
|
||||
elif [[ -f /etc/fedora-release ]]; then
|
||||
OS="fedora"
|
||||
elif [[ -f /etc/arch-release ]]; then
|
||||
OS="arch"
|
||||
if [[ "$OSTYPE" == darwin* ]]; then OS="macos"
|
||||
elif [[ -f /etc/debian_version ]]; then OS="debian"
|
||||
elif [[ -f /etc/fedora-release ]]; then OS="fedora"
|
||||
elif [[ -f /etc/arch-release ]]; then OS="arch"
|
||||
fi
|
||||
ok "OS: $OS"
|
||||
|
||||
|
|
@ -135,44 +218,38 @@ 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_PACMAN=0; command -v pacman >/dev/null 2>&1 && HAS_PACMAN=1
|
||||
|
||||
# ── sudo ─────────────────────────────────────────────────────────────────────
|
||||
# sudo
|
||||
HAS_SUDO=0
|
||||
if [[ $OS == "macos" ]]; then
|
||||
# brew handles its own privilege escalation; no sudo needed for system tools
|
||||
HAS_SUDO=1
|
||||
HAS_SUDO=1 # brew handles its own privilege escalation
|
||||
elif sudo -n true 2>/dev/null; then
|
||||
HAS_SUDO=1
|
||||
ok "sudo: available (passwordless)"
|
||||
HAS_SUDO=1; ok "sudo: available (passwordless)"
|
||||
elif [[ $AUTO_YES -eq 1 ]]; then
|
||||
warn "sudo requires a password but running non-interactively (--yes)"
|
||||
warn "System package installations will be skipped"
|
||||
else
|
||||
# Prompt once for password now so later sudo calls don't interrupt flow
|
||||
warn "Some steps require sudo. Authenticating now..."
|
||||
if sudo true; then
|
||||
HAS_SUDO=1
|
||||
ok "sudo: authenticated"
|
||||
HAS_SUDO=1; ok "sudo: authenticated"
|
||||
else
|
||||
warn "sudo not available — system package installations will be skipped"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Network ──────────────────────────────────────────────────────────────────
|
||||
# Network
|
||||
if curl -fsSL --connect-timeout 5 https://github.com -o /dev/null 2>/dev/null; then
|
||||
ok "Network: github.com reachable"
|
||||
else
|
||||
warn "Network: cannot reach github.com — plugin and binary downloads may fail"
|
||||
warn "Check your internet connection or proxy settings before continuing"
|
||||
fi
|
||||
|
||||
# ── Homebrew (macOS) ─────────────────────────────────────────────────────────
|
||||
# Homebrew (macOS)
|
||||
if [[ $OS == "macos" && $HAS_BREW -eq 0 ]]; then
|
||||
warn "Homebrew not found — it is the recommended package manager for macOS"
|
||||
if ask "Install Homebrew now? (strongly recommended — required for system tools)"; then
|
||||
info "This may take a few minutes and will prompt for your password..."
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || \
|
||||
die "Homebrew installation failed. Install manually: https://brew.sh"
|
||||
# Source brew for Apple Silicon and Intel paths
|
||||
for brew_path in /opt/homebrew/bin/brew /usr/local/bin/brew; do
|
||||
[[ -x "$brew_path" ]] && eval "$("$brew_path" shellenv)" && break
|
||||
done
|
||||
|
|
@ -182,7 +259,7 @@ if [[ $OS == "macos" && $HAS_BREW -eq 0 ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# ── curl ─────────────────────────────────────────────────────────────────────
|
||||
# curl
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
warn "curl not found — required to download plugins and tools"
|
||||
if pkg_install curl curl curl curl 2>/dev/null; then
|
||||
|
|
@ -196,7 +273,7 @@ if ! command -v curl >/dev/null 2>&1; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# ── git ──────────────────────────────────────────────────────────────────────
|
||||
# git
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
warn "git not found — required for vim-plug to install plugins"
|
||||
if pkg_install git git git git 2>/dev/null; then
|
||||
|
|
@ -210,9 +287,8 @@ if ! command -v git >/dev/null 2>&1; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# ── vim ──────────────────────────────────────────────────────────────────────
|
||||
# vim
|
||||
[ -f "$SCRIPT_DIR/.vimrc" ] || die ".vimrc not found in $SCRIPT_DIR — is this the chopsticks repo?"
|
||||
|
||||
if ! command -v vim >/dev/null 2>&1; then
|
||||
warn "vim not found — attempting to install"
|
||||
if pkg_install vim vim vim vim 2>/dev/null; then
|
||||
|
|
@ -225,70 +301,25 @@ if ! command -v vim >/dev/null 2>&1; then
|
|||
macOS: brew install vim"
|
||||
fi
|
||||
fi
|
||||
|
||||
VIM_VERSION=$(vim --version | head -n1)
|
||||
ok "Found: $VIM_VERSION"
|
||||
|
||||
ok "Found: $(vim --version | head -n1)"
|
||||
vim --version | grep -q 'Vi IMproved 8\|Vi IMproved 9' || \
|
||||
warn "Vim 8.0+ recommended for full async/LSP support — some features may not work"
|
||||
|
||||
# ── Node.js ──────────────────────────────────────────────────────────────────
|
||||
# Node.js (optional — vim-lsp needs no Node.js; only npm formatters do)
|
||||
HAS_NODE=0; command -v node >/dev/null 2>&1 && HAS_NODE=1
|
||||
|
||||
if [[ $HAS_NODE -eq 0 ]]; then
|
||||
warn "Node.js not found — CoC LSP and npm-based formatters will be unavailable"
|
||||
info "Without Node.js, the config falls back to vim-lsp (pure VimScript)."
|
||||
info ""
|
||||
info "Install options:"
|
||||
info " nvm (recommended): curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/HEAD/install.sh | bash"
|
||||
info " macOS: brew install node"
|
||||
info " Ubuntu/Debian: curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -"
|
||||
info " sudo apt-get install -y nodejs"
|
||||
info " Arch: sudo pacman -S nodejs npm"
|
||||
info ""
|
||||
if ask "Install Node.js via nvm now? (recommended — manages multiple Node versions)"; then
|
||||
info "Fetching latest nvm release..."
|
||||
NVM_VER=$(curl -fsSL https://api.github.com/repos/nvm-sh/nvm/releases/latest \
|
||||
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || NVM_VER="v0.40.1"
|
||||
[[ -z "$NVM_VER" ]] && NVM_VER="v0.40.1"
|
||||
info "Installing nvm $NVM_VER + Node.js LTS..."
|
||||
if curl -fsSL "https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VER}/install.sh" | bash >/dev/null 2>&1; then
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
# shellcheck disable=SC1091
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
if command -v nvm >/dev/null 2>&1; then
|
||||
nvm install --lts >/dev/null 2>&1 && nvm use --lts >/dev/null 2>&1 || true
|
||||
command -v node >/dev/null 2>&1 && HAS_NODE=1 && ok "Node.js $(node --version) installed via nvm"
|
||||
fi
|
||||
fi
|
||||
if [[ $HAS_NODE -eq 0 ]]; then
|
||||
warn "nvm install failed — CoC and npm tools will be skipped"
|
||||
warn "After manually installing Node.js, re-run: ./install.sh"
|
||||
fi
|
||||
else
|
||||
skip "Node.js — config will use vim-lsp fallback (no Node.js required)"
|
||||
fi
|
||||
else
|
||||
if [[ $HAS_NODE -eq 1 ]]; then
|
||||
ok "Node.js $(node --version) found"
|
||||
else
|
||||
warn "Node.js not found — npm formatters (prettier, eslint) will be unavailable"
|
||||
warn "LSP still works without Node.js. To add formatters later: brew install node"
|
||||
fi
|
||||
|
||||
# ── Python3 ──────────────────────────────────────────────────────────────────
|
||||
# Python3 / pip3
|
||||
HAS_PYTHON=0; command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1
|
||||
HAS_PIP=0; command -v pip3 >/dev/null 2>&1 && HAS_PIP=1
|
||||
|
||||
if [[ $HAS_PYTHON -eq 0 ]]; then
|
||||
warn "python3 not found — Python formatters/linters will be unavailable"
|
||||
if ask "Install Python 3?"; then
|
||||
if pkg_install python3 python3 python3 python3 2>/dev/null; then
|
||||
command -v python3 >/dev/null 2>&1 && HAS_PYTHON=1 && ok "Python3 installed"
|
||||
else
|
||||
warn "Python3 install failed — Python tools will be skipped"
|
||||
fi
|
||||
else
|
||||
skip "Python3"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Bootstrap pip3 when python3 exists but pip3 is absent (common on Ubuntu minimal)
|
||||
if [[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]]; then
|
||||
warn "python3 found but pip3 missing — attempting bootstrap"
|
||||
|
|
@ -299,11 +330,10 @@ if [[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]]; then
|
|||
warn "pip3 bootstrap failed — Python tools will be skipped"
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ $HAS_PIP -eq 1 ]] && ok "Python/pip3 found"
|
||||
[[ $HAS_PYTHON -eq 1 && $HAS_PIP -eq 0 ]] && warn "pip3 not available — Python tools will be skipped"
|
||||
|
||||
# ── Go ───────────────────────────────────────────────────────────────────────
|
||||
# Go
|
||||
HAS_GO=0; command -v go >/dev/null 2>&1 && HAS_GO=1
|
||||
[[ $HAS_GO -eq 1 ]] && ok "Go $(go version | awk '{print $3}') found"
|
||||
[[ $HAS_GO -eq 0 ]] && warn "Go not found — Go tools will be skipped (see https://go.dev/dl/)"
|
||||
|
|
@ -316,22 +346,29 @@ step "Setting up symlinks"
|
|||
|
||||
if [ -f "$HOME/.vimrc" ] && [ ! -L "$HOME/.vimrc" ]; then
|
||||
TS=$(date +%Y%m%d_%H%M%S)
|
||||
warn "Backing up existing ~/.vimrc → ~/.vimrc.backup.$TS"
|
||||
warn "Backing up existing ~/.vimrc → $HOME/.vimrc.backup.$TS"
|
||||
mv "$HOME/.vimrc" "$HOME/.vimrc.backup.$TS"
|
||||
fi
|
||||
ln -sf "$SCRIPT_DIR/.vimrc" "$HOME/.vimrc"
|
||||
# Verify symlink
|
||||
[[ -L "$HOME/.vimrc" ]] && ok "~/.vimrc → $SCRIPT_DIR/.vimrc" || die "Failed to create ~/.vimrc symlink"
|
||||
if [[ -L "$HOME/.vimrc" ]]; then
|
||||
ok "$HOME/.vimrc → $SCRIPT_DIR/.vimrc"
|
||||
else
|
||||
die "Failed to create ~/.vimrc symlink"
|
||||
fi
|
||||
|
||||
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 → ~/.vim/coc-settings.json.backup.$TS"
|
||||
warn "Backing up existing coc-settings.json → $COC_CFG.backup.$TS"
|
||||
mv "$COC_CFG" "$COC_CFG.backup.$TS"
|
||||
fi
|
||||
ln -sf "$SCRIPT_DIR/coc-settings.json" "$COC_CFG"
|
||||
[[ -L "$COC_CFG" ]] && ok "~/.vim/coc-settings.json → $SCRIPT_DIR/coc-settings.json" || warn "coc-settings.json symlink failed (non-fatal)"
|
||||
if [[ -L "$COC_CFG" ]]; then
|
||||
ok "$HOME/.vim/coc-settings.json → $SCRIPT_DIR/coc-settings.json"
|
||||
else
|
||||
warn "coc-settings.json symlink failed (non-fatal)"
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 3. vim-plug + Plugins
|
||||
|
|
@ -342,13 +379,16 @@ step "Installing vim-plug"
|
|||
VIM_PLUG="$HOME/.vim/autoload/plug.vim"
|
||||
if [ ! -f "$VIM_PLUG" ]; then
|
||||
mkdir -p "$HOME/.vim/autoload"
|
||||
if safe_download "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" "$VIM_PLUG"; then
|
||||
if safe_download \
|
||||
"https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" \
|
||||
"$VIM_PLUG"; then
|
||||
ok "vim-plug downloaded"
|
||||
else
|
||||
# Fallback: git clone
|
||||
warn "curl download failed — trying git clone fallback"
|
||||
if git clone --depth=1 https://github.com/junegunn/vim-plug.git /tmp/vim-plug-src 2>/dev/null; then
|
||||
cp /tmp/vim-plug-src/plug.vim "$VIM_PLUG" && rm -rf /tmp/vim-plug-src
|
||||
if git clone --depth=1 https://github.com/junegunn/vim-plug.git \
|
||||
/tmp/vim-plug-src 2>/dev/null; then
|
||||
cp /tmp/vim-plug-src/plug.vim "$VIM_PLUG"
|
||||
rm -rf /tmp/vim-plug-src
|
||||
ok "vim-plug installed (via git)"
|
||||
else
|
||||
die "vim-plug installation failed. Check your network connection and try again."
|
||||
|
|
@ -360,156 +400,250 @@ else
|
|||
fi
|
||||
|
||||
step "Installing Vim plugins"
|
||||
# Use /dev/tty when available so vim properly manages the terminal (alternate
|
||||
# screen buffer, cursor, colours) and restores it cleanly on exit.
|
||||
# Fall back to --not-a-term for non-interactive/CI environments.
|
||||
|
||||
_vim_run() {
|
||||
if { true </dev/tty; } 2>/dev/null; then
|
||||
# Interactive terminal: let vim manage the alternate screen properly
|
||||
# Interactive terminal: vim uses alternate screen; user sees progress
|
||||
vim "$@" </dev/tty
|
||||
else
|
||||
# Non-interactive / CI: TERM=dumb suppresses all escape sequences;
|
||||
# stdout+stderr redirected so nothing leaks into installer output
|
||||
TERM=dumb vim "$@" </dev/null >/dev/null 2>&1
|
||||
# No TTY (SSH batch, CI): do NOT redirect stdin (causes "Error reading input" exit)
|
||||
# or stdout (breaks async job callbacks — partial install).
|
||||
# Redirect only stderr; escape sequences appear on stdout but installation succeeds.
|
||||
vim --not-a-term "$@" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
_vim_run +PlugInstall +qall || true # post-install hooks (e.g. fzf) may exit non-zero; harmless
|
||||
ok "Plugins installed"
|
||||
_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
|
||||
|
||||
_plug_count=$(ls -1 "$HOME/.vim/plugged" 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [[ $_plug_count -eq 0 ]]; then
|
||||
die "Plugin installation failed — ~/.vim/plugged is empty. Check network and retry."
|
||||
fi
|
||||
ok "Plugins installed ($_plug_count)"
|
||||
|
||||
# ============================================================================
|
||||
# 4. System Tools
|
||||
# 4. Module Selection
|
||||
# ============================================================================
|
||||
|
||||
step "Select optional components"
|
||||
|
||||
_ITEMS=()
|
||||
_idx=0
|
||||
|
||||
# Index map (-1 = not in menu / unavailable)
|
||||
_I_RIPGREP=-1; _I_FZF=-1; _I_CTAGS=-1; _I_SHELLCHECK=-1
|
||||
_I_HADOLINT=-1; _I_MARKSMAN=-1
|
||||
_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 ]] && [[ $HAS_SUDO -eq 1 ]]; }; then
|
||||
HAS_PKG_MGR=1
|
||||
fi
|
||||
|
||||
# ── System tools ─────────────────────────────────────────────────────────────
|
||||
if [[ $HAS_PKG_MGR -eq 1 ]]; then
|
||||
_I_RIPGREP=$_idx
|
||||
_ITEMS+=("ripgrep|,rg / ,rG project-wide search · powers Ctrl+p preview|1")
|
||||
: $(( _idx++ ))
|
||||
|
||||
_I_FZF=$_idx
|
||||
_ITEMS+=("fzf|Ctrl+p fuzzy file search · ,b buffers · ,rt tag search|1")
|
||||
: $(( _idx++ ))
|
||||
|
||||
_I_CTAGS=$_idx
|
||||
_ITEMS+=("universal-ctags|code symbol index (backing engine for ,rt tag jumps)|1")
|
||||
: $(( _idx++ ))
|
||||
|
||||
_I_SHELLCHECK=$_idx
|
||||
_ITEMS+=("shellcheck|shell script static analysis (ALE integration, on-save)|1")
|
||||
: $(( _idx++ ))
|
||||
|
||||
_I_HADOLINT=$_idx
|
||||
_ITEMS+=("hadolint|Dockerfile linting (ALE integration, on-save)|1")
|
||||
: $(( _idx++ ))
|
||||
|
||||
_I_MARKSMAN=$_idx
|
||||
_ITEMS+=("marksman|Markdown LSP — completion · go-to-definition · live diagnostics|1")
|
||||
: $(( _idx++ ))
|
||||
else
|
||||
warn "No package manager available — system tools skipped"
|
||||
fi
|
||||
|
||||
# ── npm tools ────────────────────────────────────────────────────────────────
|
||||
if [[ $HAS_NODE -eq 1 ]]; then
|
||||
_I_NPM=$_idx
|
||||
_ITEMS+=("npm formatter suite|prettier / eslint / markdownlint / stylelint / tsc — ALE fix-on-save|1")
|
||||
: $(( _idx++ ))
|
||||
fi
|
||||
|
||||
# ── Python tools ─────────────────────────────────────────────────────────────
|
||||
if [[ $HAS_PIP -eq 1 ]]; then
|
||||
_I_PYTHON=$_idx
|
||||
_ITEMS+=("Python tool suite|black / isort / flake8 / pylint / yamllint / sqlfluff — ALE fix-on-save|1")
|
||||
: $(( _idx++ ))
|
||||
fi
|
||||
|
||||
# ── Go tools ─────────────────────────────────────────────────────────────────
|
||||
if [[ $HAS_GO -eq 1 ]]; then
|
||||
_I_GO=$_idx
|
||||
_ITEMS+=("Go tool suite|gopls (LSP) / goimports / staticcheck — completion · format · analysis|1")
|
||||
: $(( _idx++ ))
|
||||
fi
|
||||
|
||||
# ── tmux ─────────────────────────────────────────────────────────────────────
|
||||
if command -v tmux >/dev/null 2>&1; then
|
||||
if ! grep -q 'vim-tmux-navigator' "$HOME/.tmux.conf" 2>/dev/null; then
|
||||
_I_TMUX=$_idx
|
||||
_ITEMS+=("tmux integration|seamless Ctrl+h/j/k/l navigation between vim and tmux panes|1")
|
||||
: $(( _idx++ ))
|
||||
else
|
||||
ok "tmux integration (vim-tmux-navigator already configured)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${#_ITEMS[@]} -gt 0 ]]; then
|
||||
_menu_checkbox "Select components to install:" "${_ITEMS[@]}"
|
||||
echo -e "${BOLD}Install plan:${NC}"
|
||||
for ((_i = 0; _i < _MENU_N; _i++)); do
|
||||
if [[ ${MENU_SEL[$_i]:-0} -eq 1 ]]; then
|
||||
echo -e " ${GREEN}✓${NC} ${_MENU_LABELS[$_i]}"
|
||||
else
|
||||
echo -e " ${DIM}—${NC} ${_MENU_LABELS[$_i]}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
else
|
||||
warn "No optional components available for this environment"
|
||||
MENU_SEL=()
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 5. System Tools
|
||||
# ============================================================================
|
||||
|
||||
step "System tools"
|
||||
|
||||
if [[ $OS == "macos" && $HAS_BREW -eq 0 ]]; then
|
||||
skip "system tools (Homebrew not available — install brew first, then re-run)"
|
||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||
elif ask "Install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)?"; then
|
||||
if [[ $HAS_PKG_MGR -eq 0 ]]; then
|
||||
skip "system tools (no package manager available)"
|
||||
SKIPPED+=("ripgrep" "fzf" "universal-ctags" "shellcheck" "hadolint" "marksman")
|
||||
else
|
||||
|
||||
install_sys() {
|
||||
local name="$1" check="$2"; shift 2
|
||||
if command -v "$check" >/dev/null 2>&1; then
|
||||
ok "$name (already installed)"
|
||||
return
|
||||
# _do_sys <name> <cmd_check> <idx> <brew_pkg> <apt_pkg> <pac_pkg> [dnf_pkg]
|
||||
_do_sys() {
|
||||
local name="$1" check="$2" idx="$3"
|
||||
local brew_p="${4:-}" apt_p="${5:-}" pac_p="${6:-}" dnf_p="${7:-}"
|
||||
|
||||
if [[ $idx -lt 0 ]] || ! _selected "$idx"; then
|
||||
skip "$name"; SKIPPED+=("$name"); return
|
||||
fi
|
||||
local installed=0
|
||||
for cmd in "$@"; do
|
||||
if eval "$cmd" >/dev/null 2>&1; then installed=1; break; fi
|
||||
done
|
||||
if [[ $installed -eq 1 ]]; then
|
||||
if command -v "$check" >/dev/null 2>&1; then
|
||||
ok "$name (already installed)"; return
|
||||
fi
|
||||
if pkg_install "$brew_p" "$apt_p" "$pac_p" "$dnf_p"; then
|
||||
ok "$name"; INSTALLED+=("$name")
|
||||
else
|
||||
fail "$name — could not install automatically (install manually)"
|
||||
FAILED+=("$name")
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
if [[ $OS == "macos" ]]; then
|
||||
install_sys "ripgrep" rg "brew install ripgrep"
|
||||
install_sys "fzf" fzf "brew install fzf"
|
||||
install_sys "universal-ctags" ctags "brew install universal-ctags"
|
||||
install_sys "shellcheck" shellcheck "brew install shellcheck"
|
||||
install_sys "hadolint" hadolint "brew install hadolint"
|
||||
install_sys "marksman" marksman "brew install marksman"
|
||||
|
||||
elif [[ $HAS_APT -eq 1 ]]; then
|
||||
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||
warn "No sudo — skipping apt system tools"
|
||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||
# _do_binary_apt: for tools with no apt/dnf package — download binary from GitHub
|
||||
_do_binary_apt() {
|
||||
local name="$1" check="$2" idx="$3" url="$4" tmp="$5"
|
||||
if [[ $idx -lt 0 ]] || ! _selected "$idx"; then
|
||||
skip "$name"; SKIPPED+=("$name"); return
|
||||
fi
|
||||
if command -v "$check" >/dev/null 2>&1; then
|
||||
ok "$name (already installed)"; return
|
||||
fi
|
||||
if safe_download "$url" "$tmp"; then
|
||||
chmod +x "$tmp" && sudo mv "$tmp" /usr/local/bin/"$check"
|
||||
ok "$name"; INSTALLED+=("$name")
|
||||
else
|
||||
sudo apt-get update -qq
|
||||
install_sys "ripgrep" rg "sudo apt-get install -y ripgrep"
|
||||
install_sys "fzf" fzf "sudo apt-get install -y fzf"
|
||||
install_sys "universal-ctags" ctags "sudo apt-get install -y universal-ctags"
|
||||
install_sys "shellcheck" shellcheck "sudo apt-get install -y shellcheck"
|
||||
fail "$name — binary download failed (install manually)"
|
||||
FAILED+=("$name")
|
||||
fi
|
||||
}
|
||||
|
||||
# hadolint: no apt package — download binary from GitHub releases
|
||||
if command -v hadolint >/dev/null 2>&1; then
|
||||
ok "hadolint (already installed)"
|
||||
else
|
||||
if [[ $OS == "macos" ]]; then
|
||||
_do_sys "ripgrep" rg "$_I_RIPGREP" ripgrep "" "" ""
|
||||
_do_sys "fzf" fzf "$_I_FZF" fzf "" "" ""
|
||||
_do_sys "universal-ctags" ctags "$_I_CTAGS" universal-ctags "" "" ""
|
||||
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" shellcheck "" "" ""
|
||||
_do_sys "hadolint" hadolint "$_I_HADOLINT" hadolint "" "" ""
|
||||
_do_sys "marksman" marksman "$_I_MARKSMAN" marksman "" "" ""
|
||||
|
||||
elif [[ $HAS_APT -eq 1 ]]; then
|
||||
[[ $HAS_SUDO -eq 1 ]] && sudo apt-get update -qq
|
||||
_do_sys "ripgrep" rg "$_I_RIPGREP" "" ripgrep "" ""
|
||||
_do_sys "fzf" fzf "$_I_FZF" "" fzf "" ""
|
||||
_do_sys "universal-ctags" ctags "$_I_CTAGS" "" universal-ctags "" ""
|
||||
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" shellcheck "" ""
|
||||
|
||||
# hadolint: no apt package — binary from GitHub releases
|
||||
HARCH=$(arch_github)
|
||||
HVER=$(curl -fsSL https://api.github.com/repos/hadolint/hadolint/releases/latest \
|
||||
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || HVER=""
|
||||
if [[ -n "$HVER" ]] && safe_download \
|
||||
_do_binary_apt "hadolint" hadolint "$_I_HADOLINT" \
|
||||
"https://github.com/hadolint/hadolint/releases/download/${HVER}/hadolint-Linux-${HARCH}" \
|
||||
/tmp/chopsticks-hadolint; then
|
||||
chmod +x /tmp/chopsticks-hadolint && sudo mv /tmp/chopsticks-hadolint /usr/local/bin/hadolint
|
||||
ok "hadolint"; INSTALLED+=("hadolint")
|
||||
else
|
||||
fail "hadolint — download failed (install manually: https://github.com/hadolint/hadolint/releases)"
|
||||
FAILED+=("hadolint")
|
||||
fi
|
||||
fi
|
||||
/tmp/chopsticks-hadolint
|
||||
|
||||
# marksman: no apt package — download binary from GitHub releases
|
||||
if command -v marksman >/dev/null 2>&1; then
|
||||
ok "marksman (already installed)"
|
||||
else
|
||||
# marksman: no apt package — binary from GitHub releases
|
||||
MARCH=$(arch_linux_x64)
|
||||
MVER=$(curl -fsSL https://api.github.com/repos/artempyanykh/marksman/releases/latest \
|
||||
| grep '"tag_name"' | cut -d'"' -f4 2>/dev/null) || MVER=""
|
||||
if [[ -n "$MVER" ]] && safe_download \
|
||||
_do_binary_apt "marksman" marksman "$_I_MARKSMAN" \
|
||||
"https://github.com/artempyanykh/marksman/releases/download/${MVER}/marksman-linux-${MARCH}" \
|
||||
/tmp/chopsticks-marksman; then
|
||||
chmod +x /tmp/chopsticks-marksman && sudo mv /tmp/chopsticks-marksman /usr/local/bin/marksman
|
||||
ok "marksman"; INSTALLED+=("marksman")
|
||||
else
|
||||
fail "marksman — download failed (install manually: https://github.com/artempyanykh/marksman/releases)"
|
||||
FAILED+=("marksman")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
/tmp/chopsticks-marksman
|
||||
|
||||
elif [[ $HAS_PACMAN -eq 1 ]]; then
|
||||
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||
warn "No sudo — skipping pacman system tools"
|
||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||
else
|
||||
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"
|
||||
fi
|
||||
elif [[ $HAS_PACMAN -eq 1 ]]; then
|
||||
_do_sys "ripgrep" rg "$_I_RIPGREP" "" "" ripgrep ""
|
||||
_do_sys "fzf" fzf "$_I_FZF" "" "" fzf ""
|
||||
_do_sys "universal-ctags" ctags "$_I_CTAGS" "" "" ctags ""
|
||||
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" "" shellcheck ""
|
||||
_do_sys "hadolint" hadolint "$_I_HADOLINT" "" "" hadolint ""
|
||||
_do_sys "marksman" marksman "$_I_MARKSMAN" "" "" marksman ""
|
||||
|
||||
elif [[ $HAS_DNF -eq 1 ]]; then
|
||||
if [[ $HAS_SUDO -eq 0 ]]; then
|
||||
warn "No sudo — skipping dnf system tools"
|
||||
SKIPPED+=("ripgrep" "fzf" "shellcheck" "ctags" "hadolint" "marksman")
|
||||
else
|
||||
install_sys "ripgrep" rg "sudo dnf install -y ripgrep"
|
||||
install_sys "fzf" fzf "sudo dnf install -y fzf"
|
||||
install_sys "shellcheck" shellcheck "sudo dnf install -y ShellCheck"
|
||||
skip "universal-ctags — install manually: sudo dnf install ctags"
|
||||
SKIPPED+=("ctags")
|
||||
skip "hadolint — install manually: https://github.com/hadolint/hadolint/releases"
|
||||
elif [[ $HAS_DNF -eq 1 ]]; then
|
||||
_do_sys "ripgrep" rg "$_I_RIPGREP" "" "" "" ripgrep
|
||||
_do_sys "fzf" fzf "$_I_FZF" "" "" "" fzf
|
||||
_do_sys "shellcheck" shellcheck "$_I_SHELLCHECK" "" "" "" ShellCheck
|
||||
if [[ $_I_CTAGS -ge 0 ]] && _selected "$_I_CTAGS"; then
|
||||
skip "universal-ctags — Fedora: install manually: sudo dnf install ctags"
|
||||
SKIPPED+=("universal-ctags")
|
||||
fi
|
||||
if [[ $_I_HADOLINT -ge 0 ]] && _selected "$_I_HADOLINT"; then
|
||||
skip "hadolint — Fedora: install manually: https://github.com/hadolint/hadolint/releases"
|
||||
SKIPPED+=("hadolint")
|
||||
skip "marksman — install manually: https://github.com/artempyanykh/marksman/releases"
|
||||
fi
|
||||
if [[ $_I_MARKSMAN -ge 0 ]] && _selected "$_I_MARKSMAN"; then
|
||||
skip "marksman — Fedora: install manually: https://github.com/artempyanykh/marksman/releases"
|
||||
SKIPPED+=("marksman")
|
||||
fi
|
||||
|
||||
else
|
||||
warn "Unknown distro — skipping system tools (install manually)"
|
||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||
fi
|
||||
|
||||
else
|
||||
skip "system tools"
|
||||
SKIPPED+=("ripgrep" "fzf" "ctags" "shellcheck" "hadolint" "marksman")
|
||||
warn "Unknown distro — skipping system tools (install manually)"
|
||||
SKIPPED+=("ripgrep" "fzf" "universal-ctags" "shellcheck" "hadolint" "marksman")
|
||||
fi
|
||||
|
||||
fi # end HAS_PKG_MGR
|
||||
|
||||
# ============================================================================
|
||||
# 5. npm tools
|
||||
# 6. npm Tools
|
||||
# ============================================================================
|
||||
|
||||
step "npm tools (formatters + linters)"
|
||||
|
||||
if [[ $HAS_NODE -eq 1 ]]; then
|
||||
if ask "Install npm tools (prettier, markdownlint-cli, stylelint, eslint, typescript)?"; then
|
||||
if [[ $HAS_NODE -eq 0 ]]; then
|
||||
skip "npm tools (Node.js not installed)"
|
||||
SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript")
|
||||
elif [[ $_I_NPM -lt 0 ]] || ! _selected "$_I_NPM"; then
|
||||
skip "npm formatter suite (skipped by user)"
|
||||
SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript")
|
||||
else
|
||||
npm_install() {
|
||||
local pkg="$1"; local check="${2:-$1}"
|
||||
local pkg="$1" check="${2:-$1}"
|
||||
if command -v "$check" >/dev/null 2>&1; then
|
||||
ok "$pkg (already installed)"; return
|
||||
fi
|
||||
|
|
@ -525,25 +659,23 @@ if [[ $HAS_NODE -eq 1 ]]; then
|
|||
npm_install stylelint-config-standard
|
||||
npm_install eslint
|
||||
npm_install typescript tsc
|
||||
else
|
||||
skip "npm tools"
|
||||
SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript")
|
||||
fi
|
||||
else
|
||||
skip "npm tools (Node.js not installed)"
|
||||
SKIPPED+=("prettier" "markdownlint-cli" "stylelint" "eslint" "typescript")
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 6. Python tools
|
||||
# 7. Python Tools
|
||||
# ============================================================================
|
||||
|
||||
step "Python tools (formatters + linters)"
|
||||
|
||||
if [[ $HAS_PIP -eq 1 ]]; then
|
||||
if ask "Install Python tools (black, isort, flake8, pylint, yamllint, sqlfluff)?"; then
|
||||
if [[ $HAS_PIP -eq 0 ]]; then
|
||||
skip "Python tools (pip3 not installed)"
|
||||
SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
|
||||
elif [[ $_I_PYTHON -lt 0 ]] || ! _selected "$_I_PYTHON"; then
|
||||
skip "Python tool suite (skipped by user)"
|
||||
SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
|
||||
else
|
||||
pip_install() {
|
||||
local pkg="$1"; local check="${2:-$1}"
|
||||
local pkg="$1" check="${2:-$1}"
|
||||
if command -v "$check" >/dev/null 2>&1; then
|
||||
ok "$pkg (already installed)"; return
|
||||
fi
|
||||
|
|
@ -560,23 +692,21 @@ if [[ $HAS_PIP -eq 1 ]]; then
|
|||
pip_install pylint
|
||||
pip_install yamllint
|
||||
pip_install sqlfluff
|
||||
else
|
||||
skip "Python tools"
|
||||
SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
|
||||
fi
|
||||
else
|
||||
skip "Python tools (pip3 not installed)"
|
||||
SKIPPED+=("black" "isort" "flake8" "pylint" "yamllint" "sqlfluff")
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 7. Go tools
|
||||
# 8. Go Tools
|
||||
# ============================================================================
|
||||
|
||||
step "Go tools"
|
||||
|
||||
if [[ $HAS_GO -eq 1 ]]; then
|
||||
if ask "Install Go tools (gopls, goimports, staticcheck)?"; then
|
||||
if [[ $HAS_GO -eq 0 ]]; then
|
||||
skip "Go tools (go not installed — see https://go.dev/dl/)"
|
||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||
elif [[ $_I_GO -lt 0 ]] || ! _selected "$_I_GO"; then
|
||||
skip "Go tool suite (skipped by user)"
|
||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||
else
|
||||
GOBIN="$(go env GOPATH)/bin"
|
||||
export PATH="$PATH:$GOBIN"
|
||||
|
||||
|
|
@ -597,26 +727,24 @@ if [[ $HAS_GO -eq 1 ]]; then
|
|||
|
||||
echo "$PATH" | grep -q "$GOBIN" || \
|
||||
warn "Add Go binaries to PATH: export PATH=\"\$PATH:$GOBIN\""
|
||||
else
|
||||
skip "Go tools"
|
||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||
fi
|
||||
else
|
||||
skip "Go tools (go not installed — see https://go.dev/dl/)"
|
||||
SKIPPED+=("gopls" "goimports" "staticcheck")
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 8. tmux: vim-tmux-navigator integration
|
||||
# 9. tmux: vim-tmux-navigator integration
|
||||
# ============================================================================
|
||||
|
||||
step "tmux: vim-tmux-navigator integration"
|
||||
|
||||
if command -v tmux >/dev/null 2>&1; then
|
||||
if ! command -v tmux >/dev/null 2>&1; then
|
||||
skip "tmux not found — skipping navigator config"
|
||||
SKIPPED+=("tmux-navigator-config")
|
||||
elif [[ $_I_TMUX -lt 0 ]]; then
|
||||
: # already configured — noted earlier
|
||||
elif ! _selected "$_I_TMUX"; then
|
||||
skip "tmux navigator config (skipped by user)"
|
||||
SKIPPED+=("tmux-navigator-config")
|
||||
else
|
||||
TMUX_CONF="$HOME/.tmux.conf"
|
||||
if grep -q 'vim-tmux-navigator' "$TMUX_CONF" 2>/dev/null; then
|
||||
ok "vim-tmux-navigator bindings already present in ~/.tmux.conf"
|
||||
elif ask "Append vim-tmux-navigator bindings to ~/.tmux.conf (enables seamless Ctrl+h/j/k/l across vim and tmux)?"; then
|
||||
cat >> "$TMUX_CONF" << 'TMUXEOF'
|
||||
|
||||
# vim-tmux-navigator: seamless Ctrl+h/j/k/l navigation between vim and tmux
|
||||
|
|
@ -631,34 +759,21 @@ TMUXEOF
|
|||
warn "Note: C-l now navigates panes instead of clearing the screen."
|
||||
warn " To restore clear: add 'bind C-l send-keys C-l' to ~/.tmux.conf"
|
||||
INSTALLED+=("tmux-navigator-config")
|
||||
else
|
||||
skip "tmux navigator config"
|
||||
SKIPPED+=("tmux-navigator-config")
|
||||
fi
|
||||
else
|
||||
skip "tmux not found — skipping navigator config"
|
||||
SKIPPED+=("tmux-navigator-config")
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# 9. CoC language server extensions
|
||||
# 10. LSP language servers
|
||||
# ============================================================================
|
||||
|
||||
step "CoC language server extensions"
|
||||
|
||||
if [[ $HAS_NODE -eq 1 ]]; then
|
||||
if ask "Install CoC language servers (LSP for all configured languages)?"; then
|
||||
info "(Downloading CoC extensions via npm — this may take 1-3 minutes)"
|
||||
# Note: coc-marksman doesn't exist on npm — markdown LSP is handled via coc-settings.json
|
||||
_vim_run +'CocInstall -sync coc-json coc-tsserver coc-pyright coc-sh coc-html coc-css coc-yaml coc-go coc-rust-analyzer coc-sql' +qall
|
||||
ok "CoC language servers installed"
|
||||
else
|
||||
skip "CoC language servers"
|
||||
info "Install later with :CocInstall <name> inside Vim"
|
||||
fi
|
||||
else
|
||||
warn "Node.js not found — using vim-lsp fallback (run :LspInstallServer inside Vim for each language)"
|
||||
fi
|
||||
step "LSP language servers"
|
||||
info "vim-lsp installs language servers on demand — no action needed here."
|
||||
info ""
|
||||
info "To install a server: open a source file in Vim and run:"
|
||||
info " :LspInstallServer"
|
||||
info ""
|
||||
info "Supported: Python, JS/TS, Go, Rust, C/C++, Shell, HTML, CSS, JSON, YAML, Markdown, SQL"
|
||||
info ""
|
||||
info "For Markdown LSP (marksman), the installer already handled it above."
|
||||
|
||||
# ============================================================================
|
||||
# Summary
|
||||
|
|
@ -689,15 +804,15 @@ echo -e "${BOLD}---------------------------------------${NC}"
|
|||
echo -e "${BOLD} You're ready. Open Vim with:${NC}"
|
||||
echo -e "${BOLD}---------------------------------------${NC}"
|
||||
echo -e " ${CYAN}vim${NC} Launch startup dashboard"
|
||||
echo -e " ${CYAN}vim .${NC} Open file tree + dashboard"
|
||||
echo -e " ${CYAN}vim .${NC} Open dashboard in current directory"
|
||||
echo -e " ${CYAN}vim myfile${NC} Edit a specific file"
|
||||
echo ""
|
||||
echo -e "${BOLD} Survival Guide (first-time Vim users)${NC}"
|
||||
echo -e "${BOLD} First steps inside Vim${NC}"
|
||||
echo -e " ${CYAN}Esc${NC} or ${CYAN}jk${NC} Exit insert mode → back to Normal"
|
||||
echo -e " ${CYAN}:q!${NC} + Enter Emergency quit without saving"
|
||||
echo -e " ${CYAN},x${NC} Save and quit"
|
||||
echo -e " ${CYAN},?${NC} Open cheat sheet inside Vim"
|
||||
echo -e " ${CYAN},${NC} + pause Interactive keybinding guide"
|
||||
echo -e " ${CYAN},?${NC} Open cheat sheet"
|
||||
echo -e " ${CYAN}:LspInstallServer${NC} Install LSP for current filetype"
|
||||
echo ""
|
||||
echo -e "${YELLOW}[!]${NC} Ctrl+s is mapped to save in Vim."
|
||||
echo " If it freezes your terminal, add this to ~/.bashrc or ~/.zshrc:"
|
||||
|
|
|
|||
Loading…
Reference in a new issue