diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/library.rs | 6 | ||||
| -rw-r--r-- | src/eval/mod.rs | 4 | ||||
| -rw-r--r-- | src/ide/highlight.rs | 1 | ||||
| -rw-r--r-- | src/syntax/ast.rs | 17 | ||||
| -rw-r--r-- | src/syntax/kind.rs | 7 | ||||
| -rw-r--r-- | src/syntax/lexer.rs | 12 | ||||
| -rw-r--r-- | src/syntax/parser.rs | 13 |
7 files changed, 42 insertions, 18 deletions
diff --git a/src/eval/library.rs b/src/eval/library.rs index 14f02d98..d3f7547d 100644 --- a/src/eval/library.rs +++ b/src/eval/library.rs @@ -59,8 +59,8 @@ pub struct LangItems { pub raw_languages: fn() -> Vec<(&'static str, Vec<&'static str>)>, /// A hyperlink: `https://typst.org`. pub link: fn(url: EcoString) -> Content, - /// A reference: `@target`. - pub ref_: fn(target: Label) -> Content, + /// A reference: `@target`, `@target[..]`. + pub reference: fn(target: Label, supplement: Option<Content>) -> Content, /// A section heading: `= Introduction`. pub heading: fn(level: NonZeroUsize, body: Content) -> Content, /// An item in a bullet list: `- ...`. @@ -106,7 +106,7 @@ impl Hash for LangItems { self.emph.hash(state); self.raw.hash(state); self.link.hash(state); - self.ref_.hash(state); + self.reference.hash(state); self.heading.hash(state); self.list_item.hash(state); self.enum_item.hash(state); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index ae5f668a..127c930f 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -567,7 +567,9 @@ impl Eval for ast::Ref { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - Ok((vm.items.ref_)(Label(self.get().into()))) + let label = Label(self.target().into()); + let supplement = self.supplement().map(|block| block.eval(vm)).transpose()?; + Ok((vm.items.reference)(label, supplement)) } } diff --git a/src/ide/highlight.rs b/src/ide/highlight.rs index 7827b2c9..6214328b 100644 --- a/src/ide/highlight.rs +++ b/src/ide/highlight.rs @@ -129,6 +129,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> { SyntaxKind::Link => Some(Tag::Link), SyntaxKind::Label => Some(Tag::Label), SyntaxKind::Ref => Some(Tag::Ref), + SyntaxKind::RefMarker => None, SyntaxKind::Heading => Some(Tag::Heading), SyntaxKind::HeadingMarker => None, SyntaxKind::ListItem => None, diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 2fdedbcf..8e48358d 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -101,7 +101,7 @@ pub enum Expr { Link(Link), /// A label: `<intro>`. Label(Label), - /// A reference: `@target`. + /// A reference: `@target`, `@target[..]`. Ref(Ref), /// A section heading: `= Introduction`. Heading(Heading), @@ -604,14 +604,23 @@ impl Label { } node! { - /// A reference: `@target`. + /// A reference: `@target`, `@target[..]`. Ref } impl Ref { /// Get the target. - pub fn get(&self) -> &str { - self.0.text().trim_start_matches('@') + pub fn target(&self) -> &str { + self.0 + .children() + .find(|node| node.kind() == SyntaxKind::RefMarker) + .map(|node| node.text().trim_start_matches('@')) + .unwrap_or_default() + } + + /// Get the supplement. + pub fn supplement(&self) -> Option<ContentBlock> { + self.0.cast_last_match() } } diff --git a/src/syntax/kind.rs b/src/syntax/kind.rs index 47b5da31..ce3ae744 100644 --- a/src/syntax/kind.rs +++ b/src/syntax/kind.rs @@ -36,8 +36,10 @@ pub enum SyntaxKind { Link, /// A label: `<intro>`. Label, - /// A reference: `@target`. + /// A reference: `@target`, `@target[..]`. Ref, + /// Introduces a reference: `@target`. + RefMarker, /// A section heading: `= Introduction`. Heading, /// Introduces a section heading: `=`, `==`, ... @@ -324,12 +326,14 @@ impl SyntaxKind { Self::Parbreak => "paragraph break", Self::Escape => "escape sequence", Self::Shorthand => "shorthand", + Self::SmartQuote => "smart quote", Self::Strong => "strong content", Self::Emph => "emphasized content", Self::Raw => "raw block", Self::Link => "link", Self::Label => "label", Self::Ref => "reference", + Self::RefMarker => "reference marker", Self::Heading => "heading", Self::HeadingMarker => "heading marker", Self::ListItem => "list item", @@ -358,7 +362,6 @@ impl SyntaxKind { Self::Star => "star", Self::Underscore => "underscore", Self::Dollar => "dollar sign", - Self::SmartQuote => "smart quote", Self::Plus => "plus", Self::Minus => "minus", Self::Slash => "slash", diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs index 919cce69..8e27d98d 100644 --- a/src/syntax/lexer.rs +++ b/src/syntax/lexer.rs @@ -172,7 +172,7 @@ impl Lexer<'_> { 'h' if self.s.eat_if("ttps://") => self.link(), '0'..='9' => self.numbering(start), '<' if self.s.at(is_id_continue) => self.label(), - '@' if self.s.at(is_id_continue) => self.reference(), + '@' => self.ref_marker(), '.' if self.s.eat_if("..") => SyntaxKind::Shorthand, '-' if self.s.eat_if("--") => SyntaxKind::Shorthand, @@ -297,6 +297,11 @@ impl Lexer<'_> { self.text() } + fn ref_marker(&mut self) -> SyntaxKind { + self.s.eat_while(is_id_continue); + SyntaxKind::RefMarker + } + fn label(&mut self) -> SyntaxKind { let label = self.s.eat_while(is_id_continue); if label.is_empty() { @@ -310,11 +315,6 @@ impl Lexer<'_> { SyntaxKind::Label } - fn reference(&mut self) -> SyntaxKind { - self.s.eat_while(is_id_continue); - SyntaxKind::Ref - } - fn text(&mut self) -> SyntaxKind { macro_rules! table { ($(|$c:literal)*) => { diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index 201d78fa..127a89d5 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -104,8 +104,7 @@ fn markup_expr(p: &mut Parser, at_start: &mut bool) { | SyntaxKind::SmartQuote | SyntaxKind::Raw | SyntaxKind::Link - | SyntaxKind::Label - | SyntaxKind::Ref => p.eat(), + | SyntaxKind::Label => p.eat(), SyntaxKind::Hashtag => embedded_code_expr(p), SyntaxKind::Star => strong(p), @@ -114,6 +113,7 @@ fn markup_expr(p: &mut Parser, at_start: &mut bool) { SyntaxKind::ListMarker if *at_start => list_item(p), SyntaxKind::EnumMarker if *at_start => enum_item(p), SyntaxKind::TermMarker if *at_start => term_item(p), + SyntaxKind::RefMarker => reference(p), SyntaxKind::Dollar => formula(p), SyntaxKind::LeftBracket @@ -198,6 +198,15 @@ fn term_item(p: &mut Parser) { p.wrap(m, SyntaxKind::TermItem); } +fn reference(p: &mut Parser) { + let m = p.marker(); + p.assert(SyntaxKind::RefMarker); + if p.directly_at(SyntaxKind::LeftBracket) { + content_block(p); + } + p.wrap(m, SyntaxKind::Ref); +} + fn whitespace_line(p: &mut Parser) { while !p.newline() && p.current().is_trivia() { p.eat(); |
