- Lua 74%
- Vim Script 23.9%
- Shell 2.1%
| autoload | ||
| bin | ||
| docs | ||
| lua/mocha | ||
| plugin | ||
| scripts | ||
| LICENSE | ||
| README.md | ||
mocha.nvim
Completion + fuzzy finder for classic Vim. An own set, built from scratch: it replaces Shougo/denite.nvim, Shougo/deoplete.nvim, Shougo/neoinclude.vim, Shougo/deoplete-clangx, lighttiger2505/deoplete-vim-lsp, wellle/tmux-complete.vim, the roxma bridge shims (nvim-yarp, vim-hug-neovim-rpc) and gergap/vim-ollama — 9 plugins to 5, zero Python in the editor path.
The mocha family
| piece | what | where |
|---|---|---|
| mocha.nvim | this repo — finder + completion engine (denite/deoplete core parity) | git.zergs.net/sloth/mocha.nvim |
| mocha-clangx | clang code-completion source (deoplete-clangx port) | git.zergs.net/sloth/mocha-clangx |
| mocha-lsp | vim-lsp completion source (deoplete-vim-lsp port) | git.zergs.net/sloth/mocha-lsp |
| mocha-tmux | tmux pane-words source (tmux-complete port) | git.zergs.net/sloth/mocha-tmux |
| mocha-zerg | Vim front-end for Luna (zerg) — chat, range edits, inline completion, quickfix; replaces vim-ollama | ~/work/zerg/example/vim (inside the zerg repo; study in its client/docs/vim-integration.md, Luna-side asks in plan/mocha-zerg-luna-handoff.md) |
Each source repo is a thin, filetype-gated Lua 5.1 module implementing the same
source contract (docs/INTERFACES.md); mocha-zerg consumes the stream-json
transport rather than the ops seam but shares the family invariants: classic Vim,
no Python, parity-first, local by default.
What it is
- Finder (
:Mocha) — denite feature parity, scoped to the configured workflow: sources buffer / file/rec (+ git, py aliases) / file/old / grep / tag; matchers fuzzy, substring, project_files, ignore_globs; sorters sublime, rank; converters relative_word, truncate; filter buffer, resume, multi-select, preview, quickfix. - Completion (
mocha#complete#*) — deoplete feature parity for the configured filetypes (python, lua, erlang, c, cpp): debounced async gather, full_fuzzy matcher, rank sorter, converters, disabled_syntaxes, ignore_sources, indentkeys skip, post-Confirm skip, selection guard. - Backend: Lua 5.1 on vim's built-in
if_luabridge; viml autoload for editor plumbing; JSON strings at the boundary. Optional LuaJIT workers (bin/mochad, base64+msgpack over job pipes) take over filtering for candidate sets aboveg:mocha#worker_min(default 10000); everything works in-process when luajit is absent. FFI is deliberately not used in hot paths (measured — see docs/BENCH.md); it is reserved for future capability bindings in the workers (PCRE2, sqlite).
Requirements (Debian stable focus)
- Vim >= 9.1 with
+lua(Lua 5.1),+job,+channel,+timers. Debian stable 13 (trixie) or newer satisfies this; the 9.1 floor comes from theif_luabindings used (vim.call,vim.dict,vim.list, ...). - Optional:
luajitfor the worker path (Debian's package IS OpenResty luajit2). - Optional tools:
ag(file/rec, grep),ctags(tags),git.
On targeting vim-athena: there is no athena-specific target. On Debian, vim-athena
is a stub package that depends on vim-motif (verified: apt-cache depends vim-athena
→ Depends: vim-motif), and /usr/bin/gvim is the same vim.motif binary. mocha is
therefore built against vim features, not a GUI toolkit: it runs identically in a
terminal (vim), and in every GUI variant (gvim, vim-motif, vim-athena, vim-nox)
because they all expose the same if_lua surface. Nothing needs to be rebuilt or
reinstalled for athena; if a variant ever diverges in features, vim --version is the
checklist.
Install (vim-plug)
Plug 'https://git.zergs.net/sloth/mocha.nvim'
Plug 'https://git.zergs.net/sloth/mocha-clangx', {'for': ['c', 'cpp']}
Plug 'https://git.zergs.net/sloth/mocha-lsp', {'for': ['c', 'cpp', 'python', 'lua', 'erlang']}
Plug 'https://git.zergs.net/sloth/mocha-tmux'
" mocha-zerg (the vim-ollama replacement) lives in the zerg repo, not a plug repo:
set rtp+=~/work/zerg/example/vim
Configuration lives in config/vim/plugin/mocha-finder.vim and mocha-complete.vim
(see the dotfiles repo) — the API mirrors denite/deoplete call shapes, so migrations
are mechanical. The finder keys are the denite keys: <leader>d buffers, <leader>f
live grep (ag), <leader><BS> resume, <F4> project files.
Feature extent beyond the originals
Additive, opt-in, documented in docs/LEARNINGS.md and docs/PARITY.md:
quickfix/loclist(+quickfix_all,loclist_all) actions with query titles- per-session per-dir cache for file/rec (skips the job when the listing is fresh)
- LuaJIT worker offload above a threshold (see docs/BENCH.md for crossover)
- prompt history (+ unbound cycle actions),
path_display='tail', preview-follow (gated, update-only), identity-based multi-select (survives re-filter) - zerg integration: host-side ops seam (docs/ZERG.md, vim-free
lua/mocha/ops/*) and mocha-zerg, the Vim front-end for Luna that replaces vim-ollama (chat, range edits, quickfix fixes, ghost-text completion)
Performance vs the original stack (percent view; raw runs in docs/MEASUREMENTS.md)
Both stacks measured head-to-head on the same box and fixture, 2026-10-14. PUC = vim's embedded Lua 5.1; JIT = the optional LuaJIT workers (engage above 10k candidates, in-process fallback below).
| metric | old stack (denite+deoplete+yarp+python3.13) | mocha | mocha vs old |
|---|---|---|---|
| cold end-to-end (launch + first candidates) | ~330 ms | ~138 ms | 2.4x faster (-58%) |
| first candidates, file/rec/git | 303 ms cold / 111 ms warm | ~117 ms | 2.6x faster cold; warm parity (+/-5%) |
| grep first result | 140 ms | ~111 ms | 1.3x faster (-21%) |
| fuzzy filter 50k | 7.0-9.5 ms (py re) |
9.3-11.8 PUC / 2.6-2.9 JIT | 25-30% slower PUC; 2.5-3.4x faster JIT |
| substring 50k | 3.0-3.1 ms | 3.3-3.7 PUC / 0.7-1.1 JIT | 10-20% slower PUC; 2.7-4.3x faster JIT |
| sublime sort 50k | 471 ms | 351 PUC / 35.1 JIT | 1.3x faster PUC; 13x faster JIT |
| memory, finder open | ~71 MB (vim 41 + py host 29) | ~26 MB zero helpers | -64% (-42% with workers) |
| disk, replaced stack | ~25 MB (incl. vim-ollama + venv) | ~4.5 MB | -82% |
The two honest asterisks: warm directory listing is a wash (the python host is only
paid once), and the pure-PUC fuzzy matcher is 25-30% slower than Python's re per
keystroke — the LuaJIT path (the real default above 10k candidates) inverts that
2.5-3.4x. Everything else, especially cold start and memory, is decisively ahead.
Parity guarantee
The configured surface is verified 1:1 against the originals by empirical diffing (same corpora and fixtures through both implementations), see:
docs/PARITY.md— final status table with evidencedocs/PARITY_COMPLETION.md— the detailed completion audit with reproducersdocs/BENCH.md— measurements, methodology, worker/FFI analysisdocs/LEARNINGS.md— design notes from the successor ecosystems (ddu, ddc, telescope)docs/INTERFACES.md— internal contracts (sources, filters, workers)docs/REVIEW.md— build history and review roundsdocs/ZERG.md— zerg integration: the ops seam + the mocha-zerg front-end pointer
Roadmap ("when time comes")
- GUI theme parity (low priority): onehalf already ships GUI colors
(
onehalfdark.vimgui=definitions),/usr/bin/gvimstarts cleanly on the X display, and screenshot tooling exists. When the GUI variant is actually used: add ahas('gui_running')block in the vimrc (minimal chrome:set guioptions-=T,-=m,-=r, keep the One Half dark palette; font already set to Inconsolata Nerd Font 12). Nothing is needed for terminal vim. - Prompt-buffer filter line (
buftype=prompt) — blocked until the<CR>mapping semantics are redesigned deliberately. - Top-K insertion — measured dead end in-process (scoring dominates; workers cover large sets); revisit only with new evidence.
- Per-picker mapping API, file:line:col prompt parsing — waiting on real demand.
Tests
sh scripts/smoke.sh— fast gate: luac, finder, interactive grep gating, worker ping.sh scripts/test.sh— the full headless suite (10 sections): luac, ops (filter/load/run/fuzzy/score/parse_grep/parse_tags), finder sources, the interactive filter path (spawn gating + AND terms + resume), multi-source, actions (open/split/tabopen/preview/select-all/quit), quickfix output, cramped-layout (E36) resilience, the completion config API, and the 11k-file worker path (timings printed). Self-fixturing; no state outside a temp dir.scripts/test.shruns everywhere vim 9.1 + ag exist;luajitsections skip cleanly when absent; end-to-end 18.2 s (mocha-zerg's mock suite: 0.43 s). Parity oracles (denite/deoplete diffing) were session artifacts; the suite above is the permanent regression net.
Verified environment
Debian 13 stable, vim 9.1.1230+ patches, +lua(5.1) +job +channel +timers. On the user's box, every flow in the dotfiles configuration is tested headless (see docs/REVIEW.md); interactive passes are the user's.