use crate::Item;
use crate::parser::Parser;
use crate::support::{strip_leading_label, strip_trailing_label};
impl Parser<'_> {
pub(crate) fn parse_heading(&mut self) {
let (line_start, content_end, line_end) = self.current_line_bounds();
let bytes = self.src.as_bytes();
let mut level: u8 = 0;
let mut i = line_start;
while i < content_end && bytes[i] == b'=' {
level = level.saturating_add(1);
i += 1;
}
if i >= content_end || !bytes[i].is_ascii_whitespace() {
self.parse_paragraph();
return;
}
while i < content_end && (bytes[i] == b' ' || bytes[i] == b'\t') {
i += 1;
}
let (text_end, parsed_label) = strip_trailing_label(self.src, i, content_end);
let label_span = parsed_label
.as_ref()
.map(|label| self.span(label.start, label.end));
let label = parsed_label.map(|label| label.text);
let content = &self.src[i..text_end];
let inlines = self.parse_inlines(content, i);
let span = self.span(line_start, content_end);
self.items.push(Item::Heading {
level,
inlines,
label,
label_span,
span,
});
self.pos = line_end;
}
pub(crate) fn parse_paragraph(&mut self) {
let bytes = self.src.as_bytes();
let para_start = self.pos;
let mut para_end = self.pos;
let mut text_start: Option<usize> = None;
loop {
if self.pos >= bytes.len() || self.at_blank_line() {
break;
}
if self.starts_with("=") && self.heading_level_of_current_line().is_some() {
break;
}
if self.at_directive_keyword().is_some() || self.at_list_marker() {
break;
}
let (line_start, content_end, line_end) = self.current_line_bounds();
if text_start.is_none() {
text_start = Some(line_start);
}
para_end = content_end;
self.pos = line_end;
}
if let Some(start) = text_start {
let (body_start, parsed_label) = strip_leading_label(self.src, start, para_end);
let label_span = parsed_label
.as_ref()
.map(|label| self.span(label.start, label.end));
let label = parsed_label.map(|label| label.text);
let slice = &self.src[body_start..para_end];
let mut inlines = self.parse_inlines(slice, body_start);
for inline in &mut inlines {
if inline.text.contains("\r\n") {
inline.text = inline.text.replace("\r\n", "\n");
}
}
let span = self.span(para_start, para_end);
self.items.push(Item::Paragraph {
inlines,
label,
label_span,
span,
});
}
}
fn heading_level_of_current_line(&self) -> Option<u8> {
let (start, content_end, _) = self.current_line_bounds();
let bytes = self.src.as_bytes();
let mut i = start;
let mut level: u8 = 0;
while i < content_end && bytes[i] == b'=' {
level = level.saturating_add(1);
i += 1;
}
if level == 0 {
return None;
}
if i < content_end && bytes[i].is_ascii_whitespace() {
Some(level)
} else {
None
}
}
}