-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
gh-133346: Make theming support in _colorize extensible #133347
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
Changes from 5 commits
3344008
68e2385
252dfa0
b29c9b9
ca34939
5c5c3e1
f449e7b
8da314f
65d3a78
0866fd8
965c7cf
230d658
c4808c8
fd9c85c
664ef14
e67fda9
70ca161
3166d63
5c45ddb
68a5c44
9f51769
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,11 @@ | |
BUILTINS = {str(name) for name in dir(builtins) if not name.startswith('_')} | ||
|
||
|
||
def THEME(): | ||
# Not cached: the user can modify the theme inside the interactive session. | ||
return _colorize.get_theme().repl | ||
|
||
|
||
class Span(NamedTuple): | ||
"""Span indexing that's inclusive on both ends.""" | ||
|
||
|
@@ -44,7 +49,7 @@ def from_token(cls, token: TI, line_len: list[int]) -> Self: | |
|
||
class ColorSpan(NamedTuple): | ||
span: Span | ||
tag: _colorize.ColorTag | ||
tag: str | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little sad about this but currently Python typing cannot construct a type that is "a set of string literals from this type's attributes" and I didn't feel like repeating myself in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :( |
||
|
||
|
||
@functools.cache | ||
|
@@ -135,7 +140,7 @@ def recover_unterminated_string( | |
|
||
span = Span(start, end) | ||
trace("yielding span {a} -> {b}", a=span.start, b=span.end) | ||
yield ColorSpan(span, "STRING") | ||
yield ColorSpan(span, "string") | ||
ambv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
trace( | ||
"unhandled token error({buffer}) = {te}", | ||
|
@@ -164,28 +169,28 @@ def gen_colors_from_token_stream( | |
| T.TSTRING_START | T.TSTRING_MIDDLE | T.TSTRING_END | ||
): | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "STRING") | ||
yield ColorSpan(span, "string") | ||
case T.COMMENT: | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "COMMENT") | ||
yield ColorSpan(span, "comment") | ||
case T.NUMBER: | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "NUMBER") | ||
yield ColorSpan(span, "number") | ||
case T.OP: | ||
if token.string in "([{": | ||
bracket_level += 1 | ||
elif token.string in ")]}": | ||
bracket_level -= 1 | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "OP") | ||
yield ColorSpan(span, "op") | ||
case T.NAME: | ||
if is_def_name: | ||
is_def_name = False | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "DEFINITION") | ||
yield ColorSpan(span, "definition") | ||
elif keyword.iskeyword(token.string): | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "KEYWORD") | ||
yield ColorSpan(span, "keyword") | ||
if token.string in IDENTIFIERS_AFTER: | ||
is_def_name = True | ||
elif ( | ||
|
@@ -194,10 +199,10 @@ def gen_colors_from_token_stream( | |
and is_soft_keyword_used(prev_token, token, next_token) | ||
): | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "SOFT_KEYWORD") | ||
yield ColorSpan(span, "soft_keyword") | ||
elif token.string in BUILTINS: | ||
span = Span.from_token(token, line_lengths) | ||
yield ColorSpan(span, "BUILTIN") | ||
yield ColorSpan(span, "builtin") | ||
|
||
|
||
keyword_first_sets_match = {"False", "None", "True", "await", "lambda", "not"} | ||
|
@@ -290,15 +295,16 @@ def disp_str( | |
# move past irrelevant spans | ||
colors.pop(0) | ||
|
||
theme = THEME() | ||
pre_color = "" | ||
post_color = "" | ||
if colors and colors[0].span.start < start_index: | ||
# looks like we're continuing a previous color (e.g. a multiline str) | ||
pre_color = _colorize.theme[colors[0].tag] | ||
pre_color = theme[colors[0].tag] | ||
|
||
for i, c in enumerate(buffer, start_index): | ||
if colors and colors[0].span.start == i: # new color starts now | ||
pre_color = _colorize.theme[colors[0].tag] | ||
pre_color = theme[colors[0].tag] | ||
|
||
if c == "\x1a": # CTRL-Z on Windows | ||
chars.append(c) | ||
|
@@ -315,7 +321,7 @@ def disp_str( | |
char_widths.append(str_width(c)) | ||
|
||
if colors and colors[0].span.end == i: # current color ends now | ||
post_color = _colorize.theme["RESET"] | ||
post_color = theme.reset | ||
colors.pop(0) | ||
|
||
chars[-1] = pre_color + chars[-1] + post_color | ||
|
@@ -325,7 +331,7 @@ def disp_str( | |
if colors and colors[0].span.start < i and colors[0].span.end > i: | ||
# even though the current color should be continued, reset it for now. | ||
# the next call to `disp_str()` will revive it. | ||
chars[-1] += _colorize.theme["RESET"] | ||
chars[-1] += theme.reset | ||
|
||
return chars, char_widths | ||
|
||
|
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.
It's a little unfortunate for import times that this will bring a dependency on
dataclasses
module to all modules that import this. :-(