Skip to content

Instantly share code, notes, and snippets.

@Leinnan
Created April 7, 2023 16:11
Show Gist options
  • Select an option

  • Save Leinnan/9c46bc762fc80773baedb43273fb4e8b to your computer and use it in GitHub Desktop.

Select an option

Save Leinnan/9c46bc762fc80773baedb43273fb4e8b to your computer and use it in GitHub Desktop.
0001-Add-parsing-pseudo-classes.patch
From f1dcf7f96c37eb2b8f4215ca31ede61ce45bd192 Mon Sep 17 00:00:00 2001
From: Piotr Siuszko <siuszko@zoho.com>
Date: Fri, 7 Apr 2023 18:10:16 +0200
Subject: [PATCH] Add parsing pseudo classes
---
src/parser.rs | 23 ++++++++++++++---------
src/selector.rs | 27 +++++++++++++++++++++++----
src/system.rs | 4 ++++
3 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/src/parser.rs b/src/parser.rs
index 2d94699..0c93929 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -7,7 +7,7 @@ use smallvec::{smallvec, SmallVec};
use crate::{
property::PropertyValues,
- selector::{Selector, SelectorElement},
+ selector::{NextValueType, Selector, SelectorElement},
stylesheet::StyleRule,
EcssError,
};
@@ -72,18 +72,22 @@ impl<'i> QualifiedRuleParser<'i> for StyleSheetParser {
) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
let mut elements = smallvec![];
- let mut next_is_class = false;
+ let mut next_value_type = NextValueType::default();
while let Ok(token) = input.next_including_whitespace() {
use cssparser::Token::*;
match token {
Ident(v) => {
- if next_is_class {
- next_is_class = false;
- elements.push(SelectorElement::Class(v.to_string()));
- } else {
- elements.push(SelectorElement::Component(v.to_string()));
- }
+ match next_value_type {
+ NextValueType::Class => {
+ elements.push(SelectorElement::Class(v.to_string()));
+ }
+ NextValueType::PseudoClass => {
+ elements.push(SelectorElement::PseudoClass(v.to_string()));
+ }
+ _ => elements.push(SelectorElement::Component(v.to_string())),
+ };
+ next_value_type = NextValueType::default();
}
IDHash(v) => {
if v.is_empty() {
@@ -93,7 +97,8 @@ impl<'i> QualifiedRuleParser<'i> for StyleSheetParser {
}
}
WhiteSpace(_) => elements.push(SelectorElement::Child),
- Delim(c) if *c == '.' => next_is_class = true,
+ Delim(c) if *c == '.' => next_value_type = NextValueType::Class,
+ Colon => next_value_type = NextValueType::PseudoClass,
_ => {
let token = token.to_css_string();
return Err(input.new_custom_error(EcssError::UnexpectedToken(token)));
diff --git a/src/selector.rs b/src/selector.rs
index 67f2243..c2f4bcf 100644
--- a/src/selector.rs
+++ b/src/selector.rs
@@ -15,10 +15,19 @@ pub enum SelectorElement {
Component(String),
/// A class name component selector element, `.border`
Class(String),
+ PseudoClass(String),
/// Indicates a parent-child relation between previous elements and next elements, like `window .border`
Child,
}
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
+pub enum NextValueType {
+ #[default]
+ Unspecified,
+ Class,
+ PseudoClass,
+}
+
/// A selector parsed from a `css` rule. Each selector has a internal hash used to differentiate between many rules in the same sheet.
#[derive(Debug, Default, Clone)]
pub struct Selector {
@@ -76,6 +85,10 @@ impl std::fmt::Display for Selector {
result.push('.');
result.push_str(c);
}
+ SelectorElement::PseudoClass(c) => {
+ result.push(':');
+ result.push_str(c);
+ }
SelectorElement::Child => result.push(' '),
}
}
@@ -117,23 +130,29 @@ impl Hash for Selector {
impl<'i> From<Vec<CowRcStr<'i>>> for Selector {
fn from(input: Vec<CowRcStr<'i>>) -> Self {
let mut elements = smallvec![];
- let mut next_is_class = false;
+ let mut next_value_type = NextValueType::default();
for value in input.into_iter().filter(|v| !v.is_empty()) {
if value.as_ref() == "." {
- next_is_class = true;
+ next_value_type = NextValueType::Class;
+ continue;
+ }
+ if value.as_ref() == ":" {
+ next_value_type = NextValueType::PseudoClass;
continue;
}
if let Some(value) = value.strip_prefix('#') {
elements.push(SelectorElement::Name(value.to_string()));
- } else if next_is_class {
+ } else if next_value_type == NextValueType::Class {
elements.push(SelectorElement::Class(value.to_string()))
+ } else if next_value_type == NextValueType::PseudoClass {
+ elements.push(SelectorElement::PseudoClass(value.to_string()))
} else {
elements.push(SelectorElement::Component(value.to_string()))
}
- next_is_class = false;
+ next_value_type = NextValueType::default();
}
Self::new(elements)
diff --git a/src/system.rs b/src/system.rs
index ab50251..d0152eb 100644
--- a/src/system.rs
+++ b/src/system.rs
@@ -167,6 +167,10 @@ fn select_entities_node(
SelectorElement::Class(class) => {
get_entities_with(class.as_str(), &css_query.classes, filter)
}
+ SelectorElement::PseudoClass(_class) => {
+ // TODO how to handle that?
+ get_entities_with_component("interaction", world, registry, filter)
+ }
SelectorElement::Component(component) => {
get_entities_with_component(component.as_str(), world, registry, filter)
}
--
2.40.0.windows.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment