0704
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate line-by-line diff between two markdown files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def read_lines(path: Path) -> list[str]:
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
return text.splitlines()
|
||||
|
||||
|
||||
def generate_line_diff(src: Path, dst: Path) -> str:
|
||||
src_lines = read_lines(src)
|
||||
dst_lines = read_lines(dst)
|
||||
src_name = src.as_posix()
|
||||
dst_name = dst.as_posix()
|
||||
diff = difflib.unified_diff(
|
||||
src_lines,
|
||||
dst_lines,
|
||||
fromfile=src_name,
|
||||
tofile=dst_name,
|
||||
lineterm="",
|
||||
)
|
||||
return "\n".join(diff)
|
||||
|
||||
|
||||
def generate_compact_line_diff(src: Path, dst: Path, context: int = 2) -> str:
|
||||
"""Generate a compact diff showing only changed lines with a little context."""
|
||||
src_lines = read_lines(src)
|
||||
dst_lines = read_lines(dst)
|
||||
src_name = src.as_posix()
|
||||
dst_name = dst.as_posix()
|
||||
|
||||
sm = difflib.SequenceMatcher(None, src_lines, dst_lines)
|
||||
output = [f"--- {src_name}", f"+++ {dst_name}", ""]
|
||||
|
||||
for tag, i1, i2, j1, j2 in sm.get_opcodes():
|
||||
if tag == "equal":
|
||||
# Show only a few context lines around changes
|
||||
if context > 0:
|
||||
ctx = src_lines[i1:i2]
|
||||
if len(ctx) <= context * 2 + 1:
|
||||
for line in ctx:
|
||||
output.append(f" {line}")
|
||||
else:
|
||||
for line in ctx[:context]:
|
||||
output.append(f" {line}")
|
||||
output.append(" ...")
|
||||
for line in ctx[-context:]:
|
||||
output.append(f" {line}")
|
||||
elif tag == "replace":
|
||||
output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},{j2 - j1} @@")
|
||||
for line in src_lines[i1:i2]:
|
||||
output.append(f"-{line}")
|
||||
for line in dst_lines[j1:j2]:
|
||||
output.append(f"+{line}")
|
||||
elif tag == "delete":
|
||||
output.append(f"@@ -{i1 + 1},{i2 - i1} +{j1 + 1},0 @@")
|
||||
for line in src_lines[i1:i2]:
|
||||
output.append(f"-{line}")
|
||||
elif tag == "insert":
|
||||
output.append(f"@@ -{i1 + 1},0 +{j1 + 1},{j2 - j1} @@")
|
||||
for line in dst_lines[j1:j2]:
|
||||
output.append(f"+{line}")
|
||||
|
||||
return "\n".join(output)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Generate line-by-line diff for markdown files.")
|
||||
parser.add_argument("--input-dir", type=Path, required=True, help="Directory containing source files.")
|
||||
parser.add_argument("--output-dir", type=Path, required=True, help="Directory containing polished files.")
|
||||
parser.add_argument("--out-diff-dir", type=Path, required=True, help="Directory to write diff files.")
|
||||
parser.add_argument("--compact", action="store_true", help="Show only changed lines with context.")
|
||||
parser.add_argument("--context", type=int, default=2, help="Number of context lines around changes (compact mode).")
|
||||
args = parser.parse_args()
|
||||
|
||||
args.out_diff_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for src in sorted(args.input_dir.glob("*.md")):
|
||||
dst = args.output_dir / src.name
|
||||
if not dst.exists():
|
||||
print(f"Skip {src.name}: no matching polished file.")
|
||||
continue
|
||||
|
||||
if args.compact:
|
||||
diff_text = generate_compact_line_diff(src, dst, context=args.context)
|
||||
suffix = "-compact.diff"
|
||||
else:
|
||||
diff_text = generate_line_diff(src, dst)
|
||||
suffix = "-line.diff"
|
||||
|
||||
out_path = args.out_diff_dir / (src.stem + suffix)
|
||||
out_path.write_text(diff_text, encoding="utf-8")
|
||||
print(f"Wrote {out_path}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user