Skip to content

Commit bcf38b8

Browse files
committed
Use root minify.py and fix test file path in injector
1 parent 933218a commit bcf38b8

File tree

3 files changed

+170
-2
lines changed

3 files changed

+170
-2
lines changed

.github/workflows/verify.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ jobs:
4646
# Specify patterns
4747
exclude: |
4848
images/
49+
.verify-helper/scripts/
4950
# If you have config.toml
5051
config: .verify-helper/config.toml
5152
- name: parse-doxygen

.verify-helper/scripts/inject_minified_docs.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def minify_code(code):
3333
"""Minify C++ code on-the-fly using the minify utility."""
3434
try:
3535
result = subprocess.run(
36-
['python3', 'cp-algo/util/minify.py'],
36+
['python3', 'cp-algo/minify.py'],
3737
input=code,
3838
capture_output=True,
3939
text=True,
@@ -145,6 +145,8 @@ def main():
145145
markdown_dir = Path('_jekyll')
146146
minified_dir = Path('cp-algo/min')
147147
minified_bundled_dir = Path('.competitive-verifier/minified-bundled')
148+
# Repository root (script is in .verify-helper/scripts/)
149+
repo_root = Path(__file__).resolve().parents[2]
148150

149151
# If _jekyll doesn't exist, try the verify-helper path (for local testing)
150152
if not markdown_dir.exists():
@@ -200,7 +202,7 @@ def main():
200202
# Reconstruct source file path - test files are relative to repo root
201203
if original_ext:
202204
# path_without_ext is like "verify/test_file", we need the actual file in the repo
203-
source_file = docs_root.parent / (path_without_ext + original_ext)
205+
source_file = repo_root / (path_without_ext + original_ext)
204206
if source_file.exists():
205207
# Generate bundled+minified version only
206208
minified_bundled_code = bundle_and_minify(source_file)

cp-algo/minify.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simple C++ code minifier for competitive programming.
4+
Removes comments, extra whitespace, and compresses the code.
5+
"""
6+
7+
import re
8+
import sys
9+
10+
def minify_cpp(code):
11+
# Remove comments while preserving strings
12+
lines = code.split('\n')
13+
cleaned_lines = []
14+
15+
for line in lines:
16+
# Remove single-line comments, but not if // is inside a string
17+
in_string = False
18+
escape_next = False
19+
result = []
20+
i = 0
21+
22+
while i < len(line):
23+
if escape_next:
24+
result.append(line[i])
25+
escape_next = False
26+
i += 1
27+
continue
28+
29+
if line[i] == '\\' and in_string:
30+
result.append(line[i])
31+
escape_next = True
32+
i += 1
33+
continue
34+
35+
if line[i] == '"':
36+
result.append(line[i])
37+
in_string = not in_string
38+
i += 1
39+
continue
40+
41+
if not in_string and i + 1 < len(line) and line[i:i+2] == '//':
42+
# Found comment outside string, discard rest of line
43+
break
44+
45+
result.append(line[i])
46+
i += 1
47+
48+
cleaned_lines.append(''.join(result))
49+
50+
code = '\n'.join(cleaned_lines)
51+
52+
# Remove multi-line comments (but preserve #line directives content)
53+
code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL)
54+
55+
# Remove empty lines
56+
code = re.sub(r'\n\s*\n', '\n', code)
57+
58+
# Remove leading/trailing whitespace on each line
59+
lines = [line.strip() for line in code.split('\n')]
60+
61+
# Keep preprocessor directives on their own lines
62+
result = []
63+
for line in lines:
64+
if line.startswith('#'):
65+
result.append(line)
66+
elif line:
67+
result.append(line)
68+
69+
code = '\n'.join(result)
70+
71+
# Compress spaces (but not in preprocessor directives or strings)
72+
def compress_line(line):
73+
if line.startswith('#'):
74+
return line
75+
76+
# Split by string literals while keeping them
77+
result = []
78+
current = []
79+
i = 0
80+
81+
while i < len(line):
82+
if line[i] == '"':
83+
# Found start of string - save accumulated code
84+
if current:
85+
code_part = ''.join(current)
86+
# Compress the code part
87+
code_part = re.sub(r'\s+', ' ', code_part)
88+
code_part = re.sub(r'\s*([+\-*/%=<>!&|^~,;:?(){}[\]])\s*', r'\1', code_part)
89+
result.append(code_part)
90+
current = []
91+
92+
# Now collect the entire string literal
93+
string_chars = ['"']
94+
i += 1
95+
while i < len(line):
96+
if line[i] == '\\' and i + 1 < len(line):
97+
# Escape sequence
98+
string_chars.append(line[i])
99+
string_chars.append(line[i + 1])
100+
i += 2
101+
elif line[i] == '"':
102+
# End of string
103+
string_chars.append('"')
104+
i += 1
105+
break
106+
else:
107+
string_chars.append(line[i])
108+
i += 1
109+
110+
# Keep string literal as-is
111+
result.append(''.join(string_chars))
112+
else:
113+
current.append(line[i])
114+
i += 1
115+
116+
# Handle any remaining code
117+
if current:
118+
code_part = ''.join(current)
119+
code_part = re.sub(r'\s+', ' ', code_part)
120+
code_part = re.sub(r'\s*([+\-*/%=<>!&|^~,;:?(){}[\]])\s*', r'\1', code_part)
121+
result.append(code_part)
122+
123+
return ''.join(result)
124+
125+
lines = [compress_line(line) for line in code.split('\n')]
126+
127+
# Join lines intelligently: keep preprocessor directives on their own lines,
128+
# and keep a newline after them
129+
result_lines = []
130+
for i, line in enumerate(lines):
131+
if not line:
132+
continue
133+
134+
if line.startswith('#'):
135+
# Preprocessor directive - always on its own line
136+
result_lines.append(line)
137+
else:
138+
# Regular code - try to join with previous line if possible
139+
if result_lines and not result_lines[-1].startswith('#'):
140+
# Previous line is not a preprocessor directive, can join
141+
result_lines[-1] += line
142+
else:
143+
# Previous line is a preprocessor directive or this is first line
144+
result_lines.append(line)
145+
146+
code = '\n'.join(result_lines)
147+
148+
return code
149+
150+
if __name__ == '__main__':
151+
if len(sys.argv) > 1:
152+
with open(sys.argv[1], 'r') as f:
153+
code = f.read()
154+
else:
155+
code = sys.stdin.read()
156+
157+
minified = minify_cpp(code)
158+
print(minified)
159+
160+
# Print stats to stderr
161+
original_size = len(code)
162+
minified_size = len(minified)
163+
print(f"Original: {original_size} bytes", file=sys.stderr)
164+
print(f"Minified: {minified_size} bytes", file=sys.stderr)
165+
print(f"Reduction: {original_size - minified_size} bytes ({100*(1-minified_size/original_size):.1f}%)", file=sys.stderr)

0 commit comments

Comments
 (0)