diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-01-23 15:03:10 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-01-23 15:23:52 +0100 |
| commit | 4653ffebb43d733a3cff873d0903c7d00aaeb499 (patch) | |
| tree | 6a97b2e6a6903b3198547d6f3d0a7e3d2eb023cd /library | |
| parent | 84c6c8b0e6b17996a603ec88b7490107154f38f3 (diff) | |
Math module
Diffstat (limited to 'library')
| -rw-r--r-- | library/src/lib.rs | 230 | ||||
| -rw-r--r-- | library/src/math/accent.rs | 2 | ||||
| -rw-r--r-- | library/src/math/frac.rs | 5 | ||||
| -rw-r--r-- | library/src/math/lr.rs | 91 | ||||
| -rw-r--r-- | library/src/math/matrix.rs | 14 | ||||
| -rw-r--r-- | library/src/math/mod.rs | 77 | ||||
| -rw-r--r-- | library/src/math/op.rs | 131 | ||||
| -rw-r--r-- | library/src/math/root.rs | 2 | ||||
| -rw-r--r-- | library/src/math/spacing.rs | 18 |
9 files changed, 306 insertions, 264 deletions
diff --git a/library/src/lib.rs b/library/src/lib.rs index c2f51ee4..c4b6710f 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -11,144 +11,146 @@ pub mod text; pub mod visualize; use typst::geom::{Align, Color, Dir, GenAlign}; -use typst::model::{LangItems, Library, Node, NodeId, Scope, StyleMap}; +use typst::model::{LangItems, Library, Module, Node, NodeId, Scope, StyleMap}; use self::layout::LayoutRoot; /// Construct the standard library. pub fn build() -> Library { - Library { scope: scope(), styles: styles(), items: items() } + let math = math::module(); + let global = global(math.clone()); + Library { global, math, styles: styles(), items: items() } } -/// Construct the standard scope. -fn scope() -> Scope { - let mut std = Scope::new(); +/// Construct the module with global definitions. +fn global(math: Module) -> Module { + let mut global = Scope::deduplicating(); // Basics. - std.def_func::<basics::HeadingNode>("heading"); - std.def_func::<basics::ListNode>("list"); - std.def_func::<basics::EnumNode>("enum"); - std.def_func::<basics::TermsNode>("terms"); - std.def_func::<basics::TableNode>("table"); + global.def_func::<basics::HeadingNode>("heading"); + global.def_func::<basics::ListNode>("list"); + global.def_func::<basics::EnumNode>("enum"); + global.def_func::<basics::TermsNode>("terms"); + global.def_func::<basics::TableNode>("table"); // Text. - std.def_func::<text::TextNode>("text"); - std.def_func::<text::LinebreakNode>("linebreak"); - std.def_func::<text::SymbolNode>("symbol"); - std.def_func::<text::SmartQuoteNode>("smartquote"); - std.def_func::<text::StrongNode>("strong"); - std.def_func::<text::EmphNode>("emph"); - std.def_func::<text::LowerFunc>("lower"); - std.def_func::<text::UpperFunc>("upper"); - std.def_func::<text::SmallcapsFunc>("smallcaps"); - std.def_func::<text::SubNode>("sub"); - std.def_func::<text::SuperNode>("super"); - std.def_func::<text::UnderlineNode>("underline"); - std.def_func::<text::StrikeNode>("strike"); - std.def_func::<text::OverlineNode>("overline"); - std.def_func::<text::RawNode>("raw"); + global.def_func::<text::TextNode>("text"); + global.def_func::<text::LinebreakNode>("linebreak"); + global.def_func::<text::SymbolNode>("symbol"); + global.def_func::<text::SmartQuoteNode>("smartquote"); + global.def_func::<text::StrongNode>("strong"); + global.def_func::<text::EmphNode>("emph"); + global.def_func::<text::LowerFunc>("lower"); + global.def_func::<text::UpperFunc>("upper"); + global.def_func::<text::SmallcapsFunc>("smallcaps"); + global.def_func::<text::SubNode>("sub"); + global.def_func::<text::SuperNode>("super"); + global.def_func::<text::UnderlineNode>("underline"); + global.def_func::<text::StrikeNode>("strike"); + global.def_func::<text::OverlineNode>("overline"); + global.def_func::<text::RawNode>("raw"); // Math. - math::define(&mut std); + global.define("math", math); // Layout. - std.def_func::<layout::PageNode>("page"); - std.def_func::<layout::PagebreakNode>("pagebreak"); - std.def_func::<layout::VNode>("v"); - std.def_func::<layout::ParNode>("par"); - std.def_func::<layout::ParbreakNode>("parbreak"); - std.def_func::<layout::HNode>("h"); - std.def_func::<layout::BoxNode>("box"); - std.def_func::<layout::BlockNode>("block"); - std.def_func::<layout::StackNode>("stack"); - std.def_func::<layout::GridNode>("grid"); - std.def_func::<layout::ColumnsNode>("columns"); - std.def_func::<layout::ColbreakNode>("colbreak"); - std.def_func::<layout::PlaceNode>("place"); - std.def_func::<layout::AlignNode>("align"); - std.def_func::<layout::PadNode>("pad"); - std.def_func::<layout::RepeatNode>("repeat"); - std.def_func::<layout::MoveNode>("move"); - std.def_func::<layout::ScaleNode>("scale"); - std.def_func::<layout::RotateNode>("rotate"); - std.def_func::<layout::HideNode>("hide"); + global.def_func::<layout::PageNode>("page"); + global.def_func::<layout::PagebreakNode>("pagebreak"); + global.def_func::<layout::VNode>("v"); + global.def_func::<layout::ParNode>("par"); + global.def_func::<layout::ParbreakNode>("parbreak"); + global.def_func::<layout::HNode>("h"); + global.def_func::<layout::BoxNode>("box"); + global.def_func::<layout::BlockNode>("block"); + global.def_func::<layout::StackNode>("stack"); + global.def_func::<layout::GridNode>("grid"); + global.def_func::<layout::ColumnsNode>("columns"); + global.def_func::<layout::ColbreakNode>("colbreak"); + global.def_func::<layout::PlaceNode>("place"); + global.def_func::<layout::AlignNode>("align"); + global.def_func::<layout::PadNode>("pad"); + global.def_func::<layout::RepeatNode>("repeat"); + global.def_func::<layout::MoveNode>("move"); + global.def_func::<layout::ScaleNode>("scale"); + global.def_func::<layout::RotateNode>("rotate"); + global.def_func::<layout::HideNode>("hide"); // Visualize. - std.def_func::<visualize::ImageNode>("image"); - std.def_func::<visualize::LineNode>("line"); - std.def_func::<visualize::RectNode>("rect"); - std.def_func::<visualize::SquareNode>("square"); - std.def_func::<visualize::EllipseNode>("ellipse"); - std.def_func::<visualize::CircleNode>("circle"); + global.def_func::<visualize::ImageNode>("image"); + global.def_func::<visualize::LineNode>("line"); + global.def_func::<visualize::RectNode>("rect"); + global.def_func::<visualize::SquareNode>("square"); + global.def_func::<visualize::EllipseNode>("ellipse"); + global.def_func::<visualize::CircleNode>("circle"); // Meta. - std.def_func::<meta::DocumentNode>("document"); - std.def_func::<meta::RefNode>("ref"); - std.def_func::<meta::LinkNode>("link"); - std.def_func::<meta::OutlineNode>("outline"); + global.def_func::<meta::DocumentNode>("document"); + global.def_func::<meta::RefNode>("ref"); + global.def_func::<meta::LinkNode>("link"); + global.def_func::<meta::OutlineNode>("outline"); // Compute. - std.def_func::<compute::TypeFunc>("type"); - std.def_func::<compute::ReprFunc>("repr"); - std.def_func::<compute::AssertFunc>("assert"); - std.def_func::<compute::EvalFunc>("eval"); - std.def_func::<compute::IntFunc>("int"); - std.def_func::<compute::FloatFunc>("float"); - std.def_func::<compute::LumaFunc>("luma"); - std.def_func::<compute::RgbFunc>("rgb"); - std.def_func::<compute::CmykFunc>("cmyk"); - std.def_func::<compute::StrFunc>("str"); - std.def_func::<compute::LabelFunc>("label"); - std.def_func::<compute::RegexFunc>("regex"); - std.def_func::<compute::RangeFunc>("range"); - std.def_func::<compute::AbsFunc>("abs"); - std.def_func::<compute::MinFunc>("min"); - std.def_func::<compute::MaxFunc>("max"); - std.def_func::<compute::EvenFunc>("even"); - std.def_func::<compute::OddFunc>("odd"); - std.def_func::<compute::ModFunc>("mod"); - std.def_func::<compute::ReadFunc>("read"); - std.def_func::<compute::CsvFunc>("csv"); - std.def_func::<compute::JsonFunc>("json"); - std.def_func::<compute::XmlFunc>("xml"); - std.def_func::<compute::LoremFunc>("lorem"); - std.def_func::<compute::NumberingFunc>("numbering"); + global.def_func::<compute::TypeFunc>("type"); + global.def_func::<compute::ReprFunc>("repr"); + global.def_func::<compute::AssertFunc>("assert"); + global.def_func::<compute::EvalFunc>("eval"); + global.def_func::<compute::IntFunc>("int"); + global.def_func::<compute::FloatFunc>("float"); + global.def_func::<compute::LumaFunc>("luma"); + global.def_func::<compute::RgbFunc>("rgb"); + global.def_func::<compute::CmykFunc>("cmyk"); + global.def_func::<compute::StrFunc>("str"); + global.def_func::<compute::LabelFunc>("label"); + global.def_func::<compute::RegexFunc>("regex"); + global.def_func::<compute::RangeFunc>("range"); + global.def_func::<compute::AbsFunc>("abs"); + global.def_func::<compute::MinFunc>("min"); + global.def_func::<compute::MaxFunc>("max"); + global.def_func::<compute::EvenFunc>("even"); + global.def_func::<compute::OddFunc>("odd"); + global.def_func::<compute::ModFunc>("mod"); + global.def_func::<compute::ReadFunc>("read"); + global.def_func::<compute::CsvFunc>("csv"); + global.def_func::<compute::JsonFunc>("json"); + global.def_func::<compute::XmlFunc>("xml"); + global.def_func::<compute::LoremFunc>("lorem"); + global.def_func::<compute::NumberingFunc>("numbering"); // Colors. - std.define("black", Color::BLACK); - std.define("gray", Color::GRAY); - std.define("silver", Color::SILVER); - std.define("white", Color::WHITE); - std.define("navy", Color::NAVY); - std.define("blue", Color::BLUE); - std.define("aqua", Color::AQUA); - std.define("teal", Color::TEAL); - std.define("eastern", Color::EASTERN); - std.define("purple", Color::PURPLE); - std.define("fuchsia", Color::FUCHSIA); - std.define("maroon", Color::MAROON); - std.define("red", Color::RED); - std.define("orange", Color::ORANGE); - std.define("yellow", Color::YELLOW); - std.define("olive", Color::OLIVE); - std.define("green", Color::GREEN); - std.define("lime", Color::LIME); + global.define("black", Color::BLACK); + global.define("gray", Color::GRAY); + global.define("silver", Color::SILVER); + global.define("white", Color::WHITE); + global.define("navy", Color::NAVY); + global.define("blue", Color::BLUE); + global.define("aqua", Color::AQUA); + global.define("teal", Color::TEAL); + global.define("eastern", Color::EASTERN); + global.define("purple", Color::PURPLE); + global.define("fuchsia", Color::FUCHSIA); + global.define("maroon", Color::MAROON); + global.define("red", Color::RED); + global.define("orange", Color::ORANGE); + global.define("yellow", Color::YELLOW); + global.define("olive", Color::OLIVE); + global.define("green", Color::GREEN); + global.define("lime", Color::LIME); // Other constants. - std.define("ltr", Dir::LTR); - std.define("rtl", Dir::RTL); - std.define("ttb", Dir::TTB); - std.define("btt", Dir::BTT); - std.define("start", GenAlign::Start); - std.define("end", GenAlign::End); - std.define("left", GenAlign::Specific(Align::Left)); - std.define("center", GenAlign::Specific(Align::Center)); - std.define("right", GenAlign::Specific(Align::Right)); - std.define("top", GenAlign::Specific(Align::Top)); - std.define("horizon", GenAlign::Specific(Align::Horizon)); - std.define("bottom", GenAlign::Specific(Align::Bottom)); - - std + global.define("ltr", Dir::LTR); + global.define("rtl", Dir::RTL); + global.define("ttb", Dir::TTB); + global.define("btt", Dir::BTT); + global.define("start", GenAlign::Start); + global.define("end", GenAlign::End); + global.define("left", GenAlign::Specific(Align::Left)); + global.define("center", GenAlign::Specific(Align::Center)); + global.define("right", GenAlign::Specific(Align::Right)); + global.define("top", GenAlign::Specific(Align::Top)); + global.define("horizon", GenAlign::Specific(Align::Horizon)); + global.define("bottom", GenAlign::Specific(Align::Bottom)); + + Module::new("global").with_scope(global) } /// Construct the standard style map. @@ -187,7 +189,7 @@ fn items() -> LangItems { term_item: |term, description| { layout::ListItem::Term(basics::TermItem { term, description }).pack() }, - math: |body, block| math::MathNode { body, block }.pack(), + math_formula: |body, block| math::FormulaNode { body, block }.pack(), math_atom: |atom| math::AtomNode(atom).pack(), math_delimited: |body| math::LrNode(body).pack(), math_script: |base, sub, sup| math::ScriptNode { base, sub, sup }.pack(), diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index b8c31c19..a15a6020 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -133,7 +133,7 @@ fn attachment(ctx: &MathContext, id: GlyphId, italics_correction: Abs) -> Abs { /// Extract a single character from content. fn extract(accent: &Content) -> Option<char> { - let atom = accent.to::<MathNode>()?.body.to::<AtomNode>()?; + let atom = accent.to::<FormulaNode>()?.body.to::<AtomNode>()?; let mut chars = atom.0.chars(); let c = chars.next().filter(|_| chars.next().is_none())?; Some(combining(c)) diff --git a/library/src/math/frac.rs b/library/src/math/frac.rs index 50a68fea..e945473c 100644 --- a/library/src/math/frac.rs +++ b/library/src/math/frac.rs @@ -98,6 +98,7 @@ fn layout( denom: &Content, binom: bool, ) -> SourceResult<()> { + let short_fall = DELIM_SHORT_FALL.scaled(ctx); let axis = scaled!(ctx, axis_height); let thickness = scaled!(ctx, fraction_rule_thickness); let shift_up = scaled!( @@ -149,9 +150,9 @@ fn layout( frame.push_frame(denom_pos, denom); if binom { - ctx.push(GlyphFragment::new(ctx, '(')); + ctx.push(GlyphFragment::new(ctx, '(').stretch_vertical(ctx, height, short_fall)); ctx.push(frame); - ctx.push(GlyphFragment::new(ctx, ')')); + ctx.push(GlyphFragment::new(ctx, ')').stretch_vertical(ctx, height, short_fall)); } else { frame.push( line_pos, diff --git a/library/src/math/lr.rs b/library/src/math/lr.rs index 9cfc6e5f..89d12380 100644 --- a/library/src/math/lr.rs +++ b/library/src/math/lr.rs @@ -1,7 +1,7 @@ use super::*; /// How much less high scaled delimiters can be than what they wrap. -const DELIM_SHORT_FALL: Em = Em::new(0.1); +pub(super) const DELIM_SHORT_FALL: Em = Em::new(0.1); /// # Left-Right /// Scales delimiters. @@ -62,7 +62,7 @@ impl LayoutMath for LrNode { } let MathFragment::Glyph(glyph) = *fragment else { continue }; - let short_fall = DELIM_SHORT_FALL.at(glyph.font_size); + let short_fall = DELIM_SHORT_FALL.scaled(ctx); *fragment = MathFragment::Variant( glyph.stretch_vertical(ctx, height, short_fall), ); @@ -76,3 +76,90 @@ impl LayoutMath for LrNode { Ok(()) } } + +/// # Floor +/// Floor an expression. +/// +/// ## Example +/// ``` +/// $ floor(x/2) $ +/// ``` +/// +/// ## Parameters +/// - body: Content (positional, required) +/// The expression to floor. +/// +/// ## Category +/// math +#[func] +pub fn floor(args: &mut Args) -> SourceResult<Value> { + delimited(args, '⌊', '⌋') +} + +/// # Ceil +/// Ceil an expression. +/// +/// ## Example +/// ``` +/// $ ceil(x/2) $ +/// ``` +/// +/// ## Parameters +/// - body: Content (positional, required) +/// The expression to ceil. +/// +/// ## Category +/// math +#[func] +pub fn ceil(args: &mut Args) -> SourceResult<Value> { + delimited(args, '⌈', '⌉') +} + +/// # Abs +/// Take the absolute value of an expression. +/// +/// ## Example +/// ``` +/// $ abs(x/2) $ +/// ``` +/// +/// ## Parameters +/// - body: Content (positional, required) +/// The expression to take the absolute value of. +/// +/// ## Category +/// math +#[func] +pub fn abs(args: &mut Args) -> SourceResult<Value> { + delimited(args, '|', '|') +} + +/// # Norm +/// Take the norm of an expression. +/// +/// ## Example +/// ``` +/// $ norm(x/2) $ +/// ``` +/// +/// ## Parameters +/// - body: Content (positional, required) +/// The expression to take the norm of. +/// +/// ## Category +/// math +#[func] +pub fn norm(args: &mut Args) -> SourceResult<Value> { + delimited(args, '‖', '‖') +} + +fn delimited(args: &mut Args, left: char, right: char) -> SourceResult<Value> { + Ok(Value::Content( + LrNode(Content::sequence(vec![ + AtomNode(left.into()).pack(), + args.expect::<Content>("body")?, + AtomNode(right.into()).pack(), + ])) + .pack(), + )) +} diff --git a/library/src/math/matrix.rs b/library/src/math/matrix.rs index aa21e9cf..9472e989 100644 --- a/library/src/math/matrix.rs +++ b/library/src/math/matrix.rs @@ -161,6 +161,7 @@ fn layout( ) -> SourceResult<()> { let axis = scaled!(ctx, axis_height); let gap = ROW_GAP.scaled(ctx); + let short_fall = DELIM_SHORT_FALL.scaled(ctx); ctx.style(ctx.style.for_denominator()); let mut rows = vec![]; @@ -169,17 +170,20 @@ fn layout( } ctx.unstyle(); - if let Some(left) = left { - ctx.push(GlyphFragment::new(ctx, left)); - } - let mut frame = stack(ctx, rows, align, gap, 0); + let height = frame.height(); frame.set_baseline(frame.height() / 2.0 + axis); + if let Some(left) = left { + ctx.push(GlyphFragment::new(ctx, left).stretch_vertical(ctx, height, short_fall)); + } + ctx.push(frame); if let Some(right) = right { - ctx.push(GlyphFragment::new(ctx, right)); + ctx.push( + GlyphFragment::new(ctx, right).stretch_vertical(ctx, height, short_fall), + ); } Ok(()) diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 44b52e96..0de440be 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -33,7 +33,7 @@ pub use self::style::*; use ttf_parser::GlyphId; use ttf_parser::Rect; use typst::font::Font; -use typst::model::{Guard, Scope, SequenceNode}; +use typst::model::{Guard, Module, Scope, SequenceNode}; use unicode_math_class::MathClass; use self::ctx::*; @@ -48,38 +48,38 @@ use crate::text::TextNode; use crate::text::TextSize; use crate::text::{families, variant, FallbackList, FontFamily, SpaceNode, SymbolNode}; -/// Hook up all math definitions. -pub fn define(scope: &mut Scope) { - scope.def_func::<MathNode>("math"); - scope.def_func::<LrNode>("lr"); - scope.def_func::<AccentNode>("accent"); - scope.def_func::<FracNode>("frac"); - scope.def_func::<BinomNode>("binom"); - scope.def_func::<ScriptNode>("script"); - scope.def_func::<SqrtNode>("sqrt"); - scope.def_func::<RootNode>("root"); - scope.def_func::<FloorNode>("floor"); - scope.def_func::<CeilNode>("ceil"); - scope.def_func::<VecNode>("vec"); - scope.def_func::<CasesNode>("cases"); - scope.def_func::<UnderbraceNode>("underbrace"); - scope.def_func::<OverbraceNode>("overbrace"); - scope.def_func::<BoldNode>("bold"); - scope.def_func::<ItalicNode>("italic"); - scope.def_func::<SerifNode>("serif"); - scope.def_func::<SansNode>("sans"); - scope.def_func::<CalNode>("cal"); - scope.def_func::<FrakNode>("frak"); - scope.def_func::<MonoNode>("mono"); - scope.def_func::<BbNode>("bb"); - scope.define("thin", HNode::strong(THIN).pack()); - scope.define("med", HNode::strong(MEDIUM).pack()); - scope.define("thick", HNode::strong(THICK).pack()); - scope.define("quad", HNode::strong(QUAD).pack()); - define_operators(scope); +/// Create a module with all math definitions. +pub fn module() -> Module { + let mut math = Scope::deduplicating(); + math.def_func::<FormulaNode>("formula"); + math.def_func::<LrNode>("lr"); + math.def_func::<FloorFunc>("floor"); + math.def_func::<CeilFunc>("ceil"); + math.def_func::<AbsFunc>("abs"); + math.def_func::<AccentNode>("accent"); + math.def_func::<FracNode>("frac"); + math.def_func::<BinomNode>("binom"); + math.def_func::<ScriptNode>("script"); + math.def_func::<SqrtNode>("sqrt"); + math.def_func::<RootNode>("root"); + math.def_func::<VecNode>("vec"); + math.def_func::<CasesNode>("cases"); + math.def_func::<UnderbraceNode>("underbrace"); + math.def_func::<OverbraceNode>("overbrace"); + math.def_func::<BoldNode>("bold"); + math.def_func::<ItalicNode>("italic"); + math.def_func::<SerifNode>("serif"); + math.def_func::<SansNode>("sans"); + math.def_func::<CalNode>("cal"); + math.def_func::<FrakNode>("frak"); + math.def_func::<MonoNode>("mono"); + math.def_func::<BbNode>("bb"); + define_spacings(&mut math); + define_operators(&mut math); + Module::new("math").with_scope(math) } -/// # Math +/// # Formula /// A mathematical formula. /// /// ## Syntax @@ -131,7 +131,7 @@ pub fn define(scope: &mut Scope) { #[func] #[capable(Show, Finalize, Layout, Inline, LayoutMath)] #[derive(Debug, Clone, Hash)] -pub struct MathNode { +pub struct FormulaNode { /// Whether the formula is displayed as a separate block. pub block: bool, /// The content of the formula. @@ -139,7 +139,7 @@ pub struct MathNode { } #[node] -impl MathNode { +impl FormulaNode { fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { let body = args.expect("body")?; let block = args.named("block")?.unwrap_or(false); @@ -148,13 +148,14 @@ impl MathNode { fn field(&self, name: &str) -> Option<Value> { match name { + "body" => Some(Value::Content(self.body.clone())), "block" => Some(Value::Bool(self.block)), _ => None, } } } -impl Show for MathNode { +impl Show for FormulaNode { fn show(&self, _: &mut Vt, _: &Content, _: StyleChain) -> SourceResult<Content> { let mut realized = self.clone().pack().guarded(Guard::Base(NodeId::of::<Self>())); if self.block { @@ -164,7 +165,7 @@ impl Show for MathNode { } } -impl Finalize for MathNode { +impl Finalize for FormulaNode { fn finalize(&self, realized: Content) -> Content { realized.styled( TextNode::FAMILY, @@ -173,7 +174,7 @@ impl Finalize for MathNode { } } -impl Layout for MathNode { +impl Layout for FormulaNode { fn layout( &self, vt: &mut Vt, @@ -200,14 +201,14 @@ impl Layout for MathNode { } } -impl Inline for MathNode {} +impl Inline for FormulaNode {} #[capability] trait LayoutMath { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()>; } -impl LayoutMath for MathNode { +impl LayoutMath for FormulaNode { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { self.body.layout_math(ctx) } diff --git a/library/src/math/op.rs b/library/src/math/op.rs index aef0d41b..a7d29166 100644 --- a/library/src/math/op.rs +++ b/library/src/math/op.rs @@ -25,12 +25,6 @@ pub struct OpNode { pub limits: bool, } -impl OpNode { - fn new(text: impl Into<EcoString>, limits: bool) -> Self { - Self { text: text.into(), limits } - } -} - #[node] impl OpNode { fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { @@ -55,96 +49,41 @@ impl LayoutMath for OpNode { } /// Hook up all operators. -pub fn define_operators(scope: &mut Scope) { - let mut define = |name: &str, limits| { - scope.define(name, OpNode { text: name.into(), limits }.pack()); - }; - - // These have the same name in code and display. - define("arccos", false); - define("arcsin", false); - define("arctan", false); - define("arg", false); - define("cos", false); - define("cosh", false); - define("cot", false); - define("coth", false); - define("csc", false); - define("deg", false); - define("det", true); - define("dim", false); - define("exp", false); - define("gcd", true); - define("hom", false); - define("inf", true); - define("ker", false); - define("lg", false); - define("lim", true); - define("ln", false); - define("log", false); - define("max", true); - define("min", true); - define("Pr", true); - define("sec", false); - define("sin", false); - define("sinh", false); - define("sup", true); - define("tan", false); - define("tanh", false); - - // These have an extra thin space. - scope.define("liminf", OpNode::new("lim inf", true).pack()); - scope.define("limsup", OpNode::new("lim sup", true).pack()); -} - -/// # Floor -/// A floored expression. -/// -/// ## Example -/// ``` -/// $ floor(x/2) $ -/// ``` -/// -/// ## Parameters -/// - body: Content (positional, required) -/// The expression to floor. -/// -/// ## Category -/// math -#[func] -#[capable] -#[derive(Debug, Hash)] -pub struct FloorNode(pub Content); - -#[node] -impl FloorNode { - fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { - Ok(Self(args.expect("body")?).pack()) - } +pub(super) fn define_operators(math: &mut Scope) { + math.define("arccos", op("arccos", false)); + math.define("arcsin", op("arcsin", false)); + math.define("arctan", op("arctan", false)); + math.define("arg", op("arg", false)); + math.define("cos", op("cos", false)); + math.define("cosh", op("cosh", false)); + math.define("cot", op("cot", false)); + math.define("coth", op("coth", false)); + math.define("csc", op("csc", false)); + math.define("deg", op("deg", false)); + math.define("det", op("det", true)); + math.define("dim", op("dim", false)); + math.define("exp", op("exp", false)); + math.define("gcd", op("gcd", true)); + math.define("hom", op("hom", false)); + math.define("inf", op("inf", true)); + math.define("ker", op("ker", false)); + math.define("lg", op("lg", false)); + math.define("lim", op("lim", true)); + math.define("ln", op("ln", false)); + math.define("log", op("log", false)); + math.define("max", op("max", true)); + math.define("min", op("min", true)); + math.define("Pr", op("Pr", true)); + math.define("sec", op("sec", false)); + math.define("sin", op("sin", false)); + math.define("sinh", op("sinh", false)); + math.define("sup", op("sup", true)); + math.define("tan", op("tan", false)); + math.define("tanh", op("tanh", false)); + math.define("liminf", op("lim inf", true)); + math.define("limsup", op("lim sup", true)); } -/// # Ceil -/// A ceiled expression. -/// -/// ## Example -/// ``` -/// $ ceil(x/2) $ -/// ``` -/// -/// ## Parameters -/// - body: Content (positional, required) -/// The expression to ceil. -/// -/// ## Category -/// math -#[func] -#[capable] -#[derive(Debug, Hash)] -pub struct CeilNode(pub Content); - -#[node] -impl CeilNode { - fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { - Ok(Self(args.expect("body")?).pack()) - } +fn op(name: &str, limits: bool) -> Content { + OpNode { text: name.into(), limits }.pack() } diff --git a/library/src/math/root.rs b/library/src/math/root.rs index f5c5b2b8..2efe4e07 100644 --- a/library/src/math/root.rs +++ b/library/src/math/root.rs @@ -155,7 +155,7 @@ fn layout( /// Select a precomposed radical, if the font has it. fn precomposed(ctx: &MathContext, index: Option<&Content>, target: Abs) -> Option<Frame> { - let node = index?.to::<MathNode>()?.body.to::<AtomNode>()?; + let node = index?.to::<FormulaNode>()?.body.to::<AtomNode>()?; let c = match node.0.as_str() { "3" => '∛', "4" => '∜', diff --git a/library/src/math/spacing.rs b/library/src/math/spacing.rs index 0f613309..d5a7603d 100644 --- a/library/src/math/spacing.rs +++ b/library/src/math/spacing.rs @@ -1,10 +1,18 @@ use super::*; -pub(super) const ZERO: Em = Em::zero(); -pub(super) const THIN: Em = Em::new(1.0 / 6.0); -pub(super) const MEDIUM: Em = Em::new(2.0 / 9.0); -pub(super) const THICK: Em = Em::new(5.0 / 18.0); -pub(super) const QUAD: Em = Em::new(1.0); +const ZERO: Em = Em::zero(); +const THIN: Em = Em::new(1.0 / 6.0); +const MEDIUM: Em = Em::new(2.0 / 9.0); +const THICK: Em = Em::new(5.0 / 18.0); +const QUAD: Em = Em::new(1.0); + +/// Hook up all spacings. +pub(super) fn define_spacings(math: &mut Scope) { + math.define("thin", HNode::strong(THIN).pack()); + math.define("med", HNode::strong(MEDIUM).pack()); + math.define("thick", HNode::strong(THICK).pack()); + math.define("quad", HNode::strong(QUAD).pack()); +} /// Determine the spacing between two fragments in a given style. pub(super) fn spacing(left: MathClass, right: MathClass, style: MathStyle) -> Em { |
