zudo-text

検索したい単語を入力

いつでも検索バーを開ける

Spell

bridge.spell checks prose text against the OS system dictionary (NSSpellChecker on macOS) and returns misspelling spans for the markdown editor's underline decorations.

Adapter support

bridge.spell.isSupported() has no Capabilities flag — it is a runtime probe only, like bridge.fileSearch.isSupported():

  • Tauri macOS desktop — checks text against the account's system dictionary and user-added words.

  • Mock adapter — deterministic in-memory fixture for renderer tests and isolated preview fixtures. It never touches an OS dictionary.

  • REST, browser production, iOS, and other Tauri platforms — report unsupported. They never forward spell-check requests to an HTTP endpoint or another engine.

check never throws on any adapter, including when unsupported — it is called from a timer-driven editor plugin that cannot afford to crash the debounce loop.

Bridge contract

interface SpellRange {
  start: number;
  length: number;
}

interface SpellAPI {
  isSupported(): Promise<boolean>;
  check(texts: string[]): Promise<SpellRange[][]>;
  suggest(word: string): Promise<string[]>;
  learn(word: string): Promise<void>;
  ignore(word: string): Promise<void>;
}

function createUnsupportedSpell(): SpellAPI;

check takes one paragraph-sized prose segment per array entry and returns one SpellRange[] per input segment, in input order. start/length are UTF-16 code units — the same unit JS string indexing and CodeMirror 6 offsets use, so no conversion is needed before turning a range into a decoration.

suggest returns up to 5 correction suggestions for a single word, best-first. learn adds a word to the OS user dictionary (persists across sessions and other apps on the same machine). ignore suppresses a word for the current app session only, scoped to one spell-document tag on the Tauri adapter — it does not persist and does not affect the OS user dictionary.

createUnsupportedSpell() is the shared stub behind RestAdapter: isSupported() resolves false, check(texts) resolves texts.map(() => []), suggest resolves [], and learn/ignore resolve without effect.

Mock adapter fixture

createMockSpell(options?: MockSpellOptions) ships a fixed default word list (teh→the, recieve→receive, definately→definitely, wierd→weird, mesage→message, spelings→spellings), matched case-insensitively by tokenizing each segment on /[A-Za-z']+/. options.words replaces the fixture; options.supported overrides the default navigator.platform Mac sniff (copied from the mock fileSearch.isSupported disambiguation of real macOS vs iPadOS via maxTouchPoints).

learn/ignore are tracked in an in-memory set scoped to that createMockSpell() call, so subsequent check calls on the same instance stop flagging a learned or ignored word — this is observable directly in tests without a fake IPC layer.

See Spellcheck for the full feature: the Rust engine, the CodeMirror extension, the context menu, settings, and the design decisions behind the contract above.