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
|
||||
*.swo
|
||||
.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
|
||||
|
||||
Five minutes from zero to a working Vim environment.
|
||||
Five minutes from zero to a working Vim setup.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
## Install
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||
```
|
||||
|
||||
Traditional:
|
||||
```bash
|
||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||
cd ~/.vim && ./install.sh
|
||||
```
|
||||
Open vim. Plugins install automatically on first launch (30-60s). Restart vim.
|
||||
|
||||
Non-interactive / CI:
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
||||
```
|
||||
## Modes
|
||||
|
||||
---
|
||||
| Mode | Enter | Leave |
|
||||
|------|-------|-------|
|
||||
| Normal | startup default | — |
|
||||
| Insert | `i` / `a` / `o` | `Esc` or `jk` |
|
||||
| Visual | `v` / `V` | `Esc` |
|
||||
|
||||
## Step 2: Open Vim
|
||||
|
||||
```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
|
||||
## Survival
|
||||
|
||||
```
|
||||
,? Open cheat sheet (all bindings in one place)
|
||||
Esc / jk Exit insert mode → Normal
|
||||
Ctrl+s Save
|
||||
Ctrl+p Fuzzy find file
|
||||
,e File browser (netrw)
|
||||
gd Go to definition
|
||||
K Show documentation
|
||||
[g / ]g Prev / next LSP diagnostic
|
||||
,rn Rename symbol
|
||||
,rG Search word under cursor (ripgrep)
|
||||
,gs Git status
|
||||
,mp Markdown live preview in browser
|
||||
,w / ,x Save / Save+quit
|
||||
Esc / jk back to Normal
|
||||
,w save
|
||||
,x save + quit
|
||||
:q! force quit
|
||||
Ctrl+s save from any mode
|
||||
,? cheat sheet
|
||||
:ChopsticksLearn interactive tutorial
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
## Find things
|
||||
|
||||
```
|
||||
,gs git status (stage with 's', commit with 'cc')
|
||||
,gd diff current file
|
||||
Ctrl+p fuzzy find file (git-aware)
|
||||
,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
|
||||
,gc commit
|
||||
,gp push
|
||||
,gl pull
|
||||
]x / [x conflict markers
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
## Edit
|
||||
|
||||
```
|
||||
BASICS
|
||||
Esc / jk Exit insert mode → Normal
|
||||
Ctrl+s Save
|
||||
:q! + Enter Emergency quit
|
||||
,? Open cheat sheet
|
||||
|
||||
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)
|
||||
s + 2 chars EasyMotion jump
|
||||
gc toggle comment
|
||||
cs"' change surrounding " to '
|
||||
Alt+j / Alt+k move line
|
||||
,u undo tree
|
||||
,y clipboard yank
|
||||
```
|
||||
|
||||
---
|
||||
## 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.
|
||||
> Solarized · vim-lsp (no Node.js) · Markdown-first · One-command install.
|
||||
<h1 align="center">chopsticks</h1>
|
||||
|
||||
[](LICENSE)
|
||||
[](https://www.vim.org/)
|
||||
[](#installation)
|
||||
[](https://github.com/m1ngsama/chopsticks/releases)
|
||||
[](https://github.com/m1ngsama/chopsticks/commits/main)
|
||||
[](https://github.com/m1ngsama/chopsticks/stargazers)
|
||||
<p align="center">
|
||||
<strong>Vim for engineers. 29 plugins, 19ms startup, works over SSH.</strong>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<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
|
||||
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)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [LSP](#lsp)
|
||||
- [Key Mappings](#key-mappings)
|
||||
- [Markdown](#markdown)
|
||||
- [Features](#features)
|
||||
- [Plugins](#plugins)
|
||||
- [Customization](#customization)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
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.
|
||||
|
||||
---
|
||||
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 |
|
||||
|-----------|--------------|
|
||||
| **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 |
|
||||
## What's in the box
|
||||
|
||||
---
|
||||
| | |
|
||||
|-|-|
|
||||
| **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
|
||||
|
||||
| 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
|
||||
## Install
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash
|
||||
```
|
||||
|
||||
Non-interactive / CI:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/m1ngsama/chopsticks/main/get.sh | bash -s -- --yes
|
||||
```
|
||||
|
||||
### Git clone
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/m1ngsama/chopsticks.git ~/.vim
|
||||
cd ~/.vim && ./install.sh
|
||||
```
|
||||
|
||||
### What the installer does
|
||||
Supports macOS (brew), Debian/Ubuntu (apt), Arch (pacman), Fedora (dnf).
|
||||
|
||||
1. Detects OS and package manager
|
||||
2. Verifies or installs `curl`, `git`, `vim`
|
||||
3. Backs up existing `~/.vimrc`, then symlinks `~/.vimrc → ~/.vim/.vimrc`
|
||||
4. Installs vim-plug and runs `:PlugInstall`
|
||||
5. Offers to install system tools (ripgrep, fzf, ctags, shellcheck, hadolint, marksman)
|
||||
6. Offers to install 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`
|
||||
First launch installs plugins automatically (30-60s). Restart vim when done.
|
||||
|
||||
**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
|
||||
|
||||
Code intelligence is provided by **vim-lsp** — a pure VimScript LSP client with no
|
||||
Node.js dependency. It works on any machine, including servers accessed via SSH.
|
||||
```vim
|
||||
: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
|
||||
:LspInstallServer " auto-detects filetype and installs the correct server
|
||||
:LspStatus " check server status
|
||||
:ChopsticksLearn " interactive tutorial — 10 lessons
|
||||
,? " cheat sheet (every binding)
|
||||
```
|
||||
|
||||
Supported languages and their servers:
|
||||
|
||||
| Language | Server |
|
||||
|----------|--------|
|
||||
| Python | pylsp / pyright |
|
||||
| JavaScript / TypeScript | typescript-language-server |
|
||||
| Go | gopls |
|
||||
| Rust | rust-analyzer |
|
||||
| C / C++ | clangd |
|
||||
| Shell | bash-language-server |
|
||||
| HTML | vscode-html-language-server |
|
||||
| CSS / SCSS | vscode-css-language-server |
|
||||
| JSON | vscode-json-language-server |
|
||||
| YAML | yaml-language-server |
|
||||
| Markdown | marksman |
|
||||
| SQL | sqls |
|
||||
|
||||
**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`.
|
||||
|
||||
---
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Startup time | **19ms** (29 plugins loaded) |
|
||||
| Lazy-loaded | 8 plugins (on command or filetype) |
|
||||
| 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) |
|
||||
| TTY large file | 500KB (syntax disabled) |
|
||||
|
||||
Measured with `vim --startuptime`. We benchmark every change.
|
||||
|
||||
## 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
|
||||
:PlugInstall " install missing plugins
|
||||
:PlugUpdate " update all plugins
|
||||
```
|
||||
More in the [wiki](https://github.com/m1ngsama/chopsticks/wiki).
|
||||
|
||||
**LSP server not starting**
|
||||
## Contributing
|
||||
|
||||
```vim
|
||||
: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`.
|
||||
|
||||
---
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md). The two rules that matter: no Node.js dependencies, and don't regress startup time.
|
||||
|
||||
## 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
|
||||
|
||||
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
|
||||
|
|
@ -441,7 +429,7 @@ fi
|
|||
_vim_run +'PlugClean!' +qall || true # remove plugins no longer in vimrc; ignore exit code (none expected)
|
||||
_vim_run +'PlugInstall --sync' +qall || true # fzf post-install hook may exit non-zero; harmless
|
||||
|
||||
_plug_count=$(ls -1 "$HOME/.vim/plugged" 2>/dev/null | wc -l | tr -d ' ')
|
||||
_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
|
||||
die "Plugin installation failed — ~/.vim/plugged is empty. Check network and retry."
|
||||
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