Which language: Python (specified explicitly, not auto-detect)
Version: 11.12.0
Using: highlight (not highlightAuto)
Describe the issue
A nested replacement field inside an f-string format spec (dynamic width/precision, e.g. f"{x:{w}}") closes the subst region on the inner }. The field's own closing } is then emitted as plain string text, and the subst span ends up brace-unbalanced.
Sample Code to Reproduce
Actual — hljs.highlight('f"{x:{w}}"', {language:'python'}).value:
<span class="hljs-string">f"<span class="hljs-subst">{x:{w}</span>}"</span>
The subst span is {x:{w} (an unmatched {) and the final } renders in string color instead of as part of the field. f"{value:{width}.{prec}f}" fails the same way.
Expected behavior
The whole {x:{w}} is a single replacement field, and the nested {w} is itself a field. This is valid Python — {w} sets the width dynamically (f"{x:{w}}" with x=42, w=6 → ' 42'). The closing } should belong to the field, not leak into the string, and the subst region should be brace-balanced.
Cause
SUBST in src/languages/python.js (begin:/\{/, end:/\}/) does not contain itself (SUBST.contains = [STRING, NUMBER, PROMPT]), so it ends at the first inner } and cannot handle nested replacement fields.
Assisted-by: Claude Opus 4 (high)
Which language: Python (specified explicitly, not auto-detect)
Version: 11.12.0
Using:
highlight(nothighlightAuto)Describe the issue
A nested replacement field inside an f-string format spec (dynamic width/precision, e.g.
f"{x:{w}}") closes thesubstregion on the inner}. The field's own closing}is then emitted as plain string text, and thesubstspan ends up brace-unbalanced.Sample Code to Reproduce
f"{x:{w}}"Actual —
hljs.highlight('f"{x:{w}}"', {language:'python'}).value:The
substspan is{x:{w}(an unmatched{) and the final}renders in string color instead of as part of the field.f"{value:{width}.{prec}f}"fails the same way.Expected behavior
The whole
{x:{w}}is a single replacement field, and the nested{w}is itself a field. This is valid Python —{w}sets the width dynamically (f"{x:{w}}"withx=42, w=6→' 42'). The closing}should belong to the field, not leak into the string, and thesubstregion should be brace-balanced.Cause
SUBSTinsrc/languages/python.js(begin:/\{/, end:/\}/) does notcontainitself (SUBST.contains = [STRING, NUMBER, PROMPT]), so it ends at the first inner}and cannot handle nested replacement fields.Assisted-by: Claude Opus 4 (high)