Skip to content

Commit 3139096

Browse files
committed
Fix PyREPL coloring of double braces in f/t-strings
1 parent 84914ad commit 3139096

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

Lib/_pyrepl/utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,17 @@ def from_re(cls, m: Match[str], group: int | str) -> Self:
4141

4242
@classmethod
4343
def from_token(cls, token: TI, line_len: list[int]) -> Self:
44+
end_offset = 0
45+
if ((token.type is T.FSTRING_MIDDLE or token.type is T.TSTRING_MIDDLE)
46+
and token.string.endswith(("{", "}"))):
47+
# Double braces in f-string / t-string are translated into a single
48+
# brace by the tokenizer, and are always at the end of the token:
49+
# we must add 1 to the token end position to color the two braces.
50+
end_offset = 1
51+
4452
return cls(
4553
line_len[token.start[0] - 1] + token.start[1],
46-
line_len[token.end[0] - 1] + token.end[1] - 1,
54+
line_len[token.end[0] - 1] + token.end[1] - 1 + end_offset,
4755
)
4856

4957

Lib/test/test_pyrepl/test_reader.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,37 @@ def unfinished_function():
517517
self.assert_screen_equal(reader, code, clean=True)
518518
self.assert_screen_equal(reader, expected)
519519

520+
def test_syntax_highlighting_literal_brace_in_fstring_or_tstring(self):
521+
code = dedent(
522+
"""\
523+
f"{{"
524+
f"}}"
525+
f"a{{b"
526+
f"a}}b"
527+
f"a{{b}}c"
528+
t"a{{b}}c"
529+
f"{{{0}}}"
530+
f"{ {0} }"
531+
"""
532+
)
533+
expected = dedent(
534+
"""\
535+
{s}f"{z}{s}<<{z}{s}"{z}
536+
{s}f"{z}{s}>>{z}{s}"{z}
537+
{s}f"{z}{s}a<<{z}{s}b{z}{s}"{z}
538+
{s}f"{z}{s}a>>{z}{s}b{z}{s}"{z}
539+
{s}f"{z}{s}a<<{z}{s}b>>{z}{s}c{z}{s}"{z}
540+
{s}t"{z}{s}a<<{z}{s}b>>{z}{s}c{z}{s}"{z}
541+
{s}f"{z}{s}<<{z}{o}<{z}{n}0{z}{o}>{z}{s}>>{z}{s}"{z}
542+
{s}f"{z}{o}<{z} {o}<{z}{n}0{z}{o}>{z} {o}>{z}{s}"{z}
543+
"""
544+
).format(**colors).replace("<", "{").replace(">", "}")
545+
events = code_to_events(code)
546+
reader, _ = handle_all_events(events)
547+
self.assert_screen_equal(reader, code, clean=True)
548+
self.maxDiff=None
549+
self.assert_screen_equal(reader, expected)
550+
520551
def test_control_characters(self):
521552
code = 'flag = "🏳️‍🌈"'
522553
events = code_to_events(code)

0 commit comments

Comments
 (0)