Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Zero's core is the `num()` function, which provides flexible number formatting.
decimal-separator: str = ".",
product: content = sym.times,
tight: bool = false,
breakable: bool | dict = false,
math: bool = true,

omit-unity-mantissa: bool = false,
Expand All @@ -128,6 +129,7 @@ Zero's core is the `num()` function, which provides flexible number formatting.
- `decimal-separator: str = "."` : Specifies the marker that is used for separating integer and decimal part.
- `product: content = sym.times` : Specifies the multiplication symbol used for scientific notation.
- `tight: bool = false` : If true, tight spacing is applied between operands (applies to $\times$ and $\pm$).
- `breakable: bool | dict` : Whether numbers and quantities can be broken across paragraph lines. Setting this to `true`/`false` entirely enables/disables breaking. For more fine-grained control, a dictionary with the keys `uncertainty`, `power`, and `unit` (all booleans) can be passed for specifying whether breaks are allowed after the ± symbol, the × symbol, or before the unit, respectively.
- `math: bool = true` : If set to `false`, the parts of the number won't be wrapped in a `math.equation`. This makes it possible to use `num()` with non-math fonts.
- `omit-unity-mantissa: bool = false` : Determines whether a mantissa of 1 is omitted in scientific notation, e.g., $10^4$ instead of $1\cdot 10^4$.
- `positive-sign: bool = false` : If set to `true`, positive coefficients are shown with a $+$ sign.
Expand Down Expand Up @@ -409,7 +411,6 @@ The appearance of units can be configured via `set-unit`:
#set-unit(
unit-separator: content = sym.space.thin,
fraction: str = "power",
breakable: bool = false,
prefix: auto | none = auto
)
```
Expand All @@ -418,7 +419,6 @@ The appearance of units can be configured via `set-unit`:
- `"power"` : Units with negative exponents are shown as powers.
- `"fraction"` : When units with negative exponents are present, a fraction is created and the concerned units are put in the denominator.
- `"inline"` : An inline fraction is created.
- `breakable: bool` : Whether units and quantities can be broken across paragraph lines.
- `prefix: auto | none` : When set to `auto` and `num.exponent` is set to `"eng"`, a metric prefix is displayed along with the unit, replacing the exponent, e.g., `zi.m[2e4]` will render as 20km.

These options are also available when instancing a quantity, e.g., `#zi.m(fraction: "inline")[2.5]`.
Expand Down
46 changes: 38 additions & 8 deletions src/formatting.typ
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,19 @@
}


#let nonbreaking-binary-class(body, tight: false, breakable: true) = {
let space = if tight { 0pt } else { 2em/9 }

if breakable {
math.class("binary", body)
} else {
// Recover spacing of binary relations but without breakability
h(space) + math.class("normal", body) + h(space)
}
}

#let format-uncertainty = it => {
/// pm, digits, mode, concise, tight, math
/// pm, digits, mode, concise, tight, math, breakable
let pm = it.pm
if pm == none { return () }
let is-symmetric = type(pm.first()) != array
Expand Down Expand Up @@ -206,18 +216,26 @@
decimal-separator: it.decimal-separator,
)))
if is-symmetric {
if it.concise { ("(", pm.first(), ")") } else if it.math {
if it.concise {
("(", pm.first(), ")")
} else if it.math {
(
math.class("normal", none),
math.class(if it.tight { "normal" } else { "binary" }, sym.plus.minus),
nonbreaking-binary-class(
sym.plus.minus,
tight: it.tight,
breakable: it.breakable.uncertainty
),
pm.first(),
)
} else {
let space = if not it.tight { sym.space.thin }
let space = if it.tight { sym.space.hair } else { sym.space.thin }
(
space,
sym.wj,
sym.plus.minus,
space,
if not it.breakable.uncertainty { sym.wj },
pm.first(),
)
}
Expand All @@ -231,6 +249,7 @@
)
} else {
(
sym.wj,
non-math-attach(
none,
t: "+" + pm.at(0),
Expand All @@ -243,7 +262,7 @@


#let format-power = it => {
/// x, base, product, positive-sign-exponent, tight, math
/// x, base, product, positive-sign-exponent, tight, math, breakable
if it.exponent == none { return () }

let (sign, integer, fractional) = decompose-signed-float-numeral(it.exponent)
Expand All @@ -262,19 +281,24 @@
if it.product == none { (power,) } else {
(
box(),
math.class(if it.tight { "normal" } else { "binary" }, it.product),
nonbreaking-binary-class(
it.product,
tight: it.tight,
breakable: it.breakable.power
),
power,
)
}
} else {
let power = non-math-attach([#it.base], t: [#exponent])
if it.product == none { (power,) } else {
let space = if not it.tight { sym.space.thin }
let space = if it.tight { sym.space.hair } else { sym.space.thin }
(
box(),
space,
sym.wj,
it.product,
space,
if not it.breakable.power { sym.wj },
power,
)
}
Expand All @@ -284,6 +308,7 @@


#let show-num-impl = it => {
let breakable = utility.process-breakable(it.breakable)
/// sign, int, frac, e, pm,
/// digits
/// omit-unity-mantissa, uncertainty-mode, positive-sign
Expand Down Expand Up @@ -321,6 +346,7 @@
math: it.math,
mode: it.uncertainty-mode,
decimal-separator: it.decimal-separator,
breakable: breakable
)


Expand All @@ -332,6 +358,7 @@
tight: it.tight,
math: it.math,
decimal-separator: it.decimal-separator,
breakable: breakable
)

let integer-part = (
Expand All @@ -349,6 +376,9 @@
)

let uncertainty-part = format-uncertainty(uncertainty)
if not breakable.uncertainty and uncertainty-part.len() != 0{
// uncertainty-part = (std.box(equation-from-items(uncertainty-part)),)
}

if concise-uncertainty {
fractional-part += uncertainty-part
Expand Down
2 changes: 1 addition & 1 deletion src/state.typ
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
fixed: none,
exponent: auto,
trim-zeros: false,
breakable: false,
group: (
size: 3,
separator: sym.space.thin,
Expand All @@ -30,7 +31,6 @@
unit: (
unit-separator: sym.space.thin,
fraction: "power",
breakable: false,
use-sqrt: true,
prefix: auto,
lowercase-liter: false,
Expand Down
69 changes: 26 additions & 43 deletions src/units.typ
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,15 @@
/// Unprocessed arguments.
..args,
) = {
assert(
fraction in ("power", "fraction", "inline"),
message: "Invalid fraction: "
+ fraction
+ ". Expected \"power\", \"fraction\", or \"inline\"",
)

let fold-units = fold-units.with(
unit-separator: unit-separator,
unit-separator: unit-separator + sym.wj,
math: math,
use-sqrt: use-sqrt,
)
Expand All @@ -200,45 +207,32 @@
let denominator-content = fold-units(..denominator, denom-exp-multiplier)

if fraction == "power" {
// Numerator may be empty!
// Numerator could be empty!
let result = denominator-content
if numerator.len() != 0 {
result = numerator-content + unit-separator + result
result = numerator-content + unit-separator + sym.wj + result
}
return if math { $result$ } else { result }
}

// For the two fractional modes, the numerator shall not be empty.
if numerator.len() == 0 { numerator-content = $1$ }

if fraction == "fraction" {
if not math {
assert(
false,
"`math: false` cannot be used together with `fraction: \"fraction\"`",
)
if math {
if denominator.len() > 1 and fraction == "inline" {
denominator-content = $(#denominator-content)$
}
return $#numerator-content/#denominator-content$
} else if fraction == "inline" {
set std.math.frac(style: "horizontal") if fraction == "inline"
$#numerator-content/#denominator-content$
} else {
if denominator.len() > 1 {
denominator-content = "(" + denominator-content + ")"
denominator-content = [(#denominator-content)]
}

if math {
$#numerator-content#h(0pt)\/#h(0pt)#denominator-content$
} else {
numerator-content + "/" + denominator-content
}
} else {
assert(
false,
message: "Invalid fraction: "
+ fraction
+ ". Expected \"power\", \"fraction\", or \"symbol\"",
)
numerator-content + "/" + denominator-content
}
}


#let unit(
unit,
..args,
Expand All @@ -249,19 +243,12 @@
}
let num-state = update-num-state(num-state.get(), args)

let result = show-unit(
let result = (show-unit(
unit.numerator,
unit.denominator,
..num-state.unit,
math: num-state.math,
)
if not num-state.unit.breakable {
if num-state.math {
result = $result$
} else {
result = box(result)
}
}
))
result
}

Expand Down Expand Up @@ -319,26 +306,22 @@
unit.numerator.first().first() = prefix + unit.numerator.first().first()
}
}
let breakable = utility.process-breakable(num-state.breakable)

let result = {
num(value, state: num-state, force-parentheses-around-uncertainty: true)
sym.wj
separator
show-unit(
if not breakable.unit { sym.wj }
box(show-unit(
unit.numerator,
unit.denominator,
fraction: num-state.unit.fraction,
unit-separator: num-state.unit.unit-separator,
math: num-state.math,
)
))
}

if not num-state.unit.breakable {
if num-state.math {
result = $result$
} else {
result = box(result)
}
}
result
}

Expand Down
24 changes: 24 additions & 0 deletions src/utility.typ
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,27 @@
#assert.eq(shift-decimal-left("123", "456", digits: -5), ("12345600", ""))
#assert.eq(shift-decimal-left("0", "0012", digits: -4), ("12", ""))
#assert.eq(shift-decimal-left("0", "0012", digits: -2), ("0", "12"))


#let process-breakable(breakable) = {
let default = (
uncertainty: false,
power: false,
unit: false,
)

if breakable == false {
return default
}
if breakable == true {
return (
uncertainty: true,
power: true,
unit: true,
)
}
if type(breakable) == dictionary {
return default + breakable
}
assert(false)
}
5 changes: 5 additions & 0 deletions tests/breakable/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# generated by tytanic, do not edit

/diff/
/out/
/ref/
Loading
Loading