Reorganize library and tests

This commit is contained in:
Laurenz 2022-11-29 13:37:25 +01:00
parent 836692e73c
commit 0efe669278
234 changed files with 506 additions and 487 deletions

View File

@ -395,7 +395,7 @@ impl SystemWorld {
Self { Self {
root, root,
library: Prehashed::new(typst_library::new()), library: Prehashed::new(typst_library::build()),
book: Prehashed::new(searcher.book), book: Prehashed::new(searcher.book),
fonts: searcher.fonts, fonts: searcher.fonts,
hashes: RefCell::default(), hashes: RefCell::default(),

View File

@ -1,7 +1,7 @@
use crate::base::NumberingPattern; use crate::compute::NumberingPattern;
use crate::layout::{BlockNode, GridNode, HNode, Spacing, TrackSizing}; use crate::layout::{BlockNode, GridNode, HNode, ParNode, Spacing, TrackSizing};
use crate::prelude::*; use crate::prelude::*;
use crate::text::{ParNode, SpaceNode, TextNode}; use crate::text::{SpaceNode, TextNode};
/// An unordered (bulleted) or ordered (numbered) list. /// An unordered (bulleted) or ordered (numbered) list.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

View File

@ -0,0 +1,9 @@
//! Common document elements.
mod heading;
mod list;
mod table;
pub use self::heading::*;
pub use self::list::*;
pub use self::table::*;

View File

@ -106,12 +106,6 @@ pub fn str(_: &Vm, args: &mut Args) -> SourceResult<Value> {
})) }))
} }
/// Create a blind text string.
pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let words: usize = args.expect("number of words")?;
Ok(Value::Str(lipsum::lipsum(words).into()))
}
/// Create a label from a string. /// Create a label from a string.
pub fn label(_: &Vm, args: &mut Args) -> SourceResult<Value> { pub fn label(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(Value::Label(Label(args.expect("string")?))) Ok(Value::Label(Label(args.expect("string")?)))

View File

@ -1,20 +1,9 @@
//! Foundational functions. use crate::prelude::*;
mod calc;
mod create;
mod data;
mod numbering;
pub use self::calc::*;
pub use self::create::*;
pub use self::data::*;
pub use self::numbering::*;
use comemo::Track; use comemo::Track;
use typst::model::{self, Route, Vm};
use typst::syntax::Source;
use crate::prelude::*; use typst::model;
use typst::syntax::Source;
/// The name of a value's type. /// The name of a value's type.
pub fn type_(_: &Vm, args: &mut Args) -> SourceResult<Value> { pub fn type_(_: &Vm, args: &mut Args) -> SourceResult<Value> {
@ -39,7 +28,7 @@ pub fn assert(_: &Vm, args: &mut Args) -> SourceResult<Value> {
pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> { pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?; let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
let source = Source::synthesized(text, span); let source = Source::synthesized(text, span);
let route = Route::default(); let route = model::Route::default();
let module = model::eval(vm.world(), route.track(), &source)?; let module = model::eval(vm.world(), route.track(), &source)?;
Ok(Value::Content(module.content)) Ok(Value::Content(module.content))
} }

View File

@ -0,0 +1,13 @@
//! Computational functions.
mod calc;
mod create;
mod data;
mod foundations;
mod utility;
pub use self::calc::*;
pub use self::create::*;
pub use self::data::*;
pub use self::foundations::*;
pub use self::utility::*;

View File

@ -4,6 +4,12 @@ use unscanny::Scanner;
use crate::prelude::*; use crate::prelude::*;
/// Create a blind text string.
pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let words: usize = args.expect("number of words")?;
Ok(Value::Str(lipsum::lipsum(words).into()))
}
/// Apply a numbering pattern to a number. /// Apply a numbering pattern to a number.
pub fn numbering(_: &Vm, args: &mut Args) -> SourceResult<Value> { pub fn numbering(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let number = args.expect::<usize>("number")?; let number = args.expect::<usize>("number")?;
@ -11,7 +17,15 @@ pub fn numbering(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(Value::Str(pattern.apply(number).into())) Ok(Value::Str(pattern.apply(number).into()))
} }
/// A numbering pattern for lists or headings. /// How to turn a number into text.
///
/// A pattern consists of a prefix, followed by one of `1`, `a`, `A`, `i`, `I`
/// or `*`, and then a suffix.
///
/// Examples of valid patterns:
/// - `1)`
/// - `a.`
/// - `(I)`
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct NumberingPattern { pub struct NumberingPattern {
prefix: EcoString, prefix: EcoString,
@ -60,7 +74,7 @@ castable! {
/// Different kinds of numberings. /// Different kinds of numberings.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum NumberingKind { enum NumberingKind {
Arabic, Arabic,
Letter, Letter,
Roman, Roman,

View File

@ -1,5 +1,5 @@
use super::{HorizontalAlign, ParNode};
use crate::prelude::*; use crate::prelude::*;
use crate::text::{HorizontalAlign, ParNode};
/// Align content along the layouting axes. /// Align content along the layouting axes.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

View File

@ -1,8 +1,7 @@
use typst::model::Style; use typst::model::Style;
use super::{AlignNode, BlockNode, ColbreakNode, PlaceNode, Spacing, VNode}; use super::{AlignNode, BlockNode, ColbreakNode, ParNode, PlaceNode, Spacing, VNode};
use crate::prelude::*; use crate::prelude::*;
use crate::text::ParNode;
/// Arrange spacing, paragraphs and block-level nodes into a flow. /// Arrange spacing, paragraphs and block-level nodes into a flow.
/// ///

View File

@ -5,9 +5,12 @@ mod columns;
mod container; mod container;
mod flow; mod flow;
mod grid; mod grid;
mod hide;
mod pad; mod pad;
mod page; mod page;
mod par;
mod place; mod place;
mod repeat;
mod spacing; mod spacing;
mod stack; mod stack;
mod transform; mod transform;
@ -17,9 +20,12 @@ pub use self::columns::*;
pub use self::container::*; pub use self::container::*;
pub use self::flow::*; pub use self::flow::*;
pub use self::grid::*; pub use self::grid::*;
pub use self::hide::*;
pub use self::pad::*; pub use self::pad::*;
pub use self::page::*; pub use self::page::*;
pub use self::par::*;
pub use self::place::*; pub use self::place::*;
pub use self::repeat::*;
pub use self::spacing::*; pub use self::spacing::*;
pub use self::stack::*; pub use self::stack::*;
pub use self::transform::*; pub use self::transform::*;
@ -36,14 +42,11 @@ use typst::model::{
}; };
use typst::World; use typst::World;
use crate::basics::{DescNode, EnumNode, ListItem, ListNode, DESC, ENUM, LIST};
use crate::meta::DocumentNode;
use crate::prelude::*; use crate::prelude::*;
use crate::shared::BehavedBuilder; use crate::shared::BehavedBuilder;
use crate::structure::{ use crate::text::{LinebreakNode, SmartQuoteNode, SpaceNode, TextNode};
DescNode, DocumentNode, EnumNode, ListItem, ListNode, DESC, ENUM, LIST,
};
use crate::text::{
LinebreakNode, ParNode, ParbreakNode, SmartQuoteNode, SpaceNode, TextNode,
};
/// Root-level layout. /// Root-level layout.
#[capability] #[capability]

View File

@ -4,12 +4,11 @@ use xi_unicode::LineBreakIterator;
use typst::model::Key; use typst::model::Key;
use super::{ use super::{HNode, RepeatNode, Spacing};
shape, Lang, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode,
TextNode,
};
use crate::layout::{HNode, Spacing};
use crate::prelude::*; use crate::prelude::*;
use crate::text::{
shape, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode, TextNode,
};
/// Arrange text, spacing and inline-level nodes into a paragraph. /// Arrange text, spacing and inline-level nodes into a paragraph.
#[derive(Hash)] #[derive(Hash)]
@ -129,30 +128,6 @@ impl ParbreakNode {
impl Unlabellable for ParbreakNode {} impl Unlabellable for ParbreakNode {}
/// Repeats content to fill a line.
#[derive(Debug, Hash)]
pub struct RepeatNode(pub Content);
#[node(Layout, Inline)]
impl RepeatNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
}
impl Layout for RepeatNode {
fn layout(
&self,
world: Tracked<dyn World>,
styles: StyleChain,
regions: &Regions,
) -> SourceResult<Fragment> {
self.0.layout(world, styles, regions)
}
}
impl Inline for RepeatNode {}
/// Range of a substring of text. /// Range of a substring of text.
type Range = std::ops::Range<usize>; type Range = std::ops::Range<usize>;

View File

@ -0,0 +1,25 @@
use crate::prelude::*;
/// Repeats content to fill a line.
#[derive(Debug, Hash)]
pub struct RepeatNode(pub Content);
#[node(Layout, Inline)]
impl RepeatNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
}
impl Layout for RepeatNode {
fn layout(
&self,
world: Tracked<dyn World>,
styles: StyleChain,
regions: &Regions,
) -> SourceResult<Fragment> {
self.0.layout(world, styles, regions)
}
}
impl Inline for RepeatNode {}

View File

@ -1,8 +1,7 @@
use typst::model::StyledNode; use typst::model::StyledNode;
use super::{AlignNode, Spacing}; use super::{AlignNode, ParNode, Spacing};
use crate::prelude::*; use crate::prelude::*;
use crate::text::ParNode;
/// Arrange content and spacing along an axis. /// Arrange content and spacing along an axis.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

View File

@ -1,13 +1,14 @@
//! Typst's standard library. //! Typst's standard library.
pub mod base; pub mod basics;
pub mod graphics; pub mod compute;
pub mod layout; pub mod layout;
pub mod math; pub mod math;
pub mod meta;
pub mod prelude; pub mod prelude;
pub mod shared; pub mod shared;
pub mod structure;
pub mod text; pub mod text;
pub mod visualize;
use typst::geom::{Align, Color, Dir, GenAlign}; use typst::geom::{Align, Color, Dir, GenAlign};
use typst::model::{LangItems, Library, Node, NodeId, Scope, StyleMap}; use typst::model::{LangItems, Library, Node, NodeId, Scope, StyleMap};
@ -15,7 +16,7 @@ use typst::model::{LangItems, Library, Node, NodeId, Scope, StyleMap};
use self::layout::LayoutRoot; use self::layout::LayoutRoot;
/// Construct the standard library. /// Construct the standard library.
pub fn new() -> Library { pub fn build() -> Library {
Library { scope: scope(), styles: styles(), items: items() } Library { scope: scope(), styles: styles(), items: items() }
} }
@ -23,97 +24,102 @@ pub fn new() -> Library {
fn scope() -> Scope { fn scope() -> Scope {
let mut std = Scope::new(); let mut std = Scope::new();
// Basics.
std.def_node::<basics::HeadingNode>("heading");
std.def_node::<basics::ListNode>("list");
std.def_node::<basics::EnumNode>("enum");
std.def_node::<basics::DescNode>("desc");
std.def_node::<basics::TableNode>("table");
// Text. // Text.
std.def_node::<text::TextNode>("text");
std.def_node::<text::LinebreakNode>("linebreak"); std.def_node::<text::LinebreakNode>("linebreak");
std.def_node::<text::SmartQuoteNode>("smartquote"); std.def_node::<text::SmartQuoteNode>("smartquote");
std.def_node::<text::TextNode>("text");
std.def_node::<text::ParNode>("par");
std.def_node::<text::ParbreakNode>("parbreak");
std.def_node::<text::StrongNode>("strong"); std.def_node::<text::StrongNode>("strong");
std.def_node::<text::EmphNode>("emph"); std.def_node::<text::EmphNode>("emph");
std.def_node::<text::RawNode>("raw");
std.def_node::<text::UnderlineNode>("underline");
std.def_node::<text::StrikethroughNode>("strike");
std.def_node::<text::OverlineNode>("overline");
std.def_node::<text::SuperNode>("super");
std.def_node::<text::SubNode>("sub");
std.def_node::<text::LinkNode>("link");
std.def_node::<text::RepeatNode>("repeat");
std.def_fn("lower", text::lower); std.def_fn("lower", text::lower);
std.def_fn("upper", text::upper); std.def_fn("upper", text::upper);
std.def_fn("smallcaps", text::smallcaps); std.def_fn("smallcaps", text::smallcaps);
std.def_node::<text::SubNode>("sub");
// Structure. std.def_node::<text::SuperNode>("super");
std.def_node::<structure::DocumentNode>("document"); std.def_node::<text::UnderlineNode>("underline");
std.def_node::<structure::RefNode>("ref"); std.def_node::<text::StrikeNode>("strike");
std.def_node::<structure::HeadingNode>("heading"); std.def_node::<text::OverlineNode>("overline");
std.def_node::<structure::ListNode>("list"); std.def_node::<text::RawNode>("raw");
std.def_node::<structure::EnumNode>("enum");
std.def_node::<structure::DescNode>("desc");
std.def_node::<structure::TableNode>("table");
// Layout.
std.def_node::<layout::PageNode>("page");
std.def_node::<layout::PagebreakNode>("pagebreak");
std.def_node::<layout::HNode>("h");
std.def_node::<layout::VNode>("v");
std.def_node::<layout::BoxNode>("box");
std.def_node::<layout::BlockNode>("block");
std.def_node::<layout::AlignNode>("align");
std.def_node::<layout::PadNode>("pad");
std.def_node::<layout::StackNode>("stack");
std.def_node::<layout::GridNode>("grid");
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");
std.def_node::<graphics::LineNode>("line");
std.def_node::<graphics::RectNode>("rect");
std.def_node::<graphics::SquareNode>("square");
std.def_node::<graphics::EllipseNode>("ellipse");
std.def_node::<graphics::CircleNode>("circle");
std.def_node::<graphics::HideNode>("hide");
// Math. // Math.
std.def_node::<math::MathNode>("math"); std.def_node::<math::MathNode>("math");
std.def_node::<math::AtomNode>("atom");
std.def_node::<math::FracNode>("frac");
std.define("sum", ""); std.define("sum", "");
std.define("in", ""); std.define("in", "");
std.define("arrow", ""); std.define("arrow", "");
std.define("NN", ""); std.define("NN", "");
std.define("RR", ""); std.define("RR", "");
// Base. // Layout.
std.def_fn("type", base::type_); std.def_node::<layout::PageNode>("page");
std.def_fn("repr", base::repr); std.def_node::<layout::PagebreakNode>("pagebreak");
std.def_fn("assert", base::assert); std.def_node::<layout::FlowNode>("flow");
std.def_fn("eval", base::eval); std.def_node::<layout::VNode>("v");
std.def_fn("int", base::int); std.def_node::<layout::ParNode>("par");
std.def_fn("float", base::float); std.def_node::<layout::ParbreakNode>("parbreak");
std.def_fn("luma", base::luma); std.def_node::<layout::HNode>("h");
std.def_fn("rgb", base::rgb); std.def_node::<layout::BoxNode>("box");
std.def_fn("cmyk", base::cmyk); std.def_node::<layout::BlockNode>("block");
std.def_fn("str", base::str); std.def_node::<layout::StackNode>("stack");
std.def_fn("lorem", base::lorem); std.def_node::<layout::GridNode>("grid");
std.def_fn("label", base::label); std.def_node::<layout::ColumnsNode>("columns");
std.def_fn("regex", base::regex); std.def_node::<layout::ColbreakNode>("colbreak");
std.def_fn("range", base::range); std.def_node::<layout::PlaceNode>("place");
std.def_fn("numbering", base::numbering); std.def_node::<layout::AlignNode>("align");
std.def_fn("abs", base::abs); std.def_node::<layout::PadNode>("pad");
std.def_fn("min", base::min); std.def_node::<layout::RepeatNode>("repeat");
std.def_fn("max", base::max); std.def_node::<layout::MoveNode>("move");
std.def_fn("even", base::even); std.def_node::<layout::ScaleNode>("scale");
std.def_fn("odd", base::odd); std.def_node::<layout::RotateNode>("rotate");
std.def_fn("mod", base::mod_); std.def_node::<layout::HideNode>("hide");
std.def_fn("csv", base::csv);
std.def_fn("json", base::json);
std.def_fn("xml", base::xml);
// Predefined colors. // Visualize.
std.def_node::<visualize::ImageNode>("image");
std.def_node::<visualize::LineNode>("line");
std.def_node::<visualize::RectNode>("rect");
std.def_node::<visualize::SquareNode>("square");
std.def_node::<visualize::EllipseNode>("ellipse");
std.def_node::<visualize::CircleNode>("circle");
// Meta.
std.def_node::<meta::DocumentNode>("document");
std.def_node::<meta::RefNode>("ref");
std.def_node::<meta::LinkNode>("link");
// Compute.
std.def_fn("type", compute::type_);
std.def_fn("repr", compute::repr);
std.def_fn("assert", compute::assert);
std.def_fn("eval", compute::eval);
std.def_fn("int", compute::int);
std.def_fn("float", compute::float);
std.def_fn("luma", compute::luma);
std.def_fn("rgb", compute::rgb);
std.def_fn("cmyk", compute::cmyk);
std.def_fn("str", compute::str);
std.def_fn("label", compute::label);
std.def_fn("regex", compute::regex);
std.def_fn("range", compute::range);
std.def_fn("abs", compute::abs);
std.def_fn("min", compute::min);
std.def_fn("max", compute::max);
std.def_fn("even", compute::even);
std.def_fn("odd", compute::odd);
std.def_fn("mod", compute::mod_);
std.def_fn("csv", compute::csv);
std.def_fn("json", compute::json);
std.def_fn("xml", compute::xml);
std.def_fn("lorem", compute::lorem);
std.def_fn("numbering", compute::numbering);
// Colors.
std.define("black", Color::BLACK); std.define("black", Color::BLACK);
std.define("gray", Color::GRAY); std.define("gray", Color::GRAY);
std.define("silver", Color::SILVER); std.define("silver", Color::SILVER);
@ -167,7 +173,7 @@ fn items() -> LangItems {
text_id: NodeId::of::<text::TextNode>(), text_id: NodeId::of::<text::TextNode>(),
text_str: |content| Some(&content.to::<text::TextNode>()?.0), text_str: |content| Some(&content.to::<text::TextNode>()?.0),
smart_quote: |double| text::SmartQuoteNode { double }.pack(), smart_quote: |double| text::SmartQuoteNode { double }.pack(),
parbreak: || text::ParbreakNode.pack(), parbreak: || layout::ParbreakNode.pack(),
strong: |body| text::StrongNode(body).pack(), strong: |body| text::StrongNode(body).pack(),
emph: |body| text::EmphNode(body).pack(), emph: |body| text::EmphNode(body).pack(),
raw: |text, lang, block| { raw: |text, lang, block| {
@ -177,15 +183,13 @@ fn items() -> LangItems {
None => content, None => content,
} }
}, },
link: |url| text::LinkNode::from_url(url).pack(), link: |url| meta::LinkNode::from_url(url).pack(),
ref_: |target| structure::RefNode(target).pack(), ref_: |target| meta::RefNode(target).pack(),
heading: |level, body| structure::HeadingNode { level, body }.pack(), heading: |level, body| basics::HeadingNode { level, body }.pack(),
list_item: |body| structure::ListItem::List(Box::new(body)).pack(), list_item: |body| basics::ListItem::List(Box::new(body)).pack(),
enum_item: |number, body| { enum_item: |number, body| basics::ListItem::Enum(number, Box::new(body)).pack(),
structure::ListItem::Enum(number, Box::new(body)).pack()
},
desc_item: |term, body| { desc_item: |term, body| {
structure::ListItem::Desc(Box::new(structure::DescItem { term, body })).pack() basics::ListItem::Desc(Box::new(basics::DescItem { term, body })).pack()
}, },
math: |children, display| math::MathNode { children, display }.pack(), math: |children, display| math::MathNode { children, display }.pack(),
math_atom: |atom| math::AtomNode(atom).pack(), math_atom: |atom| math::AtomNode(atom).pack(),

View File

@ -1,7 +1,7 @@
use crate::layout::{LayoutRoot, PageNode}; use crate::layout::{LayoutRoot, PageNode};
use crate::prelude::*; use crate::prelude::*;
/// The root node of the model. /// The root node that represents a full document.
#[derive(Hash)] #[derive(Hash)]
pub struct DocumentNode(pub StyleVec<PageNode>); pub struct DocumentNode(pub StyleVec<PageNode>);

View File

@ -1,5 +1,5 @@
use super::TextNode;
use crate::prelude::*; use crate::prelude::*;
use crate::text::TextNode;
/// Link text and other elements to a destination. /// Link text and other elements to a destination.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

9
library/src/meta/mod.rs Normal file
View File

@ -0,0 +1,9 @@
//! Interaction between document parts.
mod document;
mod link;
mod reference;
pub use self::document::*;
pub use self::link::*;
pub use self::reference::*;

View File

@ -1,13 +0,0 @@
//! Document structuring.
mod document;
mod heading;
mod list;
mod reference;
mod table;
pub use self::document::*;
pub use self::heading::*;
pub use self::list::*;
pub use self::reference::*;
pub use self::table::*;

View File

@ -12,7 +12,7 @@ pub struct DecoNode<const L: DecoLine>(pub Content);
pub type UnderlineNode = DecoNode<UNDERLINE>; pub type UnderlineNode = DecoNode<UNDERLINE>;
/// Typeset stricken-through text. /// Typeset stricken-through text.
pub type StrikethroughNode = DecoNode<STRIKETHROUGH>; pub type StrikeNode = DecoNode<STRIKETHROUGH>;
/// Typeset overlined text. /// Typeset overlined text.
pub type OverlineNode = DecoNode<OVERLINE>; pub type OverlineNode = DecoNode<OVERLINE>;
@ -65,7 +65,7 @@ impl<const L: DecoLine> Show for DecoNode<L> {
/// ///
/// For more details, see [`DecoNode`]. /// For more details, see [`DecoNode`].
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub(super) struct Decoration { pub struct Decoration {
pub line: DecoLine, pub line: DecoLine,
pub stroke: PartialStroke<Abs>, pub stroke: PartialStroke<Abs>,
pub offset: Smart<Abs>, pub offset: Smart<Abs>,

146
library/src/text/misc.rs Normal file
View File

@ -0,0 +1,146 @@
use super::TextNode;
use crate::prelude::*;
/// A text space.
#[derive(Debug, Hash)]
pub struct SpaceNode;
#[node(Unlabellable, Behave)]
impl SpaceNode {
fn construct(_: &Vm, _: &mut Args) -> SourceResult<Content> {
Ok(Self.pack())
}
}
impl Unlabellable for SpaceNode {}
impl Behave for SpaceNode {
fn behaviour(&self) -> Behaviour {
Behaviour::Weak(2)
}
}
/// A line break.
#[derive(Debug, Hash)]
pub struct LinebreakNode {
pub justify: bool,
}
#[node(Behave)]
impl LinebreakNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let justify = args.named("justify")?.unwrap_or(false);
Ok(Self { justify }.pack())
}
}
impl Behave for LinebreakNode {
fn behaviour(&self) -> Behaviour {
Behaviour::Destructive
}
}
/// Strong content, rendered in boldface by default.
#[derive(Debug, Hash)]
pub struct StrongNode(pub Content);
#[node(Show)]
impl StrongNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
fn field(&self, name: &str) -> Option<Value> {
match name {
"body" => Some(Value::Content(self.0.clone())),
_ => None,
}
}
}
impl Show for StrongNode {
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content {
self.0.clone().styled(TextNode::BOLD, Toggle)
}
}
/// Emphasized content, rendered with an italic font by default.
#[derive(Debug, Hash)]
pub struct EmphNode(pub Content);
#[node(Show)]
impl EmphNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
fn field(&self, name: &str) -> Option<Value> {
match name {
"body" => Some(Value::Content(self.0.clone())),
_ => None,
}
}
}
impl Show for EmphNode {
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content {
self.0.clone().styled(TextNode::ITALIC, Toggle)
}
}
/// A toggle that turns on and off alternatingly if folded.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Toggle;
impl Fold for Toggle {
type Output = bool;
fn fold(self, outer: Self::Output) -> Self::Output {
!outer
}
}
/// Convert a string or content to lowercase.
pub fn lower(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Lower, args)
}
/// Convert a string or content to uppercase.
pub fn upper(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Upper, args)
}
/// Change the case of text.
fn case(case: Case, args: &mut Args) -> SourceResult<Value> {
let Spanned { v, span } = args.expect("string or content")?;
Ok(match v {
Value::Str(v) => Value::Str(case.apply(&v).into()),
Value::Content(v) => Value::Content(v.styled(TextNode::CASE, Some(case))),
v => bail!(span, "expected string or content, found {}", v.type_name()),
})
}
/// A case transformation on text.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Case {
/// Everything is lowercased.
Lower,
/// Everything is uppercased.
Upper,
}
impl Case {
/// Apply the case to a string.
pub fn apply(self, text: &str) -> String {
match self {
Self::Lower => text.to_lowercase(),
Self::Upper => text.to_uppercase(),
}
}
}
/// Display text in small capitals.
pub fn smallcaps(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let body: Content = args.expect("content")?;
Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true)))
}

View File

@ -1,16 +1,15 @@
//! Text handling and paragraph layout. //! Text handling.
mod deco; mod deco;
mod link; mod misc;
mod par;
mod quotes; mod quotes;
mod raw; mod raw;
mod shaping; mod shaping;
mod shift; mod shift;
pub use self::deco::*; pub use self::deco::*;
pub use self::link::*; pub use self::misc::*;
pub use self::par::*; pub use self::quotes::*;
pub use self::raw::*; pub use self::raw::*;
pub use self::shaping::*; pub use self::shaping::*;
pub use self::shift::*; pub use self::shift::*;
@ -21,7 +20,7 @@ use rustybuzz::Tag;
use typst::font::{FontMetrics, FontStretch, FontStyle, FontWeight, VerticalFontMetric}; use typst::font::{FontMetrics, FontStretch, FontStyle, FontWeight, VerticalFontMetric};
use typst::util::EcoString; use typst::util::EcoString;
use self::quotes::*; use crate::layout::ParNode;
use crate::prelude::*; use crate::prelude::*;
/// A single run of text with the same style. /// A single run of text with the same style.
@ -114,19 +113,19 @@ impl TextNode {
/// Whether the font weight should be increased by 300. /// Whether the font weight should be increased by 300.
#[property(skip, fold)] #[property(skip, fold)]
const BOLD: Toggle = false; pub const BOLD: Toggle = false;
/// Whether the font style should be inverted. /// Whether the font style should be inverted.
#[property(skip, fold)] #[property(skip, fold)]
const ITALIC: Toggle = false; pub const ITALIC: Toggle = false;
/// A case transformation that should be applied to the text. /// A case transformation that should be applied to the text.
#[property(skip)] #[property(skip)]
const CASE: Option<Case> = None; pub const CASE: Option<Case> = None;
/// Whether small capital glyphs should be used. ("smcp") /// Whether small capital glyphs should be used. ("smcp")
#[property(skip)] #[property(skip)]
const SMALLCAPS: bool = false; pub const SMALLCAPS: bool = false;
/// Decorative lines. /// Decorative lines.
#[property(skip, fold)] #[property(skip, fold)]
const DECO: Decoration = vec![]; pub const DECO: Decoration = vec![];
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
// The text constructor is special: It doesn't create a text node. // The text constructor is special: It doesn't create a text node.
@ -409,161 +408,3 @@ impl Fold for FontFeatures {
self self
} }
} }
/// A text space.
#[derive(Debug, Hash)]
pub struct SpaceNode;
#[node(Unlabellable, Behave)]
impl SpaceNode {
fn construct(_: &Vm, _: &mut Args) -> SourceResult<Content> {
Ok(Self.pack())
}
}
impl Unlabellable for SpaceNode {}
impl Behave for SpaceNode {
fn behaviour(&self) -> Behaviour {
Behaviour::Weak(2)
}
}
/// A line break.
#[derive(Debug, Hash)]
pub struct LinebreakNode {
pub justify: bool,
}
#[node(Behave)]
impl LinebreakNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let justify = args.named("justify")?.unwrap_or(false);
Ok(Self { justify }.pack())
}
}
impl Behave for LinebreakNode {
fn behaviour(&self) -> Behaviour {
Behaviour::Destructive
}
}
/// A smart quote.
#[derive(Debug, Hash)]
pub struct SmartQuoteNode {
pub double: bool,
}
#[node]
impl SmartQuoteNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let double = args.named("double")?.unwrap_or(true);
Ok(Self { double }.pack())
}
}
/// Convert a string or content to lowercase.
pub fn lower(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Lower, args)
}
/// Convert a string or content to uppercase.
pub fn upper(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Upper, args)
}
/// Change the case of text.
fn case(case: Case, args: &mut Args) -> SourceResult<Value> {
let Spanned { v, span } = args.expect("string or content")?;
Ok(match v {
Value::Str(v) => Value::Str(case.apply(&v).into()),
Value::Content(v) => Value::Content(v.styled(TextNode::CASE, Some(case))),
v => bail!(span, "expected string or content, found {}", v.type_name()),
})
}
/// A case transformation on text.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Case {
/// Everything is uppercased.
Upper,
/// Everything is lowercased.
Lower,
}
impl Case {
/// Apply the case to a string.
pub fn apply(self, text: &str) -> String {
match self {
Self::Upper => text.to_uppercase(),
Self::Lower => text.to_lowercase(),
}
}
}
/// Display text in small capitals.
pub fn smallcaps(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let body: Content = args.expect("content")?;
Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true)))
}
/// Strong content, rendered in boldface by default.
#[derive(Debug, Hash)]
pub struct StrongNode(pub Content);
#[node(Show)]
impl StrongNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
fn field(&self, name: &str) -> Option<Value> {
match name {
"body" => Some(Value::Content(self.0.clone())),
_ => None,
}
}
}
impl Show for StrongNode {
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content {
self.0.clone().styled(TextNode::BOLD, Toggle)
}
}
/// Emphasized content, rendered with an italic font by default.
#[derive(Debug, Hash)]
pub struct EmphNode(pub Content);
#[node(Show)]
impl EmphNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
fn field(&self, name: &str) -> Option<Value> {
match name {
"body" => Some(Value::Content(self.0.clone())),
_ => None,
}
}
}
impl Show for EmphNode {
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content {
self.0.clone().styled(TextNode::ITALIC, Toggle)
}
}
/// A toggle that turns on and off alternatingly if folded.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Toggle;
impl Fold for Toggle {
type Output = bool;
fn fold(self, outer: Self::Output) -> Self::Output {
!outer
}
}

View File

@ -1,10 +1,24 @@
use typst::syntax::is_newline; use typst::syntax::is_newline;
use super::{Lang, Region}; use crate::prelude::*;
/// A smart quote.
#[derive(Debug, Hash)]
pub struct SmartQuoteNode {
pub double: bool,
}
#[node]
impl SmartQuoteNode {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let double = args.named("double")?.unwrap_or(true);
Ok(Self { double }.pack())
}
}
/// State machine for smart quote subtitution. /// State machine for smart quote subtitution.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct Quoter { pub struct Quoter {
/// How many quotes have been opened. /// How many quotes have been opened.
quote_depth: usize, quote_depth: usize,
/// Whether an opening quote might follow. /// Whether an opening quote might follow.
@ -68,7 +82,7 @@ fn is_opening_bracket(c: char) -> bool {
} }
/// Decides which quotes to subtitute smart quotes with. /// Decides which quotes to subtitute smart quotes with.
pub(super) struct Quotes<'s> { pub struct Quotes<'s> {
/// The opening single quote. /// The opening single quote.
pub single_open: &'s str, pub single_open: &'s str,
/// The closing single quote. /// The closing single quote.

View File

@ -6,6 +6,7 @@ use typst::font::{Font, FontVariant};
use typst::util::SliceExt; use typst::util::SliceExt;
use super::*; use super::*;
use crate::meta::LinkNode;
use crate::prelude::*; use crate::prelude::*;
/// The result of shaping text. /// The result of shaping text.
@ -13,7 +14,7 @@ use crate::prelude::*;
/// This type contains owned or borrowed shaped text runs, which can be /// This type contains owned or borrowed shaped text runs, which can be
/// measured, used to reshape substrings more quickly and converted into a /// measured, used to reshape substrings more quickly and converted into a
/// frame. /// frame.
pub(super) struct ShapedText<'a> { pub struct ShapedText<'a> {
/// The text that was shaped. /// The text that was shaped.
pub text: &'a str, pub text: &'a str,
/// The text direction. /// The text direction.
@ -32,7 +33,7 @@ pub(super) struct ShapedText<'a> {
/// A single glyph resulting from shaping. /// A single glyph resulting from shaping.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct ShapedGlyph { pub struct ShapedGlyph {
/// The font the glyph is contained in. /// The font the glyph is contained in.
pub font: Font, pub font: Font,
/// The glyph's index in the font. /// The glyph's index in the font.
@ -314,7 +315,7 @@ struct ShapingContext<'a> {
} }
/// Shape text into [`ShapedText`]. /// Shape text into [`ShapedText`].
pub(super) fn shape<'a>( pub fn shape<'a>(
world: Tracked<dyn World>, world: Tracked<dyn World>,
text: &'a str, text: &'a str,
styles: StyleChain<'a>, styles: StyleChain<'a>,

View File

@ -2,8 +2,8 @@ use std::ffi::OsStr;
use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat}; use typst::image::{Image, ImageFormat, RasterFormat, VectorFormat};
use crate::meta::LinkNode;
use crate::prelude::*; use crate::prelude::*;
use crate::text::LinkNode;
/// Show a raster or vector graphic. /// Show a raster or vector graphic.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

View File

@ -1,11 +1,9 @@
//! Graphical elements and effects. //! Drawing and visualization.
mod hide;
mod image; mod image;
mod line; mod line;
mod shape; mod shape;
pub use self::hide::*;
pub use self::image::*; pub use self::image::*;
pub use self::line::*; pub use self::line::*;
pub use self::shape::*; pub use self::shape::*;

View File

@ -1,7 +1,7 @@
use std::f64::consts::SQRT_2; use std::f64::consts::SQRT_2;
use crate::meta::LinkNode;
use crate::prelude::*; use crate::prelude::*;
use crate::text::LinkNode;
/// A sizable and fillable shape with optional content. /// A sizable and fillable shape with optional content.
#[derive(Debug, Hash)] #[derive(Debug, Hash)]

View File

@ -1,4 +1,4 @@
//! Document and computation model. //! Content and computation model.
#[macro_use] #[macro_use]
mod library; mod library;

View File

@ -3,7 +3,9 @@
## Directory structure ## Directory structure
Top level directory structure: Top level directory structure:
- `src`: Testing code. - `src`: Testing code.
- `typ`: Input files. - `typ`: Input files. The tests in `compiler` specifically test the compiler
while the others test the standard library (but also the compiler
indirectly).
- `ref`: Reference images which the output is compared with to determine whether - `ref`: Reference images which the output is compared with to determine whether
a test passed or failed. a test passed or failed.
- `png`: PNG files produced by tests. - `png`: PNG files produced by tests.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

BIN
tests/ref/basics/desc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
tests/ref/basics/enum.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 797 B

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
tests/ref/compiler/if.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
tests/ref/compiler/let.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

BIN
tests/ref/compiler/ops.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 B

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

BIN
tests/ref/compute/data.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 B

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Some files were not shown because too many files have changed in this diff Show More