Skip to main content

css_ast/values/grid/
impls.rs

1use super::{GridTemplateColumnsStyleValue, GridTemplateRowsStyleValue};
2use crate::{AutoTrackList, CssAtomSet, KeywordValue, LineNameList, TrackList, Value};
3use css_parse::{Cursor, Parse, Parser, Result as ParserResult, T};
4
5// `grid-template-columns`/`grid-template-rows` share `none | <track-list> | <auto-track-list> |
6// subgrid <line-name-list>?`. The generated dispatch picks between `<track-list>` and
7// `<auto-track-list>` using a single-token peek with no backtracking, but the two grammars share
8// a valid prefix (both can start with a `<fixed-size>`-shaped track) and only diverge on whether
9// a `repeat(auto-fill|auto-fit, ...)` shows up later - something a single-token peek can't see.
10// Trying `<auto-track-list>` first via a checkpointing `try_parse` is safe (it can only succeed
11// when a literal auto-repeat is present, which `<track-list>` can never contain) and falls back
12// to `<track-list>` otherwise.
13macro_rules! impl_grid_template_axis_parse {
14	($ty:ident) => {
15		impl<'a> Parse<'a> for $ty<'a> {
16			fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
17			where
18				I: Iterator<Item = Cursor> + Clone,
19			{
20				if p.peek::<T![Ident]>() {
21					let c = p.peek_n(1);
22					if p.equals_atom(c.into(), &CssAtomSet::None) {
23						return Ok(Self::None(p.parse::<KeywordValue<'a, T![Ident]>>()?));
24					}
25					if p.equals_atom(c.into(), &CssAtomSet::Subgrid) {
26						let keyword = p.parse::<KeywordValue<'a, T![Ident]>>()?;
27						let names = p.parse_if_peek::<Value<'a, LineNameList<'a>>>()?;
28						return Ok(Self::Subgrid(keyword, names));
29					}
30					// Not `none`/`subgrid` - could still be a track keyword like `auto` or
31					// `min-content`, so fall through to the track-list attempts below.
32				}
33				if let Ok(auto_track_list) = p.try_parse::<Value<'a, AutoTrackList<'a>>>() {
34					return Ok(Self::AutoTrackList(auto_track_list));
35				}
36				Ok(Self::TrackList(p.parse::<Value<'a, TrackList<'a>>>()?))
37			}
38		}
39	};
40}
41
42impl_grid_template_axis_parse!(GridTemplateColumnsStyleValue);
43impl_grid_template_axis_parse!(GridTemplateRowsStyleValue);
44
45#[cfg(test)]
46mod tests {
47	use super::super::*;
48	use crate::CssAtomSet;
49	use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
50
51	#[test]
52	fn test_writes() {
53		assert_parse!(CssAtomSet::ATOMS, GridTemplateAreasStyleValue, "none");
54		assert_parse!(CssAtomSet::ATOMS, GridTemplateAreasStyleValue, r#""foo""bar""#);
55
56		assert_parse!(CssAtomSet::ATOMS, FlowToleranceStyleValue, "infinite");
57		assert_parse!(CssAtomSet::ATOMS, FlowToleranceStyleValue, "30px");
58	}
59
60	#[test]
61	fn test_grid_template_columns_and_rows() {
62		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "none");
63		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "100px 1fr");
64		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "[a] 100px [b] repeat(2,1fr) [c]");
65		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "repeat(auto-fill,minmax(100px,1fr))");
66		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "subgrid");
67		assert_parse!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "subgrid [a] [b c] repeat(2,[d])");
68
69		assert_parse!(CssAtomSet::ATOMS, GridTemplateRowsStyleValue, "none");
70		assert_parse!(CssAtomSet::ATOMS, GridTemplateRowsStyleValue, "minmax(min-content,1fr) fit-content(20%)");
71
72		assert_peek_false!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "");
73		assert_parse_error!(CssAtomSet::ATOMS, GridTemplateColumnsStyleValue, "1fr repeat(auto-fill,1fr)");
74	}
75
76	#[test]
77	fn test_grid_auto_columns_and_rows() {
78		assert_parse!(CssAtomSet::ATOMS, GridAutoColumnsStyleValue, "min-content");
79		assert_parse!(CssAtomSet::ATOMS, GridAutoColumnsStyleValue, "minmax(100px,1fr)");
80		assert_parse!(CssAtomSet::ATOMS, GridAutoColumnsStyleValue, "fit-content(20%)");
81		assert_parse!(CssAtomSet::ATOMS, GridAutoRowsStyleValue, "auto 1fr");
82	}
83
84	#[test]
85	fn test_grid_auto_flow() {
86		assert_parse!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "row");
87		assert_parse!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "column");
88		assert_parse!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "dense");
89		assert_parse!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "row dense");
90		assert_parse!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "column dense");
91		assert_peek_false!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "");
92		assert_peek_false!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "auto");
93		assert_parse_error!(CssAtomSet::ATOMS, GridAutoFlowStyleValue, "row column");
94	}
95}