ntermqt 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nterm/__init__.py +54 -0
- nterm/__main__.py +619 -0
- nterm/askpass/__init__.py +22 -0
- nterm/askpass/server.py +393 -0
- nterm/config.py +158 -0
- nterm/connection/__init__.py +17 -0
- nterm/connection/profile.py +296 -0
- nterm/manager/__init__.py +29 -0
- nterm/manager/connect_dialog.py +322 -0
- nterm/manager/editor.py +262 -0
- nterm/manager/io.py +678 -0
- nterm/manager/models.py +346 -0
- nterm/manager/settings.py +264 -0
- nterm/manager/tree.py +493 -0
- nterm/resources.py +48 -0
- nterm/session/__init__.py +60 -0
- nterm/session/askpass_ssh.py +399 -0
- nterm/session/base.py +110 -0
- nterm/session/interactive_ssh.py +522 -0
- nterm/session/pty_transport.py +571 -0
- nterm/session/ssh.py +610 -0
- nterm/terminal/__init__.py +11 -0
- nterm/terminal/bridge.py +83 -0
- nterm/terminal/resources/terminal.html +253 -0
- nterm/terminal/resources/terminal.js +414 -0
- nterm/terminal/resources/xterm-addon-fit.min.js +8 -0
- nterm/terminal/resources/xterm-addon-unicode11.min.js +8 -0
- nterm/terminal/resources/xterm-addon-web-links.min.js +8 -0
- nterm/terminal/resources/xterm.css +209 -0
- nterm/terminal/resources/xterm.min.js +8 -0
- nterm/terminal/widget.py +380 -0
- nterm/theme/__init__.py +10 -0
- nterm/theme/engine.py +456 -0
- nterm/theme/stylesheet.py +377 -0
- nterm/theme/themes/clean.yaml +0 -0
- nterm/theme/themes/default.yaml +36 -0
- nterm/theme/themes/dracula.yaml +36 -0
- nterm/theme/themes/gruvbox_dark.yaml +36 -0
- nterm/theme/themes/gruvbox_hybrid.yaml +38 -0
- nterm/theme/themes/gruvbox_light.yaml +36 -0
- nterm/vault/__init__.py +32 -0
- nterm/vault/credential_manager.py +163 -0
- nterm/vault/keychain.py +135 -0
- nterm/vault/manager_ui.py +962 -0
- nterm/vault/profile.py +219 -0
- nterm/vault/resolver.py +250 -0
- nterm/vault/store.py +642 -0
- ntermqt-0.1.0.dist-info/METADATA +327 -0
- ntermqt-0.1.0.dist-info/RECORD +52 -0
- ntermqt-0.1.0.dist-info/WHEEL +5 -0
- ntermqt-0.1.0.dist-info/entry_points.txt +5 -0
- ntermqt-0.1.0.dist-info/top_level.txt +1 -0
nterm/theme/engine.py
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Theme system.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
import logging
|
|
10
|
+
import yaml
|
|
11
|
+
from nterm.resources import resources
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Theme:
|
|
18
|
+
"""Terminal theme definition."""
|
|
19
|
+
name: str
|
|
20
|
+
|
|
21
|
+
# Terminal colors (xterm.js ITheme)
|
|
22
|
+
terminal_colors: dict = field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
# Font
|
|
25
|
+
font_family: str = "JetBrains Mono, Cascadia Code, Consolas, monospace"
|
|
26
|
+
font_size: int = 14
|
|
27
|
+
|
|
28
|
+
# Widget styling (Qt)
|
|
29
|
+
background_color: str = "#1e1e2e"
|
|
30
|
+
foreground_color: str = "#cdd6f4"
|
|
31
|
+
border_color: str = "#313244"
|
|
32
|
+
accent_color: str = "#89b4fa"
|
|
33
|
+
|
|
34
|
+
# Overlay styling
|
|
35
|
+
overlay_background: str = "rgba(30, 30, 46, 0.9)"
|
|
36
|
+
overlay_text_color: str = "#cdd6f4"
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def load(cls, path: Path) -> Theme:
|
|
40
|
+
"""Load theme from YAML file."""
|
|
41
|
+
with open(path) as f:
|
|
42
|
+
data = yaml.safe_load(f)
|
|
43
|
+
return cls(**data)
|
|
44
|
+
|
|
45
|
+
def save(self, path: Path) -> None:
|
|
46
|
+
"""Save theme to YAML file."""
|
|
47
|
+
data = {
|
|
48
|
+
'name': self.name,
|
|
49
|
+
'terminal_colors': self.terminal_colors,
|
|
50
|
+
'font_family': self.font_family,
|
|
51
|
+
'font_size': self.font_size,
|
|
52
|
+
'background_color': self.background_color,
|
|
53
|
+
'foreground_color': self.foreground_color,
|
|
54
|
+
'border_color': self.border_color,
|
|
55
|
+
'accent_color': self.accent_color,
|
|
56
|
+
'overlay_background': self.overlay_background,
|
|
57
|
+
'overlay_text_color': self.overlay_text_color,
|
|
58
|
+
}
|
|
59
|
+
with open(path, 'w') as f:
|
|
60
|
+
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def default(cls) -> Theme:
|
|
64
|
+
"""Default dark theme (Catppuccin Mocha inspired)."""
|
|
65
|
+
return cls(
|
|
66
|
+
name="default",
|
|
67
|
+
terminal_colors={
|
|
68
|
+
"background": "#1e1e2e",
|
|
69
|
+
"foreground": "#cdd6f4",
|
|
70
|
+
"cursor": "#f5e0dc",
|
|
71
|
+
"cursorAccent": "#1e1e2e",
|
|
72
|
+
"selectionBackground": "#585b70",
|
|
73
|
+
"selectionForeground": "#cdd6f4",
|
|
74
|
+
"black": "#45475a",
|
|
75
|
+
"red": "#f38ba8",
|
|
76
|
+
"green": "#a6e3a1",
|
|
77
|
+
"yellow": "#f9e2af",
|
|
78
|
+
"blue": "#89b4fa",
|
|
79
|
+
"magenta": "#f5c2e7",
|
|
80
|
+
"cyan": "#94e2d5",
|
|
81
|
+
"white": "#bac2de",
|
|
82
|
+
"brightBlack": "#585b70",
|
|
83
|
+
"brightRed": "#f38ba8",
|
|
84
|
+
"brightGreen": "#a6e3a1",
|
|
85
|
+
"brightYellow": "#f9e2af",
|
|
86
|
+
"brightBlue": "#89b4fa",
|
|
87
|
+
"brightMagenta": "#f5c2e7",
|
|
88
|
+
"brightCyan": "#94e2d5",
|
|
89
|
+
"brightWhite": "#a6adc8",
|
|
90
|
+
},
|
|
91
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
92
|
+
font_size=14,
|
|
93
|
+
background_color="#1e1e2e",
|
|
94
|
+
foreground_color="#cdd6f4",
|
|
95
|
+
border_color="#313244",
|
|
96
|
+
accent_color="#89b4fa",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def dracula(cls) -> Theme:
|
|
101
|
+
"""Dracula theme."""
|
|
102
|
+
return cls(
|
|
103
|
+
name="dracula",
|
|
104
|
+
terminal_colors={
|
|
105
|
+
"background": "#282a36",
|
|
106
|
+
"foreground": "#f8f8f2",
|
|
107
|
+
"cursor": "#f8f8f2",
|
|
108
|
+
"cursorAccent": "#282a36",
|
|
109
|
+
"selectionBackground": "#44475a",
|
|
110
|
+
"selectionForeground": "#f8f8f2",
|
|
111
|
+
"black": "#21222c",
|
|
112
|
+
"red": "#ff5555",
|
|
113
|
+
"green": "#50fa7b",
|
|
114
|
+
"yellow": "#f1fa8c",
|
|
115
|
+
"blue": "#bd93f9",
|
|
116
|
+
"magenta": "#ff79c6",
|
|
117
|
+
"cyan": "#8be9fd",
|
|
118
|
+
"white": "#f8f8f2",
|
|
119
|
+
"brightBlack": "#6272a4",
|
|
120
|
+
"brightRed": "#ff6e6e",
|
|
121
|
+
"brightGreen": "#69ff94",
|
|
122
|
+
"brightYellow": "#ffffa5",
|
|
123
|
+
"brightBlue": "#d6acff",
|
|
124
|
+
"brightMagenta": "#ff92df",
|
|
125
|
+
"brightCyan": "#a4ffff",
|
|
126
|
+
"brightWhite": "#ffffff",
|
|
127
|
+
},
|
|
128
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
129
|
+
font_size=14,
|
|
130
|
+
background_color="#282a36",
|
|
131
|
+
foreground_color="#f8f8f2",
|
|
132
|
+
border_color="#44475a",
|
|
133
|
+
accent_color="#bd93f9",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
@classmethod
|
|
137
|
+
def nord(cls) -> Theme:
|
|
138
|
+
"""Nord theme."""
|
|
139
|
+
return cls(
|
|
140
|
+
name="nord",
|
|
141
|
+
terminal_colors={
|
|
142
|
+
"background": "#2e3440",
|
|
143
|
+
"foreground": "#d8dee9",
|
|
144
|
+
"cursor": "#d8dee9",
|
|
145
|
+
"cursorAccent": "#2e3440",
|
|
146
|
+
"selectionBackground": "#434c5e",
|
|
147
|
+
"selectionForeground": "#d8dee9",
|
|
148
|
+
"black": "#3b4252",
|
|
149
|
+
"red": "#bf616a",
|
|
150
|
+
"green": "#a3be8c",
|
|
151
|
+
"yellow": "#ebcb8b",
|
|
152
|
+
"blue": "#81a1c1",
|
|
153
|
+
"magenta": "#b48ead",
|
|
154
|
+
"cyan": "#88c0d0",
|
|
155
|
+
"white": "#e5e9f0",
|
|
156
|
+
"brightBlack": "#4c566a",
|
|
157
|
+
"brightRed": "#bf616a",
|
|
158
|
+
"brightGreen": "#a3be8c",
|
|
159
|
+
"brightYellow": "#ebcb8b",
|
|
160
|
+
"brightBlue": "#81a1c1",
|
|
161
|
+
"brightMagenta": "#b48ead",
|
|
162
|
+
"brightCyan": "#8fbcbb",
|
|
163
|
+
"brightWhite": "#eceff4",
|
|
164
|
+
},
|
|
165
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
166
|
+
font_size=14,
|
|
167
|
+
background_color="#2e3440",
|
|
168
|
+
foreground_color="#d8dee9",
|
|
169
|
+
border_color="#3b4252",
|
|
170
|
+
accent_color="#88c0d0",
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def solarized_dark(cls) -> Theme:
|
|
175
|
+
"""Solarized Dark theme."""
|
|
176
|
+
return cls(
|
|
177
|
+
name="solarized_dark",
|
|
178
|
+
terminal_colors={
|
|
179
|
+
"background": "#002b36",
|
|
180
|
+
"foreground": "#839496",
|
|
181
|
+
"cursor": "#839496",
|
|
182
|
+
"cursorAccent": "#002b36",
|
|
183
|
+
"selectionBackground": "#073642",
|
|
184
|
+
"selectionForeground": "#93a1a1",
|
|
185
|
+
"black": "#073642",
|
|
186
|
+
"red": "#dc322f",
|
|
187
|
+
"green": "#859900",
|
|
188
|
+
"yellow": "#b58900",
|
|
189
|
+
"blue": "#268bd2",
|
|
190
|
+
"magenta": "#d33682",
|
|
191
|
+
"cyan": "#2aa198",
|
|
192
|
+
"white": "#eee8d5",
|
|
193
|
+
"brightBlack": "#002b36",
|
|
194
|
+
"brightRed": "#cb4b16",
|
|
195
|
+
"brightGreen": "#586e75",
|
|
196
|
+
"brightYellow": "#657b83",
|
|
197
|
+
"brightBlue": "#839496",
|
|
198
|
+
"brightMagenta": "#6c71c4",
|
|
199
|
+
"brightCyan": "#93a1a1",
|
|
200
|
+
"brightWhite": "#fdf6e3",
|
|
201
|
+
},
|
|
202
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
203
|
+
font_size=14,
|
|
204
|
+
background_color="#002b36",
|
|
205
|
+
foreground_color="#839496",
|
|
206
|
+
border_color="#073642",
|
|
207
|
+
accent_color="#268bd2",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@classmethod
|
|
211
|
+
def gruvbox_dark(cls) -> Theme:
|
|
212
|
+
"""Gruvbox Dark theme."""
|
|
213
|
+
return cls(
|
|
214
|
+
name="gruvbox_dark",
|
|
215
|
+
terminal_colors={
|
|
216
|
+
"background": "#282828",
|
|
217
|
+
"foreground": "#ebdbb2",
|
|
218
|
+
"cursor": "#ebdbb2",
|
|
219
|
+
"cursorAccent": "#282828",
|
|
220
|
+
"selectionBackground": "#504945",
|
|
221
|
+
"selectionForeground": "#ebdbb2",
|
|
222
|
+
"black": "#282828",
|
|
223
|
+
"red": "#cc241d",
|
|
224
|
+
"green": "#98971a",
|
|
225
|
+
"yellow": "#d79921",
|
|
226
|
+
"blue": "#458588",
|
|
227
|
+
"magenta": "#b16286",
|
|
228
|
+
"cyan": "#689d6a",
|
|
229
|
+
"white": "#a89984",
|
|
230
|
+
"brightBlack": "#928374",
|
|
231
|
+
"brightRed": "#fb4934",
|
|
232
|
+
"brightGreen": "#b8bb26",
|
|
233
|
+
"brightYellow": "#fabd2f",
|
|
234
|
+
"brightBlue": "#83a598",
|
|
235
|
+
"brightMagenta": "#d3869b",
|
|
236
|
+
"brightCyan": "#8ec07c",
|
|
237
|
+
"brightWhite": "#ebdbb2",
|
|
238
|
+
},
|
|
239
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
240
|
+
font_size=14,
|
|
241
|
+
background_color="#282828",
|
|
242
|
+
foreground_color="#ebdbb2",
|
|
243
|
+
border_color="#3c3836",
|
|
244
|
+
accent_color="#d79921",
|
|
245
|
+
overlay_background="rgba(40, 40, 40, 0.9)",
|
|
246
|
+
overlay_text_color="#ebdbb2",
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
@classmethod
|
|
250
|
+
def gruvbox_light(cls) -> Theme:
|
|
251
|
+
"""Gruvbox Light theme."""
|
|
252
|
+
return cls(
|
|
253
|
+
name="gruvbox_light",
|
|
254
|
+
terminal_colors={
|
|
255
|
+
"background": "#fbf1c7",
|
|
256
|
+
"foreground": "#3c3836",
|
|
257
|
+
"cursor": "#3c3836",
|
|
258
|
+
"cursorAccent": "#fbf1c7",
|
|
259
|
+
"selectionBackground": "#d5c4a1",
|
|
260
|
+
"selectionForeground": "#3c3836",
|
|
261
|
+
"black": "#fbf1c7",
|
|
262
|
+
"red": "#cc241d",
|
|
263
|
+
"green": "#98971a",
|
|
264
|
+
"yellow": "#d79921",
|
|
265
|
+
"blue": "#458588",
|
|
266
|
+
"magenta": "#b16286",
|
|
267
|
+
"cyan": "#689d6a",
|
|
268
|
+
"white": "#7c6f64",
|
|
269
|
+
"brightBlack": "#928374",
|
|
270
|
+
"brightRed": "#9d0006",
|
|
271
|
+
"brightGreen": "#79740e",
|
|
272
|
+
"brightYellow": "#b57614",
|
|
273
|
+
"brightBlue": "#076678",
|
|
274
|
+
"brightMagenta": "#8f3f71",
|
|
275
|
+
"brightCyan": "#427b58",
|
|
276
|
+
"brightWhite": "#3c3836",
|
|
277
|
+
},
|
|
278
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
279
|
+
font_size=14,
|
|
280
|
+
background_color="#fbf1c7",
|
|
281
|
+
foreground_color="#3c3836",
|
|
282
|
+
border_color="#d5c4a1",
|
|
283
|
+
accent_color="#b57614",
|
|
284
|
+
overlay_background="rgba(251, 241, 199, 0.95)",
|
|
285
|
+
overlay_text_color="#3c3836",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
@classmethod
|
|
289
|
+
def clean(cls) -> Theme:
|
|
290
|
+
"""
|
|
291
|
+
Clean theme.
|
|
292
|
+
|
|
293
|
+
Light, professional appearance inspired by classic terminal clients.
|
|
294
|
+
Warm paper tones with high contrast text.
|
|
295
|
+
"""
|
|
296
|
+
return cls(
|
|
297
|
+
name="clean",
|
|
298
|
+
terminal_colors={
|
|
299
|
+
"background": "#fdf6e3",
|
|
300
|
+
"foreground": "#3c3836",
|
|
301
|
+
"cursor": "#3c3836",
|
|
302
|
+
"cursorAccent": "#fdf6e3",
|
|
303
|
+
"selectionBackground": "#d5c4a1",
|
|
304
|
+
"selectionForeground": "#3c3836",
|
|
305
|
+
"black": "#3c3836",
|
|
306
|
+
"red": "#cc241d",
|
|
307
|
+
"green": "#98971a",
|
|
308
|
+
"yellow": "#d79921",
|
|
309
|
+
"blue": "#458588",
|
|
310
|
+
"magenta": "#b16286",
|
|
311
|
+
"cyan": "#689d6a",
|
|
312
|
+
"white": "#a89984",
|
|
313
|
+
"brightBlack": "#928374",
|
|
314
|
+
"brightRed": "#9d0006",
|
|
315
|
+
"brightGreen": "#79740e",
|
|
316
|
+
"brightYellow": "#b57614",
|
|
317
|
+
"brightBlue": "#076678",
|
|
318
|
+
"brightMagenta": "#8f3f71",
|
|
319
|
+
"brightCyan": "#427b58",
|
|
320
|
+
"brightWhite": "#fbf1c7",
|
|
321
|
+
},
|
|
322
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
323
|
+
font_size=14,
|
|
324
|
+
background_color="#f5f0e1",
|
|
325
|
+
foreground_color="#3c3836",
|
|
326
|
+
border_color="#d5c4a1",
|
|
327
|
+
accent_color="#d79921",
|
|
328
|
+
overlay_background="rgba(245, 240, 225, 0.95)",
|
|
329
|
+
overlay_text_color="#3c3836",
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
@classmethod
|
|
333
|
+
def gruvbox_hybrid(cls) -> Theme:
|
|
334
|
+
"""
|
|
335
|
+
Gruvbox Hybrid theme.
|
|
336
|
+
|
|
337
|
+
Dark UI chrome (Qt widgets) with light terminal.
|
|
338
|
+
Best of both worlds: comfortable dark UI, high-contrast terminal.
|
|
339
|
+
"""
|
|
340
|
+
return cls(
|
|
341
|
+
name="gruvbox_hybrid",
|
|
342
|
+
# Terminal: Gruvbox LIGHT for readability
|
|
343
|
+
terminal_colors={
|
|
344
|
+
"background": "#fbf1c7",
|
|
345
|
+
"foreground": "#3c3836",
|
|
346
|
+
"cursor": "#3c3836",
|
|
347
|
+
"cursorAccent": "#fbf1c7",
|
|
348
|
+
"selectionBackground": "#d5c4a1",
|
|
349
|
+
"selectionForeground": "#3c3836",
|
|
350
|
+
"black": "#fbf1c7",
|
|
351
|
+
"red": "#cc241d",
|
|
352
|
+
"green": "#98971a",
|
|
353
|
+
"yellow": "#d79921",
|
|
354
|
+
"blue": "#458588",
|
|
355
|
+
"magenta": "#b16286",
|
|
356
|
+
"cyan": "#689d6a",
|
|
357
|
+
"white": "#7c6f64",
|
|
358
|
+
"brightBlack": "#928374",
|
|
359
|
+
"brightRed": "#9d0006",
|
|
360
|
+
"brightGreen": "#79740e",
|
|
361
|
+
"brightYellow": "#b57614",
|
|
362
|
+
"brightBlue": "#076678",
|
|
363
|
+
"brightMagenta": "#8f3f71",
|
|
364
|
+
"brightCyan": "#427b58",
|
|
365
|
+
"brightWhite": "#3c3836",
|
|
366
|
+
},
|
|
367
|
+
font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
|
|
368
|
+
font_size=14,
|
|
369
|
+
# UI chrome: Gruvbox DARK for comfort
|
|
370
|
+
background_color="#282828",
|
|
371
|
+
foreground_color="#ebdbb2",
|
|
372
|
+
border_color="#3c3836",
|
|
373
|
+
accent_color="#d79921",
|
|
374
|
+
overlay_background="rgba(40, 40, 40, 0.9)",
|
|
375
|
+
overlay_text_color="#ebdbb2",
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class ThemeEngine:
|
|
380
|
+
"""Manages theme loading and switching."""
|
|
381
|
+
|
|
382
|
+
def __init__(self, theme_dir: Path = None):
|
|
383
|
+
"""
|
|
384
|
+
Initialize theme engine.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
theme_dir: Directory to load custom themes from
|
|
388
|
+
"""
|
|
389
|
+
self.theme_dir = theme_dir or resources.get_path("theme", "themes")
|
|
390
|
+
|
|
391
|
+
self._themes: dict[str, Theme] = {}
|
|
392
|
+
self._current: Optional[Theme] = None
|
|
393
|
+
|
|
394
|
+
# Register built-in themes
|
|
395
|
+
self._themes["default"] = Theme.default()
|
|
396
|
+
self._themes["dracula"] = Theme.dracula()
|
|
397
|
+
self._themes["nord"] = Theme.nord()
|
|
398
|
+
self._themes["solarized_dark"] = Theme.solarized_dark()
|
|
399
|
+
self._themes["gruvbox_dark"] = Theme.gruvbox_dark()
|
|
400
|
+
self._themes["gruvbox_light"] = Theme.gruvbox_light()
|
|
401
|
+
self._themes["gruvbox_hybrid"] = Theme.gruvbox_hybrid()
|
|
402
|
+
self._themes["clean"] = Theme.clean()
|
|
403
|
+
|
|
404
|
+
def load_themes(self) -> None:
|
|
405
|
+
"""Load all themes from theme directory."""
|
|
406
|
+
if not self.theme_dir.exists():
|
|
407
|
+
logger.debug(f"Theme directory not found: {self.theme_dir}")
|
|
408
|
+
return
|
|
409
|
+
|
|
410
|
+
for path in self.theme_dir.glob("*.yaml"):
|
|
411
|
+
try:
|
|
412
|
+
theme = Theme.load(path)
|
|
413
|
+
self._themes[theme.name] = theme
|
|
414
|
+
logger.debug(f"Loaded theme: {theme.name}")
|
|
415
|
+
except Exception as e:
|
|
416
|
+
logger.warning(f"Failed to load theme {path}: {e}")
|
|
417
|
+
|
|
418
|
+
def get_theme(self, name: str) -> Optional[Theme]:
|
|
419
|
+
"""
|
|
420
|
+
Get theme by name.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
name: Theme name
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Theme if found, None otherwise
|
|
427
|
+
"""
|
|
428
|
+
return self._themes.get(name)
|
|
429
|
+
|
|
430
|
+
def list_themes(self) -> list[str]:
|
|
431
|
+
"""
|
|
432
|
+
List available theme names.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
List of theme names
|
|
436
|
+
"""
|
|
437
|
+
return sorted(self._themes.keys())
|
|
438
|
+
|
|
439
|
+
def register_theme(self, theme: Theme) -> None:
|
|
440
|
+
"""
|
|
441
|
+
Register a theme.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
theme: Theme to register
|
|
445
|
+
"""
|
|
446
|
+
self._themes[theme.name] = theme
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def current(self) -> Theme:
|
|
450
|
+
"""Current active theme."""
|
|
451
|
+
return self._current or self._themes["default"]
|
|
452
|
+
|
|
453
|
+
@current.setter
|
|
454
|
+
def current(self, theme: Theme) -> None:
|
|
455
|
+
"""Set current active theme."""
|
|
456
|
+
self._current = theme
|