summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library/src/lib.rs230
-rw-r--r--library/src/math/accent.rs2
-rw-r--r--library/src/math/frac.rs5
-rw-r--r--library/src/math/lr.rs91
-rw-r--r--library/src/math/matrix.rs14
-rw-r--r--library/src/math/mod.rs77
-rw-r--r--library/src/math/op.rs131
-rw-r--r--library/src/math/root.rs2
-rw-r--r--library/src/math/spacing.rs18
-rw-r--r--src/ide/complete.rs7
-rw-r--r--src/ide/tooltip.rs14
-rw-r--r--src/model/eval.rs25
-rw-r--r--src/model/library.rs10
-rw-r--r--src/model/module.rs22
-rw-r--r--src/model/scope.rs44
-rw-r--r--src/syntax/ast.rs2
-rw-r--r--src/syntax/parser.rs7
-rw-r--r--tests/src/tests.rs12
-rw-r--r--tests/typ/layout/par.typ1
-rw-r--r--tests/typ/math/matrix.typ6
-rw-r--r--tests/typ/math/style.typ4
21 files changed, 407 insertions, 317 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 {
diff --git a/src/ide/complete.rs b/src/ide/complete.rs
index f0808b21..5b044746 100644
--- a/src/ide/complete.rs
+++ b/src/ide/complete.rs
@@ -4,7 +4,6 @@ use if_chain::if_chain;
use super::{plain_docs_sentence, summarize_font_family};
use crate::model::{CastInfo, Scope, Value};
-use crate::syntax::ast::AstNode;
use crate::syntax::{ast, LinkedNode, Source, SyntaxKind};
use crate::util::{format_eco, EcoString};
use crate::World;
@@ -118,8 +117,8 @@ fn complete_params(ctx: &mut CompletionContext) -> bool {
if let Some(grand) = parent.parent();
if let Some(expr) = grand.cast::<ast::Expr>();
let set = matches!(expr, ast::Expr::Set(_));
- if let Some(callee) = match expr {
- ast::Expr::FuncCall(call) => call.callee().as_untyped().cast(),
+ if let Some(ast::Expr::Ident(callee)) = match expr {
+ ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::Set(set) => Some(set.target()),
_ => None,
};
@@ -377,7 +376,7 @@ impl<'a> CompletionContext<'a> {
let leaf = LinkedNode::new(source.root()).leaf_at(cursor)?;
Some(Self {
world,
- scope: &world.library().scope,
+ scope: &world.library().global.scope(),
before: &text[..cursor],
after: &text[cursor..],
leaf,
diff --git a/src/ide/tooltip.rs b/src/ide/tooltip.rs
index 0d46695b..076e2b45 100644
--- a/src/ide/tooltip.rs
+++ b/src/ide/tooltip.rs
@@ -2,7 +2,7 @@ use if_chain::if_chain;
use super::{plain_docs_sentence, summarize_font_family};
use crate::model::{CastInfo, Value};
-use crate::syntax::ast::{self, AstNode};
+use crate::syntax::ast;
use crate::syntax::{LinkedNode, Source, SyntaxKind};
use crate::World;
@@ -23,7 +23,7 @@ fn function_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<String> {
leaf.parent_kind(),
Some(SyntaxKind::FuncCall | SyntaxKind::SetRule),
);
- if let Some(Value::Func(func)) = world.library().scope.get(&ident);
+ if let Some(Value::Func(func)) = world.library().global.scope().get(&ident);
if let Some(info) = func.info();
then {
return Some(plain_docs_sentence(info.docs));
@@ -44,14 +44,14 @@ fn named_param_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<String> {
if matches!(grand.kind(), SyntaxKind::Args);
if let Some(grand_grand) = grand.parent();
if let Some(expr) = grand_grand.cast::<ast::Expr>();
- if let Some(callee) = match expr {
- ast::Expr::FuncCall(call) => call.callee().as_untyped().cast(),
+ if let Some(ast::Expr::Ident(callee)) = match expr {
+ ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::Set(set) => Some(set.target()),
_ => None,
};
// Find metadata about the function.
- if let Some(Value::Func(func)) = world.library().scope.get(&callee);
+ if let Some(Value::Func(func)) = world.library().global.scope().get(&callee);
if let Some(info) = func.info();
then { (info, named) }
else { return None; }
@@ -103,8 +103,8 @@ fn font_family_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<String> {
if matches!(parent.kind(), SyntaxKind::Args);
if let Some(grand) = parent.parent();
if let Some(expr) = grand.cast::<ast::Expr>();
- if let Some(callee) = match expr {
- ast::Expr::FuncCall(call) => call.callee().as_untyped().cast(),
+ if let Some(ast::Expr::Ident(callee)) = match expr {
+ ast::Expr::FuncCall(call) => Some(call.callee()),
ast::Expr::Set(set) => Some(set.target()),
_ => None,
};
diff --git a/src/model/eval.rs b/src/model/eval.rs
index 67c733ce..6de328bc 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -2,7 +2,7 @@
use std::collections::BTreeMap;
use std::mem;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use comemo::{Track, Tracked};
use unicode_segmentation::UnicodeSegmentation;
@@ -32,9 +32,9 @@ pub fn eval(
) -> SourceResult<Module> {
// Prevent cyclic evaluation.
let id = source.id();
+ let path = if id.is_detached() { Path::new("") } else { world.source(id).path() };
if route.contains(id) {
- let path = world.source(id).path().display();
- panic!("Tried to cyclicly evaluate {}", path);
+ panic!("Tried to cyclicly evaluate {}", path.display());
}
// Hook up the lang items.
@@ -43,7 +43,7 @@ pub fn eval(
// Evaluate the module.
let route = unsafe { Route::insert(route, id) };
- let scopes = Scopes::new(Some(&library.scope));
+ let scopes = Scopes::new(Some(library));
let mut vm = Vm::new(world, route.track(), id, scopes, 0);
let result = source.ast()?.eval(&mut vm);
@@ -53,7 +53,8 @@ pub fn eval(
}
// Assemble the module.
- Ok(Module::evaluated(source.path(), vm.scopes.top, result?))
+ let name = path.file_stem().unwrap_or_default().to_string_lossy();
+ Ok(Module::new(name).with_scope(vm.scopes.top).with_content(result?))
}
/// A virtual machine.
@@ -521,7 +522,7 @@ impl Eval for ast::Math {
.map(|expr| expr.eval_in_math(vm))
.collect::<SourceResult<_>>()?;
let block = self.block();
- Ok((vm.items.math)(Content::sequence(seq), block))
+ Ok((vm.items.math_formula)(Content::sequence(seq), block))
}
}
@@ -608,11 +609,11 @@ impl Eval for ast::Ident {
impl ast::Ident {
fn eval_in_math(&self, vm: &mut Vm) -> SourceResult<Content> {
if self.as_untyped().len() == self.len()
- && matches!(vm.scopes.get(self), Ok(Value::Func(_)) | Err(_))
+ && matches!(vm.scopes.get_in_math(self), Ok(Value::Func(_)) | Err(_))
{
Ok((vm.items.symbol)(EcoString::from(self.get()) + ":op".into()))
} else {
- Ok(self.eval(vm)?.display_in_math())
+ Ok(vm.scopes.get_in_math(self).at(self.span())?.clone().display_in_math())
}
}
}
@@ -933,7 +934,13 @@ impl Eval for ast::FuncCall {
impl ast::FuncCall {
fn eval_in_math(&self, vm: &mut Vm) -> SourceResult<Content> {
- let callee = self.callee().eval(vm)?;
+ let callee = match self.callee() {
+ ast::Expr::Ident(ident) => {
+ vm.scopes.get_in_math(&ident).at(ident.span())?.clone()
+ }
+ expr => expr.eval(vm)?,
+ };
+
if let Value::Func(callee) = callee {
let args = self.args().eval(vm)?;
Ok(Self::eval_call(vm, &callee, args, self.span())?.display_in_math())
diff --git a/src/model/library.rs b/src/model/library.rs
index 54eeeb5b..a64b0263 100644
--- a/src/model/library.rs
+++ b/src/model/library.rs
@@ -4,7 +4,7 @@ use std::num::NonZeroUsize;
use once_cell::sync::OnceCell;
-use super::{Content, NodeId, Scope, StyleChain, StyleMap, Vt};
+use super::{Content, Module, NodeId, StyleChain, StyleMap, Vt};
use crate::diag::SourceResult;
use crate::doc::Document;
use crate::geom::{Abs, Dir};
@@ -14,7 +14,9 @@ use crate::util::{hash128, EcoString};
#[derive(Debug, Clone, Hash)]
pub struct Library {
/// The scope containing definitions that are available everywhere.
- pub scope: Scope,
+ pub global: Module,
+ /// The scope containing definitions available in math mode.
+ pub math: Module,
/// The default properties for page size, font selection and so on.
pub styles: StyleMap,
/// Defines which standard library items fulfill which syntactical roles.
@@ -66,7 +68,7 @@ pub struct LangItems {
/// An item in a term list: `/ Term: Details`.
pub term_item: fn(term: Content, description: Content) -> Content,
/// A mathematical formula: `$x$`, `$ x^2 $`.
- pub math: fn(body: Content, block: bool) -> Content,
+ pub math_formula: fn(body: Content, block: bool) -> Content,
/// A subsection in a math formula that is surrounded by matched delimiters:
/// `[x + y]`.
pub math_delimited: fn(body: Content) -> Content,
@@ -106,7 +108,7 @@ impl Hash for LangItems {
self.list_item.hash(state);
self.enum_item.hash(state);
self.term_item.hash(state);
- self.math.hash(state);
+ self.math_formula.hash(state);
self.math_atom.hash(state);
self.math_script.hash(state);
self.math_frac.hash(state);
diff --git a/src/model/module.rs b/src/model/module.rs
index ba6c76fb..6a1c60a5 100644
--- a/src/model/module.rs
+++ b/src/model/module.rs
@@ -1,5 +1,4 @@
use std::fmt::{self, Debug, Formatter};
-use std::path::Path;
use std::sync::Arc;
use super::{Content, Scope, Value};
@@ -22,7 +21,7 @@ struct Repr {
}
impl Module {
- /// Create a new, empty module with the given `name`.
+ /// Create a new module.
pub fn new(name: impl Into<EcoString>) -> Self {
Self(Arc::new(Repr {
name: name.into(),
@@ -31,10 +30,16 @@ impl Module {
}))
}
- /// Create a new module from an evalauted file.
- pub fn evaluated(path: &Path, scope: Scope, content: Content) -> Self {
- let name = path.file_stem().unwrap_or_default().to_string_lossy().into();
- Self(Arc::new(Repr { name, scope, content }))
+ /// Update the module's scope.
+ pub fn with_scope(mut self, scope: Scope) -> Self {
+ Arc::make_mut(&mut self.0).scope = scope;
+ self
+ }
+
+ /// Update the module's content.
+ pub fn with_content(mut self, content: Content) -> Self {
+ Arc::make_mut(&mut self.0).content = content;
+ self
}
/// Get the module's name.
@@ -47,6 +52,11 @@ impl Module {
&self.0.scope
}
+ /// Access the module's scope, mutably.
+ pub fn scope_mut(&mut self) -> &mut Scope {
+ &mut Arc::make_mut(&mut self.0).scope
+ }
+
/// Try to access a definition in the module.
pub fn get(&self, name: &str) -> StrResult<&Value> {
self.scope().get(&name).ok_or_else(|| {
diff --git a/src/model/scope.rs b/src/model/scope.rs
index c54cf1b3..bb0d4684 100644
--- a/src/model/scope.rs
+++ b/src/model/scope.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
-use super::{Func, FuncType, Value};
+use super::{Func, FuncType, Library, Value};
use crate::diag::StrResult;
use crate::util::EcoString;
@@ -13,13 +13,13 @@ pub struct Scopes<'a> {
pub top: Scope,
/// The stack of lower scopes.
pub scopes: Vec<Scope>,
- /// The base scope.
- pub base: Option<&'a Scope>,
+ /// The standard library.
+ pub base: Option<&'a Library>,
}
impl<'a> Scopes<'a> {
/// Create a new, empty hierarchy of scopes.
- pub fn new(base: Option<&'a Scope>) -> Self {
+ pub fn new(base: Option<&'a Library>) -> Self {
Self { top: Scope::new(), scopes: vec![], base }
}
@@ -39,7 +39,16 @@ impl<'a> Scopes<'a> {
pub fn get(&self, var: &str) -> StrResult<&Value> {
Ok(std::iter::once(&self.top)
.chain(self.scopes.iter().rev())
- .chain(self.base.into_iter())
+ .chain(self.base.map(|base| base.global.scope()))
+ .find_map(|scope| scope.get(var))
+ .ok_or("unknown variable")?)
+ }
+
+ /// Try to access a variable immutably from within a math formula.
+ pub fn get_in_math(&self, var: &str) -> StrResult<&Value> {
+ Ok(std::iter::once(&self.top)
+ .chain(self.scopes.iter().rev())
+ .chain(self.base.map(|base| base.math.scope()))
.find_map(|scope| scope.get(var))
.ok_or("unknown variable")?)
}
@@ -50,10 +59,9 @@ impl<'a> Scopes<'a> {
.chain(&mut self.scopes.iter_mut().rev())
.find_map(|scope| scope.get_mut(var))
.ok_or_else(|| {
- if self.base.map_or(false, |base| base.get(var).is_some()) {
- "cannot mutate a constant"
- } else {
- "unknown variable"
+ match self.base.and_then(|base| base.global.scope().get(var)) {
+ Some(_) => "cannot mutate a constant",
+ _ => "unknown variable",
}
})?
}
@@ -61,17 +69,29 @@ impl<'a> Scopes<'a> {
/// A map from binding names to values.
#[derive(Default, Clone, Hash)]
-pub struct Scope(BTreeMap<EcoString, Slot>);
+pub struct Scope(BTreeMap<EcoString, Slot>, bool);
impl Scope {
/// Create a new empty scope.
pub fn new() -> Self {
- Self::default()
+ Self(BTreeMap::new(), false)
+ }
+
+ /// Create a new scope with duplication prevention.
+ pub fn deduplicating() -> Self {
+ Self(BTreeMap::new(), true)
}
/// Bind a value to a name.
pub fn define(&mut self, name: impl Into<EcoString>, value: impl Into<Value>) {
- self.0.insert(name.into(), Slot::new(value.into(), Kind::Normal));
+ let name = name.into();
+
+ #[cfg(debug_assertions)]
+ if self.1 && self.0.contains_key(&name) {
+ panic!("duplicate definition: {name}");
+ }
+
+ self.0.insert(name, Slot::new(value.into(), Kind::Normal));
}
/// Define a function through a native rust function.
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index ceda2d57..4bab0c42 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -1505,7 +1505,7 @@ node! {
impl SetRule {
/// The function to set style properties for.
- pub fn target(&self) -> Ident {
+ pub fn target(&self) -> Expr {
self.0.cast_first_match().expect("set rule is missing target")
}
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs
index 15839e18..07f53372 100644
--- a/src/syntax/parser.rs
+++ b/src/syntax/parser.rs
@@ -712,7 +712,14 @@ fn let_binding(p: &mut Parser) {
fn set_rule(p: &mut Parser) {
let m = p.marker();
p.assert(SyntaxKind::Set);
+
+ let m2 = p.marker();
p.expect(SyntaxKind::Ident);
+ while p.eat_if(SyntaxKind::Dot) {
+ p.expect(SyntaxKind::Ident);
+ p.wrap(m2, SyntaxKind::FieldAccess);
+ }
+
args(p);
if p.eat_if(SyntaxKind::If) {
code_expr(p);
diff --git a/tests/src/tests.rs b/tests/src/tests.rs
index 16dea380..ac3e4d85 100644
--- a/tests/src/tests.rs
+++ b/tests/src/tests.rs
@@ -186,10 +186,14 @@ fn library() -> Library {
lib.styles.set(TextNode::SIZE, TextSize(Abs::pt(10.0).into()));
// Hook up helpers into the global scope.
- lib.scope.def_func::<TestFunc>("test");
- lib.scope.def_func::<PrintFunc>("print");
- lib.scope.define("conifer", RgbaColor::new(0x9f, 0xEB, 0x52, 0xFF));
- lib.scope.define("forest", RgbaColor::new(0x43, 0xA1, 0x27, 0xFF));
+ lib.global.scope_mut().def_func::<TestFunc>("test");
+ lib.global.scope_mut().def_func::<PrintFunc>("print");
+ lib.global
+ .scope_mut()
+ .define("conifer", RgbaColor::new(0x9f, 0xEB, 0x52, 0xFF));
+ lib.global
+ .scope_mut()
+ .define("forest", RgbaColor::new(0x43, 0xA1, 0x27, 0xFF));
lib
}
diff --git a/tests/typ/layout/par.typ b/tests/typ/layout/par.typ
index aabe63ef..264209b8 100644
--- a/tests/typ/layout/par.typ
+++ b/tests/typ/layout/par.typ
@@ -25,7 +25,6 @@ Hello
// While we're at it, test the larger block spacing wins.
#set block(spacing: 0pt)
#show raw: set block(spacing: 15pt)
-#show math: set block(spacing: 7.5pt)
#show list: set block(spacing: 2.5pt)
```rust
diff --git a/tests/typ/math/matrix.typ b/tests/typ/math/matrix.typ
index 3d67800d..aa99bb1b 100644
--- a/tests/typ/math/matrix.typ
+++ b/tests/typ/math/matrix.typ
@@ -7,7 +7,7 @@ $ v = vec(1, 2+3, 4) $
$ binom(n, 1) = 1/2 n (n-1) $
---
-#set vec(delim: "|")
+#set math.vec(delim: "|")
$ vec(1, 2) $
---
@@ -19,8 +19,8 @@ $ f(x, y) := cases(
) $
---
-// Error: 17-20 expected "(", "[", "{", or "|"
-#set vec(delim: "%")
+// Error: 22-25 expected "(", "[", "{", "|", or "||"
+#set math.vec(delim: "%")
---
// Error: 9-12 missing argument: lower index
diff --git a/tests/typ/math/style.typ b/tests/typ/math/style.typ
index e249a45a..a8b9c7a5 100644
--- a/tests/typ/math/style.typ
+++ b/tests/typ/math/style.typ
@@ -1,6 +1,6 @@
#let part = $ a b A B $
-#let kinds = (serif, sans, cal, frak, mono, bb)
-#let modifiers = (v => v, italic, bold, v => italic(bold(v)))
+#let kinds = (math.serif, math.sans, math.cal, math.frak, math.mono, math.bb)
+#let modifiers = (v => v, math.italic, math.bold, v => math.italic(math.bold(v)))
#let cells = ([:triangle:nested:], [--], [`italic`], [`bold`], [both])
#for k in kinds {