mirror of
https://github.com/typst/typst
synced 2025-05-15 09:35:28 +08:00
131 lines
4.2 KiB
Rust
131 lines
4.2 KiB
Rust
use super::*;
|
|
use AxisKey::*;
|
|
|
|
|
|
/// An argument key which identifies a layouting axis.
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
pub enum AxisKey {
|
|
Generic(GenericAxis),
|
|
Specific(SpecificAxis),
|
|
}
|
|
|
|
impl AxisKey {
|
|
/// The generic version of this axis key in the given system of axes.
|
|
pub fn to_generic(self, axes: LayoutAxes) -> GenericAxis {
|
|
match self {
|
|
Generic(axis) => axis,
|
|
Specific(axis) => axis.to_generic(axes),
|
|
}
|
|
}
|
|
|
|
/// The specific version of this axis key in the given system of axes.
|
|
pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis {
|
|
match self {
|
|
Generic(axis) => axis.to_specific(axes),
|
|
Specific(axis) => axis,
|
|
}
|
|
}
|
|
}
|
|
|
|
key!(AxisKey, "axis",
|
|
"horizontal" | "h" => Specific(Horizontal),
|
|
"vertical" | "v" => Specific(Vertical),
|
|
"primary" | "p" => Generic(Primary),
|
|
"secondary" | "s" => Generic(Secondary),
|
|
);
|
|
|
|
key!(Direction, "direction",
|
|
"left-to-right" | "ltr" => LeftToRight,
|
|
"right-to-left" | "rtl" => RightToLeft,
|
|
"top-to-bottom" | "ttb" => TopToBottom,
|
|
"bottom-to-top" | "btt" => BottomToTop,
|
|
);
|
|
|
|
/// A map for storing extents along axes.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ExtentMap<E: ExpressionKind + Copy>(ConsistentMap<AxisKey, E>);
|
|
|
|
impl<E: ExpressionKind + Copy> ExtentMap<E> {
|
|
/// Parse an extent map from the function args.
|
|
///
|
|
/// If `all` is true other arguments will create an error, otherwise
|
|
/// they are left intact.
|
|
pub fn new(args: &mut FuncArgs, all: bool) -> ParseResult<ExtentMap<E>> {
|
|
let mut map = ConsistentMap::new();
|
|
|
|
for arg in args.iter_keys() {
|
|
let key = match arg.key.v.as_str() {
|
|
"width" | "w" => AxisKey::Specific(Horizontal),
|
|
"height" | "h" => AxisKey::Specific(Vertical),
|
|
"primary-size" | "ps" => AxisKey::Generic(Primary),
|
|
"secondary-size" | "ss" => AxisKey::Generic(Secondary),
|
|
|
|
_ => if all {
|
|
error!("expected dimension")
|
|
} else {
|
|
args.add_key_pair(arg);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
let e = E::from_expr(arg.value)?;
|
|
map.add(key, e)?;
|
|
}
|
|
|
|
Ok(ExtentMap(map))
|
|
}
|
|
|
|
/// Deduplicate from generic to specific axes.
|
|
pub fn dedup(&self, axes: LayoutAxes) -> LayoutResult<ConsistentMap<SpecificAxis, E>> {
|
|
self.0.dedup(|key, &val| Ok((key.to_specific(axes), val)))
|
|
}
|
|
}
|
|
|
|
/// An argument key which identifies an axis, but allows for positional
|
|
/// arguments with unspecified axes.
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
pub enum PosAxisKey {
|
|
/// The first positional argument.
|
|
First,
|
|
/// The second positional argument.
|
|
Second,
|
|
/// An axis keyword argument.
|
|
Keyword(AxisKey),
|
|
}
|
|
|
|
/// A map for storing some data for via keyword or positionally given axes.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct PosAxisMap<E: ExpressionKind + Copy>(ConsistentMap<PosAxisKey, E>);
|
|
|
|
impl<E: ExpressionKind + Copy> PosAxisMap<E> {
|
|
/// Parse a positional axis map from the function args.
|
|
pub fn new(args: &mut FuncArgs) -> ParseResult<PosAxisMap<E>> {
|
|
let mut map = ConsistentMap::new();
|
|
|
|
map.add_opt(PosAxisKey::First, args.get_pos_opt::<E>()?)?;
|
|
map.add_opt(PosAxisKey::Second, args.get_pos_opt::<E>()?)?;
|
|
|
|
for arg in args.iter_keys() {
|
|
let axis = AxisKey::from_ident(&arg.key)?;
|
|
let value = E::from_expr(arg.value)?;
|
|
|
|
map.add(PosAxisKey::Keyword(axis), value)?;
|
|
}
|
|
|
|
Ok(PosAxisMap(map))
|
|
}
|
|
|
|
/// Deduplicate from positional or specific to generic axes.
|
|
pub fn dedup<F>(&self, axes: LayoutAxes, f: F) -> LayoutResult<ConsistentMap<GenericAxis, E>>
|
|
where F: Fn(E) -> Option<GenericAxis> {
|
|
self.0.dedup(|key, &e| {
|
|
Ok((match key {
|
|
PosAxisKey::First => f(e).unwrap_or(Primary),
|
|
PosAxisKey::Second => f(e).unwrap_or(Secondary),
|
|
PosAxisKey::Keyword(AxisKey::Specific(axis)) => axis.to_generic(axes),
|
|
PosAxisKey::Keyword(AxisKey::Generic(axis)) => *axis,
|
|
}, e))
|
|
})
|
|
}
|
|
}
|