Compare commits

...

3 Commits

Author SHA1 Message Date
JEEVITHA KANNAN K S
2e10ad471e
Merge 4dbcca736d into 696110eae5 2024-10-26 06:59:36 +05:30
Adam Perkowski
696110eae5
refact(release): better categories (#876) 2024-10-25 15:44:41 -05:00
Jeevitha Kannan K S
4dbcca736d
feat: Add automation based on config file 2024-10-16 01:13:50 +05:30
5 changed files with 88 additions and 10 deletions

19
.github/release.yml vendored
View File

@ -1,20 +1,23 @@
changelog: changelog:
categories: categories:
- title: '🚀 Features' - title: '🚀 Features'
labels: label: 'enhancement'
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes' - title: '🐛 Bug Fixes'
labels: label: 'bug'
- 'fix' - title: '⚙️ Refactoring'
- 'bugfix' label: 'refactor'
- 'bug' - title: '🧩 UI/UX'
label: 'UI/UX'
- title: '📚 Documentation' - title: '📚 Documentation'
label: 'documentation' label: 'documentation'
- title: '🔒 Security' - title: '🔒 Security'
label: 'security' label: 'security'
- title: '🧰 GitHub Actions' - title: '🧰 GitHub Actions'
label: 'github actions' label: 'github_actions'
- title: '🦀 Rust'
label: 'rust'
- title: '📃 Scripting'
label: 'script'
exclude: exclude:
labels: labels:
- 'skip-changelog' - 'skip-changelog'

28
core/src/config.rs Normal file
View File

@ -0,0 +1,28 @@
use serde::Deserialize;
use std::path::Path;
use std::process;
#[derive(Deserialize)]
pub struct Config {
pub auto_execute: Vec<String>,
}
impl Config {
pub fn from_file(path: &Path) -> Self {
let content = match std::fs::read_to_string(path) {
Ok(content) => content,
Err(e) => {
eprintln!("Failed to read config file {}: {}", path.display(), e);
process::exit(1);
}
};
match toml::from_str(&content) {
Ok(config) => config,
Err(e) => {
eprintln!("Failed to parse config file: {}", e);
process::exit(1);
}
}
}
}

View File

@ -1,3 +1,4 @@
mod config;
mod inner; mod inner;
use std::rc::Rc; use std::rc::Rc;
@ -5,6 +6,7 @@ use std::rc::Rc;
use ego_tree::Tree; use ego_tree::Tree;
use std::path::PathBuf; use std::path::PathBuf;
pub use config::Config;
pub use inner::get_tabs; pub use inner::get_tabs;
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
@ -33,3 +35,16 @@ pub struct ListNode {
pub command: Command, pub command: Command,
pub task_list: String, pub task_list: String,
} }
impl Tab {
pub fn find_command(&self, name: &str) -> Option<Rc<ListNode>> {
self.tree.root().descendants().find_map(|node| {
let value = node.value();
if value.name == name && !node.has_children() {
Some(value.clone())
} else {
None
}
})
}
}

View File

@ -9,6 +9,7 @@ mod theme;
use std::{ use std::{
io::{self, stdout}, io::{self, stdout},
path::PathBuf,
time::Duration, time::Duration,
}; };
@ -26,6 +27,11 @@ use state::AppState;
// Linux utility toolbox // Linux utility toolbox
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
struct Args { struct Args {
#[arg(
long,
help = "Path to the configuration file for automatic command selection"
)]
config: Option<PathBuf>,
#[arg(short, long, value_enum)] #[arg(short, long, value_enum)]
#[arg(default_value_t = Theme::Default)] #[arg(default_value_t = Theme::Default)]
#[arg(help = "Set the theme to use in the application")] #[arg(help = "Set the theme to use in the application")]
@ -38,7 +44,7 @@ struct Args {
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
let args = Args::parse(); let args = Args::parse();
let mut state = AppState::new(args.theme, args.override_validation); let mut state = AppState::new(args.theme, args.override_validation, args.config);
stdout().execute(EnterAlternateScreen)?; stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?; enable_raw_mode()?;

View File

@ -9,6 +9,7 @@ use crate::{
}; };
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use ego_tree::NodeId; use ego_tree::NodeId;
use linutil_core::Config;
use linutil_core::{ListNode, Tab}; use linutil_core::{ListNode, Tab};
#[cfg(feature = "tips")] #[cfg(feature = "tips")]
use rand::Rng; use rand::Rng;
@ -19,6 +20,7 @@ use ratatui::{
widgets::{Block, Borders, List, ListState, Paragraph}, widgets::{Block, Borders, List, ListState, Paragraph},
Frame, Frame,
}; };
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use temp_dir::TempDir; use temp_dir::TempDir;
@ -79,10 +81,12 @@ pub struct ListEntry {
} }
impl AppState { impl AppState {
pub fn new(theme: Theme, override_validation: bool) -> Self { pub fn new(theme: Theme, override_validation: bool, config_path: Option<PathBuf>) -> Self {
let (temp_dir, tabs) = linutil_core::get_tabs(!override_validation); let (temp_dir, tabs) = linutil_core::get_tabs(!override_validation);
let root_id = tabs[0].tree.root().id(); let root_id = tabs[0].tree.root().id();
let auto_execute_commands = config_path.map(|path| Config::from_file(&path).auto_execute);
let mut state = Self { let mut state = Self {
_temp_dir: temp_dir, _temp_dir: temp_dir,
theme, theme,
@ -100,9 +104,31 @@ impl AppState {
}; };
state.update_items(); state.update_items();
if let Some(auto_execute_commands) = auto_execute_commands {
state.handle_initial_auto_execute(&auto_execute_commands);
}
state state
} }
fn handle_initial_auto_execute(&mut self, auto_execute_commands: &[String]) {
self.selected_commands = auto_execute_commands
.iter()
.filter_map(|name| self.tabs.iter().find_map(|tab| tab.find_command(name)))
.collect();
if !self.selected_commands.is_empty() {
let cmd_names: Vec<_> = self
.selected_commands
.iter()
.map(|node| node.name.as_str())
.collect();
let prompt = ConfirmPrompt::new(&cmd_names);
self.focus = Focus::ConfirmationPrompt(Float::new(Box::new(prompt), 40, 40));
}
}
fn get_list_item_shortcut(&self) -> Box<[Shortcut]> { fn get_list_item_shortcut(&self) -> Box<[Shortcut]> {
if self.selected_item_is_dir() { if self.selected_item_is_dir() {
Box::new([Shortcut::new("Go to selected dir", ["l", "Right", "Enter"])]) Box::new([Shortcut::new("Go to selected dir", ["l", "Right", "Enter"])])