Directory Tree Generation Utilities.
This module provides functions to generate a textual or Rich-enhanced representation of a directory's structure. It supports excluding specified files and directories and can output the tree to the console or a file.
Core functionalities: - Recursive traversal of directories. - Filtering of items based on .llmignore files, CLI arguments, core system exclusions, and a default set of common development artifacts. - Generation of plain text tree for file output. - Generation of a Rich Tree
object for styled console output.
Generate and output tree structure.
Parameters:
Name | Type | Description | Default |
---|
root_dir | Path | Root directory to generate tree for. | required |
output_file_path | Optional[Path] | Optional path to save the tree. If None, returns string for console. | None |
ignore_list | Optional[list[str]] | List of patterns to ignore. | None |
config_global_excludes | Optional[list[str]] | Global exclusion patterns from config. | None |
Returns:
Type | Description |
---|
Optional[str] | String representation of the tree if no output file specified, None otherwise. |
Source code in src/codebrief/tools/tree_generator.py
| def generate_and_output_tree(
root_dir: Path,
output_file_path: Optional[Path] = None,
ignore_list: Optional[list[str]] = None,
config_global_excludes: Optional[list[str]] = None, # <--- NEW PARAMETER
) -> Optional[str]:
"""Generate and output tree structure.
Args:
root_dir: Root directory to generate tree for.
output_file_path: Optional path to save the tree. If None, returns string for console.
ignore_list: List of patterns to ignore.
config_global_excludes: Global exclusion patterns from config.
Returns:
String representation of the tree if no output file specified, None otherwise.
"""
if not root_dir.is_dir():
console.print(
f"[bold red]Error: Root directory '{root_dir}' not found or is not a directory.[/bold red]"
)
raise typer.Exit(code=1)
llmignore_spec = ignore_handler.load_ignore_patterns(root_dir)
# Simplified console message logic for brevity, can be restored from your version
if (
llmignore_spec
and output_file_path
and (root_dir / ignore_handler.LLMIGNORE_FILENAME).exists()
):
console.print(
f"[dim]Using .llmignore patterns from '{root_dir / ignore_handler.LLMIGNORE_FILENAME}'[/dim]"
)
elif not llmignore_spec and output_file_path:
console.print(
"[dim]No .llmignore file, or it's empty. Using fallback exclusions if applicable.[/dim]"
)
effective_cli_ignores = list(ignore_list) if ignore_list else []
if output_file_path:
abs_output_file = output_file_path.resolve()
if (
abs_output_file.is_relative_to(root_dir.resolve())
and abs_output_file.name not in effective_cli_ignores
):
effective_cli_ignores.append(abs_output_file.name)
# Re-add this console print if desired
# console.print(f"[dim]Output file '{abs_output_file.name}' will be dynamically ignored for this run.[/dim]")
current_tool_specific_exclusions = DEFAULT_EXCLUDED_ITEMS_TOOL_SPECIFIC.copy()
# Create Rich tree for both file output and console display
rich_tree_root_label = f"📁 [link file://{root_dir.resolve()}]{root_dir.name}"
rich_tree_root = RichTree(
rich_tree_root_label,
guide_style="bold bright_blue",
)
_add_nodes_to_rich_tree_recursive(
rich_tree_node=rich_tree_root,
current_path_obj=root_dir,
root_dir_for_ignores=root_dir,
llmignore_spec=llmignore_spec,
cli_ignores=effective_cli_ignores,
config_global_excludes=config_global_excludes,
tool_specific_fallback_exclusions=current_tool_specific_exclusions,
)
if output_file_path:
# Render Rich tree to string for file output
from io import StringIO
from rich.console import Console as RichConsole
string_buffer = StringIO()
file_console = RichConsole(file=string_buffer, width=120, legacy_windows=False)
file_console.print(rich_tree_root)
rich_output = string_buffer.getvalue()
try:
output_file_path.parent.mkdir(parents=True, exist_ok=True)
with output_file_path.open(mode="w", encoding="utf-8") as f:
f.write(rich_output)
console.print(
f"Directory tree saved to [cyan]{output_file_path.resolve()}[/cyan]"
)
except OSError as e:
console.print(
f"[bold red]Error writing to output file '{output_file_path}': {e}[/bold red]"
)
raise typer.Exit(code=1) from e
return None
else:
# Return the string representation for console output or clipboard
from io import StringIO
from rich.console import Console as RichConsole
string_buffer = StringIO()
console_for_capture = RichConsole(
file=string_buffer, width=120, legacy_windows=False
)
console_for_capture.print(rich_tree_root)
return string_buffer.getvalue()
|