Performance improvements, better readme and complete python bindings
🧪 Test / test (push) Failing after 28m30s
🧪 Test / test (push) Failing after 28m30s
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Render README.md from README.md.in by expanding @snippet directives.
|
||||
|
||||
Directive format (in README.md.in):
|
||||
<!-- @snippet path/to/file.cpp snippet_name -->
|
||||
|
||||
Snippet tags (in C++ source files):
|
||||
// [snippet: snippet_name]
|
||||
...content...
|
||||
// [/snippet: snippet_name]
|
||||
|
||||
In Python files use # instead of //.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
TEMPLATE = ROOT / "README.md.in"
|
||||
OUTPUT = ROOT / "README.md"
|
||||
|
||||
DIRECTIVE_RE = re.compile(r'<!--\s*@snippet\s+(\S+)\s+(\S+)\s*-->')
|
||||
|
||||
LANG_MAP = {'.cpp': 'cpp', '.hpp': 'cpp', '.h': 'cpp', '.py': 'python', '.c': 'c'}
|
||||
|
||||
|
||||
def comment_prefix(path: Path) -> str:
|
||||
return '#' if path.suffix == '.py' else '//'
|
||||
|
||||
|
||||
def extract_snippet(file_path: Path, name: str) -> str:
|
||||
prefix = comment_prefix(file_path)
|
||||
open_tag = f'{prefix} [snippet: {name}]'
|
||||
close_tag = f'{prefix} [/snippet: {name}]'
|
||||
|
||||
text = file_path.read_text()
|
||||
lines = text.splitlines()
|
||||
|
||||
in_snippet = False
|
||||
found = False
|
||||
result = []
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if stripped == open_tag:
|
||||
if in_snippet:
|
||||
raise ValueError(f"Nested open tag for '{name}' in {file_path}")
|
||||
in_snippet = True
|
||||
found = True
|
||||
continue
|
||||
if stripped == close_tag:
|
||||
if not in_snippet:
|
||||
raise ValueError(f"Unexpected close tag for '{name}' in {file_path}")
|
||||
in_snippet = False
|
||||
continue
|
||||
if in_snippet:
|
||||
result.append(line)
|
||||
|
||||
if not found:
|
||||
raise ValueError(f"Snippet '{name}' not found in {file_path}")
|
||||
if in_snippet:
|
||||
raise ValueError(f"Unclosed snippet '{name}' in {file_path}")
|
||||
|
||||
# Strip leading/trailing blank lines
|
||||
while result and not result[0].strip():
|
||||
result.pop(0)
|
||||
while result and not result[-1].strip():
|
||||
result.pop()
|
||||
|
||||
# Dedent common leading whitespace
|
||||
content = textwrap.dedent('\n'.join(result))
|
||||
return content
|
||||
|
||||
|
||||
def lang_for(file_path: Path) -> str:
|
||||
return LANG_MAP.get(file_path.suffix, '')
|
||||
|
||||
|
||||
def render(template: str) -> str:
|
||||
errors = []
|
||||
|
||||
def replace(m: re.Match) -> str:
|
||||
rel_path = m.group(1)
|
||||
name = m.group(2)
|
||||
file_path = ROOT / rel_path
|
||||
if not file_path.exists():
|
||||
errors.append(f"File not found: {file_path}")
|
||||
return m.group(0)
|
||||
try:
|
||||
content = extract_snippet(file_path, name)
|
||||
except ValueError as e:
|
||||
errors.append(str(e))
|
||||
return m.group(0)
|
||||
lang = lang_for(file_path)
|
||||
return f'```{lang}\n{content}\n```'
|
||||
|
||||
result = DIRECTIVE_RE.sub(replace, template)
|
||||
|
||||
if errors:
|
||||
for err in errors:
|
||||
print(f"ERROR: {err}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not TEMPLATE.exists():
|
||||
print(f"Error: {TEMPLATE} not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
rendered = render(TEMPLATE.read_text())
|
||||
OUTPUT.write_text(rendered)
|
||||
print(f"Rendered {TEMPLATE.name} → {OUTPUT.name}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user