Merge branch 'main' of ssh://github.com/christitustech/linutil into cleanup

This commit is contained in:
afonsofrancof 2024-07-30 21:35:44 +01:00
commit b3dedea471
No known key found for this signature in database
18 changed files with 275 additions and 159 deletions

View File

@ -8,3 +8,8 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
ignore:
- dependency-name: "actions/stale"
versions: '>= 9'
- dependency-name: "actions/setup-python"
versions: '> 4'

83
Cargo.lock generated
View File

@ -280,6 +280,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.14.5"
@ -319,6 +325,25 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "include_dir"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd"
dependencies = [
"include_dir_macros",
]
[[package]]
name = "include_dir_macros"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
dependencies = [
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "ioctl-rs" name = "ioctl-rs"
version = "0.1.6" version = "0.1.6"
@ -525,6 +550,34 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]] [[package]]
name = "ratatui" name = "ratatui"
version = "0.27.0" version = "0.27.0"
@ -546,6 +599,15 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.1" version = "0.5.1"
@ -555,6 +617,15 @@ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
] ]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.17" version = "1.0.17"
@ -722,6 +793,16 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
dependencies = [
"rand",
"remove_dir_all",
]
[[package]] [[package]]
name = "termios" name = "termios"
version = "0.2.2" version = "0.2.2"
@ -759,9 +840,11 @@ dependencies = [
"clap", "clap",
"crossterm", "crossterm",
"ego-tree", "ego-tree",
"include_dir",
"oneshot", "oneshot",
"portable-pty", "portable-pty",
"ratatui", "ratatui",
"tempdir",
"tui-term", "tui-term",
] ]

View File

@ -12,6 +12,8 @@ oneshot = "0.1.8"
portable-pty = "0.8.1" portable-pty = "0.8.1"
ratatui = "0.27.0" ratatui = "0.27.0"
tui-term = "0.1.12" tui-term = "0.1.12"
include_dir = "0.7.4"
tempdir = "0.3.7"
[[bin]] [[bin]]
name = "linutil" name = "linutil"

Binary file not shown.

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
setupAlacritty() { setupAlacritty() {
echo "Install Alacritty if not already installed..." echo "Install Alacritty if not already installed..."
if ! command_exists alacritty; then if ! command_exists alacritty; then

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
setupKitty() { setupKitty() {
echo "Install Kitty if not already installed..." echo "Install Kitty if not already installed..."
if ! command_exists kitty; then if ! command_exists kitty; then

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
setupRofi() { setupRofi() {
echo "Install Rofi if not already installed..." echo "Install Rofi if not already installed..."
if ! command_exists rofi; then if ! command_exists rofi; then

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
# Check if the home directory and linuxtoolbox folder exist, create them if they don't # Check if the home directory and linuxtoolbox folder exist, create them if they don't
LINUXTOOLBOXDIR="$HOME/linuxtoolbox" LINUXTOOLBOXDIR="$HOME/linuxtoolbox"

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
installDepend() { installDepend() {
## Check for dependencies. ## Check for dependencies.
echo -e "${YELLOW}Installing dependencies...${RC}" echo -e "${YELLOW}Installing dependencies...${RC}"

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
# Check if the home directory and linuxtoolbox folder exist, create them if they don't # Check if the home directory and linuxtoolbox folder exist, create them if they don't
LINUXTOOLBOXDIR="$HOME/linuxtoolbox" LINUXTOOLBOXDIR="$HOME/linuxtoolbox"

View File

@ -1,5 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
. ./common-script.sh
fastUpdate() { fastUpdate() {
case ${PACKAGER} in case ${PACKAGER} in
pacman) pacman)

5
src/commands/test/lib.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
say_hello () {
echo Hi
}

6
src/commands/test/main.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
# The current working directory will always be inside "commands"
. test/lib.sh
say_hello

View File

@ -1,4 +1,4 @@
use crate::{float::floating_window, theme::*}; use crate::{float::floating_window, running_command::Command, state::AppState};
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind}; use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
use ego_tree::{tree, NodeId}; use ego_tree::{tree, NodeId};
use ratatui::{ use ratatui::{
@ -9,19 +9,9 @@ use ratatui::{
Frame, Frame,
}; };
macro_rules! with_common_script {
($command:expr) => {
concat!(
include_str!("commands/common-script.sh"),
include_str!($command)
)
};
}
#[derive(Clone)]
struct ListNode { struct ListNode {
name: &'static str, name: &'static str,
command: &'static str, command: Command,
} }
/// This is a data structure that has everything necessary to draw and manage a menu of commands /// This is a data structure that has everything necessary to draw and manage a menu of commands
@ -65,62 +55,53 @@ impl CustomList {
// case the tree! macro expands to `ego-tree::tree` data structure // case the tree! macro expands to `ego-tree::tree` data structure
let tree = tree!(ListNode { let tree = tree!(ListNode {
name: "root", name: "root",
command: "" command: Command::None,
} => { } => {
// ListNode {
// name: "Just ls, nothing special, trust me",
// command: include_str!("commands/special_ls.sh"),
// },
ListNode { ListNode {
name: "System Setup", name: "System Setup",
command: "" command: Command::None,
} => { } => {
ListNode { ListNode {
name: "Build Prerequisites", name: "Build Prerequisites",
command: with_common_script!("commands/system-setup/1-compile-setup.sh"), command: Command::LocalFile("system-setup/1-compile-setup.sh"),
}, },
ListNode { ListNode {
name: "Gaming Dependencies", name: "Gaming Dependencies",
command: with_common_script!("commands/system-setup/2-gaming-setup.sh"), command: Command::LocalFile("system-setup/2-gaming-setup.sh"),
}, },
ListNode { ListNode {
name: "Global Theme", name: "Global Theme",
command: with_common_script!("commands/system-setup/3-global-theme.sh"), command: Command::LocalFile("system-setup/3-global-theme.sh"),
}, },
ListNode {
name: "Recursion?",
command: "cargo run"
}
}, },
ListNode { ListNode {
name: "Applications Setup", name: "Applications Setup",
command: "" command: Command::None
} => { } => {
ListNode { ListNode {
name: "Alacritty Setup", name: "Alacritty Setup",
command: with_common_script!("commands/applications-setup/alacritty-setup.sh"), command: Command::LocalFile("applications-setup/alacritty-setup.sh"),
},
ListNode {
name: "Kitty Setup",
command: with_common_script!("commands/applications-setup/kitty-setup.sh"),
}, },
ListNode { ListNode {
name: "Bash Prompt Setup", name: "Bash Prompt Setup",
command: "bash -c \"$(curl -s https://raw.githubusercontent.com/ChrisTitusTech/mybash/main/setup.sh)\"" command: Command::Raw("bash -c \"$(curl -s https://raw.githubusercontent.com/ChrisTitusTech/mybash/main/setup.sh)\""),
},
ListNode {
name: "Kitty Setup",
command: Command::LocalFile("applications-setup/kitty-setup.sh")
}, },
ListNode { ListNode {
name: "Neovim Setup", name: "Neovim Setup",
command: "bash -c \"$(curl -s https://raw.githubusercontent.com/ChrisTitusTech/neovim/main/setup.sh)\"" command: Command::Raw("bash -c \"$(curl -s https://raw.githubusercontent.com/ChrisTitusTech/neovim/main/setup.sh)\""),
}, },
ListNode { ListNode {
name: "Rofi Setup", name: "Rofi Setup",
command: with_common_script!("commands/applications-setup/rofi-setup.sh"), command: Command::LocalFile("applications-setup/rofi-setup.sh"),
}, },
}, },
ListNode { ListNode {
name: "Full System Update", name: "Full System Update",
command: with_common_script!("commands/system-update.sh"), command: Command::LocalFile("system-update.sh"),
}, },
}); });
// We don't get a reference, but rather an id, because references are siginficantly more // We don't get a reference, but rather an id, because references are siginficantly more
@ -138,8 +119,7 @@ impl CustomList {
} }
/// Draw our custom widget to the frame /// Draw our custom widget to the frame
pub fn draw(&mut self, frame: &mut Frame, area: Rect, filter: String) { pub fn draw(&mut self, frame: &mut Frame, area: Rect, filter: String, state: &AppState) {
let theme = get_theme();
self.filter(filter); self.filter(filter);
let item_list: Vec<Line> = if self.filter_query.is_empty() { let item_list: Vec<Line> = if self.filter_query.is_empty() {
@ -148,8 +128,12 @@ impl CustomList {
// to go up the tree // to go up the tree
// icons:   // icons:  
if !self.at_root() { if !self.at_root() {
items.push(Line::from(format!("{} ..", theme.dir_icon)).style(theme.dir_color)); items.push(
Line::from(format!("{} ..", state.theme.dir_icon))
.style(state.theme.dir_color),
);
} }
// Get the last element in the `visit_stack` vec // Get the last element in the `visit_stack` vec
let curr = self let curr = self
.inner_tree .inner_tree
@ -162,13 +146,13 @@ impl CustomList {
// it's a directory and will be handled as such // it's a directory and will be handled as such
if node.has_children() { if node.has_children() {
items.push( items.push(
Line::from(format!("{} {}", theme.dir_icon, node.value().name)) Line::from(format!("{} {}", state.theme.dir_icon, node.value().name))
.style(theme.dir_color), .style(state.theme.dir_color),
); );
} else { } else {
items.push( items.push(
Line::from(format!("{} {}", theme.cmd_icon, node.value().name)) Line::from(format!("{} {}", state.theme.cmd_icon, node.value().name))
.style(theme.cmd_color), .style(state.theme.cmd_color),
); );
} }
} }
@ -177,7 +161,7 @@ impl CustomList {
self.filtered_items self.filtered_items
.iter() .iter()
.map(|node| { .map(|node| {
Line::from(format!("{} {}", theme.cmd_icon, node.name)).style(theme.cmd_color) Line::from(format!("{} {}", state.theme.cmd_icon, node.value().name)).style(state.theme.cmd_color)
}) })
.collect() .collect()
}; };
@ -244,7 +228,7 @@ impl CustomList {
} }
/// Handle key events, we are only interested in `Press` and `Repeat` events /// Handle key events, we are only interested in `Press` and `Repeat` events
pub fn handle_key(&mut self, event: KeyEvent) -> Option<&'static str> { pub fn handle_key(&mut self, event: KeyEvent, state: &AppState) -> Option<Command> {
if event.kind == KeyEventKind::Release { if event.kind == KeyEventKind::Release {
return None; return None;
} }
@ -274,14 +258,14 @@ impl CustomList {
} }
// The 'p' key toggles the preview on and off // The 'p' key toggles the preview on and off
KeyCode::Char('p') => { KeyCode::Char('p') => {
self.toggle_preview_window(); self.toggle_preview_window(state);
None None
} }
KeyCode::Enter => self.handle_enter(), KeyCode::Enter => self.handle_enter(),
_ => None, _ => None,
} }
} }
fn toggle_preview_window(&mut self) { fn toggle_preview_window(&mut self, state: &AppState) {
// If the preview window is active, disable it // If the preview window is active, disable it
if self.preview_window_state.is_some() { if self.preview_window_state.is_some() {
self.preview_window_state = None; self.preview_window_state = None;
@ -290,17 +274,23 @@ impl CustomList {
// Get the selected command // Get the selected command
if let Some(selected_command) = self.get_selected_command() { if let Some(selected_command) = self.get_selected_command() {
// If command is a folder, we don't display a preview let lines = match selected_command {
if selected_command.is_empty() { Command::Raw(cmd) => {
return;
}
// Reconstruct the line breaks and file formatting after the // Reconstruct the line breaks and file formatting after the
// 'include_str!()' call in the node // 'include_str!()' call in the node
let lines: Vec<String> = selected_command cmd.lines().map(|line| line.to_string()).collect()
.lines() }
.map(|line| line.to_string()) Command::LocalFile(file_path) => {
.collect(); let mut full_path = state.temp_path.clone();
full_path.push(file_path);
let file_contents = std::fs::read_to_string(&full_path)
.map_err(|_| format!("File not found: {:?}", &full_path))
.unwrap();
file_contents.lines().map(|line| line.to_string()).collect()
}
// If command is a folder, we don't display a preview
Command::None => return,
};
// Show the preview window with the text lines // Show the preview window with the text lines
self.preview_window_state = Some(PreviewWindowState::new(lines)); self.preview_window_state = Some(PreviewWindowState::new(lines));
@ -358,7 +348,7 @@ impl CustomList {
/// ///
/// This could probably be integrated into the 'handle_enter()' method as to avoid code /// This could probably be integrated into the 'handle_enter()' method as to avoid code
/// duplication, but I don't want to make too major changes to the codebase. /// duplication, but I don't want to make too major changes to the codebase.
fn get_selected_command(&self) -> Option<&'static str> { fn get_selected_command(&self) -> Option<Command> {
let curr = self let curr = self
.inner_tree .inner_tree
.get(*self.visit_stack.last().unwrap()) .get(*self.visit_stack.last().unwrap())
@ -375,7 +365,7 @@ impl CustomList {
idx += 1; idx += 1;
} }
if idx == selected { if idx == selected {
return Some(node.value().command); return Some(node.value().command.clone());
} }
} }
None None
@ -385,8 +375,9 @@ impl CustomList {
/// - Run a command, if it is the currently selected item, /// - Run a command, if it is the currently selected item,
/// - Go up a directory /// - Go up a directory
/// - Go down into a directory /// - Go down into a directory
///
/// Returns `Some(command)` when command is selected, othervise we returns `None` /// Returns `Some(command)` when command is selected, othervise we returns `None`
fn handle_enter(&mut self) -> Option<&'static str> { fn handle_enter(&mut self) -> Option<Command> {
// Get the current node (current directory) // Get the current node (current directory)
let curr = self let curr = self
.inner_tree .inner_tree
@ -414,7 +405,7 @@ impl CustomList {
self.list_state.select(Some(0)); self.list_state.select(Some(0));
return None; return None;
} else { } else {
return Some(node.value().command); return Some(node.value().command.clone());
} }
} }
} }

View File

@ -1,6 +1,7 @@
mod float; mod float;
mod list; mod list;
mod running_command; mod running_command;
pub mod state;
mod theme; mod theme;
use std::{ use std::{
@ -16,6 +17,7 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand, ExecutableCommand,
}; };
use include_dir::include_dir;
use list::CustomList; use list::CustomList;
use ratatui::{ use ratatui::{
backend::{Backend, CrosstermBackend}, backend::{Backend, CrosstermBackend},
@ -26,7 +28,9 @@ use ratatui::{
Terminal, Terminal,
}; };
use running_command::RunningCommand; use running_command::RunningCommand;
use theme::set_theme; use state::AppState;
use tempdir::TempDir;
use theme::THEMES;
/// This is a binary :), Chris, change this to update the documentation on -h /// This is a binary :), Chris, change this to update the documentation on -h
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -38,16 +42,29 @@ struct Args {
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
let args = Args::parse(); let args = Args::parse();
if args.compat {
set_theme(0); let theme = if args.compat {
} THEMES[0].clone()
} else {
THEMES[1].clone()
};
let commands_dir = include_dir!("src/commands");
let temp_dir: TempDir = TempDir::new("linutil_scripts").unwrap();
commands_dir
.extract(temp_dir.path())
.expect("Failed to extract the saved directory");
let state = AppState {
theme,
temp_path: temp_dir.path().to_owned(),
};
stdout().execute(EnterAlternateScreen)?; stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?; enable_raw_mode()?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear()?; terminal.clear()?;
run(&mut terminal)?; run(&mut terminal, &state)?;
// restore terminal // restore terminal
disable_raw_mode()?; disable_raw_mode()?;
@ -59,7 +76,7 @@ fn main() -> std::io::Result<()> {
Ok(()) Ok(())
} }
fn run<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> { fn run<B: Backend>(terminal: &mut Terminal<B>, state: &AppState) -> io::Result<()> {
let mut command_opt: Option<RunningCommand> = None; let mut command_opt: Option<RunningCommand> = None;
let mut custom_list = CustomList::new(); let mut custom_list = CustomList::new();
let mut search_input = String::new(); let mut search_input = String::new();
@ -100,10 +117,10 @@ fn run<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
//Render the search bar (First chunk of the screen) //Render the search bar (First chunk of the screen)
frame.render_widget(search_bar, chunks[0]); frame.render_widget(search_bar, chunks[0]);
//Render the command list (Second chunk of the screen) //Render the command list (Second chunk of the screen)
custom_list.draw(frame, chunks[1], search_input.clone()); custom_list.draw(frame, chunks[1], search_input.clone(),state);
if let Some(ref mut command) = &mut command_opt { if let Some(ref mut command) = &mut command_opt {
command.draw(frame); command.draw(frame, state);
} }
}) })
.unwrap(); .unwrap();
@ -128,28 +145,8 @@ fn run<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
if key.code == KeyCode::Char('q') { if key.code == KeyCode::Char('q') {
return Ok(()); return Ok(());
} }
//Activate search mode if the forward slash key gets pressed if let Some(cmd) = custom_list.handle_key(key, state) {
if key.code == KeyCode::Char('/') { command_opt = Some(RunningCommand::new(cmd, state));
// Enter search mode
in_search_mode = true;
continue;
}
//Insert user input into the search bar
if in_search_mode {
match key.code {
KeyCode::Char(c) => search_input.push(c),
KeyCode::Backspace => {
search_input.pop();
}
KeyCode::Esc => {
search_input = String::new();
in_search_mode = false
}
KeyCode::Enter => in_search_mode = false,
_ => {}
}
} else if let Some(cmd) = custom_list.handle_key(key) {
command_opt = Some(RunningCommand::new(cmd));
} }
} }
} }

View File

@ -11,7 +11,7 @@ use portable_pty::{
}; };
use ratatui::{ use ratatui::{
layout::Size, layout::Size,
style::{Color, Style, Stylize}, style::{Style, Stylize},
text::{Line, Span}, text::{Line, Span},
widgets::{Block, Borders}, widgets::{Block, Borders},
Frame, Frame,
@ -21,7 +21,14 @@ use tui_term::{
widget::PseudoTerminal, widget::PseudoTerminal,
}; };
use crate::{float::floating_window, theme::get_theme}; use crate::{float::floating_window, state::AppState};
#[derive(Clone)]
pub enum Command {
Raw(&'static str),
LocalFile(&'static str),
None, // Directory
}
/// This is a struct for storing everything connected to a running command /// This is a struct for storing everything connected to a running command
// Create a new instance on every new command you want to run // Create a new instance on every new command you want to run
@ -50,14 +57,22 @@ pub struct RunningCommand {
} }
impl RunningCommand { impl RunningCommand {
pub fn new(command: &str) -> Self { pub fn new(command: Command, state: &AppState) -> Self {
let pty_system = NativePtySystem::default(); let pty_system = NativePtySystem::default();
let mut cmd = CommandBuilder::new("sh");
cmd.arg("-c");
cmd.arg(command);
let cwd = std::env::current_dir().unwrap(); let mut cmd = CommandBuilder::new("sh");
cmd.cwd(cwd); match command {
Command::Raw(prompt) => {
cmd.arg("-c");
cmd.arg(prompt);
}
Command::LocalFile(file) => {
cmd.arg(file);
}
Command::None => panic!("Command::None was treated as a command"),
}
cmd.cwd(&state.temp_path);
let pair = pty_system let pair = pty_system
.openpty(PtySize { .openpty(PtySize {
@ -153,9 +168,7 @@ impl RunningCommand {
} }
} }
pub fn draw(&mut self, frame: &mut Frame) { pub fn draw(&mut self, frame: &mut Frame, state: &AppState) {
{
let theme = get_theme();
// Funny name // Funny name
let floater = floating_window(frame.size()); let floater = floating_window(frame.size());
@ -180,13 +193,13 @@ impl RunningCommand {
Line::from( Line::from(
Span::default() Span::default()
.content("SUCCESS!") .content("SUCCESS!")
.style(Style::default().fg(theme.success_color).reversed()), .style(Style::default().fg(state.theme.success_color).reversed()),
) )
} else { } else {
Line::from( Line::from(
Span::default() Span::default()
.content("FAILED!") .content("FAILED!")
.style(Style::default().fg(theme.fail_color).reversed()), .style(Style::default().fg(state.theme.fail_color).reversed()),
) )
}; };
@ -205,7 +218,7 @@ impl RunningCommand {
let pseudo_term = PseudoTerminal::new(&screen).block(term_border); let pseudo_term = PseudoTerminal::new(&screen).block(term_border);
frame.render_widget(pseudo_term, floater); frame.render_widget(pseudo_term, floater);
} }
}
/// Send SIGHUB signal, *not* SIGKILL or SIGTERM, to the child process /// Send SIGHUB signal, *not* SIGKILL or SIGTERM, to the child process
pub fn kill_child(&mut self) { pub fn kill_child(&mut self) {
if !self.is_finished() { if !self.is_finished() {

9
src/state.rs Normal file
View File

@ -0,0 +1,9 @@
use crate::theme::Theme;
use std::path::PathBuf;
pub struct AppState {
/// Selected theme
pub theme: Theme,
/// Path to the root of the unpacked files in /tmp
pub temp_path: PathBuf,
}

View File

@ -1,7 +1,6 @@
use ratatui::style::Color; use ratatui::style::Color;
pub static mut THEME_IDX: usize = 1; #[derive(Clone)]
pub struct Theme { pub struct Theme {
pub dir_color: Color, pub dir_color: Color,
pub cmd_color: Color, pub cmd_color: Color,
@ -29,11 +28,3 @@ pub const THEMES: [Theme; 2] = [
success_color: Color::Rgb(5, 255, 55), success_color: Color::Rgb(5, 255, 55),
}, },
]; ];
pub fn get_theme() -> &'static Theme {
&THEMES[unsafe { THEME_IDX }]
}
pub fn set_theme(idx: usize) {
unsafe { THEME_IDX = idx };
}