|
| 1 | +from __future__ import annotations |
| 2 | + |
1 | 3 | import logging |
2 | 4 | import sys |
| 5 | +from typing import TYPE_CHECKING, Any |
3 | 6 |
|
| 7 | +if TYPE_CHECKING: |
| 8 | + from .cli import ParsedArgs |
4 | 9 |
|
5 | | -def main() -> None: |
6 | | - # Force UTF-8 for stdout on Windows (default cp1252 can't handle Unicode) |
| 10 | + |
| 11 | +def _configure_windows_utf8() -> None: |
7 | 12 | if sys.platform == "win32" and hasattr(sys.stdout, "reconfigure"): |
8 | 13 | sys.stdout.reconfigure(encoding="utf-8") |
9 | | - from .cli import parse_args |
10 | | - from .clipboard import ClipboardError, copy_to_clipboard |
| 14 | + |
| 15 | + |
| 16 | +def _build_diff_tree(args: ParsedArgs) -> dict[str, Any]: |
| 17 | + from .diffctx import GitError, build_diff_context |
| 18 | + |
| 19 | + assert args.diff_range is not None |
| 20 | + try: |
| 21 | + return build_diff_context( |
| 22 | + root_dir=args.root_dir, |
| 23 | + diff_range=args.diff_range, |
| 24 | + budget_tokens=args.budget, |
| 25 | + alpha=args.alpha, |
| 26 | + tau=args.tau, |
| 27 | + no_content=args.no_content, |
| 28 | + ignore_file=args.ignore_file, |
| 29 | + no_default_ignores=args.no_default_ignores, |
| 30 | + full=args.full_diff, |
| 31 | + ) |
| 32 | + except GitError as e: |
| 33 | + print(f"Error: {e}", file=sys.stderr) |
| 34 | + sys.exit(1) |
| 35 | + |
| 36 | + |
| 37 | +def _build_standard_tree(args: ParsedArgs) -> dict[str, Any]: |
11 | 38 | from .ignore import get_ignore_specs |
12 | | - from .logger import setup_logging |
13 | | - from .tokens import print_token_summary |
14 | 39 | from .tree import TreeBuildContext, build_tree |
15 | | - from .writer import tree_to_string, write_string_to_file |
16 | 40 |
|
| 41 | + ctx = TreeBuildContext( |
| 42 | + base_dir=args.root_dir, |
| 43 | + combined_spec=get_ignore_specs(args.root_dir, args.ignore_file, args.no_default_ignores, args.output_file), |
| 44 | + output_file=args.output_file, |
| 45 | + max_depth=args.max_depth, |
| 46 | + no_content=args.no_content, |
| 47 | + max_file_bytes=args.max_file_bytes, |
| 48 | + ) |
| 49 | + return { |
| 50 | + "name": args.root_dir.name, |
| 51 | + "type": "directory", |
| 52 | + "children": build_tree(args.root_dir, ctx), |
| 53 | + } |
| 54 | + |
| 55 | + |
| 56 | +def _handle_clipboard(output_content: str, args: ParsedArgs) -> bool: |
| 57 | + from .clipboard import ClipboardError, copy_to_clipboard |
| 58 | + |
| 59 | + if not args.copy: |
| 60 | + return False |
17 | 61 | try: |
18 | | - args = parse_args() |
19 | | - setup_logging(args.verbosity) |
20 | | - |
21 | | - if args.diff_range: |
22 | | - from .diffctx import GitError, build_diff_context |
23 | | - |
24 | | - try: |
25 | | - directory_tree = build_diff_context( |
26 | | - root_dir=args.root_dir, |
27 | | - diff_range=args.diff_range, |
28 | | - budget_tokens=args.budget, |
29 | | - alpha=args.alpha, |
30 | | - tau=args.tau, |
31 | | - no_content=args.no_content, |
32 | | - ignore_file=args.ignore_file, |
33 | | - no_default_ignores=args.no_default_ignores, |
34 | | - full=args.full_diff, |
35 | | - ) |
36 | | - except GitError as e: |
37 | | - print(f"Error: {e}", file=sys.stderr) |
38 | | - sys.exit(1) |
39 | | - else: |
40 | | - ctx = TreeBuildContext( |
41 | | - base_dir=args.root_dir, |
42 | | - combined_spec=get_ignore_specs(args.root_dir, args.ignore_file, args.no_default_ignores, args.output_file), |
43 | | - output_file=args.output_file, |
44 | | - max_depth=args.max_depth, |
45 | | - no_content=args.no_content, |
46 | | - max_file_bytes=args.max_file_bytes, |
47 | | - ) |
48 | | - |
49 | | - directory_tree = { |
50 | | - "name": args.root_dir.name, |
51 | | - "type": "directory", |
52 | | - "children": build_tree(args.root_dir, ctx), |
53 | | - } |
54 | | - |
55 | | - output_content = tree_to_string(directory_tree, args.output_format) |
56 | | - print_token_summary(output_content) |
57 | | - |
58 | | - clipboard_ok = False |
59 | | - if args.copy: |
60 | | - try: |
61 | | - copy_to_clipboard(output_content) |
62 | | - print("Copied to clipboard", file=sys.stderr) |
63 | | - clipboard_ok = True |
64 | | - except ClipboardError as e: |
65 | | - print(f"Clipboard unavailable: {e}", file=sys.stderr) |
66 | | - |
67 | | - if args.output_file: |
68 | | - try: |
69 | | - write_string_to_file(output_content, args.output_file, args.output_format) |
70 | | - print(f"Saved to {args.output_file}", file=sys.stderr) |
71 | | - except IsADirectoryError: |
72 | | - print(f"Error: {args.output_file} is a directory", file=sys.stderr) |
73 | | - sys.exit(1) |
74 | | - except OSError: |
75 | | - sys.exit(1) |
76 | | - elif args.force_stdout or not args.copy or not clipboard_ok: |
77 | | - # force_stdout: -o - was explicitly passed (forces stdout even with --copy) |
78 | | - sys.stdout.write(output_content) |
79 | | - logging.info(f"Directory tree written to stdout in {args.output_format} format") |
| 62 | + copy_to_clipboard(output_content) |
| 63 | + print("Copied to clipboard", file=sys.stderr) |
| 64 | + return True |
| 65 | + except ClipboardError as e: |
| 66 | + print(f"Clipboard unavailable: {e}", file=sys.stderr) |
| 67 | + return False |
80 | 68 |
|
| 69 | + |
| 70 | +def _handle_output_file(output_content: str, args: ParsedArgs) -> None: |
| 71 | + from .writer import write_string_to_file |
| 72 | + |
| 73 | + if not args.output_file: |
| 74 | + return |
| 75 | + try: |
| 76 | + write_string_to_file(output_content, args.output_file, args.output_format) |
| 77 | + print(f"Saved to {args.output_file}", file=sys.stderr) |
| 78 | + except IsADirectoryError: |
| 79 | + print(f"Error: {args.output_file} is a directory", file=sys.stderr) |
| 80 | + sys.exit(1) |
| 81 | + except OSError: |
| 82 | + sys.exit(1) |
| 83 | + |
| 84 | + |
| 85 | +def _run() -> None: |
| 86 | + from .cli import parse_args |
| 87 | + from .logger import setup_logging |
| 88 | + from .tokens import print_token_summary |
| 89 | + from .writer import tree_to_string |
| 90 | + |
| 91 | + args = parse_args() |
| 92 | + setup_logging(args.verbosity) |
| 93 | + |
| 94 | + directory_tree = _build_diff_tree(args) if args.diff_range else _build_standard_tree(args) |
| 95 | + |
| 96 | + output_content = tree_to_string(directory_tree, args.output_format) |
| 97 | + print_token_summary(output_content) |
| 98 | + |
| 99 | + clipboard_ok = _handle_clipboard(output_content, args) |
| 100 | + _handle_output_file(output_content, args) |
| 101 | + |
| 102 | + should_write_stdout = args.force_stdout or not args.copy or not clipboard_ok |
| 103 | + if not args.output_file and should_write_stdout: |
| 104 | + sys.stdout.write(output_content) |
| 105 | + logging.info(f"Directory tree written to stdout in {args.output_format} format") |
| 106 | + |
| 107 | + |
| 108 | +def main() -> None: |
| 109 | + _configure_windows_utf8() |
| 110 | + try: |
| 111 | + _run() |
81 | 112 | except KeyboardInterrupt: |
82 | 113 | print("\nInterrupted", file=sys.stderr) |
83 | 114 | sys.exit(130) |
|
0 commit comments