1# Copyright 2015 Google Inc. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from __future__ import print_function, division, absolute_import, unicode_literals
16
17import logging
18import re
19
20from glyphsLib.util import cast_to_number_or_bool, reverse_cast_to_number_or_bool
21
22logger = logging.getLogger(__name__)
23
24
25def parse_glyphs_filter(filter_str, is_pre=False):
26    """Parses glyphs custom filter string into a dict object that
27       ufo2ft can consume.
28
29        Reference:
30            ufo2ft: https://github.com/googlei18n/ufo2ft
31            Glyphs 2.3 Handbook July 2016, p184
32
33        Args:
34            filter_str - a string of glyphs app filter
35
36        Return:
37            A dictionary contains the structured filter.
38            Return None if parse failed.
39    """
40    elements = filter_str.split(";")
41
42    if elements[0] == "":
43        logger.error(
44            "Failed to parse glyphs filter, expecting a filter name: \
45             %s",
46            filter_str,
47        )
48        return None
49
50    result = {"name": elements[0]}
51    for idx, elem in enumerate(elements[1:]):
52        if not elem:
53            # skip empty arguments
54            continue
55        if ":" in elem:
56            # Key value pair
57            key, value = elem.split(":", 1)
58            if key.lower() in ["include", "exclude"]:
59                if idx != len(elements[1:]) - 1:
60                    logger.error(
61                        "{} can only present as the last argument in the filter. "
62                        "{} is ignored.".format(key, elem)
63                    )
64                    continue
65                result[key.lower()] = re.split("[ ,]+", value)
66            else:
67                if "kwargs" not in result:
68                    result["kwargs"] = {}
69                result["kwargs"][key] = cast_to_number_or_bool(value)
70        else:
71            if "args" not in result:
72                result["args"] = []
73            result["args"].append(cast_to_number_or_bool(elem))
74    if is_pre:
75        result["pre"] = True
76    return result
77
78
79def write_glyphs_filter(result):
80    elements = [result["name"]]
81    if "args" in result:
82        for arg in result["args"]:
83            elements.append(reverse_cast_to_number_or_bool(arg))
84    if "kwargs" in result:
85        for key, arg in result["kwargs"].items():
86            if key.lower() not in ("include", "exclude"):
87                elements.append(key + ":" + reverse_cast_to_number_or_bool(arg))
88        for key, arg in result["kwargs"].items():
89            if key.lower() in ("include", "exclude"):
90                elements.append(key + ":" + reverse_cast_to_number_or_bool(arg))
91    return ";".join(elements)
92