Skip to content

Commit 5eb2fec

Browse files
committed
fix web profiler bundle file formatting: missing indent
1 parent d15ea08 commit 5eb2fec

File tree

4 files changed

+166
-26
lines changed

4 files changed

+166
-26
lines changed

src/Symfony/Bundle/WebProfilerBundle/Profiler/CodeExtension.php

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

142-
$lines = [];
143131
if (0 > $srcContext) {
144-
$srcContext = \count($content);
132+
$srcContext = \count($lines);
145133
}
146134

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

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

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

157203
/**
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!';

src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/CodeExtensionTest.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,92 @@ 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): void
136+
{
137+
$template = <<<'TWIG'
138+
{{ file_path|file_excerpt(line, src_context) }}
139+
TWIG;
140+
141+
$this->assertEquals($expected, $this->render($template, $data));
142+
}
143+
144+
public static function fileExcerptIntegrationProvider(): \Generator
145+
{
146+
$fixturesPath = realpath(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'Fixtures');
147+
148+
yield 'file_except: php file' => [
149+
'expected' => <<<'HTML'
150+
<ol start="1"><li><a class="anchor" id="line1"></a><code><span style="color: #0000BB">&lt;?php</span></span></code></li>
151+
<li><a class="anchor" id="line2"></a><code><span style="color: #0000BB"></span></span></code></li>
152+
<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></span></code></li>
153+
<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></span></code></li>
154+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></span></code></li></ol>
155+
HTML,
156+
'data' => [
157+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
158+
'line' => 0,
159+
'src_context' => 3,
160+
],
161+
];
162+
163+
yield 'file_except: php file with selected line and no source context' => [
164+
'expected' => <<<'HTML'
165+
<ol start="1"><li class="selected"><a class="anchor" id="line1"></a><code><span style="color: #0000BB">&lt;?php</span></span></code></li>
166+
<li><a class="anchor" id="line2"></a><code><span style="color: #0000BB"></span></span></code></li>
167+
<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></span></code></li>
168+
<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></span></code></li>
169+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></span></code></li></ol>
170+
HTML,
171+
'data' => [
172+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
173+
'line' => 1,
174+
'src_context' => -1,
175+
],
176+
];
177+
178+
yield 'file_except: php file excerpt with selected line and custom source context' => [
179+
'expected' => <<<'HTML'
180+
<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></span></code></li>
181+
<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></span></code></li>
182+
<li><a class="anchor" id="line5"></a><code><span style="color: #007700"></span></span></code></li></ol>
183+
HTML,
184+
'data' => [
185+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
186+
'line' => 3,
187+
'src_context' => 1,
188+
],
189+
];
190+
191+
yield 'file_except: php file excerpt with out of bound selected line' => [
192+
'expected' => <<<'HTML'
193+
<ol start="99"></ol>
194+
HTML,
195+
'data' => [
196+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.php',
197+
'line' => 100,
198+
'src_context' => 1,
199+
],
200+
];
201+
202+
yield 'file_except: json file' => [
203+
'expected' => <<<'HTML'
204+
<ol start="1"><li><a class="anchor" id="line1"></a><code>[</code></li>
205+
<li><a class="anchor" id="line2"></a><code> "Hello",</code></li>
206+
<li><a class="anchor" id="line3"></a><code> "World!"</code></li>
207+
<li><a class="anchor" id="line4"></a><code>]</code></li>
208+
<li><a class="anchor" id="line5"></a><code></code></li></ol>
209+
HTML,
210+
'data' => [
211+
'file_path' => $fixturesPath.\DIRECTORY_SEPARATOR.'hello_world.json',
212+
'line' => 0,
213+
'src_context' => 3,
214+
],
215+
];
216+
}
217+
132218
public function testFormatFileFromTextIntegration()
133219
{
134220
$template = <<<'TWIG'

0 commit comments

Comments
 (0)