diff --git a/composer.json b/composer.json index 9be9a9415..09c813c44 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "2.10-dev" + "dev-master": "3.0-dev" } } } diff --git a/readme.md b/readme.md index f726dc45c..6148b11fa 100644 --- a/readme.md +++ b/readme.md @@ -50,8 +50,9 @@ Alternatively, you can download the whole package or [tracy.phar](https://github | Tracy | compatible with PHP | compatible with browsers |-----------|---------------|---------- -| Tracy 2.10| PHP 8.0 – 8.3 | Chrome 64+, Firefox 69+, Safari 15.4+ and iOS Safari 15.4+ -| Tracy 2.9 | PHP 7.2 – 8.2 | Chrome 64+, Firefox 69+, Safari 13.1+ and iOS Safari 13.4+ +| Tracy 3.0 | PHP 8.0 – 8.3 | Chrome 112+, Firefox 117+, Safari 16.5+ +| Tracy 2.10| PHP 8.0 – 8.3 | Chrome 64+, Firefox 69+, Safari 15.4+ +| Tracy 2.9 | PHP 7.2 – 8.2 | Chrome 64+, Firefox 69+, Safari 13.1+ Usage diff --git a/src/Bridges/Nette/Bridge.php b/src/Bridges/Nette/Bridge.php index 1819ab024..41d68033a 100644 --- a/src/Bridges/Nette/Bridge.php +++ b/src/Bridges/Nette/Bridge.php @@ -9,7 +9,6 @@ namespace Tracy\Bridges\Nette; -use Latte; use Nette; use Tracy; use Tracy\BlueScreen; @@ -17,87 +16,18 @@ /** - * Bridge for NEON & Latte. + * Bridge for NEON. */ class Bridge { public static function initialize(): void { $blueScreen = Tracy\Debugger::getBlueScreen(); - if (!class_exists(Latte\Bridges\Tracy\BlueScreenPanel::class)) { - $blueScreen->addPanel([self::class, 'renderLatteError']); - $blueScreen->addAction([self::class, 'renderLatteUnknownMacro']); - $blueScreen->addFileGenerator(fn(string $file) => substr($file, -6) === '.latte' - ? "{block content}\n\$END\$" - : null); - Tracy\Debugger::addSourceMapper([self::class, 'mapLatteSourceCode']); - } - $blueScreen->addAction([self::class, 'renderMemberAccessException']); $blueScreen->addPanel([self::class, 'renderNeonError']); } - public static function renderLatteError(?\Throwable $e): ?array - { - if ($e instanceof Latte\CompileException && $e->sourceName) { - return [ - 'tab' => 'Template', - 'panel' => (preg_match('#\n|\?#', $e->sourceName) - ? '' - : '
' - . (@is_file($e->sourceName) // @ - may trigger error - ? 'File: ' . Helpers::editorLink($e->sourceName, $e->sourceLine) - : '' . htmlspecialchars($e->sourceName . ($e->sourceLine ? ':' . $e->sourceLine : '')) . '') - . '
') - . BlueScreen::highlightFile($e->sourceCode, $e->sourceLine, 15, false), - ]; - } - - return null; - } - - - public static function renderLatteUnknownMacro(?\Throwable $e): ?array - { - if ( - $e instanceof Latte\CompileException - && $e->sourceName - && @is_file($e->sourceName) // @ - may trigger error - && (preg_match('#Unknown macro (\{\w+)\}, did you mean (\{\w+)\}\?#A', $e->getMessage(), $m) - || preg_match('#Unknown attribute (n:\w+), did you mean (n:\w+)\?#A', $e->getMessage(), $m)) - ) { - return [ - 'link' => Helpers::editorUri($e->sourceName, $e->sourceLine, 'fix', $m[1], $m[2]), - 'label' => 'fix it', - ]; - } - - return null; - } - - - /** @return array{file: string, line: int, label: string, active: bool} */ - public static function mapLatteSourceCode(string $file, int $line): ?array - { - if (!strpos($file, '.latte--')) { - return null; - } - - $lines = file($file); - if ( - !preg_match('#^/(?:\*\*|/) source: (\S+\.latte)#m', implode('', array_slice($lines, 0, 10)), $m) - || !@is_file($m[1]) // @ - may trigger error - ) { - return null; - } - - $file = $m[1]; - $line = $line && preg_match('#/\* line (\d+) \*/#', $lines[$line - 1], $m) ? (int) $m[1] : 0; - return ['file' => $file, 'line' => $line, 'label' => 'Latte', 'active' => true]; - } - - public static function renderMemberAccessException(?\Throwable $e): ?array { if (!$e instanceof Nette\MemberAccessException && !$e instanceof \LogicException) { diff --git a/src/Bridges/Nette/TracyExtension.php b/src/Bridges/Nette/TracyExtension.php index 9a11a58a2..8d0a48323 100644 --- a/src/Bridges/Nette/TracyExtension.php +++ b/src/Bridges/Nette/TracyExtension.php @@ -130,7 +130,7 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class) if ($this->debugMode) { foreach ($this->config->bar as $item) { if (is_string($item) && substr($item, 0, 1) === '@') { - $item = new Statement(['@' . $builder::THIS_CONTAINER, 'getService'], [substr($item, 1)]); + $item = new Statement(['@' . $builder::ThisContainer, 'getService'], [substr($item, 1)]); } elseif (is_string($item)) { $item = new Statement($item); } diff --git a/src/Tracy/Bar/assets/bar.css b/src/Tracy/Bar/assets/bar.css index 80cf43af0..6a64f5b7e 100644 --- a/src/Tracy/Bar/assets/bar.css +++ b/src/Tracy/Bar/assets/bar.css @@ -4,81 +4,76 @@ /* common styles */ #tracy-debug { + --tracy-space: 10px; display: none; direction: ltr; -} -body#tracy-debug { /* in popup window */ - display: block; -} + &:not(body) { /* not in popup window */ + position: absolute; + left: 0; + top: 0; + } -#tracy-debug:not(body) { - position: absolute; - left: 0; - top: 0; -} + & a { + color: #125EAE; + text-decoration: none; -#tracy-debug a { - color: #125EAE; - text-decoration: none; -} - -#tracy-debug a:hover, -#tracy-debug a:focus { - background-color: #125EAE; - color: white; -} + &:hover, + &:focus { + background-color: #125EAE; + color: white; + } + } -#tracy-debug h2, -#tracy-debug h3, -#tracy-debug p { - margin: .4em 0; -} + & h2, + & h3 { + font-weight: bold; + } -#tracy-debug table { - background: #FDF5CE; - width: 100%; -} + & table { + background: #FDF5CE; + width: 100%; -#tracy-debug tr:nth-child(2n) td { - background: rgba(0, 0, 0, 0.02); -} + .tracy-right { + text-align: right; + } + } -#tracy-debug td, -#tracy-debug th { - border: 1px solid #E6DFBF; - padding: 2px 5px; - vertical-align: top; - text-align: left; -} + & tr:nth-child(2n) td { + background: rgba(0, 0, 0, 0.02); + } -#tracy-debug th { - background: #F4F3F1; - color: #655E5E; - font-size: 90%; - font-weight: bold; -} + & td, + & th { + border: 1px solid #E6DFBF; + padding: 2px 5px; + vertical-align: top; + text-align: left; + } -#tracy-debug pre, -#tracy-debug code { - font: 9pt/1.5 Consolas, monospace; -} + & th { + background: #F4F3F1; + color: #655E5E; + font-size: 90%; + font-weight: bold; + } -#tracy-debug table .tracy-right { - text-align: right; -} + & pre, + & code { + font: 9pt/1.5 Consolas, monospace; + } -#tracy-debug svg { - display: inline; -} + & svg { + display: inline; + } -#tracy-debug .tracy-dump { - margin: 0; - padding: 2px 5px; + .tracy-dump { + margin: 0; + padding: 2px 5px; + } } -/* bar */ #tracy-debug-bar { font: normal normal 13px/1.55 Tahoma, sans-serif; color: #333; @@ -97,69 +92,71 @@ body#tracy-debug { /* in popup window */ border-radius: 3px; box-shadow: 1px 1px 10px rgba(0, 0, 0, .15); -} - -#tracy-debug-bar:hover { - opacity: 1; - transition: opacity 0.1s; -} -#tracy-debug-bar .tracy-row { - list-style: none none; - display: flex; -} + &:hover { + opacity: 1; + transition: opacity 0.1s; + } -#tracy-debug-bar .tracy-row:not(:first-child) { - background: #d5d2c6; - opacity: .8; -} + .tracy-row { + list-style: none none; + display: flex; + + &:not(:first-child) { + background: #d5d2c6; + opacity: .8; + } + + &[data-tracy-group="ajax"] { + animation: tracy-row-flash .2s ease; + } + + @keyframes tracy-row-flash { + 0% { + background: #c9c0a0; + } + } + + &:not(:first-child) li:first-child { + width: 4.1em; + text-align: center; + } + } -#tracy-debug-bar .tracy-row[data-tracy-group="ajax"] { - animation: tracy-row-flash .2s ease; -} -@keyframes tracy-row-flash { - 0% { - background: #c9c0a0; + & img { + vertical-align: bottom; + position: relative; + top: -2px; } -} -#tracy-debug-bar .tracy-row:not(:first-child) li:first-child { - width: 4.1em; - text-align: center; -} - -#tracy-debug-bar img { - vertical-align: bottom; - position: relative; - top: -2px; -} + & svg { + vertical-align: bottom; + width: 1.23em; + height: 1.55em; + } -#tracy-debug-bar svg { - vertical-align: bottom; - width: 1.23em; - height: 1.55em; -} + .tracy-label { + margin-left: .2em; + } -#tracy-debug-bar .tracy-label { - margin-left: .2em; -} + & li > a, + & li > span { + color: #000; + display: block; + padding: 0 .4em; + } -#tracy-debug-bar li > a, -#tracy-debug-bar li > span { - color: #000; - display: block; - padding: 0 .4em; -} + & li > a:hover { + color: black; + background: #c3c1b8; + } -#tracy-debug-bar li > a:hover { - color: black; - background: #c3c1b8; + & li:first-child { + cursor: move; + } } -#tracy-debug-bar li:first-child { - cursor: move; -} #tracy-debug-logo svg { width: 3.4em; @@ -168,124 +165,135 @@ body#tracy-debug { /* in popup window */ /* panels */ -#tracy-debug .tracy-panel { - display: none; - font: normal normal 12px/1.5 sans-serif; - background: white; - color: #333; - text-align: left; -} +#tracy-debug { + .tracy-panel { + display: none; + font: normal normal 12px/1.5 sans-serif; + background: white; + color: #333; + text-align: left; + } -body#tracy-debug .tracy-panel { /* in popup window */ - display: block; -} + & h1 { + font: normal normal 23px/1.4 Tahoma, sans-serif; + color: #575753; + margin: -5px -5px var(--tracy-space); + padding: 0 5px 0 5px; + word-wrap: break-word; + } -#tracy-debug h1 { - font: normal normal 23px/1.4 Tahoma, sans-serif; - color: #575753; - margin: -5px -5px 5px; - padding: 0 5px 0 5px; - word-wrap: break-word; -} + .tracy-inner { + overflow: auto; + flex: 1; + } -#tracy-debug .tracy-inner { - overflow: auto; - flex: 1; -} + .tracy-panel .tracy-icons { + display: none; + } -#tracy-debug .tracy-panel .tracy-icons { - display: none; -} + .tracy-panel-ajax h1::after, + .tracy-panel-redirect h1::after { + content: 'ajax'; + float: right; + font-size: 65%; + margin: 0 .3em; + } -#tracy-debug .tracy-panel-ajax h1::after, -#tracy-debug .tracy-panel-redirect h1::after { - content: 'ajax'; - float: right; - font-size: 65%; - margin: 0 .3em; -} + .tracy-panel-redirect h1::after { + content: 'redirect'; + } -#tracy-debug .tracy-panel-redirect h1::after { - content: 'redirect'; -} + .tracy-mode-peek, + .tracy-mode-float { + position: fixed; + flex-direction: column; + padding: var(--tracy-space); + min-width: 200px; + min-height: 80px; + border-radius: 5px; + box-shadow: 1px 1px 20px rgba(102, 102, 102, 0.36); + border: 1px solid rgba(0, 0, 0, 0.1); + } -#tracy-debug .tracy-mode-peek, -#tracy-debug .tracy-mode-float { - position: fixed; - flex-direction: column; - padding: 10px; - min-width: 200px; - min-height: 80px; - border-radius: 5px; - box-shadow: 1px 1px 20px rgba(102, 102, 102, 0.36); - border: 1px solid rgba(0, 0, 0, 0.1); -} + .tracy-mode-peek, + .tracy-mode-float:not(.tracy-panel-resized) { + max-width: 700px; + max-height: 500px; -#tracy-debug .tracy-mode-peek, -#tracy-debug .tracy-mode-float:not(.tracy-panel-resized) { - max-width: 700px; - max-height: 500px; -} + @media (max-height: 555px) { + max-height: 100vh; + } + } -@media (max-height: 555px) { - #tracy-debug .tracy-mode-peek, - #tracy-debug .tracy-mode-float:not(.tracy-panel-resized) { - max-height: 100vh; + .tracy-mode-peek h1 { + cursor: move; } -} -#tracy-debug .tracy-mode-peek h1 { - cursor: move; -} + .tracy-mode-float { + display: flex; + opacity: .95; + transition: opacity 0.2s; + will-change: opacity, top, left; + overflow: auto; + resize: both; + } -#tracy-debug .tracy-mode-float { - display: flex; - opacity: .95; - transition: opacity 0.2s; - will-change: opacity, top, left; - overflow: auto; - resize: both; -} + .tracy-focused { + display: flex; + opacity: 1; + transition: opacity 0.1s; + } -#tracy-debug .tracy-focused { - display: flex; - opacity: 1; - transition: opacity 0.1s; -} + .tracy-mode-float h1 { + cursor: move; + padding-right: 25px; + } -#tracy-debug .tracy-mode-float h1 { - cursor: move; - padding-right: 25px; -} + .tracy-mode-float .tracy-icons { + display: block; + position: absolute; + top: 0; + right: 5px; + font-size: 18px; + } -#tracy-debug .tracy-mode-float .tracy-icons { - display: block; - position: absolute; - top: 0; - right: 5px; - font-size: 18px; -} + .tracy-mode-window { + padding: var(--tracy-space); + } -#tracy-debug .tracy-mode-window { - padding: 10px; -} + .tracy-icons a { + color: #575753; -#tracy-debug .tracy-icons a { - color: #575753; -} + &:hover { + color: white; + } + } -#tracy-debug .tracy-icons a:hover { - color: white; -} + .tracy-inner-container { + min-width: 100%; + float: left; + /* explicit gaps: */ + display: flex; + flex-direction: column; + gap: var(--tracy-space); -#tracy-debug .tracy-inner-container { - min-width: 100%; - float: left; -} + & > * { + margin-bottom: 0; /* disable implicit gaps */ + } + + &:not(:last-child) { + margin-bottom: var(--tracy-space); + } + } -@media print { - #tracy-debug * { + + @media print { display: none; } } + + +body#tracy-debug { /* in popup window */ + display: block; +} diff --git a/src/Tracy/BlueScreen/BlueScreen.php b/src/Tracy/BlueScreen/BlueScreen.php index 7158d8e0f..0def96739 100644 --- a/src/Tracy/BlueScreen/BlueScreen.php +++ b/src/Tracy/BlueScreen/BlueScreen.php @@ -132,7 +132,7 @@ public function renderToFile(\Throwable $exception, string $file): bool if ($handle = @fopen($file, 'x')) { ob_start(); // double buffer prevents sending HTTP headers in some PHP ob_start(function ($buffer) use ($handle): void { fwrite($handle, $buffer); }, 4096); - $this->renderTemplate($exception, __DIR__ . '/assets/page.phtml', false); + $this->renderTemplate($exception, __DIR__ . '/assets/page.phtml', toScreen: false); ob_end_flush(); ob_end_clean(); fclose($handle); @@ -312,8 +312,8 @@ public static function highlightFile( } $source = $php - ? static::highlightPhp($source, $line, $lines, $column) - : ''; + ? CodeHighlighter::highlightPhp($source, $line, $column) + : '' . static::highlightLine(htmlspecialchars($source, ENT_IGNORE, 'UTF-8'), $line, $lines, $column) . '
'; if ($editor = Helpers::editorUri($file, $line)) { $source = substr_replace($source, ' title="Ctrl-Click to open in editor" data-tracy-href="' . Helpers::escapeHtml($editor) . '"', 4, 0); @@ -328,23 +328,7 @@ public static function highlightFile( */ public static function highlightPhp(string $source, int $line, int $lines = 15, 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'); - } - - $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]; //' . CodeHighlighter::highlightLine(htmlspecialchars($source, ENT_IGNORE, 'UTF-8'), $line, $column) . '
- $source = str_replace('
', "\n", $source[1]);
- $out .= static::highlightLine($source, $line, $lines, $column);
- $out = str_replace(' ', ' ', $out);
- return "$out
";
+ return CodeHighlighter::highlightPhp($source, $line, $column);
}
@@ -353,93 +337,7 @@ public static function highlightPhp(string $source, int $line, int $lines = 15,
*/
public static function highlightLine(string $html, int $line, int $lines = 15, int $column = 0): string
{
- $source = explode("\n", "\n" . str_replace("\r\n", "\n", $html));
- $out = '';
- $spans = 1;
- $start = $i = max(1, min($line, count($source) - 1) - (int) floor($lines * 2 / 3));
- while (--$i >= 1) { // find last highlighted block
- if (preg_match('#.*(?span[^>]*>)#', $source[$i], $m)) {
- if ($m[1] !== '') {
- $spans++;
- $out .= $m[1];
- }
-
- break;
- }
- }
-
- $source = array_slice($source, $start, $lines, true);
- end($source);
- $numWidth = strlen((string) key($source));
-
- foreach ($source as $n => $s) {
- $spans += substr_count($s, ']+>#', $s, $tags);
- if ($n == $line) {
- $s = strip_tags($s);
- if ($column) {
- $s = preg_replace(
- '#((?:&.*?;|[^&]){' . ($column - 1) . '})(&.*?;|.)#u',
- '\1\2',
- $s . ' ',
- 1,
- );
- }
- $out .= sprintf(
- "%{$numWidth}s: %s\n%s",
- $n,
- $s,
- implode('', $tags[0]),
- );
- } else {
- $out .= sprintf("%{$numWidth}s: %s\n", $n, $s);
- }
- }
-
- $out .= str_repeat('', $spans) . '
';
- return $out;
- }
-
-
- /**
- * Returns syntax highlighted source code to Terminal.
- */
- public static function highlightPhpCli(string $file, int $line, int $lines = 15, int $column = 0): ?string
- {
- $source = @file_get_contents($file); // @ file may not exist
- if ($source === false) {
- return null;
- }
-
- $s = self::highlightPhp($source, $line, $lines);
-
- $colors = [
- '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",
- ];
-
- $stack = ['0'];
- $s = preg_replace_callback(
- '#<\w+(?: (class|style)=["\'](.*?)["\'])?[^>]*>|\w+>#',
- function ($m) use ($colors, &$stack): string {
- if ($m[0][1] === '/') {
- array_pop($stack);
- } else {
- $stack[] = isset($m[2], $colors[$m[2]]) ? $colors[$m[2]] : '0';
- }
-
- return "\e[0m\e[" . end($stack) . 'm';
- },
- $s,
- );
- $s = htmlspecialchars_decode(strip_tags($s), ENT_QUOTES | ENT_HTML5);
- return $s;
+ return CodeHighlighter::highlightLine($html, $line, $column);
}
@@ -478,7 +376,7 @@ public function getDumper(): \Closure
public function formatMessage(\Throwable $exception): string
{
- $msg = Helpers::encodeString(trim((string) $exception->getMessage()), self::MaxMessageLength, false);
+ $msg = Helpers::encodeString(trim((string) $exception->getMessage()), self::MaxMessageLength, showWhitespaces: false);
// highlight 'string'
$msg = preg_replace(
diff --git a/src/Tracy/BlueScreen/CodeHighlighter.php b/src/Tracy/BlueScreen/CodeHighlighter.php
new file mode 100644
index 000000000..fb5ae0f3d
--- /dev/null
+++ b/src/Tracy/BlueScreen/CodeHighlighter.php
@@ -0,0 +1,139 @@
+]*>#', function ($m) use (&$openTags, &$closeTags) {
+ if ($m[0][1] === '/') {
+ array_pop($openTags);
+ array_shift($closeTags);
+ } else {
+ $openTags[] = $m[0];
+ array_unshift($closeTags, "$m[1]>");
+ }
+ }, $lines[$n]);
+
+ if ($n === $line) {
+ $s = strip_tags($lines[$n]);
+ if ($column) {
+ $s = preg_replace(
+ '#((?:&.*?;|[^&]){' . ($column - 1) . '})(&.*?;|.)#u',
+ '\1\2',
+ $s . ' ',
+ 1,
+ );
+ }
+ $out .= sprintf("%{$numWidth}s: %s\n%s", $n, $s, implode('', $openTags));
+ } else {
+ $out .= sprintf("%{$numWidth}s: %s\n", $n, $lines[$n]);
+ }
+ }
+
+ $out .= implode('', $closeTags);
+ return $out;
+ }
+
+
+ /**
+ * Returns syntax highlighted source code.
+ */
+ public static function highlightPhp(string $code, int $line, int $column = 0): string
+ {
+ $html = self::highlightPhpCode($code);
+ $html = self::highlightLine($html, $line, $column);
+ return ""; + } + + + 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; + } + + + /** + * Returns syntax highlighted source code to Terminal. + */ + public static function highlightPhpCli(string $code, int $line, int $column = 0): string + { + return Helpers::htmlToAnsi( + self::highlightPhp($code, $line, $column), + [ + '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 7e007625f..9f43ed979 100644 --- a/src/Tracy/BlueScreen/assets/bluescreen.css +++ b/src/Tracy/BlueScreen/assets/bluescreen.css @@ -2,16 +2,6 @@ * This file is part of the Tracy (https://tracy.nette.org) */ -:root { - --tracy-space: 16px; -} - -@media (max-width: 600px) { - :root { - --tracy-space: 8px; - } -} - html.tracy-bs-visible, html.tracy-bs-visible body { display: block; @@ -19,6 +9,7 @@ html.tracy-bs-visible body { } #tracy-bs { + --tracy-space: 16px; font: 9pt/1.5 Verdana, sans-serif; background: white; color: #333; @@ -28,391 +19,403 @@ html.tracy-bs-visible body { top: 0; width: 100%; text-align: left; -} - -#tracy-bs a { - text-decoration: none; - color: #328ADC; - padding: 0 4px; - margin: 0 -4px; -} - -#tracy-bs a + a { - margin-left: 0; -} - -#tracy-bs a:hover, -#tracy-bs a:focus { - color: #085AA3; -} - -#tracy-bs-toggle { - position: absolute; - right: .5em; - top: .5em; - text-decoration: none; - background: #CD1818; - color: white !important; - padding: 3px; -} -#tracy-bs-toggle.tracy-collapsed { - position: fixed; -} - -.tracy-bs-main { - display: flex; - flex-direction: column; - padding-bottom: 80vh; -} - -.tracy-bs-main.tracy-collapsed { - display: none; -} - -#tracy-bs p, -#tracy-bs table, -#tracy-bs pre, -#tracy-bs h1, -#tracy-bs h2, -#tracy-bs h3 { - margin: 0 0 var(--tracy-space); -} - -#tracy-bs h1 { - font-size: 15pt; - font-weight: normal; - text-shadow: 1px 1px 2px rgba(0, 0, 0, .3); -} - -#tracy-bs h1 span { - white-space: pre-wrap; -} + @media (max-width: 600px) { + --tracy-space: 8px; + } -#tracy-bs h2 { - font-size: 14pt; - font-weight: normal; - margin-top: var(--tracy-space); -} + & a { + text-decoration: none; + color: #328ADC; + padding: 0 4px; + margin: 0 -4px; -#tracy-bs h3 { - font-size: 10pt; - font-weight: bold; -} + &:hover, + &:focus { + color: #085AA3; + } + } -#tracy-bs pre, -#tracy-bs code, -#tracy-bs table { - font: 9pt/1.5 Consolas, monospace !important; -} + & a + a { + margin-left: 0; + } -#tracy-bs pre, -#tracy-bs table { - background: #FDF5CE; - padding: .4em .7em; - border: 2px solid #ffffffa6; - box-shadow: 1px 2px 6px #00000005; - overflow: auto; -} + #tracy-bs-toggle { + position: absolute; + right: .5em; + top: .5em; + text-decoration: none; + background: #CD1818; + color: white !important; + padding: 3px; + + &.tracy-collapsed { + position: fixed; + } + } -#tracy-bs table pre { - padding: 0; - margin: 0; - border: none; - box-shadow: none; -} + .tracy-bs-main { + display: flex; + flex-direction: column; + padding-bottom: 80vh; -#tracy-bs table { - border-collapse: collapse; - width: 100%; -} + &.tracy-collapsed { + display: none; + } + } -#tracy-bs td, -#tracy-bs th { - vertical-align: top; - text-align: left; - padding: 2px 6px; - border: 1px solid #e6dfbf; -} + & h1 { + font-size: 15pt; + font-weight: normal; + text-shadow: 1px 1px 2px rgba(0, 0, 0, .3); -#tracy-bs th { - font-weight: bold; -} + & span { + white-space: pre-wrap; + } + } -#tracy-bs tr > :first-child { - width: 20%; -} + & h2 { + font-size: 14pt; + font-weight: normal; + } -#tracy-bs tr:nth-child(2n), -#tracy-bs tr:nth-child(2n) pre { - background-color: #F7F0CB; -} + & h3 { + font-size: 10pt; + font-weight: bold; + } -#tracy-bs .tracy-footer--sticky { - position: fixed; - width: 100%; - bottom: 0; -} + & pre, + & code, + & table { + font: 9pt/1.5 Consolas, monospace !important; + } -#tracy-bs footer ul { - font-size: 7pt; - padding: var(--tracy-space); - margin: var(--tracy-space) 0 0; - color: #777; - background: #F6F5F3; - border-top: 1px solid #DDD; - list-style: none; -} + & pre, + & table { + background: #FDF5CE; + padding: .4em .7em; + border: 2px solid #ffffffa6; + box-shadow: 1px 2px 6px #00000005; + overflow: auto; + } -#tracy-bs .tracy-footer-logo { - position: relative; -} + & table { + border-collapse: collapse; + width: 100%; -#tracy-bs .tracy-footer-logo a { - position: absolute; - bottom: 0; - right: 0; - width: 100px; - height: 50px; - background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAUBAMAAAD/1DctAAAAMFBMVEWupZzj39rEvbTy8O3X0sz9/PvGwLu8tavQysHq6OS0rKP5+Pbd2dT29fPMxbzPx8DKErMJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACGUlEQVQoFX3TQWgTQRQA0MWLIJJDYehBTykhG5ERTx56K1u8eEhCYtomE7x5L4iLh0ViF7egewuFFqSIYE6hIHsIYQ6CQSg9CDKn4QsNCRlB59C74J/ZNHW1+An5+bOPyf6/s46oz2P+A0yIeZZ2ieEHi6TOnLKTxvWq+b52mxlVO3xnM1s7xLX1504XQH65OnW2dBqn7cCkYsFsfYsWpyY/2salmFTpEyzeR8zosYqMdiPDXdyU52K1wgEa/SjGpdEwUAxqvRfckQCDOyFearsEHe2grvkh/cFAHKvdtI3lcVceKQIOFpv+FOZaNPQBwJZLPp+hfrvT5JZXaUFsR8zqQc9qSgAharkfS5M/5F6nGJJAtXq/eLr3ucZpHccSxOOIPaQhtHohpCH2Xu6rLmQ0djnr4/+J3C6v+AW8/XWYxwYNdlhWj/P5fPSTQwVr0T9lGxdaBCqErNZaqYnEwbkjEB3NasGF3lPdrHa1nnxNOMgj0+neePUPjd2v/qVvUv29ifvc19huQ48qwXShy/9o8o3OSk0cs37mOFd0Ydgvsf/oZEnPVtggfd66lORn9mDyyzXU13SRtH2L6aR5T/snGAcZPfAXz5J1YlJWBEuxdMYqQecpBrlM49xAbmqyHA+xlA1FxBtqT2xmJoNXZlIt74ZBLeJ9ZGDqByNI7p543idzJ23vXEv7IgnsxiS+eNtwNbFdLq7+Bi4wQ0I4SVb9AAAAAElFTkSuQmCC') no-repeat; - opacity: .6; - padding: 0; - margin: 0; -} + & pre { + padding: 0; + margin: 0; + border: none; + box-shadow: none; + } + } -#tracy-bs .tracy-footer-logo a:hover, -#tracy-bs .tracy-footer-logo a:focus { - opacity: 1; - transition: opacity 0.1s; -} + & td, + & th { + vertical-align: top; + text-align: left; + padding: 2px 6px; + border: 1px solid #e6dfbf; + } + & th { + font-weight: bold; + } -#tracy-bs .tracy-section { - padding-left: calc(1.5 * var(--tracy-space)); - padding-right: calc(1.5 * var(--tracy-space)); -} + & tr > :first-child { + width: 20%; + } -#tracy-bs .tracy-section-panel { - background: #F4F3F1; - padding: var(--tracy-space) var(--tracy-space) 0; - margin: 0 0 var(--tracy-space); - border-radius: 8px; - box-shadow: inset 1px 1px 0px 0 #00000005; - overflow: hidden; -} + & tr:nth-child(2n), + & tr:nth-child(2n) pre { + background-color: #F7F0CB; + } -#tracy-bs .outer, /* deprecated */ -#tracy-bs .tracy-pane { - overflow: auto; -} + .tracy-footer--sticky { + position: fixed; + width: 100%; + bottom: 0; + } -#tracy-bs.tracy-mac .tracy-pane { - padding-bottom: 12px; -} + & footer ul { + font-size: 7pt; + padding: var(--tracy-space); + margin: var(--tracy-space) 0 0; + color: #777; + background: #F6F5F3; + border-top: 1px solid #DDD; + list-style: none; + } + .tracy-footer-logo { + position: relative; + + & a { + position: absolute; + bottom: 0; + right: 0; + width: 100px; + height: 50px; + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAUBAMAAAD/1DctAAAAMFBMVEWupZzj39rEvbTy8O3X0sz9/PvGwLu8tavQysHq6OS0rKP5+Pbd2dT29fPMxbzPx8DKErMJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACGUlEQVQoFX3TQWgTQRQA0MWLIJJDYehBTykhG5ERTx56K1u8eEhCYtomE7x5L4iLh0ViF7egewuFFqSIYE6hIHsIYQ6CQSg9CDKn4QsNCRlB59C74J/ZNHW1+An5+bOPyf6/s46oz2P+A0yIeZZ2ieEHi6TOnLKTxvWq+b52mxlVO3xnM1s7xLX1504XQH65OnW2dBqn7cCkYsFsfYsWpyY/2salmFTpEyzeR8zosYqMdiPDXdyU52K1wgEa/SjGpdEwUAxqvRfckQCDOyFearsEHe2grvkh/cFAHKvdtI3lcVceKQIOFpv+FOZaNPQBwJZLPp+hfrvT5JZXaUFsR8zqQc9qSgAharkfS5M/5F6nGJJAtXq/eLr3ucZpHccSxOOIPaQhtHohpCH2Xu6rLmQ0djnr4/+J3C6v+AW8/XWYxwYNdlhWj/P5fPSTQwVr0T9lGxdaBCqErNZaqYnEwbkjEB3NasGF3lPdrHa1nnxNOMgj0+neePUPjd2v/qVvUv29ifvc19huQ48qwXShy/9o8o3OSk0cs37mOFd0Ydgvsf/oZEnPVtggfd66lORn9mDyyzXU13SRtH2L6aR5T/snGAcZPfAXz5J1YlJWBEuxdMYqQecpBrlM49xAbmqyHA+xlA1FxBtqT2xmJoNXZlIt74ZBLeJ9ZGDqByNI7p543idzJ23vXEv7IgnsxiS+eNtwNbFdLq7+Bi4wQ0I4SVb9AAAAAElFTkSuQmCC') no-repeat; + opacity: .6; + padding: 0; + margin: 0; + + &:hover, + &:focus { + opacity: 1; + transition: opacity 0.1s; + } + } + } -/* header */ -#tracy-bs .tracy-section--error { - background: #CD1818; - color: white; - font-size: 13pt; - padding-top: var(--tracy-space); -} -#tracy-bs .tracy-section--error h1 { - color: white; -} + .tracy-section { + padding: var(--tracy-space); + } -#tracy-bs .tracy-section--error::selection, -#tracy-bs .tracy-section--error ::selection { - color: black !important; - background: #FDF5CE !important; -} + .tracy-section-panel { + background: #F4F3F1; + padding: var(--tracy-space); + border-radius: 8px; + box-shadow: inset 1px 1px 0px 0 #00000005; + overflow: hidden; + } -#tracy-bs .tracy-section--error a { - color: #ffefa1 !important; -} + .outer, /* deprecated */ + .tracy-pane { + overflow: auto; + } -#tracy-bs .tracy-section--error span span { - font-size: 80%; - color: rgba(255, 255, 255, 0.5); - text-shadow: none; -} + .tracy-pane:not(:last-child) { + margin-bottom: var(--tracy-space); + } -#tracy-bs .tracy-section--error a.tracy-action { - color: white !important; - opacity: 0; - font-size: .7em; - border-bottom: none !important; -} + &.tracy-mac .tracy-pane { + padding-bottom: 12px; + } -#tracy-bs .tracy-section--error:hover a.tracy-action { - opacity: .6; -} -#tracy-bs .tracy-section--error a.tracy-action:hover { - opacity: 1; -} + /* header */ + .tracy-section--error { + background: #CD1818; + color: white; + font-size: 13pt; + + & h1 { + color: white; + } + + &::selection, + & ::selection { + color: black !important; + background: #FDF5CE !important; + } + + & a { + color: #ffefa1 !important; + } + + & span span { + font-size: 80%; + color: rgba(255, 255, 255, 0.5); + text-shadow: none; + } + + & a.tracy-action { + color: white !important; + opacity: 0; + font-size: .7em; + border-bottom: none !important; + } + + &:hover a.tracy-action { + opacity: .6; + } + + & a.tracy-action:hover { + opacity: 1; + } + + & i { + color: #ffefa1; + font-style: normal; + } + } -#tracy-bs .tracy-section--error i { - color: #ffefa1; - font-style: normal; -} + /* source code */ + & pre.tracy-code > div { + min-width: 100%; + float: left; + white-space: pre; + } -/* source code */ -#tracy-bs pre.tracy-code > div { - min-width: 100%; - float: left; - white-space: pre; -} + .tracy-code-comment { + color: rgba(0, 0, 0, 0.5); + font-style: italic; + } -#tracy-bs .tracy-line-highlight { - background: #CD1818; - color: white; - font-weight: bold; - font-style: normal; - display: block; - padding: 0 1ch; - margin: 0 -1ch; -} + .tracy-code-keyword { + color: #D24; + font-weight: bold; + } -#tracy-bs .tracy-column-highlight { - display: inline-block; - backdrop-filter: grayscale(1); - margin: 0 -1px; - padding: 0 1px; -} + .tracy-code-var { + font-weight: bold; + } -#tracy-bs .tracy-line { - color: #9F9C7F; - font-weight: normal; - font-style: normal; -} + .tracy-line-highlight { + background: #CD1818; + color: white; + font-weight: bold; + font-style: normal; + display: block; + padding: 0 1ch; + margin: 0 -1ch -1lh; + } -#tracy-bs a.tracy-editor { - color: inherit; - border-bottom: 1px dotted rgba(0, 0, 0, .3); - border-radius: 3px; -} + .tracy-column-highlight { + display: inline-block; + backdrop-filter: grayscale(1); + margin: 0 -1px; + padding: 0 1px; + } -#tracy-bs a.tracy-editor:hover { - background: #0001; -} + .tracy-line { + color: #9F9C7F; + font-weight: normal; + font-style: normal; + } -#tracy-bs span[data-tracy-href] { - border-bottom: 1px dotted rgba(0, 0, 0, .3); -} + & a.tracy-editor { + color: inherit; + border-bottom: 1px dotted rgba(0, 0, 0, .3); + border-radius: 3px; -#tracy-bs .tracy-dump-whitespace { - color: #0003; -} + &:hover { + background: #0001; + } + } -#tracy-bs .tracy-caused { - float: right; - padding: .3em calc(1.5 * var(--tracy-space)); - background: #df8075; - border-radius: 0 0 0 8px; - white-space: nowrap; -} + & span[data-tracy-href] { + border-bottom: 1px dotted rgba(0, 0, 0, .3); + } -#tracy-bs .tracy-caused a { - color: white; -} + .tracy-dump-whitespace { + color: #0003; + } -#tracy-bs .tracy-callstack { - display: grid; - grid-template-columns: max-content 1fr; - margin-bottom: calc(.5 * var(--tracy-space)); -} + .tracy-caused { + float: right; + padding: .3em calc(1.5 * var(--tracy-space)); + background: #df8075; + border-radius: 0 0 0 8px; + white-space: nowrap; -#tracy-bs .tracy-callstack-file { - text-align: right; - padding-right: var(--tracy-space); - white-space: nowrap; - height: calc(1.5 * var(--tracy-space)); -} + & a { + color: white; + } + } -#tracy-bs .tracy-callstack-callee { - white-space: nowrap; - height: calc(1.5 * var(--tracy-space)); -} + .tracy-callstack { + display: grid; + grid-template-columns: max-content 1fr; + } -#tracy-bs .tracy-callstack-additional { - grid-column-start: 1; - grid-column-end: 3; -} + .tracy-callstack-file { + text-align: right; + padding-right: var(--tracy-space); + white-space: nowrap; + height: calc(1.5 * var(--tracy-space)); + } -#tracy-bs .tracy-callstack-args tr:first-child > * { - position: relative; -} + .tracy-callstack-callee { + white-space: nowrap; + height: calc(1.5 * var(--tracy-space)); + } -#tracy-bs .tracy-callstack-args tr:first-child td:before { - position: absolute; - right: .3em; - content: 'may not be true'; - opacity: .4; -} + .tracy-callstack-additional { + grid-column-start: 1; + grid-column-end: 3; + } -#tracy-bs .tracy-panel-fadein { - animation: tracy-panel-fadein .12s ease; -} + .tracy-callstack-additional:not(:last-child) { + margin-bottom: var(--tracy-space); + } -@keyframes tracy-panel-fadein { - 0% { - opacity: 0; + .tracy-callstack-args tr:first-child > * { + position: relative; } -} -#tracy-bs .tracy-section--causedby { - flex-direction: column; - padding: 0; -} + .tracy-callstack-args tr:first-child td:before { + position: absolute; + right: .3em; + content: 'may not be true'; + opacity: .4; + } -#tracy-bs .tracy-section--causedby:not(.tracy-collapsed) { - display: flex; -} + .tracy-panel-fadein { + animation: tracy-panel-fadein .12s ease; + } -#tracy-bs .tracy-section--causedby .tracy-section--error { - background: #cd1818a6; -} + @keyframes tracy-panel-fadein { + 0% { + opacity: 0; + } + } -#tracy-bs .tracy-section--error + .tracy-section--stack { - margin-top: calc(1.5 * var(--tracy-space)); -} + .tracy-section--causedby { + flex-direction: column; + padding: 0; + &:not(.tracy-collapsed) { + display: flex; + } -/* tabs */ -#tracy-bs .tracy-tab-bar { - display: flex; - list-style: none; - padding-left: 0; - margin: 0; - width: 100%; - font-size: 110%; -} + & .tracy-section--error { + background: #cd1818a6; + } + } -#tracy-bs .tracy-tab-bar > *:not(:first-child) { - margin-left: var(--tracy-space); -} + .tracy-section--error + .tracy-section--stack { + margin-top: calc(1.5 * var(--tracy-space)); + } -#tracy-bs .tracy-tab-bar a { - display: block; - padding: calc(.5 * var(--tracy-space)) var(--tracy-space); - margin: 0; - height: 100%; - box-sizing: border-box; - border-radius: 5px 5px 0 0; - text-decoration: none; - transition: all 0.1s; -} -#tracy-bs .tracy-tab-bar > .tracy-active a { - background: white; -} + /* tabs */ + .tracy-tab-bar { + display: flex; + list-style: none; + padding-left: 0; + margin: 0; + width: 100%; + font-size: 110%; + + & > *:not(:first-child) { + margin-left: var(--tracy-space); + } + + & a { + display: block; + padding: calc(.5 * var(--tracy-space)) var(--tracy-space); + margin: 0; + height: 100%; + box-sizing: border-box; + border-radius: 5px 5px 0 0; + text-decoration: none; + transition: all 0.1s; + } + + & > .tracy-active a { + background: white; + } + } -#tracy-bs .tracy-tab-panel { - border-top: 2px solid white; - padding-top: var(--tracy-space); - overflow: auto; + .tracy-tab-panel { + border-top: 2px solid white; + padding-top: var(--tracy-space); + overflow: auto; + } } diff --git a/src/Tracy/Debugger/Debugger.php b/src/Tracy/Debugger/Debugger.php index 9059fc6c4..71b9bcb7a 100644 --- a/src/Tracy/Debugger/Debugger.php +++ b/src/Tracy/Debugger/Debugger.php @@ -17,7 +17,7 @@ */ class Debugger { - public const Version = '2.10.3'; + public const Version = '3.0-dev'; /** server modes for Debugger::enable() */ public const @@ -235,6 +235,7 @@ public static function enable( 'Bar/Bar', 'Bar/DefaultBarPanel', 'BlueScreen/BlueScreen', + 'BlueScreen/CodeHighlighter', 'Dumper/Describer', 'Dumper/Dumper', 'Dumper/Exposer', diff --git a/src/Tracy/Debugger/DeferredContent.php b/src/Tracy/Debugger/DeferredContent.php index 2ed27ffca..7ad3e9bea 100644 --- a/src/Tracy/Debugger/DeferredContent.php +++ b/src/Tracy/Debugger/DeferredContent.php @@ -147,7 +147,7 @@ private function buildJsCss(): string public function clean(): void { foreach ($this->sessionStorage->getData() as &$items) { - $items = array_slice((array) $items, -10, null, true); + $items = array_slice((array) $items, -10, null, preserve_keys: true); $items = array_filter($items, fn($item) => isset($item['time']) && $item['time'] > time() - 60); } } diff --git a/src/Tracy/Debugger/DevelopmentStrategy.php b/src/Tracy/Debugger/DevelopmentStrategy.php index d778027d3..3a60a765a 100644 --- a/src/Tracy/Debugger/DevelopmentStrategy.php +++ b/src/Tracy/Debugger/DevelopmentStrategy.php @@ -54,11 +54,11 @@ private function renderExceptionCli(\Throwable $exception): void } if ($logFile && !headers_sent()) { - header("X-Tracy-Error-Log: $logFile", false); + header("X-Tracy-Error-Log: $logFile", replace: false); } - if (Helpers::detectColors()) { - echo "\n\n" . $this->blueScreen->highlightPhpCli($exception->getFile(), $exception->getLine()) . "\n"; + if (Helpers::detectColors() && @is_file($exception->getFile())) { + echo "\n\n" . CodeHighlighter::highlightPhpCli(file_get_contents($exception->getFile()), $exception->getLine()) . "\n"; } echo "$exception\n" . ($logFile ? "\n(stored in $logFile)\n" : ''); diff --git a/src/Tracy/Dumper/Describer.php b/src/Tracy/Dumper/Describer.php index 72d330f91..39b054991 100644 --- a/src/Tracy/Dumper/Describer.php +++ b/src/Tracy/Dumper/Describer.php @@ -132,7 +132,7 @@ private function describeArray(array $arr, int $depth = 0, ?int $refId = null): return $res; } elseif ($depth && $this->maxItems && count($arr) > $this->maxItems) { $value->length = count($arr); - $arr = array_slice($arr, 0, $this->maxItems, true); + $arr = array_slice($arr, 0, $this->maxItems, preserve_keys: true); } $items = &$value->items; @@ -144,7 +144,7 @@ private function describeArray(array $arr, int $depth = 0, ?int $refId = null): $res = new Value(Value::TypeArray, null, count($arr)); $res->depth = $depth; $items = &$res->items; - $arr = array_slice($arr, 0, $this->maxItems, true); + $arr = array_slice($arr, 0, $this->maxItems, preserve_keys: true); } $items = []; diff --git a/src/Tracy/Dumper/Exposer.php b/src/Tracy/Dumper/Exposer.php index 5a7d5c0e5..c7328983f 100644 --- a/src/Tracy/Dumper/Exposer.php +++ b/src/Tracy/Dumper/Exposer.php @@ -142,7 +142,7 @@ public static function exposeArrayObject(\ArrayObject $obj, Value $value, Descri public static function exposeDOMNode(\DOMNode $obj, Value $value, Describer $describer): void { - $props = preg_match_all('#^\s*\[([^\]]+)\] =>#m', print_r($obj, true), $tmp) ? $tmp[1] : []; + $props = preg_match_all('#^\s*\[([^\]]+)\] =>#m', print_r($obj, return: true), $tmp) ? $tmp[1] : []; sort($props); foreach ($props as $p) { $describer->addPropertyTo($value, $p, $obj->$p, Value::PropertyPublic); diff --git a/src/Tracy/Dumper/Renderer.php b/src/Tracy/Dumper/Renderer.php index 8f42c486a..edcff7498 100644 --- a/src/Tracy/Dumper/Renderer.php +++ b/src/Tracy/Dumper/Renderer.php @@ -100,8 +100,7 @@ public function renderAsText(\stdClass $model, array $colors = []): string $this->parents = $this->snapshot = $this->above = []; } - $s = $colors ? self::htmlToAnsi($s, $colors) : $s; - $s = htmlspecialchars_decode(strip_tags($s), ENT_QUOTES | ENT_HTML5); + $s = $colors ? Helpers::htmlToAnsi($s, $colors) : Helpers::htmlToText($s); $s = str_replace('…', '...', $s); $s .= substr($s, -1) === "\n" ? '' : "\n"; @@ -115,48 +114,21 @@ public function renderAsText(\stdClass $model, array $colors = []): string private function renderVar(mixed $value, int $depth = 0, string|int|null $keyType = null): string { - switch (true) { - case $value === null: - return 'null'; - - case is_bool($value): - return '' . ($value ? 'true' : 'false') . ''; - - case is_int($value): - return '' . $value . ''; - - case is_float($value): - return '' . self::jsonEncode($value) . ''; - - case is_string($value): - return $this->renderString($value, $depth, $keyType); - - case is_array($value): - case $value->type === Value::TypeArray: - return $this->renderArray($value, $depth); - - case $value->type === Value::TypeRef: - return $this->renderVar($this->snapshot[$value->value], $depth, $keyType); - - case $value->type === Value::TypeObject: - return $this->renderObject($value, $depth); - - case $value->type === Value::TypeNumber: - return '' . Helpers::escapeHtml($value->value) . ''; - - case $value->type === Value::TypeText: - return '' . Helpers::escapeHtml($value->value) . ''; - - case $value->type === Value::TypeStringHtml: - case $value->type === Value::TypeBinaryHtml: - return $this->renderString($value, $depth, $keyType); - - case $value->type === Value::TypeResource: - return $this->renderResource($value, $depth); - - default: - throw new \Exception('Unknown type'); - } + return match (true) { + $value === null => 'null', + is_bool($value) => '' . ($value ? 'true' : 'false') . '', + is_int($value) => '' . $value . '', + is_float($value) => '' . self::jsonEncode($value) . '', + is_string($value) => $this->renderString($value, $depth, $keyType), + is_array($value), $value->type === Value::TypeArray => $this->renderArray($value, $depth), + $value->type === Value::TypeRef => $this->renderVar($this->snapshot[$value->value], $depth, $keyType), + $value->type === Value::TypeObject => $this->renderObject($value, $depth), + $value->type === Value::TypeNumber => '' . Helpers::escapeHtml($value->value) . '', + $value->type === Value::TypeText => '' . Helpers::escapeHtml($value->value) . '', + $value->type === Value::TypeStringHtml, $value->type === Value::TypeBinaryHtml => $this->renderString($value, $depth, $keyType), + $value->type === Value::TypeResource => $this->renderResource($value, $depth), + default => throw new \Exception('Unknown type'), + }; } @@ -449,25 +421,4 @@ public static function jsonEncode(mixed $value): string } } } - - - private static function htmlToAnsi(string $s, array $colors): string - { - $stack = ['0']; - $s = preg_replace_callback( - '#<\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 "\033[" . end($stack) . 'm'; - }, - $s, - ); - $s = preg_replace('/\e\[0m(\n*)(?=\e)/', '$1', $s); - return $s; - } } diff --git a/src/Tracy/Dumper/assets/dumper-dark.css b/src/Tracy/Dumper/assets/dumper-dark.css index 349159e71..50f1fbe94 100644 --- a/src/Tracy/Dumper/assets/dumper-dark.css +++ b/src/Tracy/Dumper/assets/dumper-dark.css @@ -2,144 +2,146 @@ * This file is part of the Tracy (https://tracy.nette.org) */ -.tracy-dump.tracy-dark { - text-align: left; - color: #f8f8f2; - background: #29292e; - border-radius: 4px; - padding: 1em; - margin: 1em 0; - word-break: break-all; - white-space: pre-wrap; -} +.tracy-dark { + &.tracy-dump { + text-align: left; + color: #f8f8f2; + background: #29292e; + border-radius: 4px; + padding: 1em; + margin: 1em 0; + word-break: break-all; + white-space: pre-wrap; + } -.tracy-dump.tracy-dark div { - padding-left: 2.5ex; -} + &.tracy-dump div { + padding-left: 2.5ex; + } -.tracy-dump.tracy-dark div div { - border-left: 1px solid rgba(255, 255, 255, .1); - margin-left: .5ex; -} + &.tracy-dump div div { + border-left: 1px solid rgba(255, 255, 255, .1); + margin-left: .5ex; + } -.tracy-dump.tracy-dark div div:hover { - border-left-color: rgba(255, 255, 255, .25); -} + &.tracy-dump div div:hover { + border-left-color: rgba(255, 255, 255, .25); + } -.tracy-dark .tracy-dump-location { - color: silver; - font-size: 80%; - text-decoration: none; - background: none; - opacity: .5; - float: right; - cursor: pointer; -} + .tracy-dump-location { + color: silver; + font-size: 80%; + text-decoration: none; + background: none; + opacity: .5; + float: right; + cursor: pointer; + } -.tracy-dark .tracy-dump-location:hover, -.tracy-dark .tracy-dump-location:focus { - opacity: 1; -} + .tracy-dump-location:hover, + .tracy-dump-location:focus { + opacity: 1; + } -.tracy-dark .tracy-dump-array, -.tracy-dark .tracy-dump-object { - color: #f69c2e; - user-select: text; -} + .tracy-dump-array, + .tracy-dump-object { + color: #f69c2e; + user-select: text; + } -.tracy-dark .tracy-dump-string { - color: #3cdfef; - white-space: break-spaces; -} + .tracy-dump-string { + color: #3cdfef; + white-space: break-spaces; + } -.tracy-dark div.tracy-dump-string { - position: relative; - padding-left: 3.5ex; -} + & div.tracy-dump-string { + position: relative; + padding-left: 3.5ex; + } -.tracy-dark .tracy-dump-lq { - margin-left: calc(-1ex - 1px); -} + .tracy-dump-lq { + margin-left: calc(-1ex - 1px); + } -.tracy-dark div.tracy-dump-string:before { - content: ''; - position: absolute; - left: calc(3ex - 1px); - top: 1.5em; - bottom: 0; - border-left: 1px solid rgba(255, 255, 255, .1); -} + & div.tracy-dump-string:before { + content: ''; + position: absolute; + left: calc(3ex - 1px); + top: 1.5em; + bottom: 0; + border-left: 1px solid rgba(255, 255, 255, .1); + } -.tracy-dark .tracy-dump-virtual span, -.tracy-dark .tracy-dump-dynamic span, -.tracy-dark .tracy-dump-string span { - color: rgba(255, 255, 255, 0.5); -} + .tracy-dump-virtual span, + .tracy-dump-dynamic span, + .tracy-dump-string span { + color: rgba(255, 255, 255, 0.5); + } -.tracy-dark .tracy-dump-virtual i, -.tracy-dark .tracy-dump-dynamic i, -.tracy-dark .tracy-dump-string i { - font-size: 80%; - font-style: normal; - color: rgba(255, 255, 255, 0.5); - user-select: none; -} + .tracy-dump-virtual i, + .tracy-dump-dynamic i, + .tracy-dump-string i { + font-size: 80%; + font-style: normal; + color: rgba(255, 255, 255, 0.5); + user-select: none; + } -.tracy-dark .tracy-dump-number { - color: #77d285; -} + .tracy-dump-number { + color: #77d285; + } -.tracy-dark .tracy-dump-null, -.tracy-dark .tracy-dump-bool { - color: #f3cb44; -} + .tracy-dump-null, + .tracy-dump-bool { + color: #f3cb44; + } -.tracy-dark .tracy-dump-virtual { - font-style: italic; -} + .tracy-dump-virtual { + font-style: italic; + } -.tracy-dark .tracy-dump-public::after { - content: ' pub'; -} + .tracy-dump-public::after { + content: ' pub'; + } -.tracy-dark .tracy-dump-protected::after { - content: ' pro'; -} + .tracy-dump-protected::after { + content: ' pro'; + } -.tracy-dark .tracy-dump-private::after { - content: ' pri'; -} + .tracy-dump-private::after { + content: ' pri'; + } -.tracy-dark .tracy-dump-public::after, -.tracy-dark .tracy-dump-protected::after, -.tracy-dark .tracy-dump-private::after, -.tracy-dark .tracy-dump-hash { - font-size: 85%; - color: rgba(255, 255, 255, 0.35); -} + .tracy-dump-public::after, + .tracy-dump-protected::after, + .tracy-dump-private::after, + .tracy-dump-hash { + font-size: 85%; + color: rgba(255, 255, 255, 0.35); + } -.tracy-dark .tracy-dump-indent { - display: none; -} + .tracy-dump-indent { + display: none; + } -.tracy-dark .tracy-dump-highlight { - background: #C22; - color: white; - border-radius: 2px; - padding: 0 2px; - margin: 0 -2px; -} + .tracy-dump-highlight { + background: #C22; + color: white; + border-radius: 2px; + padding: 0 2px; + margin: 0 -2px; + } -span[data-tracy-href] { - border-bottom: 1px dotted rgba(255, 255, 255, .2); -} + span[data-tracy-href] { + border-bottom: 1px dotted rgba(255, 255, 255, .2); + } -.tracy-dark .tracy-dump-flash { - animation: tracy-dump-flash .2s ease; -} + .tracy-dump-flash { + animation: tracy-dump-flash .2s ease; + } -@keyframes tracy-dump-flash { - 0% { - background: #c0c0c033; + @keyframes tracy-dump-flash { + 0% { + background: #c0c0c033; + } } } diff --git a/src/Tracy/Dumper/assets/dumper-light.css b/src/Tracy/Dumper/assets/dumper-light.css index 963dfb8c4..a58d7d836 100644 --- a/src/Tracy/Dumper/assets/dumper-light.css +++ b/src/Tracy/Dumper/assets/dumper-light.css @@ -2,144 +2,146 @@ * This file is part of the Tracy (https://tracy.nette.org) */ -.tracy-dump.tracy-light { - text-align: left; - color: #444; - background: #fdf9e2; - border-radius: 4px; - padding: 1em; - margin: 1em 0; - word-break: break-all; - white-space: pre-wrap; -} +.tracy-light { + &.tracy-dump { + text-align: left; + color: #444; + background: #fdf9e2; + border-radius: 4px; + padding: 1em; + margin: 1em 0; + word-break: break-all; + white-space: pre-wrap; + } -.tracy-dump.tracy-light div { - padding-left: 2.5ex; -} + &.tracy-dump div { + padding-left: 2.5ex; + } -.tracy-dump.tracy-light div div { - border-left: 1px solid rgba(0, 0, 0, .1); - margin-left: .5ex; -} + &.tracy-dump div div { + border-left: 1px solid rgba(0, 0, 0, .1); + margin-left: .5ex; + } -.tracy-dump.tracy-light div div:hover { - border-left-color: rgba(0, 0, 0, .25); -} + &.tracy-dump div div:hover { + border-left-color: rgba(0, 0, 0, .25); + } -.tracy-light .tracy-dump-location { - color: gray; - font-size: 80%; - text-decoration: none; - background: none; - opacity: .5; - float: right; - cursor: pointer; -} + .tracy-dump-location { + color: gray; + font-size: 80%; + text-decoration: none; + background: none; + opacity: .5; + float: right; + cursor: pointer; + } -.tracy-light .tracy-dump-location:hover, -.tracy-light .tracy-dump-location:focus { - opacity: 1; -} + .tracy-dump-location:hover, + .tracy-dump-location:focus { + opacity: 1; + } -.tracy-light .tracy-dump-array, -.tracy-light .tracy-dump-object { - color: #C22; - user-select: text; -} + .tracy-dump-array, + .tracy-dump-object { + color: #C22; + user-select: text; + } -.tracy-light .tracy-dump-string { - color: #35D; - white-space: break-spaces; -} + .tracy-dump-string { + color: #35D; + white-space: break-spaces; + } -.tracy-light div.tracy-dump-string { - position: relative; - padding-left: 3.5ex; -} + & div.tracy-dump-string { + position: relative; + padding-left: 3.5ex; + } -.tracy-light .tracy-dump-lq { - margin-left: calc(-1ex - 1px); -} + .tracy-dump-lq { + margin-left: calc(-1ex - 1px); + } -.tracy-light div.tracy-dump-string:before { - content: ''; - position: absolute; - left: calc(3ex - 1px); - top: 1.5em; - bottom: 0; - border-left: 1px solid rgba(0, 0, 0, .1); -} + & div.tracy-dump-string:before { + content: ''; + position: absolute; + left: calc(3ex - 1px); + top: 1.5em; + bottom: 0; + border-left: 1px solid rgba(0, 0, 0, .1); + } -.tracy-light .tracy-dump-virtual span, -.tracy-light .tracy-dump-dynamic span, -.tracy-light .tracy-dump-string span { - color: rgba(0, 0, 0, 0.5); -} + .tracy-dump-virtual span, + .tracy-dump-dynamic span, + .tracy-dump-string span { + color: rgba(0, 0, 0, 0.5); + } -.tracy-light .tracy-dump-virtual i, -.tracy-light .tracy-dump-dynamic i, -.tracy-light .tracy-dump-string i { - font-size: 80%; - font-style: normal; - color: rgba(0, 0, 0, 0.5); - user-select: none; -} + .tracy-dump-virtual i, + .tracy-dump-dynamic i, + .tracy-dump-string i { + font-size: 80%; + font-style: normal; + color: rgba(0, 0, 0, 0.5); + user-select: none; + } -.tracy-light .tracy-dump-number { - color: #090; -} + .tracy-dump-number { + color: #090; + } -.tracy-light .tracy-dump-null, -.tracy-light .tracy-dump-bool { - color: #850; -} + .tracy-dump-null, + .tracy-dump-bool { + color: #850; + } -.tracy-light .tracy-dump-virtual { - font-style: italic; -} + .tracy-dump-virtual { + font-style: italic; + } -.tracy-light .tracy-dump-public::after { - content: ' pub'; -} + .tracy-dump-public::after { + content: ' pub'; + } -.tracy-light .tracy-dump-protected::after { - content: ' pro'; -} + .tracy-dump-protected::after { + content: ' pro'; + } -.tracy-light .tracy-dump-private::after { - content: ' pri'; -} + .tracy-dump-private::after { + content: ' pri'; + } -.tracy-light .tracy-dump-public::after, -.tracy-light .tracy-dump-protected::after, -.tracy-light .tracy-dump-private::after, -.tracy-light .tracy-dump-hash { - font-size: 85%; - color: rgba(0, 0, 0, 0.35); -} + .tracy-dump-public::after, + .tracy-dump-protected::after, + .tracy-dump-private::after, + .tracy-dump-hash { + font-size: 85%; + color: rgba(0, 0, 0, 0.35); + } -.tracy-light .tracy-dump-indent { - display: none; -} + .tracy-dump-indent { + display: none; + } -.tracy-light .tracy-dump-highlight { - background: #C22; - color: white; - border-radius: 2px; - padding: 0 2px; - margin: 0 -2px; -} + .tracy-dump-highlight { + background: #C22; + color: white; + border-radius: 2px; + padding: 0 2px; + margin: 0 -2px; + } -span[data-tracy-href] { - border-bottom: 1px dotted rgba(0, 0, 0, .2); -} + span[data-tracy-href] { + border-bottom: 1px dotted rgba(0, 0, 0, .2); + } -.tracy-light .tracy-dump-flash { - animation: tracy-dump-flash .2s ease; -} + .tracy-dump-flash { + animation: tracy-dump-flash .2s ease; + } -@keyframes tracy-dump-flash { - 0% { - background: #c0c0c033; + @keyframes tracy-dump-flash { + 0% { + background: #c0c0c033; + } } } diff --git a/src/Tracy/Helpers.php b/src/Tracy/Helpers.php index ff00284f5..4116d7472 100644 --- a/src/Tracy/Helpers.php +++ b/src/Tracy/Helpers.php @@ -91,6 +91,12 @@ public static function escapeHtml(mixed $s): string } + public static function htmlToText(string $s): string + { + return htmlspecialchars_decode(strip_tags($s), ENT_QUOTES | ENT_HTML5); + } + + public static function findTrace(array $trace, array|string $method, ?int &$index = null): ?array { $m = is_array($method) ? $method : explode('::', $method); @@ -451,9 +457,9 @@ public static function isUtf8(string $s): bool /** @internal */ - public static function truncateString(string $s, int $len, bool $utf): string + public static function truncateString(string $s, int $len, bool $utf8): string { - if (!$utf) { + if (!$utf8) { return $len < 0 ? substr($s, $len) : substr($s, 0, $len); } elseif (function_exists('mb_substr')) { return $len < 0 @@ -468,6 +474,28 @@ public static function truncateString(string $s, int $len, bool $utf): string } + /** @internal */ + public static function htmlToAnsi(string $s, array $colors): string + { + $stack = ['0']; + $s = preg_replace_callback( + '#<\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[" . end($stack) . 'm'; + }, + $s, + ); + $s = preg_replace('/\e\[0m( *)(?=\e)/', '$1', $s); + $s = self::htmlToText($s); + return $s; + } + + /** @internal */ public static function minifyJs(string $s): string { @@ -516,6 +544,7 @@ function ($match) use (&$last) { /** @internal */ public static function minifyCss(string $s): string { + return $s; $last = ''; return preg_replace_callback( <<<'XX' diff --git a/src/Tracy/Logger/Logger.php b/src/Tracy/Logger/Logger.php index 4ef677798..7c9e65bc5 100644 --- a/src/Tracy/Logger/Logger.php +++ b/src/Tracy/Logger/Logger.php @@ -15,23 +15,22 @@ */ class Logger implements ILogger { - /** @var string|null name of the directory where errors should be logged */ - public $directory; + /** name of the directory where errors should be logged */ + public ?string $directory = null; - /** @var string|array|null email or emails to which send error notifications */ - public $email; + /** email or emails to which send error notifications */ + public string|array|null $email = null; - /** @var string|null sender of email notifications */ - public $fromEmail; + /** sender of email notifications */ + public ?string $fromEmail = null; - /** @var mixed interval for sending email is 2 days */ - public $emailSnooze = '2 days'; + /** interval for sending email is 2 days */ + public mixed $emailSnooze = '2 days'; /** @var callable handler for sending emails */ public $mailer; - /** @var BlueScreen|null */ - private $blueScreen; + private ?BlueScreen $blueScreen = null; public function __construct(?string $directory, string|array|null $email = null, ?BlueScreen $blueScreen = null) @@ -78,10 +77,7 @@ public function log(mixed $message, string $level = self::INFO) } - /** - * @param mixed $message - */ - public static function formatMessage($message): string + public static function formatMessage(mixed $message): string { if ($message instanceof \Throwable) { foreach (Helpers::getExceptionChain($message) as $exception) { @@ -101,10 +97,7 @@ public static function formatMessage($message): string } - /** - * @param mixed $message - */ - public static function formatLogLine($message, ?string $exceptionFile = null): string + public static function formatLogLine(mixed $message, ?string $exceptionFile = null): string { return implode(' ', [ date('[Y-m-d H-i-s]'), @@ -152,10 +145,7 @@ protected function logException(\Throwable $exception, ?string $file = null): st } - /** - * @param mixed $message - */ - protected function sendEmail($message): void + protected function sendEmail(mixed $message): void { $snooze = is_numeric($this->emailSnooze) ? $this->emailSnooze @@ -174,10 +164,9 @@ protected function sendEmail($message): void /** * Default mailer. - * @param mixed $message * @internal */ - public function defaultMailer($message, string $email): void + public function defaultMailer(mixed $message, string $email): void { $host = preg_replace('#[^\w.-]+#', '', $_SERVER['SERVER_NAME'] ?? php_uname('n')); $parts = str_replace( diff --git a/src/Tracy/assets/reset.css b/src/Tracy/assets/reset.css index e333f841e..a31a6846c 100644 --- a/src/Tracy/assets/reset.css +++ b/src/Tracy/assets/reset.css @@ -2,375 +2,385 @@ * This file is part of the Tracy (https://tracy.nette.org) */ -tracy-div:not(a b), -tracy-div:not(a b) * { - font: inherit; - line-height: inherit; - color: inherit; - background: transparent; - margin: 0; - padding: 0; - border: none; - text-align: inherit; - list-style: inherit; - opacity: 1; - border-radius: 0; - box-shadow: none; - text-shadow: none; - box-sizing: border-box; - text-decoration: none; - text-transform: inherit; - white-space: inherit; - float: none; - clear: none; - max-width: initial; - min-width: initial; - max-height: initial; - min-height: initial; -} - -tracy-div:not(a b) *:hover { - color: inherit; - background: transparent; -} - -tracy-div:not(a b) *:not(svg):not(img):not(table) { - width: initial; - height: initial; -} - -tracy-div:not(a b):before, -tracy-div:not(a b):after, -tracy-div:not(a b) *:before, -tracy-div:not(a b) *:after { - all: unset; -} - -tracy-div:not(a b) b, -tracy-div:not(a b) strong { - font-weight: bold; -} - -tracy-div:not(a b) small { - font-size: smaller; -} - -tracy-div:not(a b) i, -tracy-div:not(a b) em { - font-style: italic; -} - -tracy-div:not(a b) big { - font-size: larger; -} - -tracy-div:not(a b) small, -tracy-div:not(a b) sub, -tracy-div:not(a b) sup { - font-size: smaller; -} - -tracy-div:not(a b) ins { - text-decoration: underline; -} - -tracy-div:not(a b) del { - text-decoration: line-through; -} - -tracy-div:not(a b) table { - border-collapse: collapse; -} - -tracy-div:not(a b) pre { - font-family: monospace; - white-space: pre; -} - -tracy-div:not(a b) code, -tracy-div:not(a b) kbd, -tracy-div:not(a b) samp { - font-family: monospace; -} - -tracy-div:not(a b) input { - background-color: white; - padding: 1px; - border: 1px solid; -} - -tracy-div:not(a b) textarea { - background-color: white; - border: 1px solid; - padding: 2px; - white-space: pre-wrap; -} - -tracy-div:not(a b) select { - border: 1px solid; - white-space: pre; -} - -tracy-div:not(a b) article, -tracy-div:not(a b) aside, -tracy-div:not(a b) details, -tracy-div:not(a b) div, -tracy-div:not(a b) figcaption, -tracy-div:not(a b) footer, -tracy-div:not(a b) form, -tracy-div:not(a b) header, -tracy-div:not(a b) hgroup, -tracy-div:not(a b) main, -tracy-div:not(a b) nav, -tracy-div:not(a b) section, -tracy-div:not(a b) summary, -tracy-div:not(a b) pre, -tracy-div:not(a b) p, -tracy-div:not(a b) dl, -tracy-div:not(a b) dd, -tracy-div:not(a b) dt, -tracy-div:not(a b) blockquote, -tracy-div:not(a b) figure, -tracy-div:not(a b) address, -tracy-div:not(a b) h1, -tracy-div:not(a b) h2, -tracy-div:not(a b) h3, -tracy-div:not(a b) h4, -tracy-div:not(a b) h5, -tracy-div:not(a b) h6, -tracy-div:not(a b) ul, -tracy-div:not(a b) ol, -tracy-div:not(a b) li, -tracy-div:not(a b) hr { - display: block; -} - -tracy-div:not(a b) a, -tracy-div:not(a b) b, -tracy-div:not(a b) big, -tracy-div:not(a b) code, -tracy-div:not(a b) em, -tracy-div:not(a b) i, -tracy-div:not(a b) small, -tracy-div:not(a b) span, -tracy-div:not(a b) strong { - display: inline; -} - -tracy-div:not(a b) table { - display: table; -} - -tracy-div:not(a b) tr { - display: table-row; -} - -tracy-div:not(a b) col { - display: table-column; -} - -tracy-div:not(a b) colgroup { - display: table-column-group; -} - -tracy-div:not(a b) tbody { - display: table-row-group; -} - -tracy-div:not(a b) thead { - display: table-header-group; -} - -tracy-div:not(a b) tfoot { - display: table-footer-group; -} - -tracy-div:not(a b) td { - display: table-cell; -} - -tracy-div:not(a b) th { - display: table-cell; -} - - - -/* TableSort */ -tracy-div:not(a b) .tracy-sortable > :first-child > tr:first-child > * { - position: relative; -} - -tracy-div:not(a b) .tracy-sortable > :first-child > tr:first-child > *:hover:before { - position: absolute; - right: .3em; - content: "\21C5"; - opacity: .4; - font-weight: normal; -} - - -/* dump */ -tracy-div:not(a b) .tracy-dump div { - padding-left: 3ex; -} - -tracy-div:not(a b) .tracy-dump div div { - border-left: 1px solid rgba(0, 0, 0, .1); - margin-left: .5ex; -} - -tracy-div:not(a b) .tracy-dump div div:hover { - border-left-color: rgba(0, 0, 0, .25); -} - -tracy-div:not(a b) .tracy-dump { - background: #FDF5CE; - padding: .4em .7em; - border: 1px dotted silver; - overflow: auto; -} - -tracy-div:not(a b) table .tracy-dump.tracy-dump { /* overwrite .tracy-dump.tracy-light etc. */ - padding: 0; - margin: 0; - border: none; -} - -tracy-div:not(a b) .tracy-dump-location { - color: gray; - font-size: 80%; - text-decoration: none; - background: none; - opacity: .5; - float: right; - cursor: pointer; -} - -tracy-div:not(a b) .tracy-dump-location:hover, -tracy-div:not(a b) .tracy-dump-location:focus { - color: gray; - background: none; - opacity: 1; -} - -tracy-div:not(a b) .tracy-dump-array, -tracy-div:not(a b) .tracy-dump-object { - color: #C22; -} - -tracy-div:not(a b) .tracy-dump-string { - color: #35D; - white-space: break-spaces; -} - -tracy-div:not(a b) div.tracy-dump-string { - position: relative; - padding-left: 3.5ex; -} - -tracy-div:not(a b) .tracy-dump-lq { - margin-left: calc(-1ex - 1px); -} - -tracy-div:not(a b) div.tracy-dump-string:before { - content: ''; - position: absolute; - left: calc(3ex - 1px); - top: 1.5em; - bottom: 0; - border-left: 1px solid rgba(0, 0, 0, .1); -} - -tracy-div:not(a b) .tracy-dump-virtual span, -tracy-div:not(a b) .tracy-dump-dynamic span, -tracy-div:not(a b) .tracy-dump-string span { - color: rgba(0, 0, 0, 0.5); -} - -tracy-div:not(a b) .tracy-dump-virtual i, -tracy-div:not(a b) .tracy-dump-dynamic i, -tracy-div:not(a b) .tracy-dump-string i { - font-size: 80%; - font-style: normal; - color: rgba(0, 0, 0, 0.5); - user-select: none; -} - -tracy-div:not(a b) .tracy-dump-number { - color: #090; -} - -tracy-div:not(a b) .tracy-dump-null, -tracy-div:not(a b) .tracy-dump-bool { - color: #850; -} - -tracy-div:not(a b) .tracy-dump-virtual { - font-style: italic; -} - -tracy-div:not(a b) .tracy-dump-public::after { - content: ' pub'; -} - -tracy-div:not(a b) .tracy-dump-protected::after { - content: ' pro'; -} - -tracy-div:not(a b) .tracy-dump-private::after { - content: ' pri'; -} - -tracy-div:not(a b) .tracy-dump-public::after, -tracy-div:not(a b) .tracy-dump-protected::after, -tracy-div:not(a b) .tracy-dump-private::after, -tracy-div:not(a b) .tracy-dump-hash { - font-size: 85%; - color: rgba(0, 0, 0, 0.5); -} - -tracy-div:not(a b) .tracy-dump-indent { - display: none; -} - -tracy-div:not(a b) .tracy-dump-highlight { - background: #C22; - color: white; - border-radius: 2px; - padding: 0 2px; - margin: 0 -2px; -} - -tracy-div:not(a b) span[data-tracy-href] { - border-bottom: 1px dotted rgba(0, 0, 0, .2); -} - - -/* toggle */ -tracy-div:not(a b) .tracy-toggle:after { - content: ''; - display: inline-block; - vertical-align: middle; - line-height: 0; - border-top: .6ex solid; - border-right: .6ex solid transparent; - border-left: .6ex solid transparent; - transform: scale(1, 1.5); - margin: 0 .2ex 0 .7ex; - transition: .1s transform; - opacity: .5; -} - -tracy-div:not(a b) .tracy-toggle.tracy-collapsed:after { - transform: rotate(-90deg) scale(1, 1.5) translate(.1ex, 0); -} - - -/* tabs */ -tracy-div:not(a b) .tracy-tab-label { - user-select: none; -} - -tracy-div:not(a b) .tracy-tab-panel:not(.tracy-active) { - display: none; +tracy-div:not(a b) { + :is(&, & *) { + font: inherit; + line-height: inherit; + color: inherit; + background: transparent; + margin: 0; + padding: 0; + border: none; + text-align: inherit; + list-style: inherit; + opacity: 1; + border-radius: 0; + box-shadow: none; + text-shadow: none; + box-sizing: border-box; + text-decoration: none; + text-transform: inherit; + white-space: inherit; + float: none; + clear: none; + max-width: initial; + min-width: initial; + max-height: initial; + min-height: initial; + } + + *:hover { + color: inherit; + background: transparent; + } + + *:not(svg):not(img):not(table) { + width: initial; + height: initial; + } + + &:before, + &:after, + *:before, + *:after { + all: unset; + } + + :is( + h1, h2, h3, h4, h5, h6, + p, + ol, ul, dl, + pre, table, hr, + ):where(:not(:last-child)) { + margin-bottom: var(--tracy-space); + } + + & b, + & strong { + font-weight: bold; + } + + & small { + font-size: smaller; + } + + & i, + & em { + font-style: italic; + } + + & big { + font-size: larger; + } + + & small, + & sub, + & sup { + font-size: smaller; + } + + & ins { + text-decoration: underline; + } + + & del { + text-decoration: line-through; + } + + & table { + border-collapse: collapse; + } + + & pre { + font-family: monospace; + white-space: pre; + } + + & code, + & kbd, + & samp { + font-family: monospace; + } + + & input { + background-color: white; + padding: 1px; + border: 1px solid; + } + + & textarea { + background-color: white; + border: 1px solid; + padding: 2px; + white-space: pre-wrap; + } + + & select { + border: 1px solid; + white-space: pre; + } + + & article, + & aside, + & details, + & div, + & figcaption, + & footer, + & form, + & header, + & hgroup, + & main, + & nav, + & section, + & summary, + & pre, + & p, + & dl, + & dd, + & dt, + & blockquote, + & figure, + & address, + & h1, + & h2, + & h3, + & h4, + & h5, + & h6, + & ul, + & ol, + & li, + & hr { + display: block; + } + + & a, + & b, + & big, + & code, + & em, + & i, + & small, + & span, + & strong { + display: inline; + } + + & table { + display: table; + } + + & tr { + display: table-row; + } + + & col { + display: table-column; + } + + & colgroup { + display: table-column-group; + } + + & tbody { + display: table-row-group; + } + + & thead { + display: table-header-group; + } + + & tfoot { + display: table-footer-group; + } + + & td { + display: table-cell; + } + + & th { + display: table-cell; + } + + + + /* TableSort */ + .tracy-sortable > :first-child > tr:first-child > * { + position: relative; + } + + .tracy-sortable > :first-child > tr:first-child > *:hover:before { + position: absolute; + right: .3em; + content: "\21C5"; + opacity: .4; + font-weight: normal; + } + + + /* dump */ + .tracy-dump div { + padding-left: 3ex; + } + + .tracy-dump div div { + border-left: 1px solid rgba(0, 0, 0, .1); + margin-left: .5ex; + } + + .tracy-dump div div:hover { + border-left-color: rgba(0, 0, 0, .25); + } + + .tracy-dump { + background: #FDF5CE; + padding: .4em .7em; + border: 1px dotted silver; + overflow: auto; + } + + & table .tracy-dump.tracy-dump { /* overwrite .tracy-dump.tracy-light etc. */ + padding: 0; + margin: 0; + border: none; + } + + .tracy-dump-location { + color: gray; + font-size: 80%; + text-decoration: none; + background: none; + opacity: .5; + float: right; + cursor: pointer; + } + + .tracy-dump-location:hover, + .tracy-dump-location:focus { + color: gray; + background: none; + opacity: 1; + } + + .tracy-dump-array, + .tracy-dump-object { + color: #C22; + } + + .tracy-dump-string { + color: #35D; + white-space: break-spaces; + } + + & div.tracy-dump-string { + position: relative; + padding-left: 3.5ex; + } + + .tracy-dump-lq { + margin-left: calc(-1ex - 1px); + } + + & div.tracy-dump-string:before { + content: ''; + position: absolute; + left: calc(3ex - 1px); + top: 1.5em; + bottom: 0; + border-left: 1px solid rgba(0, 0, 0, .1); + } + + .tracy-dump-virtual span, + .tracy-dump-dynamic span, + .tracy-dump-string span { + color: rgba(0, 0, 0, 0.5); + } + + .tracy-dump-virtual i, + .tracy-dump-dynamic i, + .tracy-dump-string i { + font-size: 80%; + font-style: normal; + color: rgba(0, 0, 0, 0.5); + user-select: none; + } + + .tracy-dump-number { + color: #090; + } + + .tracy-dump-null, + .tracy-dump-bool { + color: #850; + } + + .tracy-dump-virtual { + font-style: italic; + } + + .tracy-dump-public::after { + content: ' pub'; + } + + .tracy-dump-protected::after { + content: ' pro'; + } + + .tracy-dump-private::after { + content: ' pri'; + } + + .tracy-dump-public::after, + .tracy-dump-protected::after, + .tracy-dump-private::after, + .tracy-dump-hash { + font-size: 85%; + color: rgba(0, 0, 0, 0.5); + } + + .tracy-dump-indent { + display: none; + } + + .tracy-dump-highlight { + background: #C22; + color: white; + border-radius: 2px; + padding: 0 2px; + margin: 0 -2px; + } + + & span[data-tracy-href] { + border-bottom: 1px dotted rgba(0, 0, 0, .2); + } + + + /* toggle */ + .tracy-toggle:after { + content: ''; + display: inline-block; + vertical-align: middle; + line-height: 0; + border-top: .6ex solid; + border-right: .6ex solid transparent; + border-left: .6ex solid transparent; + transform: scale(1, 1.5); + margin: 0 .2ex 0 .7ex; + transition: .1s transform; + opacity: .5; + } + + .tracy-toggle.tracy-collapsed:after { + transform: rotate(-90deg) scale(1, 1.5) translate(.1ex, 0); + } + + + /* tabs */ + .tracy-tab-label { + user-select: none; + } + + .tracy-tab-panel:not(.tracy-active) { + display: none; + } } diff --git a/tests/Tracy/Debugger.dump().cli.phpt b/tests/Tracy/Debugger.dump().cli.phpt index a4842b5eb..c920bec4b 100644 --- a/tests/Tracy/Debugger.dump().cli.phpt +++ b/tests/Tracy/Debugger.dump().cli.phpt @@ -23,7 +23,7 @@ test('production mode', function () { Debugger::dump('sensitive data'); Assert::same('', ob_get_clean()); - Assert::match("'forced'", Debugger::dump('forced', true)); + Assert::match("'forced'", Debugger::dump('forced', return: true)); }); @@ -34,7 +34,7 @@ test('development mode', function () { Debugger::dump('sensitive data'); Assert::match('', ob_get_clean()); // is dumped to stout - Assert::match("'forced'", Debugger::dump('forced', true)); + Assert::match("'forced'", Debugger::dump('forced', return: true)); }); diff --git a/tests/Tracy/Debugger.dump().phpt b/tests/Tracy/Debugger.dump().phpt index 58983641e..77ce490a8 100644 --- a/tests/Tracy/Debugger.dump().phpt +++ b/tests/Tracy/Debugger.dump().phpt @@ -26,7 +26,7 @@ test('production mode', function () { Debugger::dump('sensitive data'); Assert::same('', ob_get_clean()); - Assert::match("'forced'", Debugger::dump('forced', true)); + Assert::match("'forced'", Debugger::dump('forced', return: true)); }); @@ -38,7 +38,7 @@ test('development mode', function () { Assert::match("'sensitive data' ", ob_get_clean()); - Assert::match("'forced'", Debugger::dump('forced', true)); + Assert::match("'forced'", Debugger::dump('forced', return: true)); }); diff --git a/tests/Tracy/Dumper.keys.phpt b/tests/Tracy/Dumper.keys.phpt index 23a4e72c9..fed6efc4e 100644 --- a/tests/Tracy/Dumper.keys.phpt +++ b/tests/Tracy/Dumper.keys.phpt @@ -90,4 +90,4 @@ Assert::equal([ [['string' => '<a> &', 'length' => 9], 0, 3], ], ], -], array_values(json_decode(explode("'", Dumper::formatSnapshotAttribute($snapshot))[1], true))); +], array_values(json_decode(explode("'", Dumper::formatSnapshotAttribute($snapshot))[1], associative: true))); diff --git a/tests/Tracy/Dumper.keysToHide.phpt b/tests/Tracy/Dumper.keysToHide.phpt index 613d884c3..5306495c6 100644 --- a/tests/Tracy/Dumper.keysToHide.phpt +++ b/tests/Tracy/Dumper.keysToHide.phpt @@ -65,4 +65,4 @@ Assert::equal([ ], ], ], -], array_values(json_decode(explode("'", Dumper::formatSnapshotAttribute($snapshot))[1], true))); +], array_values(json_decode(explode("'", Dumper::formatSnapshotAttribute($snapshot))[1], associative: true))); diff --git a/tests/Tracy/Dumper.toHtml().live.phpt b/tests/Tracy/Dumper.toHtml().live.phpt index 25e946304..bb3ee9567 100644 --- a/tests/Tracy/Dumper.toHtml().live.phpt +++ b/tests/Tracy/Dumper.toHtml().live.phpt @@ -16,7 +16,7 @@ require __DIR__ . '/fixtures/DumpClass.php'; function formatSnapshot(): array { - return json_decode(explode("'", Dumper::formatSnapshotAttribute(Dumper::$liveSnapshot))[1], true); + return json_decode(explode("'", Dumper::formatSnapshotAttribute(Dumper::$liveSnapshot))[1], associative: true); } diff --git a/tests/Tracy/Dumper.toTerminal().phpt b/tests/Tracy/Dumper.toTerminal().phpt index 18365fe16..7392e4a27 100644 --- a/tests/Tracy/Dumper.toTerminal().phpt +++ b/tests/Tracy/Dumper.toTerminal().phpt @@ -18,13 +18,13 @@ Assert::match("\e[1;33mnull\e[0m", Dumper::toTerminal(null)); Assert::match( <<$html
File: %a%
-%d%: +
+%d%: define('MY_CONST', 123); +%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%: throw new Exception('The my exception', 123); +%d%: } %d%: %d%: -%d%: define('MY_CONST', 123); -
%d%: +
+%d%: function third($arg1) +%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%: third([1, 2, 3]); +%d%: } %d%: %d%: -%d%: function third($arg1) -
$arg1 |
@@ -99,22 +99,22 @@
-
|
---|