#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct SpecifiedValue
{
pub originalCss: String,
}
impl ToCss for SpecifiedValue
{
fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result
{
dest.write_str(&self.originalCss)
}
}
impl SpecifiedValue
{
pub(crate) fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, CustomParseError<'i>>>
{
let mut references = Some(HashSet::new());
let (_first, css, _last) = Self::parse_self_contained_declaration_value(input, &mut references)?;
Ok
(
SpecifiedValue
{
originalCss: css.into_owned(),
}
)
}
fn parse_self_contained_declaration_value<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Option<HashSet<Atom>>) -> Result<(TokenSerializationType, Cow<'i, str>, TokenSerializationType), ParseError<'i, CustomParseError<'i>>>
{
let start_position = input.position();
let mut missing_closing_characters = String::new();
let (first, last) = Self::parse_declaration_value(input, references, &mut missing_closing_characters)?;
let mut css: Cow<str> = input.slice_from(start_position).into();
if !missing_closing_characters.is_empty()
{
if css.ends_with("\\")
{
let first = missing_closing_characters.as_bytes()[0];
if first == b'"' || first == b'\''
{
css.to_mut().pop();
}
}
css.to_mut().push_str(&missing_closing_characters);
}
Ok((first, css, last))
}
fn parse_declaration_value<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Option<HashSet<Atom>>, missing_closing_characters: &mut String) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i, CustomParseError<'i>>>
{
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input|
{
let start = input.state();
input.next_including_whitespace()?;
input.reset(&start);
Self::parse_declaration_value_block(input, references, missing_closing_characters)
})
}
fn parse_declaration_value_block<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Option<HashSet<Atom>>, missing_closing_characters: &mut String) -> Result<(TokenSerializationType, TokenSerializationType), ParseError<'i, CustomParseError<'i>>>
{
let mut token_start = input.position();
let mut token = match input.next_including_whitespace_and_comments()
{
Ok(token) => token.clone(),
Err(_) => return Ok((TokenSerializationType::nothing(), TokenSerializationType::nothing()))
};
let first_token_type = token.serialization_type();
loop
{
macro_rules! nested
{
() =>
{
input.parse_nested_block(|input|
{
Self::parse_declaration_value_block(input, references, missing_closing_characters)
})?
}
}
macro_rules! check_closed
{
($closing: expr) =>
{
if !input.slice_from(token_start).ends_with($closing)
{
missing_closing_characters.push_str($closing)
}
}
}
use ::cssparser::Token::*;
let last_token_type = match token
{
Comment(_) =>
{
let token_slice = input.slice_from(token_start);
if !token_slice.ends_with("*/")
{
missing_closing_characters.push_str(if token_slice.ends_with('*') { "/" } else { "*/" })
}
token.serialization_type()
}
BadUrl(url) => return Err(ParseError::Custom(CustomParseError::BadUrlInDeclarationValueBlock(url))),
BadString(string) => return Err(ParseError::Custom(CustomParseError::BadStringInDeclarationValueBlock(string))),
CloseParenthesis => return Err(ParseError::Custom(CustomParseError::UnbalancedCloseParenthesisInDeclarationValueBlock)),
CloseSquareBracket => return Err(ParseError::Custom(CustomParseError::UnbalancedCloseSquareBracketInDeclarationValueBlock)),
CloseCurlyBracket => return Err(ParseError::Custom(CustomParseError::UnbalancedCloseCurlyBracketInDeclarationValueBlock)),
Function(ref name) =>
{
if name.eq_ignore_ascii_case("var")
{
let args_start = input.state();
input.parse_nested_block(|input| Self::parse_var_function(input, references))?;
input.reset(&args_start);
}
nested!();
check_closed!(")");
CloseParenthesis.serialization_type()
}
ParenthesisBlock =>
{
nested!();
check_closed!(")");
CloseParenthesis.serialization_type()
}
CurlyBracketBlock =>
{
nested!();
check_closed!("}");
CloseCurlyBracket.serialization_type()
}
SquareBracketBlock =>
{
nested!();
check_closed!("]");
CloseSquareBracket.serialization_type()
}
QuotedString(_) =>
{
let token_slice = input.slice_from(token_start);
let quote = &token_slice[..1];
if !(token_slice.ends_with(quote) && token_slice.len() > 1)
{
missing_closing_characters.push_str(quote)
}
token.serialization_type()
}
Ident(ref value) | AtKeyword(ref value) | Hash(ref value) | IDHash(ref value) | UnquotedUrl(ref value) | Dimension { unit: ref value, .. } =>
{
if value.ends_with("�") && input.slice_from(token_start).ends_with("\\")
{
missing_closing_characters.push_str("�")
}
match token
{
UnquotedUrl(_) => check_closed!(")"),
_ =>
{
}
}
token.serialization_type()
}
_ =>
{
token.serialization_type()
}
};
token_start = input.position();
token = match input.next_including_whitespace_and_comments()
{
Ok(token) => token.clone(),
Err(..) => return Ok((first_token_type, last_token_type)),
};
}
}
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut Option<HashSet<Atom>>) -> Result<(), ParseError<'i, CustomParseError<'i>>>
{
let name = input.expect_ident_cloned()?;
if input.try(|input| input.expect_comma()).is_ok()
{
input.parse_until_before(Delimiter::Bang | Delimiter::Semicolon, |input|
{
input.next_including_whitespace()?;
while let Ok(_) = input.next_including_whitespace_and_comments()
{
}
Ok(())
})?;
}
if let Some(ref mut refs) = *references
{
refs.insert(Atom::from(name));
}
Ok(())
}
}