Repository: fonttools/openstep-plist (language: python)

Issue:
Support Glyphs-style "tuples"
Glyphs 3 plist files have "tuples" which appear on a single line even when other lines are separated/indented. The easiest way to support this would be to remove the `if indent is not None...` blocks from `write_array_from_tuple`. However, this may have Unintended Consequences.


Discussion / hints:
ugh. I really wish we can avoid adding quirks to this project, I'd like to keep it general purpose and not tied to Glyphs.app, even if it's the main target. Can we think about ways to inject some custom callbacks to format these maybe?
on second thought, I guess it'd be fine if we add a new writer option, e.g. `single_line_tuples=False`, that optionally enable this. I see we already have two duplicate implementations for serializing list and tuple objects. Could you send a PR?

Fix patch:
diff --git a/src/openstep_plist/writer.pyx b/src/openstep_plist/writer.pyx
index b0b9034..b6cc262 100644
--- a/src/openstep_plist/writer.pyx
+++ b/src/openstep_plist/writer.pyx
@@ -114,9 +114,14 @@ cdef class Writer:
     cdef int float_precision
     cdef unicode indent
     cdef int current_indent_level
+    cdef bint single_line_tuples
 
     def __cinit__(
-        self, bint unicode_escape=True, int float_precision=6, indent=None
+        self,
+        bint unicode_escape=True,
+        int float_precision=6,
+        indent=None,
+        bint single_line_tuples=False,
     ):
         self.dest = array.clone(unicode_array_template, 0, zero=False)
         self.unicode_escape = unicode_escape
@@ -129,6 +134,7 @@ cdef class Writer:
                 self.indent = ' ' * indent
         else:
             self.indent = None
+        self.single_line_tuples = single_line_tuples
         self.current_indent_level = 0
 
     def getvalue(self):
@@ -433,7 +439,7 @@ cdef class Writer:
         count = 1
 
         indent = self.indent
-        if indent is not None:
+        if indent is not None and not self.single_line_tuples:
             self.current_indent_level += 1
             newline_indent = '\n' + self.current_indent_level * indent
             indent_length = PyUnicode_GET_SIZE(newline_indent)
@@ -450,10 +456,13 @@ cdef class Writer:
                     count += 2
                 else:
                     dest.append(',')
+                    if self.single_line_tuples:
+                        dest.append(' ')
+                        count += 1
                     array.extend_buffer(dest, <char*>indent_chars, indent_length)
                     count += 1 + indent_length
 
-        if indent is not None:
+        if indent is not None and not self.single_line_tuples:
             self.current_indent_level -= 1
             newline_indent = '\n' + self.current_indent_level * indent
             indent_length = PyUnicode_GET_SIZE(newline_indent)
@@ -594,21 +603,25 @@ cdef class Writer:
         return count
 
 
-def dumps(obj, bint unicode_escape=True, int float_precision=6, indent=None):
+def dumps(obj, bint unicode_escape=True, int float_precision=6, indent=None,
+          single_line_tuples=False):
     w = Writer(
         unicode_escape=unicode_escape,
         float_precision=float_precision,
         indent=indent,
+        single_line_tuples=single_line_tuples,
     )
     w.write(obj)
     return w.getvalue()
 
 
-def dump(obj, fp, bint unicode_escape=True, int float_precision=6, indent=None):
+def dump(obj, fp, bint unicode_escape=True, int float_precision=6, indent=None,
+         single_line_tuples=False):
     w = Writer(
         unicode_escape=unicode_escape,
         float_precision=float_precision,
         indent=indent,
+        single_line_tuples=single_line_tuples,
     )
     w.write(obj)
     w.dump(fp)


Test patch:
diff --git a/tests/test_writer.py b/tests/test_writer.py
index aafa043..77deabc 100644
--- a/tests/test_writer.py
+++ b/tests/test_writer.py
@@ -269,3 +269,25 @@ def test_dump():
 )
 def test_string_needs_quotes(string, expected):
     assert string_needs_quotes(string) is expected
+
+
+def test_single_line_tuples():
+    assert openstep_plist.dumps({"a": 1, "b": (2, 3), "c": "Hello"}, indent=0) == (
+        """{
+a = 1;
+b = (
+2,
+3
+);
+c = Hello;
+}"""
+    )
+    assert openstep_plist.dumps(
+        {"a": 1, "b": (2, 3), "c": "Hello"}, indent=0, single_line_tuples=True
+    ) == (
+        """{
+a = 1;
+b = (2, 3);
+c = Hello;
+}"""
+    )