Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions docs/_posts/2025-08-29-1425-improved-file-list-handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
layout: post
title: "Improved File List Handling in aditi check Command"
date: 2025-08-29 14:25:00 -0400
author: Aditi Development Team
tags: [features, ui, usability]
summary: "New options for complete file list visibility in check command output"
---

## Better Visibility for Large-Scale DITA Migration Projects

When working with large documentation repositories, the `aditi check` command helps identify DITA compatibility issues across hundreds or even thousands of AsciiDoc files. Previously, when a rule violation affected many files, the output would truncate the file list after 10 entries, showing "... and X more" to keep the terminal output manageable.

While this truncation keeps the output clean, users often need to see the complete list of affected files for planning and tracking purposes. Today's update introduces two new options that give you full control over how file lists are displayed.

## New Options

### `--show-all` Flag

The `--show-all` flag displays all affected files directly in the terminal without truncation:

```bash
aditi check --rule ContentType --show-all
```

This is particularly useful when you need to quickly see all affected files for a specific rule violation without exporting to a file.

### `--export-files` Option

For more permanent records or when dealing with very large file lists, the `--export-files` option saves the complete list to a file:

```bash
aditi check --export-files violations-report.txt
```

The exported file includes:
- Generation timestamp
- Total files processed and issues found
- Files grouped by rule name
- Sorted file paths for easy navigation

Example export format:
```
# Aditi Check Results - Files with Issues
# Generated: 2025-08-29T14:25:22.565988
# Total files: 150
# Total issues: 342

## ContentType (45 files)
- modules/getting-started.adoc
- modules/installation-guide.adoc
- modules/troubleshooting.adoc
...

## EntityReference (23 files)
- assemblies/product-overview.adoc
- assemblies/quick-start.adoc
...
```

## Using Both Options Together

You can combine both options for maximum flexibility:

```bash
aditi check --show-all --export-files full-report.txt --rule BlockTitle
```

This displays all files in the terminal while also creating a permanent record.

## Consistent Experience Across Commands

The same file list display logic is now used in both the `check` command and the `journey` command, ensuring a consistent user experience throughout the tool.

## Implementation Details

The implementation adds a reusable `_display_file_list()` helper method to the processor module, which handles:
- Truncation logic (show 10 files by default)
- Full display when requested
- Consistent formatting across different commands

This approach maintains backward compatibility while providing the flexibility needed for large-scale documentation projects.

## Next Steps

These improvements make it easier to track and manage DITA migration progress across large documentation sets. Combined with the journey workflow, teams can now better plan and execute their migration strategies with full visibility into the scope of work required.

Try out the new options with:
```bash
aditi check --help
```

Happy migrating!
12 changes: 11 additions & 1 deletion src/aditi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,24 @@ def check(
help="Check only specific rule (e.g., EntityReference)",
),
verbose: bool = verbose_option,
show_all: bool = typer.Option(
False,
"--show-all",
help="Show all affected files without truncation",
),
export_files: Optional[Path] = typer.Option(
None,
"--export-files",
help="Export full list of affected files to specified file",
),
) -> None:
"""Check AsciiDoc files for DITA compatibility issues.

Runs Vale with AsciiDocDITA rules to identify issues that need
to be addressed before migration to DITA.
"""
setup_logging(verbose)
check_command(paths, rule, verbose)
check_command(paths, rule, verbose, show_all, export_files)


@app.command()
Expand Down
18 changes: 14 additions & 4 deletions src/aditi/commands/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ def check_command(
"-v",
help="Show detailed violation information",
),
show_all: bool = typer.Option(
False,
"--show-all",
help="Show all affected files without truncation",
),
export_files: Optional[Path] = typer.Option(
None,
"--export-files",
help="Export full list of affected files to specified file",
),
) -> None:
"""Check AsciiDoc files for DITA compatibility issues.

Expand Down Expand Up @@ -184,10 +194,10 @@ def check_command(

# Display detailed results if verbose
if verbose:
_display_verbose_results(result, processor)
_display_verbose_results(result, processor, show_all, export_files)
else:
# Display summary
processor.display_summary(result)
# Display summary with new options
processor.display_summary(result, show_all=show_all, export_files=export_files)

except Exception as e:
console.print(f"[red]Error during check:[/red] {e}")
Expand All @@ -198,7 +208,7 @@ def check_command(
vale_container.cleanup()


def _display_verbose_results(result, processor):
def _display_verbose_results(result, processor, show_all=False, export_files=None):
"""Display verbose results with detailed violation information."""
console.print("\n📊 Detailed Analysis Results\n")

Expand Down
26 changes: 19 additions & 7 deletions src/aditi/commands/journey.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,11 +942,16 @@ def process_single_rule(rule, issues, description, processor, config_manager) ->
# Show affected files
files_affected = list(set(v.file_path for v in issues))
console.print("These files have this issue:")
for i, file_path in enumerate(files_affected[:10]):
rel_path = file_path.relative_to(Path.cwd())
console.print(f" • {rel_path}")
if len(files_affected) > 10:
console.print(f" ... and {len(files_affected) - 10} more")
# Use the processor's file list display helper if available
if hasattr(processor, '_display_file_list'):
processor._display_file_list(files_affected, rule.name, show_all=False, max_display=10)
else:
# Fallback to inline display
for i, file_path in enumerate(files_affected[:10]):
rel_path = file_path.relative_to(Path.cwd())
console.print(f" • {rel_path}")
if len(files_affected) > 10:
console.print(f" ... and {len(files_affected) - 10} more")

console.print()

Expand Down Expand Up @@ -1157,8 +1162,15 @@ def recheck_rule_violations(rule_name: str, files_affected: List[Path], processo
# Show affected files in the same format as process_single_rule
files_with_issues = list(set(v.file_path for v in rule_issues))
console.print("These files have this issue:")
for file_path in files_with_issues:
console.print(f" • {file_path}")
# Use the processor's file list display helper if available
if hasattr(processor, '_display_file_list'):
processor._display_file_list(files_with_issues, rule_name, show_all=False, max_display=10)
else:
# Fallback to inline display
for file_path in files_with_issues[:10]:
console.print(f" • {file_path}")
if len(files_with_issues) > 10:
console.print(f" ... and {len(files_with_issues) - 10} more")

except Exception as e:
console.print(f"[red]Error during recheck: {e}[/red]")
Expand Down
68 changes: 66 additions & 2 deletions src/aditi/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,14 +466,40 @@ def _backup_file(self, file_path: Path) -> bool:
console.print(f"[yellow]Warning: Failed to backup {file_path}:[/yellow] {e}")
return False

def display_summary(self, result: ProcessingResult):
def _display_file_list(self, files: List[Path], rule_name: str, show_all: bool = False, max_display: int = 10) -> None:
"""Display a list of files with optional truncation.

Args:
files: List of file paths
rule_name: Name of the rule for context
show_all: If True, show all files without truncation
max_display: Maximum number of files to show when not showing all
"""
if show_all or len(files) <= max_display:
# Show all files
for file_path in files:
rel_path = file_path.relative_to(Path.cwd())
console.print(f" • {rel_path}")
else:
# Show truncated list
for file_path in files[:max_display]:
rel_path = file_path.relative_to(Path.cwd())
console.print(f" • {rel_path}")
console.print(f" ... and {len(files) - max_display} more")

def display_summary(self, result: ProcessingResult, show_all: bool = False, export_files: Optional[Path] = None):
"""Display a summary of the processing results.

Args:
result: The processing result to display
show_all: If True, show all affected files without truncation
export_files: If provided, export full file list to this path
"""
console.print("\n📊 Analysis Results\n")

# Prepare export data if needed
export_data = {} if export_files else None

# Violations by rule
rule_counts = result.get_violations_by_rule()
if rule_counts:
Expand All @@ -497,6 +523,22 @@ def display_summary(self, result: ProcessingResult):
for rule_name in rules_of_type:
count = rule_counts[rule_name]
console.print(f" {rule_name} ({count} {'issue' if count == 1 else 'issues'})")

# Get affected files for this rule
affected_files = list(set(
v.file_path for v in result.violations_found
if v.rule_name == rule_name
))

# Store in export data if needed
if export_data is not None:
export_data[rule_name] = [str(f.relative_to(Path.cwd())) for f in affected_files]

# Display files if show_all or in verbose mode
if show_all and affected_files:
console.print(" Files affected:")
self._display_file_list(affected_files, rule_name, show_all=True)

console.print() # Blank line after each section

# Show unimplemented rules
Expand Down Expand Up @@ -533,5 +575,27 @@ def display_summary(self, result: ProcessingResult):
if result.total_violations > 0 and auto_fixable > 0:
auto_fix_percentage = (auto_fixable / result.total_violations) * 100
console.print(f"\n✨ Good news! {auto_fix_percentage:.0f}% of issues can be fixed automatically.")


# Export file list if requested
if export_files and export_data:
try:
with open(export_files, 'w') as f:
# Write header
f.write(f"# Aditi Check Results - Files with Issues\n")
f.write(f"# Generated: {datetime.now().isoformat()}\n")
f.write(f"# Total files: {len(result.files_processed)}\n")
f.write(f"# Total issues: {result.total_violations}\n\n")

# Write files by rule
for rule_name in sorted(export_data.keys()):
files = export_data[rule_name]
f.write(f"## {rule_name} ({len(files)} files)\n")
for file_path in sorted(files):
f.write(f" - {file_path}\n")
f.write("\n")

console.print(f"\n✓ Full file list exported to: {export_files}")
except Exception as e:
console.print(f"\n[red]Error exporting file list:[/red] {e}")

console.print("\nNext step: Run 'aditi journey' for guided workflow")
Loading