Skip to content

Commit 0bca8df

Browse files
committed
format attribute arguments
1 parent 1970287 commit 0bca8df

3 files changed

Lines changed: 98 additions & 7 deletions

File tree

phpdotnet/phd/Package/Generic/XHTML.php

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,13 +1544,13 @@ private function render_attribute_args(string $args): string {
15441544
$parts = $this->split_attribute_args($args);
15451545

15461546
if (count($parts) <= 1) {
1547-
return $this->link_constants_in_text($parts[0]['value'] ?? '');
1547+
return $this->render_attribute_arg_value($parts[0]['value'] ?? '');
15481548
}
15491549

15501550
$lines = [];
15511551
$prefix = '';
15521552
foreach ($parts as $part) {
1553-
$rendered = $this->link_constants_in_text($part['value']);
1553+
$rendered = $this->render_attribute_arg_value($part['value']);
15541554
$line = '&nbsp;&nbsp;&nbsp;&nbsp;' . $prefix . $rendered;
15551555
if ($part['separator'] === ',') {
15561556
$line .= ',';
@@ -1621,6 +1621,75 @@ private function split_attribute_args(string $args): array {
16211621
return $parts;
16221622
}
16231623

1624+
private function render_attribute_arg_value(string $value): string {
1625+
$prefix = '';
1626+
if (preg_match('/^([A-Za-z_][A-Za-z0-9_]*)\s*:(?!:)\s*/', $value, $m)) {
1627+
$prefix = '<code class="parameter">' . $m[1] . '</code>: ';
1628+
$value = substr($value, strlen($m[0]));
1629+
}
1630+
1631+
$out = '';
1632+
$buffer = '';
1633+
$length = strlen($value);
1634+
for ($i = 0; $i < $length; $i++) {
1635+
$ch = $value[$i];
1636+
if ($ch !== '"' && $ch !== "'") {
1637+
$buffer .= $ch;
1638+
continue;
1639+
}
1640+
1641+
if ($buffer !== '') {
1642+
$out .= $this->format_attribute_non_string_segment($buffer);
1643+
$buffer = '';
1644+
}
1645+
1646+
$stringChar = $ch;
1647+
$literal = $ch;
1648+
$i++;
1649+
for (; $i < $length; $i++) {
1650+
$sc = $value[$i];
1651+
$literal .= $sc;
1652+
if ($sc === '\\' && $i + 1 < $length) {
1653+
$literal .= $value[++$i];
1654+
continue;
1655+
}
1656+
if ($sc === $stringChar) {
1657+
break;
1658+
}
1659+
}
1660+
$out .= '<span class="type string">' . htmlspecialchars($literal, ENT_NOQUOTES, 'UTF-8') . '</span>';
1661+
}
1662+
if ($buffer !== '') {
1663+
$out .= $this->format_attribute_non_string_segment($buffer);
1664+
}
1665+
1666+
return $prefix . $out;
1667+
}
1668+
1669+
private function format_attribute_non_string_segment(string $segment): string {
1670+
$linked = $this->link_constants_in_text($segment);
1671+
1672+
// Split out <a>...</a> regions so we don't touch their contents.
1673+
$parts = preg_split('/(<a [^>]*>[^<]*<\/a>)/', $linked, -1, PREG_SPLIT_DELIM_CAPTURE);
1674+
foreach ($parts as $i => $part) {
1675+
if ($i % 2 === 1) {
1676+
continue;
1677+
}
1678+
$part = preg_replace_callback(
1679+
'/\b(true|false|null)\b/i',
1680+
fn(array $m) => '<span class="type ' . strtolower($m[1]) . '">' . $m[1] . '</span>',
1681+
$part,
1682+
);
1683+
$part = preg_replace_callback(
1684+
'/(?<![\w.])-?\d+(\.\d+)?(?![\w.])/',
1685+
fn(array $m) => '<span class="type ' . (isset($m[1]) && $m[1] !== '' ? 'float' : 'int') . '">' . $m[0] . '</span>',
1686+
$part,
1687+
);
1688+
$parts[$i] = $part;
1689+
}
1690+
return implode('', $parts);
1691+
}
1692+
16241693
private function link_constants_in_text(string $text): string {
16251694
$escaped = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
16261695

tests/package/generic/attribute_formatting_005.phpt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Content:
5555
<p class="para">1. Attribute with literal named arguments</p>
5656
<div class="classsynopsis"><div class="classsynopsisinfo">
5757

58-
<span class="attribute">#[<a href="class.deprecated.html">\Deprecated</a>(<br>&nbsp;&nbsp;&nbsp;&nbsp;since: '8.5',<br>&nbsp;&nbsp;&nbsp;&nbsp;message: 'Deprecated since PHP 8.4'<br>)]</span><br>
58+
<span class="attribute">#[<a href="class.deprecated.html">\Deprecated</a>(<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">since</code>: <span class="type string">'8.5'</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">message</code>: <span class="type string">'Deprecated since PHP 8.4'</span><br>)]</span><br>
5959
<span class="modifier">final</span>
6060
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
6161
{</div>
@@ -66,7 +66,7 @@ Content:
6666
<p class="para">2. Attribute with single literal positional argument</p>
6767
<div class="classsynopsis"><div class="classsynopsisinfo">
6868

69-
<span class="attribute">#[<a href="class.deprecated.html">\Deprecated</a>('Deprecated since PHP 8.4')]</span><br>
69+
<span class="attribute">#[<a href="class.deprecated.html">\Deprecated</a>(<span class="type string">'Deprecated since PHP 8.4'</span>)]</span><br>
7070
<span class="modifier">final</span>
7171
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
7272
{</div>
@@ -77,7 +77,7 @@ Content:
7777
<p class="para">3. Unknown attribute with literal argument</p>
7878
<div class="classsynopsis"><div class="classsynopsisinfo">
7979

80-
<span class="attribute">#[\UnknownAttribute(foo: 'bar')]</span><br>
80+
<span class="attribute">#[\UnknownAttribute(<code class="parameter">foo</code>: <span class="type string">'bar'</span>)]</span><br>
8181
<span class="modifier">final</span>
8282
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
8383
{</div>
@@ -88,7 +88,7 @@ Content:
8888
<p class="para">4. Namespaced attribute with literal argument</p>
8989
<div class="classsynopsis"><div class="classsynopsisinfo">
9090

91-
<span class="attribute">#[\Some\Namespaced\Attribute(value: 42)]</span><br>
91+
<span class="attribute">#[\Some\Namespaced\Attribute(<code class="parameter">value</code>: <span class="type int">42</span>)]</span><br>
9292
<span class="modifier">final</span>
9393
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
9494
{</div>
@@ -109,11 +109,22 @@ Content:
109109
<div class="section">
110110
<p class="para">6. Attribute with mix of known and unknown class constants</p>
111111
<div class="classsynopsis"><div class="classsynopsisinfo">
112-
112+
113113
<span class="attribute">#[<a href="class.attribute.html">\Attribute</a>(<br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="class.attribute.html#attribute.constants.target-class">Attribute::TARGET_CLASS</a><br>&nbsp;&nbsp;&nbsp;&nbsp;| Unknown::CONST<br>)]</span><br>
114114
<span class="modifier">final</span>
115115
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
116116
{</div>
117117
}</div>
118118
</div>
119+
120+
<div class="section">
121+
<p class="para">7. Attribute with bool, null, int and float literal arguments</p>
122+
<div class="classsynopsis"><div class="classsynopsisinfo">
123+
124+
<span class="attribute">#[\UnknownAttribute(<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">enabled</code>: <span class="type true">true</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">fallback</code>: <span class="type false">false</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">default</code>: <span class="type null">null</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">count</code>: <span class="type int">42</span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<code class="parameter">ratio</code>: <span class="type float">3.14</span><br>)]</span><br>
125+
<span class="modifier">final</span>
126+
<span class="modifier">class</span> <strong class="classname">Deprecated</strong>
127+
{</div>
128+
}</div>
129+
</div>
119130
</div>

tests/package/generic/data/attribute_formatting_005.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,15 @@
6666
</ooclass>
6767
</classsynopsis>
6868
</section>
69+
70+
<section>
71+
<para>7. Attribute with bool, null, int and float literal arguments</para>
72+
<classsynopsis class="class">
73+
<ooclass>
74+
<modifier role="attribute">#[\UnknownAttribute(enabled: true, fallback: false, default: null, count: 42, ratio: 3.14)]</modifier>
75+
<modifier>final</modifier>
76+
<classname>Deprecated</classname>
77+
</ooclass>
78+
</classsynopsis>
79+
</section>
6980
</chapter>

0 commit comments

Comments
 (0)