v1.3.0
Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai> Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai> Co-Authored-By: Clément Drouin <clement.drouin@mistral.ai> Co-Authored-by: Thiago Padilha <thiago@coplane.com>
This commit is contained in:
parent
2e1e15120d
commit
078693fc64
67 changed files with 3959 additions and 819 deletions
|
|
@ -4,7 +4,12 @@ import sys
|
|||
|
||||
from rich import print as rprint
|
||||
from textual.app import App
|
||||
from textual.theme import Theme
|
||||
|
||||
from vibe.cli.textual_ui.terminal_theme import (
|
||||
TERMINAL_THEME_NAME,
|
||||
capture_terminal_theme,
|
||||
)
|
||||
from vibe.core.paths.global_paths import GLOBAL_ENV_FILE
|
||||
from vibe.setup.onboarding.screens import (
|
||||
ApiKeyScreen,
|
||||
|
|
@ -16,7 +21,15 @@ from vibe.setup.onboarding.screens import (
|
|||
class OnboardingApp(App[str | None]):
|
||||
CSS_PATH = "onboarding.tcss"
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._terminal_theme: Theme | None = capture_terminal_theme()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
if self._terminal_theme:
|
||||
self.register_theme(self._terminal_theme)
|
||||
self.theme = TERMINAL_THEME_NAME
|
||||
|
||||
self.install_screen(WelcomeScreen(), "welcome")
|
||||
self.install_screen(ThemeSelectionScreen(), "theme_selection")
|
||||
self.install_screen(ApiKeyScreen(), "api_key")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import ClassVar
|
||||
from typing import TYPE_CHECKING, ClassVar
|
||||
|
||||
from textual.app import ComposeResult
|
||||
from textual.binding import Binding, BindingType
|
||||
|
|
@ -9,10 +9,16 @@ from textual.events import Resize
|
|||
from textual.theme import BUILTIN_THEMES
|
||||
from textual.widgets import Markdown, Static
|
||||
|
||||
from vibe.cli.textual_ui.terminal_theme import TERMINAL_THEME_NAME
|
||||
from vibe.core.config import VibeConfig
|
||||
from vibe.setup.onboarding.base import OnboardingScreen
|
||||
|
||||
THEMES = sorted(k for k in BUILTIN_THEMES if k != "textual-ansi")
|
||||
if TYPE_CHECKING:
|
||||
from vibe.setup.onboarding import OnboardingApp
|
||||
|
||||
THEMES = [TERMINAL_THEME_NAME] + sorted(
|
||||
k for k in BUILTIN_THEMES if k != "textual-ansi"
|
||||
)
|
||||
|
||||
VISIBLE_NEIGHBORS = 3
|
||||
FADE_CLASSES = ["fade-1", "fade-2", "fade-3"]
|
||||
|
|
@ -73,7 +79,7 @@ class ThemeSelectionScreen(OnboardingScreen):
|
|||
Horizontal(
|
||||
Static("Navigate ↑ ↓", id="nav-hint"),
|
||||
Vertical(*self._compose_theme_list(), id="theme-list"),
|
||||
Static("Press Enter ↵", id="enter-hint"),
|
||||
Static("Press Enter \u21b5", id="enter-hint"),
|
||||
id="theme-row",
|
||||
)
|
||||
)
|
||||
|
|
@ -83,10 +89,24 @@ class ThemeSelectionScreen(OnboardingScreen):
|
|||
with preview:
|
||||
yield Container(Markdown(PREVIEW_MARKDOWN), id="preview-inner")
|
||||
|
||||
@property
|
||||
def _has_terminal_theme(self) -> bool:
|
||||
app: OnboardingApp = self.app # type: ignore[assignment]
|
||||
return app._terminal_theme is not None
|
||||
|
||||
@property
|
||||
def _available_themes(self) -> list[str]:
|
||||
if self._has_terminal_theme:
|
||||
return THEMES
|
||||
return [t for t in THEMES if t != TERMINAL_THEME_NAME]
|
||||
|
||||
def on_mount(self) -> None:
|
||||
current_theme = self.app.theme
|
||||
if current_theme in THEMES:
|
||||
self._theme_index = THEMES.index(current_theme)
|
||||
themes = self._available_themes
|
||||
if current_theme == TERMINAL_THEME_NAME:
|
||||
self._theme_index = 0
|
||||
elif current_theme in themes:
|
||||
self._theme_index = themes.index(current_theme)
|
||||
self._update_display()
|
||||
self._update_preview_height()
|
||||
self.focus()
|
||||
|
|
@ -102,8 +122,9 @@ class ThemeSelectionScreen(OnboardingScreen):
|
|||
preview.styles.max_height = max(10, available)
|
||||
|
||||
def _get_theme_at_offset(self, offset: int) -> str:
|
||||
index = (self._theme_index + offset) % len(THEMES)
|
||||
return THEMES[index]
|
||||
themes = self._available_themes
|
||||
index = (self._theme_index + offset) % len(themes)
|
||||
return themes[index]
|
||||
|
||||
def _update_display(self) -> None:
|
||||
for i, widget in enumerate(self._theme_widgets):
|
||||
|
|
@ -121,8 +142,10 @@ class ThemeSelectionScreen(OnboardingScreen):
|
|||
widget.add_class(FADE_CLASSES[distance])
|
||||
|
||||
def _navigate(self, direction: int) -> None:
|
||||
self._theme_index = (self._theme_index + direction) % len(THEMES)
|
||||
self.app.theme = THEMES[self._theme_index]
|
||||
themes = self._available_themes
|
||||
self._theme_index = (self._theme_index + direction) % len(themes)
|
||||
theme = themes[self._theme_index]
|
||||
self.app.theme = theme
|
||||
self._update_display()
|
||||
|
||||
def action_next_theme(self) -> None:
|
||||
|
|
@ -132,7 +155,7 @@ class ThemeSelectionScreen(OnboardingScreen):
|
|||
self._navigate(-1)
|
||||
|
||||
def action_next(self) -> None:
|
||||
theme = THEMES[self._theme_index]
|
||||
theme = self._available_themes[self._theme_index]
|
||||
try:
|
||||
VibeConfig.save_updates({"textual_theme": theme})
|
||||
except OSError:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ from textual.containers import CenterMiddle, Horizontal
|
|||
from textual.message import Message
|
||||
from textual.widgets import Static
|
||||
|
||||
from vibe.cli.textual_ui.terminal_theme import (
|
||||
TERMINAL_THEME_NAME,
|
||||
capture_terminal_theme,
|
||||
)
|
||||
from vibe.core.paths.global_paths import GLOBAL_CONFIG_FILE, TRUSTED_FOLDERS_FILE
|
||||
|
||||
|
||||
|
|
@ -145,9 +149,13 @@ class TrustFolderApp(App):
|
|||
self.folder_path = folder_path
|
||||
self._result: bool | None = None
|
||||
self._quit_without_saving = False
|
||||
self._terminal_theme = capture_terminal_theme()
|
||||
self._load_theme()
|
||||
|
||||
def _load_theme(self) -> None:
|
||||
if self._terminal_theme:
|
||||
self.register_theme(self._terminal_theme)
|
||||
|
||||
config_file = GLOBAL_CONFIG_FILE.path
|
||||
if not config_file.is_file():
|
||||
return
|
||||
|
|
@ -155,10 +163,18 @@ class TrustFolderApp(App):
|
|||
try:
|
||||
with config_file.open("rb") as f:
|
||||
config_data = tomllib.load(f)
|
||||
if textual_theme := config_data.get("textual_theme"):
|
||||
self.theme = textual_theme
|
||||
except (OSError, tomllib.TOMLDecodeError, KeyError):
|
||||
pass
|
||||
except (OSError, tomllib.TOMLDecodeError):
|
||||
return
|
||||
|
||||
textual_theme = config_data.get("textual_theme")
|
||||
if not textual_theme:
|
||||
return
|
||||
|
||||
if textual_theme == TERMINAL_THEME_NAME:
|
||||
if self._terminal_theme:
|
||||
self.theme = TERMINAL_THEME_NAME
|
||||
else:
|
||||
self.theme = textual_theme
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield TrustFolderDialog(self.folder_path)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue