summaryrefslogtreecommitdiff
path: root/src/parse/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse/mod.rs')
-rw-r--r--src/parse/mod.rs69
1 files changed, 60 insertions, 9 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index a8dee7f3..ed8bc5ce 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -162,11 +162,6 @@ fn markup(p: &mut Parser, mut at_start: bool) {
});
}
-/// Parse a single line of markup.
-fn markup_line(p: &mut Parser) {
- markup_indented(p, usize::MAX);
-}
-
/// Parse markup that stays right of the given `column`.
fn markup_indented(p: &mut Parser, min_indent: usize) {
p.eat_while(|t| match t {
@@ -185,7 +180,6 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
{
break;
}
- Some(NodeKind::Label(_)) => break,
_ => {}
}
@@ -195,6 +189,33 @@ fn markup_indented(p: &mut Parser, min_indent: usize) {
marker.end(p, NodeKind::Markup { min_indent });
}
+/// Parse a line of markup that can prematurely end if `f` returns true.
+fn markup_line<F>(p: &mut Parser, mut f: F)
+where
+ F: FnMut(&NodeKind) -> bool,
+{
+ p.eat_while(|t| match t {
+ NodeKind::Space { newlines } => *newlines == 0,
+ NodeKind::LineComment | NodeKind::BlockComment => true,
+ _ => false,
+ });
+
+ p.perform(NodeKind::Markup { min_indent: usize::MAX }, |p| {
+ let mut at_start = false;
+ while let Some(kind) = p.peek() {
+ if let NodeKind::Space { newlines: (1 ..) } = kind {
+ break;
+ }
+
+ if f(kind) {
+ break;
+ }
+
+ markup_node(p, &mut at_start);
+ }
+ });
+}
+
/// Parse a markup node.
fn markup_node(p: &mut Parser, at_start: &mut bool) {
let token = match p.peek() {
@@ -226,6 +247,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
| NodeKind::Ellipsis
| NodeKind::Quote { .. }
| NodeKind::Escape(_)
+ | NodeKind::Link(_)
| NodeKind::Raw(_)
| NodeKind::Math(_)
| NodeKind::Label(_)
@@ -233,12 +255,22 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
p.eat();
}
- // Grouping markup.
+ // Strong, emph, heading.
NodeKind::Star => strong(p),
NodeKind::Underscore => emph(p),
NodeKind::Eq => heading(p, *at_start),
+
+ // Lists.
NodeKind::Minus => list_node(p, *at_start),
- NodeKind::EnumNumbering(_) => enum_node(p, *at_start),
+ NodeKind::Plus | NodeKind::EnumNumbering(_) => enum_node(p, *at_start),
+ NodeKind::Slash => {
+ desc_node(p, *at_start).ok();
+ }
+ NodeKind::Colon => {
+ let marker = p.marker();
+ p.eat();
+ marker.convert(p, NodeKind::Text(':'.into()));
+ }
// Hashtag + keyword / identifier.
NodeKind::Ident(_)
@@ -293,7 +325,7 @@ fn heading(p: &mut Parser, at_start: bool) {
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
p.eat_while(|kind| *kind == NodeKind::Space { newlines: 0 });
- markup_line(p);
+ markup_line(p, |kind| matches!(kind, NodeKind::Label(_)));
marker.end(p, NodeKind::Heading);
} else {
let text = p.get(current_start .. p.prev_end()).into();
@@ -331,6 +363,25 @@ fn enum_node(p: &mut Parser, at_start: bool) {
}
}
+/// Parse a single description list item.
+fn desc_node(p: &mut Parser, at_start: bool) -> ParseResult {
+ let marker = p.marker();
+ let text: EcoString = p.peek_src().into();
+ p.eat();
+
+ let min_indent = p.column(p.prev_end());
+ if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
+ markup_line(p, |node| matches!(node, NodeKind::Colon));
+ p.expect(NodeKind::Colon)?;
+ markup_indented(p, min_indent);
+ marker.end(p, NodeKind::Desc);
+ } else {
+ marker.convert(p, NodeKind::Text(text));
+ }
+
+ Ok(())
+}
+
/// Parse an expression within a markup mode.
fn markup_expr(p: &mut Parser) {
// Does the expression need termination or can content follow directly?