summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-10-18 00:02:38 +0200
committerLaurenz <laurmaedje@gmail.com>2022-10-18 00:04:12 +0200
commitc0e972b91a7bf8d22cd24a38fc92a9c6214c8a0c (patch)
tree19362eb993f15ef1b9bceeac821852bb6edfe955 /src
parente21822665591dc19766275da1e185215a6b945ef (diff)
Reduce dependencies from compiler on library
Diffstat (limited to 'src')
-rw-r--r--src/export/pdf/mod.rs3
-rw-r--r--src/frame.rs61
-rw-r--r--src/lib.rs26
-rw-r--r--src/library/graphics/mod.rs2
-rw-r--r--src/library/layout/mod.rs2
-rw-r--r--src/library/layout/page.rs2
-rw-r--r--src/library/layout/transform.rs (renamed from src/library/graphics/transform.rs)0
-rw-r--r--src/library/math/mod.rs2
-rw-r--r--src/library/mod.rs122
-rw-r--r--src/library/prelude.rs3
-rw-r--r--src/library/structure/list.rs2
-rw-r--r--src/library/text/lang.rs74
-rw-r--r--src/library/text/mod.rs16
-rw-r--r--src/model/collapse.rs61
-rw-r--r--src/model/content.rs32
-rw-r--r--src/model/eval.rs154
-rw-r--r--src/model/layout.rs41
-rw-r--r--src/model/recipe.rs2
-rw-r--r--src/model/styles.rs12
-rw-r--r--src/model/value.rs8
-rw-r--r--src/model/vm.rs7
21 files changed, 312 insertions, 320 deletions
diff --git a/src/export/pdf/mod.rs b/src/export/pdf/mod.rs
index a87f5c6b..2f6f255d 100644
--- a/src/export/pdf/mod.rs
+++ b/src/export/pdf/mod.rs
@@ -15,10 +15,9 @@ use pdf_writer::{Finish, Name, PdfWriter, Ref, TextStr};
use self::outline::{Heading, HeadingNode};
use self::page::Page;
use crate::font::Font;
-use crate::frame::Frame;
+use crate::frame::{Frame, Lang};
use crate::geom::{Dir, Em, Length};
use crate::image::Image;
-use crate::library::text::Lang;
/// Export a collection of frames into a PDF file.
///
diff --git a/src/frame.rs b/src/frame.rs
index c7827a9c..a367935c 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -6,10 +6,9 @@ use std::sync::Arc;
use crate::font::Font;
use crate::geom::{
- Align, Em, Length, Numeric, Paint, Point, Shape, Size, Spec, Transform,
+ Align, Dir, Em, Length, Numeric, Paint, Point, Shape, Size, Spec, Transform,
};
use crate::image::Image;
-use crate::library::text::Lang;
use crate::model::{Dict, Value};
use crate::util::EcoString;
@@ -397,6 +396,64 @@ pub struct Glyph {
pub c: char,
}
+/// A code for a natural language.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Lang([u8; 3], u8);
+
+impl Lang {
+ /// The code for the english language.
+ pub const ENGLISH: Self = Self(*b"en ", 2);
+
+ /// Construct a language from a two- or three-byte ISO 639-1/2/3 code.
+ pub fn from_str(iso: &str) -> Option<Self> {
+ let len = iso.len();
+ if matches!(len, 2 ..= 3) && iso.is_ascii() {
+ let mut bytes = [b' '; 3];
+ bytes[.. len].copy_from_slice(iso.as_bytes());
+ bytes.make_ascii_lowercase();
+ Some(Self(bytes, len as u8))
+ } else {
+ None
+ }
+ }
+
+ /// Return the language code as an all lowercase string slice.
+ pub fn as_str(&self) -> &str {
+ std::str::from_utf8(&self.0[.. usize::from(self.1)]).unwrap_or_default()
+ }
+
+ /// The default direction for the language.
+ pub fn dir(self) -> Dir {
+ match self.as_str() {
+ "ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
+ | "yi" => Dir::RTL,
+ _ => Dir::LTR,
+ }
+ }
+}
+
+/// A code for a region somewhere in the world.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Region([u8; 2]);
+
+impl Region {
+ /// Construct a region from its two-byte ISO 3166-1 alpha-2 code.
+ pub fn from_str(iso: &str) -> Option<Self> {
+ if iso.is_ascii() {
+ let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?;
+ bytes.make_ascii_uppercase();
+ Some(Self(bytes))
+ } else {
+ None
+ }
+ }
+
+ /// Return the region code as an all uppercase string slice.
+ pub fn as_str(&self) -> &str {
+ std::str::from_utf8(&self.0).unwrap_or_default()
+ }
+}
+
/// A link destination.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Destination {
diff --git a/src/lib.rs b/src/lib.rs
index 25f59aae..caed7592 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,6 +46,7 @@ pub mod image;
pub mod library;
pub mod syntax;
+use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
use comemo::{Prehashed, Track};
@@ -54,9 +55,9 @@ use crate::diag::{FileResult, SourceResult};
use crate::font::{Font, FontBook};
use crate::frame::Frame;
use crate::model::StyleMap;
-use crate::model::{Route, Scope};
+use crate::model::{Content, Route, Scope};
use crate::syntax::{Source, SourceId};
-use crate::util::Buffer;
+use crate::util::{Buffer, EcoString};
/// Typeset a source file into a collection of layouted frames.
///
@@ -105,6 +106,10 @@ pub struct Config {
///
/// Default: Typst's standard library.
pub std: Scope,
+ /// Defines which standard library items fulfill which syntactical roles.
+ ///
+ /// Default: Typst's standard library's role map.
+ pub roles: RoleMap,
/// The default properties for page size, font selection and so on.
///
/// Default: Empty style map.
@@ -115,8 +120,23 @@ impl Default for Config {
fn default() -> Self {
Self {
root: PathBuf::new(),
- std: library::new(),
+ std: library::scope(),
styles: StyleMap::new(),
+ roles: library::roles(),
}
}
}
+
+/// Definition of certain standard library items the language is aware of.
+#[derive(Debug, Clone, Hash)]
+pub struct RoleMap {
+ strong: fn(Content) -> Content,
+ emph: fn(Content) -> Content,
+ raw: fn(EcoString, Option<EcoString>, bool) -> Content,
+ link: fn(EcoString) -> Content,
+ ref_: fn(EcoString) -> Content,
+ heading: fn(NonZeroUsize, Content) -> Content,
+ list_item: fn(Content) -> Content,
+ enum_item: fn(Option<usize>, Content) -> Content,
+ desc_item: fn(Content, Content) -> Content,
+}
diff --git a/src/library/graphics/mod.rs b/src/library/graphics/mod.rs
index e9a6188f..34182121 100644
--- a/src/library/graphics/mod.rs
+++ b/src/library/graphics/mod.rs
@@ -4,10 +4,8 @@ mod hide;
mod image;
mod line;
mod shape;
-mod transform;
pub use self::image::*;
pub use hide::*;
pub use line::*;
pub use shape::*;
-pub use transform::*;
diff --git a/src/library/layout/mod.rs b/src/library/layout/mod.rs
index 588b15aa..02276f22 100644
--- a/src/library/layout/mod.rs
+++ b/src/library/layout/mod.rs
@@ -10,6 +10,7 @@ mod page;
mod place;
mod spacing;
mod stack;
+mod transform;
pub use align::*;
pub use columns::*;
@@ -21,3 +22,4 @@ pub use page::*;
pub use place::*;
pub use spacing::*;
pub use stack::*;
+pub use transform::*;
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index 9cbbcca5..7d13163d 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -188,7 +188,7 @@ impl Marginal {
Self::Content(content) => Some(content.clone()),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(page as i64)]);
- Some(func.call_detached(world, args)?.display())
+ Some(func.call_detached(world, args)?.display(world))
}
})
}
diff --git a/src/library/graphics/transform.rs b/src/library/layout/transform.rs
index b110f343..b110f343 100644
--- a/src/library/graphics/transform.rs
+++ b/src/library/layout/transform.rs
diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs
index 7b5fdf52..7d0fecb4 100644
--- a/src/library/math/mod.rs
+++ b/src/library/math/mod.rs
@@ -15,7 +15,7 @@ use rex::render::{Backend, Cursor, Renderer};
use crate::font::Font;
use crate::library::layout::BlockSpacing;
use crate::library::prelude::*;
-use crate::library::text::{variant, FontFamily, Lang, TextNode};
+use crate::library::text::{variant, FontFamily, TextNode};
/// A piece of a mathematical formula.
#[derive(Debug, Clone, Hash)]
diff --git a/src/library/mod.rs b/src/library/mod.rs
index b42ec071..cf9acdac 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -14,7 +14,7 @@ pub mod utility;
use prelude::*;
/// Construct a scope containing all standard library definitions.
-pub fn new() -> Scope {
+pub fn scope() -> Scope {
let mut std = Scope::new();
// Text.
@@ -58,6 +58,9 @@ pub fn new() -> Scope {
std.def_node::<layout::ColumnsNode>("columns");
std.def_node::<layout::ColbreakNode>("colbreak");
std.def_node::<layout::PlaceNode>("place");
+ std.def_node::<layout::MoveNode>("move");
+ std.def_node::<layout::ScaleNode>("scale");
+ std.def_node::<layout::RotateNode>("rotate");
// Graphics.
std.def_node::<graphics::ImageNode>("image");
@@ -66,9 +69,6 @@ pub fn new() -> Scope {
std.def_node::<graphics::SquareNode>("square");
std.def_node::<graphics::EllipseNode>("ellipse");
std.def_node::<graphics::CircleNode>("circle");
- std.def_node::<graphics::MoveNode>("move");
- std.def_node::<graphics::ScaleNode>("scale");
- std.def_node::<graphics::RotateNode>("rotate");
std.def_node::<graphics::HideNode>("hide");
// Math.
@@ -142,3 +142,117 @@ pub fn new() -> Scope {
std
}
+
+/// Construct the standard role map.
+pub fn roles() -> RoleMap {
+ RoleMap {
+ strong: |body| Content::show(text::StrongNode(body)),
+ emph: |body| Content::show(text::EmphNode(body)),
+ raw: |text, lang, block| {
+ let node = Content::show(text::RawNode { text, block });
+ match lang {
+ Some(_) => node.styled(text::RawNode::LANG, lang),
+ None => node,
+ }
+ },
+ link: |url| Content::show(text::LinkNode::from_url(url)),
+ ref_: |target| Content::show(structure::RefNode(target)),
+ heading: |level, body| Content::show(structure::HeadingNode { level, body }),
+ list_item: |body| Content::Item(structure::ListItem::List(Box::new(body))),
+ enum_item: |number, body| {
+ Content::Item(structure::ListItem::Enum(number, Box::new(body)))
+ },
+ desc_item: |term, body| {
+ Content::Item(structure::ListItem::Desc(Box::new(structure::DescItem {
+ term,
+ body,
+ })))
+ },
+ }
+}
+
+/// Additional methods on content.
+pub trait ContentExt {
+ /// Make this content strong.
+ fn strong(self) -> Self;
+
+ /// Make this content emphasized.
+ fn emph(self) -> Self;
+
+ /// Underline this content.
+ fn underlined(self) -> Self;
+}
+
+impl ContentExt for Content {
+ fn strong(self) -> Self {
+ Self::show(text::StrongNode(self))
+ }
+
+ fn emph(self) -> Self {
+ Self::show(text::EmphNode(self))
+ }
+
+ fn underlined(self) -> Self {
+ Self::show(text::DecoNode::<{ text::UNDERLINE }>(self))
+ }
+}
+
+/// Additional methods for the style chain.
+pub trait StyleMapExt {
+ /// Set a font family composed of a preferred family and existing families
+ /// from a style chain.
+ fn set_family(&mut self, preferred: text::FontFamily, existing: StyleChain);
+}
+
+impl StyleMapExt for StyleMap {
+ fn set_family(&mut self, preferred: text::FontFamily, existing: StyleChain) {
+ self.set(
+ text::TextNode::FAMILY,
+ std::iter::once(preferred)
+ .chain(existing.get(text::TextNode::FAMILY).iter().cloned())
+ .collect(),
+ );
+ }
+}
+
+/// Additional methods for layout nodes.
+pub trait LayoutNodeExt {
+ /// Set alignments for this node.
+ fn aligned(self, aligns: Spec<Option<RawAlign>>) -> Self;
+
+ /// Pad this node at the sides.
+ fn padded(self, padding: Sides<Relative<RawLength>>) -> Self;
+
+ /// Transform this node's contents without affecting layout.
+ fn moved(self, delta: Spec<Relative<RawLength>>) -> Self;
+}
+
+impl LayoutNodeExt for LayoutNode {
+ fn aligned(self, aligns: Spec<Option<RawAlign>>) -> Self {
+ if aligns.any(Option::is_some) {
+ layout::AlignNode { aligns, child: self }.pack()
+ } else {
+ self
+ }
+ }
+
+ fn padded(self, padding: Sides<Relative<RawLength>>) -> Self {
+ if !padding.left.is_zero()
+ || !padding.top.is_zero()
+ || !padding.right.is_zero()
+ || !padding.bottom.is_zero()
+ {
+ layout::PadNode { padding, child: self }.pack()
+ } else {
+ self
+ }
+ }
+
+ fn moved(self, delta: Spec<Relative<RawLength>>) -> Self {
+ if delta.any(|r| !r.is_zero()) {
+ layout::MoveNode { delta, child: self }.pack()
+ } else {
+ self
+ }
+ }
+}
diff --git a/src/library/prelude.rs b/src/library/prelude.rs
index 7a4284f1..1d98e2a9 100644
--- a/src/library/prelude.rs
+++ b/src/library/prelude.rs
@@ -9,6 +9,7 @@ pub use std::sync::Arc;
pub use comemo::Tracked;
pub use typst_macros::node;
+pub use super::{ContentExt, LayoutNodeExt, StyleMapExt};
pub use crate::diag::{
with_alternative, At, FileError, FileResult, SourceError, SourceResult, StrResult,
};
@@ -24,4 +25,4 @@ pub use crate::model::{
};
pub use crate::syntax::{Span, Spanned};
pub use crate::util::EcoString;
-pub use crate::World;
+pub use crate::{RoleMap, World};
diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs
index 7a43e5db..9d78238d 100644
--- a/src/library/structure/list.rs
+++ b/src/library/structure/list.rs
@@ -328,7 +328,7 @@ impl Label {
Self::Content(content) => content.clone(),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(number as i64)]);
- func.call_detached(world, args)?.display()
+ func.call_detached(world, args)?.display(world)
}
})
}
diff --git a/src/library/text/lang.rs b/src/library/text/lang.rs
deleted file mode 100644
index f2193f05..00000000
--- a/src/library/text/lang.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use crate::geom::Dir;
-use crate::model::Value;
-
-/// A code for a natural language.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-pub struct Lang([u8; 3], u8);
-
-impl Lang {
- /// The code for the english language.
- pub const ENGLISH: Self = Self(*b"en ", 2);
-
- /// Construct a language from a two- or three-byte ISO 639-1/2/3 code.
- pub fn from_str(iso: &str) -> Option<Self> {
- let len = iso.len();
- if matches!(len, 2 ..= 3) && iso.is_ascii() {
- let mut bytes = [b' '; 3];
- bytes[.. len].copy_from_slice(iso.as_bytes());
- bytes.make_ascii_lowercase();
- Some(Self(bytes, len as u8))
- } else {
- None
- }
- }
-
- /// Return the language code as an all lowercase string slice.
- pub fn as_str(&self) -> &str {
- std::str::from_utf8(&self.0[.. usize::from(self.1)]).unwrap_or_default()
- }
-
- /// The default direction for the language.
- pub fn dir(self) -> Dir {
- match self.as_str() {
- "ar" | "dv" | "fa" | "he" | "ks" | "pa" | "ps" | "sd" | "ug" | "ur"
- | "yi" => Dir::RTL,
- _ => Dir::LTR,
- }
- }
-}
-
-castable! {
- Lang,
- Expected: "string",
- Value::Str(string) => Self::from_str(&string)
- .ok_or("expected two or three letter language code (ISO 639-1/2/3)")?,
-}
-
-/// A code for a region somewhere in the world.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-pub struct Region([u8; 2]);
-
-impl Region {
- /// Construct a region from its two-byte ISO 3166-1 alpha-2 code.
- pub fn from_str(iso: &str) -> Option<Self> {
- if iso.is_ascii() {
- let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?;
- bytes.make_ascii_uppercase();
- Some(Self(bytes))
- } else {
- None
- }
- }
-
- /// Return the region code as an all uppercase string slice.
- pub fn as_str(&self) -> &str {
- std::str::from_utf8(&self.0).unwrap_or_default()
- }
-}
-
-castable! {
- Region,
- Expected: "string",
- Value::Str(string) => Self::from_str(&string)
- .ok_or("expected two letter region code (ISO 3166-1 alpha-2)")?,
-}
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index c9bf2e57..299357de 100644
--- a/src/library/text/mod.rs
+++ b/src/library/text/mod.rs
@@ -1,7 +1,6 @@
//! Text handling and paragraph layout.
mod deco;
-mod lang;
mod link;
mod par;
mod quotes;
@@ -11,7 +10,6 @@ mod shaping;
mod shift;
pub use deco::*;
-pub use lang::*;
pub use link::*;
pub use par::*;
pub use quotes::*;
@@ -290,6 +288,20 @@ castable! {
}),
}
+castable! {
+ Lang,
+ Expected: "string",
+ Value::Str(string) => Self::from_str(&string)
+ .ok_or("expected two or three letter language code (ISO 639-1/2/3)")?,
+}
+
+castable! {
+ Region,
+ Expected: "string",
+ Value::Str(string) => Self::from_str(&string)
+ .ok_or("expected two letter region code (ISO 3166-1 alpha-2)")?,
+}
+
/// The direction of text and inline objects in their line.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct HorizontalDir(pub Dir);
diff --git a/src/model/collapse.rs b/src/model/collapse.rs
index 258f577e..5a0d6531 100644
--- a/src/model/collapse.rs
+++ b/src/model/collapse.rs
@@ -114,64 +114,3 @@ impl<'a, T> Default for CollapsingBuilder<'a, T> {
Self::new()
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::library::layout::FlowChild;
- use crate::library::prelude::*;
-
- #[track_caller]
- fn test<T>(builder: CollapsingBuilder<T>, expected: &[T])
- where
- T: Debug + PartialEq,
- {
- let result = builder.finish().0;
- let items: Vec<_> = result.items().collect();
- let expected: Vec<_> = expected.iter().collect();
- assert_eq!(items, expected);
- }
-
- fn node() -> FlowChild {
- FlowChild::Node(Content::Text("Hi".into()).pack())
- }
-
- fn abs(pt: f64) -> FlowChild {
- FlowChild::Spacing(Length::pt(pt).into())
- }
-
- #[test]
- fn test_collapsing_weak() {
- let mut builder = CollapsingBuilder::new();
- let styles = StyleChain::default();
- builder.weak(FlowChild::Colbreak, styles, 0);
- builder.supportive(node(), styles);
- builder.weak(abs(10.0), styles, 0);
- builder.ignorant(FlowChild::Colbreak, styles);
- builder.weak(abs(20.0), styles, 0);
- builder.supportive(node(), styles);
- builder.weak(abs(10.0), styles, 0);
- builder.weak(abs(20.0), styles, 1);
- builder.supportive(node(), styles);
- test(builder, &[
- node(),
- FlowChild::Colbreak,
- abs(20.0),
- node(),
- abs(10.0),
- node(),
- ]);
- }
-
- #[test]
- fn test_collapsing_destructive() {
- let mut builder = CollapsingBuilder::new();
- let styles = StyleChain::default();
- builder.supportive(node(), styles);
- builder.weak(abs(10.0), styles, 0);
- builder.destructive(FlowChild::Colbreak, styles);
- builder.weak(abs(20.0), styles, 0);
- builder.supportive(node(), styles);
- test(builder, &[node(), FlowChild::Colbreak, node()]);
- }
-}
diff --git a/src/model/content.rs b/src/model/content.rs
index 5f0536c3..428865f3 100644
--- a/src/model/content.rs
+++ b/src/model/content.rs
@@ -1,23 +1,24 @@
-use std::fmt::Debug;
+use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::iter::Sum;
use std::mem;
use std::ops::{Add, AddAssign};
+use std::sync::Arc;
use comemo::Tracked;
use typed_arena::Arena;
use super::{
- Barrier, CollapsingBuilder, Interruption, Key, Layout, LayoutNode, Property, Show,
- ShowNode, StyleEntry, StyleMap, StyleVecBuilder, Target,
+ Barrier, CollapsingBuilder, Dict, Interruption, Key, Layout, LayoutNode, Property,
+ Regions, Selector, Show, ShowNode, StyleChain, StyleEntry, StyleMap, StyleVecBuilder,
+ Target,
};
-use crate::diag::StrResult;
+use crate::diag::{SourceResult, StrResult};
+use crate::frame::{Frame, Role};
+use crate::geom::{Length, Numeric};
use crate::library::layout::{FlowChild, FlowNode, PageNode, PlaceNode, Spacing};
-use crate::library::prelude::*;
use crate::library::structure::{DocNode, ListItem, ListNode, DESC, ENUM, LIST};
-use crate::library::text::{
- DecoNode, EmphNode, ParChild, ParNode, StrongNode, UNDERLINE,
-};
+use crate::library::text::{ParChild, ParNode};
use crate::util::EcoString;
use crate::World;
@@ -173,21 +174,6 @@ impl Content {
self.clone().styled_with_entry(StyleEntry::Unguard(sel))
}
- /// Make this content strong.
- pub fn strong(self) -> Self {
- Self::show(StrongNode(self))
- }
-
- /// Make this content emphasized.
- pub fn emph(self) -> Self {
- Self::show(EmphNode(self))
- }
-
- /// Underline this content.
- pub fn underlined(self) -> Self {
- Self::show(DecoNode::<UNDERLINE>(self))
- }
-
/// Add weak vertical spacing above and below the node.
pub fn spaced(self, above: Option<Length>, below: Option<Length>) -> Self {
if above.is_none() && below.is_none() {
diff --git a/src/model/eval.rs b/src/model/eval.rs
index aa5f0378..6658e244 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -141,7 +141,7 @@ fn eval_markup(
ast::MarkupNode::Expr(ast::Expr::Wrap(wrap)) => {
let tail = eval_markup(vm, nodes)?;
vm.scopes.top.define(wrap.binding().take(), tail);
- wrap.body().eval(vm)?.display()
+ wrap.body().eval(vm)?.display(vm.world)
}
_ => node.eval(vm)?,
@@ -181,7 +181,7 @@ impl Eval for ast::MarkupNode {
Self::Desc(v) => v.eval(vm),
Self::Label(v) => v.eval(vm),
Self::Ref(v) => v.eval(vm),
- Self::Expr(v) => v.eval(vm).map(Value::display),
+ Self::Expr(v) => v.eval(vm).map(|value| value.display(vm.world)),
}
}
}
@@ -242,9 +242,7 @@ impl Eval for ast::Strong {
type Output = Content;
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::show(library::text::StrongNode(
- self.body().eval(vm)?,
- )))
+ Ok((vm.roles().strong)(self.body().eval(vm)?))
}
}
@@ -252,34 +250,80 @@ impl Eval for ast::Emph {
type Output = Content;
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::show(library::text::EmphNode(
- self.body().eval(vm)?,
- )))
+ Ok((vm.roles().emph)(self.body().eval(vm)?))
+ }
+}
+
+impl Eval for ast::Raw {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ let text = self.text().clone();
+ let lang = self.lang().cloned();
+ let block = self.block();
+ Ok((vm.roles().raw)(text, lang, block))
}
}
impl Eval for ast::Link {
type Output = Content;
- fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::show(library::text::LinkNode::from_url(
- self.url().clone(),
- )))
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ Ok((vm.roles().link)(self.url().clone()))
}
}
-impl Eval for ast::Raw {
+impl Eval for ast::Label {
type Output = Content;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
- let content = Content::show(library::text::RawNode {
- text: self.text().clone(),
- block: self.block(),
- });
- Ok(match self.lang() {
- Some(_) => content.styled(library::text::RawNode::LANG, self.lang().cloned()),
- None => content,
- })
+ Ok(Content::Empty)
+ }
+}
+
+impl Eval for ast::Ref {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ Ok((vm.roles().ref_)(self.get().clone()))
+ }
+}
+
+impl Eval for ast::Heading {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ let level = self.level();
+ let body = self.body().eval(vm)?;
+ Ok((vm.roles().heading)(level, body))
+ }
+}
+
+impl Eval for ast::ListItem {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ Ok((vm.roles().list_item)(self.body().eval(vm)?))
+ }
+}
+
+impl Eval for ast::EnumItem {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ let number = self.number();
+ let body = self.body().eval(vm)?;
+ Ok((vm.roles().enum_item)(number, body))
+ }
+}
+
+impl Eval for ast::DescItem {
+ type Output = Content;
+
+ fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
+ let term = self.term().eval(vm)?;
+ let body = self.body().eval(vm)?;
+ Ok((vm.roles().desc_item)(term, body))
}
}
@@ -318,7 +362,7 @@ impl Eval for ast::MathNode {
),
node.span(),
),
- Self::Expr(expr) => match expr.eval(vm)?.display() {
+ Self::Expr(expr) => match expr.eval(vm)?.display(vm.world) {
Content::Text(text) => library::math::MathNode::Atom(text),
_ => bail!(expr.span(), "expected text"),
},
@@ -369,68 +413,6 @@ impl Eval for ast::Align {
}
}
-impl Eval for ast::Heading {
- type Output = Content;
-
- fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::show(library::structure::HeadingNode {
- body: self.body().eval(vm)?,
- level: self.level(),
- }))
- }
-}
-
-impl Eval for ast::ListItem {
- type Output = Content;
-
- fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- let body = Box::new(self.body().eval(vm)?);
- Ok(Content::Item(library::structure::ListItem::List(body)))
- }
-}
-
-impl Eval for ast::EnumItem {
- type Output = Content;
-
- fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- let number = self.number();
- let body = Box::new(self.body().eval(vm)?);
- Ok(Content::Item(library::structure::ListItem::Enum(
- number, body,
- )))
- }
-}
-
-impl Eval for ast::DescItem {
- type Output = Content;
-
- fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
- let term = self.term().eval(vm)?;
- let body = self.body().eval(vm)?;
- Ok(Content::Item(library::structure::ListItem::Desc(Box::new(
- library::structure::DescItem { term, body },
- ))))
- }
-}
-
-impl Eval for ast::Label {
- type Output = Content;
-
- fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::Empty)
- }
-}
-
-impl Eval for ast::Ref {
- type Output = Content;
-
- fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
- Ok(Content::show(library::structure::RefNode(
- self.get().clone(),
- )))
- }
-}
-
impl Eval for ast::Expr {
type Output = Value;
@@ -530,7 +512,7 @@ fn eval_code(
break;
}
- let tail = eval_code(vm, exprs)?.display();
+ let tail = eval_code(vm, exprs)?.display(vm.world);
Value::Content(tail.styled_with_map(styles))
}
ast::Expr::Show(show) => {
@@ -540,7 +522,7 @@ fn eval_code(
break;
}
- let tail = eval_code(vm, exprs)?.display();
+ let tail = eval_code(vm, exprs)?.display(vm.world);
Value::Content(tail.styled_with_entry(entry))
}
ast::Expr::Wrap(wrap) => {
diff --git a/src/model/layout.rs b/src/model/layout.rs
index 09888ba5..5248157b 100644
--- a/src/model/layout.rs
+++ b/src/model/layout.rs
@@ -8,19 +8,13 @@ use std::sync::Arc;
use comemo::{Prehashed, Tracked};
use super::{Barrier, NodeId, Resolve, StyleChain, StyleEntry};
-use super::{Builder, Content, RawAlign, RawLength, Scratch};
+use super::{Builder, Content, RawLength, Scratch};
use crate::diag::SourceResult;
use crate::frame::{Element, Frame};
-use crate::geom::{
- Align, Geometry, Length, Paint, Point, Relative, Sides, Size, Spec, Stroke,
-};
-use crate::library::graphics::MoveNode;
-use crate::library::layout::{AlignNode, PadNode};
+use crate::geom::{Align, Geometry, Length, Paint, Point, Relative, Size, Spec, Stroke};
use crate::World;
/// Layout content into a collection of pages.
-///
-/// Relayouts until all pinned locations are converged.
#[comemo::memoize]
pub fn layout(world: Tracked<dyn World>, content: &Content) -> SourceResult<Vec<Frame>> {
let styles = StyleChain::with_root(&world.config().styles);
@@ -196,37 +190,6 @@ impl LayoutNode {
pub fn stroked(self, stroke: Stroke) -> Self {
StrokeNode { stroke, child: self }.pack()
}
-
- /// Set alignments for this node.
- pub fn aligned(self, aligns: Spec<Option<RawAlign>>) -> Self {
- if aligns.any(Option::is_some) {
- AlignNode { aligns, child: self }.pack()
- } else {
- self
- }
- }
-
- /// Pad this node at the sides.
- pub fn padded(self, padding: Sides<Relative<RawLength>>) -> Self {
- if !padding.left.is_zero()
- || !padding.top.is_zero()
- || !padding.right.is_zero()
- || !padding.bottom.is_zero()
- {
- PadNode { padding, child: self }.pack()
- } else {
- self
- }
- }
-
- /// Transform this node's contents without affecting layout.
- pub fn moved(self, delta: Spec<Relative<RawLength>>) -> Self {
- if delta.any(|r| !r.is_zero()) {
- MoveNode { delta, child: self }.pack()
- } else {
- self
- }
- }
}
impl Layout for LayoutNode {
diff --git a/src/model/recipe.rs b/src/model/recipe.rs
index 05ef07a6..46dad6d1 100644
--- a/src/model/recipe.rs
+++ b/src/model/recipe.rs
@@ -89,7 +89,7 @@ impl Recipe {
Args::new(self.func.span, [arg()])
};
- Ok(self.func.v.call_detached(world, args)?.display())
+ Ok(self.func.v.call_detached(world, args)?.display(world))
}
/// What kind of structure the property interrupts.
diff --git a/src/model/styles.rs b/src/model/styles.rs
index 76199ca1..d21f3a9f 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -8,7 +8,6 @@ use comemo::Tracked;
use super::{Barrier, Content, Key, Property, Recipe, Selector, Show, Target};
use crate::diag::SourceResult;
use crate::frame::Role;
-use crate::library::text::{FontFamily, TextNode};
use crate::util::ReadableTypeId;
use crate::World;
@@ -55,17 +54,6 @@ impl StyleMap {
}
}
- /// Set a font family composed of a preferred family and existing families
- /// from a style chain.
- pub fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) {
- self.set(
- TextNode::FAMILY,
- iter::once(preferred)
- .chain(existing.get(TextNode::FAMILY).iter().cloned())
- .collect(),
- );
- }
-
/// Whether the map contains a style property for the given key.
pub fn contains<'a, K: Key<'a>>(&self, _: K) -> bool {
self.0
diff --git a/src/model/value.rs b/src/model/value.rs
index 4075ce9c..e0d5edf3 100644
--- a/src/model/value.rs
+++ b/src/model/value.rs
@@ -4,13 +4,14 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
+use comemo::Tracked;
use siphasher::sip128::{Hasher128, SipHasher};
use super::{ops, Args, Array, Cast, Content, Dict, Func, Layout, RawLength, Str};
use crate::diag::StrResult;
use crate::geom::{Angle, Color, Em, Fraction, Length, Ratio, Relative, RgbaColor};
-use crate::library::text::RawNode;
use crate::util::EcoString;
+use crate::World;
/// A computational value.
#[derive(Clone)]
@@ -113,7 +114,7 @@ impl Value {
}
/// Return the display representation of the value.
- pub fn display(self) -> Content {
+ pub fn display(self, world: Tracked<dyn World>) -> Content {
match self {
Value::None => Content::new(),
Value::Int(v) => Content::Text(format_eco!("{}", v)),
@@ -123,8 +124,7 @@ impl Value {
// For values which can't be shown "naturally", we return the raw
// representation with typst code syntax highlighting.
- v => Content::show(RawNode { text: v.repr().into(), block: false })
- .styled(RawNode::LANG, Some("typc".into())),
+ v => (world.config().roles.raw)(v.repr().into(), Some("typc".into()), false),
}
}
}
diff --git a/src/model/vm.rs b/src/model/vm.rs
index a1b1ba81..829693bc 100644
--- a/src/model/vm.rs
+++ b/src/model/vm.rs
@@ -6,7 +6,7 @@ use super::{Route, Scopes, Value};
use crate::diag::{SourceError, StrResult};
use crate::syntax::{SourceId, Span};
use crate::util::PathExt;
-use crate::World;
+use crate::{RoleMap, World};
/// A virtual machine.
pub struct Vm<'a> {
@@ -54,6 +54,11 @@ impl<'a> Vm<'a> {
return Err("cannot access file system from here".into());
}
+
+ /// The role map.
+ pub fn roles(&self) -> &RoleMap {
+ &self.world.config().roles
+ }
}
/// A control flow event that occurred during evaluation.