No description
  • Lua 74%
  • Vim Script 23.9%
  • Shell 2.1%
Find a file
Jean Chassoul 258bafc70a docs: typo
2026-10-14 15:16:28 -05:00
autoload polish: chunked cache convert, cramped-layout fallbacks, smoke script, learnings 2026-10-14 12:39:25 -05:00
bin mocha.nvim: initial import 2026-10-14 09:12:09 -05:00
docs docs: percent-view performance tables (head-to-head ratios; the two honest asterisks) 2026-10-14 15:16:24 -05:00
lua/mocha polish: chunked cache convert, cramped-layout fallbacks, smoke script, learnings 2026-10-14 12:39:25 -05:00
plugin mocha.nvim: initial import 2026-10-14 09:12:09 -05:00
scripts test: the permanent headless suite — 10 sections (ops, finder, filter, actions, quickfix, E36, completion API, worker path); testing gotchas in LEARNINGS 2026-10-14 14:59:14 -05:00
LICENSE mocha.nvim: initial import 2026-10-14 09:12:09 -05:00
README.md docs: typo 2026-10-14 15:16:28 -05:00

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_lua bridge; 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 above g: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 the if_lua bindings used (vim.call, vim.dict, vim.list, ...).
  • Optional: luajit for 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 evidence
  • docs/PARITY_COMPLETION.md — the detailed completion audit with reproducers
  • docs/BENCH.md — measurements, methodology, worker/FFI analysis
  • docs/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 rounds
  • docs/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.vim gui= definitions), /usr/bin/gvim starts cleanly on the X display, and screenshot tooling exists. When the GUI variant is actually used: add a has('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.sh runs everywhere vim 9.1 + ag exist; luajit sections 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.