mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2025-04-20 10:53:06 +01:00
Merge f28e0855b6c0e4747637cb5706e3154a5113ed51 into efa6ff9cd2eb77204028de361be008a68338aeb8
This commit is contained in:
commit
0999c9f384
23
README.md
23
README.md
@ -27,25 +27,18 @@ curl -fsSL https://christitus.com/linuxdev | sh
|
||||
|
||||
### CLI arguments
|
||||
|
||||
Linutil supports various command-line arguments to customize its behavior. Here are some common arguments you can use:
|
||||
|
||||
- `-c, --config <CONFIG>` : Path to the configuration file.
|
||||
- `--override-validation` : Show all available options, disregarding compatibility checks (UNSAFE).
|
||||
- `--size-bypass` : Bypass the terminal size limit.
|
||||
- `-y, --skip-confirmation` : Skip confirmation prompt before executing commands.
|
||||
- `-t, --theme <THEME>` : Set the theme to use in the application [default: `default`] [possible values: `default`, `compatible`].
|
||||
- `-h, --help` : Print help.
|
||||
|
||||
For more detailed usage, run:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://christitus.com/linux | sh -s -- --help
|
||||
```
|
||||
View available options by running:
|
||||
|
||||
```bash
|
||||
linutil --help
|
||||
```
|
||||
|
||||
For installer options:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://christitus.com/linux | sh -s -- --help
|
||||
```
|
||||
|
||||
## ⬇️ Installation
|
||||
|
||||
Linutil is also available as a package in various repositories:
|
||||
@ -142,7 +135,7 @@ Docs are now [here](https://github.com/Chris-Titus-Docs/linutil-docs)
|
||||
|
||||
## 🏅 Thanks to All Contributors
|
||||
|
||||
Thank you to everyone who has contributed to the development of Linutil. Your efforts are greatly appreciated, and you’re helping make this tool better for everyone!
|
||||
Thank you to everyone who has contributed to the development of Linutil. Your efforts are greatly appreciated, and you're helping make this tool better for everyone!
|
||||
|
||||
[](https://github.com/ChrisTitusTech/linutil/graphs/contributors)
|
||||
|
||||
|
@ -120,7 +120,7 @@ enum EntryType {
|
||||
|
||||
impl Entry {
|
||||
fn is_supported(&self) -> bool {
|
||||
self.preconditions.as_deref().map_or(true, |preconditions| {
|
||||
self.preconditions.as_deref().is_none_or(|preconditions| {
|
||||
preconditions.iter().all(
|
||||
|Precondition {
|
||||
matches,
|
||||
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@ -0,0 +1 @@
|
||||
imports_granularity = "Crate"
|
@ -14,7 +14,7 @@ default = ["tips"]
|
||||
tips = ["rand"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.20", features = ["derive", "std"], default-features = false }
|
||||
clap = { version = "4.5.20", features = ["derive", "std", "help", "usage"], default-features = false }
|
||||
oneshot = { version = "0.1.8", features = ["std"], default-features = false }
|
||||
portable-pty = "0.8.1"
|
||||
ratatui = { version = "0.29.0", features = ["crossterm"], default-features = false }
|
||||
|
35
tui/src/cli.rs
Normal file
35
tui/src/cli.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use crate::theme::Theme;
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser, Clone)]
|
||||
pub struct Args {
|
||||
/// Path to the configuration file
|
||||
#[arg(short, long)]
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
/// Set the theme to use in the application
|
||||
#[arg(short, long, value_enum)]
|
||||
#[arg(default_value_t = Theme::Default)]
|
||||
pub theme: Theme,
|
||||
|
||||
/// Skip confirmation prompt before executing commands
|
||||
#[arg(short = 'y', long)]
|
||||
pub skip_confirmation: bool,
|
||||
|
||||
/// Show all available options, disregarding compatibility checks (UNSAFE)
|
||||
#[arg(short = 'u', long)]
|
||||
pub override_validation: bool,
|
||||
|
||||
/// Bypass the terminal size limit
|
||||
#[arg(short = 's', long)]
|
||||
pub size_bypass: bool,
|
||||
|
||||
/// Enable mouse interaction
|
||||
#[arg(short = 'm', long)]
|
||||
pub mouse: bool,
|
||||
|
||||
/// Bypass root user check
|
||||
#[arg(short = 'r', long)]
|
||||
pub bypass_root: bool,
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod cli;
|
||||
mod confirmation;
|
||||
mod filter;
|
||||
mod float;
|
||||
@ -11,7 +12,7 @@ mod theme;
|
||||
#[cfg(feature = "tips")]
|
||||
mod tips;
|
||||
|
||||
use crate::theme::Theme;
|
||||
use crate::cli::Args;
|
||||
use clap::Parser;
|
||||
use ratatui::{
|
||||
backend::CrosstermBackend,
|
||||
@ -26,40 +27,17 @@ use ratatui::{
|
||||
use state::AppState;
|
||||
use std::{
|
||||
io::{stdout, Result, Stdout},
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
// Linux utility toolbox
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[arg(short, long, help = "Path to the configuration file")]
|
||||
config: Option<PathBuf>,
|
||||
#[arg(short, long, value_enum)]
|
||||
#[arg(default_value_t = Theme::Default)]
|
||||
#[arg(help = "Set the theme to use in the application")]
|
||||
theme: Theme,
|
||||
#[arg(
|
||||
short = 'y',
|
||||
long,
|
||||
help = "Skip confirmation prompt before executing commands"
|
||||
)]
|
||||
skip_confirmation: bool,
|
||||
#[arg(long, default_value_t = false)]
|
||||
#[clap(help = "Show all available options, disregarding compatibility checks (UNSAFE)")]
|
||||
override_validation: bool,
|
||||
#[arg(long, default_value_t = false)]
|
||||
#[clap(help = "Bypass the terminal size limit")]
|
||||
size_bypass: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut state = AppState::new(args);
|
||||
let mut state = AppState::new(args.clone());
|
||||
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
stdout().execute(EnableMouseCapture)?;
|
||||
if args.mouse {
|
||||
stdout().execute(EnableMouseCapture)?;
|
||||
}
|
||||
|
||||
enable_raw_mode()?;
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
|
||||
@ -70,7 +48,9 @@ fn main() -> Result<()> {
|
||||
// restore terminal
|
||||
disable_raw_mode()?;
|
||||
terminal.backend_mut().execute(LeaveAlternateScreen)?;
|
||||
terminal.backend_mut().execute(DisableMouseCapture)?;
|
||||
if args.mouse {
|
||||
terminal.backend_mut().execute(DisableMouseCapture)?;
|
||||
}
|
||||
terminal.backend_mut().execute(ResetColor)?;
|
||||
terminal.show_cursor()?;
|
||||
|
||||
|
@ -8,8 +8,12 @@ This means you have full system access and commands can potentially damage your
|
||||
Please proceed with caution and make sure you understand what each script does before executing it.";
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn check_root_status<'a>() -> Option<FloatingText<'a>> {
|
||||
(Uid::effective().is_root()).then_some(FloatingText::new(
|
||||
pub fn check_root_status(bypass_root: bool) -> Option<FloatingText<'static>> {
|
||||
if bypass_root {
|
||||
return None;
|
||||
}
|
||||
|
||||
Uid::effective().is_root().then_some(FloatingText::new(
|
||||
ROOT_WARNING.into(),
|
||||
"Root User Warning",
|
||||
true,
|
||||
|
@ -66,6 +66,7 @@ pub struct AppState {
|
||||
tip: &'static str,
|
||||
size_bypass: bool,
|
||||
skip_confirmation: bool,
|
||||
mouse_enabled: bool,
|
||||
}
|
||||
|
||||
pub enum Focus {
|
||||
@ -94,8 +95,18 @@ enum SelectedItem {
|
||||
None,
|
||||
}
|
||||
|
||||
enum ScrollDir {
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(args: Args) -> Self {
|
||||
#[cfg(unix)]
|
||||
let root_warning = check_root_status(args.bypass_root);
|
||||
#[cfg(not(unix))]
|
||||
let root_warning = None;
|
||||
|
||||
let tabs = linutil_core::get_tabs(!args.override_validation);
|
||||
let root_id = tabs[0].tree.root().id();
|
||||
|
||||
@ -122,10 +133,11 @@ impl AppState {
|
||||
tip: crate::tips::get_random_tip(),
|
||||
size_bypass: args.size_bypass,
|
||||
skip_confirmation: args.skip_confirmation,
|
||||
mouse_enabled: args.mouse,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
if let Some(root_warning) = check_root_status() {
|
||||
if let Some(root_warning) = root_warning {
|
||||
state.spawn_float(root_warning, FLOAT_SIZE, FLOAT_SIZE);
|
||||
}
|
||||
|
||||
@ -440,6 +452,10 @@ impl AppState {
|
||||
}
|
||||
|
||||
pub fn handle_mouse(&mut self, event: &MouseEvent) -> bool {
|
||||
if !self.mouse_enabled {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.drawable {
|
||||
return true;
|
||||
}
|
||||
@ -597,24 +613,35 @@ impl AppState {
|
||||
true
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self) {
|
||||
if let Some(selected) = self.selection.selected() {
|
||||
if selected == self.filter.item_list().len() - 1 {
|
||||
self.selection.select_first();
|
||||
} else {
|
||||
self.selection.select_next();
|
||||
}
|
||||
}
|
||||
fn scroll(&mut self, direction: ScrollDir) {
|
||||
let Some(selected) = self.selection.selected() else {
|
||||
return;
|
||||
};
|
||||
let list_len = if !self.at_root() {
|
||||
self.filter.item_list().len() + 1
|
||||
} else {
|
||||
self.filter.item_list().len()
|
||||
};
|
||||
|
||||
if list_len == 0 {
|
||||
return;
|
||||
};
|
||||
|
||||
let next_selection = match direction {
|
||||
ScrollDir::Up if selected == 0 => list_len - 1,
|
||||
ScrollDir::Down if selected >= list_len - 1 => 0,
|
||||
ScrollDir::Up => selected - 1,
|
||||
ScrollDir::Down => selected + 1,
|
||||
};
|
||||
self.selection.select(Some(next_selection));
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
if let Some(selected) = self.selection.selected() {
|
||||
if selected == 0 {
|
||||
self.selection.select_last();
|
||||
} else {
|
||||
self.selection.select_previous();
|
||||
}
|
||||
}
|
||||
self.scroll(ScrollDir::Up)
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self) {
|
||||
self.scroll(ScrollDir::Down)
|
||||
}
|
||||
|
||||
fn toggle_multi_select(&mut self) {
|
||||
|
@ -2,8 +2,7 @@ use std::fs;
|
||||
|
||||
use linutil_core::Command;
|
||||
|
||||
use crate::path;
|
||||
use crate::DynError;
|
||||
use crate::{path, DynError};
|
||||
|
||||
pub const USER_GUIDE: &str = "userguide.md";
|
||||
|
||||
|
@ -6,9 +6,10 @@ use std::{env, error::Error};
|
||||
type DynError = Box<dyn Error>;
|
||||
|
||||
pub mod tasks {
|
||||
use crate::docgen::USER_GUIDE;
|
||||
use crate::docgen::{userguide, write};
|
||||
use crate::DynError;
|
||||
use crate::{
|
||||
docgen::{userguide, write, USER_GUIDE},
|
||||
DynError,
|
||||
};
|
||||
|
||||
pub fn docgen() -> Result<(), DynError> {
|
||||
write(USER_GUIDE, &userguide()?);
|
||||
|
Loading…
x
Reference in New Issue
Block a user