mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Extend math library
This commit is contained in:
parent
e1c0cda6c8
commit
11c7ceb29e
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1027,7 +1027,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "symmie"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/typst/symmie#8504bf7ec0d8996d160832c2724ba024ab6e988a"
|
||||
source = "git+https://github.com/typst/symmie#6280fb20455cb63e6886ba5bb35b95a4b376da68"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
@ -51,10 +51,22 @@ fn scope() -> Scope {
|
||||
// Math.
|
||||
std.def_node::<math::MathNode>("math");
|
||||
std.def_node::<math::AtomNode>("atom");
|
||||
std.def_node::<math::AccNode>("acc");
|
||||
std.def_node::<math::FracNode>("frac");
|
||||
std.def_node::<math::BinomNode>("binom");
|
||||
std.def_node::<math::SqrtNode>("sqrt");
|
||||
std.def_node::<math::FloorNode>("floor");
|
||||
std.def_node::<math::CeilNode>("ceil");
|
||||
std.def_node::<math::VecNode>("vec");
|
||||
std.def_node::<math::CasesNode>("cases");
|
||||
std.def_node::<math::SerifNode>("serif");
|
||||
std.def_node::<math::SansNode>("sans");
|
||||
std.def_node::<math::BoldNode>("bold");
|
||||
std.def_node::<math::ItalNode>("ital");
|
||||
std.def_node::<math::CalNode>("cal");
|
||||
std.def_node::<math::FrakNode>("frak");
|
||||
std.def_node::<math::MonoNode>("mono");
|
||||
std.def_node::<math::BbNode>("bb");
|
||||
|
||||
// Layout.
|
||||
std.def_node::<layout::PageNode>("page");
|
||||
|
84
library/src/math/matrix.rs
Normal file
84
library/src/math/matrix.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use super::*;
|
||||
|
||||
/// A column vector in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct VecNode(Vec<Content>);
|
||||
|
||||
#[node(Texify)]
|
||||
impl VecNode {
|
||||
/// The kind of delimiter.
|
||||
pub const DELIM: Delimiter = Delimiter::Paren;
|
||||
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.all()?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for VecNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
let kind = match t.styles.get(Self::DELIM) {
|
||||
Delimiter::Paren => "pmatrix",
|
||||
Delimiter::Bracket => "bmatrix",
|
||||
Delimiter::Brace => "Bmatrix",
|
||||
Delimiter::Bar => "vmatrix",
|
||||
};
|
||||
|
||||
t.push_str("\\begin{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
for component in &self.0 {
|
||||
component.texify(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector / matrix delimiter.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Delimiter {
|
||||
Paren,
|
||||
Bracket,
|
||||
Brace,
|
||||
Bar,
|
||||
}
|
||||
|
||||
castable! {
|
||||
Delimiter,
|
||||
Expected: "type of bracket or bar",
|
||||
Value::Str(s) => match s.as_str() {
|
||||
"(" => Self::Paren,
|
||||
"[" => Self::Bracket,
|
||||
"{" => Self::Brace,
|
||||
"|" => Self::Bar,
|
||||
_ => Err("expected \"(\", \"[\", \"{\", or \"|\"")?,
|
||||
},
|
||||
}
|
||||
|
||||
/// A case distinction in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct CasesNode(Vec<Content>);
|
||||
|
||||
#[node(Texify)]
|
||||
impl CasesNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.all()?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for CasesNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\begin{cases}");
|
||||
for component in &self.0 {
|
||||
component.texify(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{cases}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
//! Mathematical formulas.
|
||||
|
||||
mod matrix;
|
||||
mod style;
|
||||
mod tex;
|
||||
|
||||
pub use self::matrix::*;
|
||||
pub use self::style::*;
|
||||
|
||||
use typst::model::{Guard, SequenceNode};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
@ -272,6 +277,79 @@ impl Texify for AtomNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// An accented node.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct AccNode {
|
||||
/// The accent base.
|
||||
pub base: Content,
|
||||
/// The Unicode accent character.
|
||||
pub accent: char,
|
||||
}
|
||||
|
||||
#[node(Texify)]
|
||||
impl AccNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
let base = args.expect("base")?;
|
||||
let Spanned { v, span } = args.expect::<Spanned<Content>>("accent")?;
|
||||
let accent = match extract(&v) {
|
||||
Some(Ok(c)) => c,
|
||||
Some(Err(msg)) => bail!(span, "{}", msg),
|
||||
None => bail!(span, "not an accent"),
|
||||
};
|
||||
Ok(Self { base, accent }.pack())
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn extract(content: &Content) -> Option<Result<char, &'static str>> {
|
||||
let MathNode { children, .. } = content.to::<MathNode>()?;
|
||||
let [child] = children.as_slice() else { return None };
|
||||
let c = if let Some(atom) = child.to::<AtomNode>() {
|
||||
let mut chars = atom.0.chars();
|
||||
chars.next().filter(|_| chars.next().is_none())?
|
||||
} else if let Some(symbol) = child.to::<SymbolNode>() {
|
||||
match symmie::get(&symbol.0) {
|
||||
Some(c) => c,
|
||||
None => return Some(Err("unknown symbol")),
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(Ok(match c {
|
||||
'`' | '\u{300}' => '\u{300}', // Grave
|
||||
'´' | '\u{301}' => '\u{301}', // Acute
|
||||
'^' | '\u{302}' => '\u{302}', // Circumflex
|
||||
'~' | '\u{223C}' | '\u{303}' => '\u{303}', // Tilde
|
||||
'¯' | '\u{304}' => '\u{304}', // Macron
|
||||
'‾' | '\u{305}' => '\u{305}', // Overline
|
||||
'˘' | '\u{306}' => '\u{306}', // Breve
|
||||
'.' | '\u{22C5}' | '\u{307}' => '\u{307}', // Dot
|
||||
'¨' | '\u{308}' => '\u{308}', // Diaeresis
|
||||
'ˇ' | '\u{30C}' => '\u{30C}', // Caron
|
||||
'→' | '\u{20D7}' => '\u{20D7}', // Arrow
|
||||
_ => return None,
|
||||
}))
|
||||
}
|
||||
|
||||
impl Texify for AccNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
if let Some(sym) = unicode_math::SYMBOLS.iter().find(|sym| {
|
||||
sym.codepoint == self.accent
|
||||
&& sym.atom_type == unicode_math::AtomType::Accent
|
||||
}) {
|
||||
t.push_str("\\");
|
||||
t.push_str(sym.name);
|
||||
t.push_str("{");
|
||||
self.base.texify(t)?;
|
||||
t.push_str("}");
|
||||
} else {
|
||||
self.base.texify(t)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A fraction in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct FracNode {
|
||||
@ -301,6 +379,35 @@ impl Texify for FracNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A binomial in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct BinomNode {
|
||||
/// The upper index.
|
||||
pub upper: Content,
|
||||
/// The lower index.
|
||||
pub lower: Content,
|
||||
}
|
||||
|
||||
#[node(Texify)]
|
||||
impl BinomNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
let upper = args.expect("upper index")?;
|
||||
let lower = args.expect("lower index")?;
|
||||
Ok(Self { upper, lower }.pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for BinomNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\binom{");
|
||||
self.upper.texify(t)?;
|
||||
t.push_str("}{");
|
||||
self.lower.texify(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A sub- and/or superscript in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct ScriptNode {
|
||||
@ -348,7 +455,7 @@ impl Texify for AlignNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A square root.
|
||||
/// A square root in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct SqrtNode(Content);
|
||||
|
||||
@ -362,91 +469,48 @@ impl SqrtNode {
|
||||
impl Texify for SqrtNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\sqrt{");
|
||||
self.0.texify_unparen(t)?;
|
||||
self.0.texify(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A column vector.
|
||||
/// A floored expression in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct VecNode(Vec<Content>);
|
||||
pub struct FloorNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl VecNode {
|
||||
/// The kind of delimiter.
|
||||
pub const DELIM: Delimiter = Delimiter::Paren;
|
||||
|
||||
impl FloorNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.all()?).pack())
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for VecNode {
|
||||
impl Texify for FloorNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
let kind = match t.styles.get(Self::DELIM) {
|
||||
Delimiter::Paren => "pmatrix",
|
||||
Delimiter::Bracket => "bmatrix",
|
||||
Delimiter::Brace => "Bmatrix",
|
||||
Delimiter::Bar => "vmatrix",
|
||||
};
|
||||
|
||||
t.push_str("\\begin{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
for component in &self.0 {
|
||||
component.texify_unparen(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
t.push_str("\\left\\lfloor ");
|
||||
self.0.texify(t)?;
|
||||
t.push_str("\\right\\rfloor ");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector / matrix delimiter.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Delimiter {
|
||||
Paren,
|
||||
Bracket,
|
||||
Brace,
|
||||
Bar,
|
||||
}
|
||||
|
||||
castable! {
|
||||
Delimiter,
|
||||
Expected: "type of bracket or bar",
|
||||
Value::Str(s) => match s.as_str() {
|
||||
"(" => Self::Paren,
|
||||
"[" => Self::Bracket,
|
||||
"{" => Self::Brace,
|
||||
"|" => Self::Bar,
|
||||
_ => Err("expected \"(\", \"[\", \"{\", or \"|\"")?,
|
||||
},
|
||||
}
|
||||
|
||||
/// A case distinction.
|
||||
/// A ceiled expression in a mathematical formula.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct CasesNode(Vec<Content>);
|
||||
pub struct CeilNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl CasesNode {
|
||||
impl CeilNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.all()?).pack())
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for CasesNode {
|
||||
impl Texify for CeilNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\begin{cases}");
|
||||
for component in &self.0 {
|
||||
component.texify_unparen(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{cases}");
|
||||
t.push_str("\\left\\lceil ");
|
||||
self.0.texify(t)?;
|
||||
t.push_str("\\right\\rceil ");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
161
library/src/math/style.rs
Normal file
161
library/src/math/style.rs
Normal file
@ -0,0 +1,161 @@
|
||||
use super::*;
|
||||
|
||||
/// Serif (roman) font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct SerifNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl SerifNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for SerifNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathrm{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sans-serif font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct SansNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl SansNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for SansNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathsf{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Bold font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct BoldNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl BoldNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for BoldNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathbf{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Italic font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct ItalNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl ItalNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for ItalNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathit{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Calligraphic font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct CalNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl CalNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for CalNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathcal{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Fraktur font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct FrakNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl FrakNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for FrakNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathfrak{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Monospace font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct MonoNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl MonoNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for MonoNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathtt{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Blackboard bold (double-struck) font style.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct BbNode(Content);
|
||||
|
||||
#[node(Texify)]
|
||||
impl BbNode {
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
Ok(Self(args.expect("body")?).pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for BbNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\mathbb{");
|
||||
self.0.texify_unparen(t)?;
|
||||
t.push_str("}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -125,6 +125,10 @@ impl Backend for FrameBackend {
|
||||
}
|
||||
|
||||
fn rule(&mut self, pos: Cursor, width: f64, height: f64) {
|
||||
if height == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.frame.push(
|
||||
self.transform(pos) + Point::with_y(Abs::pt(height) / 2.0),
|
||||
Element::Shape(Shape {
|
||||
|
@ -434,7 +434,7 @@ impl Eval for ast::MathNode {
|
||||
Self::Expr(v) => {
|
||||
if let ast::Expr::Ident(ident) = v {
|
||||
if self.as_untyped().len() == ident.len()
|
||||
&& !vm.scopes.get(ident).is_ok()
|
||||
&& matches!(vm.scopes.get(ident), Ok(Value::Func(_)) | Err(_))
|
||||
{
|
||||
let node = (vm.items.symbol)(ident.get().clone() + ":op".into());
|
||||
return Ok(node.spanned(self.span()));
|
||||
|
@ -7,6 +7,10 @@ pub fn applicable(target: &Content, styles: StyleChain) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
if target.has::<dyn Show>() && target.is_pristine() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find out how many recipes there are.
|
||||
let mut n = styles.recipes().count();
|
||||
|
||||
|
BIN
tests/ref/math/accents.png
Normal file
BIN
tests/ref/math/accents.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 8.1 KiB |
BIN
tests/ref/math/style.png
Normal file
BIN
tests/ref/math/style.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
28
tests/typ/math/accents.typ
Normal file
28
tests/typ/math/accents.typ
Normal file
@ -0,0 +1,28 @@
|
||||
// Test math accents.
|
||||
|
||||
---
|
||||
#set page(width: auto)
|
||||
|
||||
$ acc(a,`),
|
||||
acc(a,´),
|
||||
acc(a,\^),
|
||||
acc(a,~),
|
||||
acc(a,¯),
|
||||
acc(a,‾),
|
||||
acc(a,˘),
|
||||
acc(a,.),
|
||||
acc(a,¨),
|
||||
acc(a,ˇ),
|
||||
acc(a,->) $
|
||||
|
||||
$ acc(a, grave),
|
||||
acc(a, acute),
|
||||
acc(a, circum),
|
||||
acc(a, tilde),
|
||||
acc(a, macron),
|
||||
acc(a, overline),
|
||||
acc(a, breve),
|
||||
acc(a, dot),
|
||||
acc(a, dia),
|
||||
acc(a, caron),
|
||||
acc(a, arrow) $
|
@ -4,12 +4,11 @@
|
||||
$ v = vec(1, 2+3, 4) $
|
||||
|
||||
---
|
||||
#set vec(delim: "|")
|
||||
$ vec(1, 2) $
|
||||
$ binom(n, 1) = 1/2 n (n-1) $
|
||||
|
||||
---
|
||||
// Error: 17-20 expected "(", "[", "{", or "|"
|
||||
#set vec(delim: "%")
|
||||
#set vec(delim: "|")
|
||||
$ vec(1, 2) $
|
||||
|
||||
---
|
||||
$ f(x, y) := cases(
|
||||
@ -18,3 +17,11 @@ $ f(x, y) := cases(
|
||||
3 "if" x "is even",
|
||||
4 "else",
|
||||
) $
|
||||
|
||||
---
|
||||
// Error: 17-20 expected "(", "[", "{", or "|"
|
||||
#set vec(delim: "%")
|
||||
|
||||
---
|
||||
// Error: 9-12 missing argument: lower index
|
||||
$ binom(x^2) $
|
||||
|
@ -11,9 +11,13 @@ $ a^2 + b^2 = c^2 $
|
||||
Prove by induction:
|
||||
$ sum_(k=0)^n k = (n(n+1))/2 $
|
||||
|
||||
---
|
||||
We know that:
|
||||
$ floor(x/2) <= ceil(x/2) $
|
||||
|
||||
---
|
||||
// Test that blackboard style looks nice.
|
||||
$ f: NN arrow RR $
|
||||
$ f: NN -> RR $
|
||||
|
||||
---
|
||||
// Error: 1:3 expected dollar sign
|
||||
|
15
tests/typ/math/style.typ
Normal file
15
tests/typ/math/style.typ
Normal file
@ -0,0 +1,15 @@
|
||||
#let part = $ a b A B $
|
||||
#let kinds = (serif, sans, cal, frak, mono, bb)
|
||||
#let modifiers = (v => v, ital, bold, v => ital(bold(v)))
|
||||
|
||||
#let cells = ([:triangle:nested:], [--], [`ital`], [`bold`], [both])
|
||||
#for k in kinds {
|
||||
cells.push(raw(repr(k).trim("<function ").trim(">")))
|
||||
for m in modifiers {
|
||||
cells.push($ #m(#k(part)) $)
|
||||
}
|
||||
}
|
||||
|
||||
#set page(width: auto)
|
||||
#set par(align: center)
|
||||
#table(columns: 1 + modifiers.len(), ..cells)
|
Loading…
x
Reference in New Issue
Block a user