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.
Files changed (52) hide show
  1. nterm/__init__.py +54 -0
  2. nterm/__main__.py +619 -0
  3. nterm/askpass/__init__.py +22 -0
  4. nterm/askpass/server.py +393 -0
  5. nterm/config.py +158 -0
  6. nterm/connection/__init__.py +17 -0
  7. nterm/connection/profile.py +296 -0
  8. nterm/manager/__init__.py +29 -0
  9. nterm/manager/connect_dialog.py +322 -0
  10. nterm/manager/editor.py +262 -0
  11. nterm/manager/io.py +678 -0
  12. nterm/manager/models.py +346 -0
  13. nterm/manager/settings.py +264 -0
  14. nterm/manager/tree.py +493 -0
  15. nterm/resources.py +48 -0
  16. nterm/session/__init__.py +60 -0
  17. nterm/session/askpass_ssh.py +399 -0
  18. nterm/session/base.py +110 -0
  19. nterm/session/interactive_ssh.py +522 -0
  20. nterm/session/pty_transport.py +571 -0
  21. nterm/session/ssh.py +610 -0
  22. nterm/terminal/__init__.py +11 -0
  23. nterm/terminal/bridge.py +83 -0
  24. nterm/terminal/resources/terminal.html +253 -0
  25. nterm/terminal/resources/terminal.js +414 -0
  26. nterm/terminal/resources/xterm-addon-fit.min.js +8 -0
  27. nterm/terminal/resources/xterm-addon-unicode11.min.js +8 -0
  28. nterm/terminal/resources/xterm-addon-web-links.min.js +8 -0
  29. nterm/terminal/resources/xterm.css +209 -0
  30. nterm/terminal/resources/xterm.min.js +8 -0
  31. nterm/terminal/widget.py +380 -0
  32. nterm/theme/__init__.py +10 -0
  33. nterm/theme/engine.py +456 -0
  34. nterm/theme/stylesheet.py +377 -0
  35. nterm/theme/themes/clean.yaml +0 -0
  36. nterm/theme/themes/default.yaml +36 -0
  37. nterm/theme/themes/dracula.yaml +36 -0
  38. nterm/theme/themes/gruvbox_dark.yaml +36 -0
  39. nterm/theme/themes/gruvbox_hybrid.yaml +38 -0
  40. nterm/theme/themes/gruvbox_light.yaml +36 -0
  41. nterm/vault/__init__.py +32 -0
  42. nterm/vault/credential_manager.py +163 -0
  43. nterm/vault/keychain.py +135 -0
  44. nterm/vault/manager_ui.py +962 -0
  45. nterm/vault/profile.py +219 -0
  46. nterm/vault/resolver.py +250 -0
  47. nterm/vault/store.py +642 -0
  48. ntermqt-0.1.0.dist-info/METADATA +327 -0
  49. ntermqt-0.1.0.dist-info/RECORD +52 -0
  50. ntermqt-0.1.0.dist-info/WHEEL +5 -0
  51. ntermqt-0.1.0.dist-info/entry_points.txt +5 -0
  52. 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