Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Highlighter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Tempest\Highlight\Languages\Python\PythonLanguage;
use Tempest\Highlight\Languages\Scss\ScssLanguage;
use Tempest\Highlight\Languages\Sql\SqlLanguage;
use Tempest\Highlight\Languages\Terminal\TerminalLanguage;
use Tempest\Highlight\Languages\Text\TextLanguage;
use Tempest\Highlight\Languages\Twig\TwigLanguage;
use Tempest\Highlight\Languages\Xml\XmlLanguage;
Expand Down Expand Up @@ -69,6 +70,7 @@ public function __construct(private readonly Theme $theme = new CssTheme())
->addLanguage(new PythonLanguage())
->addLanguage(new ScssLanguage())
->addLanguage(new SqlLanguage())
->addLanguage(new TerminalLanguage())
->addLanguage(new XmlLanguage())
->addLanguage(new YamlLanguage())
->addLanguage(new DotEnvLanguage())
Expand Down
28 changes: 28 additions & 0 deletions src/Languages/Terminal/Patterns/TerminalCommandNamePattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Terminal\Patterns;

use Tempest\Highlight\IsPattern;
use Tempest\Highlight\Pattern;
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '$ npm install express', output: 'npm')]
#[PatternTest(input: '# docker ps -a', output: 'docker')]
#[PatternTest(input: '$ ./configure', output: './configure')]
final readonly class TerminalCommandNamePattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '/^[\$#%>]\s+(?<match>[\w.\/-][\w.\/-]*)(?=\s|$)/m';
}

public function getTokenType(): TokenTypeEnum
{
return TokenTypeEnum::KEYWORD;
}
}
29 changes: 29 additions & 0 deletions src/Languages/Terminal/Patterns/TerminalPromptPattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Terminal\Patterns;

use Tempest\Highlight\IsPattern;
use Tempest\Highlight\Pattern;
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '$ npm install', output: '$')]
#[PatternTest(input: '# apt update', output: '#')]
#[PatternTest(input: '% brew install', output: '%')]
#[PatternTest(input: '> command', output: '>')]
final readonly class TerminalPromptPattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '/^(?<match>[\$#%>])(?=\s)/m';
}

public function getTokenType(): TokenTypeEnum
{
return TokenTypeEnum::COMMENT;
}
}
60 changes: 60 additions & 0 deletions src/Languages/Terminal/TerminalLanguage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Terminal;

use Override;
use Tempest\Highlight\Languages\Base\BaseLanguage;
use Tempest\Highlight\Languages\Bash\Patterns\BashFlagPattern;
use Tempest\Highlight\Languages\Bash\Patterns\BashNumberPattern;
use Tempest\Highlight\Languages\Bash\Patterns\BashOperatorPattern;
use Tempest\Highlight\Languages\Bash\Patterns\BashVariablePattern;
use Tempest\Highlight\Languages\Php\Patterns\DoubleQuoteValuePattern;
use Tempest\Highlight\Languages\Php\Patterns\SingleQuoteValuePattern;
use Tempest\Highlight\Languages\Terminal\Patterns\TerminalCommandNamePattern;
use Tempest\Highlight\Languages\Terminal\Patterns\TerminalPromptPattern;

class TerminalLanguage extends BaseLanguage
{
public function getName(): string
{
return 'terminal';
}

#[Override]
public function getAliases(): array
{
return ['console', 'term'];
}

#[Override]
public function getPatterns(): array
{
return [
...parent::getPatterns(),

// PROMPT
new TerminalPromptPattern(),

// VALUES
new SingleQuoteValuePattern(),
new DoubleQuoteValuePattern(),

// COMMAND NAME
new TerminalCommandNamePattern(),

// VARIABLES
new BashVariablePattern(),

// OPERATORS
new BashOperatorPattern(),

// NUMBERS
new BashNumberPattern(),

// FLAGS
new BashFlagPattern(),
];
}
}
38 changes: 38 additions & 0 deletions tests/Bench/Fixtures/terminal.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
$ npm install --save express
added 57 packages in 3s

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

$ docker ps -a
CONTAINER ID IMAGE STATUS
abc123 nginx:latest Up 2 hours
def456 redis:7 Exited (0) 3 days ago

# apt update && apt install -y curl wget
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done

$ echo "Hello $USER, today is $(date)"
Hello john, today is Mon Apr 1 10:00:00 UTC 2026

$ cat /etc/hosts | grep -i 'localhost'
127.0.0.1 localhost

% brew install --cask visual-studio-code
==> Downloading https://update.code.visualstudio.com
Already downloaded: /Users/john/Library/Caches/Homebrew

> node -v
v20.11.0

$ ls -la /var/log/*.log
-rw-r--r-- 1 root root 45231 Apr 1 09:00 /var/log/syslog.log

$ kubectl get pods -n production --output=wide
NAME READY STATUS RESTARTS AGE
api-7d4b8c6f9-x2k4m 1/1 Running 0 24h
web-5f6a7b8c9-m3n5p 1/1 Running 0 24h
1 change: 1 addition & 0 deletions tests/Bench/HighlighterBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ final class HighlighterBench
'python' => 'python.txt',
'scss' => 'scss.txt',
'sql' => 'sql.txt',
'terminal' => 'terminal.txt',
'twig' => 'twig.txt',
'xml' => 'xml.txt',
'yaml' => 'yaml.txt',
Expand Down
55 changes: 55 additions & 0 deletions tests/Languages/Terminal/TerminalLanguageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Tests\Languages\Terminal;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Tempest\Highlight\Highlighter;

class TerminalLanguageTest extends TestCase
{
#[DataProvider('provide_highlight_cases')]
public function test_highlight(string $content, string $expected): void
{
$highlighter = new Highlighter();

$this->assertSame(
$expected,
$highlighter->parse($content, 'terminal'),
);

$this->assertSame(
$expected,
$highlighter->parse($content, 'console'),
);

$this->assertSame(
$expected,
$highlighter->parse($content, 'term'),
);
}

public static function provide_highlight_cases(): iterable
{
return [
[<<<'TXT'
$ npm install --save express
added 57 packages
$ echo "Hello $USER"
Hello john
# docker ps -a
CONTAINER ID IMAGE STATUS
TXT,
<<<'TXT'
<span class="hl-comment">$</span> <span class="hl-keyword">npm</span> install <span class="hl-generic">--save</span> express
added <span class="hl-number">57</span> packages
<span class="hl-comment">$</span> <span class="hl-keyword">echo</span> <span class="hl-value">&quot;Hello $USER&quot;</span>
Hello john
<span class="hl-comment">#</span> <span class="hl-keyword">docker</span> ps <span class="hl-generic">-a</span>
CONTAINER ID IMAGE STATUS
TXT],
];
}
}
Loading