diff --git a/README.md b/README.md index 0e123ab..d9565b3 100644 --- a/README.md +++ b/README.md @@ -412,35 +412,47 @@ it shows: The Story Bible window indexes all Story Bible items from your project's character, location, lore, and other reference directories. It supports: -* Automatic indexing from directories like `03-Characters`, `02-Story Bible`, - `Characters`, `Locations`, `Lore`, etc. -* Two reference syntaxes in your draft text: +* Automatic indexing from the first directory found: `03-Story-Bible` (the + bundled template's own folder), then `03-Characters`, `02-Story Bible`, + `Characters`, `Locations`, `Lore`, and so on. +* **Automatic linking in the draft — no markup required.** A name spelled and + capitalized the same way as an item's `name:` or an `aliases:` entry is + matched wherever it appears in ordinary prose ("**Bixby** stood at the + door"). Two explicit syntaxes still work too, and win any overlap with an + automatic match: - Wiki-style: `[[Character Name]]` or `[[John Doe]]` - Mention-style: `@CharacterName` or `@John` -* **Purple background highlighting** of Story Bible references in the editor +* **Purple background highlighting** of every match — automatic or explicit — + in the editor. Hovering one shows a card with the item's name, type, and a + summary (see below), and a link to open its full entry; the card stays put + while you move the pointer onto it to click that link. * Click items in the Story Bible window to see all references to them in the current file * Click reference buttons to jump directly to that location in the editor -* Metadata extraction from YAML frontmatter (id, title, type, **aliases** fields) or from filenames +* Metadata extraction from YAML frontmatter (id, name, type, **aliases**, + **summary** fields) or from filenames * Case-insensitive search and lookup * **Aliases support**: References match item IDs, names, **and aliases** for flexible linking Character sheets in the `Characters` folder are automatically indexed, and any -markdown file with YAML frontmatter containing `id:` and `title:` fields will be -included in the index. You can also add an `aliases:` field with alternative names -for a character or item: +markdown file with YAML frontmatter containing `id:` and `name:` fields will be +included in the index (`title:` is read too, if a sheet uses that word instead). +You can also add `aliases:` for alternative names, and `summary:` for the one-line +hover card: ```yaml --- id: john_smith -title: "John Smith" +name: "John Smith" type: character aliases: ["Johnny", "JS"] +summary: "A retired locksmith dragged back for one last job." --- ``` -With aliases defined, references like `[[Johnny]]` or `@JS` will match the "John Smith" -character entry. References in your draft text that match Story Bible items -by ID, name, or alias are highlighted and clickable. +With aliases defined, references like `[[Johnny]]`, `@JS`, or a bare "Johnny" in +prose will all match the "John Smith" character entry. Every reference in your +draft that matches a Story Bible item — by ID, name, or alias — is highlighted +and clickable, whether or not you typed any markup to get it there. ### Story Bible Editor (Edit ▸ Story Bible…) diff --git a/src/app/editor.rs b/src/app/editor.rs index 2a4acd9..1549bcb 100644 --- a/src/app/editor.rs +++ b/src/app/editor.rs @@ -489,7 +489,7 @@ pub(super) fn build_editor_job( let mut job = LayoutJob::default(); job.wrap.max_width = wrap_width; - if grammar.is_empty() && find.is_empty() { + if grammar.is_empty() && find.is_empty() && bible.is_empty() { job.append(text, 0.0, TextFormat::simple(font_id, color)); return job; } @@ -809,6 +809,33 @@ pub(super) fn toggle_line_comment( mod tests { use super::*; + #[test] + fn a_bible_only_reference_is_not_skipped_by_the_grammar_find_fast_path() { + // build_editor_job short-circuits to one plain run when there's + // nothing to highlight — a regression check that it doesn't take + // that shortcut when the only thing to highlight is a Story Bible + // mention (no grammar issues, no active search), which used to + // mean the purple background — and the hover card that depends on + // it being visible to find — never appeared for a name with no + // spelling issue of its own. + let text = "Protagonist stood at the door."; + let job = build_editor_job( + text, + 14.0, + egui::Color32::WHITE, + &[], + &[], + None, + &[(0, 11)], // "Protagonist" + f32::INFINITY, + ); + let highlighted = job + .sections + .iter() + .any(|s| s.format.background != egui::Color32::default()); + assert!(highlighted, "a bible-only reference must still be formatted"); + } + #[test] fn byte_to_char_is_the_inverse_of_char_to_byte() { // "café!" — é is 2 bytes, so byte and char indices diverge after it. diff --git a/src/story_bible.rs b/src/story_bible.rs index 236ddd7..975fef6 100644 --- a/src/story_bible.rs +++ b/src/story_bible.rs @@ -201,6 +201,7 @@ fn extract_from_frontmatter(relative_path: &str, content: &str) -> Option = None; + let mut title: Option = None; let mut id: Option = None; let mut item_type: Option = None; let mut aliases: Vec = Vec::new(); @@ -209,8 +210,13 @@ fn extract_from_frontmatter(relative_path: &str, content: &str) -> Option Option