Add offline live spell checking (Hunspell via spellbook)

Spelling is now checked live as you type, fully offline, using the
pure-Rust `spellbook` crate to read Hunspell .aff/.dic dictionaries (no C
libhunspell — the binary stays self-contained; ldd unchanged).

- Canadian (en-CA, default) and British (en-GB) English dictionaries are
  compiled in; more languages are auto-discovered from system Hunspell
  folders and ~/.config/md-manuscript/dictionaries/. A "Spelling" row in
  the top bar toggles live checking and picks the dictionary.
- Misspellings are underlined in red; right-clicking a word opens a menu
  of suggested corrections. A results-panel and one-click fixes work too.
- Checks run on a background thread, debounced ~400ms after the last edit.
  Prose is extracted with pulldown-cmark so code spans, code blocks and
  link targets are skipped; ALL-CAPS initialisms are ignored.
- LanguageTool still layers on top: when its results are fresh they own
  the underlines (spelling + grammar); once you edit, the offline checker
  resumes. The editor underlines, issues panel and fix-apply logic are
  now shared between the two sources.

Bundled dictionaries are SCOWL-derived under a permissive license (kept
in dictionaries/<lang>/license). Adds spell-check unit tests (tokenizer,
code-block skipping, offset mapping, en-CA/en-GB spelling); 40 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N9kRuP7JvXoUGdNNeg5ZSs
This commit is contained in:
landon
2026-08-14 06:25:08 -05:00
parent 691d1a0515
commit 19dddf30c7
14 changed files with 101168 additions and 69 deletions
+30 -1
View File
@@ -110,9 +110,38 @@ The status bar shows a live **word count** for the current file, plus the net
words added (or removed) to it since the current session started. The count
updates as you type, including unsaved edits.
## Spelling (offline)
Spelling is checked **live as you type**, entirely offline — no server, no
network. Misspelled words get a red underline; **right-click** one for a menu of
suggested corrections (click a suggestion to apply it). It uses Hunspell
dictionaries read by the pure-Rust [`spellbook`](https://crates.io/crates/spellbook)
crate, so the binary stays self-contained.
* **Two dictionaries are built in** — Canadian English (`en-CA`, the default)
and British English (`en-GB`). Pick one from the **Dictionary** dropdown on
the *Spelling* row of the top bar; the choice is remembered.
* **More languages** are discovered automatically from the usual Hunspell
folders (`/usr/share/hunspell`, `/usr/share/myspell`, …) and from a per-user
folder, `~/.config/md-manuscript/dictionaries/`. Drop a matching
`xx_YY.aff` + `xx_YY.dic` pair in there (e.g. from your distro's
`hunspell-de-de` package) and it appears in the dropdown.
* **Untick “Check as I type”** on the Spelling row to turn the underlines off.
* Code spans, fenced/indented code blocks and link targets are skipped, and
ALL-CAPS initialisms (ODT, HTTP) are left alone, to cut false positives.
When you run a **LanguageTool** check (below), its richer spelling-and-grammar
results take over the underlines until you next edit the text — at which point
the live offline checker resumes. In other words, LanguageTool is used when it's
available and current; the offline checker is the always-on default.
The bundled dictionaries live under `dictionaries/` and are derived from
[SCOWL](http://wordlist.sourceforge.net/) under a permissive license (kept
alongside them in each `license` file).
## Grammar & spelling (LanguageTool)
The editor can check the current file against a
The editor can *additionally* check the current file against a
[LanguageTool](https://languagetool.org/) server — typically a **local
instance**, so your manuscript never leaves your machine.