use std::borrow::Cow;
use std::ops::Range;
pub type Spanned<'s> = (Event<'s>, Range<usize>);
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Alignment {
#[default]
None,
Left,
Center,
Right,
}
impl Alignment {
#[must_use]
pub const fn as_str(self) -> Option<&'static str> {
match self {
Alignment::None => None,
Alignment::Left => Some("left"),
Alignment::Center => Some("center"),
Alignment::Right => Some("right"),
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Container<'s> {
Paragraph,
Heading {
level: u8,
},
Blockquote,
List {
ordered: bool,
start: Option<u64>,
},
Item,
CodeBlock {
info: Option<Cow<'s, str>>,
},
Emphasis,
Strong,
Strikethrough,
Link {
destination: Cow<'s, str>,
title: Cow<'s, str>,
},
Image {
destination: Cow<'s, str>,
title: Cow<'s, str>,
},
Table {
alignments: Vec<Alignment>,
},
TableHead,
TableRow,
TableCell,
}
impl Container<'_> {
#[must_use]
pub const fn kind(&self) -> ContainerKind {
match self {
Container::Paragraph => ContainerKind::Paragraph,
Container::Heading { .. } => ContainerKind::Heading,
Container::Blockquote => ContainerKind::Blockquote,
Container::List { .. } => ContainerKind::List,
Container::Item => ContainerKind::Item,
Container::CodeBlock { .. } => ContainerKind::CodeBlock,
Container::Emphasis => ContainerKind::Emphasis,
Container::Strong => ContainerKind::Strong,
Container::Strikethrough => ContainerKind::Strikethrough,
Container::Link { .. } => ContainerKind::Link,
Container::Image { .. } => ContainerKind::Image,
Container::Table { .. } => ContainerKind::Table,
Container::TableHead => ContainerKind::TableHead,
Container::TableRow => ContainerKind::TableRow,
Container::TableCell => ContainerKind::TableCell,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ContainerKind {
Paragraph,
Heading,
Blockquote,
List,
Item,
CodeBlock,
Emphasis,
Strong,
Strikethrough,
Link,
Image,
Table,
TableHead,
TableRow,
TableCell,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Event<'s> {
Start(Container<'s>),
End(ContainerKind),
Text(Cow<'s, str>),
Code(Cow<'s, str>),
Html(Cow<'s, str>),
InlineHtml(Cow<'s, str>),
SoftBreak,
HardBreak,
Rule,
}
pub trait Tokenizer {
fn tokenize<'s>(&self, source: &'s str) -> Vec<Spanned<'s>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_container_names_its_own_kind() {
assert_eq!(Container::Paragraph.kind(), ContainerKind::Paragraph);
assert_eq!(
Container::Heading { level: 3 }.kind(),
ContainerKind::Heading
);
assert_eq!(
Container::Link {
destination: Cow::Borrowed("/x"),
title: Cow::Borrowed(""),
}
.kind(),
ContainerKind::Link
);
}
#[test]
fn alignments_spell_themselves_as_markdoc_does() {
assert_eq!(Alignment::None.as_str(), None);
assert_eq!(Alignment::Left.as_str(), Some("left"));
assert_eq!(Alignment::Center.as_str(), Some("center"));
assert_eq!(Alignment::Right.as_str(), Some("right"));
}
}