# Inkhaven 1.2.22 — Project-wide find & replace

The edit a novelist needs most often is the one Inkhaven couldn't do:
change something *across the whole book*. Find/replace worked only on the
open paragraph; the concordance was read-only. Renaming a character over 40
chapters was impossible without leaving the editor.

1.2.22 adds **project-wide find & replace** — and does it **safely**:
nothing changes without review, and every touched paragraph is snapshotted
first. It's also the last 1.2 before the 1.3 *editorial pass* cycle: the
review-gated apply machinery here is the substrate that cycle's AI-proposed
edits will reuse.

Tests 1169 → 1186. Zero new Rust dependencies — the matcher rides the
`regex` crate already in-tree. One new tutorial
([64](../Tutorials/64-project-find-and-replace.md)).

## In the editor

Open Find & Replace with `Ctrl+R`, type your pattern and replacement, then
**`Ctrl+B`** toggles the scope from *this paragraph* to *the whole book*.
**Enter** scans every user-book paragraph and opens a **review modal**:

- Every match is shown **in context** with the hit highlighted, grouped by
  paragraph.
- **`Space`** skips (or un-skips) the match under the cursor, **`a`** keeps
  all, **`n`** skips none — per-match control, nothing applied blindly.
- **`Enter`** applies only the kept matches; **`Esc`** cancels.

Each changed paragraph is **snapshotted before the write** (annotated
`replace: X → Y`), so `F6` is your undo.

## From the command line

`inkhaven replace <pattern> <replacement>` mirrors it with a
preview-then-apply gate for scripted / CI renames:

```text
$ inkhaven replace "Anne" "Anna" --dry-run
…  »Anne« looked up …
replace: 37 matches in 24 paragraphs — dry run, nothing changed

$ inkhaven replace "Anne" "Anna" --yes
replace: applied 37 replacements in 24 paragraphs; 24 snapshots taken (restore via F6 in the editor)
```

A bare `inkhaven replace …` refuses to write and just reports the count, so
it's always safe. Flags: `--dry-run`, `--yes`, `--regex` (with `$1`…
captures), `--substring`, `--ignore-case`, `--book <name>`,
`--include-system`.

## The safe-by-design choices

- **Lexical, not semantic** — literal / whole-word / opt-in regex over a
  linear scan of paragraph bodies. Find-replace wants *exhaustive exact*
  matches with byte positions, which a vector index can't do; the scan
  never touches the embeddings, and there's no second full-text index to
  maintain.
- **Whole-word by default** — kills the `Will`/`will`, `Mark`/`market`
  footgun. `--substring` (CLI) for raw substring matching.
- **User books only by default** — a manuscript rename won't silently
  rewrite your Notes / Research / Facts. `--include-system` opts in.
- **Always reversible** — snapshot-before-write on every touched paragraph;
  the CLI dry-run previews, the editor reviews per match.

## Also in 1.2.22

Three consolidation-audit items (a shared reading-time formatter, a shared
sentence splitter, a shared chapter-prose walk) were examined and **closed
as intentional non-duplicates** — on inspection they share only a
superficial shape and diverge in substance (rounding/format, boundary
algorithm, conversion/formatting), so merging would change behaviour or add
abstraction for negative benefit. The divergence is now documented at each
site so the audit isn't re-attempted.

## New surfaces

- CLI: `inkhaven replace`.
- Editor: `Ctrl+B` in the Find & Replace modal toggles whole-book scope and
  opens the review. See [`KEYBINDING.md` §3.10](../KEYBINDING.md) and
  [Tutorial 64](../Tutorials/64-project-find-and-replace.md).
