mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-11-21 21:09:42 +00:00
Merge pull request #274 from lj3954/restructure_linutil
refactor: Split linutil into TUI and Core crates
This commit is contained in:
commit
7104991472
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -86,9 +86,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.87"
|
||||
version = "1.0.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
|
||||
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
|
@ -450,6 +450,34 @@ version = "0.2.158"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "linutil_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ego-tree",
|
||||
"include_dir",
|
||||
"serde",
|
||||
"tempdir",
|
||||
"toml",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linutil_tui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"ego-tree",
|
||||
"linutil_core",
|
||||
"oneshot",
|
||||
"portable-pty",
|
||||
"ratatui",
|
||||
"tui-term",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
|
@ -678,9 +706,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
@ -696,9 +724,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.36"
|
||||
version = "0.38.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
|
@ -972,26 +1000,6 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"ego-tree",
|
||||
"include_dir",
|
||||
"oneshot",
|
||||
"portable-pty",
|
||||
"ratatui",
|
||||
"serde",
|
||||
"tempdir",
|
||||
"toml",
|
||||
"tui-term",
|
||||
"unicode-width",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tui-term"
|
||||
version = "0.1.13"
|
||||
|
@ -1004,9 +1012,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
|
|
32
Cargo.toml
32
Cargo.toml
|
@ -1,34 +1,16 @@
|
|||
[package]
|
||||
name = "tui"
|
||||
[workspace.package]
|
||||
license = "MIT"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.16", features = ["derive"] }
|
||||
crossterm = "0.28.1"
|
||||
[workspace.dependencies]
|
||||
ego-tree = "0.6.2"
|
||||
oneshot = "0.1.8"
|
||||
portable-pty = "0.8.1"
|
||||
ratatui = "0.28.1"
|
||||
tui-term = "0.1.12"
|
||||
include_dir = "0.7.4"
|
||||
tempdir = "0.3.7"
|
||||
serde = { version = "1.0.205", features = ["derive"] }
|
||||
toml = "0.8.19"
|
||||
which = "6.0.3"
|
||||
unicode-width = "0.1.13"
|
||||
|
||||
[build-dependencies]
|
||||
chrono = "0.4.33"
|
||||
|
||||
[[bin]]
|
||||
name = "linutil"
|
||||
path = "src/main.rs"
|
||||
|
||||
|
||||
[workspace]
|
||||
members = ["tui", "core"]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
opt-level = "z"
|
||||
debug = false
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
|
|
12
build.rs
12
build.rs
|
@ -1,12 +0,0 @@
|
|||
fn main() {
|
||||
// Rebuild program if any file in commands directory changes.
|
||||
println!("cargo:rerun-if-changed=src/commands");
|
||||
// Rerun build script if any code is modified
|
||||
println!("cargo:rerun-if-changed=src");
|
||||
|
||||
// Add current date as a variable to be displayed in the 'Linux Toolbox' text.
|
||||
println!(
|
||||
"cargo:rustc-env=BUILD_DATE={}",
|
||||
chrono::Local::now().format("%Y-%m-%d")
|
||||
);
|
||||
}
|
13
core/Cargo.toml
Normal file
13
core/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "linutil_core"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
include_dir = "0.7.4"
|
||||
tempdir = "0.3.7"
|
||||
serde = { version = "1.0.205", features = ["derive"] }
|
||||
toml = "0.8.19"
|
||||
which = "6.0.3"
|
||||
ego-tree = { workspace = true }
|
|
@ -1,7 +1,42 @@
|
|||
use crate::running_command::Command;
|
||||
use crate::{Command, ListNode, Tab};
|
||||
use ego_tree::{NodeMut, Tree};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use serde::Deserialize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempdir::TempDir;
|
||||
|
||||
const TAB_DATA: Dir = include_dir!("$CARGO_MANIFEST_DIR/../tabs");
|
||||
|
||||
pub fn get_tabs(validate: bool) -> Vec<Tab> {
|
||||
let tab_files = TabList::get_tabs();
|
||||
let tabs = tab_files.into_iter().map(|path| {
|
||||
let directory = path.parent().unwrap().to_owned();
|
||||
let data = std::fs::read_to_string(path).expect("Failed to read tab data");
|
||||
let mut tab_data: TabEntry = toml::from_str(&data).expect("Failed to parse tab data");
|
||||
|
||||
if validate {
|
||||
filter_entries(&mut tab_data.data);
|
||||
}
|
||||
(tab_data, directory)
|
||||
});
|
||||
|
||||
let tabs: Vec<Tab> = tabs
|
||||
.map(|(TabEntry { name, data }, directory)| {
|
||||
let mut tree = Tree::new(ListNode {
|
||||
name: "root".to_string(),
|
||||
command: Command::None,
|
||||
});
|
||||
let mut root = tree.root_mut();
|
||||
create_directory(data, &mut root, &directory);
|
||||
Tab { name, tree }
|
||||
})
|
||||
.collect();
|
||||
|
||||
if tabs.is_empty() {
|
||||
panic!("No tabs found");
|
||||
}
|
||||
tabs
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TabList {
|
||||
|
@ -79,49 +114,6 @@ enum SystemDataType {
|
|||
CommandExists,
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
pub struct Tab {
|
||||
pub name: String,
|
||||
pub tree: Tree<ListNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct ListNode {
|
||||
pub name: String,
|
||||
pub command: Command,
|
||||
}
|
||||
|
||||
pub fn get_tabs(command_dir: &Path, validate: bool) -> Vec<Tab> {
|
||||
let tab_files = TabList::get_tabs(command_dir);
|
||||
let tabs = tab_files.into_iter().map(|path| {
|
||||
let directory = path.parent().unwrap().to_owned();
|
||||
let data = std::fs::read_to_string(path).expect("Failed to read tab data");
|
||||
let mut tab_data: TabEntry = toml::from_str(&data).expect("Failed to parse tab data");
|
||||
|
||||
if validate {
|
||||
filter_entries(&mut tab_data.data);
|
||||
}
|
||||
(tab_data, directory)
|
||||
});
|
||||
|
||||
let tabs: Vec<Tab> = tabs
|
||||
.map(|(TabEntry { name, data }, directory)| {
|
||||
let mut tree = Tree::new(ListNode {
|
||||
name: "root".to_string(),
|
||||
command: Command::None,
|
||||
});
|
||||
let mut root = tree.root_mut();
|
||||
create_directory(data, &mut root, &directory);
|
||||
Tab { name, tree }
|
||||
})
|
||||
.collect();
|
||||
|
||||
if tabs.is_empty() {
|
||||
panic!("No tabs found");
|
||||
}
|
||||
tabs
|
||||
}
|
||||
|
||||
fn filter_entries(entries: &mut Vec<Entry>) {
|
||||
entries.retain_mut(|entry| {
|
||||
if !entry.is_supported() {
|
||||
|
@ -176,15 +168,21 @@ fn create_directory(data: Vec<Entry>, node: &mut NodeMut<ListNode>, command_dir:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TabList {
|
||||
fn get_tabs(command_dir: &Path) -> Vec<PathBuf> {
|
||||
let tab_files = std::fs::read_to_string(command_dir.join("tabs.toml"))
|
||||
.expect("Failed to read tabs.toml");
|
||||
fn get_tabs() -> Vec<PathBuf> {
|
||||
let temp_dir = TempDir::new("linutil_scripts").unwrap().into_path();
|
||||
TAB_DATA
|
||||
.extract(&temp_dir)
|
||||
.expect("Failed to extract the saved directory");
|
||||
|
||||
let tab_files =
|
||||
std::fs::read_to_string(temp_dir.join("tabs.toml")).expect("Failed to read tabs.toml");
|
||||
let data: Self = toml::from_str(&tab_files).expect("Failed to parse tabs.toml");
|
||||
|
||||
data.directories
|
||||
.into_iter()
|
||||
.map(|path| command_dir.join(path).join("tab_data.toml"))
|
||||
.iter()
|
||||
.map(|path| temp_dir.join(path).join("tab_data.toml"))
|
||||
.collect()
|
||||
}
|
||||
}
|
25
core/src/lib.rs
Normal file
25
core/src/lib.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
mod inner;
|
||||
|
||||
use ego_tree::Tree;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use inner::get_tabs;
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub enum Command {
|
||||
Raw(String),
|
||||
LocalFile(PathBuf),
|
||||
None, // Directory
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct Tab {
|
||||
pub name: String,
|
||||
pub tree: Tree<ListNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct ListNode {
|
||||
pub name: String,
|
||||
pub command: Command,
|
||||
}
|
23
tui/Cargo.toml
Normal file
23
tui/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "linutil_tui"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.16", features = ["derive"] }
|
||||
crossterm = "0.28.1"
|
||||
ego-tree = { workspace = true }
|
||||
oneshot = "0.1.8"
|
||||
portable-pty = "0.8.1"
|
||||
ratatui = "0.28.1"
|
||||
tui-term = "0.1.12"
|
||||
unicode-width = "0.1.13"
|
||||
linutil_core = { path = "../core" }
|
||||
|
||||
[build-dependencies]
|
||||
chrono = "0.4.33"
|
||||
|
||||
[[bin]]
|
||||
name = "linutil"
|
||||
path = "src/main.rs"
|
7
tui/build.rs
Normal file
7
tui/build.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
// Add current date as a variable to be displayed in the 'Linux Toolbox' text.
|
||||
println!(
|
||||
"cargo:rustc-env=BUILD_DATE={}",
|
||||
chrono::Local::now().format("%Y-%m-%d")
|
||||
);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{state::ListEntry, tabs::Tab, theme::Theme};
|
||||
use crate::{state::ListEntry, theme::Theme};
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use ego_tree::NodeId;
|
||||
use linutil_core::Tab;
|
||||
use ratatui::{
|
||||
layout::{Position, Rect},
|
||||
style::Style,
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{
|
||||
float::FloatContent,
|
||||
hint::{Shortcut, ShortcutList},
|
||||
running_command::Command,
|
||||
};
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use linutil_core::Command;
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
style::{Style, Stylize},
|
|
@ -4,7 +4,6 @@ mod floating_text;
|
|||
mod hint;
|
||||
mod running_command;
|
||||
pub mod state;
|
||||
mod tabs;
|
||||
mod theme;
|
||||
|
||||
use std::{
|
||||
|
@ -21,13 +20,11 @@ use crossterm::{
|
|||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
};
|
||||
use include_dir::include_dir;
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
Terminal,
|
||||
};
|
||||
use state::AppState;
|
||||
use tempdir::TempDir;
|
||||
|
||||
// Linux utility toolbox
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -44,13 +41,7 @@ struct Args {
|
|||
fn main() -> std::io::Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
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 mut state = AppState::new(args.theme, temp_dir.path(), args.override_validation);
|
||||
let mut state = AppState::new(args.theme, args.override_validation);
|
||||
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
|
@ -3,6 +3,7 @@ use crate::{
|
|||
hint::{Shortcut, ShortcutList},
|
||||
};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use linutil_core::Command;
|
||||
use oneshot::{channel, Receiver};
|
||||
use portable_pty::{
|
||||
ChildKiller, CommandBuilder, ExitStatus, MasterPty, NativePtySystem, PtySize, PtySystem,
|
||||
|
@ -16,7 +17,6 @@ use ratatui::{
|
|||
};
|
||||
use std::{
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
thread::JoinHandle,
|
||||
};
|
||||
|
@ -25,13 +25,6 @@ use tui_term::{
|
|||
widget::PseudoTerminal,
|
||||
};
|
||||
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub enum Command {
|
||||
Raw(String),
|
||||
LocalFile(PathBuf),
|
||||
None, // Directory
|
||||
}
|
||||
|
||||
pub struct RunningCommand {
|
||||
/// A buffer to save all the command output (accumulates, until the command exits)
|
||||
buffer: Arc<Mutex<Vec<u8>>>,
|
|
@ -3,12 +3,12 @@ use crate::{
|
|||
float::{Float, FloatContent},
|
||||
floating_text::FloatingText,
|
||||
hint::{draw_shortcuts, SHORTCUT_LINES},
|
||||
running_command::{Command, RunningCommand},
|
||||
tabs::{ListNode, Tab},
|
||||
running_command::RunningCommand,
|
||||
theme::Theme,
|
||||
};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
|
||||
use ego_tree::NodeId;
|
||||
use linutil_core::{Command, ListNode, Tab};
|
||||
use ratatui::{
|
||||
layout::{Alignment, Constraint, Direction, Layout},
|
||||
style::{Style, Stylize},
|
||||
|
@ -16,7 +16,6 @@ use ratatui::{
|
|||
widgets::{Block, Borders, List, ListState, Paragraph},
|
||||
Frame,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
pub struct AppState {
|
||||
/// Selected theme
|
||||
|
@ -50,8 +49,8 @@ pub struct ListEntry {
|
|||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(theme: Theme, temp_path: &Path, override_validation: bool) -> Self {
|
||||
let tabs = crate::tabs::get_tabs(temp_path, !override_validation);
|
||||
pub fn new(theme: Theme, override_validation: bool) -> Self {
|
||||
let tabs = linutil_core::get_tabs(!override_validation);
|
||||
let root_id = tabs[0].tree.root().id();
|
||||
let mut state = Self {
|
||||
theme,
|
Loading…
Reference in New Issue
Block a user