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
1 change: 1 addition & 0 deletions Lib/_colorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ class Syntax(ThemeSection):
keyword: str = ANSIColors.BOLD_BLUE
keyword_constant: str = ANSIColors.BOLD_BLUE
builtin: str = ANSIColors.CYAN
command: str = ANSIColors.BOLD_CYAN
comment: str = ANSIColors.RED
string: str = ANSIColors.GREEN
number: str = ANSIColors.YELLOW
Expand Down
8 changes: 8 additions & 0 deletions Lib/_pyrepl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
IDENTIFIERS_AFTER = frozenset({"def", "class"})
KEYWORD_CONSTANTS = frozenset({"True", "False", "None"})
BUILTINS = frozenset({str(name) for name in dir(builtins) if not name.startswith('_')})
COMMANDS = frozenset({"exit", "quit", "copyright", "help", "clear"})


def THEME(**kwargs):
Expand Down Expand Up @@ -235,6 +236,13 @@ def gen_colors_from_token_stream(
):
span = Span.from_token(token, line_lengths)
yield ColorSpan(span, "soft_keyword")
elif (
token.string in COMMANDS
and not prev_token
and (not next_token or next_token.type == T.NEWLINE)
):
span = Span.from_token(token, line_lengths)
yield ColorSpan(span, "command")
elif (
token.string in BUILTINS
and not (prev_token and prev_token.exact_type == T.DOT)
Expand Down
25 changes: 25 additions & 0 deletions Lib/test/test_pyrepl/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,28 @@ def test_gen_colors_keyword_highlighting(self):
span_text = code[color.span.start:color.span.end + 1]
actual_highlights.append((span_text, color.tag))
self.assertEqual(actual_highlights, expected_highlights)

def test_gen_colors_command_highlighting(self):
cases = [
# highlights bare command names
("exit", [("exit", "command")]),
("quit", [("quit", "command")]),
("copyright", [("copyright", "command")]),
("help", [("help", "command")]),
("clear", [("clear", "command")]),
# no highlight when not the only token on the line
("x = exit", [("=", "op"), ("exit", "builtin")]),
("obj.exit", [(".", "op")]),
# falls through to builtin when called as function or used in expression
("exit()", [("exit", "builtin"), ("(", "op"), (")", "op")]),
("quit(0)", [("quit", "builtin"), ("(", "op"), ("0", "number"), (")", "op")]),
("print(exit)", [("print", "builtin"), ("(", "op"), ("exit", "builtin"), (")", "op")]),
]
for code, expected_highlights in cases:
with self.subTest(code=code):
colors = list(gen_colors(code))
actual_highlights = []
for color in colors:
span_text = code[color.span.start:color.span.end + 1]
actual_highlights.append((span_text, color.tag))
self.assertEqual(actual_highlights, expected_highlights)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Colorize ``exit``, ``quit``, ``copyright``, ``help``, and ``clear`` as commands in the :term:`REPL` when typed alone on a line. Patch by Bartosz Sławecki.
Loading