File cinnamon-settings-4.4.8-tinycss2.patch of Package cinnamon
From 009317e7c324a39f9ca97d731af08645359aa5bc Mon Sep 17 00:00:00 2001
From: marguerite <i@marguerite.su>
Date: Tue, 17 Mar 2020 10:53:26 +0800
Subject: [PATCH] port tinycss to tinycss2
---
debian/control | 2 +-
.../bin/CinnamonGtkSettings.py | 144 +++++++++++++-----
2 files changed, 103 insertions(+), 43 deletions(-)
diff --git a/debian/control b/debian/control
index 638885ff94..454fcf1958 100644
--- a/debian/control
+++ b/debian/control
@@ -96,7 +96,7 @@ Depends:
python3-pil,
python3-pyinotify,
python3-setproctitle,
- python3-tinycss,
+ python3-tinycss2,
python3-tz,
streamer,
wget,
diff --git a/files/usr/share/cinnamon/cinnamon-settings/bin/CinnamonGtkSettings.py b/files/usr/share/cinnamon/cinnamon-settings/bin/CinnamonGtkSettings.py
index 5b2a66418c..555cad6841 100644
--- a/files/usr/share/cinnamon/cinnamon-settings/bin/CinnamonGtkSettings.py
+++ b/files/usr/share/cinnamon/cinnamon-settings/bin/CinnamonGtkSettings.py
@@ -3,8 +3,7 @@
import os.path
import signal
-import tinycss
-from tinycss import tokenizer
+import tinycss2
import gi
gi.require_version("Gtk", "3.0")
@@ -91,11 +90,10 @@ def __init__(self, selector):
"gtk-3.0",
"gtk.css")
- self.parser = tinycss.make_parser()
self.selector = selector
self.rule_separator = "/***** %s - cinnamon-settings-generated - do not edit *****/" % self.selector
- self.my_ruleset = None
+ rules = []
file = Gio.File.new_for_path(self._path)
@@ -103,11 +101,16 @@ def __init__(self, selector):
success, content_bytes, tag = file.load_contents(None)
self._contents = content_bytes.decode()
- self.stylesheet = self.parser.parse_stylesheet(self._contents)
+ stylesheet = tinycss2.parse_stylesheet(self._contents)
+ for rs in stylesheet:
+ if isinstance(rs, tinycss2.ast.ParseError):
+ continue
+ rules.append(rs)
+ self.stylesheet = rules
except GLib.Error as e:
if e.code == Gio.IOErrorEnum.NOT_FOUND:
self._contents = ""
- self.stylesheet = tinycss.css21.Stylesheet(rules=[], errors=[], encoding="utf-8")
+ self.stylesheet = rules
else:
raise PermissionError("Could not load ~/.config/gtk-3.0/gtk.css file, check permissions")
@@ -142,30 +145,56 @@ def sanitize_contents(self):
self._contents = "\n".join(out_lines)
+ def _serialize_selector(self, rule):
+ at_css = ""
+ if isinstance(rule, tinycss2.ast.AtRule):
+ at_css += "@" + rule.at_keyword
+ at_css += self._serialize_prelude(rule.prelude)
+ return at_css
+
+ def _serialize_prelude(self, prelude):
+ at_css = ""
+ for cv in prelude:
+ if isinstance(cv, tinycss2.ast.WhitespaceToken):
+ at_css += " "
+ elif isinstance(cv, tinycss2.ast.HashToken):
+ at_css += "#" + cv.value
+ elif isinstance(cv, tinycss2.ast.FunctionBlock):
+ next
+ else:
+ at_css += cv.value
+ return at_css.strip()
+
def get_ruleset(self, selector_css):
"""
Gets the current ruleset for selector_css,
If it isn't currently defined, returns an empty
one.
"""
- for rs in self.stylesheet.rules:
- try:
- if rs.selector.as_css() == selector_css:
- return rs
- except AttributeError:
- continue
+ idx = 0
+ for rs in self.stylesheet:
+ if isinstance(rs, (tinycss2.ast.AtRule, tinycss2.ast.QualifiedRule)):
+ if self._serialize_selector(rs) == selector_css:
+ return rs, idx
+ idx += 1
- new_ruleset = tinycss.css21.RuleSet(tokenizer.tokenize_flat(selector_css), [], None, None)
- self.stylesheet.rules.append(new_ruleset)
+ new_ruleset = tinycss2.parse_one_rule(selector_css + " {}", False)
+ self.stylesheet.append(new_ruleset)
- return new_ruleset
+ return new_ruleset, len(self.stylesheet) - 1
def get_declaration(self, selector, decl_name):
- rs = self.get_ruleset(selector)
+ rs, _ = self.get_ruleset(selector)
+
+ declarations = tinycss2.parse_declaration_list(rs.content, True, True)
- for declaration in rs.declarations:
+ for declaration in declarations:
if decl_name == declaration.name:
- return declaration.value[0].value
+ decl_value = None
+ for component_value in declaration.value:
+ if isinstance(component_value, tinycss2.ast.DimensionToken):
+ decl_value = component_value.value
+ return decl_value
return None
@@ -174,32 +203,68 @@ def set_declaration(self, selector, decl_name, value_as_str):
# get modified, they become invalid (or I'm doing something wrong)
self.remove_declaration(selector, decl_name)
- rs = self.get_ruleset(selector)
-
- value_token = tokenizer.tokenize_flat(value_as_str)
-
- # Make a new declaration, add it to the ruleset
- new_decl = tinycss.css21.Declaration(decl_name, value_token, None, None, None)
-
- rs.declarations.append(new_decl)
-
- self.my_ruleset = rs
+ rs, idx = self.get_ruleset(selector)
+ # rs.content[0].value: the value of the WhitespaceToken is the actual indent
+ prefix = "\n\t"
+ if rs.content:
+ prefix = rs.content[0].value
+
+ component_values = tinycss2.parse_component_value_list(prefix + decl_name +
+ ": " + value_as_str + ";")
+ for component_value in component_values:
+ self.stylesheet[idx].content.append(component_value)
+
+ @staticmethod
+ def _remove_declaration_from_content(declaration, content):
+ idx = 0
+ ident_idx = 0
+ found_ident = False
+ done = False
+ new_content = []
+ for component_value in content:
+ idx += 1
+ if len(content) != idx and isinstance(content[idx], tinycss2.ast.IdentToken) and \
+ content[idx].value == declaration.name and \
+ isinstance(component_value, tinycss2.ast.WhitespaceToken):
+ continue
+ if isinstance(component_value, tinycss2.ast.IdentToken) and \
+ component_value.value == declaration.name:
+ found_ident = True
+ continue
+ if found_ident:
+ if isinstance(component_value, tinycss2.ast.LiteralToken):
+ if ident_idx == 0 or done:
+ done = False
+ continue
+ if len(declaration.value) - 1 == ident_idx and \
+ component_value == declaration.value[ident_idx]:
+ done = True
+ continue
+ if component_value == declaration.value[ident_idx] and \
+ content[idx] == declaration.value[ident_idx + 1]:
+ ident_idx += 1
+ continue
+ new_content.append(component_value)
+
+ return new_content
def remove_declaration(self, selector, decl_name):
- rs = self.get_ruleset(selector)
+ rs, idx = self.get_ruleset(selector)
if not rs:
return
- self.my_ruleset = None
+ declarations = tinycss2.parse_declaration_list(rs.content, True, True)
- for declaration in rs.declarations:
+ for declaration in declarations:
if decl_name == declaration.name:
- rs.declarations.remove(declaration)
+ new_content = self._remove_declaration_from_content(declaration, rs.content)
- if len(rs.declarations) == 0:
- self.stylesheet.rules.remove(rs)
+ if not new_content:
+ self.stylesheet.remove(rs)
+ break
+ self.stylesheet[idx].content = new_content
break
def save_stylesheet(self):
@@ -213,18 +278,13 @@ def save_stylesheet(self):
out += line + "\n"
- if self.my_ruleset:
+ if self.stylesheet:
if line != "":
out += "\n"
out += self.rule_separator + "\n"
-
- out += self.my_ruleset.selector.as_css() + " {\n"
-
- for decl in self.my_ruleset.declarations:
- out += " " + decl.name + ": " + decl.value.as_css() + ";\n"
-
- out += "}\n"
+ for rs in self.stylesheet:
+ out += rs.serialize()
self._contents = out