From 5c6ced8ca0b18dce25fe922431ec0019c3d63135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 24 Feb 2026 23:54:15 +0100 Subject: [PATCH] themes --- Cargo.toml | 2 +- src/main.rs | 65 ++++++++++++++++++++++++++++++++++++++++-------- src/tui/mod.rs | 14 ++++++----- src/tui/model.rs | 9 ++++--- 4 files changed, 69 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 91128a5..6c3ddb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ name = "lv" path = "./src/main.rs" [dependencies] -clap = {version="4.5", features=["derive"]} +clap = {version="4.5", features=["derive", "string"]} jiff = {version = "0.2", features = ["serde"]} ratatui = {version = "0.30.0", features=["unstable-rendered-line-info"]} ratatui-themes = { version = "0.2", features = ["serde"] } diff --git a/src/main.rs b/src/main.rs index 09f8ca1..9d0477f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,68 @@ use std::{ env::temp_dir, ffi::OsString, + fmt::{Debug, Display}, fs::{self, File}, + mem, path::PathBuf, process::{Command, exit}, + str::FromStr, }; mod tui; -use clap::{Parser, Subcommand}; +use clap::{Parser, Subcommand, ValueEnum, builder::PossibleValue}; use jiff::Zoned; +use ratatui_themes::ThemeName; + +#[repr(transparent)] +#[derive(Clone)] +pub struct Theme(ThemeName); + +impl Debug for Theme { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Display for Theme { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.slug()) + } +} + +impl FromStr for Theme { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + Ok(Self(s.parse()?)) + } +} + +impl ValueEnum for Theme { + fn value_variants<'a>() -> &'a [Self] { + // Safety: repr transparent + unsafe { mem::transmute(ThemeName::all()) } + } + + fn to_possible_value(&self) -> Option { + Some(PossibleValue::new(self.to_string())) + } +} #[derive(Subcommand, Debug)] enum Preset { /// Explore logs - Show, + Show { + /// Path where the compiler source code lives, for links in the TUI to work. + #[arg(long = "compiler-root")] + compiler_root: Option, + + /// Path where the compiler source code lives, for links in the TUI to work. + #[arg(default_value_t = Theme(ThemeName::OneDarkPro))] + #[arg(long = "theme")] + theme: Theme, + }, /// Get all the typesystem related logs Types, @@ -49,11 +97,6 @@ struct Args { #[arg(long = "logs-dir")] logs_dir: PathBuf, - /// Path where the compiler source code lives, for links in the TUI to work. - #[arg(global = true)] - #[arg(long = "compiler-root")] - compiler_root: Option, - #[arg(trailing_var_arg = true)] #[arg(allow_hyphen_values = true)] #[arg(global = true)] @@ -65,12 +108,14 @@ fn main() { preset, logs_dir, rest, - compiler_root, } = Args::parse(); let rustc_log = match preset { - Preset::Show => { - tui::run(logs_dir, compiler_root); + Preset::Show { + compiler_root, + theme: Theme(theme) + }=> { + tui::run(logs_dir, compiler_root, theme); exit(0); } Preset::Types => { diff --git a/src/tui/mod.rs b/src/tui/mod.rs index b2bb6ba..09b9b86 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,5 +1,6 @@ use itertools::Itertools; use ratatui_themes::{Theme, ThemeName}; +use serde_json::de; use std::{ fs::{self, DirEntry}, io, @@ -23,7 +24,7 @@ use ratatui::{ crossterm::event::{self, Event, KeyCode, KeyModifiers}, layout::{Constraint, HorizontalAlignment, Layout, Rect}, style::Style, - text::{Span, Text}, + text::{Line, Span, Text}, widgets::{ Block, Clear, List, ListItem, ListState, Padding, Paragraph, StatefulWidget, Widget, Wrap, }, @@ -35,9 +36,9 @@ pub mod model; pub mod processing; pub mod reader; -pub fn run(logs_dir: PathBuf, compiler_root: Option) { +pub fn run(logs_dir: PathBuf, compiler_root: Option, theme: ThemeName) { let terminal = ratatui::init(); - let theme = Theme::new(ThemeName::OneDarkPro); + let theme = Theme::new(theme); let app_result = App::new(logs_dir, compiler_root, theme).run(terminal); ratatui::restore(); @@ -458,12 +459,13 @@ impl Widget for &mut App { { let full_file_path = canonical_rustc_root.join(&file); Hyperlink::new( - format!("In file: {}", file.display()), + Line::from(format!("In file: {}", file.display())).style(default), format!("file://{}:{line}", full_file_path.display()), ) .render(first_line, buf); } else { - Span::from(format!("In file: {}:{line}", file.display())) + Line::from(format!("In file: {}:{line}", file.display())) + .style(default) .render(first_line, buf); } } @@ -489,7 +491,7 @@ impl Widget for &mut App { (res, height) }); - let list = ListView::new(builder, items.len()); + let list = ListView::new(builder, items.len()).style(default); StatefulWidget::render(list, footer_area, buf, &mut lv.footer_list); } Tab::Empty => {} diff --git a/src/tui/model.rs b/src/tui/model.rs index e5ad65b..f90f685 100644 --- a/src/tui/model.rs +++ b/src/tui/model.rs @@ -91,10 +91,11 @@ impl LogEntry { pub fn line_text(&self, accessed: bool, inline_depth: usize) -> Line<'static> { const NO_MESSAGE: &str = ""; + const SPACES_BEFORE: &str = " "; + let indent = " >".repeat(inline_depth); match self { LogEntry::Single { raw } => format!( - " ┃{}{}", - " >".repeat(inline_depth), + "{SPACES_BEFORE}┃{indent}{}", raw.fields.message().unwrap_or(NO_MESSAGE) ) .into(), @@ -105,13 +106,13 @@ impl LogEntry { && let Some(s) = val.as_str() { Line::from(format!( - "{:3}⭣{:3}⇊ ┃↪ {s}", + "{:4}⭣{:4}⇊ ┃{indent}↪ {s}", sub_entries.len(), self.count().wrapping_sub(1) )) } else { format!( - " ┃{}", + "{SPACES_BEFORE}┃{indent}{}", enter.fields.message().unwrap_or(NO_MESSAGE) ) .into()