"""Persistent TUI settings stored in ~/.navi_code/tui.json."""
from __future__ import annotations
import json
from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Any
from clients.terminal.config import settings
@dataclass
class TuiSettings:
"""User-facing TUI configuration persisted across restarts."""
theme: str = "gnexus-dark"
mouse: bool = True
scroll_speed: int = 1
diff_style: str = "unified"
keybinds: dict[str, str] = field(default_factory=dict)
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "TuiSettings":
field_defaults = {f.name: f.default for f in cls.__dataclass_fields__.values()}
merged = dict(field_defaults)
merged.update(data)
keybinds = merged.get("keybinds", {})
if keybinds is None or not isinstance(keybinds, dict):
keybinds = {}
return cls(
theme=merged.get("theme", "gnexus-dark"),
mouse=merged.get("mouse", True),
scroll_speed=merged.get("scroll_speed", 1),
diff_style=merged.get("diff_style", "unified"),
keybinds=dict(keybinds),
)
@property
def settings_dir(self) -> Path:
return settings.state_dir
@property
def settings_file(self) -> Path:
return self.settings_dir / "tui.json"
def load(self) -> "TuiSettings":
if not self.settings_file.exists():
return self._save_and_return()
try:
with self.settings_file.open("r", encoding="utf-8") as f:
data = json.load(f)
except (json.JSONDecodeError, OSError):
return self._save_and_return()
loaded = self.from_dict(data)
loaded._ensure_dir()
return loaded
def save(self) -> None:
self._ensure_dir()
with self.settings_file.open("w", encoding="utf-8") as f:
json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
def _ensure_dir(self) -> None:
self.settings_dir.mkdir(parents=True, exist_ok=True)
def _save_and_return(self) -> "TuiSettings":
self.save()
return self
# Global lazy-loaded instance.
_tui_settings: TuiSettings | None = None
def get_tui_settings() -> TuiSettings:
"""Return the loaded TUI settings, caching them for the process lifetime."""
global _tui_settings
if _tui_settings is None:
_tui_settings = TuiSettings().load()
return _tui_settings
def reload_tui_settings() -> TuiSettings:
"""Force reload from disk and return fresh settings."""
global _tui_settings
_tui_settings = TuiSettings().load()
return _tui_settings