Skip to content

Commit

Permalink
Blade echo injection
Browse files Browse the repository at this point in the history
  • Loading branch information
brendt committed Mar 15, 2024
1 parent 80f0ff3 commit 304280a
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 33 deletions.
111 changes: 110 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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 '(?<match>\@[\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?\((?<match>.*)\)';
}

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(?<match>(.|\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

Expand Down
2 changes: 2 additions & 0 deletions src/Languages/Blade/BladeLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,6 +18,7 @@ public function getInjections(): array
...parent::getInjections(),
new BladeKeywordInjection(),
new BladePhpInjection(),
new BladeEchoInjection(),
];
}

Expand Down
24 changes: 24 additions & 0 deletions src/Languages/Blade/Injections/BladeEchoInjection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Blade\Injections;

use Tempest\Highlight\Highlighter;
use Tempest\Highlight\Injection;
use Tempest\Highlight\IsInjection;

final readonly class BladeEchoInjection implements Injection
{
use IsInjection;

public function getPattern(): string
{
return '({{|{!!)(?<match>.*)(}}|!!})';
}

public function parseContent(string $content, Highlighter $highlighter): string
{
return $highlighter->parse($content, 'php');
}
}
30 changes: 0 additions & 30 deletions src/Languages/BladeLanguage.php

This file was deleted.

43 changes: 43 additions & 0 deletions tests/Languages/Blade/Injections/BladeEchoInjectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Tempest\Highlight\Tests\Languages\Blade\Injections;

use PHPUnit\Framework\Attributes\Test;
use Tempest\Highlight\Highlighter;
use Tempest\Highlight\Languages\Blade\Injections\BladeEchoInjection;
use PHPUnit\Framework\TestCase;

class BladeEchoInjectionTest extends TestCase
{
#[Test]
public function test_injection(): void
{
$content = htmlentities('{{ count($foo) }}');

$highlighter = new Highlighter();
$injection = new BladeEchoInjection();

$output = $injection->parse($content, $highlighter);

$this->assertStringContainsString(
'<span class="hl-property">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(
'<span class="hl-property">count',
$output,
);
}
}
4 changes: 2 additions & 2 deletions tests/test.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
```php
foreach ($product->versions as $version)
```blade
{{ count($var) }}
```

0 comments on commit 304280a

Please sign in to comment.