Skip to content

Commit 22d4e91

Browse files
feat: Add automation based on config file
1 parent 79eb752 commit 22d4e91

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed

core/src/config.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use serde::Deserialize;
2+
use std::path::Path;
3+
use std::process;
4+
5+
#[derive(Deserialize)]
6+
pub struct Config {
7+
pub auto_execute: Vec<String>,
8+
}
9+
10+
impl Config {
11+
pub fn from_file(path: &Path) -> Self {
12+
let content = match std::fs::read_to_string(path) {
13+
Ok(content) => content,
14+
Err(e) => {
15+
eprintln!("Failed to read config file {}: {}", path.display(), e);
16+
process::exit(1);
17+
}
18+
};
19+
20+
match toml::from_str(&content) {
21+
Ok(config) => config,
22+
Err(e) => {
23+
eprintln!("Failed to parse config file: {}", e);
24+
process::exit(1);
25+
}
26+
}
27+
}
28+
}

core/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
mod config;
12
mod inner;
23

34
use std::rc::Rc;
45

56
use ego_tree::Tree;
67
use std::path::PathBuf;
78

9+
pub use config::Config;
810
pub use inner::get_tabs;
911

1012
#[derive(Clone, Hash, Eq, PartialEq)]
@@ -33,3 +35,16 @@ pub struct ListNode {
3335
pub command: Command,
3436
pub task_list: String,
3537
}
38+
39+
impl Tab {
40+
pub fn find_command(&self, name: &str) -> Option<Rc<ListNode>> {
41+
self.tree.root().descendants().find_map(|node| {
42+
let value = node.value();
43+
if value.name == name && !node.has_children() {
44+
Some(value.clone())
45+
} else {
46+
None
47+
}
48+
})
49+
}
50+
}

tui/src/main.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod theme;
99

1010
use std::{
1111
io::{self, stdout},
12+
path::PathBuf,
1213
time::Duration,
1314
};
1415

@@ -26,6 +27,11 @@ use state::AppState;
2627
// Linux utility toolbox
2728
#[derive(Debug, Parser)]
2829
struct Args {
30+
#[arg(
31+
long,
32+
help = "Path to the configuration file for automatic command selection"
33+
)]
34+
config: Option<PathBuf>,
2935
#[arg(short, long, value_enum)]
3036
#[arg(default_value_t = Theme::Default)]
3137
#[arg(help = "Set the theme to use in the application")]
@@ -38,7 +44,7 @@ struct Args {
3844
fn main() -> io::Result<()> {
3945
let args = Args::parse();
4046

41-
let mut state = AppState::new(args.theme, args.override_validation);
47+
let mut state = AppState::new(args.theme, args.override_validation, args.config);
4248

4349
stdout().execute(EnterAlternateScreen)?;
4450
enable_raw_mode()?;

tui/src/state.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
};
1010
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
1111
use ego_tree::NodeId;
12+
use linutil_core::Config;
1213
use linutil_core::{ListNode, Tab};
1314
#[cfg(feature = "tips")]
1415
use rand::Rng;
@@ -19,6 +20,7 @@ use ratatui::{
1920
widgets::{Block, Borders, List, ListState, Paragraph},
2021
Frame,
2122
};
23+
use std::path::PathBuf;
2224
use std::rc::Rc;
2325
use temp_dir::TempDir;
2426

@@ -60,6 +62,7 @@ pub struct AppState {
6062
multi_select: bool,
6163
selected_commands: Vec<Rc<ListNode>>,
6264
drawable: bool,
65+
auto_execute: Option<Vec<String>>,
6366
#[cfg(feature = "tips")]
6467
tip: &'static str,
6568
}
@@ -79,10 +82,12 @@ pub struct ListEntry {
7982
}
8083

8184
impl AppState {
82-
pub fn new(theme: Theme, override_validation: bool) -> Self {
85+
pub fn new(theme: Theme, override_validation: bool, config_path: Option<PathBuf>) -> Self {
8386
let (temp_dir, tabs) = linutil_core::get_tabs(!override_validation);
8487
let root_id = tabs[0].tree.root().id();
8588

89+
let auto_execute = config_path.map(|path| Config::from_file(&path).auto_execute);
90+
8691
let mut state = Self {
8792
_temp_dir: temp_dir,
8893
theme,
@@ -95,14 +100,38 @@ impl AppState {
95100
multi_select: false,
96101
selected_commands: Vec::new(),
97102
drawable: false,
103+
auto_execute,
98104
#[cfg(feature = "tips")]
99105
tip: get_random_tip(),
100106
};
101107

102108
state.update_items();
109+
110+
if let Some(auto_execute) = state.auto_execute.clone() {
111+
state.handle_initial_auto_execute(&auto_execute);
112+
}
113+
103114
state
104115
}
105116

117+
fn handle_initial_auto_execute(&mut self, auto_execute: &[String]) {
118+
self.selected_commands = auto_execute
119+
.iter()
120+
.filter_map(|name| self.tabs.iter().find_map(|tab| tab.find_command(name)))
121+
.collect();
122+
123+
if !self.selected_commands.is_empty() {
124+
let cmd_names: Vec<_> = self
125+
.selected_commands
126+
.iter()
127+
.map(|node| node.name.as_str())
128+
.collect();
129+
130+
let prompt = ConfirmPrompt::new(&cmd_names);
131+
self.focus = Focus::ConfirmationPrompt(Float::new(Box::new(prompt), 40, 40));
132+
}
133+
}
134+
106135
fn get_list_item_shortcut(&self) -> Box<[Shortcut]> {
107136
if self.selected_item_is_dir() {
108137
Box::new([Shortcut::new("Go to selected dir", ["l", "Right", "Enter"])])

0 commit comments

Comments
 (0)