Skip to content

Commit

Permalink
Improved parentheses formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertoRoos committed Mar 11, 2024
1 parent 9f88c34 commit 6c28d26
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 29 deletions.
2 changes: 2 additions & 0 deletions src/tctools/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FormatInsertFinalNewline,
FormatEndOfLine,
FormatVariablesAlign,
FormatConditionalParentheses,
)


Expand Down Expand Up @@ -46,6 +47,7 @@ def main(*args) -> int:
Formatter.register_rule(FormatInsertFinalNewline)
Formatter.register_rule(FormatEndOfLine)
Formatter.register_rule(FormatVariablesAlign)
Formatter.register_rule(FormatConditionalParentheses)

formatter = Formatter(
quiet=arguments.quiet,
Expand Down
43 changes: 30 additions & 13 deletions src/tctools/format_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,22 +340,24 @@ def __init__(self, *args):

self._re_needs_parentheses = re.compile(
r"""
^ # Look for start of string or new line
(\s*IF\s+) # Match IF with surrounding ws
([^(\r\n].+?[^)\r\n]) # Match any characters NOT whitin ()
(\s+THEN) # Match THEN with preceding ws
^ # Look for start of string or new line
\s*IF\s+ # Match IF with surrounding ws
([^(\r\n].+?) # Match any characters NOT starting with (
# We cannot match the closing bracket, as this could be
# from a function call
\s+THEN # Match THEN with preceding ws
""",
re.VERBOSE | re.MULTILINE
re.VERBOSE | re.MULTILINE,
)

self._re_removes_parentheses = re.compile(
r"""
^ # Look for start of string or new line
(\s*IF\s+) # Match IF with surrounding ws
\s*IF\s* # Match IF with surrounding ws
\((.+)\) # Match any characters whitin ()
(\s+THEN) # Match THEN with preceding ws
\s*THEN # Match THEN with preceding ws
""",
re.VERBOSE | re.MULTILINE
re.VERBOSE | re.MULTILINE,
)

def format(self, content: List[str], kind: Optional[Kind] = None):
Expand All @@ -364,12 +366,27 @@ def format(self, content: List[str], kind: Optional[Kind] = None):

if self._parentheses:
pattern = self._re_needs_parentheses
replace = r"\1(\2)\3"
else:
pattern = self._re_removes_parentheses
replace = r"\1\2\3"

for i, line in enumerate(content):
line_new, replacements = pattern.subn(replace, line)
if replacements > 0:
content[i] = line_new
# Do a manual match + replace, instead of e.g. subn(), because we might
# need to add extra spaces after removing parentheses
if match := pattern.search(line):
prefix = line[: match.start(1)]
condition = match.group(1)
suffix = line[match.end(1) :]

if self._parentheses:
condition = "(" + condition + ")"
else:
prefix = prefix[:-1] # Remove parentheses
suffix = suffix[1:]

# Removing the () could cause a syntax error:
if not prefix.endswith(" "):
prefix += " "
if not suffix.startswith(" "):
suffix = " " + suffix

content[i] = prefix + condition + suffix
47 changes: 31 additions & 16 deletions tests/test_formatting_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ def test_final_newline(content, expected):
properties = {"insert_final_newline": True}

rule = format_rules.FormatInsertFinalNewline(properties)
rule.format(content)

assert content == expected
content_new = content.copy()
rule.format(content_new)
assert content_new == expected


content_eol = [
Expand Down Expand Up @@ -170,9 +170,9 @@ def test_end_of_line(eol, expected):

content = content_before.copy()
rule = format_rules.FormatEndOfLine({"end_of_line": eol})
rule.format(content)

assert content == expected
content_new = content.copy()
rule.format(content_new)
assert content_new == expected


content_variables = [
Expand Down Expand Up @@ -245,8 +245,9 @@ def test_end_of_line(eol, expected):
@pytest.mark.parametrize("content,expected,settings", content_variables)
def test_variable_align(content, expected, settings):
rule = format_rules.FormatVariablesAlign(settings)
rule.format(content, Kind.DECLARATION)
assert content == expected
content_new = content.copy()
rule.format(content_new, Kind.DECLARATION)
assert content_new == expected


content_parentheses = [
Expand All @@ -272,31 +273,45 @@ def test_variable_align(content, expected, settings):
),
(
[
"IF inputs.button = 1 THEN\r\n",
"IF func(arg1 := 1, args2 := func2()) THEN\n",
],
[
"IF(inputs.button = 1)THEN\r\n",
"IF (func(arg1 := 1, args2 := func2())) THEN\n",
],
),
# ( # This case fails, because we cannot identify matching parentheses:
# [
# "IF (1+1)*2 = 3*(x-1) THEN\n",
# ],
# [
# "IF ((1+1)*2 = 3*(x-1)) THEN\n",
# ],
# ),
]


@pytest.mark.parametrize("content,expected", content_parentheses)
def test_parentheses_add(content, expected):
rule = format_rules.FormatConditionalParentheses({"parentheses_conditionals": True})
rule.format(content)
assert content == expected
content_new = content.copy()
rule.format(content_new)
assert content_new == expected


@pytest.mark.parametrize("expected,content", content_parentheses)
def test_parentheses_remove(expected, content):
rule = format_rules.FormatConditionalParentheses({"parentheses_conditionals": False})
rule.format(content)
assert content == expected
rule = format_rules.FormatConditionalParentheses(
{"parentheses_conditionals": False}
)
content_new = content.copy()
rule.format(content_new)
assert content_new == expected


def test_parentheses_remove_no_ws():
rule = format_rules.FormatConditionalParentheses({"parentheses_conditionals": False})
rule = format_rules.FormatConditionalParentheses(
{"parentheses_conditionals": False}
)
content = ["IF(inputs.button = 1)THEN"]
rule.format(content)
assert content == ["IF inputs.button = 1 THEN"]

0 comments on commit 6c28d26

Please sign in to comment.