feat: conditional suggestions

This commit is contained in:
iff 2023-07-31 09:24:46 +02:00
parent 72db07051b
commit 6b4d926dde
5 changed files with 54 additions and 19 deletions

View file

@ -48,8 +48,10 @@ suggest = "{{command[0]}} fix {{command[2:]}}"
pattern = [ pattern = [
"pattern 1", "pattern 1",
] ]
# this will add a `sudo` before the command, without touching the rest # this will add a `sudo` before the command if the `sudo` is found by `which`
suggest = "sudo {{command}}" suggest = '''
#[executable(sudo)]
sudo {{command}}'''
``` ```
The placeholder is evaluated as following: The placeholder is evaluated as following:

View file

@ -20,7 +20,7 @@ struct Rule {
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct MatchOutput { struct MatchOutput {
pattern: Vec<String>, pattern: Vec<String>,
suggest: String, suggest: Vec<String>,
} }
fn get_rules(directory: String) -> Vec<Rule> { fn get_rules(directory: String) -> Vec<Rule> {
@ -51,9 +51,9 @@ fn gen_string_hashmap(rules: Vec<Rule>) -> String {
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let suggest = match_output.suggest; let suggest = match_output.suggest;
string_hashmap.push_str(&format!( string_hashmap.push_str(&format!(
"(vec![\"{}\"], \"{}\"),", "(vec![\"{}\"], vec![\"{}\"]),",
pattern.join("\", \""), pattern.join("\", \""),
suggest suggest.join("\", \"")
)); ));
} }
string_hashmap.push_str("]),"); string_hashmap.push_str("]),");

View file

@ -27,4 +27,11 @@ pattern = [
"you don't have access to the history db.", "you don't have access to the history db.",
"you don't have write permissions", "you don't have write permissions",
] ]
suggest = 'sudo {{command}}' suggest = [
'''
#[executable(sudo)]
sudo {{command}}''',
'''
#[executable(doas)]
doas {{command}}''',
]

View file

@ -39,7 +39,11 @@ fn match_pattern(command: &str, error_msg: &str) -> Option<String> {
for (pattern, suggest) in suggest { for (pattern, suggest) in suggest {
for pattern in pattern { for pattern in pattern {
if error_msg.contains(pattern) { if error_msg.contains(pattern) {
return Some(suggest.to_owned().to_string()); for suggest in suggest {
if let Some(suggest) = check_suggest(suggest) {
return Some(suggest);
}
}
} }
} }
} }
@ -49,6 +53,39 @@ fn match_pattern(command: &str, error_msg: &str) -> Option<String> {
} }
} }
fn check_suggest(suggest: &str) -> Option<String> {
if !suggest.starts_with('#') {
return Some(suggest.to_owned());
}
let lines = suggest.lines().collect::<Vec<&str>>();
let conditions = lines.first().unwrap();
let conditions = conditions.trim_matches(|c| c == '#' || c == '[' || c == ']');
let conditions = conditions.split(',').collect::<Vec<&str>>();
for condition in conditions {
let condition = condition.trim();
let (condition, arg) = condition.split_once('(').unwrap();
let arg = arg.trim_matches(|c| c == '(' || c == ')');
if eval_condition(condition, arg) == false {
return None;
}
}
Some(lines[1..].join("\n"))
}
fn eval_condition(condition: &str, arg: &str) -> bool {
match condition {
"executable" => {
let output = std::process::Command::new("which")
.arg(arg)
.output()
.expect("failed to execute process");
output.status.success()
}
_ => false,
}
}
fn eval_suggest(suggest: &str, last_command: &str) -> String { fn eval_suggest(suggest: &str, last_command: &str) -> String {
let mut suggest = suggest.to_owned(); let mut suggest = suggest.to_owned();
if suggest.contains("{{command}}") { if suggest.contains("{{command}}") {
@ -95,7 +132,6 @@ pub fn confirm_correction(shell: &str, command: &str, last_command: &str) {
for p in PRIVILEGE_LIST { for p in PRIVILEGE_LIST {
if command.starts_with(p) { if command.starts_with(p) {
let command = command.replace(p, ""); let command = command.replace(p, "");
println!("{} {}", p, command);
std::process::Command::new(p.trim()) std::process::Command::new(p.trim())
.arg(shell) .arg(shell)
.arg("-c") .arg("-c")

View file

@ -2,8 +2,6 @@ mod corrections;
mod shell; mod shell;
mod style; mod style;
use shell::get_privilege;
fn main() { fn main() {
std::env::set_var("LC_ALL", "C"); std::env::set_var("LC_ALL", "C");
@ -11,15 +9,7 @@ fn main() {
let last_command = shell::find_last_command(&shell); let last_command = shell::find_last_command(&shell);
let corrected_command = corrections::correct_command(&shell, &last_command); let corrected_command = corrections::correct_command(&shell, &last_command);
if let Some(mut corrected_command) = corrected_command { if let Some(corrected_command) = corrected_command {
if corrected_command.starts_with("sudo ") {
let privilege = get_privilege();
if let Some(privilege) = privilege {
if privilege != "sudo" {
corrected_command = corrected_command.replacen("sudo", &privilege, 1);
}
}
}
corrections::confirm_correction(&shell, &corrected_command, &last_command); corrections::confirm_correction(&shell, &corrected_command, &last_command);
} else { } else {
println!( println!(