FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
cmd2/cmd2/theme.py at main · python-cmd2/cmd2 · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
python-cmd2
/
cmd2
Public
Notifications
You must be signed in to change notification settings
Fork
132
Star
686
Code
Issues
1
Pull requests
2
Discussions
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cmd2
/
cmd2
/
theme.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
302 lines (223 loc) · 10.4 KB
Breadcrumbs
cmd2
/
cmd2
/
theme.py
Copy path
File metadata and controls
302 lines (223 loc) · 10.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
"""Provides a centralized theming system for cmd2.
This module manages the global theme used for both Rich terminal output and
prompt-toolkit interactive components. It ensures that styling is consistent
and synchronized across the entire application when the theme is updated using
the following strategy.
1. Rich consoles use a persistent Theme object that is updated in-place.
2. prompt-toolkit integration in cmd2 uses a DynamicStyle wrapper around a
callable that returns the current prompt-toolkit theme.
To prevent Rich's built-in styles (like 'bold', or 'italic') from
polluting the prompt-toolkit namespace or colliding with its own internal
names, only styles starting with registered prefixes (e.g., 'cmd2.') or
those explicitly mapped to UI elements are synchronized to the
prompt-toolkit theme.
"""
from
collections
.
abc
import
(
Iterable
,
Mapping
,
)
from
typing
import
cast
from
prompt_toolkit
.
styles
import
Style
as
PtStyle
from
rich
.
style
import
(
Style
,
StyleType
,
)
from
rich
.
theme
import
Theme
from
.
pt_utils
import
rich_to_pt_style
from
.
rich_utils
import
Cmd2HelpFormatter
from
.
styles
import
(
DEFAULT_ARGPARSE_STYLES
,
DEFAULT_CMD2_STYLES
,
Cmd2Style
,
)
# The application-wide theme, defined using Rich's styling system.
# Use get_theme() to access it.
# Use reset_theme() and update_theme() to modify it.
_THEME
:
Theme
|
None
=
None
# The prompt-toolkit version of the theme, synchronized from the Rich theme.
# Use get_pt_theme() to access it.
_PT_THEME
:
PtStyle
|
None
=
None
# Maps style names to internal UI component names used by prompt-toolkit.
# This allows developers to use application-specific style names in update_theme()
# while ensuring the underlying prompt-toolkit UI is styled correctly.
# Use register_pt_mapping() and unregister_pt_mapping() to manage these mappings.
#
# Presence in this mapping, even with an empty set of UI component names, flags the
# style for synchronization to the prompt-toolkit theme. Use register_synchronized_style()
# and unregister_synchronized_style() to manage synchronization for styles that lack a
# registered prefix and do not require specific UI component mappings.
_PT_UI_MAP
:
dict
[
str
,
set
[
str
]]
=
{
Cmd2Style
.
COMPLETION_MENU
: {
"completion-menu"
},
Cmd2Style
.
COMPLETION_MENU_COMPLETION
: {
"completion-menu.completion"
},
Cmd2Style
.
COMPLETION_MENU_CURRENT
: {
"completion-menu.completion.current"
},
Cmd2Style
.
COMPLETION_MENU_META
: {
"completion-menu.meta.completion"
},
Cmd2Style
.
COMPLETION_MENU_META_CURRENT
: {
"completion-menu.meta.completion.current"
,
"completion-menu.multi-column-meta"
,
},
}
# Rich styles that start with one of these prefixes are automatically
# synchronized to the prompt-toolkit theme. Use register_synchronized_prefix()
# and unregister_synchronized_prefix() to modify this set.
_SYNCHRONIZED_PREFIXES
:
set
[
str
]
=
{
"cmd2."
}
def
get_theme
()
->
Theme
:
"""Get the application-wide Rich theme. Initializes it on the first call."""
if
_THEME
is
None
:
reset_theme
()
return
cast
(
Theme
,
_THEME
)
def
get_pt_theme
()
->
PtStyle
:
"""Get the application-wide prompt-toolkit style. Initializes it on the first call."""
if
_PT_THEME
is
None
:
reset_theme
()
return
cast
(
PtStyle
,
_PT_THEME
)
def
reset_theme
()
->
None
:
"""Reset the application-wide theme to its initial state.
This function performs an in-place reset of the existing Rich theme's
styles. This ensures that any Console objects already using the theme
will reflect the changes immediately without needing to be recreated.
Changes are automatically propagated to all synchronized components.
"""
global
_THEME
# noqa: PLW0603
# Include default styles from cmd2, rich-argparse, and Rich.
styles
=
DEFAULT_CMD2_STYLES
.
copy
()
styles
.
update
(
DEFAULT_ARGPARSE_STYLES
)
default_theme
=
Theme
(
styles
,
inherit
=
True
)
if
_THEME
is
None
:
# Initial assignment
_THEME
=
default_theme
else
:
# Perform in-place reset to preserve existing references
_THEME
.
styles
.
clear
()
_THEME
.
styles
.
update
(
default_theme
.
styles
)
_sync_all
()
def
update_theme
(
styles
:
Mapping
[
str
,
StyleType
])
->
None
:
"""Update the existing theme.
This function performs an in-place update of the existing Rich theme's
styles. This ensures that any Console objects already using the theme
will reflect the changes immediately without needing to be recreated.
Changes are automatically propagated to all synchronized components.
:param styles: mapping of style names to styles
"""
# Convert any string styles to Style objects
parsed_styles
=
{
name
:
style
if
isinstance
(
style
,
Style
)
else
Style
.
parse
(
style
)
for
name
,
style
in
styles
.
items
()}
# Perform in-place update to preserve existing references
get_theme
().
styles
.
update
(
parsed_styles
)
_sync_all
()
def
_sync_all
()
->
None
:
"""Propagate the global theme to rich-argparse and prompt-toolkit.
If the theme hasn't been initialized yet, this is a no-op.
"""
if
_THEME
is
None
:
return
# Synchronize rich-argparse styles
for
name
in
Cmd2HelpFormatter
.
styles
.
keys
()
&
_THEME
.
styles
.
keys
():
Cmd2HelpFormatter
.
styles
[
name
]
=
_THEME
.
styles
[
name
]
# Synchronize the prompt-toolkit theme
_sync_pt_theme
()
def
_sync_pt_theme
()
->
None
:
"""Build a new global prompt-toolkit style object based on the current Rich theme.
If the theme hasn't been initialized yet, this is a no-op.
"""
if
_THEME
is
None
:
return
style_rules
:
list
[
tuple
[
str
,
str
]]
=
[]
for
name
,
rich_style
in
_THEME
.
styles
.
items
():
# Only synchronize if it has a registered prefix or mapped UI component.
is_framework_style
=
any
(
name
.
startswith
(
p
)
for
p
in
_SYNCHRONIZED_PREFIXES
)
is_mapped_style
=
name
in
_PT_UI_MAP
if
is_framework_style
or
is_mapped_style
:
pt_style_str
=
rich_to_pt_style
(
rich_style
)
# Register the style name as a prompt-toolkit class (accessible via 'class:name')
style_rules
.
append
((
name
,
pt_style_str
))
# Add any prompt-toolkit UI component names from the map (e.g., 'completion-menu')
if
is_mapped_style
:
style_rules
.
extend
((
pt_name
,
pt_style_str
)
for
pt_name
in
_PT_UI_MAP
[
name
])
global
_PT_THEME
# noqa: PLW0603
_PT_THEME
=
PtStyle
(
style_rules
)
def
register_pt_mapping
(
style_name
:
str
,
pt_ui_names
:
str
|
Iterable
[
str
])
->
None
:
"""Map a Rich theme style name to one or more prompt-toolkit UI components.
This enables styling of prompt-toolkit's internal elements (such as the
completion menu) using styles in the application's Rich theme.
Registering a mapping also flags the style for synchronization to the
prompt-toolkit theme, making it accessible via 'class:style_name'.
:param style_name: The style name used in the Rich theme.
:param pt_ui_names: One or more prompt-toolkit UI component names (e.g., 'completion-menu').
"""
if
isinstance
(
pt_ui_names
,
str
):
pt_ui_names
=
[
pt_ui_names
]
# Register the style in the map.
if
style_name
not
in
_PT_UI_MAP
:
_PT_UI_MAP
[
style_name
]
=
set
()
changed
=
True
else
:
changed
=
False
# Add UI mappings, excluding 'style_name' which the sync handles by default.
original_size
=
len
(
_PT_UI_MAP
[
style_name
])
_PT_UI_MAP
[
style_name
].
update
(
n
for
n
in
pt_ui_names
if
n
!=
style_name
)
if
len
(
_PT_UI_MAP
[
style_name
])
!=
original_size
:
changed
=
True
# Trigger a re-sync if the theme is already initialized
if
changed
and
_PT_THEME
is
not
None
:
_sync_pt_theme
()
def
unregister_pt_mapping
(
style_name
:
str
,
pt_ui_names
:
str
|
Iterable
[
str
])
->
None
:
"""Remove one or more prompt-toolkit UI component mappings.
The style itself remains in the synchronization mapping (even if no
UI component mappings remain), ensuring it continues to be synchronized
to the prompt-toolkit theme.
To completely remove a style from synchronization, use
unregister_synchronized_style().
:param style_name: The style name used in the Rich theme.
:param pt_ui_names: Specific UI component(s) to unmap.
"""
if
style_name
not
in
_PT_UI_MAP
:
return
if
isinstance
(
pt_ui_names
,
str
):
pt_ui_names
=
[
pt_ui_names
]
original_size
=
len
(
_PT_UI_MAP
[
style_name
])
for
name
in
pt_ui_names
:
_PT_UI_MAP
[
style_name
].
discard
(
name
)
changed
=
len
(
_PT_UI_MAP
[
style_name
])
!=
original_size
# Trigger a re-sync if the theme is already initialized
if
changed
and
_PT_THEME
is
not
None
:
_sync_pt_theme
()
def
register_synchronized_style
(
style_name
:
str
)
->
None
:
"""Register a Rich theme style for synchronization with prompt-toolkit.
This ensures that the style is synchronized to the prompt-toolkit theme
(accessible via 'class:style_name') even if it does not begin with a
registered prefix.
:param style_name: The style name used in the Rich theme.
"""
register_pt_mapping
(
style_name
, [])
def
unregister_synchronized_style
(
style_name
:
str
)
->
None
:
"""Stop synchronizing a Rich theme style with prompt-toolkit.
This removes the style and all its mappings entirely from the
prompt-toolkit theme synchronization.
:param style_name: The style name to unregister.
"""
if
style_name
in
_PT_UI_MAP
:
del
_PT_UI_MAP
[
style_name
]
# Trigger a re-sync if the theme is already initialized
if
_PT_THEME
is
not
None
:
_sync_pt_theme
()
def
register_synchronized_prefix
(
prefix
:
str
)
->
None
:
"""Register a prefix whose styles will be synchronized to the prompt-toolkit theme.
The prefix must include any desired delimiters (e.g., 'myapp.' or 'plugin-').
:param prefix: The prefix string. Must be at least 1 character.
:raises ValueError: If the prefix is empty.
"""
if
not
prefix
:
raise
ValueError
(
"Prefix cannot be empty."
)
if
prefix
not
in
_SYNCHRONIZED_PREFIXES
:
_SYNCHRONIZED_PREFIXES
.
add
(
prefix
)
# Trigger a re-sync if the theme is already initialized
if
_PT_THEME
is
not
None
:
_sync_pt_theme
()
def
unregister_synchronized_prefix
(
prefix
:
str
)
->
None
:
"""Stop synchronizing styles starting with the given prefix.
:param prefix: The prefix string to remove.
"""
if
prefix
in
_SYNCHRONIZED_PREFIXES
:
_SYNCHRONIZED_PREFIXES
.
remove
(
prefix
)
# Trigger a re-sync if the theme is already initialized
if
_PT_THEME
is
not
None
:
_sync_pt_theme
()
Back
|
FazBrowse Home
|
New Git URL