Skip to content

Commit 18624e9

Browse files
committed
Add bracenewline.py
1 parent 7c04d3b commit 18624e9

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

wpiformat/wpiformat/__init__.py

+2
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
@@ -519,6 +520,7 @@ def main():
519520
# tasks so it can clean up their formatting.
520521
task_pipeline = [
521522
BraceComment(),
523+
BraceNewline(),
522524
CIdentList(),
523525
EofNewline(),
524526
GTestName(),

wpiformat/wpiformat/bracenewline.py

+66
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)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import os
2+
3+
from .test_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+
)
18+
19+
# Brackets on next line
20+
test.add_input(
21+
"./Test.cpp",
22+
"void func1() {"
23+
+ os.linesep
24+
+ "}"
25+
+ os.linesep
26+
+ "void func2() {"
27+
+ os.linesep
28+
+ "}"
29+
+ os.linesep,
30+
)
31+
test.add_output(
32+
"void func1() {"
33+
+ os.linesep
34+
+ "}"
35+
+ os.linesep
36+
+ os.linesep
37+
+ "void func2() {"
38+
+ os.linesep
39+
+ "}"
40+
+ os.linesep,
41+
True,
42+
)
43+
44+
# Comments after brackets
45+
test.add_input(
46+
"./Test.cpp",
47+
"void func1() {"
48+
+ os.linesep
49+
+ "} // This is a comment"
50+
+ os.linesep
51+
+ "void func2() {"
52+
+ os.linesep
53+
+ "} /* This is a comment */"
54+
+ os.linesep
55+
+ "void func3() {"
56+
+ os.linesep
57+
+ "}"
58+
+ os.linesep,
59+
)
60+
test.add_output(
61+
"void func1() {"
62+
+ os.linesep
63+
+ "} // This is a comment"
64+
+ os.linesep
65+
+ os.linesep
66+
+ "void func2() {"
67+
+ os.linesep
68+
+ "} /* This is a comment */"
69+
+ os.linesep
70+
+ os.linesep
71+
+ "void func3() {"
72+
+ os.linesep
73+
+ "}"
74+
+ os.linesep,
75+
True,
76+
)
77+
78+
# Don't add line separators to uncondensed if statements (after last brace
79+
# is OK)
80+
test.add_input(
81+
"./Test.cpp",
82+
"void func1() {"
83+
+ os.linesep
84+
+ " if (1) {"
85+
+ os.linesep
86+
+ " }"
87+
+ os.linesep
88+
+ " else {"
89+
+ os.linesep
90+
+ " }"
91+
+ os.linesep
92+
+ "}"
93+
+ os.linesep,
94+
)
95+
test.add_latest_input_as_output(True)
96+
97+
# Don't add line separators to condensed if statements (after last brace
98+
# is OK)
99+
test.add_input(
100+
"./Test.cpp",
101+
"void func1() {"
102+
+ os.linesep
103+
+ " if (1) {"
104+
+ os.linesep
105+
+ " } else if () {"
106+
+ os.linesep
107+
+ " } else {"
108+
+ os.linesep
109+
+ " // comment"
110+
+ os.linesep
111+
+ " }"
112+
+ os.linesep
113+
+ "}"
114+
+ os.linesep,
115+
)
116+
test.add_latest_input_as_output(True)
117+
118+
# Don't add line separators before #endif statements
119+
test.add_input(
120+
"./Main.cpp",
121+
"using decay_t = typename decay<T>::type;"
122+
+ os.linesep
123+
+ "} // namespace std"
124+
+ os.linesep
125+
+ "#endif"
126+
+ os.linesep,
127+
)
128+
test.add_latest_input_as_output(True)
129+
130+
# Don't insert line separators within multiline comments
131+
test.add_input(
132+
"./Main.java",
133+
"/* to fine tune the pid loop."
134+
+ os.linesep
135+
+ " *"
136+
+ os.linesep
137+
+ " * @return the {@link PIDController} used by this {@link PIDSubsystem}"
138+
+ os.linesep
139+
+ " */"
140+
+ os.linesep
141+
+ "public PIDController getPIDController() {"
142+
+ os.linesep,
143+
)
144+
test.add_latest_input_as_output(True)
145+
146+
# Don't insert line separators within single line comments
147+
test.add_input(
148+
"./Main.java",
149+
"// @return the {@link PIDController} used by this {@link PIDSubsystem}"
150+
+ os.linesep
151+
+ "public PIDController getPIDController() {"
152+
+ os.linesep,
153+
)
154+
test.add_latest_input_as_output(True)
155+
156+
test.run(OutputType.FILE)

0 commit comments

Comments
 (0)