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
 
openSUSE Build Service is sponsored by