use crate::{
consts::DIVERT_MARKER,
error::{parse::line::LineError, utils::MetaData},
line::{
parse::{parse_choice, parse_gather, parse_internal_line},
InternalChoice, InternalLine,
},
};
#[derive(Clone, Debug, PartialEq)]
pub enum ParsedLineKind {
Choice {
level: u32,
choice_data: InternalChoice,
},
Gather {
level: u32,
line: InternalLine,
},
Line(InternalLine),
}
#[cfg(test)]
impl ParsedLineKind {
pub fn choice(level: u32, choice_data: InternalChoice) -> Self {
ParsedLineKind::Choice { level, choice_data }
}
pub fn gather(level: u32, line: InternalLine) -> Self {
ParsedLineKind::Gather { level, line }
}
pub fn line(line: InternalLine) -> Self {
ParsedLineKind::Line(line)
}
}
pub fn parse_line(content: &str, meta_data: &MetaData) -> Result<ParsedLineKind, LineError> {
if let Some(choice) = parse_choice(content, meta_data).transpose() {
choice
} else if let Some(gather) = parse_gather(content, meta_data).transpose() {
gather
} else {
parse_internal_line(content, meta_data).map(|line| ParsedLineKind::Line(line))
}
.map_err(|kind| LineError {
line: content.to_string(),
kind,
meta_data: meta_data.clone(),
})
}
pub fn parse_markers_and_text(line: &str, marker: char) -> Option<(u32, &str)> {
if line.trim_start().starts_with(marker) {
let (markers, line_text) = split_markers_from_text(line, marker);
let num = markers.matches(|c| c == marker).count() as u32;
Some((num, line_text))
} else {
None
}
}
fn split_markers_from_text(line: &str, marker: char) -> (&str, &str) {
let split_at = line.find(|c: char| !(c == marker || c.is_whitespace()));
match split_at {
Some(i) => line.split_at(i),
None => (line, ""),
}
}
pub fn split_at_divert_marker(content: &str) -> (&str, &str) {
if let Some(i) = content.find(DIVERT_MARKER) {
content.split_at(i)
} else {
(content, "")
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn simple_line_parses_to_line() {
let line = parse_line("Hello, World!", &().into()).unwrap();
let comparison = parse_internal_line("Hello, World!", &().into()).unwrap();
assert_eq!(line, ParsedLineKind::Line(comparison));
}
#[test]
fn line_with_choice_markers_parses_to_choice() {
let line = parse_line("* Hello, World!", &().into()).unwrap();
match line {
ParsedLineKind::Choice { .. } => (),
other => panic!("expected `ParsedLineKind::Choice` but got {:?}", other),
}
}
#[test]
fn line_with_gather_markers_parses_to_gather() {
let line = parse_line("- Hello, World!", &().into()).unwrap();
match line {
ParsedLineKind::Gather { .. } => (),
other => panic!("expected `ParsedLineKind::Gather` but got {:?}", other),
}
}
#[test]
fn choices_are_parsed_before_gathers() {
let line = parse_line("* - Hello, World!", &().into()).unwrap();
match line {
ParsedLineKind::Choice { .. } => (),
other => panic!("expected `ParsedLineKind::Choice` but got {:?}", other),
}
}
}