Merge remote-tracking branch 'upstream/main' into simple_additions

This commit is contained in:
Liam 2024-08-17 11:26:28 -07:00
commit 3b87cfafdb
No known key found for this signature in database
5 changed files with 118 additions and 55 deletions

Binary file not shown.

Binary file not shown.

View File

@ -10,6 +10,7 @@ use std::{
time::Duration, time::Duration,
}; };
use crate::theme::Theme;
use clap::Parser; use clap::Parser;
use crossterm::{ use crossterm::{
cursor::RestorePosition, cursor::RestorePosition,
@ -25,9 +26,8 @@ use ratatui::{
}; };
use state::AppState; use state::AppState;
use tempdir::TempDir; use tempdir::TempDir;
use theme::THEMES;
/// This is a binary :), Chris, change this to update the documentation on -h // Linux utility toolbox
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
struct Args { struct Args {
/// Enable compatibility mode (disable icons and RGB colors) /// Enable compatibility mode (disable icons and RGB colors)
@ -36,23 +36,22 @@ struct Args {
#[arg(long, default_value_t = false)] #[arg(long, default_value_t = false)]
#[clap(help = "Show all available options, disregarding compatibility checks (UNSAFE)")] #[clap(help = "Show all available options, disregarding compatibility checks (UNSAFE)")]
override_validation: bool, override_validation: bool,
#[arg(short, long, value_enum)]
#[arg(default_value_t = Theme::Default)]
#[arg(help = "Set the theme to use in the application")]
theme: Theme,
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
let args = Args::parse(); let args = Args::parse();
let theme = if args.compat {
THEMES[0].clone()
} else {
THEMES[1].clone()
};
let commands_dir = include_dir!("src/commands"); let commands_dir = include_dir!("src/commands");
let temp_dir: TempDir = TempDir::new("linutil_scripts").unwrap(); let temp_dir: TempDir = TempDir::new("linutil_scripts").unwrap();
commands_dir commands_dir
.extract(temp_dir.path()) .extract(temp_dir.path())
.expect("Failed to extract the saved directory"); .expect("Failed to extract the saved directory");
let mut state = AppState::new(theme, temp_dir.path(), args.override_validation); let mut state = AppState::new(args.theme, temp_dir.path(), args.override_validation);
stdout().execute(EnterAlternateScreen)?; stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?; enable_raw_mode()?;

View File

@ -71,7 +71,7 @@ impl AppState {
let longest_tab_display_len = self let longest_tab_display_len = self
.tabs .tabs
.iter() .iter()
.map(|tab| tab.name.len() + self.theme.tab_icon.len()) .map(|tab| tab.name.len() + self.theme.tab_icon().len())
.max() .max()
.unwrap_or(0); .unwrap_or(0);
@ -94,15 +94,15 @@ impl AppState {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let tab_hl_style = if let Focus::TabList = self.focus { let tab_hl_style = if let Focus::TabList = self.focus {
Style::default().reversed().fg(self.theme.tab_color) Style::default().reversed().fg(self.theme.tab_color())
} else { } else {
Style::new().fg(self.theme.tab_color) Style::new().fg(self.theme.tab_color())
}; };
let list = List::new(tabs) let list = List::new(tabs)
.block(Block::default().borders(Borders::ALL)) .block(Block::default().borders(Borders::ALL))
.highlight_style(tab_hl_style) .highlight_style(tab_hl_style)
.highlight_symbol(self.theme.tab_icon); .highlight_symbol(self.theme.tab_icon());
frame.render_stateful_widget(list, left_chunks[1], &mut self.current_tab); frame.render_stateful_widget(list, left_chunks[1], &mut self.current_tab);
let chunks = Layout::default() let chunks = Layout::default()
@ -128,7 +128,7 @@ impl AppState {
let mut items: Vec<Line> = Vec::new(); let mut items: Vec<Line> = Vec::new();
if !self.at_root() { if !self.at_root() {
items.push( items.push(
Line::from(format!("{} ..", self.theme.dir_icon)).style(self.theme.dir_color), Line::from(format!("{} ..", self.theme.dir_icon())).style(self.theme.dir_color()),
); );
} }
@ -137,11 +137,11 @@ impl AppState {
node, has_children, .. node, has_children, ..
}| { }| {
if *has_children { if *has_children {
Line::from(format!("{} {}", self.theme.dir_icon, node.name)) Line::from(format!("{} {}", self.theme.dir_icon(), node.name))
.style(self.theme.dir_color) .style(self.theme.dir_color())
} else { } else {
Line::from(format!("{} {}", self.theme.cmd_icon, node.name)) Line::from(format!("{} {}", self.theme.cmd_icon(), node.name))
.style(self.theme.cmd_color) .style(self.theme.cmd_color())
} }
}, },
)); ));
@ -202,6 +202,8 @@ impl AppState {
self.refresh_tab(); self.refresh_tab();
} }
KeyCode::Char('/') => self.enter_search(), KeyCode::Char('/') => self.enter_search(),
KeyCode::Char('t') => self.theme = self.theme.next(),
KeyCode::Char('T') => self.theme = self.theme.prev(),
_ => {} _ => {}
}, },
Focus::List if key.kind != KeyEventKind::Release => match key.code { Focus::List if key.kind != KeyEventKind::Release => match key.code {
@ -218,6 +220,8 @@ impl AppState {
} }
KeyCode::Char('/') => self.enter_search(), KeyCode::Char('/') => self.enter_search(),
KeyCode::Tab => self.focus = Focus::TabList, KeyCode::Tab => self.focus = Focus::TabList,
KeyCode::Char('t') => self.theme = self.theme.next(),
KeyCode::Char('T') => self.theme = self.theme.prev(),
_ => {} _ => {}
}, },
_ => {} _ => {}

View File

@ -1,42 +1,102 @@
use clap::ValueEnum;
use ratatui::style::Color; use ratatui::style::Color;
#[derive(Clone)] // Add the Theme name here for a new theme
pub struct Theme { // This is more secure than the previous list
pub dir_color: Color, // We cannot index out of bounds, and we are giving
pub cmd_color: Color, // names to our various themes, making it very clear
pub tab_color: Color, // This will make it easy to add new themes
pub dir_icon: &'static str, #[derive(Clone, Debug, PartialEq, Default, ValueEnum, Copy)]
pub cmd_icon: &'static str, pub enum Theme {
pub tab_icon: &'static str, #[default]
pub success_color: Color, Default,
pub fail_color: Color, Compatible,
pub focused_color: Color,
pub unfocused_color: Color,
} }
pub const THEMES: [Theme; 2] = [ impl Theme {
Theme { pub fn dir_color(&self) -> Color {
dir_color: Color::Blue, match self {
cmd_color: Color::LightGreen, Theme::Default => Color::Blue,
tab_color: Color::Yellow, Theme::Compatible => Color::Blue,
dir_icon: "[DIR]", }
cmd_icon: "[CMD]", }
tab_icon: ">> ",
success_color: Color::Green, pub fn cmd_color(&self) -> Color {
fail_color: Color::Red, match self {
focused_color: Color::LightBlue, Theme::Default => Color::Rgb(204, 224, 208),
unfocused_color: Color::Gray, Theme::Compatible => Color::LightGreen,
}, }
Theme { }
dir_color: Color::Blue,
cmd_color: Color::Rgb(204, 224, 208), pub fn tab_color(&self) -> Color {
tab_color: Color::Rgb(255, 255, 85), match self {
dir_icon: "", Theme::Default => Color::Rgb(255, 255, 85),
cmd_icon: "", Theme::Compatible => Color::Yellow,
tab_icon: "", }
fail_color: Color::Rgb(199, 55, 44), }
success_color: Color::Rgb(5, 255, 55),
focused_color: Color::LightBlue, pub fn dir_icon(&self) -> &'static str {
unfocused_color: Color::Gray, match self {
}, Theme::Default => "",
]; Theme::Compatible => "[DIR]",
}
}
pub fn cmd_icon(&self) -> &'static str {
match self {
Theme::Default => "",
Theme::Compatible => "[CMD]",
}
}
pub fn tab_icon(&self) -> &'static str {
match self {
Theme::Default => "",
Theme::Compatible => ">> ",
}
}
pub fn success_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(199, 55, 44),
Theme::Compatible => Color::Green,
}
}
pub fn fail_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(5, 255, 55),
Theme::Compatible => Color::Red,
}
}
pub fn focused_color(&self) -> Color {
match self {
Theme::Default => Color::LightBlue,
Theme::Compatible => Color::LightBlue,
}
}
pub fn unfocused_color(&self) -> Color {
match self {
Theme::Default => Color::Gray,
Theme::Compatible => Color::Gray,
}
}
}
impl Theme {
#[allow(unused)]
pub fn next(self) -> Self {
let position = self as usize;
let types = Theme::value_variants();
types[(position + 1) % types.len()].into()
}
#[allow(unused)]
pub fn prev(self) -> Self {
let position = self as usize;
let types = Theme::value_variants();
types[(position + types.len() - 1) % types.len()].into()
}
}