Skip to content

Commit 1f63491

Browse files
committed
Add bracenewline.py
1 parent 0831768 commit 1f63491

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed

wpiformat/wpiformat/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99

1010
from wpiformat.bracecomment import BraceComment
11+
from wpiformat.bracenewline import BraceNewline
1112
from wpiformat.cidentlist import CIdentList
1213
from wpiformat.clangformat import ClangFormat
1314
from wpiformat.clangtidy import ClangTidy
@@ -469,6 +470,7 @@ def main():
469470
# tasks so it can clean up their formatting.
470471
task_pipeline = [
471472
BraceComment(),
473+
BraceNewline(),
472474
CIdentList(),
473475
EofNewline(),
474476
GTestName(),

wpiformat/wpiformat/bracenewline.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""This task ensures braces are followed by two line separators."""
2+
3+
import re
4+
5+
from wpiformat.task import Task
6+
7+
8+
class BraceNewline(Task):
9+
def should_process_file(self, config_file, name):
10+
return (
11+
config_file.is_c_file(name)
12+
or config_file.is_cpp_file(name)
13+
or name.endswith("java")
14+
)
15+
16+
def run_pipeline(self, config_file, name, lines):
17+
linesep = Task.get_linesep(lines)
18+
19+
comment_regex = re.compile("//|/\*|\*/")
20+
21+
lines_list = lines.split(linesep)
22+
23+
in_multiline_comment = False
24+
for i in range(len(lines_list)):
25+
match = comment_regex.search(lines_list[i])
26+
if not match:
27+
line = lines_list[i].rstrip()
28+
else:
29+
# While in a multiline comment, we only care about "*/"
30+
if in_multiline_comment:
31+
if match.group() == "*/":
32+
line = lines_list[i][match.start() + len("*/") :].rstrip()
33+
in_multiline_comment = False
34+
else:
35+
line = lines_list[i][0 : match.start()].rstrip()
36+
37+
# If multiline comment is starting
38+
if match.group() == "/*":
39+
line = lines_list[i][0 : match.start()]
40+
in_multiline_comment = True
41+
42+
# If comment ends on same line, handle it immediately
43+
comment_end = lines_list[i].find("*/")
44+
if comment_end != -1:
45+
line += lines_list[i][comment_end + len("*/") :]
46+
line = line.rstrip()
47+
in_multiline_comment = False
48+
49+
if in_multiline_comment:
50+
continue
51+
52+
# If line with "}" isn't at end of file
53+
if i + 1 < len(lines_list) and line.endswith("}"):
54+
next_line = lines_list[i + 1].lstrip()
55+
56+
# If next line is already empty, there's nothing to do
57+
if len(next_line) > 0:
58+
if (
59+
next_line[0] != "}"
60+
and "else" not in next_line
61+
and "#endif" not in next_line
62+
):
63+
lines_list.insert(i + 1, "")
64+
i += 1
65+
66+
return (linesep.join(lines_list), True)
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import os
2+
3+
from .tasktest import *
4+
from wpiformat.bracenewline import BraceNewline
5+
6+
7+
def test_bracenewline():
8+
test = TaskTest(BraceNewline())
9+
10+
# Brackets on same line
11+
test.add_input(
12+
"./Test.cpp", "void func1() {}" + os.linesep + "void func2() {}" + os.linesep
13+
)
14+
test.add_output(
15+
"void func1() {}" + os.linesep + os.linesep + "void func2() {}" + os.linesep,
16+
True,
17+
True,
18+
)
19+
20+
# Brackets on next line
21+
test.add_input(
22+
"./Test.cpp",
23+
"void func1() {"
24+
+ os.linesep
25+
+ "}"
26+
+ os.linesep
27+
+ "void func2() {"
28+
+ os.linesep
29+
+ "}"
30+
+ os.linesep,
31+
)
32+
test.add_output(
33+
"void func1() {"
34+
+ os.linesep
35+
+ "}"
36+
+ os.linesep
37+
+ os.linesep
38+
+ "void func2() {"
39+
+ os.linesep
40+
+ "}"
41+
+ os.linesep,
42+
True,
43+
True,
44+
)
45+
46+
# Comments after brackets
47+
test.add_input(
48+
"./Test.cpp",
49+
"void func1() {"
50+
+ os.linesep
51+
+ "} // This is a comment"
52+
+ os.linesep
53+
+ "void func2() {"
54+
+ os.linesep
55+
+ "} /* This is a comment */"
56+
+ os.linesep
57+
+ "void func3() {"
58+
+ os.linesep
59+
+ "}"
60+
+ os.linesep,
61+
)
62+
test.add_output(
63+
"void func1() {"
64+
+ os.linesep
65+
+ "} // This is a comment"
66+
+ os.linesep
67+
+ os.linesep
68+
+ "void func2() {"
69+
+ os.linesep
70+
+ "} /* This is a comment */"
71+
+ os.linesep
72+
+ os.linesep
73+
+ "void func3() {"
74+
+ os.linesep
75+
+ "}"
76+
+ os.linesep,
77+
True,
78+
True,
79+
)
80+
81+
# Don't add line separators to uncondensed if statements (after last brace
82+
# is OK)
83+
test.add_input(
84+
"./Test.cpp",
85+
"void func1() {"
86+
+ os.linesep
87+
+ " if (1) {"
88+
+ os.linesep
89+
+ " }"
90+
+ os.linesep
91+
+ " else {"
92+
+ os.linesep
93+
+ " }"
94+
+ os.linesep
95+
+ "}"
96+
+ os.linesep,
97+
)
98+
test.add_latest_input_as_output(True)
99+
100+
# Don't add line separators to condensed if statements (after last brace
101+
# is OK)
102+
test.add_input(
103+
"./Test.cpp",
104+
"void func1() {"
105+
+ os.linesep
106+
+ " if (1) {"
107+
+ os.linesep
108+
+ " } else if () {"
109+
+ os.linesep
110+
+ " } else {"
111+
+ os.linesep
112+
+ " // comment"
113+
+ os.linesep
114+
+ " }"
115+
+ os.linesep
116+
+ "}"
117+
+ os.linesep,
118+
)
119+
test.add_latest_input_as_output(True)
120+
121+
# Don't add line separators before #endif statements
122+
test.add_input(
123+
"./Main.cpp",
124+
"using decay_t = typename decay<T>::type;"
125+
+ os.linesep
126+
+ "} // namespace std"
127+
+ os.linesep
128+
+ "#endif"
129+
+ os.linesep,
130+
)
131+
test.add_latest_input_as_output(True)
132+
133+
# Don't insert line separators within multiline comments
134+
test.add_input(
135+
"./Main.java",
136+
"/* to fine tune the pid loop."
137+
+ os.linesep
138+
+ " *"
139+
+ os.linesep
140+
+ " * @return the {@link PIDController} used by this {@link PIDSubsystem}"
141+
+ os.linesep
142+
+ " */"
143+
+ os.linesep
144+
+ "public PIDController getPIDController() {"
145+
+ os.linesep,
146+
)
147+
test.add_latest_input_as_output(True)
148+
149+
# Don't insert line separators within single line comments
150+
test.add_input(
151+
"./Main.java",
152+
"// @return the {@link PIDController} used by this {@link PIDSubsystem}"
153+
+ os.linesep
154+
+ "public PIDController getPIDController() {"
155+
+ os.linesep,
156+
)
157+
test.add_latest_input_as_output(True)
158+
159+
test.run(OutputType.FILE)

0 commit comments

Comments
 (0)