diff --git a/README.md b/README.md index 224e89e..d3919a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # Fast, extensible, server-side code highlighting +TODO: + +- [ ] Add JS support +- [ ] Add SQL support +- [ ] Add Twig support +- [ ] Add YAML support +- [ ] Add JSON support + ## Quickstart Highlight code like this: @@ -216,7 +224,108 @@ So, let's bring everything together to explain how you can add your own language ### Adding custom languages -Let's say you're adding `blade` support. You could create a plain language file and start from there, but it'd probably be easier to extend an existing language. +Let's say you're adding [Blade](https://laravel.com/docs/11.x/blade) support. You could create a plain language file and start from there, but it'd probably be easier to extend an existing language, `HtmlLanguage` is probably the best. Let create a new `BladeLanguage` class that extends from `HtmlLanguage`: + +```php +class BladeLanguage extends HtmlLanguage +{ + public function getInjections(): array + { + return [ + ...parent::getInjections(), + ]; + } + + public function getPatterns(): array + { + return [ + ...parent::getPatterns(), + ]; + } +} +``` + +With this class in place, we can start adding our own patterns and injections. Let's start with adding a pattern that matches all Blade keywords, which are always prepended with the `@` sign. Let's add it: + +```php +final readonly class BladeKeywordPattern implements Pattern +{ + use IsPattern; + + public function getPattern(): string + { + return '(?\@[\w]+)\b'; + } + + public function getTokenType(): TokenType + { + return TokenType::KEYWORD; + } +} +``` + +And register it in our `BladeLanguage` class: + +```php + public function getPatterns(): array + { + return [ + ...parent::getPatterns(), + new BladeKeywordPattern(), + ]; + } +``` + +Next, there are a couple of places within Blade where you can write PHP code: within the `@php` keyword, as well as within keyword brackets: `@if (count(…))`. Let's write two injections for that: + +```php +final readonly class BladeKeywordInjection implements Injection +{ + use IsInjection; + + public function getPattern(): string + { + return '(\@[\w]+)\s?\((?.*)\)'; + } + + public function parseContent(string $content, Highlighter $highlighter): string + { + return $highlighter->parse($content, 'php'); + } +} +``` + +```php +final readonly class BladePhpInjection implements Injection +{ + use IsInjection; + + public function getPattern(): string + { + return '\@php(?(.|\n)*?)\@endphp'; + } + + public function parseContent(string $content, Highlighter $highlighter): string + { + return $highlighter->parse($content, 'php'); + } +} +``` + +Let's add these to our `BladeLanguage` class as well: + +```php + public function getInjections(): array + { + return [ + ...parent::getInjections(), + new BladePhpInjection(), + new BladeKeywordInjection(), + ]; + } +``` + +And, finally, you can write `{{ … }}` and `{!! … !!}` to echo output. Whatever is between these brackets is also considered PHP, so, one more injection: ```php diff --git a/src/Languages/Blade/BladeLanguage.php b/src/Languages/Blade/BladeLanguage.php index 1c6d9b6..aae1085 100644 --- a/src/Languages/Blade/BladeLanguage.php +++ b/src/Languages/Blade/BladeLanguage.php @@ -4,6 +4,7 @@ namespace Tempest\Highlight\Languages\Blade; +use Tempest\Highlight\Languages\Blade\Injections\BladeEchoInjection; use Tempest\Highlight\Languages\Blade\Injections\BladeKeywordInjection; use Tempest\Highlight\Languages\Blade\Injections\BladePhpInjection; use Tempest\Highlight\Languages\Blade\Patterns\BladeKeywordPattern; @@ -17,6 +18,7 @@ public function getInjections(): array ...parent::getInjections(), new BladeKeywordInjection(), new BladePhpInjection(), + new BladeEchoInjection(), ]; } diff --git a/src/Languages/Blade/Injections/BladeEchoInjection.php b/src/Languages/Blade/Injections/BladeEchoInjection.php new file mode 100644 index 0000000..05fa35d --- /dev/null +++ b/src/Languages/Blade/Injections/BladeEchoInjection.php @@ -0,0 +1,24 @@ +.*)(}}|!!})'; + } + + public function parseContent(string $content, Highlighter $highlighter): string + { + return $highlighter->parse($content, 'php'); + } +} diff --git a/src/Languages/BladeLanguage.php b/src/Languages/BladeLanguage.php deleted file mode 100644 index 7af2e3c..0000000 --- a/src/Languages/BladeLanguage.php +++ /dev/null @@ -1,30 +0,0 @@ -parse($content, $highlighter); + + $this->assertStringContainsString( + 'count', + $output, + ); + } + + #[Test] + public function test_injection_raw_echo(): void + { + $content = htmlentities('{!! count($foo) !!}'); + + $highlighter = new Highlighter(); + $injection = new BladeEchoInjection(); + + $output = $injection->parse($content, $highlighter); + + $this->assertStringContainsString( + 'count', + $output, + ); + } +} diff --git a/tests/test.md b/tests/test.md index 6674c7b..2b14936 100644 --- a/tests/test.md +++ b/tests/test.md @@ -1,3 +1,3 @@ -```php -foreach ($product->versions as $version) +```blade +{{ count($var) }} ``` \ No newline at end of file