diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-11 17:42:40 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-11 18:29:48 +0100 |
| commit | 529d3e10c6b4d973e88b6c295eb22a45ea426e42 (patch) | |
| tree | 1815aa9336e71565e24d94bacccb98f09e91b693 /src | |
| parent | 8e5f446544fd147277ed2e4208c7ea793cc846a7 (diff) | |
Section references
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/library.rs | 4 | ||||
| -rw-r--r-- | src/eval/mod.rs | 2 | ||||
| -rw-r--r-- | src/ide/complete.rs | 1 | ||||
| -rw-r--r-- | src/model/content.rs | 33 | ||||
| -rw-r--r-- | src/model/realize.rs | 20 | ||||
| -rw-r--r-- | src/model/typeset.rs | 31 | ||||
| -rw-r--r-- | src/syntax/parser.rs | 38 |
7 files changed, 92 insertions, 37 deletions
diff --git a/src/eval/library.rs b/src/eval/library.rs index c37c16fd..14f02d98 100644 --- a/src/eval/library.rs +++ b/src/eval/library.rs @@ -9,7 +9,7 @@ use super::Module; use crate::diag::SourceResult; use crate::doc::Document; use crate::geom::{Abs, Dir}; -use crate::model::{Content, NodeId, StyleChain, StyleMap, Vt}; +use crate::model::{Content, Label, NodeId, StyleChain, StyleMap, Vt}; use crate::util::hash128; /// Definition of Typst's standard library. @@ -60,7 +60,7 @@ pub struct LangItems { /// A hyperlink: `https://typst.org`. pub link: fn(url: EcoString) -> Content, /// A reference: `@target`. - pub ref_: fn(target: EcoString) -> Content, + pub ref_: fn(target: Label) -> Content, /// A section heading: `= Introduction`. pub heading: fn(level: NonZeroUsize, body: Content) -> Content, /// An item in a bullet list: `- ...`. diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 145f961a..fe56c060 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -561,7 +561,7 @@ impl Eval for ast::Ref { type Output = Content; fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> { - Ok((vm.items.ref_)(self.get().into())) + Ok((vm.items.ref_)(Label(self.get().into()))) } } diff --git a/src/ide/complete.rs b/src/ide/complete.rs index a0d5e9a4..a7b001ae 100644 --- a/src/ide/complete.rs +++ b/src/ide/complete.rs @@ -974,7 +974,6 @@ impl<'a> CompletionContext<'a> { let detail = docs.map(Into::into).or_else(|| match value { Value::Symbol(_) => None, - Value::Content(_) => None, Value::Func(func) => { func.info().map(|info| plain_docs_sentence(info.docs).into()) } diff --git a/src/model/content.rs b/src/model/content.rs index 17fa786b..be737331 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -10,7 +10,7 @@ use once_cell::sync::Lazy; use super::{node, Guard, Recipe, Style, StyleMap}; use crate::diag::{SourceResult, StrResult}; -use crate::eval::{cast_from_value, Args, FuncInfo, Str, Value, Vm}; +use crate::eval::{cast_from_value, Args, Cast, FuncInfo, Str, Value, Vm}; use crate::syntax::Span; use crate::util::pretty_array_like; use crate::World; @@ -27,7 +27,7 @@ pub struct Content { /// Modifiers that can be attached to content. #[derive(Debug, Clone, PartialEq, Hash)] enum Modifier { - Prepared, + Synthesized, Guard(Guard), } @@ -59,6 +59,12 @@ impl Content { self.id } + /// Whether the content is empty. + pub fn is_empty(&self) -> bool { + self.to::<SequenceNode>() + .map_or(false, |seq| seq.children().is_empty()) + } + /// Whether the contained node is of type `T`. pub fn is<T>(&self) -> bool where @@ -112,6 +118,21 @@ impl Content { .map(|(_, value)| value) } + /// Access a field on the content as a specified type. + #[track_caller] + pub fn cast_field<T: Cast>(&self, name: &str) -> Option<T> { + match self.field(name) { + Some(value) => Some(value.clone().cast().unwrap()), + None => None, + } + } + + /// Expect a field on the content to exist as a specified type. + #[track_caller] + pub fn expect_field<T: Cast>(&self, name: &str) -> T { + self.cast_field(name).unwrap() + } + /// List all fields on the content. pub fn fields(&self) -> &[(EcoString, Value)] { &self.fields @@ -209,14 +230,14 @@ impl Content { } /// Mark this content as prepared. - pub fn prepared(mut self) -> Self { - self.modifiers.push(Modifier::Prepared); + pub fn synthesized(mut self) -> Self { + self.modifiers.push(Modifier::Synthesized); self } /// Whether this node was prepared. - pub fn is_prepared(&self) -> bool { - self.modifiers.contains(&Modifier::Prepared) + pub fn is_synthesized(&self) -> bool { + self.modifiers.contains(&Modifier::Synthesized) } /// Whether no show rule was executed for this node so far. diff --git a/src/model/realize.rs b/src/model/realize.rs index c4c67a4f..4685a605 100644 --- a/src/model/realize.rs +++ b/src/model/realize.rs @@ -3,7 +3,7 @@ use crate::diag::SourceResult; /// Whether the target is affected by show rules in the given style chain. pub fn applicable(target: &Content, styles: StyleChain) -> bool { - if target.can::<dyn Prepare>() && !target.is_prepared() { + if target.can::<dyn Synthesize>() && !target.is_synthesized() { return true; } @@ -34,6 +34,18 @@ pub fn realize( // Find out how many recipes there are. let mut n = styles.recipes().count(); + // Synthesize if not already happened for this node. + if target.can::<dyn Synthesize>() && !target.is_synthesized() { + return Ok(Some( + target + .clone() + .synthesized() + .with::<dyn Synthesize>() + .unwrap() + .synthesize(vt, styles), + )); + } + // Find an applicable recipe. let mut realized = None; for recipe in styles.recipes() { @@ -132,10 +144,10 @@ fn try_apply( } } -/// Preparations before execution of any show rule. -pub trait Prepare { +/// Synthesize fields on a node. This happens before execution of any show rule. +pub trait Synthesize { /// Prepare the node for show rule application. - fn prepare(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content>; + fn synthesize(&self, vt: &mut Vt, styles: StyleChain) -> Content; } /// The base recipe for a node. diff --git a/src/model/typeset.rs b/src/model/typeset.rs index 6361e6ce..377c7c76 100644 --- a/src/model/typeset.rs +++ b/src/model/typeset.rs @@ -77,6 +77,11 @@ impl<'a> Vt<'a> { self.provider.identify(hash128(key)) } + /// Whether things are locatable already. + pub fn locatable(&self) -> bool { + self.introspector.init() + } + /// Locate all metadata matches for the given selector. pub fn locate(&self, selector: Selector) -> Vec<(StableId, &Content)> { self.introspector.locate(selector) @@ -115,6 +120,7 @@ impl StabilityProvider { /// Provides access to information about the document. #[doc(hidden)] pub struct Introspector { + init: bool, nodes: Vec<(StableId, Content)>, queries: RefCell<Vec<(Selector, u128)>>, } @@ -122,7 +128,11 @@ pub struct Introspector { impl Introspector { /// Create a new introspector. fn new() -> Self { - Self { nodes: vec![], queries: RefCell::new(vec![]) } + Self { + init: false, + nodes: vec![], + queries: RefCell::new(vec![]), + } } /// Update the information given new frames and return whether we can stop @@ -135,14 +145,20 @@ impl Introspector { self.extract(frame, page, Transform::identity()); } + let was_init = std::mem::replace(&mut self.init, true); let queries = std::mem::take(&mut self.queries).into_inner(); - for (selector, hash) in queries { - let nodes = self.locate_impl(&selector); - if hash128(&nodes) != hash { + + for (selector, hash) in &queries { + let nodes = self.locate_impl(selector); + if hash128(&nodes) != *hash { return false; } } + if !was_init && !queries.is_empty() { + return false; + } + true } @@ -161,7 +177,7 @@ impl Introspector { let pos = pos.transform(ts); let mut node = content.clone(); let loc = Location { page, pos }; - node.push_field("loc", loc); + node.push_field("location", loc); self.nodes.push((id, node)); } } @@ -173,6 +189,11 @@ impl Introspector { #[comemo::track] impl Introspector { + /// Whether this introspector is not yet initialized. + fn init(&self) -> bool { + self.init + } + /// Locate all metadata matches for the given selector. fn locate(&self, selector: Selector) -> Vec<(StableId, &Content)> { let nodes = self.locate_impl(&selector); diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index b4321dbe..201d78fa 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -26,7 +26,7 @@ fn markup( p: &mut Parser, mut at_start: bool, min_indent: usize, - mut stop: impl FnMut(SyntaxKind) -> bool, + mut stop: impl FnMut(&Parser) -> bool, ) { let m = p.marker(); let mut nesting: usize = 0; @@ -34,7 +34,7 @@ fn markup( match p.current() { SyntaxKind::LeftBracket => nesting += 1, SyntaxKind::RightBracket if nesting > 0 => nesting -= 1, - _ if stop(p.current) => break, + _ if stop(p) => break, _ => {} } @@ -133,10 +133,10 @@ fn markup_expr(p: &mut Parser, at_start: &mut bool) { fn strong(p: &mut Parser) { let m = p.marker(); p.assert(SyntaxKind::Star); - markup(p, false, 0, |kind| { - kind == SyntaxKind::Star - || kind == SyntaxKind::Parbreak - || kind == SyntaxKind::RightBracket + markup(p, false, 0, |p| { + p.at(SyntaxKind::Star) + || p.at(SyntaxKind::Parbreak) + || p.at(SyntaxKind::RightBracket) }); p.expect(SyntaxKind::Star); p.wrap(m, SyntaxKind::Strong); @@ -145,10 +145,10 @@ fn strong(p: &mut Parser) { fn emph(p: &mut Parser) { let m = p.marker(); p.assert(SyntaxKind::Underscore); - markup(p, false, 0, |kind| { - kind == SyntaxKind::Underscore - || kind == SyntaxKind::Parbreak - || kind == SyntaxKind::RightBracket + markup(p, false, 0, |p| { + p.at(SyntaxKind::Underscore) + || p.at(SyntaxKind::Parbreak) + || p.at(SyntaxKind::RightBracket) }); p.expect(SyntaxKind::Underscore); p.wrap(m, SyntaxKind::Emph); @@ -158,8 +158,10 @@ fn heading(p: &mut Parser) { let m = p.marker(); p.assert(SyntaxKind::HeadingMarker); whitespace_line(p); - markup(p, false, usize::MAX, |kind| { - kind == SyntaxKind::Label || kind == SyntaxKind::RightBracket + markup(p, false, usize::MAX, |p| { + p.at(SyntaxKind::Label) + || p.at(SyntaxKind::RightBracket) + || (p.at(SyntaxKind::Space) && p.lexer.clone().next() == SyntaxKind::Label) }); p.wrap(m, SyntaxKind::Heading); } @@ -169,7 +171,7 @@ fn list_item(p: &mut Parser) { p.assert(SyntaxKind::ListMarker); let min_indent = p.column(p.prev_end()); whitespace_line(p); - markup(p, false, min_indent, |kind| kind == SyntaxKind::RightBracket); + markup(p, false, min_indent, |p| p.at(SyntaxKind::RightBracket)); p.wrap(m, SyntaxKind::ListItem); } @@ -178,7 +180,7 @@ fn enum_item(p: &mut Parser) { p.assert(SyntaxKind::EnumMarker); let min_indent = p.column(p.prev_end()); whitespace_line(p); - markup(p, false, min_indent, |kind| kind == SyntaxKind::RightBracket); + markup(p, false, min_indent, |p| p.at(SyntaxKind::RightBracket)); p.wrap(m, SyntaxKind::EnumItem); } @@ -187,12 +189,12 @@ fn term_item(p: &mut Parser) { p.assert(SyntaxKind::TermMarker); let min_indent = p.column(p.prev_end()); whitespace_line(p); - markup(p, false, usize::MAX, |kind| { - kind == SyntaxKind::Colon || kind == SyntaxKind::RightBracket + markup(p, false, usize::MAX, |p| { + p.at(SyntaxKind::Colon) || p.at(SyntaxKind::RightBracket) }); p.expect(SyntaxKind::Colon); whitespace_line(p); - markup(p, false, min_indent, |kind| kind == SyntaxKind::RightBracket); + markup(p, false, min_indent, |p| p.at(SyntaxKind::RightBracket)); p.wrap(m, SyntaxKind::TermItem); } @@ -679,7 +681,7 @@ fn content_block(p: &mut Parser) { let m = p.marker(); p.enter(LexMode::Markup); p.assert(SyntaxKind::LeftBracket); - markup(p, true, 0, |kind| kind == SyntaxKind::RightBracket); + markup(p, true, 0, |p| p.at(SyntaxKind::RightBracket)); p.expect(SyntaxKind::RightBracket); p.exit(); p.wrap(m, SyntaxKind::ContentBlock); |
