mirror of
https://oauth2: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@github.com/m1ngsama/chopsticks.git
synced 2026-05-10 19:10:59 +08:00
Compare commits
9 commits
4fb20177ef
...
97ca2be139
| Author | SHA1 | Date | |
|---|---|---|---|
| 97ca2be139 | |||
| 7b4b153f4b | |||
| dbb11c9473 | |||
| f0d4431eef | |||
| fa59d5be8f | |||
| 6044fc5fcb | |||
| 84d999f91f | |||
| cc328cebf2 | |||
| 575ff2c489 |
26 changed files with 1817 additions and 1777 deletions
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Something broken or unexpected
|
||||||
|
labels: bug
|
||||||
|
---
|
||||||
|
|
||||||
|
**What happened**
|
||||||
|
|
||||||
|
|
||||||
|
**What you expected**
|
||||||
|
|
||||||
|
|
||||||
|
**Steps to reproduce**
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
**Environment**
|
||||||
|
- OS:
|
||||||
|
- Vim version (`vim --version | head -1`):
|
||||||
|
- Terminal:
|
||||||
|
- SSH: yes / no
|
||||||
|
- TTY mode (`echo g:is_tty` inside vim):
|
||||||
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest a plugin, mapping, or improvement
|
||||||
|
labels: enhancement
|
||||||
|
---
|
||||||
|
|
||||||
|
**What problem does this solve?**
|
||||||
|
|
||||||
|
|
||||||
|
**What does the solution look like?**
|
||||||
|
|
||||||
|
|
||||||
|
**Alternatives you considered**
|
||||||
|
|
||||||
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
## What
|
||||||
|
|
||||||
|
<!-- One sentence: what does this PR do? -->
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
<!-- Why is this change needed? -->
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
- [ ] `vim --startuptime` shows no regression
|
||||||
|
- [ ] Tested on macOS / Linux
|
||||||
|
- [ ] `,?` cheat sheet still accurate
|
||||||
BIN
.github/demo.gif
vendored
Normal file
BIN
.github/demo.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 460 KiB |
47
.github/demo.tape
vendored
Normal file
47
.github/demo.tape
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
Output .github/demo.gif
|
||||||
|
Set Shell bash
|
||||||
|
Set FontSize 14
|
||||||
|
Set Width 960
|
||||||
|
Set Height 540
|
||||||
|
Set Theme "Builtin Solarized Dark"
|
||||||
|
Set TypingSpeed 50ms
|
||||||
|
Set Padding 10
|
||||||
|
|
||||||
|
Type "vim ~/.vim/modules/core.vim"
|
||||||
|
Enter
|
||||||
|
Sleep 1.5s
|
||||||
|
|
||||||
|
# Show the code with solarized theme and statusline
|
||||||
|
Sleep 1s
|
||||||
|
|
||||||
|
# Use Ctrl+p for fuzzy find
|
||||||
|
Type "\x10"
|
||||||
|
Sleep 1s
|
||||||
|
Type "lsp"
|
||||||
|
Sleep 1s
|
||||||
|
Escape
|
||||||
|
Sleep 0.5s
|
||||||
|
|
||||||
|
# Go to definition
|
||||||
|
Type "gg"
|
||||||
|
Sleep 0.3s
|
||||||
|
Type "/mapleader"
|
||||||
|
Enter
|
||||||
|
Sleep 1s
|
||||||
|
|
||||||
|
# Show cheat sheet
|
||||||
|
Type ",?"
|
||||||
|
Sleep 2s
|
||||||
|
Type "q"
|
||||||
|
Sleep 0.5s
|
||||||
|
|
||||||
|
# Open file browser
|
||||||
|
Type ",e"
|
||||||
|
Sleep 1.5s
|
||||||
|
Escape
|
||||||
|
Sleep 0.5s
|
||||||
|
|
||||||
|
# Quit
|
||||||
|
Type ":qa!"
|
||||||
|
Enter
|
||||||
|
Sleep 0.5s
|
||||||
66
.github/workflows/test.yml
vendored
Normal file
66
.github/workflows/test.yml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
name: test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
startup:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Vim
|
||||||
|
run: |
|
||||||
|
if [ "$(uname)" = "Darwin" ]; then
|
||||||
|
brew install vim
|
||||||
|
else
|
||||||
|
sudo apt-get update && sudo apt-get install -y vim
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install vim-plug
|
||||||
|
run: |
|
||||||
|
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
|
||||||
|
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
|
||||||
|
|
||||||
|
- name: Symlink config
|
||||||
|
run: |
|
||||||
|
ln -sf "$PWD" ~/.vim/chopsticks-src
|
||||||
|
ln -sf "$PWD/.vimrc" ~/.vimrc
|
||||||
|
mkdir -p ~/.vim/modules
|
||||||
|
cp modules/*.vim ~/.vim/modules/
|
||||||
|
|
||||||
|
- name: Install plugins
|
||||||
|
run: vim -es -u .vimrc -c 'PlugInstall --sync' -c 'qa!' 2>&1 || true
|
||||||
|
|
||||||
|
- name: Test startup
|
||||||
|
run: |
|
||||||
|
vim -u .vimrc -es -N -c 'qa!' 2>&1
|
||||||
|
echo "Vim exited cleanly"
|
||||||
|
|
||||||
|
- name: Verify modules load
|
||||||
|
run: |
|
||||||
|
vim -u .vimrc -N -c 'redir! > /tmp/test.txt | echo len(g:plugs) | redir END | qa!' 2>/dev/null
|
||||||
|
PLUGS=$(cat /tmp/test.txt | tr -d '[:space:]')
|
||||||
|
echo "Plugins registered: $PLUGS"
|
||||||
|
if [ "$PLUGS" -lt 25 ]; then
|
||||||
|
echo "FAIL: expected 25+ plugins, got $PLUGS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Measure startup time
|
||||||
|
run: |
|
||||||
|
vim -u .vimrc --startuptime /tmp/startup.log -c 'qa!' 2>/dev/null
|
||||||
|
tail -1 /tmp/startup.log
|
||||||
|
|
||||||
|
shellcheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Shellcheck install.sh
|
||||||
|
run: shellcheck install.sh get.sh
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,5 +1,3 @@
|
||||||
*.json
|
|
||||||
!coc-settings.json
|
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
||||||
30
CONTRIBUTING.md
Normal file
30
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
1. **No Node.js dependencies.** The LSP engine is pure VimScript. Some language servers need Node — that's fine. The config itself must not.
|
||||||
|
2. **Startup matters.** Run `vim --startuptime /tmp/s.log -c qa!` before and after. If your change adds >1ms, it needs a good reason.
|
||||||
|
3. **Works on TTY.** Test over SSH. If it breaks in a terminal without true color, fix it or gate it behind `g:is_tty`.
|
||||||
|
4. **One module, one concern.** Don't put git config in lsp.vim.
|
||||||
|
|
||||||
|
## Adding a plugin
|
||||||
|
|
||||||
|
1. Add the `Plug` line to `modules/plugins.vim`
|
||||||
|
2. If it's not needed at startup, lazy-load it: `Plug 'foo/bar', { 'on': 'FooCommand' }`
|
||||||
|
3. Put config in the appropriate module
|
||||||
|
4. Update the cheat sheet in `modules/tools.vim` if you add keybindings
|
||||||
|
5. Test on both macOS and Linux
|
||||||
|
|
||||||
|
## Reporting bugs
|
||||||
|
|
||||||
|
Open an issue. Include:
|
||||||
|
- OS and Vim version
|
||||||
|
- Whether you're on SSH/TTY
|
||||||
|
- Steps to reproduce
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
- Named augroups with `autocmd!`
|
||||||
|
- No comments explaining *what* — only *why*
|
||||||
|
- `exists('g:plugs["..."]')` guards for plugin-dependent config
|
||||||
|
- Test with `vim -u .vimrc --startuptime /tmp/s.log -c qa!`
|
||||||
265
QUICKSTART.md
265
QUICKSTART.md
|
|
@ -1,221 +1,96 @@
|
||||||
# Quick Start
|
# Quick Start
|
||||||
|
|
||||||
Five minutes from zero to a working Vim environment.
|
Five minutes from zero to a working Vim setup.
|
||||||
|
|
||||||
---
|
## Install
|
||||||
|
|
||||||
## Step 0: Vim Basics (2 minutes)
|
|
||||||
|
|
||||||
> **When confused, press `Esc` until things feel normal again.**
|
|
||||||
|
|
||||||
Vim is **modal** — the keyboard behaves differently depending on which mode you are in.
|
|
||||||
|
|
||||||
| 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` |
|
|
||||||
|
|
||||||
### 4 commands that get you out of any jam
|
|
||||||
|
|
||||||
| Command | Action |
|
|
||||||
|---------|--------|
|
|
||||||
| `Esc` or `jk` | Exit insert / visual mode → Normal |
|
|
||||||
| `:q!` then `Enter` | Force quit without saving |
|
|
||||||
| `,x` | Save and quit |
|
|
||||||
| `,w` or `Ctrl+s` | Save |
|
|
||||||
|
|
||||||
Once in Normal mode, press `,?` to open the cheat sheet.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 1: Install
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Traditional:
|
Open vim. Plugins install automatically on first launch (30-60s). Restart vim.
|
||||||
```bash
|
|
||||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
|
||||||
cd ~/.vim && ./install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Non-interactive / CI:
|
## Modes
|
||||||
```bash
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
| Mode | Enter | Leave |
|
||||||
|
|------|-------|-------|
|
||||||
|
| Normal | startup default | — |
|
||||||
|
| Insert | `i` / `a` / `o` | `Esc` or `jk` |
|
||||||
|
| Visual | `v` / `V` | `Esc` |
|
||||||
|
|
||||||
## Step 2: Open Vim
|
## Survival
|
||||||
|
|
||||||
```bash
|
|
||||||
vim # startup dashboard (recent files + sessions)
|
|
||||||
vim . # startup dashboard, current directory listed
|
|
||||||
vim myfile # edit a specific file
|
|
||||||
```
|
|
||||||
|
|
||||||
> **First launch:** Vim will automatically install plugins on the first open
|
|
||||||
> (takes 30–60 seconds depending on network). This is normal — wait for it
|
|
||||||
> to finish, then restart Vim.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 3: Set Up LSP
|
|
||||||
|
|
||||||
Open a source file, then run:
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:LspInstallServer
|
|
||||||
```
|
|
||||||
|
|
||||||
This auto-detects the filetype and installs the correct language server.
|
|
||||||
vim-lsp itself runs on pure VimScript — no Node.js required. However,
|
|
||||||
some language servers (JS/TS, HTML, CSS, JSON, YAML) are npm packages
|
|
||||||
that need Node.js to run. Python, Go, and Rust servers don't need it.
|
|
||||||
|
|
||||||
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 Keys That Matter
|
|
||||||
|
|
||||||
```
|
```
|
||||||
,? Open cheat sheet (all bindings in one place)
|
Esc / jk back to Normal
|
||||||
Esc / jk Exit insert mode → Normal
|
,w save
|
||||||
Ctrl+s Save
|
,x save + quit
|
||||||
Ctrl+p Fuzzy find file
|
:q! force quit
|
||||||
,e File browser (netrw)
|
Ctrl+s save from any mode
|
||||||
gd Go to definition
|
,? cheat sheet
|
||||||
K Show documentation
|
:ChopsticksLearn interactive tutorial
|
||||||
[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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
## Find things
|
||||||
|
|
||||||
## Daily Use
|
|
||||||
|
|
||||||
### Navigate Code
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `gd` | Go to definition |
|
|
||||||
| `gy` | Go to type definition |
|
|
||||||
| `gi` | Go to implementation |
|
|
||||||
| `gr` | List references |
|
|
||||||
| `K` | Docs for symbol under cursor |
|
|
||||||
| `Ctrl+o` | Jump back |
|
|
||||||
| `Ctrl+i` | Jump forward |
|
|
||||||
|
|
||||||
### Edit Code
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `Tab` | Select next completion item |
|
|
||||||
| `Enter` | Confirm completion |
|
|
||||||
| `gc` | Toggle comment (visual mode too) |
|
|
||||||
| `cs"'` | Change surrounding `"` to `'` |
|
|
||||||
| `ds(` | Delete surrounding `(` |
|
|
||||||
| `s` + 2 chars | EasyMotion: jump anywhere |
|
|
||||||
|
|
||||||
### Manage Errors
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `]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 (side window) |
|
|
||||||
| `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')
|
Ctrl+p fuzzy find file (git-aware)
|
||||||
,gd diff current file
|
,rg ripgrep project
|
||||||
|
,b search buffers
|
||||||
|
,fh recent files
|
||||||
|
,e file browser
|
||||||
|
,, last file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Write code
|
||||||
|
|
||||||
|
```
|
||||||
|
gd go to definition
|
||||||
|
K hover docs
|
||||||
|
,rn rename symbol
|
||||||
|
,ca code action
|
||||||
|
,f format
|
||||||
|
,cr run current file
|
||||||
|
Tab / S-Tab cycle completions
|
||||||
|
```
|
||||||
|
|
||||||
|
Install language servers with `:LspInstallServer` (auto-detects filetype).
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
```
|
||||||
|
,gs status (s=stage, cc=commit)
|
||||||
|
,gd diff
|
||||||
,gb blame
|
,gb blame
|
||||||
,gc commit
|
|
||||||
,gp push
|
,gp push
|
||||||
,gl pull
|
]x / [x conflict markers
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
## Edit
|
||||||
|
|
||||||
## Quick Reference Card
|
|
||||||
|
|
||||||
```
|
```
|
||||||
BASICS
|
s + 2 chars EasyMotion jump
|
||||||
Esc / jk Exit insert mode → Normal
|
gc toggle comment
|
||||||
Ctrl+s Save
|
cs"' change surrounding " to '
|
||||||
:q! + Enter Emergency quit
|
Alt+j / Alt+k move line
|
||||||
,? Open cheat sheet
|
,u undo tree
|
||||||
|
,y clipboard yank
|
||||||
FILES
|
|
||||||
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
|
|
||||||
,w Save | ,q Quit | ,x Save+quit
|
|
||||||
,wa Save all buffers
|
|
||||||
,, Switch to last file
|
|
||||||
|
|
||||||
CODE
|
|
||||||
gd Definition | gy Type def | gi Impl | gr References
|
|
||||||
K Show documentation
|
|
||||||
[g / ]g Prev / next LSP diagnostic
|
|
||||||
[e / ]e Prev / next ALE error
|
|
||||||
,rn Rename symbol
|
|
||||||
,ca Code action
|
|
||||||
,f Format buffer / selection
|
|
||||||
|
|
||||||
MARKDOWN
|
|
||||||
,mp Live preview | ,mt Table of contents
|
|
||||||
|
|
||||||
GIT
|
|
||||||
,gs Status | ,gd Diff | ,gb Blame
|
|
||||||
,gc Commit | ,gp Push | ,gl Pull
|
|
||||||
|
|
||||||
WINDOWS / PANES
|
|
||||||
Ctrl+h/j/k/l Move between Vim windows or tmux panes
|
|
||||||
,h / ,l Prev / next buffer
|
|
||||||
,tv / ,th Terminal (vertical / horizontal)
|
|
||||||
Esc Esc Exit terminal mode
|
|
||||||
,u Undo tree
|
|
||||||
|
|
||||||
SEARCH
|
|
||||||
/text Forward | ?text Backward | n next | N prev
|
|
||||||
// Search visually selected text
|
|
||||||
,* Replace word under cursor (file-wide)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
## Navigate
|
||||||
|
|
||||||
See [README.md](README.md) for the complete reference.
|
```
|
||||||
|
Ctrl+h/j/k/l splits + tmux panes
|
||||||
|
,h / ,l prev / next buffer
|
||||||
|
,z maximize window
|
||||||
|
,tv / ,th terminal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Write prose
|
||||||
|
|
||||||
|
```
|
||||||
|
,zen zen mode (Goyo + Limelight)
|
||||||
|
,mp markdown preview in browser
|
||||||
|
,mt table of contents
|
||||||
|
```
|
||||||
|
|
||||||
|
See [README](README.md) for the full reference. See the [wiki](https://github.com/m1ngsama/chopsticks/wiki) for deep dives.
|
||||||
|
|
|
||||||
540
README.md
540
README.md
|
|
@ -1,14 +1,22 @@
|
||||||
# chopsticks
|
<p align="center">
|
||||||
|
<img src=".github/demo.gif" alt="chopsticks demo" width="720">
|
||||||
|
</p>
|
||||||
|
|
||||||
> Flowing vim for any machine — SSH servers included.
|
<h1 align="center">chopsticks</h1>
|
||||||
> Solarized · vim-lsp (no Node.js) · Markdown-first · One-command install.
|
|
||||||
|
|
||||||
[](LICENSE)
|
<p align="center">
|
||||||
[](https://www.vim.org/)
|
<strong>Vim for engineers. 29 plugins, 19ms startup, works over SSH.</strong>
|
||||||
[](#installation)
|
</p>
|
||||||
[](https://github.com/m1ngsama/chopsticks/releases)
|
|
||||||
[](https://github.com/m1ngsama/chopsticks/commits/main)
|
<p align="center">
|
||||||
[](https://github.com/m1ngsama/chopsticks/stargazers)
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="MIT License"></a>
|
||||||
|
<a href="https://www.vim.org/"><img src="https://img.shields.io/badge/Vim-8.0%2B-brightgreen?style=flat-square" alt="Vim 8.0+"></a>
|
||||||
|
<a href="#install"><img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux-lightgrey?style=flat-square" alt="Platform"></a>
|
||||||
|
<a href="https://github.com/m1ngsama/chopsticks/actions"><img src="https://img.shields.io/github/actions/workflow/status/m1ngsama/chopsticks/test.yml?style=flat-square&label=tests" alt="Tests"></a>
|
||||||
|
<a href="https://github.com/m1ngsama/chopsticks/releases"><img src="https://img.shields.io/github/v/release/m1ngsama/chopsticks?style=flat-square&color=orange" alt="Release"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||||
|
|
@ -16,437 +24,157 @@ curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | b
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contents
|
## Why
|
||||||
|
|
||||||
- [Design Principles](#design-principles)
|
You SSH into a server. You need to edit code. You want LSP, fuzzy find, git integration, format-on-save — not a 20-minute setup.
|
||||||
- [Requirements](#requirements)
|
|
||||||
- [Installation](#installation)
|
|
||||||
- [LSP](#lsp)
|
|
||||||
- [Key Mappings](#key-mappings)
|
|
||||||
- [Markdown](#markdown)
|
|
||||||
- [Features](#features)
|
|
||||||
- [Plugins](#plugins)
|
|
||||||
- [Customization](#customization)
|
|
||||||
- [Troubleshooting](#troubleshooting)
|
|
||||||
|
|
||||||
---
|
chopsticks gives you a production-ready Vim config in one command. Pure VimScript — no Node.js for the core. Degrades gracefully on TTY. Works the same on your MacBook and your headless Arch box.
|
||||||
|
|
||||||
## Design Principles
|
**19ms startup** with 29 plugins, LSP, linting, and a hand-built statusline. Faster than most people's empty vimrc.
|
||||||
|
|
||||||
| Principle | What it means |
|
## What's in the box
|
||||||
|-----------|--------------|
|
|
||||||
| **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 |
|
|
||||||
|
|
||||||
---
|
| | |
|
||||||
|
|-|-|
|
||||||
|
| **LSP** | completion, go-to-def, hover, rename, code actions — pure VimScript ([vim-lsp](https://github.com/prabirshrestha/vim-lsp)) |
|
||||||
|
| **Lint + format** | [ALE](https://github.com/dense-analysis/ale) runs black, prettier, gofmt, rustfmt on save |
|
||||||
|
| **Fuzzy find** | files, buffers, grep, tags, marks, commands — [FZF](https://github.com/junegunn/fzf.vim) |
|
||||||
|
| **Git** | status, diff, blame, push, pull, conflict markers — [fugitive](https://github.com/tpope/vim-fugitive) + [gitgutter](https://github.com/airblade/vim-gitgutter) |
|
||||||
|
| **Zen mode** | `,zen` — [Goyo](https://github.com/junegunn/goyo.vim) + [Limelight](https://github.com/junegunn/limelight.vim) |
|
||||||
|
| **Run file** | `,cr` — auto-detects Python, Go, Rust, JS, C, Shell, and more |
|
||||||
|
| **TTY-aware** | degrades gracefully on SSH, console, slow links — never breaks |
|
||||||
|
| **19ms startup** | lazy-loaded plugins, deferred LSP init, zero redundant work |
|
||||||
|
|
||||||
## Requirements
|
## Install
|
||||||
|
|
||||||
| 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.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### One command
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Non-interactive / CI:
|
Or manually:
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
|
||||||
```
|
|
||||||
|
|
||||||
### Git clone
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||||
cd ~/.vim && ./install.sh
|
cd ~/.vim && ./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### What the installer does
|
Supports macOS (brew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf).
|
||||||
|
|
||||||
1. Detects OS and package manager
|
First launch installs plugins automatically (30-60s). Restart vim when done.
|
||||||
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 npm formatters (prettier, eslint, etc.) — requires Node.js
|
|
||||||
7. Offers to install Python formatters/linters (black, isort, flake8, etc.)
|
|
||||||
8. Offers to install Go tools (gopls, goimports, staticcheck)
|
|
||||||
9. Offers to append vim-tmux-navigator bindings to `~/.tmux.conf`
|
|
||||||
|
|
||||||
**Supported platforms:** macOS (Homebrew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf).
|
## Keys
|
||||||
|
|
||||||
---
|
Leader: `,` — press `,?` for the full cheat sheet inside vim.
|
||||||
|
|
||||||
|
```
|
||||||
|
Ctrl+p fuzzy find file gd go to definition
|
||||||
|
,rg ripgrep project K hover docs
|
||||||
|
,gs git status ,cr run current file
|
||||||
|
,zen zen mode ,f format
|
||||||
|
,w save ,q quit
|
||||||
|
jk exit insert mode ,? cheat sheet
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>All keybindings</strong></summary>
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
`Ctrl+p` find | `,b` buffers | `,rg` grep | `,rG` grep word | `,fh` recent | `,e` browser | `,,` last file
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
`gd` def | `gy` type | `gi` impl | `gr` refs | `K` docs | `[g` `]g` diagnostics | `,rn` rename | `,ca` action | `,o` outline | `,cr` run
|
||||||
|
|
||||||
|
### Edit
|
||||||
|
|
||||||
|
`s`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word
|
||||||
|
|
||||||
|
### Git
|
||||||
|
|
||||||
|
`,gs` status | `,gd` diff | `,gb` blame | `,gc` commit | `,gp` push | `]x` `[x` conflict
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
`Ctrl+hjkl` navigate (+ tmux) | `,z` maximize | `,h` `,l` buffers | `,tv` terminal | `Esc Esc` exit terminal
|
||||||
|
|
||||||
|
### Writing
|
||||||
|
|
||||||
|
`,zen` zen mode | `,mp` markdown preview | `,mt` table of contents
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## LSP
|
## LSP
|
||||||
|
|
||||||
Code intelligence is provided by **vim-lsp** — a pure VimScript LSP client with no
|
```vim
|
||||||
Node.js dependency. It works on any machine, including servers accessed via SSH.
|
:LspInstallServer " auto-detects filetype
|
||||||
|
:LspStatus " check what's running
|
||||||
|
```
|
||||||
|
|
||||||
Install a language server for the current file:
|
pylsp, gopls, rust-analyzer, clangd, marksman, sqls — no Node.js. JS/TS servers need Node.
|
||||||
|
|
||||||
|
ALE and vim-lsp coexist cleanly (`ale_disable_lsp=1`). ALE handles linting + formatting. vim-lsp handles everything else.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.vim/
|
||||||
|
├── .vimrc thin loader (12 lines)
|
||||||
|
├── modules/
|
||||||
|
│ ├── env.vim TTY detection, truecolor
|
||||||
|
│ ├── plugins.vim vim-plug + 29 plugins
|
||||||
|
│ ├── core.vim settings, keymaps, performance
|
||||||
|
│ ├── ui.vim solarized, statusline, startify
|
||||||
|
│ ├── editing.vim easymotion, yank highlight
|
||||||
|
│ ├── navigation.vim fzf, netrw, windows, terminal
|
||||||
|
│ ├── lsp.vim vim-lsp, asyncomplete
|
||||||
|
│ ├── lint.vim ale, format-on-save
|
||||||
|
│ ├── git.vim fugitive, gitgutter
|
||||||
|
│ ├── writing.vim markdown, previm, zen mode
|
||||||
|
│ ├── languages.vim vim-go, filetype settings
|
||||||
|
│ └── tools.vim cheat sheet, run file, helpers
|
||||||
|
└── tutor/
|
||||||
|
└── chopsticks.tutor
|
||||||
|
```
|
||||||
|
|
||||||
|
Each module is self-contained. Comment out one line in `.vimrc` to disable it. Add your own with `call s:load('mine')`.
|
||||||
|
|
||||||
|
## Learn
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
:LspInstallServer " auto-detects filetype and installs the correct server
|
:ChopsticksLearn " interactive tutorial — 10 lessons
|
||||||
:LspStatus " check server status
|
,? " cheat sheet (every binding)
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported languages and their servers:
|
## Performance
|
||||||
|
|
||||||
| Language | Server |
|
| Metric | Value |
|
||||||
|----------|--------|
|
|--------|-------|
|
||||||
| Python | pylsp / pyright |
|
| Startup time | **19ms** (29 plugins loaded) |
|
||||||
| JavaScript / TypeScript | typescript-language-server |
|
| Lazy-loaded | 8 plugins (on command or filetype) |
|
||||||
| Go | gopls |
|
| Built-in plugins skipped | 10 (gzip, tar, zip, vimball, etc.) |
|
||||||
| Rust | rust-analyzer |
|
| Runtime lint delay | 200ms (no thrashing during edits) |
|
||||||
| C / C++ | clangd |
|
| Large file threshold | 10MB (auto-disables syntax + undo) |
|
||||||
| Shell | bash-language-server |
|
| TTY large file | 500KB (syntax disabled) |
|
||||||
| HTML | vscode-html-language-server |
|
|
||||||
| CSS / SCSS | vscode-css-language-server |
|
Measured with `vim --startuptime`. We benchmark every change.
|
||||||
| JSON | vscode-json-language-server |
|
|
||||||
| YAML | yaml-language-server |
|
|
||||||
| Markdown | marksman |
|
|
||||||
| SQL | sqls |
|
|
||||||
|
|
||||||
**Note:** While vim-lsp itself needs no Node.js, some language servers (TypeScript,
|
|
||||||
HTML, CSS, JSON, YAML) are npm packages that require Node.js to run. Python (pylsp),
|
|
||||||
Go (gopls), and Rust (rust-analyzer) language servers do not need Node.js.
|
|
||||||
|
|
||||||
**Markdown LSP** requires `marksman` as a standalone binary:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install marksman # macOS
|
|
||||||
sudo pacman -S marksman # Arch
|
|
||||||
# or: install.sh handles it automatically
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key Mappings
|
|
||||||
|
|
||||||
**Leader key:** `,` (comma)
|
|
||||||
|
|
||||||
Press `,?` at any time to open the built-in cheat sheet.
|
|
||||||
|
|
||||||
### Files and Buffers
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `Ctrl+p` | Fuzzy file search — git-aware (FZF) |
|
|
||||||
| `,e` | Open netrw file browser |
|
|
||||||
| `,E` | Open netrw in vertical split |
|
|
||||||
| `,b` | Search open buffers (FZF) |
|
|
||||||
| `,rg` | Project-wide search (ripgrep + FZF) |
|
|
||||||
| `,rG` | Ripgrep word under cursor (fixed-string) |
|
|
||||||
| `,,` | Switch to last file |
|
|
||||||
| `,l` / `,h` | Next / previous buffer |
|
|
||||||
| `,bd` | Close current buffer (preserves window layout) |
|
|
||||||
| `,wa` | Save all open buffers |
|
|
||||||
| `,cd` | Change working directory to current file's directory |
|
|
||||||
|
|
||||||
### Code Intelligence (vim-lsp)
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `gd` | Go to definition |
|
|
||||||
| `gy` | Go to type definition |
|
|
||||||
| `gi` | Go to implementation |
|
|
||||||
| `gr` | Show references |
|
|
||||||
| `K` | Hover documentation |
|
|
||||||
| `[g` / `]g` | Previous / next LSP diagnostic |
|
|
||||||
| `[e` / `]e` | Previous / next ALE error |
|
|
||||||
| `,rn` | Rename symbol |
|
|
||||||
| `,f` | Format buffer / selection |
|
|
||||||
| `,ca` | Code action |
|
|
||||||
| `,o` | File outline (symbols) |
|
|
||||||
| `,ws` | Workspace symbols |
|
|
||||||
| `Tab` / `Shift+Tab` | Navigate completion popup |
|
|
||||||
| `Enter` | Confirm completion |
|
|
||||||
|
|
||||||
### Markdown
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `,mp` | Open live preview in browser (previm) |
|
|
||||||
| `,mt` | Table of contents (side window) |
|
|
||||||
| `zr` / `zm` | Unfold / fold all headings |
|
|
||||||
|
|
||||||
### Git (vim-fugitive)
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `,gs` | Git status |
|
|
||||||
| `,gc` | Git commit |
|
|
||||||
| `,gp` | Git push |
|
|
||||||
| `,gl` | Git pull |
|
|
||||||
| `,gd` | Git diff |
|
|
||||||
| `,gb` | Git blame |
|
|
||||||
|
|
||||||
### 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 |
|
|
||||||
| `Ctrl+d` / `Ctrl+u` | Half-page scroll, cursor centred |
|
|
||||||
| `Alt+j` / `Alt+k` | Move line down / up (normal and visual) |
|
|
||||||
| `,u` | Undo tree (visual branch history) |
|
|
||||||
| `F2` | Toggle paste mode |
|
|
||||||
| `F3` / `F4` | Toggle line numbers / relative numbers |
|
|
||||||
| `F5` | Toggle undo tree |
|
|
||||||
| `F6` | Toggle invisible characters |
|
|
||||||
| `gV` | Reselect last paste |
|
|
||||||
| `//` | Search visual selection |
|
|
||||||
|
|
||||||
### Survival
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `jk` | Exit insert mode |
|
|
||||||
| `Esc` | Exit insert / visual mode |
|
|
||||||
| `jk` | Exit insert mode |
|
|
||||||
| `Ctrl+s` | Save (any mode) |
|
|
||||||
| `,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 |
|
|
||||||
| `,ev` / `,sv` | Edit / reload `~/.vimrc` |
|
|
||||||
| `,cp` / `,cf` | Copy file path / filename to clipboard |
|
|
||||||
| `,*` | Search and replace word under cursor |
|
|
||||||
| `,F` | Re-indent entire file |
|
|
||||||
| `,W` | Strip trailing whitespace |
|
|
||||||
| `,ms` | Open scratch markdown buffer |
|
|
||||||
| `,ss` | Toggle spell checking |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 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 side window — press Enter to jump to heading
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### Statusline
|
|
||||||
|
|
||||||
A native, hand-written statusline using the Solarized palette:
|
|
||||||
|
|
||||||
```
|
|
||||||
N ~/.vimrc [+] main [vim] 42:7 68%
|
|
||||||
```
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:Obsess " start tracking the current session
|
|
||||||
:Obsess! " stop tracking
|
|
||||||
```
|
|
||||||
|
|
||||||
Sessions auto-restore when you open Vim in the same directory.
|
|
||||||
|
|
||||||
### Project-Local Config
|
|
||||||
|
|
||||||
Drop a `.vimrc` in any project root to override settings:
|
|
||||||
|
|
||||||
```vim
|
|
||||||
" my-project/.vimrc
|
|
||||||
set shiftwidth=2
|
|
||||||
let g:ale_python_black_options = '--line-length=100'
|
|
||||||
```
|
|
||||||
|
|
||||||
### tmux Integration
|
|
||||||
|
|
||||||
`Ctrl+h/j/k/l` navigates seamlessly between Vim splits and tmux panes.
|
|
||||||
|
|
||||||
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)?$'"
|
|
||||||
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
|
|
||||||
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
|
|
||||||
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'
|
|
||||||
```
|
|
||||||
|
|
||||||
### TTY / SSH Support
|
|
||||||
|
|
||||||
Detected automatically when `$TERM` is unset, `dumb`, `linux`, `screen`, or contains `builtin`. 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 stalling.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Plugins
|
|
||||||
|
|
||||||
### Navigation
|
|
||||||
- **fzf + fzf.vim** — fuzzy finder for files, buffers, tags, ripgrep
|
|
||||||
|
|
||||||
### Git
|
|
||||||
- **vim-fugitive** — full Git integration
|
|
||||||
- **vim-gitgutter** — diff signs in the sign column
|
|
||||||
|
|
||||||
### LSP and Completion
|
|
||||||
- **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 and Formatting
|
|
||||||
- **ALE** — async linting and format-on-save
|
|
||||||
|
|
||||||
### 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/delete/add surroundings
|
|
||||||
- **vim-commentary** — `gc` to toggle comments
|
|
||||||
- **vim-repeat** — repeat plugin maps with `.`
|
|
||||||
- **vim-unimpaired** — bracket shortcut pairs
|
|
||||||
- **targets.vim** — additional text objects
|
|
||||||
- **auto-pairs** — auto-close brackets and quotes
|
|
||||||
- **vim-easymotion** — `s` + 2 chars to jump anywhere
|
|
||||||
|
|
||||||
### UI
|
|
||||||
- **vim-colors-solarized** — color scheme
|
|
||||||
- **undotree** — visual undo branch history
|
|
||||||
- **vim-startify** — startup dashboard and session list
|
|
||||||
- **indentLine** — indent guides (non-TTY)
|
|
||||||
|
|
||||||
### Session and Navigation
|
|
||||||
- **vim-obsession** — session tracking
|
|
||||||
- **vim-tmux-navigator** — seamless Vim/tmux pane navigation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
### Per-project overrides
|
|
||||||
|
|
||||||
Create `.vimrc` in your project root:
|
|
||||||
|
|
||||||
```vim
|
|
||||||
" project/.vimrc
|
|
||||||
set shiftwidth=2
|
|
||||||
let g:ale_python_black_options = '--line-length=120'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Modify keybindings
|
|
||||||
|
|
||||||
Edit `~/.vimrc` directly (`,ev` opens it from inside Vim). Reload with `,sv`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
**Plugins not loading**
|
| Problem | Fix |
|
||||||
|
|---------|-----|
|
||||||
|
| Plugins not loading | `:PlugInstall` then `:PlugUpdate` |
|
||||||
|
| LSP not starting | `:LspInstallServer` for current filetype |
|
||||||
|
| Colors wrong | `export COLORTERM=truecolor` in shell rc |
|
||||||
|
| `Ctrl+s` freezes | `stty -ixon` in shell rc |
|
||||||
|
| Everything slow | Large file? Auto-disabled >10MB |
|
||||||
|
|
||||||
```vim
|
More in the [wiki](https://github.com/m1ngsama/chopsticks/wiki).
|
||||||
:PlugInstall " install missing plugins
|
|
||||||
:PlugUpdate " update all plugins
|
|
||||||
```
|
|
||||||
|
|
||||||
**LSP server not starting**
|
## Contributing
|
||||||
|
|
||||||
```vim
|
See [CONTRIBUTING.md](CONTRIBUTING.md). The two rules that matter: no Node.js dependencies, and don't regress startup time.
|
||||||
:LspInstallServer " install server for current filetype
|
|
||||||
:LspStatus " check server status
|
|
||||||
```
|
|
||||||
|
|
||||||
**Markdown preview not opening**
|
|
||||||
|
|
||||||
`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
|
|
||||||
```
|
|
||||||
|
|
||||||
**ALE linters not found**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
which flake8 black prettier eslint # verify tools are on PATH
|
|
||||||
```
|
|
||||||
|
|
||||||
**`Ctrl+s` freezes the terminal**
|
|
||||||
|
|
||||||
Add `stty -ixon` to your `~/.bashrc`, `~/.zshrc`, or `~/.config/fish/config.fish`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE) © m1ng
|
[MIT](LICENSE)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"languageserver": {
|
|
||||||
"marksman": {
|
|
||||||
"command": "marksman",
|
|
||||||
"args": ["server"],
|
|
||||||
"filetypes": ["markdown"],
|
|
||||||
"rootPatterns": [".git", ".marksman.toml"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
install.sh
14
install.sh
|
|
@ -380,18 +380,6 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$HOME/.vim"
|
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 → $COC_CFG.backup.$TS"
|
|
||||||
mv "$COC_CFG" "$COC_CFG.backup.$TS"
|
|
||||||
fi
|
|
||||||
ln -sf "$SCRIPT_DIR/coc-settings.json" "$COC_CFG"
|
|
||||||
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
|
# 3. vim-plug + Plugins
|
||||||
|
|
@ -441,7 +429,7 @@ fi
|
||||||
_vim_run +'PlugClean!' +qall || true # remove plugins no longer in vimrc; ignore exit code (none expected)
|
_vim_run +'PlugClean!' +qall || true # remove plugins no longer in vimrc; ignore exit code (none expected)
|
||||||
_vim_run +'PlugInstall --sync' +qall || true # fzf post-install hook may exit non-zero; harmless
|
_vim_run +'PlugInstall --sync' +qall || true # fzf post-install hook may exit non-zero; harmless
|
||||||
|
|
||||||
_plug_count=$(ls -1 "$HOME/.vim/plugged" 2>/dev/null | wc -l | tr -d ' ')
|
_plug_count=$(find "$HOME/.vim/plugged" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')
|
||||||
if [[ $_plug_count -eq 0 ]]; then
|
if [[ $_plug_count -eq 0 ]]; then
|
||||||
die "Plugin installation failed — ~/.vim/plugged is empty. Check network and retry."
|
die "Plugin installation failed — ~/.vim/plugged is empty. Check network and retry."
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
216
modules/core.vim
Normal file
216
modules/core.vim
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
" core.vim — general settings, basic keymaps, performance, indentation
|
||||||
|
" filetype/syntax already enabled by plug#end() in plugins.vim
|
||||||
|
|
||||||
|
set number
|
||||||
|
set relativenumber
|
||||||
|
|
||||||
|
if !g:is_tty
|
||||||
|
set cursorline
|
||||||
|
endif
|
||||||
|
|
||||||
|
set nobackup
|
||||||
|
set scrolloff=10
|
||||||
|
set nowrap
|
||||||
|
set incsearch
|
||||||
|
set ignorecase
|
||||||
|
set smartcase
|
||||||
|
set showcmd
|
||||||
|
set showmode
|
||||||
|
set hlsearch
|
||||||
|
set history=1000
|
||||||
|
set wildmenu
|
||||||
|
set wildmode=list:longest
|
||||||
|
set wildignorecase
|
||||||
|
set wildignore=*.docx,*.jpg,*.png,*.gif,*.pdf,*.pyc,*.exe,*.flv,*.img,*.xlsx
|
||||||
|
set wildignore+=*/node_modules/*,*/.git/*,*/__pycache__/*,*/dist/*,*/build/*
|
||||||
|
set mouse=a
|
||||||
|
set encoding=utf-8
|
||||||
|
set foldmethod=indent
|
||||||
|
set foldlevel=99
|
||||||
|
set splitbelow
|
||||||
|
set splitright
|
||||||
|
set backspace=indent,eol,start
|
||||||
|
set nrformats-=octal
|
||||||
|
set autoread
|
||||||
|
set cmdheight=1
|
||||||
|
set hidden
|
||||||
|
set whichwrap+=<,>,h,l
|
||||||
|
set magic
|
||||||
|
set showmatch
|
||||||
|
set mat=2
|
||||||
|
set noerrorbells
|
||||||
|
set novisualbell
|
||||||
|
set t_vb=
|
||||||
|
set ttimeout
|
||||||
|
set ttimeoutlen=10
|
||||||
|
|
||||||
|
if $COLORTERM ==# 'gnome-terminal'
|
||||||
|
set t_Co=256
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has("gui_running")
|
||||||
|
set guioptions-=T
|
||||||
|
set guioptions-=e
|
||||||
|
set t_Co=256
|
||||||
|
set guitablabel=%M\ %t
|
||||||
|
endif
|
||||||
|
|
||||||
|
set display+=lastline
|
||||||
|
set ffs=unix,dos,mac
|
||||||
|
set nowb
|
||||||
|
set noswapfile
|
||||||
|
|
||||||
|
if has('persistent_undo')
|
||||||
|
set undofile
|
||||||
|
let &undodir = expand('~/.vim/.undo')
|
||||||
|
silent! call mkdir(&undodir, 'p', 0700)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Text, Tab and Indent ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
set listchars=tab:>-,trail:.,extends:>,precedes:<,nbsp:_
|
||||||
|
else
|
||||||
|
set listchars=tab:→\ ,trail:·,extends:▸,precedes:◂,nbsp:·
|
||||||
|
endif
|
||||||
|
|
||||||
|
set expandtab
|
||||||
|
set smarttab
|
||||||
|
set shiftwidth=4
|
||||||
|
set tabstop=4
|
||||||
|
set lbr
|
||||||
|
set tw=0
|
||||||
|
set autoindent
|
||||||
|
set smartindent
|
||||||
|
|
||||||
|
" ── Leader ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
let mapleader = ","
|
||||||
|
|
||||||
|
" ── Basic Keymaps ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
nnoremap <leader>w :w!<cr>
|
||||||
|
nnoremap <leader>q :q<cr>
|
||||||
|
nnoremap <leader>x :x<cr>
|
||||||
|
|
||||||
|
nnoremap <silent> <leader><cr> :noh<cr>
|
||||||
|
|
||||||
|
nnoremap <leader>bd :Bclose<cr>
|
||||||
|
nnoremap <leader>ba :bufdo bd<cr>
|
||||||
|
nnoremap <leader>l :bnext<cr>
|
||||||
|
nnoremap <leader>h :bprevious<cr>
|
||||||
|
|
||||||
|
nnoremap <leader>tn :tabnew<cr>
|
||||||
|
nnoremap <leader>to :tabonly<cr>
|
||||||
|
nnoremap <leader>tc :tabclose<cr>
|
||||||
|
nnoremap <leader>tm :tabmove
|
||||||
|
nnoremap <leader>t<leader> :tabnext<cr>
|
||||||
|
|
||||||
|
let g:lasttab = 1
|
||||||
|
nnoremap <Leader>tl :exe "tabn ".g:lasttab<CR>
|
||||||
|
augroup ChopstickTabHistory
|
||||||
|
autocmd!
|
||||||
|
autocmd TabLeave * let g:lasttab = tabpagenr()
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
nnoremap <leader>te :tabedit <C-r>=expand("%:p:h")<cr>/
|
||||||
|
nnoremap <leader>cd :lcd %:p:h<cr>:pwd<cr>
|
||||||
|
|
||||||
|
nnoremap 0 ^
|
||||||
|
nnoremap gV `[v`]
|
||||||
|
|
||||||
|
cnoremap <C-p> <Up>
|
||||||
|
cnoremap <C-n> <Down>
|
||||||
|
|
||||||
|
nnoremap <M-j> :m .+1<CR>==
|
||||||
|
nnoremap <M-k> :m .-2<CR>==
|
||||||
|
vnoremap <M-j> :m '>+1<CR>gv=gv
|
||||||
|
vnoremap <M-k> :m '<-2<CR>gv=gv
|
||||||
|
|
||||||
|
nnoremap <leader>ss :setlocal spell!<cr>
|
||||||
|
nnoremap <leader>sn ]s
|
||||||
|
nnoremap <leader>sp [s
|
||||||
|
nnoremap <leader>sa zg
|
||||||
|
nnoremap <leader>s? z=
|
||||||
|
|
||||||
|
set pastetoggle=<F2>
|
||||||
|
nnoremap <F3> :set invnumber<CR>
|
||||||
|
nnoremap <F4> :set invrelativenumber<CR>
|
||||||
|
nnoremap <F6> :set list!<CR>
|
||||||
|
|
||||||
|
nnoremap <space> za
|
||||||
|
|
||||||
|
nnoremap Y y$
|
||||||
|
nnoremap Q <nop>
|
||||||
|
|
||||||
|
inoremap jk <Esc>
|
||||||
|
|
||||||
|
vnoremap < <gv
|
||||||
|
vnoremap > >gv
|
||||||
|
|
||||||
|
nnoremap n nzzzv
|
||||||
|
nnoremap N Nzzzv
|
||||||
|
|
||||||
|
vnoremap // y/\V<C-r>=escape(@",'/\')<CR><CR>
|
||||||
|
|
||||||
|
nnoremap <silent> <C-s> :w<CR>
|
||||||
|
inoremap <silent> <C-s> <C-o>:w<CR>
|
||||||
|
|
||||||
|
nnoremap <C-d> <C-d>zz
|
||||||
|
nnoremap <C-u> <C-u>zz
|
||||||
|
|
||||||
|
if has('clipboard')
|
||||||
|
nnoremap <leader>y "+y
|
||||||
|
vnoremap <leader>y "+y
|
||||||
|
nnoremap <leader>Y "+Y
|
||||||
|
nnoremap <leader>p "+p
|
||||||
|
nnoremap <leader>P "+P
|
||||||
|
endif
|
||||||
|
|
||||||
|
nnoremap <leader>qo :copen<CR>
|
||||||
|
nnoremap <leader>qc :cclose<CR>
|
||||||
|
|
||||||
|
augroup ChopstickResize
|
||||||
|
autocmd!
|
||||||
|
autocmd VimResized * wincmd =
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
" ── Performance ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
set synmaxcol=200
|
||||||
|
set ttyfast
|
||||||
|
set lazyredraw
|
||||||
|
set complete-=i
|
||||||
|
set updatetime=300
|
||||||
|
set shortmess+=cI
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
set signcolumn=auto
|
||||||
|
set synmaxcol=120
|
||||||
|
else
|
||||||
|
if has("patch-8.1.1564")
|
||||||
|
set signcolumn=number
|
||||||
|
else
|
||||||
|
set signcolumn=yes
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Project-Local Config ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
set exrc
|
||||||
|
set secure
|
||||||
|
set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal
|
||||||
|
|
||||||
|
" ── Format Options ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
augroup ChopstickFormatOptions
|
||||||
|
autocmd!
|
||||||
|
autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o formatoptions+=j
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
augroup ChopstickPaste
|
||||||
|
autocmd!
|
||||||
|
autocmd InsertLeave * set nopaste
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
set timeoutlen=500
|
||||||
46
modules/editing.vim
Normal file
46
modules/editing.vim
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
" editing.vim — EasyMotion, yank highlight, search auto-clear, undotree
|
||||||
|
|
||||||
|
" ── EasyMotion ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
let g:EasyMotion_do_mapping = 0
|
||||||
|
let g:EasyMotion_smartcase = 1
|
||||||
|
|
||||||
|
if exists('g:plugs["vim-easymotion"]')
|
||||||
|
nmap s <Plug>(easymotion-overwin-f2)
|
||||||
|
nmap <Leader>j <Plug>(easymotion-j)
|
||||||
|
nmap <Leader>k <Plug>(easymotion-k)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── UndoTree ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if exists('g:plugs["undotree"]')
|
||||||
|
nnoremap <F5> :UndotreeToggle<CR>
|
||||||
|
nnoremap <leader>u :UndotreeToggle<CR>
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Yank Highlight ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if exists('##TextYankPost') && has('timers')
|
||||||
|
function! s:YankHighlight() abort
|
||||||
|
if v:event.operator !=# 'y' | return | endif
|
||||||
|
let l:m = matchadd('IncSearch',
|
||||||
|
\ printf('\%%>%dl\%%<%dl', line("'[") - 1, line("']") + 1))
|
||||||
|
call timer_start(150, {-> matchdelete(l:m)})
|
||||||
|
endfunction
|
||||||
|
augroup ChopstickYankHL
|
||||||
|
autocmd!
|
||||||
|
autocmd TextYankPost * call s:YankHighlight()
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Blank Line Insertion (replaces vim-unimpaired) ──────────────────────────
|
||||||
|
|
||||||
|
nnoremap <silent> [<Space> :<C-u>put! =repeat(nr2char(10), v:count1)<CR>'[
|
||||||
|
nnoremap <silent> ]<Space> :<C-u>put =repeat(nr2char(10), v:count1)<CR>
|
||||||
|
|
||||||
|
" ── Auto-Clear Search Highlight ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
augroup ChopstickSearchHL
|
||||||
|
autocmd!
|
||||||
|
autocmd CursorHold * if get(v:, 'hlsearch', 0) | let v:hlsearch = 0 | endif
|
||||||
|
augroup END
|
||||||
19
modules/env.vim
Normal file
19
modules/env.vim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
" env.vim — environment detection (must load first)
|
||||||
|
|
||||||
|
set nocompatible
|
||||||
|
|
||||||
|
let g:is_tty = empty($TERM) || $TERM ==# 'dumb' || $TERM =~# 'linux'
|
||||||
|
\ || $TERM =~# 'screen' || &term =~# 'builtin'
|
||||||
|
let g:has_true_color = ($COLORTERM ==# 'truecolor' || $COLORTERM ==# '24bit')
|
||||||
|
|
||||||
|
" Skip built-in plugins we never use
|
||||||
|
let g:loaded_2html_plugin = 1
|
||||||
|
let g:loaded_getscriptPlugin = 1
|
||||||
|
let g:loaded_gzip = 1
|
||||||
|
let g:loaded_logipat = 1
|
||||||
|
let g:loaded_rrhelper = 1
|
||||||
|
let g:loaded_tarPlugin = 1
|
||||||
|
let g:loaded_vimballPlugin = 1
|
||||||
|
let g:loaded_zipPlugin = 1
|
||||||
|
let g:loaded_tutor_mode_plugin = 1
|
||||||
|
let g:loaded_spellfile_plugin = 1
|
||||||
26
modules/git.vim
Normal file
26
modules/git.vim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
" git.vim — Fugitive mappings, GitGutter config, conflict navigation
|
||||||
|
|
||||||
|
" ── GitGutter ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
let g:gitgutter_map_keys = 0
|
||||||
|
let g:gitgutter_sign_added = '+'
|
||||||
|
let g:gitgutter_sign_modified = '~'
|
||||||
|
let g:gitgutter_sign_removed = '-'
|
||||||
|
let g:gitgutter_sign_removed_first_line = '^'
|
||||||
|
let g:gitgutter_sign_modified_removed = '~'
|
||||||
|
|
||||||
|
" ── Fugitive ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if exists('g:plugs["vim-fugitive"]')
|
||||||
|
nnoremap <leader>gs :Git status<CR>
|
||||||
|
nnoremap <leader>gc :Git commit<CR>
|
||||||
|
nnoremap <leader>gp :Git push<CR>
|
||||||
|
nnoremap <leader>gl :Git pull<CR>
|
||||||
|
nnoremap <leader>gd :Gdiffsplit<CR>
|
||||||
|
nnoremap <leader>gb :Git blame<CR>
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Conflict Navigation ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
nnoremap <silent> ]x /^\(<<<<<<<\\|=======\\|>>>>>>>\)<CR>
|
||||||
|
nnoremap <silent> [x ?^\(<<<<<<<\\|=======\\|>>>>>>>\)<CR>
|
||||||
46
modules/languages.vim
Normal file
46
modules/languages.vim
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
" languages.vim — vim-go config, per-filetype autocmds
|
||||||
|
|
||||||
|
" ── vim-go (syntax only — vim-lsp handles intelligence) ─────────────────────
|
||||||
|
|
||||||
|
let g:go_gopls_enabled = 0
|
||||||
|
let g:go_code_completion_enabled = 0
|
||||||
|
let g:go_fmt_autosave = 0
|
||||||
|
let g:go_imports_autosave = 0
|
||||||
|
let g:go_highlight_types = 1
|
||||||
|
let g:go_highlight_fields = 1
|
||||||
|
let g:go_highlight_functions = 1
|
||||||
|
let g:go_highlight_function_calls = 1
|
||||||
|
|
||||||
|
" ── Filetype Detection ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
augroup ChopstickFiletype
|
||||||
|
autocmd!
|
||||||
|
|
||||||
|
autocmd BufReadPost *
|
||||||
|
\ if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
|
||||||
|
|
||||||
|
autocmd FileType python
|
||||||
|
\ setlocal expandtab shiftwidth=4 tabstop=4 textwidth=88 colorcolumn=+1
|
||||||
|
autocmd FileType javascript,typescript
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2 textwidth=100 colorcolumn=+1
|
||||||
|
autocmd FileType go
|
||||||
|
\ setlocal noexpandtab shiftwidth=4 tabstop=4 textwidth=120 colorcolumn=+1
|
||||||
|
autocmd FileType rust
|
||||||
|
\ setlocal expandtab shiftwidth=4 tabstop=4 textwidth=100 colorcolumn=+1
|
||||||
|
autocmd FileType c,cpp
|
||||||
|
\ setlocal expandtab shiftwidth=4 tabstop=4 textwidth=80 colorcolumn=+1
|
||||||
|
autocmd FileType html,css
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
autocmd FileType yaml
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
autocmd FileType markdown
|
||||||
|
\ setlocal wrap linebreak spell textwidth=0 colorcolumn=0 conceallevel=2
|
||||||
|
autocmd FileType sh
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2 textwidth=80 colorcolumn=+1
|
||||||
|
autocmd FileType make
|
||||||
|
\ setlocal noexpandtab shiftwidth=8 tabstop=8
|
||||||
|
autocmd FileType json
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
autocmd FileType dockerfile
|
||||||
|
\ setlocal expandtab shiftwidth=2 tabstop=2
|
||||||
|
augroup END
|
||||||
53
modules/lint.vim
Normal file
53
modules/lint.vim
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
" lint.vim — ALE async linting and format-on-save
|
||||||
|
|
||||||
|
let g:ale_disable_lsp = 1
|
||||||
|
|
||||||
|
let g:ale_linters = {
|
||||||
|
\ 'python': ['flake8', 'pylint'],
|
||||||
|
\ 'javascript': ['eslint'],
|
||||||
|
\ 'typescript': ['eslint'],
|
||||||
|
\ 'go': ['staticcheck'],
|
||||||
|
\ 'rust': ['cargo'],
|
||||||
|
\ 'c': ['cc'],
|
||||||
|
\ 'sh': ['shellcheck'],
|
||||||
|
\ 'yaml': ['yamllint'],
|
||||||
|
\ 'dockerfile': ['hadolint'],
|
||||||
|
\ 'css': ['stylelint'],
|
||||||
|
\ 'scss': ['stylelint'],
|
||||||
|
\ 'markdown': ['markdownlint'],
|
||||||
|
\ 'sql': ['sqlfluff'],
|
||||||
|
\}
|
||||||
|
|
||||||
|
let g:ale_fixers = {
|
||||||
|
\ '*': ['remove_trailing_lines', 'trim_whitespace'],
|
||||||
|
\ 'python': ['black', 'isort'],
|
||||||
|
\ 'javascript': ['prettier', 'eslint'],
|
||||||
|
\ 'typescript': ['prettier', 'eslint'],
|
||||||
|
\ 'go': ['goimports'],
|
||||||
|
\ 'rust': ['rustfmt'],
|
||||||
|
\ 'c': ['clang-format'],
|
||||||
|
\ 'json': ['prettier'],
|
||||||
|
\ 'yaml': ['prettier'],
|
||||||
|
\ 'html': ['prettier'],
|
||||||
|
\ 'css': ['prettier'],
|
||||||
|
\ 'scss': ['prettier'],
|
||||||
|
\ 'less': ['prettier'],
|
||||||
|
\ 'markdown': ['prettier'],
|
||||||
|
\ 'sql': ['sqlfluff'],
|
||||||
|
\}
|
||||||
|
|
||||||
|
let g:ale_fix_on_save = 1
|
||||||
|
let g:ale_python_isort_options = '--profile black'
|
||||||
|
let g:ale_sign_error = 'X'
|
||||||
|
let g:ale_sign_warning = '!'
|
||||||
|
let g:ale_lint_on_text_changed = 'normal'
|
||||||
|
let g:ale_lint_on_insert_leave = 1
|
||||||
|
let g:ale_lint_on_enter = 1
|
||||||
|
let g:ale_lint_delay = 200
|
||||||
|
let g:ale_echo_delay = 100
|
||||||
|
|
||||||
|
if exists('g:plugs["ale"]')
|
||||||
|
nnoremap <silent> [e :ALEPrevious<cr>
|
||||||
|
nnoremap <silent> ]e :ALENext<cr>
|
||||||
|
nnoremap <silent> <leader>aD :ALEDetail<cr>
|
||||||
|
endif
|
||||||
79
modules/lsp.vim
Normal file
79
modules/lsp.vim
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
" lsp.vim — vim-lsp settings, asyncomplete, LSP buffer keymaps
|
||||||
|
|
||||||
|
let g:lsp_settings_lazyload = 1
|
||||||
|
|
||||||
|
let g:lsp_settings_filetype_python = ['pylsp']
|
||||||
|
let g:lsp_settings_filetype_go = ['gopls']
|
||||||
|
let g:lsp_settings_filetype_rust = ['rust-analyzer']
|
||||||
|
let g:lsp_settings_filetype_typescript = ['typescript-language-server']
|
||||||
|
let g:lsp_settings_filetype_javascript = ['typescript-language-server']
|
||||||
|
let g:lsp_settings_filetype_c = ['clangd']
|
||||||
|
let g:lsp_settings_filetype_sh = ['bash-language-server']
|
||||||
|
let g:lsp_settings_filetype_html = ['vscode-html-language-server']
|
||||||
|
let g:lsp_settings_filetype_css = ['vscode-css-language-server']
|
||||||
|
let g:lsp_settings_filetype_scss = ['vscode-css-language-server']
|
||||||
|
let g:lsp_settings_filetype_json = ['vscode-json-language-server']
|
||||||
|
let g:lsp_settings_filetype_yaml = ['yaml-language-server']
|
||||||
|
let g:lsp_settings_filetype_markdown = ['marksman']
|
||||||
|
let g:lsp_settings_filetype_sql = ['sqls']
|
||||||
|
|
||||||
|
let g:lsp_diagnostics_virtual_text_enabled = !g:is_tty
|
||||||
|
let g:lsp_diagnostics_virtual_text_delay = 200
|
||||||
|
let g:lsp_diagnostics_highlights_enabled = !g:is_tty
|
||||||
|
let g:lsp_document_highlight_enabled = !g:is_tty
|
||||||
|
let g:lsp_document_highlight_delay = 200
|
||||||
|
let g:lsp_signs_enabled = 1
|
||||||
|
let g:lsp_diagnostics_echo_cursor = 1
|
||||||
|
let g:lsp_diagnostics_echo_delay = 100
|
||||||
|
let g:lsp_completion_documentation_enabled = 1
|
||||||
|
|
||||||
|
let g:lsp_signs_error = {'text': 'X'}
|
||||||
|
let g:lsp_signs_warning = {'text': '!'}
|
||||||
|
let g:lsp_signs_information = {'text': 'i'}
|
||||||
|
let g:lsp_signs_hint = {'text': '>'}
|
||||||
|
|
||||||
|
" ── Completion ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if has('patch-8.1.1517')
|
||||||
|
set completeopt=menuone,noinsert,noselect,popup
|
||||||
|
else
|
||||||
|
set completeopt=menuone,noinsert,noselect
|
||||||
|
endif
|
||||||
|
set pumheight=15
|
||||||
|
let g:asyncomplete_auto_popup = 1
|
||||||
|
let g:asyncomplete_auto_completeopt = 0
|
||||||
|
let g:asyncomplete_popup_delay = 50
|
||||||
|
|
||||||
|
inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
|
||||||
|
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
|
||||||
|
inoremap <expr> <CR> pumvisible() ? asyncomplete#close_popup() : "\<CR>"
|
||||||
|
|
||||||
|
" ── Buffer Keymaps ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:on_lsp_buffer_enabled() abort
|
||||||
|
setlocal omnifunc=lsp#complete
|
||||||
|
setlocal signcolumn=yes
|
||||||
|
|
||||||
|
nmap <buffer> gd <plug>(lsp-definition)
|
||||||
|
nmap <buffer> gy <plug>(lsp-type-definition)
|
||||||
|
nmap <buffer> gi <plug>(lsp-implementation)
|
||||||
|
nmap <buffer> gr <plug>(lsp-references)
|
||||||
|
nmap <buffer> [g <plug>(lsp-previous-diagnostic)
|
||||||
|
nmap <buffer> ]g <plug>(lsp-next-diagnostic)
|
||||||
|
|
||||||
|
nmap <buffer> K <plug>(lsp-hover)
|
||||||
|
|
||||||
|
nmap <buffer> <leader>rn <plug>(lsp-rename)
|
||||||
|
nmap <buffer> <leader>ca <plug>(lsp-code-action)
|
||||||
|
nmap <buffer> <leader>f <plug>(lsp-document-format)
|
||||||
|
xmap <buffer> <leader>f <plug>(lsp-document-range-format)
|
||||||
|
|
||||||
|
nmap <buffer> <leader>o <plug>(lsp-document-symbol-search)
|
||||||
|
nmap <buffer> <leader>ws <plug>(lsp-workspace-symbol-search)
|
||||||
|
nmap <buffer> <leader>cD <plug>(lsp-document-diagnostics)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup lsp_install
|
||||||
|
autocmd!
|
||||||
|
autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
|
||||||
|
augroup END
|
||||||
98
modules/navigation.vim
Normal file
98
modules/navigation.vim
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
" navigation.vim — FZF, netrw, buffer/window management, terminal
|
||||||
|
|
||||||
|
" ── netrw (built-in file browser) ───────────────────────────────────────────
|
||||||
|
|
||||||
|
let g:netrw_liststyle = 3
|
||||||
|
let g:netrw_banner = 0
|
||||||
|
let g:netrw_browse_split = 0
|
||||||
|
let g:netrw_winsize = 25
|
||||||
|
let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+'
|
||||||
|
let g:netrw_list_hide .= ',\.pyc$,node_modules,\.git,__pycache__,\.DS_Store'
|
||||||
|
|
||||||
|
nnoremap <leader>e :Explore<CR>
|
||||||
|
nnoremap <leader>E :Vexplore<CR>
|
||||||
|
|
||||||
|
" ── FZF ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:SmartFiles() abort
|
||||||
|
if isdirectory('.git') || finddir('.git', '.;') !=# ''
|
||||||
|
GFiles
|
||||||
|
else
|
||||||
|
Files
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if exists('g:plugs["fzf.vim"]')
|
||||||
|
nnoremap <C-p> :call <SID>SmartFiles()<CR>
|
||||||
|
nnoremap <leader>b :Buffers<CR>
|
||||||
|
nnoremap <leader>rg :Rg<CR>
|
||||||
|
nnoremap <leader>rG :RgWord<CR>
|
||||||
|
nnoremap <leader>rt :Tags<CR>
|
||||||
|
nnoremap <leader>gF :GFiles<CR>
|
||||||
|
nnoremap <leader>fh :History<CR>
|
||||||
|
nnoremap <leader>fc :Commands<CR>
|
||||||
|
nnoremap <leader>fm :Marks<CR>
|
||||||
|
nnoremap <leader>fl :BLines<CR>
|
||||||
|
nnoremap <leader>fL :Lines<CR>
|
||||||
|
nnoremap <leader>f/ :History/<CR>
|
||||||
|
nnoremap <leader>f: :History:<CR>
|
||||||
|
endif
|
||||||
|
|
||||||
|
let g:fzf_layout = { 'down': '40%' }
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
let g:fzf_preview_window = []
|
||||||
|
else
|
||||||
|
let g:fzf_preview_window = ['right:50%', 'ctrl-/']
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
command! -bang -nargs=* Rg
|
||||||
|
\ call fzf#vim#grep(
|
||||||
|
\ 'rg --column --line-number --no-heading --color=always --smart-case -- '
|
||||||
|
\ .shellescape(<q-args>), 1, <bang>0)
|
||||||
|
command! -bang GFiles call fzf#vim#gitfiles('', <bang>0)
|
||||||
|
else
|
||||||
|
command! -bang -nargs=* Rg
|
||||||
|
\ call fzf#vim#grep(
|
||||||
|
\ 'rg --column --line-number --no-heading --color=always --smart-case -- '
|
||||||
|
\ .shellescape(<q-args>), 1, fzf#vim#with_preview(), <bang>0)
|
||||||
|
command! -bang GFiles call fzf#vim#gitfiles('', fzf#vim#with_preview(), <bang>0)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
command! -bang -nargs=* RgWord
|
||||||
|
\ call fzf#vim#grep(
|
||||||
|
\ 'rg --column --line-number --no-heading --color=always --smart-case -F -- '
|
||||||
|
\ .shellescape(expand('<cword>')), 1, <bang>0)
|
||||||
|
else
|
||||||
|
command! -bang -nargs=* RgWord
|
||||||
|
\ call fzf#vim#grep(
|
||||||
|
\ 'rg --column --line-number --no-heading --color=always --smart-case -F -- '
|
||||||
|
\ .shellescape(expand('<cword>')), 1, fzf#vim#with_preview(), <bang>0)
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Window Maximize Toggle ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:ToggleMaximize() abort
|
||||||
|
if exists('t:maximize_session')
|
||||||
|
execute t:maximize_session
|
||||||
|
unlet t:maximize_session
|
||||||
|
else
|
||||||
|
let t:maximize_session = winrestcmd()
|
||||||
|
resize | vertical resize
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
nnoremap <silent> <leader>z :call <SID>ToggleMaximize()<CR>
|
||||||
|
|
||||||
|
" ── Terminal ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if has('terminal')
|
||||||
|
nnoremap <leader>tv :terminal<CR>
|
||||||
|
nnoremap <leader>th :terminal ++rows=10<CR>
|
||||||
|
tnoremap <Esc><Esc> <C-\><C-n>
|
||||||
|
tnoremap <C-h> <C-\><C-n><C-w>h
|
||||||
|
tnoremap <C-j> <C-\><C-n><C-w>j
|
||||||
|
tnoremap <C-k> <C-\><C-n><C-w>k
|
||||||
|
tnoremap <C-l> <C-\><C-n><C-w>l
|
||||||
|
endif
|
||||||
68
modules/plugins.vim
Normal file
68
modules/plugins.vim
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
" plugins.vim — vim-plug declarations
|
||||||
|
|
||||||
|
let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim'
|
||||||
|
if empty(glob(data_dir . '/autoload/plug.vim'))
|
||||||
|
silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs '
|
||||||
|
\ . 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
|
||||||
|
augroup PlugBootstrap
|
||||||
|
autocmd!
|
||||||
|
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
|
||||||
|
call plug#begin('~/.vim/plugged')
|
||||||
|
|
||||||
|
" ── Navigation & Search ──────────────────────────────────────────────────────
|
||||||
|
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||||
|
Plug 'junegunn/fzf.vim'
|
||||||
|
|
||||||
|
" ── Git ──────────────────────────────────────────────────────────────────────
|
||||||
|
Plug 'tpope/vim-fugitive'
|
||||||
|
Plug 'airblade/vim-gitgutter'
|
||||||
|
|
||||||
|
" ── Editing ──────────────────────────────────────────────────────────────────
|
||||||
|
Plug 'tpope/vim-surround'
|
||||||
|
Plug 'tpope/vim-commentary'
|
||||||
|
Plug 'tpope/vim-repeat'
|
||||||
|
" tpope/vim-unimpaired removed: 2.5ms startup cost, we define our own
|
||||||
|
" [q/]q (quickfix), [e/]e (ALE), [x/]x (conflict) — unimpaired's [b/]b
|
||||||
|
" is covered by ,h/,l. Blank line insertion ([<Space>) added below.
|
||||||
|
|
||||||
|
Plug 'tpope/vim-sleuth'
|
||||||
|
Plug 'wellle/targets.vim'
|
||||||
|
Plug 'jiangmiao/auto-pairs'
|
||||||
|
Plug 'easymotion/vim-easymotion', { 'on': '<Plug>(easymotion' }
|
||||||
|
|
||||||
|
" ── Linting & Formatting ────────────────────────────────────────────────────
|
||||||
|
Plug 'dense-analysis/ale'
|
||||||
|
|
||||||
|
" ── LSP + Completion (no Node.js required) ──────────────────────────────────
|
||||||
|
Plug 'prabirshrestha/vim-lsp'
|
||||||
|
Plug 'mattn/vim-lsp-settings'
|
||||||
|
Plug 'prabirshrestha/asyncomplete.vim'
|
||||||
|
Plug 'prabirshrestha/asyncomplete-lsp.vim'
|
||||||
|
|
||||||
|
" ── Language Syntax ──────────────────────────────────────────────────────────
|
||||||
|
Plug 'pangloss/vim-javascript', { 'for': ['javascript', 'javascript.jsx'] }
|
||||||
|
Plug 'HerringtonDarkholme/yats.vim', { 'for': ['typescript', 'typescript.tsx'] }
|
||||||
|
Plug 'preservim/vim-markdown', { 'for': 'markdown' }
|
||||||
|
Plug 'fatih/vim-go', { 'for': 'go' }
|
||||||
|
|
||||||
|
" ── Markdown Preview & Writing ───────────────────────────────────────────────
|
||||||
|
Plug 'previm/previm', { 'on': 'PrevimOpen' }
|
||||||
|
Plug 'junegunn/goyo.vim', { 'on': 'Goyo' }
|
||||||
|
Plug 'junegunn/limelight.vim', { 'on': ['Limelight', 'Limelight!'] }
|
||||||
|
|
||||||
|
" ── UI ───────────────────────────────────────────────────────────────────────
|
||||||
|
Plug 'mbbill/undotree', { 'on': 'UndotreeToggle' }
|
||||||
|
Plug 'mhinz/vim-startify'
|
||||||
|
Plug 'lifepillar/vim-solarized8'
|
||||||
|
if !g:is_tty
|
||||||
|
Plug 'Yggdroot/indentLine'
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Session & Navigation ────────────────────────────────────────────────────
|
||||||
|
Plug 'tpope/vim-obsession'
|
||||||
|
Plug 'christoomey/vim-tmux-navigator'
|
||||||
|
|
||||||
|
call plug#end()
|
||||||
260
modules/tools.vim
Normal file
260
modules/tools.vim
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
" tools.vim — cheat sheet, run file, sudo save, quickfix, helpers
|
||||||
|
|
||||||
|
" ── Helper Functions ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! HasPaste()
|
||||||
|
if &paste | return 'PASTE MODE ' | endif
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
command! Bclose call <SID>BufcloseCloseIt()
|
||||||
|
function! <SID>BufcloseCloseIt()
|
||||||
|
let l:currentBufNum = bufnr("%")
|
||||||
|
let l:alternateBufNum = bufnr("#")
|
||||||
|
if buflisted(l:alternateBufNum)
|
||||||
|
buffer #
|
||||||
|
else
|
||||||
|
bnext
|
||||||
|
endif
|
||||||
|
if bufnr("%") == l:currentBufNum
|
||||||
|
new
|
||||||
|
endif
|
||||||
|
if buflisted(l:currentBufNum)
|
||||||
|
execute("bdelete! " . l:currentBufNum)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
fun! CleanExtraSpaces()
|
||||||
|
let save_cursor = getpos(".")
|
||||||
|
let old_query = getreg('/')
|
||||||
|
silent! %s/\s\+$//e
|
||||||
|
call setpos('.', save_cursor)
|
||||||
|
call setreg('/', old_query)
|
||||||
|
endfun
|
||||||
|
|
||||||
|
function! ToggleNumber()
|
||||||
|
if(&relativenumber == 1)
|
||||||
|
set norelativenumber
|
||||||
|
set number
|
||||||
|
else
|
||||||
|
set relativenumber
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" ── Additional Utilities ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
nnoremap <leader>F gg=G``
|
||||||
|
nnoremap <leader>wa :wa<CR>
|
||||||
|
|
||||||
|
nnoremap <silent> <Leader>= :exe "resize " . (winheight(0) * 3/2)<CR>
|
||||||
|
nnoremap <silent> <Leader>- :exe "resize " . (winheight(0) * 2/3)<CR>
|
||||||
|
nnoremap <silent> <Leader>+ :exe "vertical resize " . (winwidth(0) * 3/2)<CR>
|
||||||
|
nnoremap <silent> <Leader>_ :exe "vertical resize " . (winwidth(0) * 2/3)<CR>
|
||||||
|
|
||||||
|
nnoremap <leader><leader> <c-^>
|
||||||
|
|
||||||
|
nnoremap <leader>W :%s/\s\+$//<CR>:let @/=''<CR>
|
||||||
|
|
||||||
|
nnoremap <leader>so :if &filetype ==# 'vim' <Bar> source % <Bar> echo "Sourced " . expand('%') <Bar> else <Bar> echo "Not a vim file" <Bar> endif<CR>
|
||||||
|
nnoremap <leader>ev :edit $MYVIMRC<CR>
|
||||||
|
nnoremap <leader>sv :source $MYVIMRC<CR>:echo "vimrc reloaded"<CR>
|
||||||
|
|
||||||
|
nnoremap <leader>* :%s/\<<C-r><C-w>\>//g<Left><Left>
|
||||||
|
|
||||||
|
if has('clipboard')
|
||||||
|
nnoremap <leader>cp :let @+ = expand("%:p")<CR>:echo "Copied: " . expand("%:p")<CR>
|
||||||
|
nnoremap <leader>cf :let @+ = expand("%:t")<CR>:echo "Copied: " . expand("%:t")<CR>
|
||||||
|
endif
|
||||||
|
|
||||||
|
nnoremap <leader>ms :e ~/buffer.md<cr>
|
||||||
|
|
||||||
|
" ── Auto-Create Directories ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:MkNonExDir(file, buf)
|
||||||
|
if empty(getbufvar(a:buf, '&buftype')) && a:file !~# '\v^\w+\:\/'
|
||||||
|
let dir = fnamemodify(a:file, ':h')
|
||||||
|
if !isdirectory(dir)
|
||||||
|
call mkdir(dir, 'p')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
augroup BWCCreateDir
|
||||||
|
autocmd!
|
||||||
|
autocmd BufWritePre *
|
||||||
|
\ if !empty(expand('<afile>')) |
|
||||||
|
\ call s:MkNonExDir(expand('<afile>'), +expand('<abuf>')) |
|
||||||
|
\ endif
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
" ── Large File Handling ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
let g:LargeFile = 1024 * 1024 * 10
|
||||||
|
let s:tty_large = g:is_tty ? 512000 : g:LargeFile
|
||||||
|
|
||||||
|
augroup ChopstickLargeFile
|
||||||
|
autocmd!
|
||||||
|
autocmd BufReadPre *
|
||||||
|
\ if !empty(expand('<afile>')) |
|
||||||
|
\ let s:fsize = getfsize(expand('<afile>')) |
|
||||||
|
\ if s:fsize > g:LargeFile || s:fsize == -2 |
|
||||||
|
\ setlocal bufhidden=unload undolevels=-1 noswapfile syntax= |
|
||||||
|
\ let b:ale_enabled = 0 |
|
||||||
|
\ elseif g:is_tty && s:fsize > s:tty_large |
|
||||||
|
\ setlocal syntax= |
|
||||||
|
\ endif |
|
||||||
|
\ endif
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
if g:is_tty && !exists("g:tty_message_shown")
|
||||||
|
augroup TTYMessage
|
||||||
|
autocmd!
|
||||||
|
autocmd VimEnter * echom "TTY mode — visual features disabled"
|
||||||
|
augroup END
|
||||||
|
let g:tty_message_shown = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Run Current File (,cr) ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:RunFile() abort
|
||||||
|
write
|
||||||
|
let l:ft = &filetype
|
||||||
|
let l:file = shellescape(expand('%:p'))
|
||||||
|
if l:ft ==# 'python' | execute '!python3 ' . l:file
|
||||||
|
elseif l:ft ==# 'javascript' | execute '!node ' . l:file
|
||||||
|
elseif l:ft ==# 'typescript' | execute '!npx ts-node ' . l:file
|
||||||
|
elseif l:ft ==# 'go' | execute '!go run ' . l:file
|
||||||
|
elseif l:ft ==# 'rust' | execute '!cargo run'
|
||||||
|
elseif l:ft ==# 'sh' | execute '!bash ' . l:file
|
||||||
|
elseif l:ft ==# 'c' | execute '!gcc -o /tmp/a.out ' . l:file . ' && /tmp/a.out'
|
||||||
|
elseif l:ft ==# 'lua' | execute '!lua ' . l:file
|
||||||
|
elseif l:ft ==# 'ruby' | execute '!ruby ' . l:file
|
||||||
|
elseif l:ft ==# 'perl' | execute '!perl ' . l:file
|
||||||
|
else | echo 'No runner for filetype: ' . l:ft
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
nnoremap <leader>cr :call <SID>RunFile()<CR>
|
||||||
|
|
||||||
|
" ── Sudo Save ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
cnoremap w!! w !sudo tee > /dev/null %
|
||||||
|
|
||||||
|
" ── QuickFix Improvements ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
augroup ChopstickQF
|
||||||
|
autocmd!
|
||||||
|
autocmd QuickFixCmdPost [^l]* cwindow
|
||||||
|
autocmd QuickFixCmdPost l* lwindow
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
nnoremap <silent> ]q :cnext<CR>
|
||||||
|
nnoremap <silent> [q :cprev<CR>
|
||||||
|
|
||||||
|
" ── Debug Helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
nnoremap <leader>sh :call <SID>SynStack()<CR>
|
||||||
|
function! <SID>SynStack()
|
||||||
|
if !exists("*synstack") | return | endif
|
||||||
|
echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" ── Cheat Sheet (,?) ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:CheatSheet() abort
|
||||||
|
let l:name = '__ChopsticksCheatSheet__'
|
||||||
|
if bufwinnr(l:name) > 0
|
||||||
|
execute bufwinnr(l:name) . 'wincmd w'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
execute 'botright new ' . l:name
|
||||||
|
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
|
||||||
|
call setline(1, [
|
||||||
|
\ '=== chopsticks — Quick Reference ===',
|
||||||
|
\ '',
|
||||||
|
\ 'SURVIVAL',
|
||||||
|
\ ' Esc / jk Exit insert or visual mode',
|
||||||
|
\ ' :q! + Enter Quit without saving',
|
||||||
|
\ ' ,x Save+quit ,w Save Ctrl+s Save (any mode)',
|
||||||
|
\ ' :w!! Sudo save (when you forgot to open as root)',
|
||||||
|
\ '',
|
||||||
|
\ 'FILES & SEARCH',
|
||||||
|
\ ' Ctrl+p Fuzzy find file (git-aware)',
|
||||||
|
\ ' ,e / ,E File browser / vertical split',
|
||||||
|
\ ' ,b Search open buffers',
|
||||||
|
\ ' ,rg Search project contents (ripgrep)',
|
||||||
|
\ ' ,rG Ripgrep word under cursor',
|
||||||
|
\ ' ,fh Recent files history',
|
||||||
|
\ ' ,fl / ,fL Search lines in buffer / all buffers',
|
||||||
|
\ ' ,fc Commands | ,fm Marks',
|
||||||
|
\ ' ,f/ / ,f: Search / command history',
|
||||||
|
\ ' ,, Switch to last file (Ctrl+^)',
|
||||||
|
\ '',
|
||||||
|
\ 'CODE INTELLIGENCE (vim-lsp)',
|
||||||
|
\ ' gd Definition gy Type def gi Impl gr Refs',
|
||||||
|
\ ' K Hover documentation',
|
||||||
|
\ ' [g / ]g Prev / next LSP diagnostic',
|
||||||
|
\ ' [e / ]e Prev / next ALE error',
|
||||||
|
\ ' ,ca Code action ,rn Rename ,f Format',
|
||||||
|
\ ' ,o File outline ,ws Workspace symbols',
|
||||||
|
\ ' ,cr Run current file',
|
||||||
|
\ '',
|
||||||
|
\ 'MARKDOWN & WRITING',
|
||||||
|
\ ' ,mp Live browser preview (previm)',
|
||||||
|
\ ' ,mt Table of contents',
|
||||||
|
\ ' ,zen Zen mode (Goyo + Limelight)',
|
||||||
|
\ ' zr / zm Unfold / fold all headings',
|
||||||
|
\ '',
|
||||||
|
\ 'EDITING',
|
||||||
|
\ ' gc Toggle comment (visual mode too)',
|
||||||
|
\ ' s + 2 chars EasyMotion jump anywhere',
|
||||||
|
\ ' ,u / F5 Undo tree',
|
||||||
|
\ ' ,y / ,Y Yank to system clipboard',
|
||||||
|
\ ' Alt+j / Alt+k Move line down / up',
|
||||||
|
\ ' ,F Re-indent file ,W Strip trailing whitespace',
|
||||||
|
\ ' ,* Search and replace word under cursor',
|
||||||
|
\ '',
|
||||||
|
\ 'GIT',
|
||||||
|
\ ' ,gs Status ,gd Diff ,gb Blame',
|
||||||
|
\ ' ,gc Commit ,gp Push ,gl Pull',
|
||||||
|
\ ' [x / ]x Navigate git conflict markers',
|
||||||
|
\ '',
|
||||||
|
\ 'WINDOWS & PANES',
|
||||||
|
\ ' Ctrl+h/j/k/l Navigate splits and tmux panes',
|
||||||
|
\ ' ,h / ,l Prev / next buffer ,bd Close buffer',
|
||||||
|
\ ' ,z Maximize / restore current window',
|
||||||
|
\ ' ,tv / ,th Terminal (vertical / horizontal)',
|
||||||
|
\ ' Esc Esc Exit terminal mode',
|
||||||
|
\ ' ,= / ,- Resize height ,+ / ,_ Resize width',
|
||||||
|
\ '',
|
||||||
|
\ 'QUICKFIX',
|
||||||
|
\ ' ,qo / ,qc Open / close quickfix',
|
||||||
|
\ ' ]q / [q Next / prev quickfix entry',
|
||||||
|
\ '',
|
||||||
|
\ 'UTILITIES',
|
||||||
|
\ ' ,ev / ,sv Edit / reload ~/.vimrc',
|
||||||
|
\ ' ,cp / ,cf Copy file path / filename to clipboard',
|
||||||
|
\ ' ,ms Scratch buffer ,cd CD to file dir',
|
||||||
|
\ ' ,ss Toggle spell ,so Source current vim file',
|
||||||
|
\ ' F2 Paste F3 Line# F4 Relative# F6 Invisible',
|
||||||
|
\ '',
|
||||||
|
\ '(press q to close)',
|
||||||
|
\ ])
|
||||||
|
setlocal nomodifiable readonly
|
||||||
|
nnoremap <buffer> <silent> q :bd<CR>
|
||||||
|
endfunction
|
||||||
|
nnoremap <silent> <leader>? :call <SID>CheatSheet()<CR>
|
||||||
|
|
||||||
|
" ── Interactive Tutorial ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function! s:ChopsticksLearn() abort
|
||||||
|
let l:tutor = g:chopsticks_dir . '/tutor/chopsticks.tutor'
|
||||||
|
if !filereadable(l:tutor)
|
||||||
|
echo "Tutorial not found: " . l:tutor
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
execute 'edit ' . fnameescape(l:tutor)
|
||||||
|
setlocal nomodifiable readonly
|
||||||
|
setlocal buftype=nofile bufhidden=wipe
|
||||||
|
setlocal filetype=text
|
||||||
|
setlocal wrap linebreak
|
||||||
|
endfunction
|
||||||
|
command! ChopsticksLearn call s:ChopsticksLearn()
|
||||||
164
modules/ui.vim
Normal file
164
modules/ui.vim
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
" ui.vim — colorscheme, statusline, startify, indentline
|
||||||
|
|
||||||
|
" ── Colorscheme (Solarized Dark — matches tmux palette) ────────────────────
|
||||||
|
|
||||||
|
if g:has_true_color && has('termguicolors') && !g:is_tty
|
||||||
|
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
|
||||||
|
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
|
||||||
|
set termguicolors
|
||||||
|
endif
|
||||||
|
|
||||||
|
set background=dark
|
||||||
|
|
||||||
|
if !g:is_tty
|
||||||
|
try
|
||||||
|
colorscheme solarized8
|
||||||
|
catch
|
||||||
|
colorscheme default
|
||||||
|
endtry
|
||||||
|
else
|
||||||
|
colorscheme default
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has("gui_running")
|
||||||
|
if has("gui_gtk2") || has("gui_gtk3")
|
||||||
|
set guifont=Hack\ 12,Source\ Code\ Pro\ 12,Monospace\ 12
|
||||||
|
elseif has("gui_win32")
|
||||||
|
set guifont=Consolas:h11:cANSI
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── IndentLine (non-TTY only) ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
if !g:is_tty && exists('g:plugs["indentLine"]')
|
||||||
|
let g:indentLine_char = '|'
|
||||||
|
let g:indentLine_first_char = '|'
|
||||||
|
let g:indentLine_showFirstIndentLevel = 1
|
||||||
|
let g:indentLine_fileTypeExclude = ['text', 'help', 'startify', 'markdown']
|
||||||
|
let g:indentLine_bufTypeExclude = ['help', 'terminal', 'nofile']
|
||||||
|
let g:indentLine_setConceal = 2
|
||||||
|
let g:indentLine_concealcursor = ''
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Startify ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if exists('g:plugs["vim-startify"]')
|
||||||
|
let g:startify_custom_header = [
|
||||||
|
\ ' ██████╗██╗ ██╗ ██████╗ ██████╗ ███████╗████████╗██╗ ██████╗██╗ ██╗███████╗',
|
||||||
|
\ ' ██╔════╝██║ ██║██╔═══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝██╔════╝',
|
||||||
|
\ ' ██║ ███████║██║ ██║██████╔╝███████╗ ██║ ██║██║ █████╔╝ ███████╗',
|
||||||
|
\ ' ██║ ██╔══██║██║ ██║██╔═══╝ ╚════██║ ██║ ██║██║ ██╔═██╗ ╚════██║',
|
||||||
|
\ ' ╚██████╗██║ ██║╚██████╔╝██║ ███████║ ██║ ██║╚██████╗██║ ██╗███████║',
|
||||||
|
\ ' ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝',
|
||||||
|
\ '',
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let g:startify_lists = [
|
||||||
|
\ { 'type': 'sessions', 'header': [' Sessions'] },
|
||||||
|
\ { 'type': 'files', 'header': [' Recent Files'] },
|
||||||
|
\ { 'type': 'dir', 'header': [' Current Dir'] },
|
||||||
|
\ { 'type': 'bookmarks', 'header': [' Bookmarks'] },
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let g:startify_bookmarks = [{'v': '~/.vimrc'}]
|
||||||
|
if filereadable(expand('~/.zshrc'))
|
||||||
|
call add(g:startify_bookmarks, {'z': '~/.zshrc'})
|
||||||
|
endif
|
||||||
|
if filereadable(expand('~/.bashrc'))
|
||||||
|
call add(g:startify_bookmarks, {'b': '~/.bashrc'})
|
||||||
|
endif
|
||||||
|
if filereadable(expand('~/.config/fish/config.fish'))
|
||||||
|
call add(g:startify_bookmarks, {'f': '~/.config/fish/config.fish'})
|
||||||
|
endif
|
||||||
|
|
||||||
|
let g:startify_session_persistence = 1
|
||||||
|
let g:startify_session_autoload = 1
|
||||||
|
let g:startify_change_to_vcs_root = 1
|
||||||
|
let g:startify_fortune_use_unicode = 0
|
||||||
|
let g:startify_enable_special = 0
|
||||||
|
let g:startify_files_number = 8
|
||||||
|
let g:startify_padding_left = 4
|
||||||
|
|
||||||
|
if !g:is_tty
|
||||||
|
augroup ChopstickStartup
|
||||||
|
autocmd!
|
||||||
|
autocmd StdinReadPre * let s:std_in = 1
|
||||||
|
autocmd VimEnter *
|
||||||
|
\ if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
|
||||||
|
\ exe 'cd ' . fnameescape(argv()[0]) |
|
||||||
|
\ if exists(':Startify') == 2 | Startify | else | enew | endif |
|
||||||
|
\ endif
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── Status Line (native — Solarized palette, seamless with tmux bar) ───────
|
||||||
|
|
||||||
|
set laststatus=2
|
||||||
|
set noshowmode
|
||||||
|
|
||||||
|
function! s:SLDefineColors() abort
|
||||||
|
hi SLNormal ctermbg=136 ctermfg=234 cterm=bold guibg=#b58900 guifg=#002b36 gui=bold
|
||||||
|
hi SLInsert ctermbg=33 ctermfg=234 cterm=bold guibg=#268bd2 guifg=#002b36 gui=bold
|
||||||
|
hi SLVisual ctermbg=125 ctermfg=234 cterm=bold guibg=#d33682 guifg=#002b36 gui=bold
|
||||||
|
hi SLReplace ctermbg=160 ctermfg=234 cterm=bold guibg=#dc322f guifg=#002b36 gui=bold
|
||||||
|
hi SLCommand ctermbg=37 ctermfg=234 cterm=bold guibg=#2aa198 guifg=#002b36 gui=bold
|
||||||
|
hi SLBody ctermbg=235 ctermfg=245 cterm=none guibg=#073642 guifg=#93a1a1
|
||||||
|
hi SLFlag ctermbg=235 ctermfg=136 cterm=none guibg=#073642 guifg=#b58900
|
||||||
|
hi SLRight ctermbg=235 ctermfg=240 cterm=none guibg=#073642 guifg=#586e75
|
||||||
|
hi SLGit ctermbg=235 ctermfg=37 cterm=none guibg=#073642 guifg=#2aa198
|
||||||
|
hi SLFtype ctermbg=235 ctermfg=244 cterm=none guibg=#073642 guifg=#839496
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup SLColors
|
||||||
|
autocmd!
|
||||||
|
autocmd ColorScheme * call s:SLDefineColors()
|
||||||
|
augroup END
|
||||||
|
call s:SLDefineColors()
|
||||||
|
|
||||||
|
function! SLMode() abort
|
||||||
|
let l:m = mode()
|
||||||
|
if l:m ==# 'n' | return [' N ', 'SLNormal' ]
|
||||||
|
elseif l:m ==# 'i' | return [' I ', 'SLInsert' ]
|
||||||
|
elseif l:m =~# '[vV]' || l:m ==# "\<C-v>" | return [' V ', 'SLVisual' ]
|
||||||
|
elseif l:m ==# 'R' | return [' R ', 'SLReplace']
|
||||||
|
elseif l:m ==# 'c' | return [' C ', 'SLCommand']
|
||||||
|
elseif l:m ==# 't' | return [' T ', 'SLInsert' ]
|
||||||
|
else | return [' ' . l:m . ' ', 'SLNormal']
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SLGit() abort
|
||||||
|
if !exists('*FugitiveHead') | return '' | endif
|
||||||
|
let l:b = FugitiveHead()
|
||||||
|
return empty(l:b) ? '' : ' ' . l:b . ' '
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SLAle() abort
|
||||||
|
if !exists('*ale#statusline#Count') | return '' | endif
|
||||||
|
let l:c = ale#statusline#Count(bufnr(''))
|
||||||
|
let l:e = l:c.error + l:c.style_error
|
||||||
|
let l:w = l:c.warning + l:c.style_warning
|
||||||
|
if l:e == 0 && l:w == 0 | return '' | endif
|
||||||
|
return printf(' E:%d W:%d ', l:e, l:w)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! SLBuild() abort
|
||||||
|
let [l:label, l:hl] = SLMode()
|
||||||
|
let l:s = '%#' . l:hl . '#' . l:label
|
||||||
|
let l:s .= '%#SLBody# %f '
|
||||||
|
let l:s .= '%#SLFlag#%m%r'
|
||||||
|
let l:s .= '%#SLBody#%='
|
||||||
|
let l:s .= '%#SLFlag#' . SLAle()
|
||||||
|
let l:s .= '%#SLGit#' . SLGit()
|
||||||
|
let l:s .= '%#SLFtype# %y '
|
||||||
|
let l:s .= '%#SLRight# %l:%c %P '
|
||||||
|
return l:s
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
set statusline=%!SLBuild()
|
||||||
|
|
||||||
|
if g:is_tty
|
||||||
|
set statusline=%f\ %h%w%m%r\ %=%(%l,%c%V\ %=\ %P%)
|
||||||
|
endif
|
||||||
56
modules/writing.vim
Normal file
56
modules/writing.vim
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
" writing.vim — vim-markdown, previm, goyo + limelight zen mode
|
||||||
|
|
||||||
|
" ── vim-markdown ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
let g:vim_markdown_conceal = 1
|
||||||
|
let g:vim_markdown_conceal_code_blocks = 0
|
||||||
|
let g:vim_markdown_folding_disabled = 0
|
||||||
|
let g:vim_markdown_folding_level = 2
|
||||||
|
let g:vim_markdown_frontmatter = 1
|
||||||
|
let g:vim_markdown_toml_frontmatter = 1
|
||||||
|
let g:vim_markdown_json_frontmatter = 1
|
||||||
|
let g:vim_markdown_follow_anchor = 1
|
||||||
|
let g:vim_markdown_new_list_item_indent = 2
|
||||||
|
let g:vim_markdown_strikethrough = 1
|
||||||
|
|
||||||
|
if exists('g:plugs["vim-markdown"]')
|
||||||
|
nnoremap <leader>mt :Toc<CR>
|
||||||
|
endif
|
||||||
|
|
||||||
|
" ── previm (Markdown browser preview) ───────────────────────────────────────
|
||||||
|
|
||||||
|
if has('macunix')
|
||||||
|
let g:previm_open_cmd = '/usr/bin/open'
|
||||||
|
elseif executable('xdg-open')
|
||||||
|
let g:previm_open_cmd = 'xdg-open'
|
||||||
|
endif
|
||||||
|
if exists('g:plugs["previm"]')
|
||||||
|
nnoremap <leader>mp :PrevimOpen<CR>
|
||||||
|
endif
|
||||||
|
let g:previm_enable_realtime = 1
|
||||||
|
|
||||||
|
" ── Goyo + Limelight (zen mode) ────────────────────────────────────────────
|
||||||
|
|
||||||
|
if exists('g:plugs["goyo.vim"]')
|
||||||
|
let g:goyo_width = 80
|
||||||
|
let g:goyo_height = '85%'
|
||||||
|
nnoremap <leader>zen :Goyo<CR>
|
||||||
|
|
||||||
|
function! s:goyo_enter()
|
||||||
|
if exists('g:plugs["limelight.vim"]') | Limelight | endif
|
||||||
|
set wrap linebreak scrolloff=999
|
||||||
|
endfunction
|
||||||
|
function! s:goyo_leave()
|
||||||
|
if exists('g:plugs["limelight.vim"]') | Limelight! | endif
|
||||||
|
set nowrap nolinebreak scrolloff=10
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup ChopstickGoyo
|
||||||
|
autocmd!
|
||||||
|
autocmd User GoyoEnter nested call s:goyo_enter()
|
||||||
|
autocmd User GoyoLeave nested call s:goyo_leave()
|
||||||
|
augroup END
|
||||||
|
endif
|
||||||
|
|
||||||
|
let g:limelight_conceal_ctermfg = 240
|
||||||
|
let g:limelight_conceal_guifg = '#586e75'
|
||||||
269
tutor/chopsticks.tutor
Normal file
269
tutor/chopsticks.tutor
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
================================================================================
|
||||||
|
= C H O P S T I C K S I N T E R A C T I V E T U T O R =
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
This tutorial teaches the key features of the chopsticks Vim configuration.
|
||||||
|
It assumes you already know basic Vim (if not, run :Tutor first).
|
||||||
|
|
||||||
|
Leader key is , (comma) throughout this tutorial.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 1: SURVIVAL BASICS
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
These four commands get you out of any situation:
|
||||||
|
|
||||||
|
1. Press Esc or type jk to return to Normal mode
|
||||||
|
2. Type ,w to save the current file
|
||||||
|
3. Type ,x to save and quit
|
||||||
|
4. Type ,q to quit (without saving)
|
||||||
|
|
||||||
|
TIP: You can also press Ctrl+s to save from ANY mode (normal, insert,
|
||||||
|
or visual). Try it now — press i to enter insert mode, then Ctrl+s
|
||||||
|
to save without leaving insert mode.
|
||||||
|
|
||||||
|
When completely lost, press ,? to open the cheat sheet with every
|
||||||
|
keybinding. Press q to close it.
|
||||||
|
|
||||||
|
>>> Try it now: press ,? then read through the sheet, then press q
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 2: FINDING FILES
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
chopsticks uses FZF (fuzzy finder) for fast navigation.
|
||||||
|
|
||||||
|
Ctrl+p Fuzzy find files (git-aware — ignores .gitignore'd files)
|
||||||
|
,b Search open buffers
|
||||||
|
,fh Recent file history
|
||||||
|
,rg Search file contents with ripgrep
|
||||||
|
,rG Search for the word under your cursor
|
||||||
|
|
||||||
|
>>> Try it now: press Ctrl+p and start typing a filename
|
||||||
|
|
||||||
|
You can also browse files with the built-in file browser:
|
||||||
|
|
||||||
|
,e Open netrw file browser in current window
|
||||||
|
,E Open netrw in a vertical split
|
||||||
|
|
||||||
|
Inside netrw:
|
||||||
|
Enter Open file
|
||||||
|
- Go up one directory
|
||||||
|
% Create new file
|
||||||
|
d Create new directory
|
||||||
|
gh Toggle hidden files
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 3: CODE INTELLIGENCE
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
chopsticks uses vim-lsp for code intelligence — no Node.js required.
|
||||||
|
|
||||||
|
First, install a language server for your filetype:
|
||||||
|
|
||||||
|
:LspInstallServer (auto-detects the language)
|
||||||
|
:LspStatus (check if it's running)
|
||||||
|
|
||||||
|
Once a server is running, these keys become available:
|
||||||
|
|
||||||
|
gd Go to definition
|
||||||
|
gy Go to type definition
|
||||||
|
gi Go to implementation
|
||||||
|
gr List all references
|
||||||
|
K Show hover documentation
|
||||||
|
|
||||||
|
[g / ]g Jump to previous / next diagnostic
|
||||||
|
,rn Rename symbol under cursor
|
||||||
|
,ca Code action (auto-fix)
|
||||||
|
,f Format buffer (or selection in visual mode)
|
||||||
|
,o File outline (symbols)
|
||||||
|
|
||||||
|
>>> Open a source file and try: gd on a function call, then Ctrl+o
|
||||||
|
to jump back
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 4: EDITING POWER
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
These editing features make chopsticks faster than vanilla Vim.
|
||||||
|
|
||||||
|
EASYMOTION — jump anywhere on screen:
|
||||||
|
Press s then type two characters from your target location.
|
||||||
|
Matching positions light up — press the highlighted letter to jump.
|
||||||
|
|
||||||
|
>>> Try it now: press s then type two letters you can see on screen
|
||||||
|
|
||||||
|
MOVE LINES — rearrange code without cut/paste:
|
||||||
|
Alt+j Move current line down
|
||||||
|
Alt+k Move current line up
|
||||||
|
(Works in visual mode too — select lines first with V )
|
||||||
|
|
||||||
|
SURROUND — change surrounding characters:
|
||||||
|
cs"' Change surrounding " to '
|
||||||
|
cs'<div> Change surrounding ' to <div>...</div>
|
||||||
|
ds( Delete surrounding parentheses
|
||||||
|
ysiw" Surround word with "
|
||||||
|
|
||||||
|
COMMENT — toggle comments:
|
||||||
|
gc Toggle comment (works in visual mode on selections)
|
||||||
|
gcc Toggle comment on current line
|
||||||
|
|
||||||
|
VISUAL FEEDBACK:
|
||||||
|
- Yanked text flashes briefly so you know what was copied
|
||||||
|
- Search highlights auto-clear after you stop moving
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 5: GIT WORKFLOW
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
All git operations through vim-fugitive:
|
||||||
|
|
||||||
|
,gs Git status (press s to stage, press cc to commit)
|
||||||
|
,gd Diff current file (side-by-side split)
|
||||||
|
,gb Git blame (who changed each line)
|
||||||
|
,gc Git commit
|
||||||
|
,gp Git push
|
||||||
|
,gl Git pull
|
||||||
|
|
||||||
|
GitGutter shows changes in the sign column (left margin):
|
||||||
|
+ Added line
|
||||||
|
~ Modified line
|
||||||
|
- Deleted line
|
||||||
|
|
||||||
|
Navigate git conflict markers:
|
||||||
|
]x Jump to next conflict marker
|
||||||
|
[x Jump to previous conflict marker
|
||||||
|
|
||||||
|
>>> Try ,gs in a git repository to see the status view
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 6: MARKDOWN & WRITING
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Markdown files get special treatment automatically:
|
||||||
|
- Word wrap enabled
|
||||||
|
- Spell checking enabled
|
||||||
|
- Syntax concealment (bold renders as bold, headings hide # markers)
|
||||||
|
- Folding by heading level
|
||||||
|
|
||||||
|
Key bindings for markdown:
|
||||||
|
|
||||||
|
,mp Open live browser preview (auto-refreshes as you type)
|
||||||
|
,mt Table of contents in a side window
|
||||||
|
,zen Enter zen mode — Goyo + Limelight
|
||||||
|
(distraction-free writing, only current paragraph highlighted)
|
||||||
|
zr Unfold all headings
|
||||||
|
zm Fold all headings
|
||||||
|
|
||||||
|
>>> Open a .md file and try ,zen to enter zen mode.
|
||||||
|
Press ,zen again to leave.
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 7: WINDOW MANAGEMENT
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Navigate between splits (works with tmux panes too):
|
||||||
|
|
||||||
|
Ctrl+h Move to left split
|
||||||
|
Ctrl+j Move to split below
|
||||||
|
Ctrl+k Move to split above
|
||||||
|
Ctrl+l Move to right split
|
||||||
|
|
||||||
|
Buffer navigation:
|
||||||
|
|
||||||
|
,h Previous buffer
|
||||||
|
,l Next buffer
|
||||||
|
,bd Close buffer (keeps window layout)
|
||||||
|
,, Switch to last file (toggle between two files)
|
||||||
|
|
||||||
|
Window tricks:
|
||||||
|
|
||||||
|
,z Maximize current window (press again to restore)
|
||||||
|
,= / ,- Resize window height (bigger / smaller)
|
||||||
|
,+ / ,_ Resize window width (bigger / smaller)
|
||||||
|
|
||||||
|
Terminal:
|
||||||
|
|
||||||
|
,tv Open terminal (vertical split)
|
||||||
|
,th Open terminal (horizontal, 10 rows)
|
||||||
|
Esc Esc Exit terminal mode back to normal
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 8: LINTING & FORMATTING
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
ALE runs linters and formatters automatically:
|
||||||
|
|
||||||
|
- Linting happens as you type (normal mode) and on save
|
||||||
|
- Format-on-save is enabled by default (black, prettier, gofmt, etc.)
|
||||||
|
|
||||||
|
Navigate errors:
|
||||||
|
|
||||||
|
[e / ]e Previous / next ALE error
|
||||||
|
,aD Show error detail in a popup
|
||||||
|
|
||||||
|
Supported out of the box:
|
||||||
|
Python: flake8 + pylint (lint), black + isort (format)
|
||||||
|
JS/TS: eslint (lint), prettier + eslint (format)
|
||||||
|
Go: staticcheck (lint), goimports (format)
|
||||||
|
Rust: cargo (lint), rustfmt (format)
|
||||||
|
Shell: shellcheck (lint)
|
||||||
|
And more: yaml, dockerfile, css, markdown, sql
|
||||||
|
|
||||||
|
>>> Write some intentionally bad code and watch the sign column
|
||||||
|
light up with X (error) and ! (warning) markers
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 9: RUNNING CODE
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Press ,cr to run the current file. It auto-detects the language:
|
||||||
|
|
||||||
|
Python → python3 file.py
|
||||||
|
JavaScript → node file.js
|
||||||
|
TypeScript → npx ts-node file.ts
|
||||||
|
Go → go run file.go
|
||||||
|
Rust → cargo run
|
||||||
|
Shell → bash file.sh
|
||||||
|
C → gcc + run
|
||||||
|
Lua, Ruby, Perl also supported
|
||||||
|
|
||||||
|
>>> Create a test file (e.g. test.py with: print("hello"))
|
||||||
|
and press ,cr to run it
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Lesson 10: DAILY TIPS
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
SEARCH AND REPLACE:
|
||||||
|
,* Replace word under cursor throughout the file
|
||||||
|
// In visual mode, search for selected text
|
||||||
|
|
||||||
|
USEFUL SHORTCUTS:
|
||||||
|
Y Yank to end of line (consistent with D and C)
|
||||||
|
,y / ,Y Yank to system clipboard
|
||||||
|
,F Re-indent entire file
|
||||||
|
,W Strip all trailing whitespace
|
||||||
|
:w!! Sudo save (when you forgot to open as root)
|
||||||
|
,ev Edit your vimrc
|
||||||
|
,sv Reload your vimrc
|
||||||
|
|
||||||
|
SESSIONS:
|
||||||
|
:Obsess Start recording session (auto-restores next time)
|
||||||
|
:Obsess! Stop recording
|
||||||
|
|
||||||
|
The startup screen (Startify) shows recent files, sessions, and bookmarks.
|
||||||
|
|
||||||
|
>>> Press ,? one more time to review the full cheat sheet.
|
||||||
|
You now know the essential chopsticks features. Happy editing!
|
||||||
|
|
||||||
|
================================================================================
|
||||||
Loading…
Reference in a new issue