escriba-search 0.1.29

Incremental buffer search for escriba — vim-grade `/` and `?` with smartcase, regex, wrap-around, whole-word `*`/`#`, hlsearch and search history. Pure and side-effect-free: a function of (text, pattern, cursor).
Documentation

Incremental buffer search for escriba — vim's / and ?.

What this is

The whole search feature as a pure function of (text, pattern, cursor). There is no I/O here: no buffer handle, no renderer, no clock. That is deliberate and is what the ★★ default delivery method asks for — a pure core split from side effects. Search happens to need no Environment seam at all, because it genuinely has no effects to inject, so every behaviour below is provable by a plain unit test with no mock and no fixture.

The caller owns the buffer and the cursor; this crate answers "where should the cursor go" and "which ranges should light up".

Feature parity with vim

vim here
/pat ?pat [SearchState::open] + [SearchState::accept]
incremental highlight while typing [SearchState::preview]
n / N [SearchState::repeat]
* / # [SearchState::search_word]
hlsearch / :noh [SearchState::highlights] / [SearchState::clear_highlight]
ignorecase / smartcase [CaseMode]
wrap + "hit BOTTOM" message [Wrapped]
bare /<CR> repeats last [Accepted::ReusedPrevious]
search history + arrows [SearchState::history_step]
regex patterns [SearchPattern::compile]

Two invariants worth knowing

Offsets are chars, never bytes. regex reports bytes; escriba's buffer is char-addressed. The conversion happens once, inside [find_all], so no consumer can mix them. A byte/char mix-up is invisible in ASCII tests and wrong on the first accented character — [engine] tests it directly.

A prompt and a committed search are different things. Cancelling /xyz must not disturb the foo you were already searching. That falls out of the type — the prompt is an Option<Prompt> holding its own text and origin, so dropping it cannot touch the committed pattern.