mirror of
https://github.com/TECHNOFAB11/pay-respects.git
synced 2025-12-12 22:40:09 +01:00
refactor: data passing
This commit is contained in:
parent
94d011cdd1
commit
dae09adb76
5 changed files with 313 additions and 241 deletions
12
src/args.rs
12
src/args.rs
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::shell::initialization;
|
use crate::shell::initialization;
|
||||||
|
|
||||||
pub fn handle_args() {
|
// returns true if should exit
|
||||||
|
pub fn handle_args() -> bool {
|
||||||
let args = std::env::args().collect::<Vec<String>>();
|
let args = std::env::args().collect::<Vec<String>>();
|
||||||
if args.len() <= 1 {
|
if args.len() <= 1 {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
let mut auto_aliasing = String::new();
|
let mut auto_aliasing = String::new();
|
||||||
let mut shell = String::new();
|
let mut shell = String::new();
|
||||||
|
|
@ -13,9 +14,11 @@ pub fn handle_args() {
|
||||||
match args[index].as_str() {
|
match args[index].as_str() {
|
||||||
"-h" | "--help" => {
|
"-h" | "--help" => {
|
||||||
print_help();
|
print_help();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
"-v" | "--version" => {
|
"-v" | "--version" => {
|
||||||
print_version();
|
print_version();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
"-a" | "--alias" => {
|
"-a" | "--alias" => {
|
||||||
if args.len() > index + 1 {
|
if args.len() > index + 1 {
|
||||||
|
|
@ -43,12 +46,13 @@ pub fn handle_args() {
|
||||||
|
|
||||||
if shell.is_empty() {
|
if shell.is_empty() {
|
||||||
eprintln!("{}", t!("no-shell"));
|
eprintln!("{}", t!("no-shell"));
|
||||||
std::process::exit(1);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let binary_path = &args[0];
|
let binary_path = &args[0];
|
||||||
|
|
||||||
initialization(&shell, binary_path, &auto_aliasing, cnf);
|
initialization(&shell, binary_path, &auto_aliasing, cnf);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_help() {
|
fn print_help() {
|
||||||
|
|
@ -63,7 +67,6 @@ fn print_help() {
|
||||||
auto_example_fish = "pay-respects fish --alias | source",
|
auto_example_fish = "pay-respects fish --alias | source",
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
std::process::exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_version() {
|
fn print_version() {
|
||||||
|
|
@ -84,5 +87,4 @@ fn print_version() {
|
||||||
{
|
{
|
||||||
println!(" - libcurl");
|
println!(" - libcurl");
|
||||||
}
|
}
|
||||||
std::process::exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
41
src/main.rs
41
src/main.rs
|
|
@ -37,9 +37,28 @@ mod requests;
|
||||||
extern crate rust_i18n;
|
extern crate rust_i18n;
|
||||||
i18n!("i18n", fallback = "en", minify_key = true);
|
i18n!("i18n", fallback = "en", minify_key = true);
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), std::io::Error>{
|
||||||
colored::control::set_override(true);
|
colored::control::set_override(true);
|
||||||
// let locale = std::env::var("LANG").unwrap_or("en_US".to_string());
|
let mut data = {
|
||||||
|
let init = init();
|
||||||
|
if init.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
init.unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
data.expand_command();
|
||||||
|
use shell::Mode;
|
||||||
|
match data.mode {
|
||||||
|
Mode::Suggestion => modes::suggestion(&mut data),
|
||||||
|
Mode::CNF => modes::cnf(&mut data),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init() -> Option<shell::Data> {
|
||||||
let locale = {
|
let locale = {
|
||||||
let sys_locale = get_locale().unwrap_or("en-US".to_string());
|
let sys_locale = get_locale().unwrap_or("en-US".to_string());
|
||||||
if sys_locale.len() < 2 {
|
if sys_locale.len() < 2 {
|
||||||
|
|
@ -50,6 +69,11 @@ fn main() {
|
||||||
};
|
};
|
||||||
rust_i18n::set_locale(&locale[0..2]);
|
rust_i18n::set_locale(&locale[0..2]);
|
||||||
|
|
||||||
|
let exit = args::handle_args();
|
||||||
|
if exit {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "request-ai")]
|
#[cfg(feature = "request-ai")]
|
||||||
{
|
{
|
||||||
if std::env::var("_PR_AI_LOCALE").is_err() {
|
if std::env::var("_PR_AI_LOCALE").is_err() {
|
||||||
|
|
@ -57,16 +81,5 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args::handle_args();
|
Some(shell::Data::init())
|
||||||
|
|
||||||
let mode = match std::env::var("_PR_MODE") {
|
|
||||||
Ok(mode) => mode,
|
|
||||||
Err(_) => "suggestion".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match mode.as_str() {
|
|
||||||
"suggestion" => modes::suggestion(),
|
|
||||||
"cnf" => modes::cnf(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
66
src/modes.rs
66
src/modes.rs
|
|
@ -1,32 +1,18 @@
|
||||||
use crate::shell::{command_output, get_shell, PRIVILEGE_LIST};
|
use crate::shell::Data;
|
||||||
use crate::style::highlight_difference;
|
use crate::style::highlight_difference;
|
||||||
use crate::suggestions::{best_match_path, split_command};
|
use crate::suggestions::{best_match_path, suggest_command};
|
||||||
use crate::system;
|
use crate::system;
|
||||||
use crate::{shell, suggestions};
|
use crate::{shell, suggestions};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use inquire::*;
|
use inquire::*;
|
||||||
|
|
||||||
pub fn suggestion() {
|
pub fn suggestion(data: &mut Data) {
|
||||||
let shell = get_shell();
|
let shell = data.shell.clone();
|
||||||
let mut last_command = shell::last_command(&shell).trim().to_string();
|
let last_command = data.command.clone();
|
||||||
last_command = shell::expand_alias(&shell, &last_command);
|
|
||||||
let mut error_msg = {
|
|
||||||
let error_msg = std::env::var("_PR_ERROR_MSG");
|
|
||||||
if let Ok(error_msg) = error_msg {
|
|
||||||
error_msg
|
|
||||||
} else {
|
|
||||||
command_output(&shell, &last_command)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
error_msg = error_msg
|
|
||||||
.split_whitespace()
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join(" ");
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let suggestion = {
|
let suggestion = {
|
||||||
let command = suggestions::suggest_command(&shell, &last_command, &error_msg);
|
let command = suggest_command(&data);
|
||||||
if command.is_none() {
|
if command.is_none() {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
@ -35,6 +21,8 @@ pub fn suggestion() {
|
||||||
shell::shell_syntax(&shell, &mut command);
|
shell::shell_syntax(&shell, &mut command);
|
||||||
command
|
command
|
||||||
};
|
};
|
||||||
|
data.update_suggest(&suggestion);
|
||||||
|
data.expand_suggest();
|
||||||
|
|
||||||
let highlighted_suggestion = {
|
let highlighted_suggestion = {
|
||||||
let difference = highlight_difference(&shell, &suggestion, &last_command);
|
let difference = highlight_difference(&shell, &suggestion, &last_command);
|
||||||
|
|
@ -45,16 +33,13 @@ pub fn suggestion() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let execution =
|
let execution =
|
||||||
suggestions::confirm_suggestion(&shell, &suggestion, &highlighted_suggestion);
|
suggestions::confirm_suggestion(&data, &highlighted_suggestion);
|
||||||
if execution.is_ok() {
|
if execution.is_ok() {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
last_command = suggestion;
|
data.update_command(&suggestion);
|
||||||
error_msg = execution.err().unwrap();
|
let msg = Some(execution.err().unwrap().split_whitespace().collect::<Vec<&str>>().join(" "));
|
||||||
error_msg = error_msg
|
data.update_error(msg);
|
||||||
.split_whitespace()
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join(" ");
|
|
||||||
|
|
||||||
let retry_message = format!("{}...", t!("retry"));
|
let retry_message = format!("{}...", t!("retry"));
|
||||||
|
|
||||||
|
|
@ -69,33 +54,24 @@ pub fn suggestion() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cnf() {
|
pub fn cnf(data: &mut Data) {
|
||||||
let shell = get_shell();
|
let shell = data.shell.clone();
|
||||||
let mut last_command = shell::last_command(&shell).trim().to_string();
|
let last_command = data.command.clone();
|
||||||
last_command = shell::expand_alias(&shell, &last_command);
|
let mut split_command = data.split.clone();
|
||||||
|
|
||||||
let mut split_command = split_command(&last_command);
|
let executable = split_command[0].as_str();
|
||||||
let executable = match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
|
||||||
true => split_command.get(1).expect(&t!("no-command")).as_str(),
|
|
||||||
false => split_command.first().expect(&t!("no-command")).as_str(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let best_match = best_match_path(executable);
|
let best_match = best_match_path(executable);
|
||||||
if best_match.is_some() {
|
if best_match.is_some() {
|
||||||
let best_match = best_match.unwrap();
|
let best_match = best_match.unwrap();
|
||||||
match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
|
||||||
true => {
|
|
||||||
split_command[1] = best_match;
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
split_command[0] = best_match;
|
split_command[0] = best_match;
|
||||||
}
|
|
||||||
}
|
|
||||||
let suggestion = split_command.join(" ");
|
let suggestion = split_command.join(" ");
|
||||||
|
data.update_suggest(&suggestion);
|
||||||
|
data.expand_suggest();
|
||||||
|
|
||||||
let highlighted_suggestion =
|
let highlighted_suggestion =
|
||||||
highlight_difference(&shell, &suggestion, &last_command).unwrap();
|
highlight_difference(&shell, &suggestion, &last_command).unwrap();
|
||||||
let _ = suggestions::confirm_suggestion(&shell, &suggestion, &highlighted_suggestion);
|
let _ = suggestions::confirm_suggestion(&data, &highlighted_suggestion);
|
||||||
} else {
|
} else {
|
||||||
let package_manager = match system::get_package_manager(&shell) {
|
let package_manager = match system::get_package_manager(&shell) {
|
||||||
Some(package_manager) => package_manager,
|
Some(package_manager) => package_manager,
|
||||||
|
|
@ -124,7 +100,7 @@ pub fn cnf() {
|
||||||
|
|
||||||
// retry after installing package
|
// retry after installing package
|
||||||
if system::install_package(&shell, &package_manager, &package) {
|
if system::install_package(&shell, &package_manager, &package) {
|
||||||
let _ = suggestions::confirm_suggestion(&shell, &last_command, &last_command);
|
let _ = suggestions::confirm_suggestion(&data, &last_command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
262
src/shell.rs
262
src/shell.rs
|
|
@ -3,9 +3,137 @@ use std::process::exit;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use regex_lite::Regex;
|
||||||
|
|
||||||
pub const PRIVILEGE_LIST: [&str; 2] = ["sudo", "doas"];
|
pub const PRIVILEGE_LIST: [&str; 2] = ["sudo", "doas"];
|
||||||
|
|
||||||
|
pub enum Mode {
|
||||||
|
Suggestion,
|
||||||
|
CNF,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
pub shell: String,
|
||||||
|
pub command: String,
|
||||||
|
pub suggest: Option<String>,
|
||||||
|
pub split: Vec<String>,
|
||||||
|
pub alias: Option<HashMap<String, String>>,
|
||||||
|
pub privilege: Option<String>,
|
||||||
|
pub error: String,
|
||||||
|
pub mode: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Init {
|
||||||
|
pub shell: String,
|
||||||
|
pub binary_path: String,
|
||||||
|
pub auto_alias: String,
|
||||||
|
pub cnf: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
pub fn init() -> Data {
|
||||||
|
let shell = get_shell();
|
||||||
|
let command = last_command(&shell).trim().to_string();
|
||||||
|
let alias = alias_map(&shell);
|
||||||
|
let mode = run_mode();
|
||||||
|
|
||||||
|
let mut init = Data {
|
||||||
|
shell,
|
||||||
|
command,
|
||||||
|
suggest: None,
|
||||||
|
alias,
|
||||||
|
split: vec![],
|
||||||
|
privilege: None,
|
||||||
|
error: "".to_string(),
|
||||||
|
mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
init.split();
|
||||||
|
init.update_error(None);
|
||||||
|
init
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_command(&mut self) {
|
||||||
|
if self.alias.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let alias = self.alias.as_ref().unwrap();
|
||||||
|
if let Some(command) = expand_alias_multiline(alias, &self.command) {
|
||||||
|
self.update_command(&command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_suggest(&mut self) {
|
||||||
|
if self.alias.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let alias = self.alias.as_ref().unwrap();
|
||||||
|
if let Some(suggest) = expand_alias_multiline(alias, &self.suggest.as_ref().unwrap()) {
|
||||||
|
self.update_suggest(&suggest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(&mut self) {
|
||||||
|
let mut split = split_command(&self.command);
|
||||||
|
if PRIVILEGE_LIST.contains(&split[0].as_str()) {
|
||||||
|
self.command = self.command.replacen(&split[0], "", 1);
|
||||||
|
self.privilege = Some(split.remove(0))
|
||||||
|
}
|
||||||
|
self.split = split;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_error(&mut self, error: Option<String>) {
|
||||||
|
if let Some(error) = error {
|
||||||
|
self.error = error;
|
||||||
|
} else {
|
||||||
|
self.error = get_error(&self.shell, &self.command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_command(&mut self, command: &str) {
|
||||||
|
self.command = command.to_string();
|
||||||
|
self.split();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_suggest(&mut self, suggest: &str) {
|
||||||
|
let split = split_command(&suggest);
|
||||||
|
if PRIVILEGE_LIST.contains(&split[0].as_str()) {
|
||||||
|
self.suggest = Some(suggest.replacen(&split[0], "", 1));
|
||||||
|
self.privilege = Some(split[0].clone())
|
||||||
|
} else {
|
||||||
|
self.suggest = Some(suggest.to_string());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split_command(command: &str) -> Vec<String> {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
eprintln!("command: {command}")
|
||||||
|
}
|
||||||
|
// this regex splits the command separated by spaces, except when the space
|
||||||
|
// is escaped by a backslash or surrounded by quotes
|
||||||
|
let regex = r#"([^\s"'\\]+|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\\ )+|\\|\n"#;
|
||||||
|
let regex = Regex::new(regex).unwrap();
|
||||||
|
let split_command = regex
|
||||||
|
.find_iter(command)
|
||||||
|
.map(|cap| cap.as_str().to_owned())
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
split_command
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_error(shell: &str, command: &str) -> String {
|
||||||
|
let error_msg = std::env::var("_PR_ERROR_MSG");
|
||||||
|
let error = if let Ok(error_msg) = error_msg {
|
||||||
|
std::env::remove_var("_PR_ERROR_MSG");
|
||||||
|
error_msg
|
||||||
|
} else {
|
||||||
|
command_output(shell, command)
|
||||||
|
};
|
||||||
|
error.split_whitespace().collect::<Vec<&str>>().join(" ")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn command_output(shell: &str, command: &str) -> String {
|
pub fn command_output(shell: &str, command: &str) -> String {
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
|
|
||||||
|
|
@ -65,85 +193,93 @@ pub fn last_command(shell: &str) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_alias(shell: &str, full_command: &str) -> String {
|
pub fn run_mode() -> Mode {
|
||||||
let alias_env = std::env::var("_PR_ALIAS");
|
match std::env::var("_PR_MODE") {
|
||||||
if alias_env.is_err() {
|
Ok(mode) => {
|
||||||
return full_command.to_string();
|
match mode.as_str() {
|
||||||
|
"suggestion" => Mode::Suggestion,
|
||||||
|
"cnf" => Mode::CNF,
|
||||||
|
_ => Mode::Suggestion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Mode::Suggestion,
|
||||||
}
|
}
|
||||||
let alias = alias_env.unwrap();
|
|
||||||
if alias.is_empty() {
|
|
||||||
return full_command.to_string();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let split_command = full_command.split_whitespace().collect::<Vec<&str>>();
|
pub fn alias_map(shell: &str) -> Option<HashMap<String, String>> {
|
||||||
let (command, pure_command) = if PRIVILEGE_LIST.contains(&split_command[0]) && split_command.len() > 1 {
|
let env = std::env::var("_PR_ALIAS");
|
||||||
(split_command[1], Some(split_command[1..].join(" ")))
|
if env.is_err() {
|
||||||
} else {
|
return None;
|
||||||
(split_command[0], None)
|
}
|
||||||
};
|
let env = env.unwrap();
|
||||||
|
if env.is_empty() {
|
||||||
let mut expanded_command = Option::None;
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut alias_map = HashMap::new();
|
||||||
match shell {
|
match shell {
|
||||||
"bash" => {
|
"bash" => {
|
||||||
for line in alias.lines() {
|
for line in env.lines() {
|
||||||
if line.starts_with(format!("alias {}=", command).as_str()) {
|
let alias = line.replace("alias ", "");
|
||||||
let alias = line.replace(format!("alias {}='", command).as_str(), "");
|
let (alias, command) = alias.split_once('=').unwrap();
|
||||||
let alias = alias.trim_end_matches('\'').trim_start_matches('\'');
|
let command = command.trim().trim_matches('\'');
|
||||||
|
alias_map.insert(alias.to_string(), command.to_string());
|
||||||
expanded_command = Some(alias.to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"zsh" => {
|
"zsh" => {
|
||||||
for line in alias.lines() {
|
for line in env.lines() {
|
||||||
if line.starts_with(format!("{}=", command).as_str()) {
|
let (alias, command) = line.split_once('=').unwrap();
|
||||||
let alias = line.replace(format!("{}=", command).as_str(), "");
|
let command = command.trim().trim_matches('\'');
|
||||||
let alias = alias.trim_start_matches('\'').trim_end_matches('\'');
|
alias_map.insert(alias.to_string(), command.to_string());
|
||||||
|
|
||||||
expanded_command = Some(alias.to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"fish" => {
|
"fish" => {
|
||||||
for line in alias.lines() {
|
for line in env.lines() {
|
||||||
if line.starts_with(format!("alias {} ", command).as_str()) {
|
let alias = line.replace("alias ", "");
|
||||||
let alias = line.replace(format!("alias {} ", command).as_str(), "");
|
let (alias, command) = alias.split_once(' ').unwrap();
|
||||||
let alias = alias.trim_start_matches('\'').trim_end_matches('\'');
|
let command = command.trim().trim_matches('\'');
|
||||||
|
alias_map.insert(alias.to_string(), command.to_string());
|
||||||
expanded_command = Some(alias.to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("Unsupported shell: {}", shell);
|
unreachable!("Unsupported shell: {}", shell);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Some(alias_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_alias(map: &HashMap<String, String>, command: &str) -> Option<String> {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
eprintln!("expand_alias: command: {}", command);
|
||||||
|
let command = if let Some(split) = command.split_once(' ') {
|
||||||
|
split.0
|
||||||
|
} else {
|
||||||
|
command
|
||||||
};
|
};
|
||||||
|
if let Some(expand) = map.get(command) {
|
||||||
if expanded_command.is_none() {
|
Some(command.replacen(&command, expand, 1))
|
||||||
return full_command.to_string();
|
} else {
|
||||||
};
|
None
|
||||||
|
|
||||||
let expanded_command = expanded_command.unwrap();
|
|
||||||
|
|
||||||
if pure_command.is_some() {
|
|
||||||
let pure_command = pure_command.unwrap();
|
|
||||||
if pure_command.starts_with(&expanded_command) {
|
|
||||||
return full_command.to_string();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
full_command.replacen(command, &expanded_command, 1)
|
pub fn expand_alias_multiline(map: &HashMap<String, String>, command: &str) -> Option<String> {
|
||||||
}
|
let lines = command.lines().collect::<Vec<&str>>();
|
||||||
|
|
||||||
pub fn expand_alias_multiline(shell: &str, full_command: &str) -> String {
|
|
||||||
let lines = full_command.lines().collect::<Vec<&str>>();
|
|
||||||
let mut expanded = String::new();
|
let mut expanded = String::new();
|
||||||
|
let mut expansion = false;
|
||||||
for line in lines {
|
for line in lines {
|
||||||
expanded = format!("{}\n{}", expanded, expand_alias(shell, line));
|
if let Some(expand) = expand_alias(&map, line){
|
||||||
|
expanded = format!("{}\n{}", expanded, expand);
|
||||||
|
expansion = true;
|
||||||
|
} else {
|
||||||
|
expanded = format!("{}\n{}", expanded, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if expansion {
|
||||||
|
Some(expanded)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
expanded
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialization(shell: &str, binary_path: &str, auto_alias: &str, cnf: bool) {
|
pub fn initialization(shell: &str, binary_path: &str, auto_alias: &str, cnf: bool) {
|
||||||
|
|
@ -173,7 +309,7 @@ pub fn initialization(shell: &str, binary_path: &str, auto_alias: &str, cnf: boo
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown shell: {}", shell);
|
println!("Unknown shell: {}", shell);
|
||||||
std::process::exit(1);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,7 +330,7 @@ def --env {} [] {{
|
||||||
pr_alias, last_command, binary_path
|
pr_alias, last_command, binary_path
|
||||||
);
|
);
|
||||||
println!("{}", init);
|
println!("{}", init);
|
||||||
std::process::exit(0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut init = match shell {
|
let mut init = match shell {
|
||||||
|
|
@ -233,12 +369,12 @@ def --env {} [] {{
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unsupported shell: {}", shell);
|
println!("Unsupported shell: {}", shell);
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if auto_alias.is_empty() {
|
if auto_alias.is_empty() {
|
||||||
println!("{}", init);
|
println!("{}", init);
|
||||||
std::process::exit(0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match shell {
|
match shell {
|
||||||
|
|
@ -264,7 +400,7 @@ end
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unsupported shell: {}", shell);
|
println!("Unsupported shell: {}", shell);
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,14 +468,12 @@ $ExecutionContext.InvokeCommand.CommandNotFoundAction =
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unsupported shell: {}", shell);
|
println!("Unsupported shell: {}", shell);
|
||||||
exit(1);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", init);
|
println!("{}", init);
|
||||||
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_shell() -> String {
|
pub fn get_shell() -> String {
|
||||||
|
|
|
||||||
|
|
@ -7,52 +7,39 @@ use regex_lite::Regex;
|
||||||
|
|
||||||
use crate::files::{get_best_match_file, get_path_files};
|
use crate::files::{get_best_match_file, get_path_files};
|
||||||
use crate::rules::match_pattern;
|
use crate::rules::match_pattern;
|
||||||
use crate::shell::{expand_alias_multiline, shell_evaluated_commands, PRIVILEGE_LIST};
|
use crate::shell::{Data, shell_evaluated_commands};
|
||||||
|
|
||||||
pub fn suggest_command(shell: &str, last_command: &str, error_msg: &str) -> Option<String> {
|
pub fn suggest_command(data: &Data) -> Option<String> {
|
||||||
let split_command = split_command(last_command);
|
let shell = &data.shell;
|
||||||
let executable = match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
let command = &data.command;
|
||||||
true => split_command.get(1).expect(&t!("no-command")).as_str(),
|
let split_command = &data.split;
|
||||||
false => split_command.first().expect(&t!("no-command")).as_str(),
|
let executable = data.split[0].as_str();
|
||||||
};
|
let error = &data.error;
|
||||||
|
let privilege = &data.privilege;
|
||||||
|
|
||||||
if !PRIVILEGE_LIST.contains(&executable) {
|
if privilege.is_none() {
|
||||||
let suggest = match_pattern("_PR_privilege", last_command, error_msg, shell);
|
let suggest = match_pattern("_PR_privilege", command, error, shell);
|
||||||
if suggest.is_some() {
|
if suggest.is_some() {
|
||||||
return suggest;
|
return suggest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_command = match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
let suggest = match_pattern(executable, command, error, shell);
|
||||||
true => &last_command[split_command[0].len() + 1..],
|
if suggest.is_some() {
|
||||||
false => last_command,
|
return suggest;
|
||||||
};
|
|
||||||
|
|
||||||
let suggest = match_pattern(executable, last_command, error_msg, shell);
|
|
||||||
if let Some(suggest) = suggest {
|
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
|
||||||
return Some(format!("{} {}", split_command[0], suggest));
|
|
||||||
}
|
|
||||||
return Some(suggest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let suggest = match_pattern("_PR_general", last_command, error_msg, shell);
|
let suggest = match_pattern("_PR_general", command, error, shell);
|
||||||
if let Some(suggest) = suggest {
|
if suggest.is_some() {
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
return suggest;
|
||||||
return Some(format!("{} {}", split_command[0], suggest));
|
|
||||||
}
|
|
||||||
return Some(suggest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-rules")]
|
#[cfg(feature = "runtime-rules")]
|
||||||
{
|
{
|
||||||
use crate::runtime_rules::runtime_match;
|
use crate::runtime_rules::runtime_match;
|
||||||
let suggest = runtime_match(executable, last_command, error_msg, shell);
|
let suggest = runtime_match(executable, command, error, shell);
|
||||||
if let Some(suggest) = suggest {
|
if suggest.is_some() {
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
return suggest;
|
||||||
return Some(format!("{} {}", split_command[0], suggest));
|
|
||||||
}
|
|
||||||
return Some(suggest);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,25 +50,20 @@ pub fn suggest_command(shell: &str, last_command: &str, error_msg: &str) -> Opti
|
||||||
|
|
||||||
// skip for commands with no arguments,
|
// skip for commands with no arguments,
|
||||||
// very likely to be an error showing the usage
|
// very likely to be an error showing the usage
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) && split_command.len() > 2
|
if privilege.is_some() && split_command.len() > 2 ||
|
||||||
|| !PRIVILEGE_LIST.contains(&split_command[0].as_str()) && split_command.len() > 1
|
privilege.is_none() && split_command.len() > 1
|
||||||
{
|
{
|
||||||
let suggest = ai_suggestion(last_command, error_msg);
|
let suggest = ai_suggestion(command, error);
|
||||||
if let Some(suggest) = suggest {
|
if let Some(suggest) = suggest {
|
||||||
let warn = format!("{}:", t!("ai-suggestion")).bold().blue();
|
let warn = format!("{}:", t!("ai-suggestion")).bold().blue();
|
||||||
let note = fill(&suggest.note, termwidth());
|
let note = fill(&suggest.note, termwidth());
|
||||||
|
|
||||||
eprintln!("{}\n{}\n", warn, note);
|
eprintln!("{}\n{}\n", warn, note);
|
||||||
let command = suggest.command;
|
let command = suggest.command;
|
||||||
if command != "None" {
|
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
|
||||||
return Some(format!("{} {}", split_command[0], command));
|
|
||||||
}
|
|
||||||
return Some(command);
|
return Some(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -262,56 +244,17 @@ pub fn compare_string(a: &str, b: &str) -> usize {
|
||||||
matrix[a.chars().count()][b.chars().count()]
|
matrix[a.chars().count()][b.chars().count()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn confirm_suggestion(shell: &str, command: &str, highlighted: &str) -> Result<(), String> {
|
pub fn confirm_suggestion(data: &Data, highlighted: &str) -> Result<(), String> {
|
||||||
eprintln!("{}\n", highlighted);
|
eprintln!("{}\n", highlighted);
|
||||||
let confirm = format!("[{}]", t!("confirm-yes")).green();
|
let confirm = format!("[{}]", t!("confirm-yes")).green();
|
||||||
eprintln!("{}: {} {}", t!("confirm"), confirm, "[Ctrl+C]".red());
|
eprintln!("{}: {} {}", t!("confirm"), confirm, "[Ctrl+C]".red());
|
||||||
std::io::stdin().read_line(&mut String::new()).unwrap();
|
std::io::stdin().read_line(&mut String::new()).unwrap();
|
||||||
|
|
||||||
for p in PRIVILEGE_LIST {
|
let shell = &data.shell;
|
||||||
let _p = p.to_owned() + " ";
|
let command = &data.suggest.clone().unwrap();
|
||||||
if !command.starts_with(&_p) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let command = {
|
|
||||||
let mut command = command.replacen(&_p, "", 1);
|
|
||||||
if command != " " {
|
|
||||||
command = expand_alias_multiline(shell, &command);
|
|
||||||
}
|
|
||||||
command
|
|
||||||
};
|
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let process = run_suggestion_p(shell, p, &command);
|
let process = run_suggestion(data, &command);
|
||||||
|
|
||||||
if process.success() {
|
|
||||||
let cd = shell_evaluated_commands(shell, &command);
|
|
||||||
if let Some(cd) = cd {
|
|
||||||
println!("{}", cd);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if now.elapsed() > Duration::from_secs(3) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
let process = std::process::Command::new(p)
|
|
||||||
.arg(shell)
|
|
||||||
.arg("-c")
|
|
||||||
.arg(command)
|
|
||||||
.env("LC_ALL", "C")
|
|
||||||
.output()
|
|
||||||
.expect("failed to execute process");
|
|
||||||
let error_msg = match process.stderr.is_empty() {
|
|
||||||
true => String::from_utf8_lossy(&process.stdout),
|
|
||||||
false => String::from_utf8_lossy(&process.stderr),
|
|
||||||
};
|
|
||||||
return Err(error_msg.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let command = expand_alias_multiline(shell, command);
|
|
||||||
let now = Instant::now();
|
|
||||||
let process = run_suggestion(shell, &command);
|
|
||||||
|
|
||||||
if process.success() {
|
if process.success() {
|
||||||
let cd = shell_evaluated_commands(shell, &command);
|
let cd = shell_evaluated_commands(shell, &command);
|
||||||
|
|
@ -337,8 +280,12 @@ pub fn confirm_suggestion(shell: &str, command: &str, highlighted: &str) -> Resu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_suggestion_p(shell: &str, p: &str, command: &str) -> std::process::ExitStatus {
|
fn run_suggestion(data: &Data, command: &str) -> std::process::ExitStatus {
|
||||||
std::process::Command::new(p)
|
let shell = &data.shell;
|
||||||
|
let privilege = &data.privilege;
|
||||||
|
match privilege {
|
||||||
|
Some(sudo) => {
|
||||||
|
std::process::Command::new(sudo)
|
||||||
.arg(shell)
|
.arg(shell)
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
|
|
@ -349,12 +296,10 @@ fn run_suggestion_p(shell: &str, p: &str, command: &str) -> std::process::ExitSt
|
||||||
.wait()
|
.wait()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
fn run_suggestion(shell: &str, command: &str) -> std::process::ExitStatus {
|
|
||||||
std::process::Command::new(shell)
|
std::process::Command::new(shell)
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
// .stdout(Stdio::inherit())
|
|
||||||
.stdout(stderr())
|
.stdout(stderr())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
|
@ -362,3 +307,5 @@ fn run_suggestion(shell: &str, command: &str) -> std::process::ExitStatus {
|
||||||
.wait()
|
.wait()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue