use super::{AtRule, Comment, CssString, Import, Selectors, Value};
use crate::output::CssBuf;
use std::io::{self, Write};
#[derive(Clone, Debug)]
pub struct Rule {
pub(crate) selectors: Selectors,
pub(crate) body: Vec<BodyItem>,
}
impl Rule {
pub fn new(selectors: Selectors) -> Rule {
Rule {
selectors,
body: Vec::new(),
}
}
pub fn push(&mut self, item: BodyItem) {
self.body.push(item);
}
pub(crate) fn write(&self, buf: &mut CssBuf) -> io::Result<()> {
if !self.body.is_empty() {
if let Some(selectors) = self.selectors.no_placeholder() {
buf.do_indent_no_nl();
if buf.format().is_compressed() {
write!(buf, "{selectors:#}")?;
} else {
write!(buf, "{selectors}")?;
}
buf.start_block();
for item in &self.body {
item.write(buf)?;
}
buf.end_block();
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum BodyItem {
Import(Import),
Property(Property),
CustomProperty(CustomProperty),
Comment(Comment),
ARule(AtRule),
}
impl BodyItem {
pub(crate) fn write(&self, buf: &mut CssBuf) -> io::Result<()> {
match self {
BodyItem::Comment(c) => c.write(buf),
BodyItem::Import(import) => import.write(buf)?,
BodyItem::Property(property) => property.write(buf),
BodyItem::CustomProperty(property) => property.write(buf),
BodyItem::ARule(rule) => rule.write(buf)?,
}
Ok(())
}
}
impl From<Comment> for BodyItem {
fn from(comment: Comment) -> BodyItem {
BodyItem::Comment(comment)
}
}
impl From<Import> for BodyItem {
fn from(import: Import) -> BodyItem {
BodyItem::Import(import)
}
}
impl From<Property> for BodyItem {
fn from(property: Property) -> BodyItem {
BodyItem::Property(property)
}
}
impl From<CustomProperty> for BodyItem {
fn from(property: CustomProperty) -> BodyItem {
BodyItem::CustomProperty(property)
}
}
impl TryFrom<AtRule> for BodyItem {
type Error = AtRule;
fn try_from(value: AtRule) -> Result<Self, Self::Error> {
if value.no_body() {
Ok(BodyItem::ARule(value))
} else {
Err(value)
}
}
}
#[derive(Clone, Debug)]
pub struct Property {
name: String,
value: Value,
}
impl Property {
pub fn new(name: String, value: Value) -> Self {
Property { name, value }
}
pub(crate) fn write(&self, buf: &mut CssBuf) {
buf.do_indent_no_nl();
buf.add_str(&self.name);
buf.add_one(": ", ":");
buf.add_str(&self.value.to_string(buf.format()).replace('\n', " "));
buf.add_one(";\n", ";");
}
}
#[derive(Clone, Debug)]
pub struct CustomProperty {
name: String,
value: CssString,
}
impl CustomProperty {
pub fn new(name: String, value: CssString) -> Self {
CustomProperty { name, value }
}
pub(crate) fn write(&self, buf: &mut CssBuf) {
buf.do_indent_no_nl();
buf.add_str(&self.name);
buf.add_str(":");
if !(self.value.quotes().is_none() || buf.format().is_compressed()) {
buf.add_str(" ");
}
buf.add_str(&self.value.to_string());
buf.add_one(";\n", ";");
}
}