Repository: fonttools/openstep-plist

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.

Comments:

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 @@ invalid_unquoted_chars = [
 )
 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;
+}"""
+    )