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
8 changes: 7 additions & 1 deletion src/Console/GenerateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Butschster\ContextGenerator\Console\Renderer\GenerateCommandRenderer;
use Butschster\ContextGenerator\DirectoriesInterface;
use Butschster\ContextGenerator\Document\Compiler\DocumentCompiler;
use Spiral\Files\FilesInterface;
use Spiral\Console\Attribute\Option;
use Spiral\Core\Container;
use Spiral\Core\Scope;
Expand Down Expand Up @@ -88,6 +89,7 @@ public function __invoke(Container $container, DirectoriesInterface $dirs): int
DocumentCompiler $compiler,
ConfigurationProvider $configProvider,
DirectoriesInterface $dirs,
FilesInterface $files,
): int {
try {
// Get the appropriate loader based on options provided
Expand Down Expand Up @@ -120,7 +122,11 @@ public function __invoke(Container $container, DirectoriesInterface $dirs): int
}

// Create the renderer for consistent output formatting
$renderer = new GenerateCommandRenderer($this->output);
$renderer = new GenerateCommandRenderer(
output: $this->output,
files: $files,
basePath: $dirs->getOutputPath()->toString(),
);

// Display summary header
$this->output->writeln('');
Expand Down
94 changes: 84 additions & 10 deletions src/Console/Renderer/GenerateCommandRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Butschster\ContextGenerator\Config\Import\ImportRegistry;
use Butschster\ContextGenerator\Document\Compiler\CompiledDocument;
use Butschster\ContextGenerator\Document\Document;
use Spiral\Files\FilesInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

Expand Down Expand Up @@ -37,6 +38,8 @@

public function __construct(
private OutputInterface $output,
private ?FilesInterface $files = null,
private ?string $basePath = null,
) {}

public function renderImports(ImportRegistry $imports): void
Expand Down Expand Up @@ -78,6 +81,7 @@ public function renderCompilationResult(Document $document, CompiledDocument $co
$outputPath = $document->outputPath;

// Calculate padding to align the document descriptions
$stats = $this->getFileStatistics($outputPath);
$padding = $this->calculatePadding($description, $outputPath);

if ($hasErrors) {
Expand All @@ -99,17 +103,87 @@ public function renderCompilationResult(Document $document, CompiledDocument $co

$this->output->newLine();
} else {
// Render success line with document info
$this->output->writeln(
\sprintf(
' <fg=green>%s</> %s <fg=cyan>[%s]</><fg=gray>%s</>',
$this->padRight(self::SUCCESS_SYMBOL, 2),
$description,
$outputPath,
$padding,
),
);
// Render success line with document info and file statistics
$this->renderSuccessWithStats($description, $outputPath, $stats, $padding);
}
}

/**
* Render success message with file statistics
*/
private function renderSuccessWithStats(string $description, string $outputPath, ?array $stats, string $padding): void
{
$statsInfo = '';
if ($stats !== null) {
$statsInfo = \sprintf(' <fg=gray>(%s, %d lines)</>', $stats['size'], $stats['lines']);
}

$this->output->writeln(
\sprintf(
' <fg=green>%s</> %s <fg=cyan>[%s]</><fg=gray>%s</>%s',
$this->padRight(self::SUCCESS_SYMBOL, 2),
$description,
$outputPath,
$padding,
$statsInfo,
),
);
}

/**
* Get file statistics for a given output path
*/
private function getFileStatistics(string $outputPath): ?array
{
if ($this->files === null || $this->basePath === null) {
return null;
}

try {
$fullPath = $this->basePath . '/' . $outputPath;
$fullPath = \str_replace('//', '/', $fullPath);

if (!$this->files->exists($fullPath)) {
return null;
}

$fileSize = $this->files->size($fullPath);
$fileContent = $this->files->read($fullPath);
$lineCount = \substr_count($fileContent, "\n") + 1;

return [
'size' => $this->formatSize($fileSize),
'lines' => $lineCount,
];
} catch (\Throwable $e) {
// If we can't read the file, return null to avoid errors
$this->output->writeln(\sprintf(
'<fg=yellow>%s Warning:</> Could not read file statistics for %s: %s',
self::WARNING_SYMBOL,
$outputPath,
$e->getMessage(),
));
return null;
}
}

/**
* Format file size in human-readable format
*/
private function formatSize(int $bytes): string
{
$units = ['B', 'KB', 'MB', 'GB'];
$i = 0;

while ($bytes >= 1024 && $i < \count($units) - 1) {
$bytes = (float) $bytes / 1024.0;
$i++;
}

// Ensure $i is within bounds
$i = \min($i, \count($units) - 1);

return (string) \round($bytes, 1) . ' ' . $units[$i];
}

/**
Expand Down
53 changes: 51 additions & 2 deletions src/Document/Compiler/DocumentCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,20 @@ public function compile(Document $document): CompiledDocument
$this->logger?->debug('Ensuring directory exists', ['directory' => $directory]);
$this->files->ensureDirectory($directory);

// Add file statistics to the generated content before writing
$finalContent = $this->addFileStatistics($compiledDocument->content, $resultPath, $outputPath);

$this->logger?->debug('Writing compiled document to file', ['path' => $resultPath]);
$this->files->write($resultPath, (string) $compiledDocument->content);
$this->files->write($resultPath, $finalContent);

$errorCount = \count($errors);
if ($errorCount > 0) {
$this->logger?->warning('Document compiled with errors', ['errorCount' => $errorCount]);
} else {
$this->logger?->info('Document compiled successfully', [
'path' => $resultPath,
'contentLength' => \strlen((string) $compiledDocument->content),
'contentLength' => \strlen($finalContent),
'fileSize' => $this->files->size($resultPath),
]);
}

Expand Down Expand Up @@ -167,4 +171,49 @@ public function buildContent(ErrorCollection $errors, Document $document): Compi
errors: $errors,
);
}

/**
* Add file statistics to the generated content
*
* @param string|\Stringable $content The original content
* @param string $resultPath The actual file path where content was written
* @param string $outputPath The configured output path
* @return string The content with file statistics added
*/
private function addFileStatistics(string|\Stringable $content, string $resultPath, string $outputPath): string
{
try {
// Check if file exists before attempting to read it
if (!$this->files->exists($resultPath)) {
$this->logger?->debug('File does not exist, skipping statistics', ['path' => $resultPath]);
return (string) $content;
}

$fileSize = $this->files->size($resultPath);
$fileContent = $this->files->read($resultPath);
$lineCount = \substr_count($fileContent, "\n") + 1; // Count lines including the last line

// Create a new content builder with the original content
$builder = $this->builderFactory->create();
$builder->addText((string) $content);

// Add file statistics
$this->logger?->debug('Adding file statistics', [
'fileSize' => $fileSize,
'lineCount' => $lineCount,
'filePath' => $outputPath,
]);

$builder->addFileStats($fileSize, $lineCount, $outputPath);

return $builder->build();
} catch (\Throwable $e) {
$this->logger?->warning('Failed to add file statistics', [
'path' => $resultPath,
'error' => $e->getMessage(),
]);
// Return original content if statistics calculation fails
return (string) $content;
}
}
}
58 changes: 58 additions & 0 deletions src/Lib/Content/Block/FileStatsBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Lib\Content\Block;

use Butschster\ContextGenerator\Lib\Content\Renderer\RendererInterface;

/**
* Block for file statistics (size, line count, etc.)
*/
final readonly class FileStatsBlock extends AbstractBlock
{
public function __construct(
string $content,
private int $fileSize,
private int $lineCount,
private ?string $filePath = null,
) {
parent::__construct($content);
}

public function render(RendererInterface $renderer): string
{
return $renderer->renderFileStatsBlock($this);
}

public function getFileSize(): int
{
return $this->fileSize;
}

public function getLineCount(): int
{
return $this->lineCount;
}

public function getFilePath(): ?string
{
return $this->filePath;
}

public function formatSize(int $bytes): string
{
$units = ['B', 'KB', 'MB', 'GB'];
$i = 0;

while ($bytes >= 1024 && $i < \count($units) - 1) {
$bytes = (float) $bytes / 1024.0;
$i++;
}

// Ensure $i is within bounds
$i = \min($i, \count($units) - 1);

return (string) \round($bytes, 2) . ' ' . $units[$i];
}
}
13 changes: 13 additions & 0 deletions src/Lib/Content/ContentBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Butschster\ContextGenerator\Lib\Content\Block\TextBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TitleBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TreeViewBlock;
use Butschster\ContextGenerator\Lib\Content\Block\FileStatsBlock;
use Butschster\ContextGenerator\Lib\Content\Renderer\MarkdownRenderer;
use Butschster\ContextGenerator\Lib\Content\Renderer\RendererInterface;

Expand Down Expand Up @@ -123,6 +124,18 @@ public function addTreeView(string $treeView): self
return $this->addBlock(new TreeViewBlock($treeView));
}

/**
* Add a file stats block
*
* @param int $fileSize The file size in bytes
* @param int $lineCount The number of lines in the file
* @param string|null $filePath The file path (optional)
*/
public function addFileStats(int $fileSize, int $lineCount, ?string $filePath = null): self
{
return $this->addBlock(new FileStatsBlock('', $fileSize, $lineCount, $filePath));
}

/**
* Add a separator block
*
Expand Down
17 changes: 17 additions & 0 deletions src/Lib/Content/Renderer/MarkdownRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Butschster\ContextGenerator\Lib\Content\Block\TextBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TitleBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TreeViewBlock;
use Butschster\ContextGenerator\Lib\Content\Block\FileStatsBlock;

/**
* Renderer for Markdown format
Expand Down Expand Up @@ -77,6 +78,22 @@ public function renderTreeViewBlock(TreeViewBlock $block): string
return \sprintf("```\n// Structure of documents\n%s\n```\n\n", $content);
}

public function renderFileStatsBlock(FileStatsBlock $block): string
{
$filePath = $block->getFilePath() ? "File: `{$block->getFilePath()}`\n" : '';
$size = $block->formatSize($block->getFileSize());
$lineCount = $block->getLineCount();

return <<<STATS
---
**File Statistics**
- **Size**: {$size}
- **Lines**: {$lineCount}
{$filePath}
\n\n
STATS;
}

public function renderSeparatorBlock(SeparatorBlock $block): string
{
return \str_repeat((string) $block, $block->getLength()) . "\n\n";
Expand Down
6 changes: 6 additions & 0 deletions src/Lib/Content/Renderer/RendererInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Butschster\ContextGenerator\Lib\Content\Block\TextBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TitleBlock;
use Butschster\ContextGenerator\Lib\Content\Block\TreeViewBlock;
use Butschster\ContextGenerator\Lib\Content\Block\FileStatsBlock;

/**
* Interface for content renderers
Expand Down Expand Up @@ -42,6 +43,11 @@ public function renderDescriptionBlock(DescriptionBlock $block): string;
*/
public function renderTreeViewBlock(TreeViewBlock $block): string;

/**
* Render a file stats block
*/
public function renderFileStatsBlock(FileStatsBlock $block): string;

/**
* Render a separator block
*/
Expand Down
Loading
Loading