Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions Lib/idlelib/colorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def any(name, alternates):
def make_pat():
kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
Copy link
Member

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.

Copy link
Author

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.

match_softkw = (
r"(?<!\\\n)" + # last line doesn't end in slash
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<MATCH_SOFTKW>match)\b" +
r"(?![ \t]*(?:" + "|".join([ # not followed by ...
Expand All @@ -27,11 +28,13 @@ def make_pat():
r"))"
)
case_default = (
r"(?<!\\\n)" + # last line doesn't end in slash
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<CASE_SOFTKW>case)" +
r"[ \t]+(?P<CASE_DEFAULT_UNDERSCORE>_\b)"
)
case_softkw_and_pattern = (
r"(?<!\\\n)" + # last line doesn't end in slash
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<CASE_SOFTKW2>case)\b" +
r"(?![ \t]*(?:" + "|".join([ # not followed by ...
Expand All @@ -45,19 +48,43 @@ def make_pat():
builtinlist = [str(name) for name in dir(builtins)
if not name.startswith('_') and
name not in keyword.kwlist]
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
builtin = (
r"(?<!" + # make sure there isn't
r"\\\n" + # a slash followed by a newline
r")" +
r"(?<!" + # make sure that there also isn't
r"|".join([
r"\.", # a dot or
r" ", # a space
]) +
r")" +
r"(" + # match any number of
r"[ \t]*" + # spaces/tabs followed by
r"(\\\\)*\\" + # an odd number of slashes followed by
r"\n" + # a newline
r")*" +
r"(" + # also match
r"|".join([ # either
r"[ \t]+", # indentation or
r"\b", # a word boundary
]) +
r")" +
any("BUILTIN", builtinlist) + # followed by a builtin
r"\b" # followed by another word boundary
)
comment = any("COMMENT", [r"#[^\n]*"])
stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb|t|rt|tr)?"
sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
dq3string = stringprefix + r'"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
sync = any("SYNC", [r"(?<!\\)\n"]) # no sync if line ends with slash
prog = re.compile("|".join([
builtin, comment, string, kw,
match_softkw, case_default,
case_softkw_and_pattern,
any("SYNC", [r"\n"]),
sync,
]),
re.DOTALL | re.MULTILINE)
return prog
Expand Down
13 changes: 12 additions & 1 deletion Lib/idlelib/idle_test/test_colorizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ async def f(): await g()
'''
case _:'''
"match x:"
self. \\
set
f(self, \\
set())
x = match if match else \\
match
""")


Expand Down Expand Up @@ -404,6 +410,7 @@ def test_recolorize_main(self, mock_notify):
('28.25', ('STRING',)), ('28.38', ('STRING',)),
('30.0', ('STRING',)),
('31.1', ('STRING',)),
('33.4', ()), ('35.4', ("BUILTIN",)), ('37.8', ()),
# SYNC at the end of every line.
('1.55', ('SYNC',)), ('2.50', ('SYNC',)), ('3.34', ('SYNC',)),
)
Expand Down Expand Up @@ -434,7 +441,11 @@ def test_recolorize_main(self, mock_notify):
eq(text.tag_nextrange('STRING', '8.12'), ('8.14', '8.17'))
eq(text.tag_nextrange('STRING', '8.17'), ('8.19', '8.26'))
eq(text.tag_nextrange('SYNC', '8.0'), ('8.26', '9.0'))
eq(text.tag_nextrange('SYNC', '31.0'), ('31.10', '33.0'))
eq(text.tag_nextrange('SYNC', '31.0'), ('31.10', '32.0'))
eq(text.tag_nextrange('SYNC', '32.0'), ('33.7', '34.0'))
eq(text.tag_nextrange('SYNC', '34.0'), ('35.10', '36.0'))
eq(text.tag_nextrange('SYNC', '36.0'), ('37.13', '39.0'))
eq(text.tag_nextrange('SYNC', '39.0'), ())

def _assert_highlighting(self, source, tag_ranges):
"""Check highlighting of a given piece of code.
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,7 @@ John Tromp
Diane Trout
Jason Trowbridge
Steven Troxler
Daniel Tsvetkov
Brent Tubbs
Anthony Tuininga
Erno Tukia
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed syntax highlighting in :mod:`IDLE <idlelib>` where slashes at the end of lines aren't
treated as line continuations.
Loading