diff --git a/src/Tracy/BlueScreen/CodeHighlighter.php b/src/Tracy/BlueScreen/CodeHighlighter.php index 4552c8269..fb5ae0f3d 100644 --- a/src/Tracy/BlueScreen/CodeHighlighter.php +++ b/src/Tracy/BlueScreen/CodeHighlighter.php @@ -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 "
$html
"; + } + - $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]; // - $tmp = str_replace('
', "\n", $source[1]); - $out .= self::highlightLine($tmp, $line, $column); - $out = str_replace(' ', ' ', $out) . $source[2] . @$source[3]; - return "
$out
"; + 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 .= '
'; + } + $last = $next; + if ($last !== '') { + $out .= ""; + } + } + + $out .= strtr($token->text, ['<' => '<', '>' => '>', '&' => '&', "\t" => ' ']); + } + if ($last !== '') { + $out .= ''; + } + return $out; } @@ -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", ], ); } diff --git a/src/Tracy/BlueScreen/assets/bluescreen.css b/src/Tracy/BlueScreen/assets/bluescreen.css index 13cceb324..abf309fa9 100644 --- a/src/Tracy/BlueScreen/assets/bluescreen.css +++ b/src/Tracy/BlueScreen/assets/bluescreen.css @@ -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; diff --git a/src/Tracy/Dumper/Renderer.php b/src/Tracy/Dumper/Renderer.php index 3ff8867b8..edcff7498 100644 --- a/src/Tracy/Dumper/Renderer.php +++ b/src/Tracy/Dumper/Renderer.php @@ -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"; diff --git a/src/Tracy/Helpers.php b/src/Tracy/Helpers.php index 132858983..fad81e006 100644 --- a/src/Tracy/Helpers.php +++ b/src/Tracy/Helpers.php @@ -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+(?: class=["\']tracy-(?:dump-)?([\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; } diff --git a/tests/Tracy/expected/Debugger.exception.html.expect b/tests/Tracy/expected/Debugger.exception.html.expect index 601a033ea..71f42d3c0 100644 --- a/tests/Tracy/expected/Debugger.exception.html.expect +++ b/tests/Tracy/expected/Debugger.exception.html.expect @@ -33,22 +33,22 @@

File: %a%

-
%d%: +
%d%: %d%: -%d%: function second($arg1, $arg2) +%d%: function second($arg1, $arg2) %d%: { -%d%: third([1, 2, 3]); +%d%: third([1, 2, 3]); %d%: } %d%: %d%: -%d%: function third($arg1) +%d%: function third($arg1) %d%: { %d%: throw new Exception('The my exception', 123); -%d%: } +%d%: } %d%: %d%: -%d%: define('MY_CONST', 123); -
+%d%:
define('MY_CONST', 123); +
@@ -67,22 +67,22 @@
-
%d%: +
%d%: %d%: -%d%: function first($arg1, $arg2) +%d%: function first($arg1, $arg2) %d%: { -%d%: second(true, false); +%d%: second(true, false); %d%: } %d%: %d%: -%d%: function second($arg1, $arg2) +%d%: function second($arg1, $arg2) %d%: { %d%: third([1, 2, 3]); -%d%: } +%d%: } %d%: %d%: -%d%: function third($arg1) -
+%d%: function
third($arg1) +
$arg1

@@ -99,22 +99,22 @@
 		
 
 		
-
19: +
19: %d%: -%d%: Debugger::$productionMode = false; -%d%: setHtmlMode(); +%d%: Debugger::$productionMode = false; +%d%: setHtmlMode(); %d%: -%d%: Debugger::enable(); +%d%: Debugger::enable(); %d%: %d%: -%d%: function first($arg1, $arg2) +%d%: function first($arg1, $arg2) %d%: { %d%: second(true, false); -%d%: } +%d%: } %d%: %d%: -%d%: function second($arg1, $arg2) -
+%d%: function
second($arg1, $arg2) +
$arg1
true
@@ -133,19 +133,18 @@
-
%d%: +
%d%: %d%: -%d%: function third($arg1) +%d%: function third($arg1) %d%: { -%d%: throw new Exception('The my exception', 123); +%d%: throw new Exception('The my exception', 123); %d%: } %d%: %d%: -%d%: define('MY_CONST', 123); -%d%: @hex2bin('a'); // E_WARNING +%d%: define('MY_CONST', 123); +%d%: @hex2bin('a'); // E_WARNING %d%: first(10, 'any string'); -%d%: -
+
$arg1
10