From 3139096f55c3965d024f50def0c5ee1ece90c990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Simon?= Date: Sat, 17 May 2025 22:23:01 +0200 Subject: [PATCH 1/4] Fix PyREPL coloring of double braces in f/t-strings --- Lib/_pyrepl/utils.py | 10 +++++++++- Lib/test/test_pyrepl/test_reader.py | 31 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index 752049ac05acdf..1065b523e40f84 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -41,9 +41,17 @@ def from_re(cls, m: Match[str], group: int | str) -> Self: @classmethod def from_token(cls, token: TI, line_len: list[int]) -> Self: + end_offset = 0 + if ((token.type is T.FSTRING_MIDDLE or token.type is T.TSTRING_MIDDLE) + and token.string.endswith(("{", "}"))): + # Double braces in f-string / t-string are translated into a single + # brace by the tokenizer, and are always at the end of the token: + # we must add 1 to the token end position to color the two braces. + end_offset = 1 + return cls( line_len[token.start[0] - 1] + token.start[1], - line_len[token.end[0] - 1] + token.end[1] - 1, + line_len[token.end[0] - 1] + token.end[1] - 1 + end_offset, ) diff --git a/Lib/test/test_pyrepl/test_reader.py b/Lib/test/test_pyrepl/test_reader.py index 57526f88f9384b..1f655264f1c00a 100644 --- a/Lib/test/test_pyrepl/test_reader.py +++ b/Lib/test/test_pyrepl/test_reader.py @@ -517,6 +517,37 @@ def unfinished_function(): self.assert_screen_equal(reader, code, clean=True) self.assert_screen_equal(reader, expected) + def test_syntax_highlighting_literal_brace_in_fstring_or_tstring(self): + code = dedent( + """\ + f"{{" + f"}}" + f"a{{b" + f"a}}b" + f"a{{b}}c" + t"a{{b}}c" + f"{{{0}}}" + f"{ {0} }" + """ + ) + expected = dedent( + """\ + {s}f"{z}{s}<<{z}{s}"{z} + {s}f"{z}{s}>>{z}{s}"{z} + {s}f"{z}{s}a<<{z}{s}b{z}{s}"{z} + {s}f"{z}{s}a>>{z}{s}b{z}{s}"{z} + {s}f"{z}{s}a<<{z}{s}b>>{z}{s}c{z}{s}"{z} + {s}t"{z}{s}a<<{z}{s}b>>{z}{s}c{z}{s}"{z} + {s}f"{z}{s}<<{z}{o}<{z}{n}0{z}{o}>{z}{s}>>{z}{s}"{z} + {s}f"{z}{o}<{z} {o}<{z}{n}0{z}{o}>{z} {o}>{z}{s}"{z} + """ + ).format(**colors).replace("<", "{").replace(">", "}") + events = code_to_events(code) + reader, _ = handle_all_events(events) + self.assert_screen_equal(reader, code, clean=True) + self.maxDiff=None + self.assert_screen_equal(reader, expected) + def test_control_characters(self): code = 'flag = "🏳️‍🌈"' events = code_to_events(code) From 369735e0001d65e52277bb5a04479feeb46ff54d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 17 May 2025 20:44:52 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst new file mode 100644 index 00000000000000..77c0b9e99852dd --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst @@ -0,0 +1 @@ +Fix PyREPL coloring of double braces in f-strings and t-strings From be293dfbaafeb77f5ffe5bcc62beea151eb6704a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Simon?= Date: Sun, 18 May 2025 01:02:28 +0200 Subject: [PATCH 3/4] Tweak blurb wording Co-authored-by: Peter Bierma --- .../2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst index 77c0b9e99852dd..7b8bab739c37c8 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-17-20-44-51.gh-issue-134158.ewLNLp.rst @@ -1 +1 @@ -Fix PyREPL coloring of double braces in f-strings and t-strings +Fix coloring of double braces in f-strings and t-strings in the :term:`REPL`. From 28c305a1d4911f62dcfe98bfe5d2f8ece6d96e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 19 May 2025 15:26:53 +0200 Subject: [PATCH 4/4] Minor adjustments --- Lib/_pyrepl/utils.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index 1065b523e40f84..e04fbdc6c8a5c4 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -41,17 +41,15 @@ def from_re(cls, m: Match[str], group: int | str) -> Self: @classmethod def from_token(cls, token: TI, line_len: list[int]) -> Self: - end_offset = 0 - if ((token.type is T.FSTRING_MIDDLE or token.type is T.TSTRING_MIDDLE) + end_offset = -1 + if (token.type in {T.FSTRING_MIDDLE, T.TSTRING_MIDDLE} and token.string.endswith(("{", "}"))): - # Double braces in f-string / t-string are translated into a single - # brace by the tokenizer, and are always at the end of the token: - # we must add 1 to the token end position to color the two braces. - end_offset = 1 + # gh-134158: a visible trailing brace comes from a double brace in input + end_offset += 1 return cls( line_len[token.start[0] - 1] + token.start[1], - line_len[token.end[0] - 1] + token.end[1] - 1 + end_offset, + line_len[token.end[0] - 1] + token.end[1] + end_offset, )