Skip to main content
Glama

CTX: Context as Code (CaC) tool

by context-hub
MIT License
235
  • Apple
  • Linux
GenerateCommandRenderer.php6.46 kB
<?php declare(strict_types=1); namespace Butschster\ContextGenerator\Console\Renderer; 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; /** * Renderer for the generate command output */ final readonly class GenerateCommandRenderer { /** * Maximum line width for consistent display */ private const int MAX_LINE_WIDTH = 100; /** * Success indicator symbol */ private const string SUCCESS_SYMBOL = '✓'; /** * Warning indicator symbol */ private const string WARNING_SYMBOL = '!'; /** * Error indicator symbol */ private const string ERROR_SYMBOL = '✗'; public function __construct( private OutputInterface $output, private ?FilesInterface $files = null, private ?string $basePath = null, ) {} public function renderImports(ImportRegistry $imports): void { \assert($this->output instanceof SymfonyStyle); foreach ($imports as $item) { $description = $item->getPath(); if (\strlen($description) > self::MAX_LINE_WIDTH - 40) { $halfLength = (self::MAX_LINE_WIDTH - 40) / 2; $description = \substr($description, 0, $halfLength) . '...' . \substr($description, -$halfLength); } // Calculate padding to align the document descriptions $padding = $this->calculatePadding($item->getType(), $description, 12); $this->output->writeln( \sprintf( ' <fg=yellow>%s</> Import %s <fg=yellow>[%s]</><fg=gray>%s</>', $this->padRight(self::SUCCESS_SYMBOL, 1), $item->getType(), $description, $padding, ), ); } $this->output->newLine(); } /** * Render the compilation result for a document */ public function renderCompilationResult(Document $document, CompiledDocument $compiledDocument): void { \assert($this->output instanceof SymfonyStyle); $hasErrors = $compiledDocument->errors->hasErrors(); $description = $document->description; $outputPath = $document->outputPath; // Calculate padding to align the document descriptions $stats = $this->getFileStatistics($outputPath); $padding = $this->calculatePadding($description, $outputPath); if ($hasErrors) { // Render warning line with document info $this->output->writeln( \sprintf( ' <fg=yellow>%s</> %s <fg=yellow>[%s]</><fg=gray>%s</>', $this->padRight(self::WARNING_SYMBOL, 1), $description, $outputPath, $padding, ), ); // Render errors foreach ($compiledDocument->errors as $error) { $this->output->writeln(\sprintf(' <fg=red>%s</> %s', self::ERROR_SYMBOL, $error)); } $this->output->newLine(); } else { // 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]; } /** * Calculate padding to align the document information */ private function calculatePadding(string $description, string $outputPath, int $additional = 5): string { $totalLength = \strlen($description) + \strlen($outputPath) + $additional; $padding = \max(0, self::MAX_LINE_WIDTH - $totalLength); return \str_repeat('.', $padding); } /** * Pad a string on the right with spaces */ private function padRight(string $text, int $length): string { return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/context-hub/generator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server