Skip to content

Commit

Permalink
BlueScreen: implemented PHP syntax highlighter
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Sep 26, 2023
1 parent 51a1942 commit 632ca26
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 56 deletions.
73 changes: 49 additions & 24 deletions src/Tracy/BlueScreen/CodeHighlighter.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,50 @@ public static function highlightLine(string $html, int $line, int $column = 0):
/**
* Returns syntax highlighted source code.
*/
public static function highlightPhp(string $source, int $line, int $column = 0): string
public static function highlightPhp(string $code, int $line, int $column = 0): string
{
if (function_exists('ini_set')) {
ini_set('highlight.comment', '#998; font-style: italic');
ini_set('highlight.default', '#000');
ini_set('highlight.html', '#06B');
ini_set('highlight.keyword', '#D24; font-weight: bold');
ini_set('highlight.string', '#080');
}
$html = self::highlightPhpCode($code);
$html = self::highlightLine($html, $line, $column);
return "<pre class='tracy-code'><div><code>$html</code></div></pre>";
}


$source = preg_replace('#(__halt_compiler\s*\(\)\s*;).*#is', '$1', $source);
$source = str_replace(["\r\n", "\r"], "\n", $source);
$source = preg_replace('#/\*sensitive\{\*/.*?/\*\}\*/#s', Dumper\Describer::HiddenValue, $source);
$source = explode("\n", highlight_string($source, true));
$out = $source[0]; // <code><span color=highlight.html>
$tmp = str_replace('<br />', "\n", $source[1]);
$out .= self::highlightLine($tmp, $line, $column);
$out = str_replace('&nbsp;', ' ', $out) . $source[2] . @$source[3];
return "<pre class='tracy-code'><div>$out</div></pre>";
private static function highlightPhpCode(string $code): string
{
$code = str_replace("\r\n", "\n", $code);
$code = preg_replace('#(__halt_compiler\s*\(\)\s*;).*#is', '$1', $code);
$code = rtrim($code);
$code = preg_replace('#/\*sensitive\{\*/.*?/\*\}\*/#s', Dumper\Describer::HiddenValue, $code);

$last = $out = '';
foreach (\PhpToken::tokenize($code) as $token) {
$next = match ($token->id) {
T_COMMENT, T_DOC_COMMENT, T_INLINE_HTML => 'tracy-code-comment',
T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG, T_LINE, T_FILE, T_DIR, T_TRAIT_C, T_METHOD_C, T_FUNC_C, T_NS_C, T_CLASS_C,
T_STRING, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE => '',
T_LNUMBER, T_DNUMBER => 'tracy-dump-number',
T_VARIABLE => 'tracy-code-var',
T_ENCAPSED_AND_WHITESPACE, T_CONSTANT_ENCAPSED_STRING => 'tracy-dump-string',
T_WHITESPACE => $last,
default => 'tracy-code-keyword',
};

if ($last !== $next) {
if ($last !== '') {
$out .= '</span>';
}
$last = $next;
if ($last !== '') {
$out .= "<span class='$last'>";
}
}

$out .= strtr($token->text, ['<' => '&lt;', '>' => '&gt;', '&' => '&amp;', "\t" => ' ']);
}
if ($last !== '') {
$out .= '</span>';
}
return $out;
}


Expand All @@ -101,13 +126,13 @@ public static function highlightPhpCli(string $code, int $line, int $column = 0)
return Helpers::htmlToAnsi(
self::highlightPhp($code, $line, $column),
[
'color: ' . ini_get('highlight.comment') => '1;30',
'color: ' . ini_get('highlight.default') => '1;36',
'color: ' . ini_get('highlight.html') => '1;35',
'color: ' . ini_get('highlight.keyword') => '1;37',
'color: ' . ini_get('highlight.string') => '1;32',
'tracy-line' => '1;30',
'tracy-line-highlight' => "1;37m\e[41",
'string' => '1;32',
'number' => '1;32',
'code-comment' => '1;30',
'code-keyword' => '1;37',
'code-var' => '1;36',
'line' => '1;30',
'line-highlight' => "1;37m\e[41",
],
);
}
Expand Down
14 changes: 14 additions & 0 deletions src/Tracy/BlueScreen/assets/bluescreen.css
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,20 @@ html.tracy-bs-visible body {
white-space: pre;
}

#tracy-bs .tracy-code-comment {
color: rgba(0, 0, 0, 0.5);
font-style: italic;
}

#tracy-bs .tracy-code-keyword {
color: #D24;
font-weight: bold;
}

#tracy-bs .tracy-code-var {
font-weight: bold;
}

#tracy-bs .tracy-line-highlight {
background: #CD1818;
color: white;
Expand Down
1 change: 0 additions & 1 deletion src/Tracy/Dumper/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ public function renderAsText(\stdClass $model, array $colors = []): string
}

$s = $colors ? Helpers::htmlToAnsi($s, $colors) : Helpers::htmlToText($s);
$s = preg_replace('/\e\[0m( *)(?=\e)/', '$1', $s);
$s = str_replace('', '...', $s);
$s .= substr($s, -1) === "\n" ? '' : "\n";

Expand Down
5 changes: 3 additions & 2 deletions src/Tracy/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,17 +479,18 @@ public static function htmlToAnsi(string $s, array $colors): string
{
$stack = ['0'];
$s = preg_replace_callback(
'#<\w+(?: (?:style|class)=["\'](?:tracy-dump-)?(.*?)["\'])?[^>]*>|</\w+>#',
'#<\w+(?: class=["\']tracy-(?:dump-)?([\w-]+)["\'])?[^>]*>|</\w+>#',
function ($m) use ($colors, &$stack): string {
if ($m[0][1] === '/') {
array_pop($stack);
} else {
$stack[] = isset($m[1], $colors[$m[1]]) ? $colors[$m[1]] : '0';
}
return "\e[0m\e[" . end($stack) . 'm';
return "\e[" . end($stack) . 'm';
},
$s,
);
$s = preg_replace('/\e\[0m( *)(?=\e)/', '$1', $s);
$s = self::htmlToText($s);
return $s;
}
Expand Down
57 changes: 28 additions & 29 deletions tests/Tracy/expected/Debugger.exception.html.expect
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,22 @@

<div class="tracy-section-panel">
<p><b>File:</b> %a%</p>
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span style="color: #06B"><span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span>
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">second</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">$arg2</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>second<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>, </span><span class='tracy-code-var'>$arg2</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">third</span><span style="color: #D24; font-weight: bold">([</span><span style="color: #000">1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">2</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">3</span><span style="color: #D24; font-weight: bold">]);
<span class='tracy-line'>%d%:</span> </span>third<span class='tracy-code-keyword'>([</span><span class='tracy-dump-number'>1</span><span class='tracy-code-keyword'>, </span><span class='tracy-dump-number'>2</span><span class='tracy-code-keyword'>, </span><span class='tracy-dump-number'>3</span><span class='tracy-code-keyword'>]);
<span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">third</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>third<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
</span><span class='tracy-line-highlight'>%d%: throw new Exception('The my exception', 123);</span>
<span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span> }
<span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">define</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #080">'MY_CONST'</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">123</span><span style="color: #D24; font-weight: bold">);
</span></span></code></div></pre>
<span class='tracy-line'>%d%:</span> </span>define<span class='tracy-code-keyword'>(</span><span class='tracy-dump-string'>'MY_CONST'</span><span class='tracy-code-keyword'>, </span><span class='tracy-dump-number'>123</span><span class='tracy-code-keyword'>);
</span></code></div></pre>
</div>
</section>

Expand All @@ -67,22 +67,22 @@
</div>

<div class="tracy-callstack-additional tracy-collapsed">
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span style="color: #06B"><span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span>
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">first</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">$arg2</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>first<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>, </span><span class='tracy-code-var'>$arg2</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">second</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">true</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">false</span><span style="color: #D24; font-weight: bold">);
<span class='tracy-line'>%d%:</span> </span>second<span class='tracy-code-keyword'>(</span>true<span class='tracy-code-keyword'>, </span>false<span class='tracy-code-keyword'>);
<span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">second</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">$arg2</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>second<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>, </span><span class='tracy-code-var'>$arg2</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
</span><span class='tracy-line-highlight'>%d%: third([1, 2, 3]);</span>
<span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span> }
<span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">third</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">)
</span></span></code></div></pre>
<span class='tracy-line'>%d%:</span> function </span>third<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>)
</span></code></div></pre>

<table class="tracy-callstack-args">
<tr><th>$arg1</th><td><pre class="tracy-dump tracy-light" data-tracy-dump='[[0,1],[1,2],[2,3]]'></pre>
Expand All @@ -99,22 +99,22 @@
</div>

<div class="tracy-callstack-additional tracy-collapsed">
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span style="color: #06B"><span style="color: #D24; font-weight: bold"><span class='tracy-line'>19:</span>
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span class='tracy-code-keyword'><span class='tracy-line'>19:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">Debugger</span><span style="color: #D24; font-weight: bold">::</span><span style="color: #000">$productionMode </span><span style="color: #D24; font-weight: bold">= </span><span style="color: #000">false</span><span style="color: #D24; font-weight: bold">;
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">setHtmlMode</span><span style="color: #D24; font-weight: bold">();
<span class='tracy-line'>%d%:</span> </span>Debugger<span class='tracy-code-keyword'>::</span><span class='tracy-code-var'>$productionMode </span><span class='tracy-code-keyword'>= </span>false<span class='tracy-code-keyword'>;
<span class='tracy-line'>%d%:</span> </span>setHtmlMode<span class='tracy-code-keyword'>();
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">Debugger</span><span style="color: #D24; font-weight: bold">::</span><span style="color: #000">enable</span><span style="color: #D24; font-weight: bold">();
<span class='tracy-line'>%d%:</span> </span>Debugger<span class='tracy-code-keyword'>::</span>enable<span class='tracy-code-keyword'>();
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">first</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">$arg2</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>first<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>, </span><span class='tracy-code-var'>$arg2</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
</span><span class='tracy-line-highlight'>%d%: second(true, false);</span>
<span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span> }
<span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">second</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">$arg2</span><span style="color: #D24; font-weight: bold">)
</span></span></code></div></pre>
<span class='tracy-line'>%d%:</span> function </span>second<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>, </span><span class='tracy-code-var'>$arg2</span><span class='tracy-code-keyword'>)
</span></code></div></pre>

<table class="tracy-callstack-args">
<tr><th>$arg1</th><td><pre class="tracy-dump tracy-light"><span class="tracy-dump-bool">true</span></pre>
Expand All @@ -133,19 +133,18 @@
</div>

<div class="tracy-callstack-additional tracy-collapsed">
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span style="color: #06B"><span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span>
<pre title="Ctrl-Click to open in editor" data-tracy-href="%a%" class='tracy-code'><div><code><span class='tracy-code-keyword'><span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> function </span><span style="color: #000">third</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #000">$arg1</span><span style="color: #D24; font-weight: bold">)
<span class='tracy-line'>%d%:</span> function </span>third<span class='tracy-code-keyword'>(</span><span class='tracy-code-var'>$arg1</span><span class='tracy-code-keyword'>)
<span class='tracy-line'>%d%:</span> {
<span class='tracy-line'>%d%:</span> throw new </span><span style="color: #000">Exception</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #080">'The my exception'</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">123</span><span style="color: #D24; font-weight: bold">);
<span class='tracy-line'>%d%:</span> throw new </span>Exception<span class='tracy-code-keyword'>(</span><span class='tracy-dump-string'>'The my exception'</span><span class='tracy-code-keyword'>, </span><span class='tracy-dump-number'>123</span><span class='tracy-code-keyword'>);
<span class='tracy-line'>%d%:</span> }
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span>
<span class='tracy-line'>%d%:</span> </span><span style="color: #000">define</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #080">'MY_CONST'</span><span style="color: #D24; font-weight: bold">, </span><span style="color: #000">123</span><span style="color: #D24; font-weight: bold">);
<span class='tracy-line'>%d%:</span> @</span><span style="color: #000">hex2bin</span><span style="color: #D24; font-weight: bold">(</span><span style="color: #080">'a'</span><span style="color: #D24; font-weight: bold">); </span><span style="color: #998; font-style: italic">// E_WARNING
<span class='tracy-line'>%d%:</span> </span>define<span class='tracy-code-keyword'>(</span><span class='tracy-dump-string'>'MY_CONST'</span><span class='tracy-code-keyword'>, </span><span class='tracy-dump-number'>123</span><span class='tracy-code-keyword'>);
<span class='tracy-line'>%d%:</span> @</span>hex2bin<span class='tracy-code-keyword'>(</span><span class='tracy-dump-string'>'a'</span><span class='tracy-code-keyword'>); </span><span class='tracy-code-comment'>// E_WARNING
</span><span class='tracy-line-highlight'>%d%: first(10, 'any string');</span>
<span style="color: #D24; font-weight: bold"><span class='tracy-line'>%d%:</span> </span>
</span></code></div></pre>
</code></div></pre>

<table class="tracy-callstack-args">
<tr><th>$arg1</th><td><pre class="tracy-dump tracy-light"><span class="tracy-dump-number">10</span></pre>
Expand Down

0 comments on commit 632ca26

Please sign in to comment.