diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-05-17 14:41:46 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-05-17 14:41:46 +0200 |
| commit | 551ea99d05166b0be50792f767ddd38b996e32fa (patch) | |
| tree | ec5e86a087e79e8c181c7d4b904216a775227e2d /src | |
| parent | 46aace78ac4ac1c075b9b1670dbb7372df1a0a82 (diff) | |
Show default values in documentation
Fixes #169
Fixes #1102
Diffstat (limited to 'src')
| -rw-r--r-- | src/eval/cast.rs | 6 | ||||
| -rw-r--r-- | src/eval/func.rs | 2 | ||||
| -rw-r--r-- | src/eval/value.rs | 2 | ||||
| -rw-r--r-- | src/geom/align.rs | 12 | ||||
| -rw-r--r-- | src/geom/axes.rs | 4 | ||||
| -rw-r--r-- | src/geom/corners.rs | 107 | ||||
| -rw-r--r-- | src/geom/rel.rs | 4 | ||||
| -rw-r--r-- | src/geom/sides.rs | 45 | ||||
| -rw-r--r-- | src/geom/stroke.rs | 54 | ||||
| -rw-r--r-- | src/syntax/parser.rs | 19 |
10 files changed, 153 insertions, 102 deletions
diff --git a/src/eval/cast.rs b/src/eval/cast.rs index b85d6e76..7ef2f1d0 100644 --- a/src/eval/cast.rs +++ b/src/eval/cast.rs @@ -230,6 +230,12 @@ impl<T: Cast> Cast for Option<T> { } } +impl<T: Into<Value>> From<Spanned<T>> for Value { + fn from(spanned: Spanned<T>) -> Self { + spanned.v.into() + } +} + impl<T: Into<Value>> From<Option<T>> for Value { fn from(v: Option<T>) -> Self { match v { diff --git a/src/eval/func.rs b/src/eval/func.rs index 75231fc9..a224c5b8 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -279,6 +279,8 @@ pub struct ParamInfo { pub docs: &'static str, /// Valid values for the parameter. pub cast: CastInfo, + /// Creates an instance of the parameter's default value. + pub default: Option<fn() -> Value>, /// Is the parameter positional? pub positional: bool, /// Is the parameter named? diff --git a/src/eval/value.rs b/src/eval/value.rs index bd612cce..36cda80b 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -54,7 +54,7 @@ pub enum Value { Styles(Styles), /// An array of values: `(1, "hi", 12cm)`. Array(Array), - /// A dictionary value: `(color: #f79143, pattern: dashed)`. + /// A dictionary value: `(a: 1, b: "hi")`. Dict(Dict), /// An executable function. Func(Func), diff --git a/src/geom/align.rs b/src/geom/align.rs index a15ec4e6..42fc493e 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -147,6 +147,10 @@ cast_from_value! { } cast_to_value! { + v: Axes<Align> => v.map(GenAlign::from).into() +} + +cast_to_value! { v: Axes<Option<GenAlign>> => match (v.x, v.y) { (Some(x), Some(y)) => Axes::new(x, y).into(), (Some(x), None) => x.into(), @@ -196,6 +200,14 @@ impl Fold for GenAlign { } } +impl Fold for Align { + type Output = Self; + + fn fold(self, _: Self::Output) -> Self::Output { + self + } +} + /// Utility struct to restrict a passed alignment value to the horizontal axis /// on cast. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] diff --git a/src/geom/axes.rs b/src/geom/axes.rs index 8bc2456a..511e6ff5 100644 --- a/src/geom/axes.rs +++ b/src/geom/axes.rs @@ -141,9 +141,9 @@ where { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if let Axes { x: Some(x), y: Some(y) } = - self.as_ref().map(|v| (v as &dyn Any).downcast_ref::<Align>()) + self.as_ref().map(|v| (v as &dyn Any).downcast_ref::<GenAlign>()) { - write!(f, "{:?}-{:?}", x, y) + write!(f, "{:?} + {:?}", x, y) } else if (&self.x as &dyn Any).is::<Abs>() { write!(f, "Size({:?}, {:?})", self.x, self.y) } else { diff --git a/src/geom/corners.rs b/src/geom/corners.rs index 26d4082b..20e9bed0 100644 --- a/src/geom/corners.rs +++ b/src/geom/corners.rs @@ -117,43 +117,47 @@ where } fn cast(mut value: Value) -> StrResult<Self> { + let keys = [ + "top-left", + "top-right", + "bottom-right", + "bottom-left", + "left", + "top", + "right", + "bottom", + "rest", + ]; + if let Value::Dict(dict) = &mut value { - let mut take = |key| dict.take(key).ok().map(T::cast).transpose(); - - let rest = take("rest")?; - let left = take("left")?.or_else(|| rest.clone()); - let top = take("top")?.or_else(|| rest.clone()); - let right = take("right")?.or_else(|| rest.clone()); - let bottom = take("bottom")?.or_else(|| rest.clone()); - let corners = Corners { - top_left: take("top-left")? - .or_else(|| top.clone()) - .or_else(|| left.clone()), - top_right: take("top-right")? - .or_else(|| top.clone()) - .or_else(|| right.clone()), - bottom_right: take("bottom-right")? - .or_else(|| bottom.clone()) - .or_else(|| right.clone()), - bottom_left: take("bottom-left")? - .or_else(|| bottom.clone()) - .or_else(|| left.clone()), - }; - - dict.finish(&[ - "top-left", - "top-right", - "bottom-right", - "bottom-left", - "left", - "top", - "right", - "bottom", - "rest", - ])?; - - Ok(corners) - } else if T::is(&value) { + if dict.iter().any(|(key, _)| keys.contains(&key.as_str())) { + let mut take = |key| dict.take(key).ok().map(T::cast).transpose(); + let rest = take("rest")?; + let left = take("left")?.or_else(|| rest.clone()); + let top = take("top")?.or_else(|| rest.clone()); + let right = take("right")?.or_else(|| rest.clone()); + let bottom = take("bottom")?.or_else(|| rest.clone()); + let corners = Corners { + top_left: take("top-left")? + .or_else(|| top.clone()) + .or_else(|| left.clone()), + top_right: take("top-right")? + .or_else(|| top.clone()) + .or_else(|| right.clone()), + bottom_right: take("bottom-right")? + .or_else(|| bottom.clone()) + .or_else(|| right.clone()), + bottom_left: take("bottom-left")? + .or_else(|| bottom.clone()) + .or_else(|| left.clone()), + }; + + dict.finish(&keys)?; + return Ok(corners); + } + } + + if T::is(&value) { Ok(Self::splat(Some(T::cast(value)?))) } else { <Self as Cast>::error(value) @@ -184,30 +188,27 @@ impl<T: Fold> Fold for Corners<Option<T>> { } } -impl<T> From<Corners<Option<T>>> for Value +impl<T> From<Corners<T>> for Value where T: PartialEq + Into<Value>, { - fn from(corners: Corners<Option<T>>) -> Self { + fn from(corners: Corners<T>) -> Self { if corners.is_uniform() { - if let Some(value) = corners.top_left { - return value.into(); - } + return corners.top_left.into(); } let mut dict = Dict::new(); - if let Some(top_left) = corners.top_left { - dict.insert("top-left".into(), top_left.into()); - } - if let Some(top_right) = corners.top_right { - dict.insert("top-right".into(), top_right.into()); - } - if let Some(bottom_right) = corners.bottom_right { - dict.insert("bottom-right".into(), bottom_right.into()); - } - if let Some(bottom_left) = corners.bottom_left { - dict.insert("bottom-left".into(), bottom_left.into()); - } + let mut handle = |key: &str, component: T| { + let value = component.into(); + if value != Value::None { + dict.insert(key.into(), value); + } + }; + + handle("top-left", corners.top_left); + handle("top-right", corners.top_right); + handle("bottom-right", corners.bottom_right); + handle("bottom-left", corners.bottom_left); Value::Dict(dict) } diff --git a/src/geom/rel.rs b/src/geom/rel.rs index 7288f380..aaa784f9 100644 --- a/src/geom/rel.rs +++ b/src/geom/rel.rs @@ -227,3 +227,7 @@ impl Fold for Rel<Length> { self } } + +cast_to_value! { + v: Rel<Abs> => v.map(Length::from).into() +} diff --git a/src/geom/sides.rs b/src/geom/sides.rs index d9a020da..a905a5f8 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -187,10 +187,10 @@ where } fn cast(mut value: Value) -> StrResult<Self> { + let keys = ["left", "top", "right", "bottom", "x", "y", "rest"]; if let Value::Dict(dict) = &mut value { - let mut try_cast = || -> StrResult<_> { + if dict.iter().any(|(key, _)| keys.contains(&key.as_str())) { let mut take = |key| dict.take(key).ok().map(T::cast).transpose(); - let rest = take("rest")?; let x = take("x")?.or_else(|| rest.clone()); let y = take("y")?.or_else(|| rest.clone()); @@ -201,13 +201,8 @@ where bottom: take("bottom")?.or_else(|| y.clone()), }; - dict.finish(&["left", "top", "right", "bottom", "x", "y", "rest"])?; - - Ok(sides) - }; - - if let Ok(res) = try_cast() { - return Ok(res); + dict.finish(&keys)?; + return Ok(sides); } } @@ -223,35 +218,31 @@ where } } -impl<T> From<Sides<Option<T>>> for Value +impl<T> From<Sides<T>> for Value where T: PartialEq + Into<Value>, { - fn from(sides: Sides<Option<T>>) -> Self { + fn from(sides: Sides<T>) -> Self { if sides.is_uniform() { - if let Some(value) = sides.left { - return value.into(); - } + return sides.left.into(); } let mut dict = Dict::new(); - if let Some(left) = sides.left { - dict.insert("left".into(), left.into()); - } - if let Some(top) = sides.top { - dict.insert("top".into(), top.into()); - } - if let Some(right) = sides.right { - dict.insert("right".into(), right.into()); - } - if let Some(bottom) = sides.bottom { - dict.insert("bottom".into(), bottom.into()); - } + let mut handle = |key: &str, component: T| { + let value = component.into(); + if value != Value::None { + dict.insert(key.into(), value); + } + }; + + handle("left", sides.left); + handle("top", sides.top); + handle("right", sides.right); + handle("bottom", sides.bottom); Value::Dict(dict) } } - impl<T: Resolve> Resolve for Sides<T> { type Output = Sides<T::Output>; diff --git a/src/geom/stroke.rs b/src/geom/stroke.rs index ead30cbb..6539922c 100644 --- a/src/geom/stroke.rs +++ b/src/geom/stroke.rs @@ -51,6 +51,35 @@ pub struct PartialStroke<T = Length> { pub miter_limit: Smart<Scalar>, } +impl<T> PartialStroke<T> { + /// Map the contained lengths with `f`. + pub fn map<F, U>(self, f: F) -> PartialStroke<U> + where + F: Fn(T) -> U, + { + PartialStroke { + paint: self.paint, + thickness: self.thickness.map(&f), + line_cap: self.line_cap, + line_join: self.line_join, + dash_pattern: self.dash_pattern.map(|pattern| { + pattern.map(|pattern| DashPattern { + array: pattern + .array + .into_iter() + .map(|l| match l { + DashLength::Length(v) => DashLength::Length(f(v)), + DashLength::LineWidth => DashLength::LineWidth, + }) + .collect(), + phase: f(pattern.phase), + }) + }), + miter_limit: self.miter_limit, + } + } +} + impl PartialStroke<Abs> { /// Unpack the stroke, filling missing fields from the `default`. pub fn unwrap_or(self, default: Stroke) -> Stroke { @@ -106,13 +135,13 @@ impl<T: Debug> Debug for PartialStroke<T> { } (Smart::Custom(paint), Smart::Auto) => paint.fmt(f), (Smart::Auto, Smart::Custom(thickness)) => thickness.fmt(f), - (Smart::Auto, Smart::Auto) => f.pad("<stroke>"), + (Smart::Auto, Smart::Auto) => f.pad("1pt + black"), } } else { write!(f, "(")?; let mut sep = ""; if let Smart::Custom(paint) = &paint { - write!(f, "{}color: {:?}", sep, paint)?; + write!(f, "{}paint: {:?}", sep, paint)?; sep = ", "; } if let Smart::Custom(thickness) = &thickness { @@ -176,7 +205,7 @@ impl Debug for LineJoin { } } -/// A line dash pattern +/// A line dash pattern. #[derive(Clone, Eq, PartialEq, Hash)] pub struct DashPattern<T = Length, DT = DashLength<T>> { /// The dash array. @@ -293,20 +322,12 @@ impl Resolve for DashPattern { cast_from_value! { PartialStroke: "stroke", thickness: Length => Self { - paint: Smart::Auto, thickness: Smart::Custom(thickness), - line_cap: Smart::Auto, - line_join: Smart::Auto, - dash_pattern: Smart::Auto, - miter_limit: Smart::Auto, + ..Default::default() }, color: Color => Self { paint: Smart::Custom(color.into()), - thickness: Smart::Auto, - line_cap: Smart::Auto, - line_join: Smart::Auto, - dash_pattern: Smart::Auto, - miter_limit: Smart::Auto, + ..Default::default() }, mut dict: Dict => { fn take<T: Cast<Value>>(dict: &mut Dict, key: &str) -> StrResult<Smart<T>> { @@ -320,7 +341,6 @@ cast_from_value! { let line_join = take::<LineJoin>(&mut dict, "join")?; let dash_pattern = take::<Option<DashPattern>>(&mut dict, "dash")?; let miter_limit = take::<f64>(&mut dict, "miter-limit")?; - dict.finish(&["paint", "thickness", "cap", "join", "dash", "miter-limit"])?; Self { @@ -359,7 +379,11 @@ impl Fold for PartialStroke<Abs> { line_cap: self.line_cap.or(outer.line_cap), line_join: self.line_join.or(outer.line_join), dash_pattern: self.dash_pattern.or(outer.dash_pattern), - miter_limit: self.miter_limit, + miter_limit: self.miter_limit.or(outer.miter_limit), } } } + +cast_to_value! { + v: PartialStroke<Abs> => v.map(Length::from).into() +} diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index 7fdba4bd..c7dbc936 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -18,7 +18,10 @@ pub fn parse(text: &str) -> SyntaxNode { /// This is only used for syntax highlighting. pub fn parse_code(text: &str) -> SyntaxNode { let mut p = Parser::new(text, 0, LexMode::Code); - code(&mut p, |_| false); + let m = p.marker(); + p.skip(); + code_exprs(&mut p, |_| false); + p.wrap_skipless(m, SyntaxKind::Code); p.finish().into_iter().next().unwrap() } @@ -511,8 +514,13 @@ fn maybe_wrap_in_math(p: &mut Parser, arg: Marker, named: Option<Marker>) { } } -fn code(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { +fn code(p: &mut Parser, stop: impl FnMut(SyntaxKind) -> bool) { let m = p.marker(); + code_exprs(p, stop); + p.wrap(m, SyntaxKind::Code); +} + +fn code_exprs(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { while !p.eof() && !stop(p.current()) { p.stop_at_newline(true); let prev = p.prev_end(); @@ -529,7 +537,6 @@ fn code(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { p.unexpected(); } } - p.wrap(m, SyntaxKind::Code); } fn code_expr(p: &mut Parser) { @@ -1474,10 +1481,14 @@ impl<'s> Parser<'s> { fn wrap(&mut self, m: Marker, kind: SyntaxKind) { self.unskip(); + self.wrap_skipless(m, kind); + self.skip(); + } + + fn wrap_skipless(&mut self, m: Marker, kind: SyntaxKind) { let from = m.0.min(self.nodes.len()); let children = self.nodes.drain(from..).collect(); self.nodes.push(SyntaxNode::inner(kind, children)); - self.skip(); } fn progress(&self, offset: usize) -> bool { |
