summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-30 12:50:58 +0100
committerLaurenz <laurmaedje@gmail.com>2022-01-30 22:46:59 +0100
commit8d1ce390e21ce0a5812a4211c893ec359906d6f1 (patch)
tree5dbe1ad96af8ce8f9f01887340fe06025462e959 /src/syntax
parentd7072f378fef733ae994fd9a1e767df4e4dd878e (diff)
Rework strong and emph
- Star and underscore not parsed as strong/emph inside of words - Stars/underscores must be balanced and they cannot go over paragraph break - New `strong` and `emph` classes
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs40
-rw-r--r--src/syntax/highlight.rs12
-rw-r--r--src/syntax/mod.rs41
-rw-r--r--src/syntax/pretty.rs24
4 files changed, 81 insertions, 36 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 13c639f9..560d7c30 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -63,8 +63,6 @@ impl Markup {
NodeKind::Space(_) => Some(MarkupNode::Space),
NodeKind::Linebreak => Some(MarkupNode::Linebreak),
NodeKind::Parbreak => Some(MarkupNode::Parbreak),
- NodeKind::Strong => Some(MarkupNode::Strong),
- NodeKind::Emph => Some(MarkupNode::Emph),
NodeKind::Text(s) | NodeKind::TextInLine(s) => {
Some(MarkupNode::Text(s.clone()))
}
@@ -72,8 +70,10 @@ impl Markup {
NodeKind::EnDash => Some(MarkupNode::Text('\u{2013}'.into())),
NodeKind::EmDash => Some(MarkupNode::Text('\u{2014}'.into())),
NodeKind::NonBreakingSpace => Some(MarkupNode::Text('\u{00A0}'.into())),
- NodeKind::Math(math) => Some(MarkupNode::Math(math.as_ref().clone())),
+ NodeKind::Strong => node.cast().map(MarkupNode::Strong),
+ NodeKind::Emph => node.cast().map(MarkupNode::Emph),
NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())),
+ NodeKind::Math(math) => Some(MarkupNode::Math(math.as_ref().clone())),
NodeKind::Heading => node.cast().map(MarkupNode::Heading),
NodeKind::List => node.cast().map(MarkupNode::List),
NodeKind::Enum => node.cast().map(MarkupNode::Enum),
@@ -91,12 +91,12 @@ pub enum MarkupNode {
Linebreak,
/// A paragraph break: Two or more newlines.
Parbreak,
- /// Strong text was enabled / disabled: `*`.
- Strong,
- /// Emphasized text was enabled / disabled: `_`.
- Emph,
/// Plain text.
Text(EcoString),
+ /// Strong content: `*Strong*`.
+ Strong(StrongNode),
+ /// Emphasized content: `_Emphasized_`.
+ Emph(EmphNode),
/// A raw block with optional syntax highlighting: `` `...` ``.
Raw(RawNode),
/// A math formula: `$a^2 = b^2 + c^2$`.
@@ -111,6 +111,32 @@ pub enum MarkupNode {
Expr(Expr),
}
+node! {
+ /// Strong content: `*Strong*`.
+ StrongNode: Strong
+}
+
+impl StrongNode {
+ /// The contents of the strong node.
+ pub fn body(&self) -> Markup {
+ self.0.cast_first_child().expect("strong node is missing markup body")
+ }
+}
+
+node! {
+ /// Emphasized content: `_Emphasized_`.
+ EmphNode: Emph
+}
+
+impl EmphNode {
+ /// The contents of the emphasis node.
+ pub fn body(&self) -> Markup {
+ self.0
+ .cast_first_child()
+ .expect("emphasis node is missing markup body")
+ }
+}
+
/// A raw block with optional syntax highlighting: `` `...` ``.
#[derive(Debug, Clone, PartialEq)]
pub struct RawNode {
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 315e8f17..b806b4e4 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -151,7 +151,10 @@ impl Category {
NodeKind::From => Some(Category::Keyword),
NodeKind::Include => Some(Category::Keyword),
NodeKind::Plus => Some(Category::Operator),
- NodeKind::Star => Some(Category::Operator),
+ NodeKind::Star => match parent.kind() {
+ NodeKind::Strong => None,
+ _ => Some(Category::Operator),
+ },
NodeKind::Slash => Some(Category::Operator),
NodeKind::PlusEq => Some(Category::Operator),
NodeKind::HyphEq => Some(Category::Operator),
@@ -191,6 +194,7 @@ impl Category {
NodeKind::Str(_) => Some(Category::String),
NodeKind::Error(_, _) => Some(Category::Invalid),
NodeKind::Unknown(_) => Some(Category::Invalid),
+ NodeKind::Underscore => None,
NodeKind::Markup(_) => None,
NodeKind::Space(_) => None,
NodeKind::Parbreak => None,
@@ -276,11 +280,7 @@ mod tests {
assert_eq!(vec, goal);
}
- test("= *AB*", &[
- (0 .. 6, Heading),
- (2 .. 3, Strong),
- (5 .. 6, Strong),
- ]);
+ test("= *AB*", &[(0 .. 6, Heading), (2 .. 6, Strong)]);
test("#f(x + 1)", &[
(0 .. 2, Function),
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index 9b606e0e..fdd50a7a 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -496,6 +496,8 @@ pub enum NodeKind {
RightParen,
/// An asterisk: `*`.
Star,
+ /// An underscore: `_`.
+ Underscore,
/// A comma: `,`.
Comma,
/// A semicolon: `;`.
@@ -599,25 +601,25 @@ pub enum NodeKind {
/// A slash and the letter "u" followed by a hexadecimal unicode entity
/// enclosed in curly braces: `\u{1F5FA}`.
Escape(char),
- /// Strong text was enabled / disabled: `*`.
+ /// Strong content: `*Strong*`.
Strong,
- /// Emphasized text was enabled / disabled: `_`.
+ /// Emphasized content: `_Emphasized_`.
Emph,
+ /// An arbitrary number of backticks followed by inner contents, terminated
+ /// with the same number of backticks: `` `...` ``.
+ Raw(Rc<RawNode>),
+ /// Dollar signs surrounding inner contents.
+ Math(Rc<MathNode>),
/// A section heading: `= Introduction`.
Heading,
+ /// An item in an unordered list: `- ...`.
+ List,
/// An item in an enumeration (ordered list): `1. ...`.
Enum,
/// A numbering: `23.`.
///
/// Can also exist without the number: `.`.
EnumNumbering(Option<usize>),
- /// An item in an unordered list: `- ...`.
- List,
- /// An arbitrary number of backticks followed by inner contents, terminated
- /// with the same number of backticks: `` `...` ``.
- Raw(Rc<RawNode>),
- /// Dollar signs surrounding inner contents.
- Math(Rc<MathNode>),
/// An identifier: `center`.
Ident(EcoString),
/// A boolean: `true`, `false`.
@@ -736,14 +738,14 @@ impl NodeKind {
matches!(self, Self::LeftParen | Self::RightParen)
}
- /// Whether this is whitespace.
- pub fn is_whitespace(&self) -> bool {
- matches!(self, Self::Space(_) | Self::Parbreak)
+ /// Whether this is a space.
+ pub fn is_space(&self) -> bool {
+ matches!(self, Self::Space(_))
}
/// Whether this is trivia.
pub fn is_trivia(&self) -> bool {
- self.is_whitespace() || matches!(self, Self::LineComment | Self::BlockComment)
+ self.is_space() || matches!(self, Self::LineComment | Self::BlockComment)
}
/// Whether this is some kind of error.
@@ -761,7 +763,7 @@ impl NodeKind {
}
}
- /// Which mode this token can appear in, in both if `None`.
+ /// Which mode this node can appear in, in both if `None`.
pub fn mode(&self) -> Option<TokenMode> {
match self {
Self::Markup(_)
@@ -814,6 +816,7 @@ impl NodeKind {
Self::LeftParen => "opening paren",
Self::RightParen => "closing paren",
Self::Star => "star",
+ Self::Underscore => "underscore",
Self::Comma => "comma",
Self::Semicolon => "semicolon",
Self::Colon => "colon",
@@ -864,14 +867,14 @@ impl NodeKind {
Self::EnDash => "en dash",
Self::EmDash => "em dash",
Self::Escape(_) => "escape sequence",
- Self::Strong => "strong",
- Self::Emph => "emphasis",
+ Self::Strong => "strong content",
+ Self::Emph => "emphasized content",
+ Self::Raw(_) => "raw block",
+ Self::Math(_) => "math formula",
+ Self::List => "list item",
Self::Heading => "heading",
Self::Enum => "enumeration item",
Self::EnumNumbering(_) => "enumeration item numbering",
- Self::List => "list item",
- Self::Raw(_) => "raw block",
- Self::Math(_) => "math formula",
Self::Ident(_) => "identifier",
Self::Bool(_) => "boolean",
Self::Int(_) => "integer",
diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs
index e8110262..07ab979b 100644
--- a/src/syntax/pretty.rs
+++ b/src/syntax/pretty.rs
@@ -95,8 +95,8 @@ impl Pretty for MarkupNode {
Self::Space => p.push(' '),
Self::Linebreak => p.push_str(r"\"),
Self::Parbreak => p.push_str("\n\n"),
- Self::Strong => p.push('*'),
- Self::Emph => p.push('_'),
+ Self::Strong(strong) => strong.pretty(p),
+ Self::Emph(emph) => emph.pretty(p),
Self::Text(text) => p.push_str(text),
Self::Raw(raw) => raw.pretty(p),
Self::Math(math) => math.pretty(p),
@@ -113,6 +113,22 @@ impl Pretty for MarkupNode {
}
}
+impl Pretty for StrongNode {
+ fn pretty(&self, p: &mut Printer) {
+ p.push('*');
+ self.body().pretty(p);
+ p.push('*');
+ }
+}
+
+impl Pretty for EmphNode {
+ fn pretty(&self, p: &mut Printer) {
+ p.push('_');
+ self.body().pretty(p);
+ p.push('_');
+ }
+}
+
impl Pretty for RawNode {
fn pretty(&self, p: &mut Printer) {
// Find out how many backticks we need.
@@ -604,12 +620,12 @@ mod tests {
#[test]
fn test_pretty_print_markup() {
// Basic stuff.
- roundtrip("*");
- roundtrip("_");
roundtrip(" ");
+ roundtrip("*ab*");
roundtrip("\\ ");
roundtrip("\n\n");
roundtrip("hi");
+ roundtrip("_ab_");
roundtrip("= *Ok*");
roundtrip("- Ok");