1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Tracy\Bridges\Nette;
9:
10: use Latte;
11: use Nette;
12: use Tracy;
13: use Tracy\BlueScreen;
14: use Tracy\Helpers;
15:
16:
17: 18: 19:
20: class Bridge
21: {
22: public static function initialize()
23: {
24: $blueScreen = Tracy\Debugger::getBlueScreen();
25: $blueScreen->addPanel([__CLASS__, 'renderLatteError']);
26: $blueScreen->addAction([__CLASS__, 'renderLatteUnknownMacro']);
27: $blueScreen->addAction([__CLASS__, 'renderMemberAccessException']);
28: $blueScreen->addPanel([__CLASS__, 'renderNeonError']);
29: }
30:
31:
32: public static function renderLatteError($e)
33: {
34: if (!$e instanceof Latte\CompileException) {
35: return null;
36: }
37: return [
38: 'tab' => 'Template',
39: 'panel' => (preg_match('#\n|\?#', $e->sourceName)
40: ? ''
41: : '<p>'
42: . (@is_file($e->sourceName)
43: ? '<b>File:</b> ' . Helpers::editorLink($e->sourceName, $e->sourceLine)
44: : '<b>' . htmlspecialchars($e->sourceName . ($e->sourceLine ? ':' . $e->sourceLine : '')) . '</b>')
45: . '</p>')
46: . '<pre class=code><div>'
47: . BlueScreen::highlightLine(htmlspecialchars($e->sourceCode, ENT_IGNORE, 'UTF-8'), $e->sourceLine)
48: . '</div></pre>',
49: ];
50: }
51:
52:
53: public static function renderLatteUnknownMacro($e)
54: {
55: if (
56: $e instanceof Latte\CompileException
57: && @is_file($e->sourceName)
58: && (preg_match('#Unknown macro (\{\w+)\}, did you mean (\{\w+)\}\?#A', $e->getMessage(), $m)
59: || preg_match('#Unknown attribute (n:\w+), did you mean (n:\w+)\?#A', $e->getMessage(), $m))
60: ) {
61: return [
62: 'link' => Helpers::editorUri($e->sourceName, $e->sourceLine, 'fix', $m[1], $m[2]),
63: 'label' => 'fix it',
64: ];
65: }
66: return null;
67: }
68:
69:
70: public static function renderMemberAccessException($e)
71: {
72: if (!$e instanceof Nette\MemberAccessException && !$e instanceof \LogicException) {
73: return null;
74: }
75: $loc = $e instanceof Nette\MemberAccessException ? $e->getTrace()[1] : $e->getTrace()[0];
76: if (preg_match('#Cannot (?:read|write to) an undeclared property .+::\$(\w+), did you mean \$(\w+)\?#A', $e->getMessage(), $m)) {
77: return [
78: 'link' => Helpers::editorUri($loc['file'], $loc['line'], 'fix', '->' . $m[1], '->' . $m[2]),
79: 'label' => 'fix it',
80: ];
81: } elseif (preg_match('#Call to undefined (static )?method .+::(\w+)\(\), did you mean (\w+)\(\)?#A', $e->getMessage(), $m)) {
82: $operator = $m[1] ? '::' : '->';
83: return [
84: 'link' => Helpers::editorUri($loc['file'], $loc['line'], 'fix', $operator . $m[2] . '(', $operator . $m[3] . '('),
85: 'label' => 'fix it',
86: ];
87: }
88: return null;
89: }
90:
91:
92: public static function renderNeonError($e)
93: {
94: if (
95: $e instanceof Nette\Neon\Exception
96: && preg_match('#line (\d+)#', $e->getMessage(), $m)
97: && ($trace = Helpers::findTrace($e->getTrace(), 'Nette\Neon\Decoder::decode'))
98: ) {
99: return [
100: 'tab' => 'NEON',
101: 'panel' => ($trace2 = Helpers::findTrace($e->getTrace(), 'Nette\DI\Config\Adapters\NeonAdapter::load'))
102: ? '<p><b>File:</b> ' . Helpers::editorLink($trace2['args'][0], $m[1]) . '</p>'
103: . self::highlightNeon(file_get_contents($trace2['args'][0]), $m[1])
104: : self::highlightNeon($trace['args'][0], (int) $m[1]),
105: ];
106: }
107: return null;
108: }
109:
110:
111: private static function highlightNeon($code, $line)
112: {
113: $code = htmlspecialchars($code, ENT_IGNORE, 'UTF-8');
114: $code = str_replace(' ', "<span class='tracy-dump-whitespace'>·</span>", $code);
115: $code = str_replace("\t", "<span class='tracy-dump-whitespace'>→ </span>", $code);
116: return '<pre class=code><div>'
117: . BlueScreen::highlightLine($code, $line)
118: . '</div></pre>';
119: }
120: }
121: