[Wip] CLI & Daemon
This commit is contained in:
parent
3bc5cc959a
commit
6a535099bb
44 changed files with 4417 additions and 303 deletions
|
|
@ -13,6 +13,19 @@ pub struct UiConfig {
|
|||
/// Whether opening the interactive UI should launch a locally installed daemon.
|
||||
#[serde(default)]
|
||||
pub daemon_start_policy: DaemonStartPolicy,
|
||||
#[serde(default)]
|
||||
pub color: TerminalPolicy,
|
||||
#[serde(default)]
|
||||
pub unicode: TerminalPolicy,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum TerminalPolicy {
|
||||
#[default]
|
||||
Auto,
|
||||
Always,
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
|
|
|
|||
|
|
@ -3,10 +3,81 @@ mod model;
|
|||
mod name;
|
||||
mod presets;
|
||||
|
||||
pub use config::{DaemonStartPolicy, UiConfig};
|
||||
pub use config::{DaemonStartPolicy, TerminalPolicy, UiConfig};
|
||||
pub use model::*;
|
||||
pub use name::ThemeName;
|
||||
|
||||
pub fn resolve(name: ThemeName) -> ResolvedTheme {
|
||||
presets::resolve(name)
|
||||
}
|
||||
|
||||
pub fn resolve_with_capabilities(
|
||||
name: ThemeName,
|
||||
color_enabled: bool,
|
||||
unicode_enabled: bool,
|
||||
) -> ResolvedTheme {
|
||||
let mut theme = if color_enabled {
|
||||
presets::resolve(name)
|
||||
} else {
|
||||
presets::resolve(ThemeName::Monospace)
|
||||
};
|
||||
theme.name = name;
|
||||
theme.unicode = unicode_enabled;
|
||||
if !unicode_enabled {
|
||||
if matches!(theme.console.cursor, CursorPresentation::Character { .. }) {
|
||||
theme.console.cursor = CursorPresentation::Character {
|
||||
glyph: "|",
|
||||
style: theme.console.text,
|
||||
};
|
||||
}
|
||||
}
|
||||
theme
|
||||
}
|
||||
|
||||
/// Resolve a theme against the terminal's color depth. Surface uses RGB
|
||||
/// colors, so a portable ANSI preset is selected when truecolor is absent.
|
||||
pub fn resolve_with_terminal_profile(
|
||||
name: ThemeName,
|
||||
color_enabled: bool,
|
||||
unicode_enabled: bool,
|
||||
truecolor_enabled: bool,
|
||||
) -> ResolvedTheme {
|
||||
let effective = if color_enabled && !truecolor_enabled && matches!(name, ThemeName::Surface) {
|
||||
ThemeName::Ansi
|
||||
} else {
|
||||
name
|
||||
};
|
||||
resolve_with_capabilities(effective, color_enabled, unicode_enabled)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ratatui::style::Color;
|
||||
|
||||
#[test]
|
||||
fn no_color_policy_removes_palette_dependencies() {
|
||||
let theme = resolve_with_capabilities(ThemeName::Surface, false, true);
|
||||
assert_eq!(theme.name, ThemeName::Surface);
|
||||
assert_eq!(theme.status.error.fg, None);
|
||||
assert_eq!(theme.surfaces.panel.bg, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ascii_policy_replaces_character_cursor() {
|
||||
let theme = resolve_with_capabilities(ThemeName::Monospace, false, false);
|
||||
assert!(!theme.unicode);
|
||||
match theme.console.cursor {
|
||||
CursorPresentation::Character { glyph, .. } => assert_eq!(glyph, "|"),
|
||||
CursorPresentation::StyledCell(_) => panic!("expected an ASCII character cursor"),
|
||||
}
|
||||
assert_ne!(theme.graphs.ram, Color::Blue);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn surface_uses_ansi_fallback_without_truecolor() {
|
||||
let theme = resolve_with_terminal_profile(ThemeName::Surface, true, true, false);
|
||||
assert_eq!(theme.name, ThemeName::Ansi);
|
||||
assert_eq!(theme.surfaces.panel.bg, None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ pub struct BorderStyles {
|
|||
pub title: Style,
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurfaceStyles {
|
||||
pub canvas: Style, pub toolbar: Style, pub panel: Style, pub panel_alternate: Style,
|
||||
pub panel_focused: Style, pub panel_selected: Style, pub footer: Style, pub overlay: Style,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ChromeMode { Bordered, Surfaces }
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChoiceItemStyle {
|
||||
pub marker: Style,
|
||||
pub label: Style,
|
||||
|
|
@ -119,6 +126,9 @@ pub struct TextSemantics {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct ResolvedTheme {
|
||||
pub name: ThemeName,
|
||||
pub unicode: bool,
|
||||
pub surfaces: SurfaceStyles,
|
||||
pub chrome: ChromeMode,
|
||||
pub text: TextStyles,
|
||||
pub status: StatusStyles,
|
||||
pub choices: ChoiceStyles,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
BorderStyles, ButtonStyles, ChoiceItemStyle, ChoiceStyles, ConsoleStyles, CursorPresentation,
|
||||
GraphStyles, LogStyles, MarkdownStyles, MarkerSet, ResolvedTheme, StatusStyles, TextStyles,
|
||||
ChromeMode, GraphStyles, LogStyles, MarkdownStyles, MarkerSet, ResolvedTheme, StatusStyles, SurfaceStyles, TextStyles,
|
||||
ThemeName,
|
||||
};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
|
|
@ -45,6 +45,9 @@ fn base(
|
|||
};
|
||||
ResolvedTheme {
|
||||
name,
|
||||
unicode: true,
|
||||
surfaces: SurfaceStyles { canvas: Style::default(), toolbar: Style::default(), panel: Style::default(), panel_alternate: Style::default(), panel_focused: focused, panel_selected: selected, footer: Style::default(), overlay: Style::default() },
|
||||
chrome: ChromeMode::Bordered,
|
||||
text: TextStyles {
|
||||
normal,
|
||||
muted,
|
||||
|
|
@ -295,6 +298,14 @@ pub fn resolve(name: ThemeName) -> ResolvedTheme {
|
|||
);
|
||||
theme.console.cursor =
|
||||
CursorPresentation::StyledCell(plain.fg(Color::Black).bg(Color::Yellow));
|
||||
theme.chrome = ChromeMode::Surfaces;
|
||||
theme.surfaces = SurfaceStyles {
|
||||
canvas: plain.bg(Color::Black), toolbar: plain.fg(Color::White).bg(Color::DarkGray),
|
||||
panel: plain.fg(Color::White).bg(Color::Rgb(30, 35, 45)),
|
||||
panel_alternate: plain.fg(Color::White).bg(Color::Rgb(45, 52, 66)),
|
||||
panel_focused: plain.fg(Color::White).bg(Color::Rgb(48, 58, 78)),
|
||||
panel_selected: selected, footer: plain.fg(Color::DarkGray).bg(Color::Black), overlay: plain.fg(Color::White).bg(Color::Rgb(45, 52, 66)),
|
||||
};
|
||||
theme
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue