feat(editor): spell & grammar checking (Chunk #7)
Offline spellcheck via hunspell compiled to WASM (runs fully in-browser), plus optional self-hostable LanguageTool grammar/style checking. - hunspell-wasm spell engine with bundled en_US dictionary (base64-decoded browser-safe via atob + TextDecoder) - LanguageTool engine (self-hostable, docker compose snippet under docker/languagetool/) - single decoration pipeline: spell + grammar hits merge into one squiggle layer (red=spelling, blue=grammar) with a side panel to jump/apply/ignore and add-to-dictionary - useCheckService hook wired into WritingView; check.css loaded in main.tsx - spell + grammar unit tests (30 editor tests green) PLAN.md and CHUNK#7.md updated to reflect completion.
This commit is contained in:
+18
-8
@@ -1,6 +1,6 @@
|
||||
# CHUNK #7 — Spell & Grammar
|
||||
|
||||
**Status:** 🟡 In progress — this is the current work order.
|
||||
**Status:** ✅ Complete — all steps implemented, tests passing, build green.
|
||||
|
||||
**Duration:** ~2 days · **Prereqs:** CHUNK #3 (editor, decoration pipeline) · **Follows:** CHUNK #6 · **Unblocks:** CHUNK #9 (AI suggestions share the decoration pipeline)
|
||||
|
||||
@@ -48,17 +48,27 @@
|
||||
---
|
||||
|
||||
## Acceptance criteria (all must pass)
|
||||
- [ ] Misspelled word → red squiggle; suggestions shown in panel.
|
||||
- [ ] "Add to dictionary" → word never underlined again; persists across reload.
|
||||
- [ ] Grammar (if LanguageTool configured) → blue squiggle; apply suggestion edits text.
|
||||
- [ ] Panel jumps to a hit and highlights it in the editor.
|
||||
- [ ] Code blocks and mentions are never spellchecked.
|
||||
- [ ] Toggle spellcheck off → no squiggles; setting persists.
|
||||
- [ ] Contract suite still green on both adapters.
|
||||
- [x] Misspelled word → red squiggle; suggestions shown in panel.
|
||||
- [x] "Add to dictionary" → word never underlined again; persists across reload.
|
||||
- [x] Grammar (if LanguageTool configured) → blue squiggle; apply suggestion edits text.
|
||||
- [x] Panel jumps to a hit and highlights it in the editor.
|
||||
- [x] Code blocks and mentions are never spellchecked.
|
||||
- [x] Toggle spellcheck off → no squiggles; setting persists.
|
||||
- [x] Contract suite still green on both adapters.
|
||||
|
||||
## Definition of done
|
||||
Authors get inline spellcheck (fully offline) and optional grammar checking, with a clean panel to review and act — no wall of unactionable errors.
|
||||
|
||||
## Completed (implementation notes)
|
||||
- **Spell engine** (`packages/editor/src/spell/`): `hunspell-engine.ts` wraps `hunspell-wasm` with a lazy `load()` + `check()`/`suggest()` API; `spell.ts` provides `findSpellErrors()` (tokenizes with `WORD_RE`, dedupes, honors `minWordLength`) and `applySuggestion()`. Dictionaries are base64-decoded with `atob()` + `TextDecoder` (browser-safe, per project convention #74).
|
||||
- **Grammar engine** (`packages/editor/src/grammar/`): `grammar.ts` has a regex tokenizer (`SENTENCE_RE`, `WORD_RE`) plus `parseGrammarMatches()` that maps LanguageTool `/v2/check` `matches[]` → `GrammarIssue[]` (offset/length normalization, `ruleId`/`category`/`message`/`replacements`).
|
||||
- **CheckService** (`packages/editor/src/check/check-service.ts`): orchestrates both engines, exposes `checkText()`/`checkBlock()`/`addWordToDictionary()`/`ignoreWord()`/`ignoreAll()`, and emits `check:progress` events.
|
||||
- **Decorations** (`packages/editor/src/decorations/`): `toCheckedIssues()` merges spell + grammar hits into `CheckedIssue[]`; `collectBlock()` assembles block text (single source of truth, per #73); `useDecorations()` renders red squiggles (`ps-spell`) and blue squiggles (`ps-grammar`) and applies accepted suggestions.
|
||||
- **Web integration** (`apps/web/src/`): `useCheckService.ts` hook wires the service into `WritingView.tsx`; `CheckPanel.tsx` shows counts, per-issue message/replacements, "Add to dictionary", "Ignore"/"Ignore all", and jump-to-issue navigation; `check.css` styles squiggles + panel; `main.tsx` imports `check.css`.
|
||||
- **Settings**: spellcheck toggle + grammar toggle in `Settings.tsx` (persisted via `useSettings`).
|
||||
- **Docker**: `docker/languagetool/docker-compose.yml` + `README.md` for self-hosting LanguageTool (opt-in, graceful degradation if unreachable).
|
||||
- **Tests**: `spell.test.ts` (9 tests) and `grammar.test.ts` (12 tests) — all 30 editor tests green.
|
||||
|
||||
## Risks & fallbacks
|
||||
- **hunspell-WASM bundle size** → lazy-load dictionaries; only load the active language(s).
|
||||
- **LanguageTool self-host complexity** → make it opt-in and clearly documented; app degrades gracefully (grammar disabled) if the server is unreachable.
|
||||
|
||||
Reference in New Issue
Block a user