#!/usr/bin/env python3 # file: scripts/audit_rust_blank_lines.py # version: 1 """Audit blank-line spacing in explicitly selected Rust sources.""" from __future__ import annotations import argparse import pathlib import re import sys from _rust_audit_common import line_depths, mask_source, selected_files _BODY = re.compile(r"^\s*(?:(?:pub(?:\([^)]*\))?|async|const|unsafe|extern|default)\s+)*(fn|struct|enum)\b") def audit_file(path: pathlib.Path) -> list[str]: """Check successive empty lines and empty function/struct/enum body lines.""" text = path.read_text(encoding="utf-8") lines = text.splitlines() masked, protected = mask_source(text) masked_lines = masked.splitlines() depths = line_depths(masked) errors: list[str] = [] previous_blank = False pending: tuple[str, int] | None = None active: tuple[str, int] | None = None for number, (original, code, depth) in enumerate(zip(lines, masked_lines, depths, strict=True), 1): blank = not original.strip() and number not in protected if blank and previous_blank: errors.append(f"{path}:{number}: consecutive blank Rust source lines") previous_blank = blank if active is not None and depth <= active[1]: active = None if active is not None and blank: errors.append(f"{path}:{number}: blank line inside {active[0]} body") if active is None and pending is None: match = _BODY.match(code) if match is not None: pending = (match.group(1), depth) if pending is not None: if "{" in code: active = pending pending = None elif ";" in code: pending = None return errors def main() -> int: """Run the read-only spacing audit on explicitly selected Rust files.""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("paths", nargs="+", help="Rust files or directories to inspect") args = parser.parse_args() files, errors = selected_files(args.paths) if errors or not files: for error in errors or ["no Rust files selected"]: print(f"Rust blank-line audit: {error}", file=sys.stderr) return 2 for path in files: try: errors.extend(audit_file(path)) except (OSError, UnicodeError) as error: print(f"Rust blank-line audit: cannot read {path}: {error}", file=sys.stderr) return 2 for error in errors: print(error, file=sys.stderr) if errors: print(f"Rust blank-line audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr) return 1 print(f"Rust blank-line audit: clean ({len(files)} file(s))") return 0 if __name__ == "__main__": raise SystemExit(main())