Skip to content

Commit

Permalink
Merge pull request #13 from keyhr/master
Browse files Browse the repository at this point in the history
Fixed line break inserting
  • Loading branch information
keyhr committed Jan 30, 2022
2 parents 70e283b + 246f828 commit dd254e9
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 48 deletions.
2 changes: 1 addition & 1 deletion c_formatter_42/data/.clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ BreakBeforeTernaryOperators: true

# ColumnLimit (unsigned)
# The column limit.
ColumnLimit: 80
ColumnLimit: 0


# FixNamespaceComments (bool)
Expand Down
57 changes: 48 additions & 9 deletions c_formatter_42/formatters/line_breaker.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import re
from c_formatter_42.formatters import helper


def line_breaker(content: str, column_limit: int = 80) -> str:
lines = content.split("\n")
lines = list(map(lambda s: insert_break(s, column_limit), lines))

return "\n".join(lines)


def insert_break(line: str, column_limit: int) -> str:
if line_length(line) <= column_limit:
return line

line_indent_level = indent_level(line)
tabulation = "\t" * (line_indent_level + 1)

# break at all breakable spaces (space after comma or space before binary operators)
breakable_space_pattern = r"((?<=,) | (?=[+\-*/%])(?!\*+\S|\+\+|\-\-))"
line = re.sub(breakable_space_pattern, "\n", line)
segments = line.split("\n")

line_indent_level = indent_level(line)

# join as many segments as it doesn't exceed line length limit
line = segments[0]
current_line_length = line_length(segments[0])
for segment in segments[1:]:
current_line_length += line_length(segment) + 1
if current_line_length > column_limit:
tabulation = "\t" * (line_indent_level + additional_indent_level(line))
line = ("\n" + tabulation).join([line, segment])
current_line_length = line_length(tabulation + segment)
else:
Expand All @@ -33,15 +35,52 @@ def insert_break(line: str, column_limit: int) -> str:
return line


#
# additional indent level increases in proportion to corresponds paren depth
#
# (examples)
# foo() * bar() * baz()
# ~~~~~~~~~~~~~^~~~~~~~ when line breaks here,
# foo() * bar()
# > * baz() next line should be indented with 1 tab
# ===
# (foo(bar() * baz()))
# ~~~~~~~~~~^~~~~~~~~ when line breaks here,
# (foo(bar()
# > > > * baz())) next line should be indented with 3 tabs
#
# function declaration, user defined type (?), and control statement needs one less tab (discount)
#
def additional_indent_level(s: str) -> int:
additional_indent_level = 1

discount_pattern = r"(^\t*{type}\t+.*?[a-zA-Z0-9_]\()|(^\t*typedef)|(^\t*(if|while))"
discount_pattern = discount_pattern.format(
type=helper.REGEX_TYPE,
)
if re.match(discount_pattern, s):
additional_indent_level = 0

is_surrounded_sq = False
is_surrounded_dq = False

for c in s:
if c == "'":
is_surrounded_sq = not is_surrounded_sq
elif c == '"':
is_surrounded_dq = not is_surrounded_dq
elif c == "(" and not is_surrounded_sq and not is_surrounded_dq:
additional_indent_level += 1
elif c == ")" and not is_surrounded_sq and not is_surrounded_dq:
additional_indent_level -= 1

return additional_indent_level


def line_length(line: str) -> int:
line = line.expandtabs(4)
return len(line)


def indent_level(line: str) -> int:
last_tab_occurance = line.rfind("\t")
if last_tab_occurance < 0:
return 0

line = line[: (last_tab_occurance + 1)]
return int(len(line.expandtabs(4)) / 4)
return line.count("\t")
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = c_formatter_42
version = 0.1.2
version = 0.1.3
description = formatting tool complient with 42 school's norm
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down
53 changes: 20 additions & 33 deletions tests/formatters/test_clang_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,26 @@ def test_clang_format_empty():
assert clang_format("") == ""


def test_clang_format_dont_join_lines():
input = """
if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
\t|| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
\t|| cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
"""
output = """
if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||
\tbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ||
\tcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
"""
assert clang_format(input) == output

input = """
if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||
\tbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ||
\tcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
"""
assert clang_format(input) == input

# def test_clang_format_dont_join_lines():
# input = """
# if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
# \t|| bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
# \t|| cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
# """
# output = """
# if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||
# \tbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ||
# \tcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
# """
# assert clang_format(input) == output
#
# input = """
# if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||
# \tbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ||
# \tcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
# """
# assert clang_format(input) == input
#

def test_clang_format_non_array_assignment_packing():
input = """
Expand All @@ -71,19 +71,6 @@ def test_clang_format_non_array_assignment_packing():
assert clang_format(input) == input


def test_clang_format_long_function_declaration():
input = """
static void st_merge_fields_in_curr(
\t\tchar *strs[3], t_tok_lst **curr, t_tok_lst *fields)
"""
output = """
static void st_merge_fields_in_curr(char *strs[3],
\t\t\t\t\t\t\t\t\tt_tok_lst **curr,
\t\t\t\t\t\t\t\t\tt_tok_lst *fields)
"""
assert clang_format(input) == output


@contextmanager
def change_temp_dir_context():
tempdir = tempfile.mkdtemp("c_formatter_42")
Expand Down
13 changes: 13 additions & 0 deletions tests/formatters/test_hoist.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,20 @@ def test_hoist_ex():
""")

# TODO test on weird types
output = """\
void foo()
{
\tt_list\t*bar;
\tbar = (t_list *)malloc(sizeof(t_list) * (count_elements(baz) + 1));
}
"""
assert output == hoist("""\
void foo()
{
\tt_list\t*bar = (t_list *)malloc(sizeof(t_list) * (count_elements(baz) + 1));
}
""")

@pytest.mark.skip()
def test_hoist_array():
Expand Down
42 changes: 38 additions & 4 deletions tests/formatters/test_line_breaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_line_indent_depth_basic_3():
input = """\
\t\t\t + 2 + 2 + 2\t
"""
assert 7 == indent_level(input)
assert 4 == indent_level(input)


def test_insert_line_break_basic_1():
Expand All @@ -40,8 +40,8 @@ def test_insert_line_break_basic_2():
def test_insert_line_break_basic_3():
output = """\
\t\t\t\treturn (fooooooooooooooooooooooooo(a, b, cccccccccccc,
\t\t\t\t\tddddddddddddd, eeeeeeeeeeeeeeee, fffffffffffffff,
\t\t\t\t\tgggggggggggg, hhhhhhhhhhhhhhhhhh));
\t\t\t\t\t\t\tddddddddddddd, eeeeeeeeeeeeeeee, fffffffffffffff,
\t\t\t\t\t\t\tgggggggggggg, hhhhhhhhhhhhhhhhhh));
"""
assert output == line_breaker("""\
\t\t\t\treturn (fooooooooooooooooooooooooo(a, b, cccccccccccc, ddddddddddddd, eeeeeeeeeeeeeeee, fffffffffffffff, gggggggggggg, hhhhhhhhhhhhhhhhhh));
Expand All @@ -50,7 +50,7 @@ def test_insert_line_break_basic_3():
def test_insert_line_break_basic_4():
output = """\
void\t\tlooooooooooooooooooooooong = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2
\t\t\t\t+ 2 + 2 + 2;
\t\t\t+ 2 + 2 + 2;
"""
assert output == line_breaker("""\
void\t\tlooooooooooooooooooooooong = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2;
Expand Down Expand Up @@ -151,3 +151,37 @@ def test_insert_line_break_basic_22():
output = ",\n\taaaa* b"
assert output == line_breaker(", aaaa* b", 7)

def test_insert_line_break_basic_23():
output = "foooooo(bar\n\t\t* baz)"
assert output == line_breaker("foooooo(bar * baz)", 7)


def test_insert_line_break_long_function_declaration():
input = """
static void\tst_merge_fields_in_curr(char *strs[3], t_tok_lst **curr, t_tok_lst *fields)
"""
output = """
static void\tst_merge_fields_in_curr(char *strs[3], t_tok_lst **curr,
\t\tt_tok_lst *fields)
"""
assert line_breaker(input) == output

def test_insert_line_break_control_statement_1():
input = """\
\twhile (true + false)
"""
output = """\
\twhile (true
\t\t+ false)
"""
assert line_breaker(input, 7) == output

def test_insert_line_break_control_statement_2():
input = """\
\tif (true + false)
"""
output = """\
\tif (true
\t\t+ false)
"""
assert line_breaker(input, 5) == output

0 comments on commit dd254e9

Please sign in to comment.