summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval/library.rs4
-rw-r--r--src/eval/mod.rs2
-rw-r--r--src/ide/complete.rs1
-rw-r--r--src/model/content.rs33
-rw-r--r--src/model/realize.rs20
-rw-r--r--src/model/typeset.rs31
-rw-r--r--src/syntax/parser.rs38
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);