use super::atrule::AtRuleBodyItem;
use super::Value;
use crate::output::{CssBuf, Format};
use crate::parser::{css::media, input_span};
use crate::value::Operator;
use crate::ParseError;
use std::io::{self, Write};
#[derive(Clone, Debug)]
pub struct MediaRule {
args: MediaArgs,
body: Vec<AtRuleBodyItem>,
}
impl MediaRule {
pub(crate) fn new(args: MediaArgs, body: Vec<AtRuleBodyItem>) -> Self {
Self { args, body }
}
pub(crate) fn write(&self, buf: &mut CssBuf) -> io::Result<()> {
if !self.body.is_empty() {
buf.do_indent_no_nl();
buf.add_str("@media ");
self.args.write(buf)?;
buf.start_block();
for item in &self.body {
item.write(buf)?;
}
buf.end_block();
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum MediaArgs {
Name(String),
Condition(String, Value),
Range(Vec<(Operator, Value)>),
Paren(Box<MediaArgs>),
Bracket(Box<MediaArgs>),
UnaryOp(String, Box<MediaArgs>),
Comma(Vec<MediaArgs>),
And(Vec<MediaArgs>),
Or(Vec<MediaArgs>),
}
impl MediaArgs {
pub(crate) fn write(&self, buf: &mut CssBuf) -> io::Result<()> {
match self {
Self::Name(name) => write!(buf, "{name}")?,
Self::UnaryOp(op, a) => {
buf.add_str(op);
buf.add_str(" ");
a.write(buf)?;
}
Self::Condition(c, v) => {
write!(buf, "({c}: {})", v.format(buf.format()))?;
}
Self::Comma(args) => {
if let Some((first, rest)) = args.split_first() {
first.write(buf)?;
for arg in rest {
buf.add_one(", ", ",");
arg.write(buf)?;
}
}
}
Self::And(args) => {
if let Some((first, rest)) = args.split_first() {
first.write(buf)?;
for arg in rest {
buf.add_str(" and ");
arg.write(buf)?;
}
}
}
Self::Or(args) => {
if let Some((first, rest)) = args.split_first() {
first.write(buf)?;
for arg in rest {
buf.add_str(" or ");
arg.write(buf)?;
}
}
}
Self::Paren(a) => {
buf.add_str("(");
a.write(buf)?;
buf.add_str(")");
}
Self::Bracket(a) => {
buf.add_str("[");
a.write(buf)?;
buf.add_str("]");
}
Self::Range(v) => {
buf.add_str("(");
if let Some(((_op, first), rest)) = v.split_first() {
buf.add_str(
&first.to_string(buf.format()).replace('\n', " "),
);
for (op, val) in rest {
write!(buf, " {op} ")?;
buf.add_str(
&val.to_string(buf.format()).replace('\n', " "),
);
}
}
buf.add_str(")");
}
}
Ok(())
}
}
impl TryFrom<Value> for MediaArgs {
type Error = crate::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
let value = value.format(Format::default()).to_string();
Ok(ParseError::check(media::args(input_span(value).borrow()))?)
}
}