sensiolabs/ansi-to-html
Convert ANSI-colored console output into an HTML5 fragment. Supports themes (e.g., Solarized), inline styles or CSS classes, can export theme CSS, and includes a Twig extension for easy use in templates.
Installation:
composer require sensiolabs/ansi-to-html
Add to composer.json if using a monorepo or custom package.
First Conversion:
use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
$ansiText = "\033[31mError: File not found\033[0m";
$converter = new AnsiToHtmlConverter();
$html = $converter->convert($ansiText);
Output: <span style="color: #ff0000">Error: File not found</span>
Quick View:
Wrap in a <pre> tag for terminal-like rendering:
echo '<pre style="background: #000; padding: 10px; font-family: monospace;">'.$html.'</pre>';
Convert CLI logs (e.g., from Log::debug() or Artisan::output()) to HTML for web dashboards:
$ansiLog = "\033[32m[INFO] User created\033[0m\n\033[31m[ERROR] Query failed\033[0m";
$htmlLog = $converter->convert($ansiLog);
return view('logs.show', ['log' => $htmlLog]);
Convert ANSI Strings:
$ansi = "Status: \033[1;34mOK\033[0m";
$html = $converter->convert($ansi);
\033[1m), colors (\033[31m), and background colors (\033[42m).Theming:
SolarizedTheme, DarkTheme, or custom themes for consistency.
use SensioLabs\AnsiConverter\Theme\DarkTheme;
$converter = new AnsiToHtmlConverter(new DarkTheme());
CSS Classes (Recommended for Reuse): Disable inline styles and use CSS classes for maintainability:
$converter = new AnsiToHtmlConverter(new SolarizedTheme(), false);
$html = $converter->convert($ansi);
<span class="ansi_color_fg_red">Error</span>echo $theme->asCss();
Register the converter as a singleton in AppServiceProvider:
public function register()
{
$this->app->singleton(AnsiToHtmlConverter::class, function ($app) {
return new AnsiToHtmlConverter(new SolarizedTheme(), false);
});
}
Usage:
$html = app(AnsiToHtmlConverter::class)->convert($ansi);
Convert CLI output to HTML for web-based Artisan logs:
use Symfony\Component\Console\Output\BufferedOutput;
class LogCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$bufferedOutput = new BufferedOutput();
// ... command logic ...
$ansiLog = $bufferedOutput->fetch();
$htmlLog = app(AnsiToHtmlConverter::class)->convert($ansiLog);
return $this->renderHtmlLog($htmlLog);
}
}
Use the Twig bridge in Blade templates:
// In AppServiceProvider::boot()
$twig = $this->app['view']->getEngine();
$twig->addExtension(new \SensioLabs\AnsiConverter\Bridge\Twig\AnsiExtension(
new AnsiToHtmlConverter(new SolarizedTheme(), false)
));
// In Blade:
<style>
{!! $ansi_css !!}
</style>
<pre class="ansi_box">{!! $ansiLog|ansi_to_html !!}</pre>
Store user preferences (e.g., dark/light mode) and switch themes dynamically:
$theme = auth()->user()->prefers_dark_mode
? new DarkTheme()
: new SolarizedTheme();
$converter = new AnsiToHtmlConverter($theme, false);
Extend AbstractTheme to create custom color schemes:
use SensioLabs\AnsiConverter\Theme\AbstractTheme;
class CustomTheme extends AbstractTheme
{
protected function getColors()
{
return [
'black' => '#1a1a1a',
'red' => '#ff5555',
'green' => '#55ff55',
// ... override defaults
];
}
}
Nested ANSI Codes:
Malformed ANSI sequences (e.g., \033[31m\033[1m) may break rendering. Validate input or sanitize:
$ansi = preg_replace('/\033\[([0-9]{1,2}(;[0-9]{1,2})*)?m/', '', $ansi); // Sanitize (careful!)
Performance with Large Text: Avoid converting massive logs (e.g., 10MB+ files) in a single call. Stream or chunk:
$chunkSize = 1024;
$html = '';
for ($i = 0; $i < strlen($ansi); $i += $chunkSize) {
$html .= $converter->convert(substr($ansi, $i, $chunkSize));
}
CSS Class Collisions: If using classes, ensure they don’t conflict with existing styles. Prefix classes:
$theme = new class extends SolarizedTheme {
public function getClassPrefix() { return 'ansi_'; }
};
Twig Caching:
Clear Twig cache after adding the AnsiExtension:
php artisan view:clear
Inspect Raw ANSI:
Use var_dump() or dd() to verify ANSI codes before conversion:
var_dump(str_split($ansi, 1)); // Check for invalid sequences
Validate HTML Output:
Wrap output in <div> and inspect with browser dev tools for rendering issues.
Theme Debugging:
Override getColors() in a custom theme to test individual colors:
return ['red' => '#ff0000', 'green' => '#00ff00']; // Force colors
Monospace Fonts:
Always pair ANSI-to-HTML with a monospace font (e.g., font-family: 'Courier New', monospace).
Pre Tags:
Use <pre> for terminal-like alignment:
<pre class="ansi-box">{!! $html !!}</pre>
Dark Mode Support: Combine with CSS media queries for automatic theme switching:
@media (prefers-color-scheme: dark) {
.ansi_color_fg_white { color: #eee !important; }
}
Laravel Logging:
Extend Monolog to auto-convert ANSI logs:
use Monolog\Logger;
$log = new Logger('ansi');
$log->pushHandler(new \Monolog\Handler\StreamHandler(storage_path('logs/ansi.log')));
$log->info("\033[31mError!\033[0m"); // Logs with ANSI
Then read the log file and convert it to HTML.
Testing:
Use assertStringContainsString() to verify conversions:
$html = $converter->convert("\033[31mTest\033[0m");
$this->assertStringContainsString('color: #ff0000', $html);
CI/CD Logs: Pipe CI logs (e.g., GitHub Actions) through the converter for web-based debugging:
$ciLog = file_get_contents('ci.log');
$htmlLog = $converter->convert($ciLog);
file_put_contents('ci.html', $htmlLog);
Accessibility: Ensure sufficient color contrast. Test with tools like WebAIM Contrast Checker.
How can I help you explore Laravel packages today?