summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-09-26 15:39:32 +0200
committerLaurenz <laurmaedje@gmail.com>2022-09-26 16:12:57 +0200
commit704f2fbaf1b4483caa12f249a222c49e44f08961 (patch)
tree146f7813fe63409df2c1bbaa487731e992d3ac71 /src/syntax
parent2661f1a5066bd5e3f8a9c68e4a5c304c248efcb7 (diff)
Description lists, link syntax, and new enum syntax
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs54
-rw-r--r--src/syntax/highlight.rs130
-rw-r--r--src/syntax/mod.rs272
3 files changed, 264 insertions, 192 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 10bee4e8..8d3696a8 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -63,9 +63,7 @@ impl Markup {
self.0.children().filter_map(|node| match node.kind() {
NodeKind::Space { newlines: (2 ..) } => Some(MarkupNode::Parbreak),
NodeKind::Space { .. } => Some(MarkupNode::Space),
- &NodeKind::Linebreak { justified } => {
- Some(MarkupNode::Linebreak { justified })
- }
+ NodeKind::Linebreak => Some(MarkupNode::Linebreak),
NodeKind::Text(s) => Some(MarkupNode::Text(s.clone())),
NodeKind::Escape(c) => Some(MarkupNode::Text((*c).into())),
NodeKind::NonBreakingSpace => Some(MarkupNode::Text('\u{00A0}'.into())),
@@ -76,6 +74,7 @@ impl Markup {
&NodeKind::Quote { double } => Some(MarkupNode::Quote { double }),
NodeKind::Strong => node.cast().map(MarkupNode::Strong),
NodeKind::Emph => node.cast().map(MarkupNode::Emph),
+ NodeKind::Link(url) => Some(MarkupNode::Link(url.clone())),
NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())),
NodeKind::Math(math) => Some(MarkupNode::Math(Spanned::new(
math.as_ref().clone(),
@@ -84,6 +83,7 @@ impl Markup {
NodeKind::Heading => node.cast().map(MarkupNode::Heading),
NodeKind::List => node.cast().map(MarkupNode::List),
NodeKind::Enum => node.cast().map(MarkupNode::Enum),
+ NodeKind::Desc => node.cast().map(MarkupNode::Desc),
NodeKind::Label(v) => Some(MarkupNode::Label(v.clone())),
NodeKind::Ref(v) => Some(MarkupNode::Ref(v.clone())),
_ => node.cast().map(MarkupNode::Expr),
@@ -96,8 +96,8 @@ impl Markup {
pub enum MarkupNode {
/// Whitespace containing less than two newlines.
Space,
- /// A forced line break: `\` or `\+` if justified.
- Linebreak { justified: bool },
+ /// A forced line break.
+ Linebreak,
/// A paragraph break: Two or more newlines.
Parbreak,
/// Plain text.
@@ -108,6 +108,8 @@ pub enum MarkupNode {
Strong(StrongNode),
/// Emphasized content: `_Emphasized_`.
Emph(EmphNode),
+ /// A hyperlink.
+ Link(EcoString),
/// A raw block with optional syntax highlighting: `` `...` ``.
Raw(RawNode),
/// A math formula: `$a^2 = b^2 + c^2$`.
@@ -116,8 +118,10 @@ pub enum MarkupNode {
Heading(HeadingNode),
/// An item in an unordered list: `- ...`.
List(ListNode),
- /// An item in an enumeration (ordered list): `1. ...`.
+ /// An item in an enumeration (ordered list): `+ ...` or `1. ...`.
Enum(EnumNode),
+ /// An item in a description list: `/ Term: Details.
+ Desc(DescNode),
/// A label.
Label(EcoString),
/// A reference.
@@ -170,8 +174,8 @@ pub struct RawNode {
pub struct MathNode {
/// The formula between the dollars / brackets.
pub formula: EcoString,
- /// Whether the formula is display-level, that is, it is surrounded by
- /// `$[..]$`.
+ /// Whether the formula is display-level, that is, it contains whitespace
+ /// after the starting dollar sign and before the ending dollar sign.
pub display: bool,
}
@@ -205,7 +209,7 @@ node! {
impl ListNode {
/// The contents of the list item.
pub fn body(&self) -> Markup {
- self.0.cast_first_child().expect("list node is missing body")
+ self.0.cast_first_child().expect("list item is missing body")
}
}
@@ -217,18 +221,36 @@ node! {
impl EnumNode {
/// The contents of the list item.
pub fn body(&self) -> Markup {
- self.0.cast_first_child().expect("enum node is missing body")
+ self.0.cast_first_child().expect("enum item is missing body")
}
/// The number, if any.
pub fn number(&self) -> Option<usize> {
+ self.0.children().find_map(|node| match node.kind() {
+ NodeKind::EnumNumbering(num) => Some(*num),
+ _ => None,
+ })
+ }
+}
+
+node! {
+ /// An item in a description list: `/ Term: Details.
+ DescNode: Desc
+}
+
+impl DescNode {
+ /// The term described by the list item.
+ pub fn term(&self) -> Markup {
self.0
- .children()
- .find_map(|node| match node.kind() {
- NodeKind::EnumNumbering(num) => Some(*num),
- _ => None,
- })
- .expect("enum node is missing number")
+ .cast_first_child()
+ .expect("description list item is missing term")
+ }
+
+ /// The description of the term.
+ pub fn body(&self) -> Markup {
+ self.0
+ .cast_last_child()
+ .expect("description list item is missing body")
}
}
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 7f5ee083..de7c70a2 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -147,12 +147,12 @@ pub fn highlight_pre(text: &str, mode: TokenMode, theme: &Theme) -> String {
/// The syntax highlighting category of a node.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Category {
+ /// A line or block comment.
+ Comment,
/// Any kind of bracket, parenthesis or brace.
Bracket,
/// Punctuation in code.
Punctuation,
- /// A line or block comment.
- Comment,
/// An easily typable shortcut to a unicode codepoint.
Shortcut,
/// An escape sequence.
@@ -161,14 +161,18 @@ pub enum Category {
Strong,
/// Emphasized text.
Emph,
+ /// A hyperlink.
+ Link,
/// Raw text or code.
Raw,
/// A math formula.
Math,
/// A section heading.
Heading,
- /// A list or enumeration.
+ /// A symbol of a list, enumeration, or description list.
List,
+ /// A term in a description list.
+ Term,
/// A label.
Label,
/// A reference.
@@ -204,66 +208,74 @@ impl Category {
i: usize,
) -> Option<Category> {
match child.kind() {
+ NodeKind::LineComment => Some(Category::Comment),
+ NodeKind::BlockComment => Some(Category::Comment),
NodeKind::LeftBrace => Some(Category::Bracket),
NodeKind::RightBrace => Some(Category::Bracket),
NodeKind::LeftBracket => Some(Category::Bracket),
NodeKind::RightBracket => Some(Category::Bracket),
NodeKind::LeftParen => Some(Category::Bracket),
NodeKind::RightParen => Some(Category::Bracket),
- NodeKind::Comma => Some(Category::Punctuation),
- NodeKind::Semicolon => Some(Category::Punctuation),
- NodeKind::Colon => Some(Category::Punctuation),
- NodeKind::Dot => Some(Category::Punctuation),
- NodeKind::LineComment => Some(Category::Comment),
- NodeKind::BlockComment => Some(Category::Comment),
+
+ NodeKind::Markup { .. } => match parent.kind() {
+ NodeKind::Desc
+ if parent
+ .children()
+ .take_while(|child| child.kind() != &NodeKind::Colon)
+ .find(|c| matches!(c.kind(), NodeKind::Markup { .. }))
+ .map_or(false, |ident| std::ptr::eq(ident, child)) =>
+ {
+ Some(Category::Term)
+ }
+ _ => None,
+ },
+ NodeKind::Space { .. } => None,
NodeKind::Linebreak { .. } => Some(Category::Shortcut),
+ NodeKind::Text(_) => None,
+ NodeKind::Escape(_) => Some(Category::Escape),
NodeKind::NonBreakingSpace => Some(Category::Shortcut),
NodeKind::Shy => Some(Category::Shortcut),
NodeKind::EnDash => Some(Category::Shortcut),
NodeKind::EmDash => Some(Category::Shortcut),
NodeKind::Ellipsis => Some(Category::Shortcut),
- NodeKind::Escape(_) => Some(Category::Escape),
+ NodeKind::Quote { .. } => None,
+ NodeKind::Star => match parent.kind() {
+ NodeKind::Strong => None,
+ _ => Some(Category::Operator),
+ },
+ NodeKind::Underscore => None,
NodeKind::Strong => Some(Category::Strong),
NodeKind::Emph => Some(Category::Emph),
+ NodeKind::Link(_) => Some(Category::Link),
NodeKind::Raw(_) => Some(Category::Raw),
NodeKind::Math(_) => Some(Category::Math),
NodeKind::Heading => Some(Category::Heading),
+ NodeKind::List => None,
+ NodeKind::Enum => None,
+ NodeKind::EnumNumbering(_) => Some(Category::List),
+ NodeKind::Desc => None,
+ NodeKind::Label(_) => Some(Category::Label),
+ NodeKind::Ref(_) => Some(Category::Ref),
+
+ NodeKind::Comma => Some(Category::Punctuation),
+ NodeKind::Semicolon => Some(Category::Punctuation),
+ NodeKind::Colon => match parent.kind() {
+ NodeKind::Desc => Some(Category::Term),
+ _ => Some(Category::Punctuation),
+ },
+ NodeKind::Plus => match parent.kind() {
+ NodeKind::Enum => Some(Category::List),
+ _ => Some(Category::Operator),
+ },
NodeKind::Minus => match parent.kind() {
NodeKind::List => Some(Category::List),
_ => Some(Category::Operator),
},
- NodeKind::EnumNumbering(_) => Some(Category::List),
- NodeKind::Label(_) => Some(Category::Label),
- NodeKind::Ref(_) => Some(Category::Ref),
- NodeKind::Not => Some(Category::Keyword),
- NodeKind::And => Some(Category::Keyword),
- NodeKind::Or => Some(Category::Keyword),
- NodeKind::Let => Some(Category::Keyword),
- NodeKind::Set => Some(Category::Keyword),
- NodeKind::Show => Some(Category::Keyword),
- NodeKind::Wrap => Some(Category::Keyword),
- NodeKind::If => Some(Category::Keyword),
- NodeKind::Else => Some(Category::Keyword),
- NodeKind::While => Some(Category::Keyword),
- NodeKind::For => Some(Category::Keyword),
- NodeKind::In => Some(Category::Keyword),
- NodeKind::As => Some(Category::Keyword),
- NodeKind::Break => Some(Category::Keyword),
- NodeKind::Continue => Some(Category::Keyword),
- NodeKind::Return => Some(Category::Keyword),
- NodeKind::Import => Some(Category::Keyword),
- NodeKind::From => Some(Category::Keyword),
- NodeKind::Include => Some(Category::Keyword),
- NodeKind::Plus => Some(Category::Operator),
- NodeKind::Star => match parent.kind() {
- NodeKind::Strong => None,
+ NodeKind::Slash => match parent.kind() {
+ NodeKind::Desc => Some(Category::List),
_ => Some(Category::Operator),
},
- NodeKind::Slash => Some(Category::Operator),
- NodeKind::PlusEq => Some(Category::Operator),
- NodeKind::HyphEq => Some(Category::Operator),
- NodeKind::StarEq => Some(Category::Operator),
- NodeKind::SlashEq => Some(Category::Operator),
+ NodeKind::Dot => Some(Category::Punctuation),
NodeKind::Eq => match parent.kind() {
NodeKind::Heading => None,
_ => Some(Category::Operator),
@@ -274,10 +286,34 @@ impl Category {
NodeKind::LtEq => Some(Category::Operator),
NodeKind::Gt => Some(Category::Operator),
NodeKind::GtEq => Some(Category::Operator),
+ NodeKind::PlusEq => Some(Category::Operator),
+ NodeKind::HyphEq => Some(Category::Operator),
+ NodeKind::StarEq => Some(Category::Operator),
+ NodeKind::SlashEq => Some(Category::Operator),
NodeKind::Dots => Some(Category::Operator),
NodeKind::Arrow => Some(Category::Operator),
+ NodeKind::Not => Some(Category::Keyword),
+ NodeKind::And => Some(Category::Keyword),
+ NodeKind::Or => Some(Category::Keyword),
NodeKind::None => Some(Category::None),
NodeKind::Auto => Some(Category::Auto),
+ NodeKind::Let => Some(Category::Keyword),
+ NodeKind::Set => Some(Category::Keyword),
+ NodeKind::Show => Some(Category::Keyword),
+ NodeKind::Wrap => Some(Category::Keyword),
+ NodeKind::If => Some(Category::Keyword),
+ NodeKind::Else => Some(Category::Keyword),
+ NodeKind::For => Some(Category::Keyword),
+ NodeKind::In => Some(Category::Keyword),
+ NodeKind::While => Some(Category::Keyword),
+ NodeKind::Break => Some(Category::Keyword),
+ NodeKind::Continue => Some(Category::Keyword),
+ NodeKind::Return => Some(Category::Keyword),
+ NodeKind::Import => Some(Category::Keyword),
+ NodeKind::Include => Some(Category::Keyword),
+ NodeKind::From => Some(Category::Keyword),
+ NodeKind::As => Some(Category::Keyword),
+
NodeKind::Ident(_) => match parent.kind() {
NodeKind::Markup { .. } => Some(Category::Interpolated),
NodeKind::FuncCall => Some(Category::Function),
@@ -302,15 +338,6 @@ impl Category {
NodeKind::Float(_) => Some(Category::Number),
NodeKind::Numeric(_, _) => Some(Category::Number),
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::Text(_) => None,
- NodeKind::Quote { .. } => None,
- NodeKind::List => None,
- NodeKind::Enum => None,
NodeKind::CodeBlock => None,
NodeKind::ContentBlock => None,
NodeKind::GroupExpr => None,
@@ -341,6 +368,9 @@ impl Category {
NodeKind::BreakExpr => None,
NodeKind::ContinueExpr => None,
NodeKind::ReturnExpr => None,
+
+ NodeKind::Error(_, _) => Some(Category::Invalid),
+ NodeKind::Unknown(_) => Some(Category::Invalid),
}
}
@@ -354,10 +384,12 @@ impl Category {
Self::Escape => "constant.character.escape.content.typst",
Self::Strong => "markup.bold.typst",
Self::Emph => "markup.italic.typst",
+ Self::Link => "markup.underline.link.typst",
Self::Raw => "markup.raw.typst",
Self::Math => "string.other.math.typst",
Self::Heading => "markup.heading.typst",
Self::List => "markup.list.typst",
+ Self::Term => "markup.bold.typst",
Self::Label => "entity.name.label.typst",
Self::Ref => "markup.other.reference.typst",
Self::Keyword => "keyword.typst",
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index 89937f2c..6c6f690c 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -571,6 +571,14 @@ impl PartialEq for NodeData {
/// the parser.
#[derive(Debug, Clone, PartialEq)]
pub enum NodeKind {
+ /// A line comment, two slashes followed by inner contents, terminated with
+ /// a newline: `//<str>\n`.
+ LineComment,
+ /// A block comment, a slash and a star followed by inner contents,
+ /// terminated with a star and a slash: `/*<str>*/`.
+ ///
+ /// The comment can contain nested block comments.
+ BlockComment,
/// A left curly brace, starting a code block: `{`.
LeftBrace,
/// A right curly brace, terminating a code block: `}`.
@@ -585,23 +593,83 @@ pub enum NodeKind {
/// A right round parenthesis, terminating a grouped expression, collection,
/// argument or parameter list: `)`.
RightParen,
+
+ /// Markup of which all lines must have a minimal indentation.
+ ///
+ /// Notably, the number does not determine in which column the markup
+ /// started, but to the right of which column all markup elements must be,
+ /// so it is zero except for headings and lists.
+ Markup { min_indent: usize },
+ /// One or more whitespace characters. Single spaces are collapsed into text
+ /// nodes if they would otherwise be surrounded by text nodes.
+ ///
+ /// Also stores how many newlines are contained.
+ Space { newlines: usize },
+ /// A forced line break.
+ Linebreak,
+ /// Consecutive text without markup. While basic text with just single
+ /// spaces is collapsed into a single node, certain symbols that could
+ /// possibly be markup force text into multiple nodes.
+ Text(EcoString),
+ /// A slash and the letter "u" followed by a hexadecimal unicode entity
+ /// enclosed in curly braces: `\u{1F5FA}`.
+ Escape(char),
+ /// A non-breaking space: `~`.
+ NonBreakingSpace,
+ /// A soft hyphen: `-?`.
+ Shy,
+ /// An en-dash: `--`.
+ EnDash,
+ /// An em-dash: `---`.
+ EmDash,
+ /// An ellipsis: `...`.
+ Ellipsis,
+ /// A smart quote: `'` or `"`.
+ Quote { double: bool },
/// The strong text toggle, multiplication operator, and wildcard import
/// symbol: `*`.
Star,
/// Toggles emphasized text: `_`.
Underscore,
+ /// Strong content: `*Strong*`.
+ Strong,
+ /// Emphasized content: `_Emphasized_`.
+ Emph,
+ /// A hyperlink.
+ Link(EcoString),
+ /// A raw block with optional syntax highlighting: `` `...` ``.
+ Raw(Arc<RawNode>),
+ /// A math formula: `$x$`, `$[x^2]$`.
+ Math(Arc<MathNode>),
+ /// A section heading: `= Introduction`.
+ Heading,
+ /// An item in an unordered list: `- ...`.
+ List,
+ /// An item in an enumeration (ordered list): `+ ...` or `1. ...`.
+ Enum,
+ /// An explicit enumeration numbering: `23.`.
+ EnumNumbering(usize),
+ /// An item in a description list: `/ Term: Details.
+ Desc,
+ /// A label: `<label>`.
+ Label(EcoString),
+ /// A reference: `@label`.
+ Ref(EcoString),
+
/// A comma separator in a sequence: `,`.
Comma,
/// A semicolon terminating an expression: `;`.
Semicolon,
/// A colon between name / key and value in a dictionary, argument or
- /// parameter list: `:`.
+ /// parameter list, or between the term and body of a description list
+ /// term: `:`.
Colon,
- /// The unary plus and addition operator: `+`.
+ /// The unary plus and addition operator, and start of enum items: `+`.
Plus,
- /// The unary negation and subtraction operator: `-`.
+ /// The unary negation and subtraction operator, and start of list
+ /// items: `-`.
Minus,
- /// The division operator: `/`.
+ /// The division operator and start of description list items: `/`.
Slash,
/// A field access and method call operator: `.`.
Dot,
@@ -627,16 +695,16 @@ pub enum NodeKind {
StarEq,
/// The divide-assign operator: `/=`.
SlashEq,
+ /// The spread operator: `..`.
+ Dots,
+ /// An arrow between a closure's parameters and body: `=>`.
+ Arrow,
/// The `not` operator.
Not,
/// The `and` operator.
And,
/// The `or` operator.
Or,
- /// The spread operator: `..`.
- Dots,
- /// An arrow between a closure's parameters and body: `=>`.
- Arrow,
/// The none literal: `none`.
None,
/// The auto literal: `auto`.
@@ -673,60 +741,7 @@ pub enum NodeKind {
From,
/// The `as` keyword.
As,
- /// Markup of which all lines must have a minimal indentation.
- ///
- /// Notably, the number does not determine in which column the markup
- /// started, but to the right of which column all markup elements must be,
- /// so it is zero except for headings and lists.
- Markup { min_indent: usize },
- /// One or more whitespace characters. Single spaces are collapsed into text
- /// nodes if they would otherwise be surrounded by text nodes.
- ///
- /// Also stores how many newlines are contained.
- Space { newlines: usize },
- /// Consecutive text without markup. While basic text with just single
- /// spaces is collapsed into a single node, certain symbols that could
- /// possibly be markup force text into multiple nodes.
- Text(EcoString),
- /// A forced line break: `\` or `\+` if justified.
- Linebreak { justified: bool },
- /// A non-breaking space: `~`.
- NonBreakingSpace,
- /// A soft hyphen: `-?`.
- Shy,
- /// An en-dash: `--`.
- EnDash,
- /// An em-dash: `---`.
- EmDash,
- /// An ellipsis: `...`.
- Ellipsis,
- /// A smart quote: `'` or `"`.
- Quote { double: bool },
- /// A slash and the letter "u" followed by a hexadecimal unicode entity
- /// enclosed in curly braces: `\u{1F5FA}`.
- Escape(char),
- /// Strong content: `*Strong*`.
- Strong,
- /// Emphasized content: `_Emphasized_`.
- Emph,
- /// A raw block with optional syntax highlighting: `` `...` ``.
- Raw(Arc<RawNode>),
- /// A math formula: `$x$`, `$[x^2]$`.
- Math(Arc<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>),
- /// A label: `<label>`.
- Label(EcoString),
- /// A reference: `@label`.
- Ref(EcoString),
+
/// An identifier: `center`.
Ident(EcoString),
/// A boolean: `true`, `false`.
@@ -799,14 +814,7 @@ pub enum NodeKind {
ContinueExpr,
/// A return expression: `return x + 1`.
ReturnExpr,
- /// A line comment, two slashes followed by inner contents, terminated with
- /// a newline: `//<str>\n`.
- LineComment,
- /// A block comment, a slash and a star followed by inner contents,
- /// terminated with a star and a slash: `/*<str>*/`.
- ///
- /// The comment can contain nested block comments.
- BlockComment,
+
/// Tokens that appear in the wrong place.
Error(SpanPos, EcoString),
/// Unknown character sequences.
@@ -844,7 +852,7 @@ impl NodeKind {
}
}
- /// Whether changes _inside_ this node are safely encapuslated, so that only
+ /// Whether changes _inside_ this node are safely encapsulated, so that only
/// this node must be reparsed.
pub fn is_bounded(&self) -> bool {
match self {
@@ -860,7 +868,6 @@ impl NodeKind {
| Self::BlockComment
| Self::Space { .. }
| Self::Escape(_) => true,
- Self::Text(t) => t != "-" && !t.ends_with('.'),
_ => false,
}
}
@@ -868,14 +875,43 @@ impl NodeKind {
/// A human-readable name for the kind.
pub fn as_str(&self) -> &'static str {
match self {
+ Self::LineComment => "line comment",
+ Self::BlockComment => "block comment",
Self::LeftBrace => "opening brace",
Self::RightBrace => "closing brace",
Self::LeftBracket => "opening bracket",
Self::RightBracket => "closing bracket",
Self::LeftParen => "opening paren",
Self::RightParen => "closing paren",
+
+ Self::Markup { .. } => "markup",
+ Self::Space { newlines: (2 ..) } => "paragraph break",
+ Self::Space { .. } => "space",
+ Self::Linebreak => "linebreak",
+ Self::Text(_) => "text",
+ Self::Escape(_) => "escape sequence",
+ Self::NonBreakingSpace => "non-breaking space",
+ Self::Shy => "soft hyphen",
+ Self::EnDash => "en dash",
+ Self::EmDash => "em dash",
+ Self::Ellipsis => "ellipsis",
+ Self::Quote { double: false } => "single quote",
+ Self::Quote { double: true } => "double quote",
Self::Star => "star",
Self::Underscore => "underscore",
+ Self::Strong => "strong content",
+ Self::Emph => "emphasized content",
+ Self::Link(_) => "link",
+ Self::Raw(_) => "raw block",
+ Self::Math(_) => "math formula",
+ Self::Heading => "heading",
+ Self::List => "list item",
+ Self::Enum => "enumeration item",
+ Self::EnumNumbering(_) => "enumeration item numbering",
+ Self::Desc => "description list item",
+ Self::Label(_) => "label",
+ Self::Ref(_) => "reference",
+
Self::Comma => "comma",
Self::Semicolon => "semicolon",
Self::Colon => "colon",
@@ -894,11 +930,11 @@ impl NodeKind {
Self::HyphEq => "subtract-assign operator",
Self::StarEq => "multiply-assign operator",
Self::SlashEq => "divide-assign operator",
+ Self::Dots => "dots",
+ Self::Arrow => "arrow",
Self::Not => "operator `not`",
Self::And => "operator `and`",
Self::Or => "operator `or`",
- Self::Dots => "dots",
- Self::Arrow => "arrow",
Self::None => "`none`",
Self::Auto => "`auto`",
Self::Let => "keyword `let`",
@@ -909,7 +945,6 @@ impl NodeKind {
Self::Else => "keyword `else`",
Self::For => "keyword `for`",
Self::In => "keyword `in`",
- Self::As => "keyword `as`",
Self::While => "keyword `while`",
Self::Break => "keyword `break`",
Self::Continue => "keyword `continue`",
@@ -917,30 +952,8 @@ impl NodeKind {
Self::Import => "keyword `import`",
Self::Include => "keyword `include`",
Self::From => "keyword `from`",
- Self::Markup { .. } => "markup",
- Self::Space { newlines: (2 ..) } => "paragraph break",
- Self::Space { .. } => "space",
- Self::Linebreak { justified: false } => "linebreak",
- Self::Linebreak { justified: true } => "justified linebreak",
- Self::Text(_) => "text",
- Self::NonBreakingSpace => "non-breaking space",
- Self::Shy => "soft hyphen",
- Self::EnDash => "en dash",
- Self::EmDash => "em dash",
- Self::Ellipsis => "ellipsis",
- Self::Quote { double: false } => "single quote",
- Self::Quote { double: true } => "double quote",
- Self::Escape(_) => "escape sequence",
- 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::Label(_) => "label",
- Self::Ref(_) => "reference",
+ Self::As => "keyword `as`",
+
Self::Ident(_) => "identifier",
Self::Bool(_) => "boolean",
Self::Int(_) => "integer",
@@ -977,8 +990,7 @@ impl NodeKind {
Self::BreakExpr => "`break` expression",
Self::ContinueExpr => "`continue` expression",
Self::ReturnExpr => "`return` expression",
- Self::LineComment => "line comment",
- Self::BlockComment => "block comment",
+
Self::Error(_, _) => "parse error",
Self::Unknown(text) => match text.as_str() {
"*/" => "end of block comment",
@@ -998,14 +1010,41 @@ impl Hash for NodeKind {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
+ Self::LineComment => {}
+ Self::BlockComment => {}
Self::LeftBrace => {}
Self::RightBrace => {}
Self::LeftBracket => {}
Self::RightBracket => {}
Self::LeftParen => {}
Self::RightParen => {}
+
+ Self::Markup { min_indent } => min_indent.hash(state),
+ Self::Space { newlines } => newlines.hash(state),
+ Self::Linebreak => {}
+ Self::Text(s) => s.hash(state),
+ Self::Escape(c) => c.hash(state),
+ Self::NonBreakingSpace => {}
+ Self::Shy => {}
+ Self::EnDash => {}
+ Self::EmDash => {}
+ Self::Ellipsis => {}
+ Self::Quote { double } => double.hash(state),
Self::Star => {}
Self::Underscore => {}
+ Self::Strong => {}
+ Self::Emph => {}
+ Self::Link(link) => link.hash(state),
+ Self::Raw(raw) => raw.hash(state),
+ Self::Math(math) => math.hash(state),
+ Self::Heading => {}
+ Self::List => {}
+ Self::Enum => {}
+ Self::EnumNumbering(num) => num.hash(state),
+ Self::Desc => {}
+ Self::Label(c) => c.hash(state),
+ Self::Ref(c) => c.hash(state),
+
Self::Comma => {}
Self::Semicolon => {}
Self::Colon => {}
@@ -1024,11 +1063,11 @@ impl Hash for NodeKind {
Self::HyphEq => {}
Self::StarEq => {}
Self::SlashEq => {}
+ Self::Dots => {}
+ Self::Arrow => {}
Self::Not => {}
Self::And => {}
Self::Or => {}
- Self::Dots => {}
- Self::Arrow => {}
Self::None => {}
Self::Auto => {}
Self::Let => {}
@@ -1039,7 +1078,6 @@ impl Hash for NodeKind {
Self::Else => {}
Self::For => {}
Self::In => {}
- Self::As => {}
Self::While => {}
Self::Break => {}
Self::Continue => {}
@@ -1047,27 +1085,8 @@ impl Hash for NodeKind {
Self::Import => {}
Self::Include => {}
Self::From => {}
- Self::Markup { min_indent } => min_indent.hash(state),
- Self::Space { newlines } => newlines.hash(state),
- Self::Linebreak { justified } => justified.hash(state),
- Self::Text(s) => s.hash(state),
- Self::NonBreakingSpace => {}
- Self::Shy => {}
- Self::EnDash => {}
- Self::EmDash => {}
- Self::Ellipsis => {}
- Self::Quote { double } => double.hash(state),
- Self::Escape(c) => c.hash(state),
- Self::Strong => {}
- Self::Emph => {}
- Self::Raw(raw) => raw.hash(state),
- Self::Math(math) => math.hash(state),
- Self::List => {}
- Self::Heading => {}
- Self::Enum => {}
- Self::EnumNumbering(num) => num.hash(state),
- Self::Label(c) => c.hash(state),
- Self::Ref(c) => c.hash(state),
+ Self::As => {}
+
Self::Ident(v) => v.hash(state),
Self::Bool(v) => v.hash(state),
Self::Int(v) => v.hash(state),
@@ -1104,8 +1123,7 @@ impl Hash for NodeKind {
Self::BreakExpr => {}
Self::ContinueExpr => {}
Self::ReturnExpr => {}
- Self::LineComment => {}
- Self::BlockComment => {}
+
Self::Error(pos, msg) => (pos, msg).hash(state),
Self::Unknown(text) => text.hash(state),
}