inline-css-macros 0.0.2

Macros for the inline-css crate
Documentation
// Copyright (C) 2023 Benjamin Stürz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
use syn::{parse::{Parse, ParseStream}, ext::IdentExt, token::{Paren, Brace}};
use crate::*;

impl Parse for CSS {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut rules = Vec::new();
        while !input.is_empty() {
            rules.push(input.parse()?);
        }
        Ok(Self(rules))
    }
}

impl Parse for Rule {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let selector = input.parse()?;
        let group: Group = input.parse()?;
        let declarations = syn::parse2(group.stream())?;
        Ok(Self {
            selector,
            group,
            declarations,
        })
    }
}

fn selector_simple(input: ParseStream) -> syn::Result<Selector> {
    let look = input.lookahead1();
    if look.peek(Token![:]) {
        let colon = input.parse()?;
        let ident = input.parse()?;
        let arg = if input.peek(Paren) {
            let group: Group = input.parse()?;
            let arg = syn::parse2(group.stream())?;
            Some((group, arg))
        } else {
            None
        };

        Ok(Selector::Colon {
            colon,
            ident,
            arg,
        })
    } else if look.peek(Token![*]) {
        input.parse().map(Selector::Any)
    } else if look.peek(Ident::peek_any) || look.peek(Token![.]) || look.peek(Token![#]) {
        let ident = if input.peek(Ident::peek_any) { Some(input.parse()?) } else { None };
        let class = if input.peek(Token![.]) {
            Some((input.parse()?, input.parse()?))
        } else {
            None
        };
        let id = if input.peek(Token![#]) {
            Some((input.parse()?, input.parse()?))
        } else {
            None
        };

        if let (&None, &None, &None) = (&ident, &class, &id) {
            todo!("Error");
        }

        Ok(Selector::Simple {
            ident,
            class,
            id,
        })
    } else {
        Err(look.error())
    }
}

fn selector_sub(input: ParseStream) -> syn::Result<Selector> {
    let mut left = selector_simple(input)?;
    while input.peek(Ident::peek_any) || input.peek(Token![.]) || input.peek(Token![#]) || input.peek(Token![:]) {
        left = Selector::Sub {
            left: Box::new(left),
            right: Box::new(selector_simple(input)?),
        };
    }
    Ok(left)
}

fn selector_plus(input: ParseStream) -> syn::Result<Selector> {
    let mut left = selector_sub(input)?;
    while input.peek(Token![+]) {
        left = Selector::Plus {
            left: Box::new(left),
            plus: input.parse()?,
            right: Box::new(selector_sub(input)?),
        };
    }
    Ok(left)
}

fn selector_comma(input: ParseStream) -> syn::Result<Selector> {
    let mut left = selector_plus(input)?;
    while input.peek(Token![,]) {
        left = Selector::Comma {
            left: Box::new(left),
            comma: input.parse()?,
            right: Box::new(selector_plus(input)?),
        };
    }
    Ok(left)
}

impl Parse for Selector {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        selector_comma(input)
    }
}

impl Parse for Declarations {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut decls = Vec::new();
        while !input.is_empty() {
            decls.push(input.parse()?);
        }
        Ok(Self(decls))
    }
}

impl Parse for Declaration {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let ident = input.parse()?;
        let colon = input.parse()?;
        let mut value = vec![input.parse()?];
        while !input.peek(Token![;]) {
            value.push(input.parse()?);
        }
        Ok(Self {
            ident,
            colon,
            value,
            semicolon: input.parse()?,
        })
    }
}

impl Parse for Value {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let look = input.lookahead1();
        if look.peek(Token![#]) {
            Ok(Self::ColorCode {
                pound: input.parse()?,
                value: input.parse()?,
            })
        } else if look.peek(LitInt) {
            let int = input.parse()?;
            if input.peek(Token![%]) {
                Ok(Self::IntPerc(int, input.parse()?))
            } else {
                Ok(Self::Int(int))
            }
        } else if look.peek(LitFloat) {
            let f = input.parse()?;
            if input.peek(Token![%]) {
                Ok(Self::FloatPerc(f, input.parse()?))
            } else {
                Ok(Self::Float(f))
            }
        } else if look.peek(Ident::peek_any) || look.peek(Token![-]) {
            let ident = input.parse()?;
            if input.peek(Paren) {
                let group: Group = input.parse()?;
                let args = syn::parse2(group.stream())?;
                Ok(Self::Function { ident, group, args })
            } else {
                Ok(Self::Ident(ident))
            }
        } else if look.peek(Brace) {
            input.parse().map(Self::Block)
        } else {
            Err(look.error())
        }
    }
}

impl Parse for Args {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut values = vec![input.parse()?];
        while input.peek(Token![,]) {
            input.parse::<Token![,]>()?;
            values.push(input.parse()?);
        }
        Ok(Self(values))
    }
}

impl Parse for CSSIdent {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut segments = Vec::new();
        while input.peek(Token![-]) {
            segments.push(CSSIdentSegment::Minus(input.parse()?));
        }
        segments.push(CSSIdentSegment::Ident(Ident::parse_any(input)?));
        while input.peek(Token![-]) {
            while input.peek(Token![-]) {
                segments.push(CSSIdentSegment::Minus(input.parse()?));
            }
            segments.push(CSSIdentSegment::Ident(Ident::parse_any(input)?));
        }
        Ok(Self(segments))
    }
}