diff --git a/src/atrule/media.rs b/src/atrule/media.rs new file mode 100644 index 0000000..ec6a93a --- /dev/null +++ b/src/atrule/media.rs @@ -0,0 +1,69 @@ +use std::fmt; + +use crate::{parse::Stmt, selector::Selector}; + +#[derive(Debug, Clone)] +pub(crate) struct MediaRule { + pub super_selector: Selector, + pub query: String, + pub body: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub(crate) struct MediaQuery { + /// The modifier, probably either "not" or "only". + /// + /// This may be `None` if no modifier is in use. + pub modifier: Option, + + /// The media type, for example "screen" or "print". + /// + /// This may be `None`. If so, `self.features` will not be empty. + pub media_type: Option, + + /// Feature queries, including parentheses. + pub features: Vec, +} + +#[allow(dead_code)] +impl MediaQuery { + pub fn is_condition(&self) -> bool { + self.modifier.is_none() && self.media_type.is_none() + } + + pub fn matches_all_types(&self) -> bool { + self.media_type.is_none() + || self + .media_type + .as_ref() + .map_or(false, |v| v.to_ascii_lowercase() == "all") + } + + pub fn condition(features: Vec) -> Self { + Self { + modifier: None, + media_type: None, + features, + } + } + + #[allow(dead_code, unused_variables)] + pub fn merge(other: &Self) -> Self { + todo!() + } +} + +impl fmt::Display for MediaQuery { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(modifier) = &self.modifier { + f.write_str(modifier)?; + } + if let Some(media_type) = &self.media_type { + f.write_str(media_type)?; + if !&self.features.is_empty() { + f.write_str(" and ")?; + } + } + f.write_str(&self.features.join(" and ")) + } +} diff --git a/src/atrule/mod.rs b/src/atrule/mod.rs index 5c42d66..e12a576 100644 --- a/src/atrule/mod.rs +++ b/src/atrule/mod.rs @@ -1,7 +1,12 @@ pub(crate) use function::Function; pub(crate) use kind::AtRuleKind; pub(crate) use mixin::Mixin; +pub(crate) use supports::SupportsRule; +pub(crate) use unknown::UnknownAtRule; mod function; mod kind; +pub mod media; mod mixin; +mod supports; +mod unknown; diff --git a/src/atrule/supports.rs b/src/atrule/supports.rs new file mode 100644 index 0000000..145c3dd --- /dev/null +++ b/src/atrule/supports.rs @@ -0,0 +1,7 @@ +use crate::parse::Stmt; + +#[derive(Debug, Clone)] +pub(crate) struct SupportsRule { + pub params: String, + pub body: Vec, +} diff --git a/src/atrule/unknown.rs b/src/atrule/unknown.rs new file mode 100644 index 0000000..2d0df7d --- /dev/null +++ b/src/atrule/unknown.rs @@ -0,0 +1,9 @@ +use crate::{parse::Stmt, selector::Selector}; + +#[derive(Debug, Clone)] +pub(crate) struct UnknownAtRule { + pub name: String, + pub super_selector: Selector, + pub params: String, + pub body: Vec, +} diff --git a/src/output.rs b/src/output.rs index 5b1cdfa..9d17bd2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -3,7 +3,14 @@ use std::io::Write; use codemap::CodeMap; -use crate::{error::SassResult, parse::Stmt, selector::Extender, selector::Selector, style::Style}; +use crate::{ + atrule::{media::MediaRule, SupportsRule, UnknownAtRule}, + error::SassResult, + parse::Stmt, + selector::Extender, + selector::Selector, + style::Style, +}; #[derive(Debug, Clone)] enum Toplevel { @@ -23,7 +30,7 @@ enum Toplevel { body: Vec, }, Newline, - Style(Box