Skip to content

Commit

Permalink
implement white-space and friends
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Aug 5, 2023
1 parent 21f9763 commit 7b31b2d
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 6 deletions.
6 changes: 3 additions & 3 deletions crates/hdx_ast/src/css/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,9 +914,9 @@ properties! {
atom!("text-spacing-trim") => TextSpacingTrim<Expr<'a, Todo>> inherits=true,
atom!("text-transform") => TextTransform<Expr<'a, Todo>> inherits=true,
atom!("text-wrap") => TextWrap<Expr<'a, Todo>> inherits=true,
atom!("white-space") => WhiteSpace<Expr<'a, Todo>> inherits=true,
atom!("white-space-collapse") => WhiteSpaceCollapse<Expr<'a, Todo>> inherits=true,
atom!("white-space-trim") => WhiteSpaceTrim<Expr<'a, Todo>>,
atom!("white-space") => WhiteSpace<WhiteSpaceShorthand<'a>> inherits=true,
atom!("white-space-collapse") => WhiteSpaceCollapse<Expr<'a, WhiteSpaceCollapseValue>> inherits=true,
atom!("white-space-trim") => WhiteSpaceTrim<Expr<'a, WhiteSpaceTrimValue>>,
atom!("word-boundary-detection") => WordBoundaryDetection<Expr<'a, Todo>> inherits=true,
atom!("word-boundary-expansion") => WordBoundaryExpansion<Expr<'a, Todo>> inherits=true,
atom!("word-break") => WordBreak<Expr<'a, Todo>> inherits=true,
Expand Down
80 changes: 77 additions & 3 deletions crates/hdx_ast/src/css/values/text.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#[cfg(feature = "serde")]
use serde::Serialize;

use super::{Expr, Shorthand};
use crate::{atom, Atom, Atomizable};

// https://drafts.csswg.org/css-text/#text-align-property
// https://drafts.csswg.org/css-text-4/#propdef-text-align
#[derive(Atomizable, Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum TextAlignValue {
Expand All @@ -16,9 +17,10 @@ pub enum TextAlignValue {
Justify, // atom!("justify")
MatchParent, // atom!("match-parent")
JustifyAll, // atom!("justify-all")
// TODO: Custom?
}

// https://drafts.csswg.org/css-text/#text-align-all-property
// https://drafts.csswg.org/css-text-4/#propdef-text-align-all
#[derive(Atomizable, Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum TextAlignAllValue {
Expand All @@ -32,7 +34,7 @@ pub enum TextAlignAllValue {
MatchParent, // atom!("match-parent")
}

// https://drafts.csswg.org/css-text/#text-align-all-property
// https://drafts.csswg.org/css-text-4/#propdef-text-align-last
#[derive(Atomizable, Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum TextAlignLastValue {
Expand All @@ -46,3 +48,75 @@ pub enum TextAlignLastValue {
Justify, // atom!("justify")
MatchParent, // atom!("match-parent")
}

// https://drafts.csswg.org/css-text-4/#propdef-text-wrap
#[derive(Atomizable, Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum TextWrapValue {
#[default]
Wrap, // atom!("wrap")
Nowrap, // atom!("nowrap")
Balance, // atom!("balance")
Stable, // atom!("stable")
Pretty, // atom!("pretty")
}

// https://drafts.csswg.org/css-text-4/#propdef-white-space-collapse
#[derive(Atomizable, Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum WhiteSpaceCollapseValue {
#[default]
Collapse, // atom!("collapse")
Discard, // atom!("discard")
Preserve, // atom!("preserve")
PreserveBreaks, // atom!("preserve-breaks")
PreserveSpaces, // atom!("preserve-spaces")
BreakSpaces, // atom!("break-spaces")
}

// https://drafts.csswg.org/css-text-4/#propdef-white-space-trim
#[derive(Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum WhiteSpaceTrimValue {
#[default]
None,
Discard {
before: bool,
after: bool,
inner: bool,
},
}

// https://drafts.csswg.org/css-text-4/#propdef-white-space
#[derive(Default, Debug, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize), serde())]
pub enum WhiteSpaceShorthand<'a> {
#[default]
Normal,
Pre,
Nowrap,
PreWrap,
PreLine,
Expanded {
collapse: Shorthand<'a, Expr<'a, WhiteSpaceCollapseValue>>,
wrap: Shorthand<'a, Expr<'a, TextWrapValue>>,
trim: Shorthand<'a, Expr<'a, WhiteSpaceTrimValue>>,
},
}

#[cfg(test)]
mod tests {

use super::*;

#[test]
fn size_test() {
use std::mem::size_of;
assert_eq!(size_of::<TextAlignValue>(), 1);
assert_eq!(size_of::<TextAlignLastValue>(), 1);
assert_eq!(size_of::<TextWrapValue>(), 1);
assert_eq!(size_of::<WhiteSpaceTrimValue>(), 3);
assert_eq!(size_of::<WhiteSpaceCollapseValue>(), 1);
assert_eq!(size_of::<WhiteSpaceShorthand>(), 32);
}
}
3 changes: 3 additions & 0 deletions crates/hdx_parser/src/css/values/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod page_floats;
pub mod shorthand;
pub mod size_adjust;
pub mod sizing;
pub mod text;
pub mod text_decor;
pub mod ui;

Expand Down Expand Up @@ -63,7 +64,9 @@ parse_for_enums! {
TextAlignValue,
TextDecorationSkipInkValue,
TextDecorationStyleValue,
TextWrapValue,
VisibilityValue,
WhiteSpaceCollapseValue,
}

// TODO:
Expand Down
151 changes: 151 additions & 0 deletions crates/hdx_parser/src/css/values/text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use hdx_ast::css::values::{
Expr, Shorthand, TextWrapValue, WhiteSpaceCollapseValue, WhiteSpaceShorthand,
WhiteSpaceTrimValue,
};
use hdx_lexer::Kind;

use crate::{atom, diagnostics, Atomizable, Parse, Parser, Result, Spanned};

impl<'a> Parse<'a> for WhiteSpaceTrimValue {
fn parse(parser: &mut Parser<'a>) -> Result<Spanned<Self>> {
let span = parser.cur().span;
let mut inner = false;
let mut after = false;
let mut before = false;
loop {
match parser.cur().kind {
Kind::Ident => match parser.cur_atom_lower().unwrap() {
atom!("none") => {
parser.advance();
return Ok(Self::None.spanned(span));
}
atom!("discard-inner") => {
parser.advance();
inner = true;
}
atom!("discard-after") => {
parser.advance();
after = true;
}
atom!("discard-before") => {
parser.advance();
before = true;
}
_ => break,
},
_ => break,
}
if inner && after && before {
break;
}
}
Ok(Self::Discard { inner, after, before }.spanned(span.up_to(&parser.cur().span)))
}
}

impl<'a> Parse<'a> for WhiteSpaceShorthand<'a> {
fn parse(parser: &mut Parser<'a>) -> Result<Spanned<Self>> {
let span = parser.cur().span;
if parser.at(Kind::Ident) {
match parser.cur_atom_lower().unwrap() {
//normal | pre | nowrap | pre-wrap | pre-line
atom!("normal") => {
parser.advance();
return Ok(Self::Normal.spanned(span));
}
atom!("pre") => {
parser.advance();
return Ok(Self::Pre.spanned(span));
}
atom!("nowrap") => {
parser.advance();
return Ok(Self::Nowrap.spanned(span));
}
atom!("pre-wrap") => {
parser.advance();
return Ok(Self::PreWrap.spanned(span));
}
atom!("pre-line") => {
parser.advance();
return Ok(Self::PreLine.spanned(span));
}
_ => {}
}
}
let mut collapse = Shorthand::Implicit;
let mut wrap = Shorthand::Implicit;
let mut trim = Shorthand::Implicit;
loop {
match parser.cur().kind {
Kind::Semicolon | Kind::Comma | Kind::Eof => {
break;
}
Kind::Ident => {
let ident = parser.cur_atom_lower().unwrap();
if collapse.is_implicit()
&& WhiteSpaceCollapseValue::from_atom(ident.clone()).is_some()
{
let node = Expr::<WhiteSpaceCollapseValue>::parse(parser)?;
collapse = Shorthand::Explicit(parser.boxup(node));
} else if wrap.is_implicit()
&& TextWrapValue::from_atom(ident.clone()).is_some()
{
let node = Expr::<TextWrapValue>::parse(parser)?;
wrap = Shorthand::Explicit(parser.boxup(node));
} else if trim.is_implicit()
&& matches!(
ident,
atom!("none")
| atom!("discard-inner") | atom!("discard-after")
| atom!("discard-before")
) {
let node = Expr::<WhiteSpaceTrimValue>::parse(parser)?;
trim = Shorthand::Explicit(parser.boxup(node));
} else {
Err(diagnostics::UnexpectedIdent(ident.clone(), parser.cur().span))?
}
}
k => {
let checkpoint = parser.checkpoint();
if collapse.is_implicit() {
let node = Expr::<WhiteSpaceCollapseValue>::parse(parser);
match node {
Ok(node) => {
collapse = Shorthand::Explicit(parser.boxup(node));
continue;
}
Err(_) => parser.rewind(checkpoint),
}
}
let checkpoint = parser.checkpoint();
if wrap.is_implicit() {
let node = Expr::<TextWrapValue>::parse(parser);
match node {
Ok(node) => {
wrap = Shorthand::Explicit(parser.boxup(node));
continue;
}
Err(_) => parser.rewind(checkpoint),
}
}
let checkpoint = parser.checkpoint();
if trim.is_implicit() {
let node = Expr::<WhiteSpaceTrimValue>::parse(parser);
match node {
Ok(node) => {
trim = Shorthand::Explicit(parser.boxup(node));
continue;
}
Err(_) => parser.rewind(checkpoint),
}
}
Err(diagnostics::Unexpected(k, parser.cur().span))?
}
}
if collapse.is_explicit() && wrap.is_explicit() && trim.is_explicit() {
break;
}
}
Ok(Self::Expanded { collapse, wrap, trim }.spanned(span.up_to(&parser.cur().span)))
}
}
3 changes: 3 additions & 0 deletions crates/hdx_writer/src/css/values/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod page_floats;
mod shorthand;
mod size_adjust;
mod sizing;
mod text;
mod text_decor;
mod ui;

Expand Down Expand Up @@ -60,7 +61,9 @@ write_atomizable_values! {
TextAlignValue,
TextDecorationSkipInkValue,
TextDecorationStyleValue,
TextWrapValue,
VisibilityValue,
WhiteSpaceCollapseValue,
}

impl<'a> WriteCss<'a> for TimeOrAuto {
Expand Down
59 changes: 59 additions & 0 deletions crates/hdx_writer/src/css/values/text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use hdx_ast::css::values::{text::*, Shorthand};

use crate::{CssWriter, Result, WriteCss};

impl<'a> WriteCss<'a> for WhiteSpaceTrimValue {
fn write_css<W: CssWriter>(&self, sink: &mut W) -> Result {
match self {
Self::None => sink.write_str("none"),
Self::Discard { inner, after, before } => {
if *inner {
sink.write_str("discard-inner")?;
if *before {
sink.write_char(' ')?;
}
}
if *before {
sink.write_str("discard-before")?;
if *after {
sink.write_char(' ')?;
}
}
if *after {
sink.write_str("discard-after")?;
}
Ok(())
}
}
}
}

impl<'a> WriteCss<'a> for WhiteSpaceShorthand<'a> {
fn write_css<W: CssWriter>(&self, sink: &mut W) -> Result {
match self {
Self::Normal => sink.write_str("normal")?,
Self::Pre => sink.write_str("pre")?,
Self::Nowrap => sink.write_str("nowrap")?,
Self::PreWrap => sink.write_str("pre-wrap")?,
Self::PreLine => sink.write_str("pre-line")?,
Self::Expanded { collapse, trim, wrap } => {
if let Shorthand::Explicit(value) = collapse {
value.write_css(sink)?;
if trim.is_explicit() {
sink.write_char(' ')?;
}
}
if let Shorthand::Explicit(value) = trim {
value.write_css(sink)?;
if wrap.is_explicit() {
sink.write_char(' ')?;
}
}
if let Shorthand::Explicit(value) = wrap {
value.write_css(sink)?;
}
}
}
Ok(())
}
}

0 comments on commit 7b31b2d

Please sign in to comment.