#! /usr/bin/env python3 from pathlib import Path import argparse def parse_args(): parser = argparse.ArgumentParser(description="Count and sort lines of code in selected files.") parser.add_argument( "--search-dirs", nargs="+", required=True, help="List of directories to search (recursively)." ) parser.add_argument( "--include-exts", nargs="+", required=True, help="List of file extensions to include (e.g. .cpp .hpp .py)" ) parser.add_argument( "--exclude-paths", nargs="*", default=[], help="Full file paths to exclude from counting." ) return parser.parse_args() def main(): args = parse_args() include_exts = tuple(args.include_exts) exclude_paths = {Path(p).resolve() for p in args.exclude_paths} files = [] for base in args.search_dirs: path = Path(base) if path.is_dir(): for file in path.rglob("*"): try: resolved_file = file.resolve() if ( file.is_file() and file.name.endswith(include_exts) and resolved_file not in exclude_paths ): files.append(str(resolved_file)) except FileNotFoundError: continue line_counts = [] total_lines = 0 for f in files: try: with open(f, "r", encoding="utf-8", errors="ignore") as file: lines = sum(1 for _ in file) line_counts.append((lines, f)) total_lines += lines except Exception as e: print(f"Failed to read {f}: {e}") line_counts.sort() for count, filename in line_counts: print(f"{count:>7} {filename}") print(f"{total_lines:>7} total") if __name__ == "__main__": main()