Hover and autocomplete in show rules
This commit is contained in:
parent
6d64d3e8e9
commit
af7fe4d760
@ -229,12 +229,11 @@ fn compile(command: CompileCommand) -> StrResult<()> {
|
||||
/// Compile a single time.
|
||||
fn compile_once(world: &mut SystemWorld, command: &CompileCommand) -> StrResult<()> {
|
||||
status(command, Status::Compiling).unwrap();
|
||||
|
||||
world.reset();
|
||||
world.main = world.resolve(&command.input).map_err(|err| err.to_string())?;
|
||||
|
||||
let main = world.resolve(&command.input).map_err(|err| err.to_string())?;
|
||||
let source = world.source(main);
|
||||
|
||||
match typst::compile(world, source) {
|
||||
match typst::compile(world) {
|
||||
// Export the PDF.
|
||||
Ok(document) => {
|
||||
let buffer = typst::export::pdf(&document);
|
||||
@ -372,6 +371,7 @@ struct SystemWorld {
|
||||
hashes: RefCell<HashMap<PathBuf, FileResult<PathHash>>>,
|
||||
paths: RefCell<HashMap<PathHash, PathSlot>>,
|
||||
sources: FrozenVec<Box<Source>>,
|
||||
main: SourceId,
|
||||
}
|
||||
|
||||
/// Holds details about the location of a font and lazily the font itself.
|
||||
@ -401,6 +401,7 @@ impl SystemWorld {
|
||||
hashes: RefCell::default(),
|
||||
paths: RefCell::default(),
|
||||
sources: FrozenVec::new(),
|
||||
main: SourceId::detached(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -414,6 +415,25 @@ impl World for SystemWorld {
|
||||
&self.library
|
||||
}
|
||||
|
||||
fn main(&self) -> &Source {
|
||||
self.source(self.main)
|
||||
}
|
||||
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
self.slot(path)?
|
||||
.source
|
||||
.get_or_init(|| {
|
||||
let buf = read(path)?;
|
||||
let text = String::from_utf8(buf)?;
|
||||
Ok(self.insert(path, text))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn source(&self, id: SourceId) -> &Source {
|
||||
&self.sources[id.into_u16() as usize]
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&self.book
|
||||
}
|
||||
@ -434,21 +454,6 @@ impl World for SystemWorld {
|
||||
.get_or_init(|| read(path).map(Buffer::from))
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
self.slot(path)?
|
||||
.source
|
||||
.get_or_init(|| {
|
||||
let buf = read(path)?;
|
||||
let text = String::from_utf8(buf)?;
|
||||
Ok(self.insert(path, text))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn source(&self, id: SourceId) -> &Source {
|
||||
&self.sources[id.into_u16() as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemWorld {
|
||||
|
@ -307,7 +307,7 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html {
|
||||
|
||||
let source = Source::new(SourceId::from_u16(0), Path::new("main.typ"), compile);
|
||||
let world = DocWorld(source);
|
||||
let mut frames = match typst::compile(&world, &world.0) {
|
||||
let mut frames = match typst::compile(&world) {
|
||||
Ok(doc) => doc.pages,
|
||||
Err(err) => {
|
||||
let msg = &err[0].message;
|
||||
@ -335,6 +335,19 @@ impl World for DocWorld {
|
||||
&LIBRARY
|
||||
}
|
||||
|
||||
fn main(&self) -> &Source {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn resolve(&self, _: &Path) -> FileResult<SourceId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn source(&self, id: SourceId) -> &Source {
|
||||
assert_eq!(id.into_u16(), 0, "invalid source id");
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&FONTS.0
|
||||
}
|
||||
@ -350,13 +363,4 @@ impl World for DocWorld {
|
||||
.contents()
|
||||
.into())
|
||||
}
|
||||
|
||||
fn resolve(&self, _: &Path) -> FileResult<SourceId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn source(&self, id: SourceId) -> &Source {
|
||||
assert_eq!(id.into_u16(), 0, "invalid source id");
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ impl Layout for EnumNode {
|
||||
|
||||
let resolved = if full {
|
||||
parents.push(number);
|
||||
let content = numbering.apply(vt.world, &parents)?.display();
|
||||
let content = numbering.apply_vt(vt, &parents)?.display();
|
||||
parents.pop();
|
||||
content
|
||||
} else {
|
||||
@ -188,7 +188,7 @@ impl Layout for EnumNode {
|
||||
Numbering::Pattern(pattern) => {
|
||||
TextNode::packed(pattern.apply_kth(parents.len(), number))
|
||||
}
|
||||
other => other.apply(vt.world, &[number])?.display(),
|
||||
other => other.apply_vt(vt, &[number])?.display(),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -128,7 +128,7 @@ impl Layout for ListNode {
|
||||
};
|
||||
|
||||
let depth = self.depth(styles);
|
||||
let marker = self.marker(styles).resolve(vt.world, depth)?;
|
||||
let marker = self.marker(styles).resolve(vt, depth)?;
|
||||
|
||||
let mut cells = vec![];
|
||||
for item in self.children() {
|
||||
@ -181,17 +181,14 @@ pub enum ListMarker {
|
||||
|
||||
impl ListMarker {
|
||||
/// Resolve the marker for the given depth.
|
||||
fn resolve(&self, world: Tracked<dyn World>, depth: usize) -> SourceResult<Content> {
|
||||
fn resolve(&self, vt: &mut Vt, depth: usize) -> SourceResult<Content> {
|
||||
Ok(match self {
|
||||
Self::Content(list) => list
|
||||
.get(depth)
|
||||
.or(list.last())
|
||||
.cloned()
|
||||
.unwrap_or_else(|| TextNode::packed('•')),
|
||||
Self::Func(func) => {
|
||||
let args = Args::new(func.span(), [Value::Int(depth as i64)]);
|
||||
func.call_detached(world, args)?.display()
|
||||
}
|
||||
Self::Func(func) => func.call_vt(vt, [Value::Int(depth as i64)])?.display(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ use std::mem;
|
||||
|
||||
use typed_arena::Arena;
|
||||
use typst::diag::SourceResult;
|
||||
use typst::eval::Tracer;
|
||||
use typst::model::{applicable, realize, SequenceNode, StyleVecBuilder, StyledNode};
|
||||
|
||||
use crate::math::{FormulaNode, LayoutMath};
|
||||
@ -68,11 +69,12 @@ impl LayoutRoot for Content {
|
||||
fn cached(
|
||||
node: &Content,
|
||||
world: Tracked<dyn World>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
provider: TrackedMut<StabilityProvider>,
|
||||
introspector: Tracked<Introspector>,
|
||||
styles: StyleChain,
|
||||
) -> SourceResult<Document> {
|
||||
let mut vt = Vt { world, provider, introspector };
|
||||
let mut vt = Vt { world, tracer, provider, introspector };
|
||||
let scratch = Scratch::default();
|
||||
let (realized, styles) = realize_root(&mut vt, &scratch, node, styles)?;
|
||||
realized
|
||||
@ -84,6 +86,7 @@ impl LayoutRoot for Content {
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
styles,
|
||||
@ -129,12 +132,13 @@ impl Layout for Content {
|
||||
fn cached(
|
||||
node: &Content,
|
||||
world: Tracked<dyn World>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
provider: TrackedMut<StabilityProvider>,
|
||||
introspector: Tracked<Introspector>,
|
||||
styles: StyleChain,
|
||||
regions: Regions,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut vt = Vt { world, provider, introspector };
|
||||
let mut vt = Vt { world, tracer, provider, introspector };
|
||||
let scratch = Scratch::default();
|
||||
let (realized, styles) = realize_block(&mut vt, &scratch, node, styles)?;
|
||||
realized
|
||||
@ -146,6 +150,7 @@ impl Layout for Content {
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
styles,
|
||||
|
@ -403,13 +403,10 @@ pub enum Marginal {
|
||||
|
||||
impl Marginal {
|
||||
/// Resolve the marginal based on the page number.
|
||||
pub fn resolve(&self, vt: &Vt, page: usize) -> SourceResult<Content> {
|
||||
pub fn resolve(&self, vt: &mut Vt, page: usize) -> SourceResult<Content> {
|
||||
Ok(match self {
|
||||
Self::Content(content) => content.clone(),
|
||||
Self::Func(func) => {
|
||||
let args = Args::new(func.span(), [Value::Int(page as i64)]);
|
||||
func.call_detached(vt.world, args)?.display()
|
||||
}
|
||||
Self::Func(func) => func.call_vt(vt, [Value::Int(page as i64)])?.display(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use typst::eval::Tracer;
|
||||
use unicode_bidi::{BidiInfo, Level as BidiLevel};
|
||||
use unicode_script::{Script, UnicodeScript};
|
||||
use xi_unicode::LineBreakIterator;
|
||||
@ -138,6 +139,7 @@ impl ParNode {
|
||||
fn cached(
|
||||
par: &ParNode,
|
||||
world: Tracked<dyn World>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
provider: TrackedMut<StabilityProvider>,
|
||||
introspector: Tracked<Introspector>,
|
||||
styles: StyleChain,
|
||||
@ -145,7 +147,7 @@ impl ParNode {
|
||||
region: Size,
|
||||
expand: bool,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut vt = Vt { world, provider, introspector };
|
||||
let mut vt = Vt { world, tracer, provider, introspector };
|
||||
let children = par.children();
|
||||
|
||||
// Collect all text into one string for BiDi analysis.
|
||||
@ -166,6 +168,7 @@ impl ParNode {
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
styles,
|
||||
|
@ -227,14 +227,13 @@ pub enum Celled<T> {
|
||||
|
||||
impl<T: Cast + Clone> Celled<T> {
|
||||
/// Resolve the value based on the cell position.
|
||||
pub fn resolve(&self, vt: &Vt, x: usize, y: usize) -> SourceResult<T> {
|
||||
pub fn resolve(&self, vt: &mut Vt, x: usize, y: usize) -> SourceResult<T> {
|
||||
Ok(match self {
|
||||
Self::Value(value) => value.clone(),
|
||||
Self::Func(func) => {
|
||||
let args =
|
||||
Args::new(func.span(), [Value::Int(x as i64), Value::Int(y as i64)]);
|
||||
func.call_detached(vt.world, args)?.cast().at(func.span())?
|
||||
}
|
||||
Self::Func(func) => func
|
||||
.call_vt(vt, [Value::Int(x as i64), Value::Int(y as i64)])?
|
||||
.cast()
|
||||
.at(func.span())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use std::str::FromStr;
|
||||
|
||||
use ecow::{eco_vec, EcoVec};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use typst::eval::Tracer;
|
||||
|
||||
use super::{Numbering, NumberingPattern};
|
||||
use crate::layout::PageNode;
|
||||
@ -125,10 +126,16 @@ impl Show for CounterNode {
|
||||
return counter.resolve(vt, id, &numbering);
|
||||
}
|
||||
|
||||
let sequence = counter.sequence(vt.world, vt.introspector)?;
|
||||
let sequence = counter.sequence(
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
)?;
|
||||
|
||||
Ok(match (sequence.single(id), sequence.single(None)) {
|
||||
(Some(current), Some(total)) => {
|
||||
numbering.apply(vt.world, &[current, total])?.display()
|
||||
numbering.apply_vt(vt, &[current, total])?.display()
|
||||
}
|
||||
_ => Content::empty(),
|
||||
})
|
||||
@ -213,7 +220,7 @@ impl Counter {
|
||||
/// id.
|
||||
pub fn resolve(
|
||||
&self,
|
||||
vt: &Vt,
|
||||
vt: &mut Vt,
|
||||
stop: Option<StableId>,
|
||||
numbering: &Numbering,
|
||||
) -> SourceResult<Content> {
|
||||
@ -221,9 +228,15 @@ impl Counter {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
|
||||
let sequence = self.sequence(vt.world, vt.introspector)?;
|
||||
let sequence = self.sequence(
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
)?;
|
||||
|
||||
Ok(match sequence.at(stop) {
|
||||
Some(state) => numbering.apply(vt.world, &state.0)?.display(),
|
||||
Some(state) => numbering.apply_vt(vt, &state.0)?.display(),
|
||||
None => Content::empty(),
|
||||
})
|
||||
}
|
||||
@ -236,8 +249,11 @@ impl Counter {
|
||||
fn sequence(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
provider: TrackedMut<StabilityProvider>,
|
||||
introspector: Tracked<Introspector>,
|
||||
) -> SourceResult<CounterSequence> {
|
||||
let mut vt = Vt { world, tracer, provider, introspector };
|
||||
let mut search = Selector::Node(
|
||||
NodeId::of::<CounterNode>(),
|
||||
Some(dict! { "counter" => self.clone() }),
|
||||
@ -277,7 +293,7 @@ impl Counter {
|
||||
None => Some(CounterUpdate::Step(NonZeroUsize::ONE)),
|
||||
},
|
||||
} {
|
||||
state.update(world, update)?;
|
||||
state.update(&mut vt, update)?;
|
||||
}
|
||||
|
||||
stops.push((id, state.clone()));
|
||||
@ -335,17 +351,15 @@ pub struct CounterState(pub SmallVec<[NonZeroUsize; 3]>);
|
||||
|
||||
impl CounterState {
|
||||
/// Advance the counter and return the numbers for the given heading.
|
||||
pub fn update(
|
||||
&mut self,
|
||||
world: Tracked<dyn World>,
|
||||
update: CounterUpdate,
|
||||
) -> SourceResult<()> {
|
||||
pub fn update(&mut self, vt: &mut Vt, update: CounterUpdate) -> SourceResult<()> {
|
||||
match update {
|
||||
CounterUpdate::Set(state) => *self = state,
|
||||
CounterUpdate::Step(level) => self.step(level),
|
||||
CounterUpdate::Func(func) => {
|
||||
let args = Args::new(func.span(), self.0.iter().copied().map(Into::into));
|
||||
*self = func.call_detached(world, args)?.cast().at(func.span())?
|
||||
*self = func
|
||||
.call_vt(vt, self.0.iter().copied().map(Into::into))?
|
||||
.cast()
|
||||
.at(func.span())?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -64,7 +64,7 @@ pub fn numbering(
|
||||
#[variadic]
|
||||
numbers: Vec<NonZeroUsize>,
|
||||
) -> Value {
|
||||
numbering.apply(vm.world(), &numbers)?
|
||||
numbering.apply_vm(vm, &numbers)?
|
||||
}
|
||||
|
||||
/// How to number a sequence of things.
|
||||
@ -78,11 +78,7 @@ pub enum Numbering {
|
||||
|
||||
impl Numbering {
|
||||
/// Apply the pattern to the given numbers.
|
||||
pub fn apply(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
numbers: &[NonZeroUsize],
|
||||
) -> SourceResult<Value> {
|
||||
pub fn apply_vm(&self, vm: &mut Vm, numbers: &[NonZeroUsize]) -> SourceResult<Value> {
|
||||
Ok(match self {
|
||||
Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()),
|
||||
Self::Func(func) => {
|
||||
@ -90,7 +86,17 @@ impl Numbering {
|
||||
func.span(),
|
||||
numbers.iter().map(|n| Value::Int(n.get() as i64)),
|
||||
);
|
||||
func.call_detached(world, args)?
|
||||
func.call_vm(vm, args)?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply the pattern to the given numbers.
|
||||
pub fn apply_vt(&self, vt: &mut Vt, numbers: &[NonZeroUsize]) -> SourceResult<Value> {
|
||||
Ok(match self {
|
||||
Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()),
|
||||
Self::Func(func) => {
|
||||
func.call_vt(vt, numbers.iter().map(|n| Value::Int(n.get() as i64)))?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -91,10 +91,12 @@ impl Show for OutlineNode {
|
||||
let depth = self.depth(styles);
|
||||
|
||||
let mut ancestors: Vec<&HeadingNode> = vec![];
|
||||
for node in vt.introspector.query(Selector::Node(
|
||||
let nodes = vt.introspector.query(Selector::Node(
|
||||
NodeId::of::<HeadingNode>(),
|
||||
Some(dict! { "outlined" => true }),
|
||||
)) {
|
||||
));
|
||||
|
||||
for node in &nodes {
|
||||
let heading = node.to::<HeadingNode>().unwrap();
|
||||
let stable_id = heading.0.stable_id().unwrap();
|
||||
if !heading.outlined(StyleChain::default()) {
|
||||
|
@ -59,11 +59,6 @@ impl Show for QueryNode {
|
||||
let target = self.target();
|
||||
let (before, after) = vt.introspector.query_split(target, id);
|
||||
let func = self.format();
|
||||
let args = Args::new(func.span(), [encode(before), encode(after)]);
|
||||
Ok(func.call_detached(vt.world, args)?.display())
|
||||
Ok(func.call_vt(vt, [before.into(), after.into()])?.display())
|
||||
}
|
||||
}
|
||||
|
||||
fn encode(list: Vec<&Content>) -> Value {
|
||||
Value::Array(list.into_iter().cloned().map(Value::Content).collect())
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ impl Show for RefNode {
|
||||
return self.to_citation(styles).show(vt, styles);
|
||||
}
|
||||
|
||||
let &[node] = matches.as_slice() else {
|
||||
let [node] = matches.as_slice() else {
|
||||
bail!(self.span(), if matches.is_empty() {
|
||||
"label does not exist in the document"
|
||||
} else {
|
||||
@ -102,8 +102,7 @@ impl Show for RefNode {
|
||||
Smart::Custom(None) => Content::empty(),
|
||||
Smart::Custom(Some(Supplement::Content(content))) => content.clone(),
|
||||
Smart::Custom(Some(Supplement::Func(func))) => {
|
||||
let args = Args::new(func.span(), [node.clone().into()]);
|
||||
func.call_detached(vt.world, args)?.display()
|
||||
func.call_vt(vt, [node.clone().into()])?.display()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::fmt::{self, Debug, Formatter, Write};
|
||||
|
||||
use ecow::EcoVec;
|
||||
use typst::eval::Tracer;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -118,7 +119,7 @@ impl State {
|
||||
/// Display the state at the postition of the given stable id.
|
||||
fn resolve(
|
||||
&self,
|
||||
vt: &Vt,
|
||||
vt: &mut Vt,
|
||||
stop: Option<StableId>,
|
||||
func: Option<Func>,
|
||||
) -> SourceResult<Content> {
|
||||
@ -126,12 +127,17 @@ impl State {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
|
||||
let sequence = self.sequence(vt.world, vt.introspector)?;
|
||||
let sequence = self.sequence(
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
TrackedMut::reborrow_mut(&mut vt.provider),
|
||||
vt.introspector,
|
||||
)?;
|
||||
|
||||
Ok(match sequence.at(stop) {
|
||||
Some(value) => {
|
||||
if let Some(func) = func {
|
||||
let args = Args::new(func.span(), [value]);
|
||||
func.call_detached(vt.world, args)?.display()
|
||||
func.call_vt(vt, [value])?.display()
|
||||
} else {
|
||||
value.display()
|
||||
}
|
||||
@ -148,8 +154,11 @@ impl State {
|
||||
fn sequence(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
provider: TrackedMut<StabilityProvider>,
|
||||
introspector: Tracked<Introspector>,
|
||||
) -> SourceResult<StateSequence> {
|
||||
let mut vt = Vt { world, tracer, provider, introspector };
|
||||
let search = Selector::Node(
|
||||
NodeId::of::<StateNode>(),
|
||||
Some(dict! { "state" => self.clone() }),
|
||||
@ -165,10 +174,7 @@ impl State {
|
||||
if let StateAction::Update(update) = node.action() {
|
||||
match update {
|
||||
StateUpdate::Set(value) => state = value,
|
||||
StateUpdate::Func(func) => {
|
||||
let args = Args::new(func.span(), [state]);
|
||||
state = func.call_detached(world, args)?;
|
||||
}
|
||||
StateUpdate::Func(func) => state = func.call_vt(&mut vt, [state])?,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ impl Array {
|
||||
}
|
||||
for item in self.iter() {
|
||||
let args = Args::new(func.span(), [item.clone()]);
|
||||
if func.call(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
if func.call_vm(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
return Ok(Some(item.clone()));
|
||||
}
|
||||
}
|
||||
@ -158,7 +158,7 @@ impl Array {
|
||||
}
|
||||
for (i, item) in self.iter().enumerate() {
|
||||
let args = Args::new(func.span(), [item.clone()]);
|
||||
if func.call(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
if func.call_vm(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
return Ok(Some(i as i64));
|
||||
}
|
||||
}
|
||||
@ -175,7 +175,7 @@ impl Array {
|
||||
let mut kept = EcoVec::new();
|
||||
for item in self.iter() {
|
||||
let args = Args::new(func.span(), [item.clone()]);
|
||||
if func.call(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
if func.call_vm(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
kept.push(item.clone())
|
||||
}
|
||||
}
|
||||
@ -196,7 +196,7 @@ impl Array {
|
||||
args.push(func.span(), Value::Int(i as i64));
|
||||
}
|
||||
args.push(func.span(), item.clone());
|
||||
func.call(vm, args)
|
||||
func.call_vm(vm, args)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -209,7 +209,7 @@ impl Array {
|
||||
let mut acc = init;
|
||||
for item in self.iter() {
|
||||
let args = Args::new(func.span(), [acc, item.clone()]);
|
||||
acc = func.call(vm, args)?;
|
||||
acc = func.call_vm(vm, args)?;
|
||||
}
|
||||
Ok(acc)
|
||||
}
|
||||
@ -221,7 +221,7 @@ impl Array {
|
||||
}
|
||||
for item in self.iter() {
|
||||
let args = Args::new(func.span(), [item.clone()]);
|
||||
if func.call(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
if func.call_vm(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
@ -236,7 +236,7 @@ impl Array {
|
||||
}
|
||||
for item in self.iter() {
|
||||
let args = Args::new(func.span(), [item.clone()]);
|
||||
if !func.call(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
if !func.call_vm(vm, args)?.cast::<bool>().at(func.span())? {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use super::{
|
||||
Vm,
|
||||
};
|
||||
use crate::diag::{bail, SourceResult, StrResult};
|
||||
use crate::model::{NodeId, Selector, StyleMap};
|
||||
use crate::model::{NodeId, Selector, StyleMap, Vt};
|
||||
use crate::syntax::ast::{self, AstNode, Expr};
|
||||
use crate::syntax::{SourceId, Span, SyntaxNode};
|
||||
use crate::util::hash128;
|
||||
@ -82,7 +82,7 @@ impl Func {
|
||||
}
|
||||
|
||||
/// Call the function with the given arguments.
|
||||
pub fn call(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
|
||||
pub fn call_vm(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
|
||||
match &**self.0 {
|
||||
Repr::Native(native) => {
|
||||
let value = (native.func)(vm, &mut args)?;
|
||||
@ -111,23 +111,29 @@ impl Func {
|
||||
}
|
||||
Repr::With(wrapped, applied) => {
|
||||
args.items = applied.items.iter().cloned().chain(args.items).collect();
|
||||
return wrapped.call(vm, args);
|
||||
return wrapped.call_vm(vm, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call the function without an existing virtual machine.
|
||||
pub fn call_detached(
|
||||
/// Call the function with a Vt.
|
||||
pub fn call_vt(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
args: Args,
|
||||
vt: &mut Vt,
|
||||
args: impl IntoIterator<Item = Value>,
|
||||
) -> SourceResult<Value> {
|
||||
let route = Route::default();
|
||||
let id = SourceId::detached();
|
||||
let scopes = Scopes::new(None);
|
||||
let mut tracer = Tracer::default();
|
||||
let mut vm = Vm::new(world, route.track(), tracer.track_mut(), id, scopes, 0);
|
||||
self.call(&mut vm, args)
|
||||
let mut vm = Vm::new(
|
||||
vt.world,
|
||||
route.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
id,
|
||||
scopes,
|
||||
);
|
||||
let args = Args::new(self.span(), args);
|
||||
self.call_vm(&mut vm, args)
|
||||
}
|
||||
|
||||
/// Apply the given arguments to the function.
|
||||
@ -208,7 +214,7 @@ impl From<NodeId> for Func {
|
||||
/// A native Rust function.
|
||||
pub struct NativeFunc {
|
||||
/// The function's implementation.
|
||||
pub func: fn(&Vm, &mut Args) -> SourceResult<Value>,
|
||||
pub func: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
|
||||
/// Details about the function.
|
||||
pub info: Lazy<FuncInfo>,
|
||||
}
|
||||
@ -352,10 +358,11 @@ impl Closure {
|
||||
args.finish()?;
|
||||
|
||||
// Evaluate the body.
|
||||
let mut sub = Vm::new(world, route, tracer, closure.location, scopes, depth);
|
||||
let result = closure.body.eval(&mut sub);
|
||||
let mut sub = Vm::new(world, route, tracer, closure.location, scopes);
|
||||
sub.depth = depth;
|
||||
|
||||
// Handle control flow.
|
||||
let result = closure.body.eval(&mut sub);
|
||||
match sub.flow {
|
||||
Some(Flow::Return(_, Some(explicit))) => return Ok(explicit),
|
||||
Some(Flow::Return(_, None)) => {}
|
||||
|
@ -81,7 +81,7 @@ pub fn eval(
|
||||
// Evaluate the module.
|
||||
let route = unsafe { Route::insert(route, id) };
|
||||
let scopes = Scopes::new(Some(library));
|
||||
let mut vm = Vm::new(world, route.track(), tracer, id, scopes, 0);
|
||||
let mut vm = Vm::new(world, route.track(), tracer, id, scopes);
|
||||
let root = match source.root().cast::<ast::Markup>() {
|
||||
Some(markup) if vm.traced.is_some() => markup,
|
||||
_ => source.ast()?,
|
||||
@ -121,7 +121,7 @@ pub fn eval_code_str(
|
||||
let scopes = Scopes::new(Some(library));
|
||||
let route = Route::default();
|
||||
let mut tracer = Tracer::default();
|
||||
let mut vm = Vm::new(world, route.track(), tracer.track_mut(), id, scopes, 0);
|
||||
let mut vm = Vm::new(world, route.track(), tracer.track_mut(), id, scopes);
|
||||
let code = root.cast::<ast::Code>().unwrap();
|
||||
let result = code.eval(&mut vm);
|
||||
|
||||
@ -139,34 +139,33 @@ pub fn eval_code_str(
|
||||
/// virtual machine is created for each module evaluation and function call.
|
||||
pub struct Vm<'a> {
|
||||
/// The compilation environment.
|
||||
pub(super) world: Tracked<'a, dyn World>,
|
||||
world: Tracked<'a, dyn World>,
|
||||
/// The language items.
|
||||
pub(super) items: LangItems,
|
||||
items: LangItems,
|
||||
/// The route of source ids the VM took to reach its current location.
|
||||
pub(super) route: Tracked<'a, Route>,
|
||||
route: Tracked<'a, Route>,
|
||||
/// The tracer for inspection of the values an expression produces.
|
||||
pub(super) tracer: TrackedMut<'a, Tracer>,
|
||||
tracer: TrackedMut<'a, Tracer>,
|
||||
/// The current location.
|
||||
pub(super) location: SourceId,
|
||||
location: SourceId,
|
||||
/// A control flow event that is currently happening.
|
||||
pub(super) flow: Option<Flow>,
|
||||
flow: Option<Flow>,
|
||||
/// The stack of scopes.
|
||||
pub(super) scopes: Scopes<'a>,
|
||||
scopes: Scopes<'a>,
|
||||
/// The current call depth.
|
||||
pub(super) depth: usize,
|
||||
depth: usize,
|
||||
/// A span that is currently traced.
|
||||
pub(super) traced: Option<Span>,
|
||||
traced: Option<Span>,
|
||||
}
|
||||
|
||||
impl<'a> Vm<'a> {
|
||||
/// Create a new virtual machine.
|
||||
pub(super) fn new(
|
||||
fn new(
|
||||
world: Tracked<'a, dyn World>,
|
||||
route: Tracked<'a, Route>,
|
||||
tracer: TrackedMut<'a, Tracer>,
|
||||
location: SourceId,
|
||||
scopes: Scopes<'a>,
|
||||
depth: usize,
|
||||
) -> Self {
|
||||
let traced = tracer.span(location);
|
||||
Self {
|
||||
@ -177,7 +176,7 @@ impl<'a> Vm<'a> {
|
||||
location,
|
||||
flow: None,
|
||||
scopes,
|
||||
depth,
|
||||
depth: 0,
|
||||
traced,
|
||||
}
|
||||
}
|
||||
@ -358,7 +357,7 @@ fn eval_markup(
|
||||
}
|
||||
|
||||
let tail = eval_markup(vm, exprs)?;
|
||||
seq.push(tail.styled_with_recipe(vm.world, recipe)?)
|
||||
seq.push(tail.styled_with_recipe(vm, recipe)?)
|
||||
}
|
||||
expr => match expr.eval(vm)? {
|
||||
Value::Label(label) => {
|
||||
@ -791,7 +790,7 @@ fn eval_code(
|
||||
}
|
||||
|
||||
let tail = eval_code(vm, exprs)?.display();
|
||||
Value::Content(tail.styled_with_recipe(vm.world, recipe)?)
|
||||
Value::Content(tail.styled_with_recipe(vm, recipe)?)
|
||||
}
|
||||
_ => expr.eval(vm)?,
|
||||
};
|
||||
@ -1053,7 +1052,7 @@ impl Eval for ast::FuncCall {
|
||||
|
||||
let callee = callee.cast::<Func>().at(callee_span)?;
|
||||
let point = || Tracepoint::Call(callee.name().map(Into::into));
|
||||
callee.call(vm, args).trace(vm.world, point, span)
|
||||
callee.call_vm(vm, args).trace(vm.world, point, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,11 +36,23 @@ pub fn analyze_expr(world: &(dyn World + 'static), node: &LinkedNode) -> Vec<Val
|
||||
}
|
||||
}
|
||||
|
||||
let span = node.span();
|
||||
let source = world.source(span.source());
|
||||
let route = Route::default();
|
||||
let mut tracer = Tracer::new(Some(span));
|
||||
eval(world.track(), route.track(), tracer.track_mut(), source).ok();
|
||||
let mut tracer = Tracer::new(Some(node.span()));
|
||||
typst::eval::eval(
|
||||
world.track(),
|
||||
route.track(),
|
||||
tracer.track_mut(),
|
||||
world.main(),
|
||||
)
|
||||
.and_then(|module| {
|
||||
typst::model::typeset(
|
||||
world.track(),
|
||||
tracer.track_mut(),
|
||||
&module.content(),
|
||||
)
|
||||
})
|
||||
.ok();
|
||||
|
||||
tracer.finish()
|
||||
}
|
||||
|
||||
|
22
src/lib.rs
22
src/lib.rs
@ -63,14 +63,15 @@ use crate::syntax::{Source, SourceId};
|
||||
use crate::util::Buffer;
|
||||
|
||||
/// Compile a source file into a fully layouted document.
|
||||
pub fn compile(world: &(dyn World + 'static), source: &Source) -> SourceResult<Document> {
|
||||
pub fn compile(world: &(dyn World + 'static)) -> SourceResult<Document> {
|
||||
// Evaluate the source file into a module.
|
||||
let route = Route::default();
|
||||
let mut tracer = Tracer::default();
|
||||
let module = eval::eval(world.track(), route.track(), tracer.track_mut(), source)?;
|
||||
let module =
|
||||
eval::eval(world.track(), route.track(), tracer.track_mut(), world.main())?;
|
||||
|
||||
// Typeset the module's contents.
|
||||
model::typeset(world.track(), &module.content())
|
||||
model::typeset(world.track(), tracer.track_mut(), &module.content())
|
||||
}
|
||||
|
||||
/// The environment in which typesetting occurs.
|
||||
@ -86,6 +87,15 @@ pub trait World {
|
||||
/// The standard library.
|
||||
fn library(&self) -> &Prehashed<Library>;
|
||||
|
||||
/// The main source file.
|
||||
fn main(&self) -> &Source;
|
||||
|
||||
/// Try to resolve the unique id of a source file.
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId>;
|
||||
|
||||
/// Access a source file by id.
|
||||
fn source(&self, id: SourceId) -> &Source;
|
||||
|
||||
/// Metadata about all known fonts.
|
||||
fn book(&self) -> &Prehashed<FontBook>;
|
||||
|
||||
@ -94,10 +104,4 @@ pub trait World {
|
||||
|
||||
/// Try to access a file at a path.
|
||||
fn file(&self, path: &Path) -> FileResult<Buffer>;
|
||||
|
||||
/// Try to resolve the unique id of a source file.
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId>;
|
||||
|
||||
/// Access a source file by id.
|
||||
fn source(&self, id: SourceId) -> &Source;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use std::hash::{Hash, Hasher};
|
||||
use std::iter::{self, Sum};
|
||||
use std::ops::{Add, AddAssign, Deref};
|
||||
|
||||
use comemo::Tracked;
|
||||
use ecow::{eco_format, EcoString, EcoVec};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
@ -19,7 +18,6 @@ use crate::eval::{
|
||||
};
|
||||
use crate::syntax::Span;
|
||||
use crate::util::pretty_array_like;
|
||||
use crate::World;
|
||||
|
||||
/// Composable representation of styled content.
|
||||
#[derive(Clone, Hash)]
|
||||
@ -219,13 +217,9 @@ impl Content {
|
||||
}
|
||||
|
||||
/// Style this content with a recipe, eagerly applying it if possible.
|
||||
pub fn styled_with_recipe(
|
||||
self,
|
||||
world: Tracked<dyn World>,
|
||||
recipe: Recipe,
|
||||
) -> SourceResult<Self> {
|
||||
pub fn styled_with_recipe(self, vm: &mut Vm, recipe: Recipe) -> SourceResult<Self> {
|
||||
if recipe.selector.is_none() {
|
||||
recipe.apply(world, self)
|
||||
recipe.apply_vm(vm, self)
|
||||
} else {
|
||||
Ok(self.styled(Style::Recipe(recipe)))
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ pub fn realize(
|
||||
|
||||
/// Try to apply a recipe to the target.
|
||||
fn try_apply(
|
||||
vt: &Vt,
|
||||
vt: &mut Vt,
|
||||
target: &Content,
|
||||
recipe: &Recipe,
|
||||
guard: Guard,
|
||||
@ -108,7 +108,7 @@ fn try_apply(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
recipe.apply(vt.world, target.clone().guarded(guard)).map(Some)
|
||||
recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some)
|
||||
}
|
||||
|
||||
Some(Selector::Label(label)) => {
|
||||
@ -116,7 +116,7 @@ fn try_apply(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
recipe.apply(vt.world, target.clone().guarded(guard)).map(Some)
|
||||
recipe.apply_vt(vt, target.clone().guarded(guard)).map(Some)
|
||||
}
|
||||
|
||||
Some(Selector::Regex(regex)) => {
|
||||
@ -140,7 +140,7 @@ fn try_apply(
|
||||
}
|
||||
|
||||
let piece = make(m.as_str().into()).guarded(guard);
|
||||
let transformed = recipe.apply(vt.world, piece)?;
|
||||
let transformed = recipe.apply_vt(vt, piece)?;
|
||||
result.push(transformed);
|
||||
cursor = m.end();
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
use std::fmt::{self, Debug, Formatter, Write};
|
||||
use std::iter;
|
||||
|
||||
use comemo::Tracked;
|
||||
use ecow::{eco_format, EcoString, EcoVec};
|
||||
|
||||
use super::{Content, Label, Node, NodeId};
|
||||
use super::{Content, Label, Node, NodeId, Vt};
|
||||
use crate::diag::{SourceResult, Trace, Tracepoint};
|
||||
use crate::eval::{cast_from_value, Args, Cast, Dict, Func, Regex, Value};
|
||||
use crate::eval::{cast_from_value, Args, Cast, Dict, Func, Regex, Value, Vm};
|
||||
use crate::syntax::Span;
|
||||
use crate::util::pretty_array_like;
|
||||
use crate::World;
|
||||
|
||||
/// A map of style properties.
|
||||
#[derive(Default, Clone, Hash)]
|
||||
@ -197,20 +195,32 @@ impl Recipe {
|
||||
}
|
||||
|
||||
/// Apply the recipe to the given content.
|
||||
pub fn apply(
|
||||
&self,
|
||||
world: Tracked<dyn World>,
|
||||
content: Content,
|
||||
) -> SourceResult<Content> {
|
||||
pub fn apply_vm(&self, vm: &mut Vm, content: Content) -> SourceResult<Content> {
|
||||
match &self.transform {
|
||||
Transform::Content(content) => Ok(content.clone()),
|
||||
Transform::Func(func) => {
|
||||
let args = Args::new(self.span, [Value::Content(content.clone())]);
|
||||
let mut result = func.call_detached(world, args);
|
||||
let mut result = func.call_vm(vm, args);
|
||||
// For selector-less show rules, a tracepoint makes no sense.
|
||||
if self.selector.is_some() {
|
||||
let point = || Tracepoint::Show(content.id().name.into());
|
||||
result = result.trace(world, point, content.span());
|
||||
result = result.trace(vm.world(), point, content.span());
|
||||
}
|
||||
Ok(result?.display())
|
||||
}
|
||||
Transform::Style(styles) => Ok(content.styled_with_map(styles.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the recipe to the given content.
|
||||
pub fn apply_vt(&self, vt: &mut Vt, content: Content) -> SourceResult<Content> {
|
||||
match &self.transform {
|
||||
Transform::Content(content) => Ok(content.clone()),
|
||||
Transform::Func(func) => {
|
||||
let mut result = func.call_vt(vt, [Value::Content(content.clone())]);
|
||||
if self.selector.is_some() {
|
||||
let point = || Tracepoint::Show(content.id().name.into());
|
||||
result = result.trace(vt.world, point, content.span());
|
||||
}
|
||||
Ok(result?.display())
|
||||
}
|
||||
|
@ -6,13 +6,18 @@ use comemo::{Constraint, Track, Tracked, TrackedMut};
|
||||
use super::{Content, Selector, StyleChain};
|
||||
use crate::diag::SourceResult;
|
||||
use crate::doc::{Document, Element, Frame, Location, Meta};
|
||||
use crate::eval::Tracer;
|
||||
use crate::geom::{Point, Transform};
|
||||
use crate::util::NonZeroExt;
|
||||
use crate::World;
|
||||
|
||||
/// Typeset content into a fully layouted document.
|
||||
#[comemo::memoize]
|
||||
pub fn typeset(world: Tracked<dyn World>, content: &Content) -> SourceResult<Document> {
|
||||
pub fn typeset(
|
||||
world: Tracked<dyn World>,
|
||||
mut tracer: TrackedMut<Tracer>,
|
||||
content: &Content,
|
||||
) -> SourceResult<Document> {
|
||||
let library = world.library();
|
||||
let styles = StyleChain::new(&library.styles);
|
||||
|
||||
@ -27,6 +32,7 @@ pub fn typeset(world: Tracked<dyn World>, content: &Content) -> SourceResult<Doc
|
||||
let mut provider = StabilityProvider::new();
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
tracer: TrackedMut::reborrow_mut(&mut tracer),
|
||||
provider: provider.track_mut(),
|
||||
introspector: introspector.track_with(&constraint),
|
||||
};
|
||||
@ -52,6 +58,8 @@ pub fn typeset(world: Tracked<dyn World>, content: &Content) -> SourceResult<Doc
|
||||
pub struct Vt<'a> {
|
||||
/// The compilation environment.
|
||||
pub world: Tracked<'a, dyn World>,
|
||||
/// The tracer for inspection of the values an expression produces.
|
||||
pub tracer: TrackedMut<'a, Tracer>,
|
||||
/// Provides stable identities to nodes.
|
||||
pub provider: TrackedMut<'a, StabilityProvider>,
|
||||
/// Provides access to information about the document.
|
||||
@ -162,8 +170,8 @@ impl Introspector {
|
||||
}
|
||||
|
||||
/// Query for all metadata matches for the given selector.
|
||||
pub fn query(&self, selector: Selector) -> Vec<&Content> {
|
||||
self.all().filter(|node| selector.matches(node)).collect()
|
||||
pub fn query(&self, selector: Selector) -> Vec<Content> {
|
||||
self.all().filter(|node| selector.matches(node)).cloned().collect()
|
||||
}
|
||||
|
||||
/// Query for all metadata matches before the given id.
|
||||
@ -171,14 +179,15 @@ impl Introspector {
|
||||
&self,
|
||||
selector: Selector,
|
||||
id: StableId,
|
||||
) -> (Vec<&Content>, Vec<&Content>) {
|
||||
) -> (Vec<Content>, Vec<Content>) {
|
||||
let mut iter = self.all();
|
||||
let before = iter
|
||||
.by_ref()
|
||||
.take_while(|node| node.stable_id() != Some(id))
|
||||
.filter(|node| selector.matches(node))
|
||||
.cloned()
|
||||
.collect();
|
||||
let after = iter.filter(|node| selector.matches(node)).collect();
|
||||
let after = iter.filter(|node| selector.matches(node)).cloned().collect();
|
||||
(before, after)
|
||||
}
|
||||
|
||||
|
@ -80,17 +80,17 @@ fn bench_typeset(iai: &mut Iai) {
|
||||
)
|
||||
.unwrap();
|
||||
let content = module.content();
|
||||
iai.run(|| typst::model::typeset(world.track(), &content));
|
||||
iai.run(|| typst::model::typeset(world.track(), tracer.track_mut(), &content));
|
||||
}
|
||||
|
||||
fn bench_compile(iai: &mut Iai) {
|
||||
let world = BenchWorld::new();
|
||||
iai.run(|| typst::compile(&world, &world.source));
|
||||
iai.run(|| typst::compile(&world));
|
||||
}
|
||||
|
||||
fn bench_render(iai: &mut Iai) {
|
||||
let world = BenchWorld::new();
|
||||
let document = typst::compile(&world, &world.source).unwrap();
|
||||
let document = typst::compile(&world).unwrap();
|
||||
iai.run(|| typst::export::render(&document.pages[0], 1.0, Color::WHITE))
|
||||
}
|
||||
|
||||
@ -124,6 +124,18 @@ impl World for BenchWorld {
|
||||
&self.library
|
||||
}
|
||||
|
||||
fn main(&self) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
Err(FileError::NotFound(path.into()))
|
||||
}
|
||||
|
||||
fn source(&self, _: SourceId) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&self.book
|
||||
}
|
||||
@ -135,12 +147,4 @@ impl World for BenchWorld {
|
||||
fn file(&self, path: &Path) -> FileResult<Buffer> {
|
||||
Err(FileError::NotFound(path.into()))
|
||||
}
|
||||
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
Err(FileError::NotFound(path.into()))
|
||||
}
|
||||
|
||||
fn source(&self, _: SourceId) -> &Source {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
@ -207,6 +207,7 @@ struct TestWorld {
|
||||
fonts: Vec<Font>,
|
||||
paths: RefCell<HashMap<PathBuf, PathSlot>>,
|
||||
sources: FrozenVec<Box<Source>>,
|
||||
main: SourceId,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -236,6 +237,7 @@ impl TestWorld {
|
||||
fonts,
|
||||
paths: RefCell::default(),
|
||||
sources: FrozenVec::new(),
|
||||
main: SourceId::detached(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,19 +251,8 @@ impl World for TestWorld {
|
||||
&self.library
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&self.book
|
||||
}
|
||||
|
||||
fn font(&self, id: usize) -> Option<Font> {
|
||||
Some(self.fonts[id].clone())
|
||||
}
|
||||
|
||||
fn file(&self, path: &Path) -> FileResult<Buffer> {
|
||||
self.slot(path)
|
||||
.buffer
|
||||
.get_or_init(|| read(path).map(Buffer::from))
|
||||
.clone()
|
||||
fn main(&self) -> &Source {
|
||||
self.source(self.main)
|
||||
}
|
||||
|
||||
fn resolve(&self, path: &Path) -> FileResult<SourceId> {
|
||||
@ -278,20 +269,38 @@ impl World for TestWorld {
|
||||
fn source(&self, id: SourceId) -> &Source {
|
||||
&self.sources[id.into_u16() as usize]
|
||||
}
|
||||
|
||||
fn book(&self) -> &Prehashed<FontBook> {
|
||||
&self.book
|
||||
}
|
||||
|
||||
fn font(&self, id: usize) -> Option<Font> {
|
||||
Some(self.fonts[id].clone())
|
||||
}
|
||||
|
||||
fn file(&self, path: &Path) -> FileResult<Buffer> {
|
||||
self.slot(path)
|
||||
.buffer
|
||||
.get_or_init(|| read(path).map(Buffer::from))
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestWorld {
|
||||
fn set(&mut self, path: &Path, text: String) -> SourceId {
|
||||
let slot = self.slot(path);
|
||||
if let Some(&Ok(id)) = slot.source.get() {
|
||||
let id = if let Some(&Ok(id)) = slot.source.get() {
|
||||
drop(slot);
|
||||
self.sources.as_mut()[id.into_u16() as usize].replace(text);
|
||||
id
|
||||
} else {
|
||||
let id = self.insert(path, text);
|
||||
slot.source.set(Ok(id)).unwrap();
|
||||
drop(slot);
|
||||
id
|
||||
}
|
||||
};
|
||||
self.main = id;
|
||||
id
|
||||
}
|
||||
|
||||
fn slot(&self, path: &Path) -> RefMut<PathSlot> {
|
||||
@ -448,7 +457,7 @@ fn test_part(
|
||||
println!("Model:\n{:#?}\n", module.content());
|
||||
}
|
||||
|
||||
let (mut frames, errors) = match typst::compile(world, source) {
|
||||
let (mut frames, errors) = match typst::compile(world) {
|
||||
Ok(document) => (document.pages, vec![]),
|
||||
Err(errors) => (vec![], *errors),
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user