Skip to content

Commit e092b46

Browse files
committed
bug #60867 [WebProfilerBundle] Fix missing indent on non php files opended in the profiler (phcorp)
This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [WebProfilerBundle] Fix missing indent on non php files opended in the profiler | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #60835 | License | MIT This fixes non-php files indent in profiler. # Testing Considering any project running at https://127.0.0.1:8000 Non-php file: https://127.0.0.1:8000/_profiler/open?file=config/packages/framework.yaml&line=0 PHP file: https://127.0.0.1:8000/_profiler/open?file=src/Kernel.php&line=0 Commits ------- 5794d41 [WebProfilerBundle] Fix missing indent on non php files opended in the profiler
2 parents 0270060 + 5794d41 commit e092b46

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy