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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
php-version: 8.1
coverage: none

- run: composer install --no-progress --prefer-dist
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
php: ['8.0', '8.1', '8.2', '8.3', '8.4']
php: ['8.1', '8.2', '8.3', '8.4', '8.5']
sapi: ['php', 'php-cgi']

fail-fast: false
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
php-version: 8.1
extensions: ds
coverage: none

Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}
],
"require": {
"php": "8.0 - 8.4",
"php": "8.1 - 8.5",
"ext-session": "*",
"ext-json": "*"
},
Expand Down Expand Up @@ -46,7 +46,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.10-dev"
"dev-master": "3.0-dev"
}
}
}
47 changes: 13 additions & 34 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,19 @@
import globals from 'globals';
import pluginJs from '@eslint/js';
import stylistic from '@stylistic/eslint-plugin';
import nette from '@nette/eslint-plugin';
import { defineConfig } from 'eslint/config';

export default [
export default defineConfig([
{
ignores: ['*/', '!src/'],
ignores: [
'vendor', 'tests', 'x',
],
},

pluginJs.configs.recommended,

stylistic.configs.customize({
indent: 'tab',
braceStyle: '1tbs',
arrowParens: true,
semi: true,
jsx: false,
}),

{
languageOptions: {
ecmaVersion: 'latest',
globals: globals.browser,
},
plugins: {
'@stylistic': stylistic,
},
rules: {
'@stylistic/no-multiple-empty-lines': ['error', { max: 2, maxEOF: 0 }],
'@stylistic/new-parens': ['error', 'never'],
'@stylistic/padded-blocks': 'off',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
'prefer-arrow-callback': 'error',
'arrow-body-style': 'error',
'eqeqeq': ['error', 'always', { null: 'ignore' }],
'no-var': 'error',
'prefer-const': 'off',
},
files: [
'*.js',
'src/**/*.js',
],

extends: [nette.configs.recommended],
},
];
]);
10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
{
"type": "module",
"devDependencies": {
"@eslint/js": "^9.4.0",
"@stylistic/eslint-plugin": "^2.1.0",
"eslint": "^9.4.0",
"globals": "^15.3.0"
"@nette/eslint-plugin": "^0.2",
"eslint": "^9.26.0"
},
"scripts": {
"lint": "eslint",
"lint:fix": "eslint --fix"
"lint": "eslint --cache",
"lint:fix": "eslint --cache --fix"
}
}
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ composer require tracy/tracy

Alternatively, you can download the whole package or [tracy.phar](https://github.com/nette/tracy/releases) file.

Tracy is compatible with PHP 8.0 to 8.4.
Tracy is compatible with PHP 8.1 to 8.5.

 <!---->

Expand Down Expand Up @@ -456,5 +456,6 @@ This is a list of unofficial integrations to other frameworks and CMS:
- [Slim Framework](https://github.com/runcmf/runtracy)
- Symfony framework: [kutny/tracy-bundle](https://github.com/kutny/tracy-bundle), [VasekPurchart/Tracy-Blue-Screen-Bundle](https://github.com/VasekPurchart/Tracy-Blue-Screen-Bundle)
- [Wordpress](https://github.com/ktstudio/WP-Tracy)
- [Joomla! CMS](https://n3t.bitbucket.io/extension/n3t-debug/)

... feel free to be famous, create an integration for your favourite platform!
73 changes: 2 additions & 71 deletions src/Bridges/Nette/Bridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,95 +9,26 @@

namespace Tracy\Bridges\Nette;

use Latte;
use Nette;
use Tracy;
use Tracy\BlueScreen;
use Tracy\Helpers;
use const ENT_IGNORE;


/**
* Bridge for NEON & Latte.
* Bridge for Utils & 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)
? ''
: '<p>'
. (@is_file($e->sourceName) // @ - may trigger error
? '<b>File:</b> ' . Helpers::editorLink($e->sourceName, $e->sourceLine)
: '<b>' . htmlspecialchars($e->sourceName . ($e->sourceLine ? ':' . $e->sourceLine : '')) . '</b>')
. '</p>')
. BlueScreen::highlightFile($e->sourceCode, $e->sourceLine, php: 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) {
Expand Down
3 changes: 2 additions & 1 deletion src/Bridges/Nette/TracyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Nette\DI\Definitions\Statement;
use Nette\Schema\Expect;
use Tracy;
use function is_array, is_string;


/**
Expand Down Expand Up @@ -130,7 +131,7 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class): void
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);
}
Expand Down
1 change: 1 addition & 0 deletions src/Bridges/Psr/PsrToTracyLoggerAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use Psr;
use Tracy;
use function is_string;


/**
Expand Down
2 changes: 2 additions & 0 deletions src/Tracy/Bar/Bar.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

namespace Tracy;

use function count;


/**
* Debug Bar.
Expand Down
6 changes: 3 additions & 3 deletions src/Tracy/Bar/assets/bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ class Panel {

let meta = this.elem.parentElement.lastElementChild;
doc.body.innerHTML = '<tracy-div itemscope>'
+ '<div class="tracy-panel tracy-mode-window" id="' + this.elem.id + '">' + this.elem.tracyContent + '</div>'
+ meta.outerHTML
+ '</tracy-div>';
+ '<div class="tracy-panel tracy-mode-window" id="' + this.elem.id + '">' + this.elem.tracyContent + '</div>'
+ meta.outerHTML
+ '</tracy-div>';
evalScripts(doc.body);
if (this.elem.querySelector('h1')) {
doc.title = this.elem.querySelector('h1').textContent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (empty($data)) {
}
?>
<style class="tracy-debug">
#tracy-debug .tracy-ErrorTab {
#tracy-debug .tracy-WarningsTab {
display: block;
background: #D51616;
color: white;
Expand All @@ -19,7 +19,7 @@ if (empty($data)) {
padding: 1px .4em;
}
</style>
<span class="tracy-ErrorTab">
<span class="tracy-WarningsTab">
<svg viewBox="0 0 2048 2048"><path fill="#fff" d="M1152 1503v-190q0-14-9.5-23.5t-22.5-9.5h-192q-13 0-22.5 9.5t-9.5 23.5v190q0 14 9.5 23.5t22.5 9.5h192q13 0 22.5-9.5t9.5-23.5zm-2-374l18-459q0-12-10-19-13-11-24-11h-220q-11 0-24 11-10 7-10 21l17 457q0 10 10 16.5t24 6.5h185q14 0 23.5-6.5t10.5-16.5zm-14-934l768 1408q35 63-2 126-17 29-46.5 46t-63.5 17h-1536q-34 0-63.5-17t-46.5-46q-37-63-2-126l768-1408q17-31 47-49t65-18 65 18 47 49z"/>
</svg><span class="tracy-label"><?= $sum = array_sum($data), $sum > 1 ? ' warnings' : ' warning' ?></span>
</span>
15 changes: 13 additions & 2 deletions src/Tracy/BlueScreen/BlueScreen.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace Tracy;

use function in_array, strlen;
use const ARRAY_FILTER_USE_KEY, ENT_IGNORE;


/**
* Red BlueScreen.
Expand Down Expand Up @@ -131,7 +134,10 @@ 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);
ob_start(function ($buffer) use ($handle) {
fwrite($handle, $buffer);
return '';
}, 4096);
$this->renderTemplate($exception, __DIR__ . '/assets/page.phtml', toScreen: false);
ob_end_flush();
ob_end_clean();
Expand Down Expand Up @@ -483,7 +489,12 @@ private function findGeneratorsAndFibers(object $object): array
$add = function ($obj) use (&$generators, &$fibers) {
if ($obj instanceof \Generator) {
try {
new \ReflectionGenerator($obj);
$ref = new \ReflectionGenerator($obj);
// Before PHP 8.4 the ReflectionGenerator cannot be constructed from closed generator.
// Since PHP 8.4 it can, but getTrace throws ReflectionException.
if (PHP_VERSION_ID >= 80400 && $ref->isClosed()) {
return;
}
$generators[spl_object_id($obj)] = $obj;
} catch (\ReflectionException) {
}
Expand Down
3 changes: 3 additions & 0 deletions src/Tracy/BlueScreen/CodeHighlighter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

namespace Tracy;

use function array_pop, array_shift, array_unshift, count, explode, floor, implode, max, min, preg_replace, preg_replace_callback, rtrim, sprintf, str_replace, strip_tags, strlen, strtr;
use const T_CLASS_C, T_CLOSE_TAG, T_COMMENT, T_CONSTANT_ENCAPSED_STRING, T_DIR, T_DNUMBER, T_DOC_COMMENT, T_ENCAPSED_AND_WHITESPACE, T_FILE, T_FUNC_C, T_INLINE_HTML, T_LINE, T_LNUMBER, T_METHOD_C, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE, T_NS_C, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_STRING, T_TRAIT_C, T_VARIABLE, T_WHITESPACE;


/** @internal */
final class CodeHighlighter
Expand Down
16 changes: 9 additions & 7 deletions src/Tracy/Debugger/Debugger.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
namespace Tracy;

use ErrorException;
use function in_array, is_bool, is_int, is_string;
use const PHP_VERSION;


/**
* Debugger: displays and logs errors.
*/
class Debugger
{
public const Version = '2.10.10';
public const Version = '3.0-dev';

/** server modes for Debugger::enable() */
public const
Expand All @@ -27,19 +29,19 @@ class Debugger

public const CookieSecret = 'tracy-debug';

/** @deprecated use Debugger::Version */
#[\Deprecated('use Debugger::Version')]
public const VERSION = self::Version;

/** @deprecated use Debugger::Development */
#[\Deprecated('use Debugger::Development')]
public const DEVELOPMENT = self::Development;

/** @deprecated use Debugger::Production */
#[\Deprecated('use Debugger::Production')]
public const PRODUCTION = self::Production;

/** @deprecated use Debugger::Detect */
#[\Deprecated('use Debugger::Detect')]
public const DETECT = self::Detect;

/** @deprecated use Debugger::CookieSecret */
#[\Deprecated('use Debugger::CookieSecret')]
public const COOKIE_SECRET = self::CookieSecret;

/** in production mode is suppressed any debugging output */
Expand Down Expand Up @@ -408,7 +410,7 @@ public static function getBar(): Bar
self::$bar = new Bar;
self::$bar->addPanel($info = new DefaultBarPanel('info'), 'Tracy:info');
$info->cpuUsage = self::$cpuUsage;
self::$bar->addPanel(new DefaultBarPanel('errors'), 'Tracy:errors'); // filled by errorHandler()
self::$bar->addPanel(new DefaultBarPanel('warnings'), 'Tracy:warnings'); // filled by errorHandler()
}

return self::$bar;
Expand Down
Loading