tempest/highlight
Fast, extensible server-side code highlighting for PHP and more. Tempest Highlight parses source code into highlighted output with a simple API: instantiate the Highlighter and call parse($code, 'php'). Ideal for docs, blogs, and code previews.
Installation:
composer require tempest/highlight
Add the service provider to config/app.php under providers:
Tempest\Highlight\HighlightServiceProvider::class,
Basic Usage:
use Tempest\Highlight\Highlight;
$highlight = app(Highlight::class);
$code = '<?php echo "Hello, World!"; ?>';
$html = $highlight->highlight($code, 'php');
First Use Case: Display syntax-highlighted code snippets in a Laravel Blade template:
// In a controller
return view('snippets.show', ['highlightedCode' => $highlight->highlight($code, 'php')]);
// In Blade
{!! $highlightedCode !!}
config/highlight.php: Default configuration (languages, themes, etc.).vendor/tempest/highlight/src/Highlight.php: Core class documentation.vendor/tempest/highlight/src/Languages/: Predefined language lexers.Use detectLanguage() to auto-detect code language (e.g., for user-uploaded files):
$language = $highlight->detectLanguage($code);
$html = $highlight->highlight($code, $language);
Override the default theme (e.g., solarized-dark) via config or runtime:
$highlight->setTheme('monokai');
$html = $highlight->highlight($code, 'javascript');
Enable line numbers globally in config/highlight.php:
'line_numbers' => true,
Or per-call:
$html = $highlight->highlight($code, 'python', ['line_numbers' => true]);
Extend existing lexers or create new ones by implementing Tempest\Highlight\Lexer\LexerInterface:
class CustomLexer implements LexerInterface {
public function tokenize(string $code): array { ... }
}
Register it via the service provider’s extend method.
Cache results for static code snippets (e.g., documentation):
$cacheKey = 'code_snippet_' . md5($code);
$html = Cache::remember($cacheKey, now()->addHours(1), function () use ($highlight, $code) {
return $highlight->highlight($code, 'php');
});
Highlight files directly from storage:
$code = Storage::disk('public')->get('scripts/app.js');
$html = $highlight->highlight($code, 'javascript');
Return highlighted code in JSON API responses:
return response()->json([
'code' => $code,
'highlighted' => $highlight->highlight($code, 'go'),
]);
Offload highlighting for large files to a queue job:
HighlightJob::dispatch($filePath, 'rust')->delay(now()->addMinute());
Use the package to generate static highlighted snippets during build:
// webpack.mix.js
mix.webpackConfig({
plugins: [
new LaravelHighlightPlugin({
files: ['resources/js/snippets/*.js'],
output: 'public/highlighted-snippets.js',
}),
],
});
Dynamically update highlighted code in real-time:
// Livewire component
public function highlightCode(string $code): string {
return app(Highlight::class)->highlight($code, 'vue');
}
Integrate with packages like spatie/laravel-markdown:
$markdown = Markdown::parse($content);
$highlighted = preg_replace_callback(
'/```([\w-]+)\n(.*?)```/s',
fn($matches) => $highlight->highlight($matches[2], $matches[1]),
$markdown
);
Mock the Highlight class in tests:
$this->mock(Highlight::class, function ($mock) {
$mock->shouldReceive('highlight')
->with('<?php ...', 'php')
->andReturn('<div class="highlight"><span>...</span></div>');
});
Language Mismatch:
php for HTML) leads to poor highlighting.detectLanguage() or validate against supported languages:
$supported = $highlight->getSupportedLanguages();
if (!in_array($language, $supported)) {
$language = 'text'; // Fallback
}
Performance with Large Files:
XSS Risks:
$highlight->highlight() in Blade can expose raw HTML.{!! !!} only in trusted contexts.Theme/Style Conflicts:
.hljs) and scope styles:
.highlight { contain: content; } /* Prevent style leaks */
Case-Sensitive Language Names:
'PHP' fails; must use 'php'.$language = strtolower(trim($language));
Lexer Overrides Not Loading:
AppServiceProvider are ignored.HighlightServiceProvider:
$this->app->register(Tempest\Highlight\HighlightServiceProvider::class);
$this->app->register(CustomHighlightProvider::class);
Inspect Tokens: Dump lexer tokens to debug highlighting issues:
$tokens = $highlight->getLexer('php')->tokenize($code);
dd($tokens); // Check for missing/incorrect token types
Enable Debug Mode: Temporarily enable verbose output:
$highlight->setDebug(true);
$html = $highlight->highlight($code, 'ruby');
// Check logs for lexer/parser errors
Check for Deprecated Methods: Monitor deprecation notices in Laravel logs if upgrading from older versions.
Validate Config:
Ensure config/highlight.php paths (e.g., lexers_path) are correct. Default:
'lexers_path' => realpath(__DIR__ . '/../../vendor/tempest/highlight/src/Languages'),
Custom Themes:
Extend the default theme by copying vendor/tempest/highlight/src/Themes/default.css to resources/css/ and overriding classes.
Language Plugins: Dynamically load lexers from a database or API:
$highlight->addLexer('custom-lang', new CustomLexer());
Event Hooks:
Listen for highlighting events (e.g., highlighting):
event(new HighlightingEvent($code, 'python'));
Fallback Lexers: Implement a fallback lexer for unsupported languages:
$highlight->setFallbackLexer(function ($code) {
return new TextLexer(); // Basic text highlighting
});
Line Number Formatting:
Customize line number output via the line_numbers option:
$html = $highlight->highlight($code, 'css', [
'line_numbers' => true,
'line_number_format' => '<span class="line-number">%s</span>',
]);
Highlighting Directories: Recursively highlight all files in a directory (e.g., for docs):
$files = Storage::disk('public')->files('snippets');
foreach ($files as $file) {
$code = Storage::disk('public')->get($file);
$html = $highlight->highlight($code, pathinfo($file, PATHINFO_EXTENSION));
Storage::disk('public')->put("highlighted/{
How can I help you explore Laravel packages today?