-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
gh-140334: Fix IDLE syntax highlighting after line continuations #140335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm the fix works on Linux:
But during typing that I noticed that the keyword pattern also suffers from this issue:
I think this regex approach is getting very messy, the builtin get's quite a bit more complex. I assume that brings significant performance penalties. At a minium I would suggest refactoring some things, rather than having to explain the lookahead each time move it to some constant e.g. LAST_LINE_NO_CONTINUATION. At best I think we could possibly try an reuse the new repl's logic, which uses tokens at not such excessive regexs.
|
|
||
|
|
||
| def make_pat(): | ||
| kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern also suffers from the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the code str.for will always raise a SyntaxError, colouring in the for like a keyword will help beginners recognise that keywords are reserved and cannot be used as variable names/attributes. I believe that the keyword pattern is working correctly. I updated the match/case patterns since they are soft keywords and are valid variable/attribute names.
Misc/NEWS.d/next/IDLE/2025-10-19-18-43-07.gh-issue-140334.3mdyHm.rst
Outdated
Show resolved
Hide resolved
…Hm.rst Made by @StanFromIreland Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
|
Please do not use the Update Branch button unless necessary (e.g. fixing conflicts, jogging the CI, or very old PRs) as it uses valuable resources. For more information see the devguide. |
|
I did some profiling and here are my results:
I think that re-writing it with |
diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py
index b4df353012..5eb06581ec 100644
--- a/Lib/idlelib/colorizer.py
+++ b/Lib/idlelib/colorizer.py
@@ -273,6 +273,20 @@ def recolorize(self):
def recolorize_main(self):
"Evaluate text and apply colorizing tags."
+
+ # Shortcut for when we are recoloring everything
+ # Usually this happens when we open a file
+ todo_tag_range = self.tag_nextrange("TODO", "1.0")
+ if not todo_tag_range:
+ return None
+ start, end = todo_tag_range
+ if (start == "1.0") and self.compare(end, "==", "end"):
+ # Remove all tags
+ self.removecolors()
+ # Recolor everything
+ self._add_tags_in_section(self.get("1.0", "end"), "1.0")
+ return None
+
next = "1.0"
while todo_tag_range := self.tag_nextrange("TODO", next):
self.tag_remove("SYNC", todo_tag_range[0], todo_tag_range[1])
@@ -340,14 +354,22 @@ def _add_tags_in_section(self, chars, head):
`head` is the index in the text widget where the text is found.
"""
- for m in self.prog.finditer(chars):
- for name, matched_text in matched_named_groups(m):
- a, b = m.span(name)
- self._add_tag(a, b, head, name)
+ subtract_chars = 0
+ for match in self.prog.finditer(chars):
+ for name, matched_text in matched_named_groups(match):
+ start, end = match.span(name)
+ self._add_tag(start-subtract_chars, end-subtract_chars, head,
+ name)
if matched_text in ("def", "class"):
- if m1 := self.idprog.match(chars, b):
- a, b = m1.span(1)
- self._add_tag(a, b, head, "DEFINITION")
+ if new_match := self.idprog.match(chars, end):
+ start, end = new_match.span(1)
+ self._add_tag(start-subtract_chars, end-subtract_chars,
+ head, "DEFINITION")
+ # Move the head to where `end` points to
+ # Also keep track of how far we've moved head so that we
+ # can account for that next time we call `self._add_tag`
+ head = self.index(f"{head} +{end-subtract_chars:d}c")
+ subtract_chars = end
def removecolors(self):
"Remove all colorizing tags."Usually IDLE takes 0.6 seconds to recolorize I would make this into its own separate PR but all PRs need GitHub issues and I don't know how to phrase the issue. I pushed the change to my forked cpython if anyone is interested. |
Description
This PR fixes incorrect syntax highlighting in IDLE when a line ends with a backslash (
\) used for line continuation.Previously
Identifiers following a backslash were sometimes misinterpreted as keywords or built-ins instead of variables or attributes.
For example in:
The last
matchwas coloured like a keyword instead of a variable.Summary of changes
Fixes gh-140334