Skip to content

Commit 5794d41

Browse files
phcorpfabpot
authored andcommitted
[WebProfilerBundle] Fix missing indent on non php files opended in the profiler
1 parent c6f3da1 commit 5794d41

File tree

4 files changed

+176
-27
lines changed

4 files changed

+176
-27
lines changed

src/Symfony/Bridge/Twig/Extension/CodeExtension.php

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -121,39 +121,85 @@ public function formatArgsAsText(array $args): string
121121
*/
122122
public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?string
123123
{
124-
if (is_file($file) && is_readable($file)) {
125-
// highlight_file could throw warnings
126-
// see https://bugs.php.net/25725
127-
$code = @highlight_file($file, true);
128-
if (\PHP_VERSION_ID >= 80300) {
129-
// remove main pre/code tags
130-
$code = preg_replace('#^<pre.*?>\s*<code.*?>(.*)</code>\s*</pre>#s', '\\1', $code);
131-
// split multiline span tags
132-
$code = preg_replace_callback('#<span ([^>]++)>((?:[^<\\n]*+\\n)++[^<]*+)</span>#', function ($m) {
133-
return "<span $m[1]>".str_replace("\n", "</span>\n<span $m[1]>", $m[2]).'</span>';
134-
}, $code);
135-
$content = explode("\n", $code);
136-
} else {
137-
// remove main code/span tags
138-
$code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
139-
// split multiline spans
140-
$code = preg_replace_callback('#<span ([^>]++)>((?:[^<]*+<br \/>)++[^<]*+)</span>#', fn ($m) => "<span $m[1]>".str_replace('<br />', "</span><br /><span $m[1]>", $m[2]).'</span>', $code);
141-
$content = explode('<br />', $code);
142-
}
124+
if (!is_file($file) || !is_readable($file)) {
125+
return null;
126+
}
127+
128+
$contents = file_get_contents($file);
129+
130+
if (!str_contains($contents, '<?php') && !str_contains($contents, '<?=')) {
131+
$lines = explode("\n", $contents);
143132

144-
$lines = [];
145133
if (0 > $srcContext) {
146-
$srcContext = \count($content);
134+
$srcContext = \count($lines);
147135
}
148136

149-
for ($i = max($line - $srcContext, 1), $max = min($line + $srcContext, \count($content)); $i <= $max; ++$i) {
150-
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><a class="anchor" id="line'.$i.'"></a><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
151-
}
137+
return $this->formatFileExcerpt(
138+
$this->extractExcerptLines($lines, $line, $srcContext),
139+
$line,
140+
$srcContext
141+
);
142+
}
152143

153-
return '<ol start="'.max($line - $srcContext, 1).'">'.implode("\n", $lines).'</ol>';
144+
// highlight_string could throw warnings
145+
// see https://bugs.php.net/25725
146+
$code = @highlight_string($contents, true);
147+
148+
if (\PHP_VERSION_ID >= 80300) {
149+
// remove main pre/code tags
150+
$code = preg_replace('#^<pre.*?>\s*<code.*?>(.*)</code>\s*</pre>#s', '\\1', $code);
151+
// split multiline span tags
152+
$code = preg_replace_callback(
153+
'#<span ([^>]++)>((?:[^<\\n]*+\\n)++[^<]*+)</span>#',
154+
static fn (array $m): string => "<span $m[1]>".str_replace("\n", "</span>\n<span $m[1]>", $m[2]).'</span>',
155+
$code
156+
);
157+
$lines = explode("\n", $code);
158+
} else {
159+
// remove main code/span tags
160+
$code = preg_replace('#^<code.*?>\s*<span.*?>(.*)</span>\s*</code>#s', '\\1', $code);
161+
// split multiline spans
162+
$code = preg_replace_callback(
163+
'#<span ([^>]++)>((?:[^<]*+<br \/>)++[^<]*+)</span>#',
164+
static fn (array $m): string => "<span $m[1]>".str_replace('<br />', "</span><br /><span $m[1]>", $m[2]).'</span>',
165+
$code
166+
);
167+
$lines = explode('<br />', $code);
154168
}
155169

156-
return null;
170+
if (0 > $srcContext) {
171+
$srcContext = \count($lines);
172+
}
173+
174+
return $this->formatFileExcerpt(
175+
array_map(
176+
self::fixCodeMarkup(...),
177+
$this->extractExcerptLines($lines, $line, $srcContext),
178+
),
179+
$line,
180+
$srcContext
181+
);
182+
}
183+
184+
private function extractExcerptLines(array $lines, int $selectedLine, int $srcContext): array
185+
{
186+
return \array_slice(
187+
$lines,
188+
max($selectedLine - $srcContext, 0),
189+
min($srcContext * 2 + 1, \count($lines) - $selectedLine + $srcContext),
190+
true
191+
);
192+
}
193+
194+
private function formatFileExcerpt(array $lines, int $selectedLine, int $srcContext): string
195+
{
196+
$start = max($selectedLine - $srcContext, 1);
197+
198+
return "<ol start=\"{$start}\">".implode("\n", array_map(
199+
static fn (string $line, int $num): string => '<li'.(++$num === $selectedLine ? ' class="selected"' : '')."><a class=\"anchor\" id=\"line{$num}\"></a><code>{$line}</code></li>",
200+
$lines,
201+
array_keys($lines),
202+
)).'</ol>';
157203
}
158204

159205
/**
@@ -243,7 +289,7 @@ protected static function fixCodeMarkup(string $line): string
243289
// missing </span> tag at the end of line
244290
$opening = strpos($line, '<span');
245291
$closing = strpos($line, '</span>');
246-
if (false !== $opening && (false === $closing || $closing > $opening)) {
292+
if (false !== $opening && (false === $closing || $closing < $opening)) {
247293
$line .= '</span>';
248294
}
249295

src/Symfony/Bridge/Twig/Tests/Extension/CodeExtensionTest.php

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,101 @@ public function testFormatFileIntegration()
129129
$this->assertEquals($expected, $this->render($template));
130130
}
131131

132+
/**
133+
* @dataProvider fileExcerptIntegrationProvider
134+
*/
135+
public function testFileExcerptIntegration(string $expected, array $data)
136+
{
137+
$template = <<<'TWIG'
138+
{{ file_path|file_excerpt(line, src_context) }}
139+
TWIG;
140+
$html = $this->render($template, $data);
141+
142+
// highlight_file function output changed sing PHP 8.3
143+
// see https://github.com/php/php-src/blob/e2667f17bc24e3cd200bb3eda457f566f1f77f8f/UPGRADING#L239-L242
144+
if (\PHP_VERSION_ID < 80300) {
145+
$html = str_replace('&nbsp;', ' ', $html);
146+
}
147+
148+
$html = html_entity_decode($html);
149+
150+
$this->assertEquals($expected, $html);
151+
}
152+
153+
public static function fileExcerptIntegrationProvider()
154+
{
155+
$fixturesPath = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures';
156+
157+
yield 'php file' => [
158+
'expected' => <<<'HTML'
159+
<ol start="1"><li><a class="anchor" id="line1"></a><code><span style="color: #0000BB"><?php</span></code></li>
160+
<li><a class="anchor" id="line2"></a><code><span style="color: #0000BB"></span></code></li>
161+
<li><a class="anchor" id="line3"></a><code><span style="color: #0000BB"></span><span style="color: #007700">echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">;</span></code></li>
162+
<li><a class="anchor" id="line4"></a><code><span style="color: #007700">echo </span><span style="color: #DD0000">'World!'</span><span style="color: #007700">;</span></code></li>
163+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></code></li></ol>
164+
HTML,
165+
'data' => [
166+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
167+
'line' => 0,
168+
'src_context' => 3,
169+
],
170+
];
171+
172+
yield 'php file with selected line and no source context' => [
173+
'expected' => <<<'HTML'
174+
<ol start="1"><li class="selected"><a class="anchor" id="line1"></a><code><span style="color: #0000BB"><?php</span></code></li>
175+
<li><a class="anchor" id="line2"></a><code><span style="color: #0000BB"></span></code></li>
176+
<li><a class="anchor" id="line3"></a><code><span style="color: #0000BB"></span><span style="color: #007700">echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">;</span></code></li>
177+
<li><a class="anchor" id="line4"></a><code><span style="color: #007700">echo </span><span style="color: #DD0000">'World!'</span><span style="color: #007700">;</span></code></li>
178+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></code></li></ol>
179+
HTML,
180+
'data' => [
181+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
182+
'line' => 1,
183+
'src_context' => -1,
184+
],
185+
];
186+
187+
yield 'php file excerpt with selected line and custom source context' => [
188+
'expected' => <<<'HTML'
189+
<ol start="2"><li class="selected"><a class="anchor" id="line3"></a><code><span style="color: #0000BB"></span><span style="color: #007700">echo </span><span style="color: #DD0000">'Hello'</span><span style="color: #007700">;</span></code></li>
190+
<li><a class="anchor" id="line4"></a><code><span style="color: #007700">echo </span><span style="color: #DD0000">'World!'</span><span style="color: #007700">;</span></code></li>
191+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></code></li></ol>
192+
HTML,
193+
'data' => [
194+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
195+
'line' => 3,
196+
'src_context' => 1,
197+
],
198+
];
199+
200+
yield 'php file excerpt with out of bound selected line' => [
201+
'expected' => <<<'HTML'
202+
<ol start="99"></ol>
203+
HTML,
204+
'data' => [
205+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
206+
'line' => 100,
207+
'src_context' => 1,
208+
],
209+
];
210+
211+
yield 'json file' => [
212+
'expected' => <<<'HTML'
213+
<ol start="1"><li><a class="anchor" id="line1"></a><code>[</code></li>
214+
<li><a class="anchor" id="line2"></a><code> "Hello",</code></li>
215+
<li><a class="anchor" id="line3"></a><code> "World!"</code></li>
216+
<li><a class="anchor" id="line4"></a><code>]</code></li>
217+
<li><a class="anchor" id="line5"></a><code></code></li></ol>
218+
HTML,
219+
'data' => [
220+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.json',
221+
'line' => 0,
222+
'src_context' => 3,
223+
],
224+
];
225+
}
226+
132227
public function testFormatFileFromTextIntegration()
133228
{
134229
$template = <<<'TWIG'
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[
2+
"Hello",
3+
"World!"
4+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
echo 'Hello';
4+
echo 'World!';

0 commit comments

Comments
 (0)