use crate::editor::text_area::markers::{GutterMarker, Severity};
pub(crate) fn error_marker(error: &str) -> Option<GutterMarker> {
let rest = error.strip_prefix("line ")?;
let (number, message) = rest.split_once(": ")?;
let line: usize = number.parse().ok()?;
Some(GutterMarker {
line: line.checked_sub(1)?,
column: 0,
severity: Severity::Error,
message: message.to_string(),
})
}
pub(crate) const STARTER_STORY: &str = "---
title: Untitled Story
characters:
narrator: Narrator
---
# start
**narrator:** Once upon a time...
The story begins here.
";
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_parse_error_marks_its_line() {
let broken = STARTER_STORY.replace("The story begins here.", "[jump](#nowhere) and prose");
let error = concinnity_cook::build_only::validate_story_source(&broken).unwrap_err();
let marker = error_marker(&error).expect("the error names a line");
let line = broken.lines().nth(marker.line).unwrap();
assert!(line.contains("#nowhere"), "{error} -> {line:?}");
assert_eq!(marker.severity, Severity::Error);
assert!(!marker.message.starts_with("line"));
}
#[test]
fn errors_without_a_source_line_mark_nothing() {
assert_eq!(
error_marker("frontmatter line 2: expected `key: value`"),
None
);
assert_eq!(error_marker("line zero: nonsense"), None);
assert_eq!(error_marker("line 0: out of range"), None);
}
#[test]
fn starter_story_parses() {
concinnity_cook::build_only::validate_story_source(STARTER_STORY)
.expect("the starter story template parses");
}
}