Math operator functions

This commit is contained in:
Laurenz 2023-01-22 13:32:06 +01:00
parent c5ef350cce
commit a0146b5b9b
2 changed files with 156 additions and 1 deletions

View File

@ -7,9 +7,11 @@ mod align;
mod atom;
mod braced;
mod frac;
mod group;
mod fragment;
mod matrix;
mod op;
mod root;
mod row;
mod script;
mod spacing;
mod stretch;
@ -54,6 +56,8 @@ pub fn define(scope: &mut Scope) {
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");
@ -70,6 +74,7 @@ pub fn define(scope: &mut Scope) {
scope.define("med", HNode::strong(MEDIUM).pack());
scope.define("thick", HNode::strong(THICK).pack());
scope.define("quad", HNode::strong(QUAD).pack());
define_operators(scope);
}
/// # Math

150
library/src/math/op.rs Normal file
View File

@ -0,0 +1,150 @@
use typst::model::Scope;
use super::*;
/// # Text Operator
/// A text operator in a math formula.
///
/// ## Parameters
/// - text: EcoString (positional, required)
/// The operator's text.
/// - limits: bool (named)
/// Whether the operator should display sub- and superscripts as limits.
///
/// Defaults to `true`.
///
/// ## Category
/// math
#[func]
#[capable(LayoutMath)]
#[derive(Debug, Hash)]
pub struct OpNode {
/// The operator's text.
pub text: EcoString,
/// Whether the operator should display sub- and superscripts as limits.
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> {
Ok(Self {
text: args.expect("text")?,
limits: args.named("limits")?.unwrap_or(true),
}
.pack())
}
}
impl LayoutMath for OpNode {
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
let frame = ctx.layout_non_math(&TextNode(self.text.clone()).pack())?;
ctx.push(FrameFragment {
frame,
class: MathClass::Large,
limits: self.limits,
});
Ok(())
}
}
/// 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("liminf", true).pack());
scope.define("limsup", OpNode::new("limsup", 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())
}
}
/// # 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())
}
}