mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Introduce fr
s
This commit is contained in:
parent
9983634cd5
commit
73fa2eda2c
@ -18,7 +18,7 @@ use std::rc::Rc;
|
||||
use crate::cache::Cache;
|
||||
use crate::color::Color;
|
||||
use crate::diag::{Diag, DiagSet, Pass};
|
||||
use crate::geom::{Angle, Length, Relative};
|
||||
use crate::geom::{Angle, Fractional, Length, Relative};
|
||||
use crate::loading::{FileHash, Loader};
|
||||
use crate::parse::parse;
|
||||
use crate::syntax::visit::Visit;
|
||||
@ -250,6 +250,7 @@ impl Eval for Expr {
|
||||
Self::Length(_, v, unit) => Value::Length(Length::with_unit(v, unit)),
|
||||
Self::Angle(_, v, unit) => Value::Angle(Angle::with_unit(v, unit)),
|
||||
Self::Percent(_, v) => Value::Relative(Relative::new(v / 100.0)),
|
||||
Self::Fractional(_, v) => Value::Fractional(Fractional::new(v)),
|
||||
Self::Color(_, v) => Value::Color(Color::Rgba(v)),
|
||||
Self::Str(_, ref v) => Value::Str(v.clone()),
|
||||
Self::Ident(ref v) => match ctx.scopes.get(&v) {
|
||||
|
@ -11,6 +11,7 @@ pub fn pos(value: Value) -> Value {
|
||||
Length(v) => Length(v),
|
||||
Angle(v) => Angle(v),
|
||||
Relative(v) => Relative(v),
|
||||
Fractional(v) => Fractional(v),
|
||||
Linear(v) => Linear(v),
|
||||
_ => Error,
|
||||
}
|
||||
@ -24,6 +25,7 @@ pub fn neg(value: Value) -> Value {
|
||||
Length(v) => Length(-v),
|
||||
Angle(v) => Angle(-v),
|
||||
Relative(v) => Relative(-v),
|
||||
Fractional(v) => Fractional(-v),
|
||||
Linear(v) => Linear(-v),
|
||||
_ => Error,
|
||||
}
|
||||
@ -44,6 +46,7 @@ pub fn add(lhs: Value, rhs: Value) -> Value {
|
||||
(Relative(a), Length(b)) => Linear(a + b),
|
||||
(Relative(a), Relative(b)) => Relative(a + b),
|
||||
(Relative(a), Linear(b)) => Linear(a + b),
|
||||
(Fractional(a), Fractional(b)) => Fractional(a + b),
|
||||
(Linear(a), Length(b)) => Linear(a + b),
|
||||
(Linear(a), Relative(b)) => Linear(a + b),
|
||||
(Linear(a), Linear(b)) => Linear(a + b),
|
||||
@ -84,6 +87,7 @@ pub fn sub(lhs: Value, rhs: Value) -> Value {
|
||||
(Relative(a), Length(b)) => Linear(a - b),
|
||||
(Relative(a), Relative(b)) => Relative(a - b),
|
||||
(Relative(a), Linear(b)) => Linear(a - b),
|
||||
(Fractional(a), Fractional(b)) => Fractional(a - b),
|
||||
(Linear(a), Length(b)) => Linear(a - b),
|
||||
(Linear(a), Relative(b)) => Linear(a - b),
|
||||
(Linear(a), Linear(b)) => Linear(a - b),
|
||||
@ -108,8 +112,13 @@ pub fn mul(lhs: Value, rhs: Value) -> Value {
|
||||
(Float(a), Angle(b)) => Angle(a * b),
|
||||
(Relative(a), Int(b)) => Relative(a * b as f64),
|
||||
(Relative(a), Float(b)) => Relative(a * b),
|
||||
(Fractional(a), Fractional(b)) => Fractional(a * b.get()),
|
||||
(Fractional(a), Int(b)) => Fractional(a * b as f64),
|
||||
(Fractional(a), Float(b)) => Fractional(a * b),
|
||||
(Int(a), Relative(b)) => Relative(a as f64 * b),
|
||||
(Int(a), Fractional(b)) => Fractional(a as f64 * b),
|
||||
(Float(a), Relative(b)) => Relative(a * b),
|
||||
(Float(a), Fractional(b)) => Fractional(a * b),
|
||||
(Linear(a), Int(b)) => Linear(a * b as f64),
|
||||
(Linear(a), Float(b)) => Linear(a * b),
|
||||
(Int(a), Linear(b)) => Linear(a as f64 * b),
|
||||
@ -134,6 +143,9 @@ pub fn div(lhs: Value, rhs: Value) -> Value {
|
||||
(Relative(a), Int(b)) => Relative(a / b as f64),
|
||||
(Relative(a), Float(b)) => Relative(a / b),
|
||||
(Relative(a), Relative(b)) => Float(a / b),
|
||||
(Fractional(a), Fractional(b)) => Float(a.get() / b.get()),
|
||||
(Fractional(a), Int(b)) => Fractional(a / b as f64),
|
||||
(Fractional(a), Float(b)) => Fractional(a / b),
|
||||
(Linear(a), Int(b)) => Linear(a / b as f64),
|
||||
(Linear(a), Float(b)) => Linear(a / b),
|
||||
_ => Error,
|
||||
|
@ -8,7 +8,7 @@ use std::rc::Rc;
|
||||
use super::EvalContext;
|
||||
use crate::color::{Color, RgbaColor};
|
||||
use crate::exec::ExecContext;
|
||||
use crate::geom::{Angle, Length, Linear, Relative};
|
||||
use crate::geom::{Angle, Fractional, Length, Linear, Relative};
|
||||
use crate::syntax::{Expr, Span, Spanned, Tree};
|
||||
|
||||
/// A computational value.
|
||||
@ -28,6 +28,8 @@ pub enum Value {
|
||||
Angle(Angle),
|
||||
/// A relative value: `50%`.
|
||||
Relative(Relative),
|
||||
/// A fractional value: `1fr`.
|
||||
Fractional(Fractional),
|
||||
/// A combination of an absolute length and a relative value: `20% + 5cm`.
|
||||
Linear(Linear),
|
||||
/// A color value: `#f79143ff`.
|
||||
@ -75,6 +77,7 @@ impl Value {
|
||||
Self::Length(_) => Length::TYPE_NAME,
|
||||
Self::Angle(_) => Angle::TYPE_NAME,
|
||||
Self::Relative(_) => Relative::TYPE_NAME,
|
||||
Self::Fractional(_) => Fractional::TYPE_NAME,
|
||||
Self::Linear(_) => Linear::TYPE_NAME,
|
||||
Self::Color(_) => Color::TYPE_NAME,
|
||||
Self::Str(_) => String::TYPE_NAME,
|
||||
@ -601,6 +604,7 @@ primitive! {
|
||||
primitive! { Length: "length", Value::Length }
|
||||
primitive! { Angle: "angle", Value::Angle }
|
||||
primitive! { Relative: "relative", Value::Relative }
|
||||
primitive! { Fractional: "fractional", Value::Fractional }
|
||||
primitive! {
|
||||
Linear: "linear",
|
||||
Value::Linear,
|
||||
|
101
src/geom/fr.rs
Normal file
101
src/geom/fr.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use decorum::N64;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A fractional length.
|
||||
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Fractional(N64);
|
||||
|
||||
impl Fractional {
|
||||
/// Takes up zero space: `0fr`.
|
||||
pub fn zero() -> Self {
|
||||
Self(N64::from(0.0))
|
||||
}
|
||||
|
||||
/// Takes up as much space as all other items with this fractional size: `1fr`.
|
||||
pub fn one() -> Self {
|
||||
Self(N64::from(1.0))
|
||||
}
|
||||
|
||||
/// Create a new fractional value.
|
||||
pub fn new(ratio: f64) -> Self {
|
||||
Self(N64::from(ratio))
|
||||
}
|
||||
|
||||
/// Get the underlying ratio.
|
||||
pub fn get(self) -> f64 {
|
||||
self.0.into()
|
||||
}
|
||||
|
||||
/// Whether the ratio is zero.
|
||||
pub fn is_zero(self) -> bool {
|
||||
self.0 == 0.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Fractional {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}fr", self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Fractional {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Fractional {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self {
|
||||
Self(-self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Fractional {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
sub_impl!(Fractional - Fractional -> Fractional);
|
||||
|
||||
impl Mul<f64> for Fractional {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, other: f64) -> Self {
|
||||
Self(self.0 * other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Fractional> for f64 {
|
||||
type Output = Fractional;
|
||||
|
||||
fn mul(self, other: Fractional) -> Fractional {
|
||||
other * self
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f64> for Fractional {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, other: f64) -> Self {
|
||||
Self(self.0 / other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for Fractional {
|
||||
type Output = f64;
|
||||
|
||||
fn div(self, other: Self) -> f64 {
|
||||
self.get() / other.get()
|
||||
}
|
||||
}
|
||||
|
||||
assign_impl!(Fractional += Fractional);
|
||||
assign_impl!(Fractional -= Fractional);
|
||||
assign_impl!(Fractional *= f64);
|
||||
assign_impl!(Fractional /= f64);
|
@ -5,6 +5,7 @@ mod macros;
|
||||
mod align;
|
||||
mod angle;
|
||||
mod dir;
|
||||
mod fr;
|
||||
mod gen;
|
||||
mod length;
|
||||
mod linear;
|
||||
@ -18,6 +19,7 @@ mod spec;
|
||||
pub use align::*;
|
||||
pub use angle::*;
|
||||
pub use dir::*;
|
||||
pub use fr::*;
|
||||
pub use gen::*;
|
||||
pub use length::*;
|
||||
pub use linear::*;
|
||||
|
@ -335,6 +335,7 @@ fn literal(p: &mut Parser) -> Option<Expr> {
|
||||
Token::Length(val, unit) => Expr::Length(span, val, unit),
|
||||
Token::Angle(val, unit) => Expr::Angle(span, val, unit),
|
||||
Token::Percent(p) => Expr::Percent(span, p),
|
||||
Token::Fraction(p) => Expr::Fractional(span, p),
|
||||
Token::Color(color) => Expr::Color(span, color),
|
||||
Token::Str(token) => Expr::Str(span, {
|
||||
if !token.terminated {
|
||||
|
@ -393,6 +393,7 @@ impl<'s> Tokens<'s> {
|
||||
// Otherwise parse into the fitting numeric type.
|
||||
let build = match suffix {
|
||||
"%" => Token::Percent,
|
||||
"fr" => Token::Fraction,
|
||||
"pt" => |x| Token::Length(x, LengthUnit::Pt),
|
||||
"mm" => |x| Token::Length(x, LengthUnit::Mm),
|
||||
"cm" => |x| Token::Length(x, LengthUnit::Cm),
|
||||
@ -880,6 +881,7 @@ mod tests {
|
||||
|
||||
let suffixes = [
|
||||
("%", Percent as fn(f64) -> Token<'static>),
|
||||
("fr", Fraction as fn(f64) -> Token<'static>),
|
||||
("mm", |x| Length(x, LengthUnit::Mm)),
|
||||
("pt", |x| Length(x, LengthUnit::Pt)),
|
||||
("cm", |x| Length(x, LengthUnit::Cm)),
|
||||
|
@ -4,7 +4,7 @@ use std::fmt::{self, Arguments, Write};
|
||||
|
||||
use crate::color::{Color, RgbaColor};
|
||||
use crate::eval::*;
|
||||
use crate::geom::{Angle, Length, Linear, Relative};
|
||||
use crate::geom::{Angle, Fractional, Length, Linear, Relative};
|
||||
use crate::syntax::*;
|
||||
|
||||
/// Pretty print an item and return the resulting string.
|
||||
@ -192,6 +192,7 @@ impl Pretty for Expr {
|
||||
Self::Length(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
|
||||
Self::Angle(_, v, u) => write!(p, "{}{}", v, u).unwrap(),
|
||||
Self::Percent(_, v) => write!(p, "{}%", v).unwrap(),
|
||||
Self::Fractional(_, v) => write!(p, "{}fr", v).unwrap(),
|
||||
Self::Color(_, v) => v.pretty(p),
|
||||
Self::Str(_, v) => v.pretty(p),
|
||||
Self::Ident(v) => v.pretty(p),
|
||||
@ -456,6 +457,7 @@ impl Pretty for Value {
|
||||
Value::Length(v) => v.pretty(p),
|
||||
Value::Angle(v) => v.pretty(p),
|
||||
Value::Relative(v) => v.pretty(p),
|
||||
Value::Fractional(v) => v.pretty(p),
|
||||
Value::Linear(v) => v.pretty(p),
|
||||
Value::Color(v) => v.pretty(p),
|
||||
Value::Str(v) => v.pretty(p),
|
||||
@ -575,6 +577,7 @@ pretty_display! {
|
||||
Length,
|
||||
Angle,
|
||||
Relative,
|
||||
Fractional,
|
||||
Linear,
|
||||
RgbaColor,
|
||||
Color,
|
||||
@ -659,6 +662,7 @@ mod tests {
|
||||
roundtrip("{10pt}");
|
||||
roundtrip("{14.1deg}");
|
||||
roundtrip("{20%}");
|
||||
roundtrip("{0.5fr}");
|
||||
roundtrip("{#abcdef}");
|
||||
roundtrip(r#"{"hi"}"#);
|
||||
test_parse(r#"{"let's \" go"}"#, r#"{"let's \" go"}"#);
|
||||
@ -725,6 +729,7 @@ mod tests {
|
||||
test_value(Angle::deg(90.0), "90deg");
|
||||
test_value(Relative::one() / 2.0, "50%");
|
||||
test_value(Relative::new(0.3) + Length::cm(2.0), "30% + 2cm");
|
||||
test_value(Fractional::one() * 7.55, "7.55fr");
|
||||
test_value(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101");
|
||||
test_value("hello", r#""hello""#);
|
||||
test_value("\n", r#""\n""#);
|
||||
|
@ -24,6 +24,8 @@ pub enum Expr {
|
||||
/// _Note_: `50%` is stored as `50.0` here, but as `0.5` in the
|
||||
/// corresponding [value](crate::geom::Relative).
|
||||
Percent(Span, f64),
|
||||
/// A fraction unit literal: `1fr`.
|
||||
Fractional(Span, f64),
|
||||
/// A color literal: `#ffccee`.
|
||||
Color(Span, RgbaColor),
|
||||
/// A string literal: `"hello!"`.
|
||||
@ -73,6 +75,7 @@ impl Expr {
|
||||
Self::Length(span, _, _) => span,
|
||||
Self::Angle(span, _, _) => span,
|
||||
Self::Percent(span, _) => span,
|
||||
Self::Fractional(span, _) => span,
|
||||
Self::Color(span, _) => span,
|
||||
Self::Str(span, _) => span,
|
||||
Self::Ident(ref v) => v.span,
|
||||
|
@ -133,6 +133,8 @@ pub enum Token<'s> {
|
||||
/// _Note_: `50%` is stored as `50.0` here, as in the corresponding
|
||||
/// [literal](super::Expr::Percent).
|
||||
Percent(f64),
|
||||
/// A fraction unit: `3fr`.
|
||||
Fraction(f64),
|
||||
/// A color value: `#20d82a`.
|
||||
Color(RgbaColor),
|
||||
/// A quoted string: `"..."`.
|
||||
@ -258,6 +260,7 @@ impl<'s> Token<'s> {
|
||||
Self::Length(_, _) => "length",
|
||||
Self::Angle(_, _) => "angle",
|
||||
Self::Percent(_) => "percentage",
|
||||
Self::Fraction(_) => "`fr` value",
|
||||
Self::Color(_) => "color",
|
||||
Self::Str(_) => "string",
|
||||
Self::LineComment(_) => "line comment",
|
||||
|
@ -80,6 +80,7 @@ visit! {
|
||||
Expr::Length(_, _, _) => {}
|
||||
Expr::Angle(_, _, _) => {}
|
||||
Expr::Percent(_, _) => {}
|
||||
Expr::Fractional(_, _) => {}
|
||||
Expr::Color(_, _) => {}
|
||||
Expr::Str(_, _) => {}
|
||||
Expr::Ident(_) => {}
|
||||
|
@ -10,7 +10,7 @@
|
||||
// Test math operators.
|
||||
|
||||
// Test plus and minus.
|
||||
#for v in (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt) {
|
||||
#for v in (1, 3.14, 12pt, 45deg, 90%, 13% + 10pt, 6.3fr) {
|
||||
// Test plus.
|
||||
test(+v, v)
|
||||
|
||||
|
@ -275,6 +275,10 @@
|
||||
"name": "constant.numeric.percentage.typst",
|
||||
"match": "\\b(\\d*)?\\.?\\d+([eE][+-]?\\d+)?%"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.fr.typst",
|
||||
"match": "\\b(\\d*)?\\.?\\d+([eE][+-]?\\d+)?fr"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.integer.typst",
|
||||
"match": "\\b\\d+\\b"
|
||||
|
Loading…
x
Reference in New Issue
Block a user