mod block;
mod generated_entities;
mod inline;
mod tagfilter;
mod utils;
pub mod html;
use std::borrow::Cow;
use std::collections::VecDeque;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Event<'a> {
Start(Tag<'a>),
End,
Text(Cow<'a, str>),
Code(Cow<'a, str>),
SoftBreak,
HardBreak,
ThematicBreak,
Html(Cow<'a, str>),
TaskListMarker(bool),
InlineMath(Cow<'a, str>),
DisplayMath(Cow<'a, str>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Tag<'a> {
Paragraph,
Heading(u8),
CodeBlock(Option<Cow<'a, str>>),
CodeSpan,
DisplayMath,
HtmlBlock,
Quote,
List(ListKind),
Item,
Emphasis,
Strong,
Link {
url: Cow<'a, str>,
title: Option<Cow<'a, str>>,
},
Image {
url: Cow<'a, str>,
title: Option<Cow<'a, str>>,
},
Strikethrough,
Table(Vec<Alignment>),
TableHead,
TableBody,
TableRow,
TableCell,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ListKind {
Ordered(u32),
Unordered,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
None,
Left,
Center,
Right,
}
pub(crate) enum Action<'a> {
Event(Event<'a>),
InlineParse(inline::InlineRoot),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Options(u64);
impl Options {
pub const TABLES: Self = Self(1 << 0);
pub const TASK_LISTS: Self = Self(1 << 1);
pub const STRIKETHROUGH: Self = Self(1 << 2);
pub const EXTENDED_AUTOLINKS: Self = Self(1 << 3);
pub const TAGFILTER: Self = Self(1 << 4);
pub const MATH_DOLLARS: Self = Self(1 << 5);
pub const MATH_CODE: Self = Self(1 << 6);
pub const MATH_LATEX: Self = Self(1 << 7);
pub const GFM_DIALECT: Self = Self(1 << 8);
pub const IMMEDIATE_MODE: Self = Self(1 << 9);
pub const GFM: Self = Self(
Self::TABLES.0
| Self::TASK_LISTS.0
| Self::STRIKETHROUGH.0
| Self::EXTENDED_AUTOLINKS.0
| Self::TAGFILTER.0
| Self::GFM_DIALECT.0,
);
pub const MATH: Self = Self(Self::MATH_DOLLARS.0 | Self::MATH_CODE.0 | Self::MATH_LATEX.0);
pub const fn empty() -> Self {
Self(0)
}
pub const fn from_bits(bits: u64) -> Self {
Self(bits)
}
pub const fn bits(self) -> u64 {
self.0
}
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
pub fn insert(&mut self, other: Self) {
self.0 |= other.0;
}
pub fn remove(&mut self, other: Self) {
self.0 &= !other.0;
}
}
impl std::ops::BitOr for Options {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for Options {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl std::ops::BitAnd for Options {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
pub use tagfilter::{filter_disallowed_html, filter_disallowed_html_into};
use crate::block::BufferedLeafEvents;
pub struct Parser {
block_parser: block::BlockParser,
line_start: usize,
current_pos: usize,
finished: bool,
}
impl Parser {
pub fn new() -> Self {
Self {
block_parser: block::BlockParser::new(Options::empty()),
line_start: 0,
current_pos: 0,
finished: false,
}
}
pub fn with_options(options: Options) -> Self {
Self {
block_parser: block::BlockParser::new(options),
line_start: 0,
current_pos: 0,
finished: false,
}
}
pub fn feed_chunk<'a>(&mut self, s: &'a str) -> (VecDeque<Event<'a>>, usize) {
let mut iter = self.feed(s);
let events = iter.by_ref().collect();
let read = iter.consumed();
(events, read)
}
pub fn finish<'a>(&mut self, s: &'a str) -> VecDeque<Event<'a>> {
self.finish_iter(s).collect()
}
pub fn parse_str(markdown: &str, options: Options) -> Vec<Event<'_>> {
let mut parser = Self::with_options(options);
let (events, consumed) = parser.feed_chunk(markdown);
let mut all: Vec<Event<'_>> = events.into_iter().collect();
let remaining = if consumed > 0 {
&markdown[consumed..]
} else {
markdown
};
all.extend(parser.finish(remaining));
all
}
pub fn feed<'p, 'a>(&'p mut self, s: &'a str) -> EventIterator<'p, 'a> {
let pos = self.current_pos;
EventIterator {
inner: InnerEventIterator {
parser: self,
buf: s.as_bytes(),
actions: VecDeque::new(),
active_event_source: None,
mode: IteratorMode::Feed {
pos,
output_line_start: 0,
},
},
}
}
pub fn finish_iter<'p, 'a>(&'p mut self, s: &'a str) -> EventIterator<'p, 'a> {
EventIterator {
inner: InnerEventIterator {
parser: self,
buf: s.as_bytes(),
actions: VecDeque::new(),
active_event_source: None,
mode: IteratorMode::Finish {
state: FinishState::Tail,
batch_active: false,
},
},
}
}
}
pub struct EventIterator<'p, 'a> {
inner: InnerEventIterator<'p, 'a>,
}
struct InnerEventIterator<'p, 'a> {
parser: &'p mut Parser,
buf: &'a [u8],
actions: VecDeque<Action<'a>>,
active_event_source: Option<EventOutputSource<'a>>,
mode: IteratorMode,
}
enum IteratorMode {
Feed {
pos: usize,
output_line_start: usize,
},
Finish {
state: FinishState,
batch_active: bool,
},
}
enum FinishState {
Tail,
CloseBlocks,
Done,
}
enum EventOutputSource<'a> {
Buffered(block::BufferedLeafEvents<'a>),
Inline(inline::InlineCursor),
}
impl<'p, 'a> EventIterator<'p, 'a> {
pub fn consumed(&self) -> usize {
let IteratorMode::Feed {
output_line_start, ..
} = self.inner.mode
else {
return self.inner.buf.len();
};
if self.inner.parser.block_parser.leaf_is_open() {
output_line_start
} else {
self.inner.parser.line_start
}
}
}
impl<'p, 'a> Iterator for EventIterator<'p, 'a> {
type Item = Event<'a>;
#[inline(always)]
fn next(&mut self) -> Option<Event<'a>> {
self.inner.next()
}
}
#[inline(always)]
fn check_buffered<'a>(
source: &mut Option<EventOutputSource<'a>>,
buffered: Option<BufferedLeafEvents<'a>>,
) -> Option<Event<'a>> {
let mut events = buffered?;
let event = unsafe { events.next().unwrap_unchecked() };
*source = Some(EventOutputSource::Buffered(events));
Some(event)
}
impl<'p, 'a> Iterator for InnerEventIterator<'p, 'a> {
type Item = Event<'a>;
#[inline(always)]
fn next(&mut self) -> Option<Event<'a>> {
loop {
if let Some(source) = &mut self.active_event_source {
let event = match source {
EventOutputSource::Buffered(events) => events.next(),
EventOutputSource::Inline(cursor) => {
self.parser.block_parser.next_inline_event(cursor)
}
};
if let Some(event) = event {
return Some(event);
}
self.active_event_source = None;
}
if let Some(action) = self.actions.pop_front() {
match action {
Action::Event(event) => return Some(event),
Action::InlineParse(root) => {
if let IteratorMode::Finish { batch_active, .. } = &mut self.mode {
*batch_active = true;
}
let mut cursor = inline::InlineCursor::new(root);
if let Some(event) = self.parser.block_parser.next_inline_event(&mut cursor)
{
self.active_event_source = Some(EventOutputSource::Inline(cursor));
return Some(event);
}
continue;
}
}
}
if let IteratorMode::Finish {
state,
batch_active,
} = &mut self.mode
{
if *batch_active {
self.parser.block_parser.reset_inline();
*batch_active = false;
}
let buf = self.buf;
match state {
FinishState::Tail => {
*state = FinishState::CloseBlocks;
if !self.parser.finished && self.parser.line_start < buf.len() {
let pos = self.parser.line_start;
let mut end = buf.len();
if buf[end - 1] == b'\n' {
end -= 1;
if end > pos && buf[end - 1] == b'\r' {
end -= 1;
}
} else if buf[end - 1] == b'\r' {
end -= 1;
}
let mut buffered = None;
self.parser.block_parser.parse_line_for_iter(
buf,
pos..end,
pos..buf.len(),
&mut self.actions,
&mut buffered,
);
if let Some(event) =
check_buffered(&mut self.active_event_source, buffered)
{
return Some(event);
}
}
continue;
}
FinishState::CloseBlocks => {
*state = FinishState::Done;
self.parser.finished = true;
let mut buffered = None;
self.parser.block_parser.finish_for_iter(
buf,
&mut self.actions,
&mut buffered,
);
if let Some(event) = check_buffered(&mut self.active_event_source, buffered)
{
return Some(event);
}
continue;
}
FinishState::Done => return None,
}
}
let IteratorMode::Feed {
pos,
output_line_start,
} = &mut self.mode
else {
unreachable!()
};
self.parser.block_parser.reset_inline();
loop {
if *pos >= self.buf.len() {
return None;
}
let new_bytes = &self.buf[*pos..];
let line_end = if new_bytes.len() >= 16 {
match memchr::memchr2(b'\n', b'\r', new_bytes) {
Some(offset) => *pos + offset,
None => self.buf.len(),
}
} else {
match new_bytes.iter().position(|&b| b == b'\n' || b == b'\r') {
Some(offset) => *pos + offset,
None => self.buf.len(),
}
};
if line_end >= self.buf.len() {
*pos = self.buf.len();
return None;
}
let mut next_line_start = line_end + 1;
if self.buf[line_end] == b'\r' {
if line_end + 1 == self.buf.len() {
*pos = line_end; return None;
}
if self.buf.get(line_end + 1) == Some(&b'\n') {
next_line_start += 1;
}
}
let line_start = self.parser.line_start;
let line = line_start..line_end;
let line_with_ending = line_start..next_line_start;
let mut buffered = None;
self.parser.block_parser.parse_line_for_iter(
self.buf,
line,
line_with_ending,
&mut self.actions,
&mut buffered,
);
self.parser.line_start = next_line_start;
*pos = next_line_start;
if let Some(mut events) = buffered {
*output_line_start = line_start;
self.parser.current_pos = *pos;
let event = unsafe { events.next().unwrap_unchecked() };
self.active_event_source = Some(EventOutputSource::Buffered(events));
return Some(event);
}
if !self.actions.is_empty() {
*output_line_start = line_start;
self.parser.current_pos = *pos;
break;
}
}
}
}
}
impl Drop for InnerEventIterator<'_, '_> {
fn drop(&mut self) {
if matches!(self.mode, IteratorMode::Feed { .. }) {
while self.next().is_some() {}
self.parser.block_parser.reset_inline();
let IteratorMode::Feed {
pos,
output_line_start,
} = self.mode
else {
unreachable!()
};
if self.parser.block_parser.leaf_is_open() {
let consumed = output_line_start;
self.parser.block_parser.update_leaf_spans(consumed);
self.parser.line_start -= consumed;
self.parser.current_pos = pos - consumed;
} else {
let consumed = self.parser.line_start;
self.parser.line_start = 0;
self.parser.current_pos = pos - consumed;
}
} else {
self.parser.block_parser.reset_inline();
}
}
}
impl Default for Parser {
fn default() -> Self {
Self::new()
}
}