Compare commits

..

No commits in common. "565f2fc80b48f1e4f610c51b0aaec44ebfcd74f9" and "97ca2be139553be185cd8c3e724a4c862d4af2b1" have entirely different histories.

13 changed files with 582 additions and 395 deletions

View file

@ -48,8 +48,8 @@ jobs:
vim -u .vimrc -N -c 'redir! > /tmp/test.txt | echo len(g:plugs) | redir END | qa!' 2>/dev/null 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:]') PLUGS=$(cat /tmp/test.txt | tr -d '[:space:]')
echo "Plugins registered: $PLUGS" echo "Plugins registered: $PLUGS"
if [ "$PLUGS" -lt 20 ]; then if [ "$PLUGS" -lt 25 ]; then
echo "FAIL: expected 20+ plugins, got $PLUGS" echo "FAIL: expected 25+ plugins, got $PLUGS"
exit 1 exit 1
fi fi

1
.vimrc
View file

@ -16,5 +16,6 @@ call s:load('navigation')
call s:load('lsp') call s:load('lsp')
call s:load('lint') call s:load('lint')
call s:load('git') call s:load('git')
call s:load('writing')
call s:load('languages') call s:load('languages')
call s:load('tools') call s:load('tools')

View file

@ -1,84 +0,0 @@
# Changelog
## Unreleased
### Added
- `:ChopsticksStatus` diagnostic command — checks system tools, LSP servers, linters, formatters
## 2.1.0 — 2025-04-22
### Added
- Cheat sheet (`,?`) — vertical sidebar, one key per line, section headers
- Previm markdown preview restored (lazy-loaded, `,mp`)
- `:LspInstallServer` added to cheat sheet
### Changed
- Plugin count: 25 (restored previm, dropped 5 bloat plugins)
- QUICKSTART updated — removed stale references, improved first-launch guidance
## 2.0.0 — 2025-04-21
### Added
- Sidebar toggle (`,e` / `,E`) — left-side netrw with `topleft vertical`, winfixwidth, proper toggle
- Enriched statusline — SLMode, SLGit, SLAle, SLFlags
- Toggle feedback — F2/F3/F4/F6/`,ss` echo current state
- `vim .` layout — netrw left + Startify right, proper proportions
- Interactive tutorial (`:ChopsticksLearn`)
### Removed (Unix minimalism refactor)
- **565 lines** of dead code and bloat
- 5 plugins: Goyo, Limelight, vim-obsession, indentLine, vim-unimpaired
- `modules/writing.vim` — folded into `languages.vim`
- `tutor/chopsticks.tutor` — removed (269 lines)
- Tab management keybindings (8 mappings), spell nav bindings (4 mappings)
- Dead functions: HasPaste(), CleanExtraSpaces(), ToggleNumber(), SynStack
- TTY welcome message, `,so`, `,ms`, `,sh` mappings
### Changed
- CI plugin threshold lowered to 20
- README: hero layout with demo GIF, badges, architecture diagram
- vim-markdown settings absorbed from writing.vim into languages.vim
## 1.3.0 — 2025-04-20
### Changed
- Startup: 39ms → 19ms (51% faster)
- Dropped vim-unimpaired for performance
- Runtime tuning across modules
## 1.2.0 — 2025-04-19
### Added
- Hero README with demo GIF, CI badges
- GitHub Actions CI (startup test on macOS + Ubuntu, shellcheck)
- Issue/PR templates
### Changed
- Documentation rewrite — clean, short, for engineers
## 1.1.0 — 2025-04-18
### Added
- 12-module architecture (env → plugins → core → ui → editing → navigation → lsp → lint → git → writing → languages → tools)
- Zen mode (Goyo + Limelight)
- Run file (`,cr`) with auto filetype detection
- Smart search (SmartFiles, Rg, RgWord)
- EasyMotion, yank highlight, undo tree
- Robust installer (`get.sh`) with preflight checks
### Changed
- `.vimrc` split into 12 self-contained modules
- Comprehensive bug audit (14 fixes)
## 1.0.0 — 2025-04-16
### Added
- Initial Vim configuration — migrated from Neovim
- vim-plug plugin manager
- vim-lsp + asyncomplete (pure VimScript LSP)
- ALE linting + format-on-save
- FZF fuzzy finder
- Fugitive + GitGutter
- Solarized colorscheme
- TTY detection and graceful degradation
- Platform installer (macOS, Debian, Arch, Fedora)

View file

@ -8,7 +8,7 @@ Five minutes from zero to a working Vim setup.
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
``` ```
Open vim. First launch auto-installs plugins — **wait 30-60s, don't close vim**. Restart when done. Open vim. Plugins install automatically on first launch (30-60s). Restart vim.
## Modes ## Modes
@ -26,7 +26,8 @@ Esc / jk back to Normal
,x save + quit ,x save + quit
:q! force quit :q! force quit
Ctrl+s save from any mode Ctrl+s save from any mode
,? cheat sheet (toggle sidebar) ,? cheat sheet
:ChopsticksLearn interactive tutorial
``` ```
## Find things ## Find things
@ -52,7 +53,7 @@ K hover docs
Tab / S-Tab cycle completions Tab / S-Tab cycle completions
``` ```
**First time in a new language?** Run `:LspInstallServer` — it auto-detects filetype and installs the right server. Do this once per language. Install language servers with `:LspInstallServer` (auto-detects filetype).
## Git ## Git
@ -84,17 +85,12 @@ Ctrl+h/j/k/l splits + tmux panes
,tv / ,th terminal ,tv / ,th terminal
``` ```
## Markdown ## Write prose
``` ```
,mp preview in browser ,zen zen mode (Goyo + Limelight)
,mp markdown preview in browser
,mt table of contents ,mt table of contents
``` ```
## Health check
```
:ChopsticksStatus see what's installed and what's missing
```
See [README](README.md) for the full reference. See the [wiki](https://github.com/m1ngsama/chopsticks/wiki) for deep dives. See [README](README.md) for the full reference. See the [wiki](https://github.com/m1ngsama/chopsticks/wiki) for deep dives.

View file

@ -5,7 +5,7 @@
<h1 align="center">chopsticks</h1> <h1 align="center">chopsticks</h1>
<p align="center"> <p align="center">
<strong>Vim for engineers. 25 plugins, works over SSH.</strong> <strong>Vim for engineers. 29 plugins, 19ms startup, works over SSH.</strong>
</p> </p>
<p align="center"> <p align="center">
@ -30,20 +30,20 @@ You SSH into a server. You need to edit code. You want LSP, fuzzy find, git inte
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. 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.
**25 plugins**, LSP, linting, and a hand-built statusline. No bloat, no decorations, just tools. **19ms startup** with 29 plugins, LSP, linting, and a hand-built statusline. Faster than most people's empty vimrc.
## What's in the box ## What's in the box
| Feature | Description | | | |
|---------|-------------| |-|-|
| **LSP** | completion, go-to-def, hover, rename, code actions — pure VimScript ([vim-lsp](https://github.com/prabirshrestha/vim-lsp)) | | **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 | | **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) | | **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) | | **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 | | **Run file** | `,cr` — auto-detects Python, Go, Rust, JS, C, Shell, and more |
| **Markdown** | live preview in browser (`,mp`), table of contents (`,mt`) |
| **Diagnostics** | `:ChopsticksStatus` — see what's installed, what's missing, how to fix it |
| **TTY-aware** | degrades gracefully on SSH, console, slow links — never breaks | | **TTY-aware** | degrades gracefully on SSH, console, slow links — never breaks |
| **19ms startup** | lazy-loaded plugins, deferred LSP init, zero redundant work |
## Install ## Install
@ -64,13 +64,13 @@ First launch installs plugins automatically (30-60s). Restart vim when done.
## Keys ## Keys
Leader: `,` Leader: `,` — press `,?` for the full cheat sheet inside vim.
``` ```
Ctrl+p fuzzy find file gd go to definition Ctrl+p fuzzy find file gd go to definition
,rg ripgrep project K hover docs ,rg ripgrep project K hover docs
,e toggle file sidebar ,cr run current file ,gs git status ,cr run current file
,gs git status ,f format ,zen zen mode ,f format
,w save ,q quit ,w save ,q quit
jk exit insert mode ,? cheat sheet jk exit insert mode ,? cheat sheet
``` ```
@ -80,35 +80,27 @@ jk exit insert mode ,? cheat sheet
### Files ### Files
`Ctrl+p` find | `,b` buffers | `,rg` grep | `,rG` grep word | `,fh` recent | `,fl` lines | `,e` browser | `,E` browser (file dir) | `,,` last file `Ctrl+p` find | `,b` buffers | `,rg` grep | `,rG` grep word | `,fh` recent | `,e` browser | `,,` last file
### Code ### Code
`gd` def | `gy` type | `gi` impl | `gr` refs | `K` docs | `[g` `]g` diagnostics | `[e` `]e` ALE errors | `,rn` rename | `,ca` action | `,o` outline | `,cr` run `gd` def | `gy` type | `gi` impl | `gr` refs | `K` docs | `[g` `]g` diagnostics | `,rn` rename | `,ca` action | `,o` outline | `,cr` run
### Edit ### Edit
`s`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word | `,F` re-indent | `,W` strip whitespace | `[<Space>` `]<Space>` blank lines `s`+2ch jump | `gc` comment | `cs"'` surround | `Alt+j/k` move line | `,u` undo tree | `,y` clipboard | `,*` replace word
### Git ### Git
`,gs` status | `,gd` diff | `,gb` blame | `,gc` commit | `,gp` push | `,gl` pull | `]x` `[x` conflict `,gs` status | `,gd` diff | `,gb` blame | `,gc` commit | `,gp` push | `]x` `[x` conflict
### Windows ### Windows
`Ctrl+hjkl` navigate (+ tmux) | `,z` maximize | `,h` `,l` buffers | `,bd` close buffer | `,=` `,` resize | `,tv` `,th` terminal | `Esc Esc` exit terminal `Ctrl+hjkl` navigate (+ tmux) | `,z` maximize | `,h` `,l` buffers | `,tv` terminal | `Esc Esc` exit terminal
### Markdown ### Writing
`,mp` preview in browser | `,mt` table of contents `,zen` zen mode | `,mp` markdown preview | `,mt` table of contents
### Toggle
`F2` paste | `F3` line numbers | `F4` relative numbers | `F6` invisible chars | `,ss` spell check
### Utilities
`,cp` copy full path | `,cf` copy filename | `,ev` edit vimrc | `,sv` reload vimrc | `,wa` save all | `:ChopsticksStatus` diagnostics
</details> </details>
@ -117,7 +109,6 @@ jk exit insert mode ,? cheat sheet
```vim ```vim
:LspInstallServer " auto-detects filetype :LspInstallServer " auto-detects filetype
:LspStatus " check what's running :LspStatus " check what's running
:ChopsticksStatus " see all tools + LSP + linters at a glance
``` ```
pylsp, gopls, rust-analyzer, clangd, marksman, sqls — no Node.js. JS/TS servers need Node. pylsp, gopls, rust-analyzer, clangd, marksman, sqls — no Node.js. JS/TS servers need Node.
@ -128,32 +119,46 @@ ALE and vim-lsp coexist cleanly (`ale_disable_lsp=1`). ALE handles linting + for
``` ```
~/.vim/ ~/.vim/
├── .vimrc thin loader ├── .vimrc thin loader (12 lines)
├── modules/ ├── modules/
│ ├── env.vim TTY detection, truecolor, skip built-in plugins │ ├── env.vim TTY detection, truecolor
│ ├── plugins.vim vim-plug + 25 plugins │ ├── plugins.vim vim-plug + 29 plugins
│ ├── core.vim settings, keymaps, performance │ ├── core.vim settings, keymaps, performance
│ ├── ui.vim solarized, statusline, startify │ ├── ui.vim solarized, statusline, startify
│ ├── editing.vim easymotion, yank highlight, blank lines │ ├── editing.vim easymotion, yank highlight
│ ├── navigation.vim fzf, netrw sidebar, windows, terminal │ ├── navigation.vim fzf, netrw, windows, terminal
│ ├── lsp.vim vim-lsp, asyncomplete │ ├── lsp.vim vim-lsp, asyncomplete
│ ├── lint.vim ale, format-on-save │ ├── lint.vim ale, format-on-save
│ ├── git.vim fugitive, gitgutter, conflict nav │ ├── git.vim fugitive, gitgutter
│ ├── languages.vim vim-go, markdown, filetype settings │ ├── writing.vim markdown, previm, zen mode
│ └── tools.vim run file, quickfix, cheat sheet, diagnostics │ ├── 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')`. Each module is self-contained. Comment out one line in `.vimrc` to disable it. Add your own with `call s:load('mine')`.
## Learn
```vim
:ChopsticksLearn " interactive tutorial — 10 lessons
,? " cheat sheet (every binding)
```
## Performance ## Performance
| Metric | Value | | Metric | Value |
|--------|-------| |--------|-------|
| Lazy-loaded | 7 plugins (on command or filetype) | | Startup time | **19ms** (29 plugins loaded) |
| Lazy-loaded | 8 plugins (on command or filetype) |
| Built-in plugins skipped | 10 (gzip, tar, zip, vimball, etc.) | | Built-in plugins skipped | 10 (gzip, tar, zip, vimball, etc.) |
| Runtime lint delay | 200ms (no thrashing during edits) |
| Large file threshold | 10MB (auto-disables syntax + undo) | | Large file threshold | 10MB (auto-disables syntax + undo) |
| TTY large file | 500KB (syntax disabled) | | TTY large file | 500KB (syntax disabled) |
Measured with `vim --startuptime`. We benchmark every change.
## Troubleshooting ## Troubleshooting
| Problem | Fix | | Problem | Fix |
@ -163,7 +168,6 @@ Each module is self-contained. Comment out one line in `.vimrc` to disable it. A
| Colors wrong | `export COLORTERM=truecolor` in shell rc | | Colors wrong | `export COLORTERM=truecolor` in shell rc |
| `Ctrl+s` freezes | `stty -ixon` in shell rc | | `Ctrl+s` freezes | `stty -ixon` in shell rc |
| Everything slow | Large file? Auto-disabled >10MB | | Everything slow | Large file? Auto-disabled >10MB |
| What's installed? | `:ChopsticksStatus` shows tools, LSP, linters |
More in the [wiki](https://github.com/m1ngsama/chopsticks/wiki). More in the [wiki](https://github.com/m1ngsama/chopsticks/wiki).

View file

@ -100,6 +100,20 @@ nnoremap <leader>ba :bufdo bd<cr>
nnoremap <leader>l :bnext<cr> nnoremap <leader>l :bnext<cr>
nnoremap <leader>h :bprevious<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 <leader>cd :lcd %:p:h<cr>:pwd<cr>
nnoremap 0 ^ nnoremap 0 ^
@ -113,12 +127,16 @@ nnoremap <M-k> :m .-2<CR>==
vnoremap <M-j> :m '>+1<CR>gv=gv vnoremap <M-j> :m '>+1<CR>gv=gv
vnoremap <M-k> :m '<-2<CR>gv=gv vnoremap <M-k> :m '<-2<CR>gv=gv
nnoremap <silent> <leader>ss :setlocal spell!<CR>:echo 'Spell: ' . (&spell ? 'ON' : 'OFF')<CR> nnoremap <leader>ss :setlocal spell!<cr>
nnoremap <leader>sn ]s
nnoremap <leader>sp [s
nnoremap <leader>sa zg
nnoremap <leader>s? z=
nnoremap <silent> <F2> :set paste!<CR>:echo 'Paste: ' . (&paste ? 'ON' : 'OFF')<CR> set pastetoggle=<F2>
nnoremap <silent> <F3> :set invnumber<CR>:echo 'Line numbers: ' . (&number ? 'ON' : 'OFF')<CR> nnoremap <F3> :set invnumber<CR>
nnoremap <silent> <F4> :set invrelativenumber<CR>:echo 'Relative numbers: ' . (&relativenumber ? 'ON' : 'OFF')<CR> nnoremap <F4> :set invrelativenumber<CR>
nnoremap <silent> <F6> :set list!<CR>:echo 'List chars: ' . (&list ? 'ON' : 'OFF')<CR> nnoremap <F6> :set list!<CR>
nnoremap <space> za nnoremap <space> za

View file

@ -1,31 +1,4 @@
" languages.vim — vim-go, vim-markdown, per-filetype autocmds " languages.vim — vim-go config, per-filetype autocmds
" ── 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
if has('macunix')
let g:previm_open_cmd = '/usr/bin/open'
elseif executable('xdg-open')
let g:previm_open_cmd = 'xdg-open'
endif
let g:previm_enable_realtime = 1
if exists('g:plugs["previm"]')
nnoremap <leader>mp :PrevimOpen<CR>
endif
" ── vim-go (syntax only — vim-lsp handles intelligence) ───────────────────── " ── vim-go (syntax only — vim-lsp handles intelligence) ─────────────────────

View file

@ -4,37 +4,13 @@
let g:netrw_liststyle = 3 let g:netrw_liststyle = 3
let g:netrw_banner = 0 let g:netrw_banner = 0
let g:netrw_browse_split = 4 let g:netrw_browse_split = 0
let g:netrw_winsize = 25 let g:netrw_winsize = 25
let g:netrw_altv = 1
let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+' let g:netrw_list_hide = '\(^\|\s\s\)\zs\.\S\+'
let g:netrw_list_hide .= ',\.pyc$,node_modules,\.git,__pycache__,\.DS_Store' let g:netrw_list_hide .= ',\.pyc$,node_modules,\.git,__pycache__,\.DS_Store'
function! s:ToggleSidebar(...) abort nnoremap <leader>e :Explore<CR>
let l:dir = a:0 ? a:1 : getcwd() nnoremap <leader>E :Vexplore<CR>
if getbufvar(winbufnr(1), '&filetype') ==# 'netrw' && getwinvar(1, '&winfixwidth')
let l:cur = winnr()
1wincmd w
close
if l:cur > 1
execute (l:cur - 1) . 'wincmd w'
endif
return
endif
execute 'topleft vertical 30new'
execute 'Explore ' . fnameescape(l:dir)
setlocal winfixwidth
setlocal bufhidden=wipe
wincmd p
endfunction
nnoremap <silent> <leader>e :call <SID>ToggleSidebar()<CR>
nnoremap <silent> <leader>E :call <SID>ToggleSidebar(expand('%:p:h'))<CR>
augroup ChopstickNetrw
autocmd!
autocmd FileType netrw setlocal bufhidden=wipe
augroup END
" ── FZF ───────────────────────────────────────────────────────────────────── " ── FZF ─────────────────────────────────────────────────────────────────────
@ -102,11 +78,9 @@ function! s:ToggleMaximize() abort
if exists('t:maximize_session') if exists('t:maximize_session')
execute t:maximize_session execute t:maximize_session
unlet t:maximize_session unlet t:maximize_session
echo 'Window: restored'
else else
let t:maximize_session = winrestcmd() let t:maximize_session = winrestcmd()
resize | vertical resize resize | vertical resize
echo 'Window: MAXIMIZED'
endif endif
endfunction endfunction
nnoremap <silent> <leader>z :call <SID>ToggleMaximize()<CR> nnoremap <silent> <leader>z :call <SID>ToggleMaximize()<CR>

View file

@ -24,6 +24,10 @@ Plug 'airblade/vim-gitgutter'
Plug 'tpope/vim-surround' Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary' Plug 'tpope/vim-commentary'
Plug 'tpope/vim-repeat' 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 'tpope/vim-sleuth'
Plug 'wellle/targets.vim' Plug 'wellle/targets.vim'
Plug 'jiangmiao/auto-pairs' Plug 'jiangmiao/auto-pairs'
@ -32,7 +36,7 @@ Plug 'easymotion/vim-easymotion', { 'on': '<Plug>(easymotion' }
" ── Linting & Formatting ──────────────────────────────────────────────────── " ── Linting & Formatting ────────────────────────────────────────────────────
Plug 'dense-analysis/ale' Plug 'dense-analysis/ale'
" ── LSP + Completion ───────────────────────────────────────────────────────── " ── LSP + Completion (no Node.js required) ──────────────────────────────────
Plug 'prabirshrestha/vim-lsp' Plug 'prabirshrestha/vim-lsp'
Plug 'mattn/vim-lsp-settings' Plug 'mattn/vim-lsp-settings'
Plug 'prabirshrestha/asyncomplete.vim' Plug 'prabirshrestha/asyncomplete.vim'
@ -42,13 +46,23 @@ Plug 'prabirshrestha/asyncomplete-lsp.vim'
Plug 'pangloss/vim-javascript', { 'for': ['javascript', 'javascript.jsx'] } Plug 'pangloss/vim-javascript', { 'for': ['javascript', 'javascript.jsx'] }
Plug 'HerringtonDarkholme/yats.vim', { 'for': ['typescript', 'typescript.tsx'] } Plug 'HerringtonDarkholme/yats.vim', { 'for': ['typescript', 'typescript.tsx'] }
Plug 'preservim/vim-markdown', { 'for': 'markdown' } Plug 'preservim/vim-markdown', { 'for': 'markdown' }
Plug 'previm/previm', { 'on': 'PrevimOpen' }
Plug 'fatih/vim-go', { 'for': 'go' } 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 ─────────────────────────────────────────────────────────────────────── " ── UI ───────────────────────────────────────────────────────────────────────
Plug 'mbbill/undotree', { 'on': 'UndotreeToggle' } Plug 'mbbill/undotree', { 'on': 'UndotreeToggle' }
Plug 'mhinz/vim-startify' Plug 'mhinz/vim-startify'
Plug 'lifepillar/vim-solarized8' Plug 'lifepillar/vim-solarized8'
if !g:is_tty
Plug 'Yggdroot/indentLine'
endif
" ── Session & Navigation ────────────────────────────────────────────────────
Plug 'tpope/vim-obsession'
Plug 'christoomey/vim-tmux-navigator' Plug 'christoomey/vim-tmux-navigator'
call plug#end() call plug#end()

View file

@ -1,6 +1,11 @@
" tools.vim — run file, sudo save, quickfix, helpers " tools.vim — cheat sheet, run file, sudo save, quickfix, helpers
" ── Buffer Close ─────────────────────────────────────────────────────────── " ── Helper Functions ────────────────────────────────────────────────────────
function! HasPaste()
if &paste | return 'PASTE MODE ' | endif
return ''
endfunction
command! Bclose call <SID>BufcloseCloseIt() command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt() function! <SID>BufcloseCloseIt()
@ -19,18 +24,38 @@ function! <SID>BufcloseCloseIt()
endif endif
endfunction endfunction
" ── Utilities ────────────────────────────────────────────────────────────── 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>F gg=G``
nnoremap <leader>wa :wa<CR> nnoremap <leader>wa :wa<CR>
nnoremap <silent> <Leader>= :exe "resize " . (winheight(0) * 3/2)<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 "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><leader> <c-^>
nnoremap <leader>W :%s/\s\+$//<CR>:let @/=''<CR> 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>ev :edit $MYVIMRC<CR>
nnoremap <leader>sv :source $MYVIMRC<CR>:echo "vimrc reloaded"<CR> nnoremap <leader>sv :source $MYVIMRC<CR>:echo "vimrc reloaded"<CR>
@ -41,6 +66,8 @@ if has('clipboard')
nnoremap <leader>cf :let @+ = expand("%:t")<CR>:echo "Copied: " . expand("%:t")<CR> nnoremap <leader>cf :let @+ = expand("%:t")<CR>:echo "Copied: " . expand("%:t")<CR>
endif endif
nnoremap <leader>ms :e ~/buffer.md<cr>
" ── Auto-Create Directories ───────────────────────────────────────────────── " ── Auto-Create Directories ─────────────────────────────────────────────────
function! s:MkNonExDir(file, buf) function! s:MkNonExDir(file, buf)
@ -78,6 +105,14 @@ augroup ChopstickLargeFile
\ endif \ endif
augroup END 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) ────────────────────────────────────────────────── " ── Run Current File (,cr) ──────────────────────────────────────────────────
function! s:RunFile() abort function! s:RunFile() abort
@ -103,7 +138,7 @@ nnoremap <leader>cr :call <SID>RunFile()<CR>
cnoremap w!! w !sudo tee > /dev/null % cnoremap w!! w !sudo tee > /dev/null %
" ── QuickFix ──────────────────────────────────────────────────────────────── " ── QuickFix Improvements ───────────────────────────────────────────────────
augroup ChopstickQF augroup ChopstickQF
autocmd! autocmd!
@ -114,192 +149,112 @@ augroup END
nnoremap <silent> ]q :cnext<CR> nnoremap <silent> ]q :cnext<CR>
nnoremap <silent> [q :cprev<CR> nnoremap <silent> [q :cprev<CR>
" ── Status Diagnostic (:ChopsticksStatus) ─────────────────────────────────── " ── Debug Helpers ───────────────────────────────────────────────────────────
function! s:Check(name, cmd) abort nnoremap <leader>sh :call <SID>SynStack()<CR>
return executable(a:cmd) ? ' OK ' . a:name : ' -- ' . a:name . ' (missing: ' . a:cmd . ')' function! <SID>SynStack()
endfunction if !exists("*synstack") | return | endif
echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')
function! s:LspCheck(ft, server) abort endfunc
if !exists('*lsp#get_server_names')
return ' -- ' . a:ft . ' (vim-lsp not loaded)'
endif
let l:dir = expand('~/.local/share/vim-lsp-settings/servers/' . a:server)
if isdirectory(l:dir)
return ' OK ' . a:ft . ' (' . a:server . ')'
endif
return ' -- ' . a:ft . ' (:LspInstallServer in a ' . a:ft . ' file)'
endfunction
function! s:ChopsticksStatus() abort
let l:lines = []
call add(l:lines, 'chopsticks status')
call add(l:lines, repeat('─', 50))
call add(l:lines, '')
call add(l:lines, '── system tools ──')
call add(l:lines, s:Check('fzf', 'fzf'))
call add(l:lines, s:Check('ripgrep', 'rg'))
call add(l:lines, s:Check('git', 'git'))
call add(l:lines, s:Check('curl', 'curl'))
call add(l:lines, s:Check('node', 'node'))
call add(l:lines, s:Check('python3', 'python3'))
call add(l:lines, s:Check('go', 'go'))
call add(l:lines, '')
call add(l:lines, '── lsp servers ── (:LspInstallServer to install)')
call add(l:lines, s:LspCheck('python', 'pylsp'))
call add(l:lines, s:LspCheck('go', 'gopls'))
call add(l:lines, s:LspCheck('rust', 'rust-analyzer'))
call add(l:lines, s:LspCheck('typescript', 'typescript-language-server'))
call add(l:lines, s:LspCheck('c/c++', 'clangd'))
call add(l:lines, s:LspCheck('bash', 'bash-language-server'))
call add(l:lines, s:LspCheck('html', 'vscode-html-language-server'))
call add(l:lines, s:LspCheck('json', 'vscode-json-language-server'))
call add(l:lines, s:LspCheck('yaml', 'yaml-language-server'))
call add(l:lines, s:LspCheck('markdown', 'marksman'))
call add(l:lines, s:LspCheck('sql', 'sqls'))
call add(l:lines, '')
call add(l:lines, '── linters ──')
call add(l:lines, s:Check('flake8 (python)', 'flake8'))
call add(l:lines, s:Check('pylint (python)', 'pylint'))
call add(l:lines, s:Check('eslint (js/ts)', 'eslint'))
call add(l:lines, s:Check('staticcheck (go)', 'staticcheck'))
call add(l:lines, s:Check('shellcheck (sh)', 'shellcheck'))
call add(l:lines, s:Check('yamllint (yaml)', 'yamllint'))
call add(l:lines, s:Check('hadolint (docker)', 'hadolint'))
call add(l:lines, s:Check('markdownlint (md)', 'markdownlint'))
call add(l:lines, '')
call add(l:lines, '── formatters ── (format-on-save is ON)')
call add(l:lines, s:Check('black (python)', 'black'))
call add(l:lines, s:Check('isort (python)', 'isort'))
call add(l:lines, s:Check('prettier (js/ts/json/md)', 'prettier'))
call add(l:lines, s:Check('goimports (go)', 'goimports'))
call add(l:lines, s:Check('rustfmt (rust)', 'rustfmt'))
call add(l:lines, s:Check('clang-format (c)', 'clang-format'))
call add(l:lines, '')
let l:ok = len(filter(copy(l:lines), 'v:val =~# " OK "'))
let l:miss = len(filter(copy(l:lines), 'v:val =~# " -- "'))
call add(l:lines, repeat('─', 50))
call add(l:lines, ' ' . l:ok . ' ready, ' . l:miss . ' missing')
call add(l:lines, '')
call add(l:lines, ' Install missing tools with ./install.sh')
call add(l:lines, ' Install LSP servers with :LspInstallServer')
let l:name = '__ChopsticksStatus__'
if bufwinnr(l:name) > 0
execute bufwinnr(l:name) . 'wincmd w | bd'
endif
execute 'botright new ' . l:name
resize 45
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
setlocal nowrap nonumber norelativenumber signcolumn=no
call setline(1, l:lines)
setlocal nomodifiable readonly
nnoremap <buffer> <silent> q :bd<CR>
endfunction
command! ChopsticksStatus call s:ChopsticksStatus()
" ── Cheat Sheet (,?) ──────────────────────────────────────────────────────── " ── Cheat Sheet (,?) ────────────────────────────────────────────────────────
function! s:CheatSheet() abort function! s:CheatSheet() abort
let l:name = '__ChopsticksCheatSheet__' let l:name = '__ChopsticksCheatSheet__'
if bufwinnr(l:name) > 0 if bufwinnr(l:name) > 0
execute bufwinnr(l:name) . 'wincmd w | bd' execute bufwinnr(l:name) . 'wincmd w'
return return
endif endif
execute 'vertical botright new ' . l:name execute 'botright new ' . l:name
vertical resize 42
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
setlocal nowrap nonumber norelativenumber signcolumn=no
setlocal winfixwidth
call setline(1, [ call setline(1, [
\ ' chopsticks ,? close', \ '=== chopsticks — Quick Reference ===',
\ ' ─────────────────────────────',
\ '', \ '',
\ ' ── files ──────────────────', \ 'SURVIVAL',
\ ' Ctrl+p find file', \ ' Esc / jk Exit insert or visual mode',
\ ' ,b buffers', \ ' :q! + Enter Quit without saving',
\ ' ,rg grep project', \ ' ,x Save+quit ,w Save Ctrl+s Save (any mode)',
\ ' ,rG grep word', \ ' :w!! Sudo save (when you forgot to open as root)',
\ ' ,e sidebar (cwd)',
\ ' ,E sidebar (file dir)',
\ ' ,, last file',
\ ' ,fh recent files',
\ ' ,fl lines in buffer',
\ ' ,fc commands',
\ ' ,fm marks',
\ '', \ '',
\ ' ── code ──────────────────', \ 'FILES & SEARCH',
\ ' gd definition', \ ' Ctrl+p Fuzzy find file (git-aware)',
\ ' gy type definition', \ ' ,e / ,E File browser / vertical split',
\ ' gi implementation', \ ' ,b Search open buffers',
\ ' gr references', \ ' ,rg Search project contents (ripgrep)',
\ ' K hover docs', \ ' ,rG Ripgrep word under cursor',
\ ' ,rn rename', \ ' ,fh Recent files history',
\ ' ,ca code action', \ ' ,fl / ,fL Search lines in buffer / all buffers',
\ ' ,f format', \ ' ,fc Commands | ,fm Marks',
\ ' ,o outline', \ ' ,f/ / ,f: Search / command history',
\ ' ,cr run file', \ ' ,, Switch to last file (Ctrl+^)',
\ ' ,mp markdown preview',
\ ' ,mt table of contents',
\ ' [g ]g LSP diagnostics',
\ ' [e ]e ALE errors',
\ ' :LspInstallServer setup LSP',
\ '', \ '',
\ ' ── edit ──────────────────', \ 'CODE INTELLIGENCE (vim-lsp)',
\ ' gc comment', \ ' gd Definition gy Type def gi Impl gr Refs',
\ ' s+2ch easymotion jump', \ ' K Hover documentation',
\ ' cs"'' surround', \ ' [g / ]g Prev / next LSP diagnostic',
\ ' ,u undo tree', \ ' [e / ]e Prev / next ALE error',
\ ' ,y clipboard yank', \ ' ,ca Code action ,rn Rename ,f Format',
\ ' Alt+j/k move line', \ ' ,o File outline ,ws Workspace symbols',
\ ' ,* replace word', \ ' ,cr Run current file',
\ ' ,F re-indent file',
\ ' ,W strip whitespace',
\ '', \ '',
\ ' ── git ───────────────────', \ 'MARKDOWN & WRITING',
\ ' ,gs status', \ ' ,mp Live browser preview (previm)',
\ ' ,gd diff', \ ' ,mt Table of contents',
\ ' ,gb blame', \ ' ,zen Zen mode (Goyo + Limelight)',
\ ' ,gc commit', \ ' zr / zm Unfold / fold all headings',
\ ' ,gp push',
\ ' ,gl pull',
\ ' [x ]x conflict markers',
\ '', \ '',
\ ' ── windows ───────────────', \ 'EDITING',
\ ' Ctrl+hjkl navigate splits', \ ' gc Toggle comment (visual mode too)',
\ ' ,h ,l prev / next buf', \ ' s + 2 chars EasyMotion jump anywhere',
\ ' ,bd close buffer', \ ' ,u / F5 Undo tree',
\ ' ,z maximize toggle', \ ' ,y / ,Y Yank to system clipboard',
\ ' ,= ,- resize height', \ ' Alt+j / Alt+k Move line down / up',
\ ' ,tv ,th terminal v / h', \ ' ,F Re-indent file ,W Strip trailing whitespace',
\ ' ]q [q next / prev qf', \ ' ,* Search and replace word under cursor',
\ ' ,qo ,qc open / close qf',
\ '', \ '',
\ ' ── toggle ────────────────', \ 'GIT',
\ ' F2 paste mode', \ ' ,gs Status ,gd Diff ,gb Blame',
\ ' F3 line numbers', \ ' ,gc Commit ,gp Push ,gl Pull',
\ ' F4 relative numbers', \ ' [x / ]x Navigate git conflict markers',
\ ' F6 invisible chars',
\ ' ,ss spell check',
\ '', \ '',
\ ' ── survival ──────────────', \ 'WINDOWS & PANES',
\ ' ,w save', \ ' Ctrl+h/j/k/l Navigate splits and tmux panes',
\ ' ,q quit', \ ' ,h / ,l Prev / next buffer ,bd Close buffer',
\ ' ,x save + quit', \ ' ,z Maximize / restore current window',
\ ' Ctrl+s save (any mode)', \ ' ,tv / ,th Terminal (vertical / horizontal)',
\ ' jk exit insert', \ ' Esc Esc Exit terminal mode',
\ ' :w!! sudo save', \ ' ,= / ,- Resize height ,+ / ,_ Resize width',
\ ' ,ev edit vimrc', \ '',
\ ' ,sv reload vimrc', \ 'QUICKFIX',
\ ' :ChopsticksStatus health', \ ' ,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 setlocal nomodifiable readonly
nnoremap <buffer> <silent> q :bd<CR> nnoremap <buffer> <silent> q :bd<CR>
nnoremap <buffer> <silent> <leader>? :bd<CR>
endfunction endfunction
nnoremap <silent> <leader>? :call <SID>CheatSheet()<CR> 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()

View file

@ -1,4 +1,4 @@
" ui.vim — colorscheme, statusline, startify " ui.vim — colorscheme, statusline, startify, indentline
" ── Colorscheme (Solarized Dark — matches tmux palette) ──────────────────── " ── Colorscheme (Solarized Dark — matches tmux palette) ────────────────────
@ -28,16 +28,49 @@ if has("gui_running")
endif endif
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 ──────────────────────────────────────────────────────────────── " ── Startify ────────────────────────────────────────────────────────────────
if exists('g:plugs["vim-startify"]') if exists('g:plugs["vim-startify"]')
let g:startify_custom_header = [
\ ' ██████╗██╗ ██╗ ██████╗ ██████╗ ███████╗████████╗██╗ ██████╗██╗ ██╗███████╗',
\ ' ██╔════╝██║ ██║██╔═══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔════╝██║ ██╔╝██╔════╝',
\ ' ██║ ███████║██║ ██║██████╔╝███████╗ ██║ ██║██║ █████╔╝ ███████╗',
\ ' ██║ ██╔══██║██║ ██║██╔═══╝ ╚════██║ ██║ ██║██║ ██╔═██╗ ╚════██║',
\ ' ╚██████╗██║ ██║╚██████╔╝██║ ███████║ ██║ ██║╚██████╗██║ ██╗███████║',
\ ' ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝',
\ '',
\ ]
let g:startify_lists = [ let g:startify_lists = [
\ { 'type': 'sessions', 'header': [' Sessions'] }, \ { 'type': 'sessions', 'header': [' Sessions'] },
\ { 'type': 'files', 'header': [' Recent Files'] }, \ { 'type': 'files', 'header': [' Recent Files'] },
\ { 'type': 'dir', 'header': [' Current Dir'] }, \ { 'type': 'dir', 'header': [' Current Dir'] },
\ { 'type': 'bookmarks', 'header': [' Bookmarks'] },
\ ] \ ]
let g:startify_bookmarks = [{'v': '~/.vimrc'}] 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_persistence = 1
let g:startify_session_autoload = 1 let g:startify_session_autoload = 1
let g:startify_change_to_vcs_root = 1 let g:startify_change_to_vcs_root = 1
@ -46,29 +79,15 @@ if exists('g:plugs["vim-startify"]')
let g:startify_files_number = 8 let g:startify_files_number = 8
let g:startify_padding_left = 4 let g:startify_padding_left = 4
function! s:SetupDirView() abort
if argc() != 1 || !isdirectory(argv()[0]) || exists('s:std_in')
return
endif
let l:dir = fnameescape(argv()[0])
execute 'cd ' . l:dir
vertical rightbelow vnew
if exists(':Startify') == 2
Startify
else
enew
endif
wincmd h
vertical resize 30
setlocal winfixwidth
wincmd l
endfunction
if !g:is_tty if !g:is_tty
augroup ChopstickStartup augroup ChopstickStartup
autocmd! autocmd!
autocmd StdinReadPre * let s:std_in = 1 autocmd StdinReadPre * let s:std_in = 1
autocmd VimEnter * nested call <SID>SetupDirView() 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 augroup END
endif endif
@ -125,19 +144,11 @@ function! SLAle() abort
return printf(' E:%d W:%d ', l:e, l:w) return printf(' E:%d W:%d ', l:e, l:w)
endfunction endfunction
function! SLFlags() abort
let l:f = ''
if &paste | let l:f .= ' PASTE' | endif
if &spell | let l:f .= ' SPELL' | endif
return empty(l:f) ? '' : l:f . ' '
endfunction
function! SLBuild() abort function! SLBuild() abort
let [l:label, l:hl] = SLMode() let [l:label, l:hl] = SLMode()
let l:s = '%#' . l:hl . '#' . l:label let l:s = '%#' . l:hl . '#' . l:label
let l:s .= '%#SLBody# %f ' let l:s .= '%#SLBody# %f '
let l:s .= '%#SLFlag#%m%r' let l:s .= '%#SLFlag#%m%r'
let l:s .= '%#SLFlag#' . SLFlags()
let l:s .= '%#SLBody#%=' let l:s .= '%#SLBody#%='
let l:s .= '%#SLFlag#' . SLAle() let l:s .= '%#SLFlag#' . SLAle()
let l:s .= '%#SLGit#' . SLGit() let l:s .= '%#SLGit#' . SLGit()

56
modules/writing.vim Normal file
View 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
View 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!
================================================================================