Skip to content

Commit 3ccac98

Browse files
committed
2-char indent also on first/last of %{ ... %} guts and avoid to
use clang-format on %include oriented gut lines
1 parent a8eeab9 commit 3ccac98

File tree

1 file changed

+60
-19
lines changed

1 file changed

+60
-19
lines changed

devel/bin/mccode-clangformat

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ BACKUP_SUFFIX = '.orig'
2424

2525
# Match a %{ on its own line then capture inner until a %} on its own line.
2626
BLOCK_RE = re.compile(
27-
r'(^[ \t]*%[\s]*\{\s*\n)(.*?)(\n[ \t]*%\}[ \t]*$)',
27+
r'(^[\s]*%\{[\s]*\n)(.*?)(\n[\s]*%\}[\s]*$)',
2828
re.DOTALL | re.MULTILINE
2929
)
3030

@@ -38,26 +38,22 @@ def find_files(root: Path) -> List[Path]:
3838
return files
3939

4040

41-
def _indent_middle_lines(core: str, indent_str: str, indent_blank_lines: bool) -> str:
41+
def _indent_lines(core: str, indent_str: str, indent_blank_lines: bool) -> str:
4242
"""
43-
Add `indent_str` to all lines of `core` except the first and last lines.
44-
`core` must not have leading/trailing newlines (strip them before calling).
45-
If there are fewer than 3 lines, there are no 'middle' lines to indent.
43+
Add `indent_str` to all lines of `core`. `core` may contain trailing newlines;
44+
those are preserved. We operate per-line using splitlines(True).
4645
"""
4746
if not indent_str:
4847
return core
4948

50-
lines = core.splitlines()
51-
if len(lines) < 3:
52-
return core
49+
lines = core.splitlines(True) # keep line endings
5350

54-
for i in range(1, len(lines) - 1):
51+
for i in range(0, len(lines)):
5552
if not indent_blank_lines and lines[i].strip() == '':
5653
continue
5754
lines[i] = indent_str + lines[i]
5855

59-
return "\n".join(lines)
60-
56+
return ''.join(lines)
6157

6258

6359
def run_clang_format_file_style(code: str, clang_path: str, assume_filename: Path) -> str:
@@ -75,6 +71,45 @@ def run_clang_format_file_style(code: str, clang_path: str, assume_filename: Pat
7571
return out
7672

7773

74+
def _format_preserving_percent_lines(inner: str, clang_path: str, style_file: Path) -> str:
75+
"""
76+
Format inner text with clang-format but skip lines that start with '%'.
77+
Keeps original line endings.
78+
"""
79+
lines = inner.splitlines(True) # preserve endings
80+
out_parts = []
81+
buffer = []
82+
83+
def flush_buffer():
84+
if not buffer:
85+
return
86+
chunk = ''.join(buffer)
87+
# strip only a single trailing newline so clang-format output is normalized
88+
if chunk.endswith('\n'):
89+
chunk_in = chunk[:-1]
90+
trailing_nl = '\n'
91+
else:
92+
chunk_in = chunk
93+
trailing_nl = ''
94+
formatted = run_clang_format_file_style(chunk_in, clang_path=clang_path, assume_filename=style_file)
95+
# clang-format usually emits a trailing newline; strip one to maintain control
96+
if formatted.endswith('\n'):
97+
formatted = formatted[:-1]
98+
out_parts.append(formatted + trailing_nl)
99+
buffer.clear()
100+
101+
for L in lines:
102+
if L.lstrip().startswith('%'):
103+
# flush any accumulated non-% lines, then append this % line unchanged
104+
flush_buffer()
105+
out_parts.append(L.lstrip())
106+
else:
107+
buffer.append(L)
108+
109+
flush_buffer()
110+
return ''.join(out_parts)
111+
112+
78113
def process_file(path: Path, clang_path: str, style_file: Path, check_only: bool = False,
79114
) -> Tuple[bool, str]:
80115
"""
@@ -89,24 +124,29 @@ def process_file(path: Path, clang_path: str, style_file: Path, check_only: bool
89124
inner = m.group(2)
90125
trailing = m.group(3)
91126

127+
# We'll feed clang-format only the non-'%' lines, preserving '%' lines.
92128
try:
93-
formatted_inner = run_clang_format_file_style(
129+
formatted_inner = _format_preserving_percent_lines(
94130
inner,
95131
clang_path=clang_path,
96-
assume_filename=style_file # force clang-format to use the script's style file
132+
style_file=style_file
97133
)
98134
except Exception as e:
99135
raise RuntimeError(f'Formatting failed for {path}: {e}')
100136

101-
# Strip only outer newlines; keep content as-is for first/last lines
102-
core = formatted_inner.strip('\n')
137+
# Preserve exact content lines from clang-format, but remove a single
138+
# trailing newline so we can control delimiter placement below.
139+
if formatted_inner.endswith('\n'):
140+
formatted_core = formatted_inner[:-1]
141+
else:
142+
formatted_core = formatted_inner
103143

104-
# Apply variable indentation to middle lines only
105-
core = _indent_middle_lines(core, indent_str=" ", indent_blank_lines=True)
144+
# Apply variable indentation (preserves per-line endings)
145+
core = _indent_lines(formatted_core, indent_str=" ", indent_blank_lines=False)
106146

107147
# If clang-format produced nothing meaningful, keep empty
108148
if core == '':
109-
result = leading + "\n" + trailing.lstrip("\n")
149+
result = leading + trailing.lstrip("\n")
110150
else:
111151
# Preserve delimiters on their own lines and ensure a newline before trailing
112152
result = leading + core + "\n" + trailing.lstrip("\n")
@@ -211,4 +251,5 @@ def main():
211251
print('No changes necessary.')
212252

213253
if __name__ == '__main__':
214-
main()
254+
main()
255+

0 commit comments

Comments
 (0)