summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-23 15:58:59 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-23 16:07:54 +0100
commit5ae81971f299688b05d77af208d7bb44ffce5e2d (patch)
tree35b914f9bdf5565d4602c4bdda08ccbc30977df4
parentb2a3d3f235fb5a23322435b854460f52db772114 (diff)
Introduce `Library`
-rw-r--r--cli/src/main.rs28
-rw-r--r--library/src/lib.rs15
-rw-r--r--src/lib.rs33
-rw-r--r--src/model/eval.rs7
-rw-r--r--src/model/library.rs (renamed from src/model/items.rs)63
-rw-r--r--src/model/mod.rs4
-rw-r--r--src/model/vm.rs4
-rw-r--r--tests/src/benches.rs27
-rw-r--r--tests/src/tests.rs46
9 files changed, 115 insertions, 112 deletions
diff --git a/cli/src/main.rs b/cli/src/main.rs
index f7fd5903..3db491bb 100644
--- a/cli/src/main.rs
+++ b/cli/src/main.rs
@@ -19,9 +19,10 @@ use siphasher::sip128::{Hasher128, SipHasher};
use termcolor::{ColorChoice, StandardStream, WriteColor};
use typst::diag::{FileError, FileResult, SourceError, StrResult};
use typst::font::{Font, FontBook, FontInfo, FontVariant};
+use typst::model::Library;
use typst::syntax::{Source, SourceId};
use typst::util::{Buffer, PathExt};
-use typst::{Config, World};
+use typst::World;
use walkdir::WalkDir;
type CodespanResult<T> = Result<T, CodespanError>;
@@ -178,15 +179,8 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
PathBuf::new()
};
- let config = Config {
- root,
- scope: typst_library::scope(),
- styles: typst_library::styles(),
- items: typst_library::items(),
- };
-
// Create the world that serves sources, fonts and files.
- let mut world = SystemWorld::new(config);
+ let mut world = SystemWorld::new(root);
// Typeset.
typeset_once(&mut world, &command)?;
@@ -371,7 +365,8 @@ fn fonts(command: FontsCommand) -> StrResult<()> {
/// A world that provides access to the operating system.
struct SystemWorld {
- config: Prehashed<Config>,
+ root: PathBuf,
+ library: Prehashed<Library>,
book: Prehashed<FontBook>,
fonts: Vec<FontSlot>,
hashes: RefCell<HashMap<PathBuf, FileResult<PathHash>>>,
@@ -394,12 +389,13 @@ struct PathSlot {
}
impl SystemWorld {
- fn new(config: Config) -> Self {
+ fn new(root: PathBuf) -> Self {
let mut searcher = FontSearcher::new();
searcher.search_system();
Self {
- config: Prehashed::new(config),
+ root,
+ library: Prehashed::new(typst_library::new()),
book: Prehashed::new(searcher.book),
fonts: searcher.fonts,
hashes: RefCell::default(),
@@ -410,8 +406,12 @@ impl SystemWorld {
}
impl World for SystemWorld {
- fn config(&self) -> &Prehashed<Config> {
- &self.config
+ fn root(&self) -> &Path {
+ &self.root
+ }
+
+ fn library(&self) -> &Prehashed<Library> {
+ &self.library
}
fn book(&self) -> &Prehashed<FontBook> {
diff --git a/library/src/lib.rs b/library/src/lib.rs
index e5e60968..7fcad183 100644
--- a/library/src/lib.rs
+++ b/library/src/lib.rs
@@ -10,12 +10,17 @@ pub mod structure;
pub mod text;
use typst::geom::{Align, Color, Dir, GenAlign};
-use typst::model::{LangItems, Node, NodeId, Scope, StyleMap};
+use typst::model::{LangItems, Library, Node, NodeId, Scope, StyleMap};
use self::layout::LayoutRoot;
-/// Construct the standard library scope.
-pub fn scope() -> Scope {
+/// Construct the standard library.
+pub fn new() -> Library {
+ Library { scope: scope(), styles: styles(), items: items() }
+}
+
+/// Construct the standard scope.
+fn scope() -> Scope {
let mut std = Scope::new();
// Text.
@@ -147,12 +152,12 @@ pub fn scope() -> Scope {
}
/// Construct the standard style map.
-pub fn styles() -> StyleMap {
+fn styles() -> StyleMap {
StyleMap::new()
}
/// Construct the standard lang item mapping.
-pub fn items() -> LangItems {
+fn items() -> LangItems {
LangItems {
layout: |content, world, styles| content.layout_root(world, styles),
em: |styles| styles.get(text::TextNode::SIZE),
diff --git a/src/lib.rs b/src/lib.rs
index 319c13ab..75200144 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -42,14 +42,14 @@ pub mod frame;
pub mod image;
pub mod syntax;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use comemo::{Prehashed, Track};
use crate::diag::{FileResult, SourceResult};
use crate::font::{Font, FontBook};
use crate::frame::Frame;
-use crate::model::{LangItems, Route, Scope, StyleChain, StyleMap};
+use crate::model::{Library, Route, StyleChain};
use crate::syntax::{Source, SourceId};
use crate::util::Buffer;
@@ -62,24 +62,24 @@ pub fn typeset(
world: &(dyn World + 'static),
source: &Source,
) -> SourceResult<Vec<Frame>> {
- // Set up the language items.
- let config = world.config();
- crate::model::set_lang_items(config.items);
-
// Evaluate the source file into a module.
let route = Route::default();
let module = model::eval(world.track(), route.track(), source)?;
// Layout the module's contents.
- let styles = StyleChain::with_root(&config.styles);
- item!(layout)(&module.content, world.track(), styles)
+ let library = world.library();
+ let styles = StyleChain::with_root(&library.styles);
+ (library.items.layout)(&module.content, world.track(), styles)
}
/// The environment in which typesetting occurs.
#[comemo::track]
pub trait World {
- /// Access the global configuration.
- fn config(&self) -> &Prehashed<Config>;
+ /// The compilation root.
+ fn root(&self) -> &Path;
+
+ /// The standard library.
+ fn library(&self) -> &Prehashed<Library>;
/// Metadata about all known fonts.
fn book(&self) -> &Prehashed<FontBook>;
@@ -96,16 +96,3 @@ pub trait World {
/// Access a source file by id.
fn source(&self, id: SourceId) -> &Source;
}
-
-/// The global configuration for typesetting.
-#[derive(Debug, Clone, Hash)]
-pub struct Config {
- /// The compilation root, relative to which absolute paths are.
- pub root: PathBuf,
- /// The scope containing definitions that are available everywhere.
- pub scope: Scope,
- /// The default properties for page size, font selection and so on.
- pub styles: StyleMap,
- /// Defines which standard library items fulfill which syntactical roles.
- pub items: LangItems,
-}
diff --git a/src/model/eval.rs b/src/model/eval.rs
index 7f2cea63..fb1bd121 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -35,10 +35,13 @@ pub fn eval(
panic!("Tried to cyclicly evaluate {}", path);
}
+ // Hook up the lang items.
+ let library = world.library();
+ super::set_lang_items(library.items.clone());
+
// Evaluate the module.
let route = unsafe { Route::insert(route, id) };
- let std = &world.config().scope;
- let scopes = Scopes::new(Some(std));
+ let scopes = Scopes::new(Some(&library.scope));
let mut vm = Vm::new(world, route.track(), id, scopes);
let result = source.ast()?.eval(&mut vm);
diff --git a/src/model/items.rs b/src/model/library.rs
index 50ea8b60..8433e514 100644
--- a/src/model/items.rs
+++ b/src/model/library.rs
@@ -5,41 +5,26 @@ use std::num::NonZeroUsize;
use comemo::Tracked;
use once_cell::sync::OnceCell;
-use super::{Content, NodeId, StyleChain};
+use super::{Content, NodeId, Scope, StyleChain, StyleMap};
use crate::diag::SourceResult;
use crate::frame::Frame;
use crate::geom::{Abs, Dir};
use crate::util::{hash128, EcoString};
use crate::World;
-/// Global storage for lang items.
-#[doc(hidden)]
-pub static LANG_ITEMS: OnceCell<LangItems> = OnceCell::new();
-
-/// Set the lang items. This is a hack :(
-///
-/// Passing the lang items everywhere they are needed (especially the text node
-/// related things) is very painful. By storing them globally, in theory, we
-/// break incremental, but only when different sets of lang items are used in
-/// the same program. For this reason, if this function is called multiple
-/// times, the items must be the same.
-pub(crate) fn set_lang_items(items: LangItems) {
- if LANG_ITEMS.set(items).is_err() {
- let first = hash128(LANG_ITEMS.get().unwrap());
- let second = hash128(&items);
- assert_eq!(first, second, "set differing lang items");
- }
-}
-
-/// Access a lang item.
-macro_rules! item {
- ($name:ident) => {
- $crate::model::LANG_ITEMS.get().unwrap().$name
- };
+/// A Typst standard library.
+#[derive(Debug, Clone, Hash)]
+pub struct Library {
+ /// The scope containing definitions that are available everywhere.
+ pub scope: Scope,
+ /// The default properties for page size, font selection and so on.
+ pub styles: StyleMap,
+ /// Defines which standard library items fulfill which syntactical roles.
+ pub items: LangItems,
}
/// Definition of certain standard library items the language is aware of.
-#[derive(Copy, Clone)]
+#[derive(Clone)]
pub struct LangItems {
/// The root layout function.
pub layout: fn(
@@ -128,3 +113,29 @@ impl Hash for LangItems {
self.math_align.hash(state);
}
}
+
+/// Global storage for lang items.
+#[doc(hidden)]
+pub static LANG_ITEMS: OnceCell<LangItems> = OnceCell::new();
+
+/// Set the lang items. This is a hack :(
+///
+/// Passing the lang items everywhere they are needed (especially the text node
+/// related things) is very painful. By storing them globally, in theory, we
+/// break incremental, but only when different sets of lang items are used in
+/// the same program. For this reason, if this function is called multiple
+/// times, the items must be the same.
+pub(crate) fn set_lang_items(items: LangItems) {
+ if let Err(items) = LANG_ITEMS.set(items) {
+ let first = hash128(LANG_ITEMS.get().unwrap());
+ let second = hash128(&items);
+ assert_eq!(first, second, "set differing lang items");
+ }
+}
+
+/// Access a lang item.
+macro_rules! item {
+ ($name:ident) => {
+ $crate::model::LANG_ITEMS.get().unwrap().$name
+ };
+}
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 0f946a40..93e33d5c 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -1,7 +1,7 @@
//! Document and computation model.
#[macro_use]
-mod items;
+mod library;
#[macro_use]
mod cast;
#[macro_use]
@@ -34,7 +34,7 @@ pub use self::content::*;
pub use self::dict::*;
pub use self::eval::*;
pub use self::func::*;
-pub use self::items::*;
+pub use self::library::*;
pub use self::scope::*;
pub use self::str::*;
pub use self::styles::*;
diff --git a/src/model/vm.rs b/src/model/vm.rs
index 28885f29..d13be29c 100644
--- a/src/model/vm.rs
+++ b/src/model/vm.rs
@@ -38,7 +38,7 @@ impl<'a> Vm<'a> {
location,
scopes,
flow: None,
- items: world.config().items,
+ items: world.library().items.clone(),
}
}
@@ -47,7 +47,7 @@ impl<'a> Vm<'a> {
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {
if !self.location.is_detached() {
if let Some(path) = path.strip_prefix('/') {
- return Ok(self.world.config().root.join(path).normalize());
+ return Ok(self.world.root().join(path).normalize());
}
if let Some(dir) = self.world.source(self.location).path().parent() {
diff --git a/tests/src/benches.rs b/tests/src/benches.rs
index 29117a90..1e5550c5 100644
--- a/tests/src/benches.rs
+++ b/tests/src/benches.rs
@@ -1,12 +1,13 @@
-use std::path::{Path, PathBuf};
+use std::path::Path;
use comemo::{Prehashed, Track, Tracked};
use iai::{black_box, main, Iai};
use typst::diag::{FileError, FileResult};
use typst::font::{Font, FontBook};
+use typst::model::Library;
use typst::syntax::{Source, SourceId, TokenMode, Tokens};
use typst::util::Buffer;
-use typst::{Config, World};
+use typst::World;
use unscanny::Scanner;
const TEXT: &str = include_str!("../typ/benches/bench.typ");
@@ -90,7 +91,7 @@ fn bench_render(iai: &mut Iai) {
}
struct BenchWorld {
- config: Prehashed<Config>,
+ library: Prehashed<Library>,
book: Prehashed<FontBook>,
font: Font,
source: Source,
@@ -98,22 +99,14 @@ struct BenchWorld {
impl BenchWorld {
fn new() -> Self {
- let config = Config {
- root: PathBuf::new(),
- scope: typst_library::scope(),
- styles: typst_library::styles(),
- items: typst_library::items(),
- };
-
let font = Font::new(FONT.into(), 0).unwrap();
let book = FontBook::from_fonts([&font]);
- let source = Source::detached(TEXT);
Self {
- config: Prehashed::new(config),
+ library: Prehashed::new(typst_library::new()),
book: Prehashed::new(book),
font,
- source,
+ source: Source::detached(TEXT),
}
}
@@ -123,8 +116,12 @@ impl BenchWorld {
}
impl World for BenchWorld {
- fn config(&self) -> &Prehashed<Config> {
- &self.config
+ fn root(&self) -> &Path {
+ Path::new("")
+ }
+
+ fn library(&self) -> &Prehashed<Library> {
+ &self.library
}
fn book(&self) -> &Prehashed<FontBook> {
diff --git a/tests/src/tests.rs b/tests/src/tests.rs
index 89c83857..2c0a1e71 100644
--- a/tests/src/tests.rs
+++ b/tests/src/tests.rs
@@ -15,10 +15,10 @@ use typst::diag::{bail, FileError, FileResult};
use typst::font::{Font, FontBook};
use typst::frame::{Element, Frame};
use typst::geom::{Abs, RgbaColor, Sides};
-use typst::model::{Smart, Value};
+use typst::model::{Library, Smart, Value};
use typst::syntax::{Source, SourceId, SyntaxNode};
use typst::util::{Buffer, PathExt};
-use typst::{Config, World};
+use typst::World;
use typst_library::layout::PageNode;
use typst_library::text::{TextNode, TextSize};
use unscanny::Scanner;
@@ -144,21 +144,22 @@ impl Args {
}
}
-fn config() -> Config {
+fn library() -> Library {
+ let mut lib = typst_library::new();
+
// Set page width to 120pt with 10pt margins, so that the inner page is
// exactly 100pt wide. Page height is unbounded and font size is 10pt so
// that it multiplies to nice round numbers.
- let mut styles = typst_library::styles();
- styles.set(PageNode::WIDTH, Smart::Custom(Abs::pt(120.0).into()));
- styles.set(PageNode::HEIGHT, Smart::Auto);
- styles.set(PageNode::MARGIN, Sides::splat(Some(Smart::Custom(Abs::pt(10.0).into()))));
- styles.set(TextNode::SIZE, TextSize(Abs::pt(10.0).into()));
+ lib.styles.set(PageNode::WIDTH, Smart::Custom(Abs::pt(120.0).into()));
+ lib.styles.set(PageNode::HEIGHT, Smart::Auto);
+ lib.styles
+ .set(PageNode::MARGIN, Sides::splat(Some(Smart::Custom(Abs::pt(10.0).into()))));
+ lib.styles.set(TextNode::SIZE, TextSize(Abs::pt(10.0).into()));
// Hook up helpers into the global scope.
- let mut scope = typst_library::scope();
- scope.define("conifer", RgbaColor::new(0x9f, 0xEB, 0x52, 0xFF));
- scope.define("forest", RgbaColor::new(0x43, 0xA1, 0x27, 0xFF));
- scope.def_fn("test", move |_, args| {
+ lib.scope.define("conifer", RgbaColor::new(0x9f, 0xEB, 0x52, 0xFF));
+ lib.scope.define("forest", RgbaColor::new(0x43, 0xA1, 0x27, 0xFF));
+ lib.scope.def_fn("test", move |_, args| {
let lhs = args.expect::<Value>("left-hand side")?;
let rhs = args.expect::<Value>("right-hand side")?;
if lhs != rhs {
@@ -166,7 +167,7 @@ fn config() -> Config {
}
Ok(Value::None)
});
- scope.def_fn("print", move |_, args| {
+ lib.scope.def_fn("print", move |_, args| {
print!("> ");
for (i, value) in args.all::<Value>()?.into_iter().enumerate() {
if i > 0 {
@@ -178,18 +179,13 @@ fn config() -> Config {
Ok(Value::None)
});
- Config {
- root: PathBuf::new(),
- scope,
- styles,
- items: typst_library::items(),
- }
+ lib
}
/// A world that provides access to the tests environment.
struct TestWorld {
print: PrintConfig,
- config: Prehashed<Config>,
+ library: Prehashed<Library>,
book: Prehashed<FontBook>,
fonts: Vec<Font>,
paths: RefCell<HashMap<PathBuf, PathSlot>>,
@@ -219,7 +215,7 @@ impl TestWorld {
Self {
print,
- config: Prehashed::new(config()),
+ library: Prehashed::new(library()),
book: Prehashed::new(FontBook::from_fonts(&fonts)),
fonts,
paths: RefCell::default(),
@@ -229,8 +225,12 @@ impl TestWorld {
}
impl World for TestWorld {
- fn config(&self) -> &Prehashed<Config> {
- &self.config
+ fn root(&self) -> &Path {
+ Path::new("")
+ }
+
+ fn library(&self) -> &Prehashed<Library> {
+ &self.library
}
fn book(&self) -> &Prehashed<FontBook> {