mirror of
https://github.com/TECHNOFAB11/pay-respects.git
synced 2025-12-12 14:30:10 +01:00
feat: range substitution for typos
This commit is contained in:
parent
b991214729
commit
2a5fa8a950
4 changed files with 102 additions and 53 deletions
|
|
@ -1,24 +1,26 @@
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
fn rtag (name: &str, x: i32, y: String) -> TokenStream2 {
|
fn rtag(name: &str, x: i32, y: String) -> TokenStream2 {
|
||||||
let tag = format!("{}{} = {}", name, x, y);
|
let tag = format!("{}{} = {}", name, x, y);
|
||||||
let tag: TokenStream2 = tag.parse().unwrap();
|
let tag: TokenStream2 = tag.parse().unwrap();
|
||||||
tag
|
tag
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag (name: &str, x: i32) -> String {
|
fn tag(name: &str, x: i32) -> String {
|
||||||
let tag = format!("{{{}{}}}", name, x);
|
let tag = format!("{{{}{}}}", name, x);
|
||||||
let tag = tag.as_str();
|
let tag = tag.as_str();
|
||||||
let tag = tag.to_owned();
|
let tag = tag.to_owned();
|
||||||
tag
|
tag
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_placeholder(string: &str, start: &str, end: &str) -> (std::ops::Range<usize>, std::ops::Range<usize>) {
|
fn eval_placeholder(
|
||||||
|
string: &str,
|
||||||
|
start: &str,
|
||||||
|
end: &str,
|
||||||
|
) -> (std::ops::Range<usize>, std::ops::Range<usize>) {
|
||||||
let start_index = string.find(start).unwrap();
|
let start_index = string.find(start).unwrap();
|
||||||
let end_index = string[start_index..].find(end).unwrap()
|
let end_index = string[start_index..].find(end).unwrap() + start_index + end.len();
|
||||||
+ start_index
|
|
||||||
+ end.len();
|
|
||||||
|
|
||||||
let placeholder = start_index..end_index;
|
let placeholder = start_index..end_index;
|
||||||
|
|
||||||
|
|
@ -27,7 +29,11 @@ fn eval_placeholder(string: &str, start: &str, end: &str) -> (std::ops::Range<us
|
||||||
(placeholder, args)
|
(placeholder, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opts(suggest: &mut String, replace_list: &mut Vec<TokenStream2>, opt_list: &mut Vec<TokenStream2>) {
|
pub fn opts(
|
||||||
|
suggest: &mut String,
|
||||||
|
replace_list: &mut Vec<TokenStream2>,
|
||||||
|
opt_list: &mut Vec<TokenStream2>,
|
||||||
|
) {
|
||||||
let mut replace_tag = 0;
|
let mut replace_tag = 0;
|
||||||
let tag_name = "opts";
|
let tag_name = "opts";
|
||||||
while suggest.contains("{{opt::") {
|
while suggest.contains("{{opt::") {
|
||||||
|
|
@ -82,7 +88,6 @@ pub fn err(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn command(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
pub fn command(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
let mut replace_tag = 0;
|
let mut replace_tag = 0;
|
||||||
let tag_name = "command";
|
let tag_name = "command";
|
||||||
|
|
@ -109,19 +114,18 @@ pub fn command(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let command = format!{r#"split_command[{}..{}].join(" ")"#, start_string, end_string};
|
let command = format! {r#"split_command[{}..{}].join(" ")"#, start_string, end_string};
|
||||||
|
|
||||||
replace_list.push(rtag(tag_name, replace_tag, command));
|
replace_list.push(rtag(tag_name, replace_tag, command));
|
||||||
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
||||||
replace_tag += 1;
|
|
||||||
} else {
|
} else {
|
||||||
let range = range.parse::<i32>().unwrap_or(0);
|
let range = range.parse::<i32>().unwrap_or(0);
|
||||||
let command = format!("split_command[{}]", range);
|
let command = format!("split_command[{}]", range);
|
||||||
|
|
||||||
replace_list.push(rtag(tag_name, replace_tag, command));
|
replace_list.push(rtag(tag_name, replace_tag, command));
|
||||||
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
||||||
replace_tag += 1;
|
|
||||||
}
|
}
|
||||||
|
replace_tag += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,24 +136,54 @@ pub fn typo(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
while suggest.contains("{{typo") {
|
while suggest.contains("{{typo") {
|
||||||
let (placeholder, args) = eval_placeholder(suggest, "{{typo", "}}");
|
let (placeholder, args) = eval_placeholder(suggest, "{{typo", "}}");
|
||||||
|
|
||||||
let string_index;
|
let string_index = if suggest.contains('[') {
|
||||||
if suggest.contains('[') {
|
|
||||||
let split = suggest[args.to_owned()]
|
let split = suggest[args.to_owned()]
|
||||||
.split(&['[', ']'])
|
.split(&['[', ']'])
|
||||||
.collect::<Vec<&str>>();
|
.collect::<Vec<&str>>();
|
||||||
let command_index = split[1].parse::<i32>().unwrap();
|
let command_index = split[1];
|
||||||
if command_index < 0 {
|
if !command_index.contains(':') {
|
||||||
string_index = format!("split_command.len() {}", command_index);
|
let command_index = command_index.parse::<i32>().unwrap();
|
||||||
|
|
||||||
|
let index = if command_index < 0 {
|
||||||
|
format!("split_command.len() {}", command_index)
|
||||||
|
} else {
|
||||||
|
command_index.to_string()
|
||||||
|
};
|
||||||
|
format!("{}..{} + 1", index, index)
|
||||||
} else {
|
} else {
|
||||||
string_index = command_index.to_string();
|
let (start, end) = command_index.split_once(':').unwrap();
|
||||||
|
let start = start.parse::<i32>().unwrap_or(0);
|
||||||
|
let start_string = if start < 0 {
|
||||||
|
format!("split_command.len() {}", start)
|
||||||
|
} else {
|
||||||
|
start.to_string()
|
||||||
|
};
|
||||||
|
let end = end.parse::<i32>();
|
||||||
|
let end_string = if end.is_err() {
|
||||||
|
String::from("split_command.len()")
|
||||||
|
} else {
|
||||||
|
let end = end.unwrap();
|
||||||
|
if end < 0 {
|
||||||
|
format!("split_command.len() {}", end + 1)
|
||||||
|
} else {
|
||||||
|
(end + 1).to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("{}..{}", start_string, end_string)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Typo suggestion must have a command index");
|
unreachable!("Typo suggestion must have a command index");
|
||||||
}
|
};
|
||||||
let match_list;
|
let match_list;
|
||||||
if suggest.contains('(') {
|
if suggest.contains('(') {
|
||||||
let split = suggest[args.to_owned()]
|
let split = suggest[args.to_owned()]
|
||||||
.split_once("(").unwrap().1.rsplit_once(")").unwrap().0;
|
.split_once("(")
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.rsplit_once(")")
|
||||||
|
.unwrap()
|
||||||
|
.0;
|
||||||
match_list = split.split(',').collect::<Vec<&str>>();
|
match_list = split.split(',').collect::<Vec<&str>>();
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Typo suggestion must have a match list");
|
unreachable!("Typo suggestion must have a match list");
|
||||||
|
|
@ -161,13 +195,19 @@ pub fn typo(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let command;
|
let command;
|
||||||
if match_list[0].starts_with("eval_shell_command("){
|
if match_list[0].starts_with("eval_shell_command(") {
|
||||||
let function = match_list.join(",");
|
let function = match_list.join(",");
|
||||||
// add a " after first comma, and a " before last )
|
// add a " after first comma, and a " before last )
|
||||||
let function = format!("{}\"{}{}",
|
let function = format!(
|
||||||
|
"{}\"{}{}",
|
||||||
&function[..function.find(',').unwrap() + 1],
|
&function[..function.find(',').unwrap() + 1],
|
||||||
&function[function.find(',').unwrap() + 1..function.len() - 1], "\")");
|
&function[function.find(',').unwrap() + 1..function.len() - 1],
|
||||||
command = format!("suggest_typo(&split_command[{}], {})", string_index, function);
|
"\")"
|
||||||
|
);
|
||||||
|
command = format!(
|
||||||
|
"suggest_typo(&split_command[{}], &{})",
|
||||||
|
string_index, function
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let match_list = match_list
|
let match_list = match_list
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -175,15 +215,16 @@ pub fn typo(suggest: &mut String, replace_list: &mut Vec<TokenStream2>) {
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
let string_match_list = match_list.join("\".to_string(), \"");
|
let string_match_list = match_list.join("\".to_string(), \"");
|
||||||
let string_match_list = format!("\"{}\".to_string()", string_match_list);
|
let string_match_list = format!("\"{}\".to_string()", string_match_list);
|
||||||
command = format!("suggest_typo(&split_command[{}], vec![{}])", string_index, string_match_list);
|
command = format!(
|
||||||
|
"suggest_typo(&split_command[{}], &[{}])",
|
||||||
|
string_index, string_match_list
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
replace_list.push(rtag(tag_name, replace_tag, command));
|
replace_list.push(rtag(tag_name, replace_tag, command));
|
||||||
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
suggest.replace_range(placeholder, &tag(tag_name, replace_tag));
|
||||||
replace_tag += 1;
|
replace_tag += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell(suggest: &mut String, cmd_list: &mut Vec<String>) {
|
pub fn shell(suggest: &mut String, cmd_list: &mut Vec<String>) {
|
||||||
|
|
@ -198,13 +239,16 @@ pub fn shell(suggest: &mut String, cmd_list: &mut Vec<String>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell_tag(suggest: &mut String, replace_list: &mut Vec<TokenStream2>, cmd_list: Vec<String>) {
|
pub fn shell_tag(
|
||||||
|
suggest: &mut String,
|
||||||
|
replace_list: &mut Vec<TokenStream2>,
|
||||||
|
cmd_list: Vec<String>,
|
||||||
|
) {
|
||||||
let mut replace_tag = 0;
|
let mut replace_tag = 0;
|
||||||
let tag_name = "shell";
|
let tag_name = "shell";
|
||||||
|
|
||||||
for command in cmd_list {
|
for command in cmd_list {
|
||||||
if suggest.contains(&command) {
|
if suggest.contains(&command) {
|
||||||
|
|
||||||
*suggest = suggest.replace(&command, &tag(tag_name, replace_tag));
|
*suggest = suggest.replace(&command, &tag(tag_name, replace_tag));
|
||||||
|
|
||||||
let split = command.split_once(',').unwrap();
|
let split = command.split_once(',').unwrap();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ suggest = [
|
||||||
pattern = [ "no such file or directory" ]
|
pattern = [ "no such file or directory" ]
|
||||||
suggest = [
|
suggest = [
|
||||||
'''
|
'''
|
||||||
{{command[0}} {{opt::(?:\s)-[\w]+}} {{typo[-1](file)}} '''
|
{{command[0}} {{opt::(?:\s)-[\w]+}} {{typo[1:](file)}} '''
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ pub fn get_best_match_file(input: &str) -> Option<String> {
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let best_match = find_similar(&exit_dir, dir_files);
|
let best_match = find_similar(&exit_dir, &dir_files);
|
||||||
best_match.as_ref()?;
|
best_match.as_ref()?;
|
||||||
|
|
||||||
input = format!("{}/{}", input, best_match.unwrap());
|
input = format!("{}/{}", input, best_match.unwrap());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::process::{Stdio, exit};
|
use std::process::{exit, Stdio};
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use regex_lite::Regex;
|
use regex_lite::Regex;
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ pub fn suggest_command(shell: &str, last_command: &str, error_msg: &str) -> Opti
|
||||||
|
|
||||||
let last_command = match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
let last_command = match PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
||||||
true => &last_command[split_command[0].len() + 1..],
|
true => &last_command[split_command[0].len() + 1..],
|
||||||
false => &last_command,
|
false => last_command,
|
||||||
};
|
};
|
||||||
|
|
||||||
let suggest = match_pattern(executable, last_command, error_msg, shell);
|
let suggest = match_pattern(executable, last_command, error_msg, shell);
|
||||||
|
|
@ -35,7 +35,7 @@ pub fn suggest_command(shell: &str, last_command: &str, error_msg: &str) -> Opti
|
||||||
return Some(suggest);
|
return Some(suggest);
|
||||||
}
|
}
|
||||||
|
|
||||||
let suggest = match_pattern("general", &last_command, error_msg, shell);
|
let suggest = match_pattern("general", last_command, error_msg, shell);
|
||||||
if let Some(suggest) = suggest {
|
if let Some(suggest) = suggest {
|
||||||
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
if PRIVILEGE_LIST.contains(&split_command[0].as_str()) {
|
||||||
return Some(format!("{} {}", split_command[0], suggest));
|
return Some(format!("{} {}", split_command[0], suggest));
|
||||||
|
|
@ -132,31 +132,36 @@ pub fn split_command(command: &str) -> Vec<String> {
|
||||||
split_command
|
split_command
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_typo(typo: &str, candidates: Vec<String>) -> String {
|
fn suggest_typo(typos: &[String], candidates: &[String]) -> String {
|
||||||
let mut suggestion = typo.to_owned();
|
let mut path_files = Vec::new();
|
||||||
|
let mut suggestions = Vec::new();
|
||||||
if candidates.len() == 1 {
|
for typo in typos {
|
||||||
match candidates[0].as_str() {
|
let typo = typo.as_str();
|
||||||
"path" => {
|
if candidates.len() == 1 {
|
||||||
let path_files = get_path_files();
|
match candidates[0].as_str() {
|
||||||
if let Some(suggest) = find_similar(typo, path_files) {
|
"path" => {
|
||||||
suggestion = suggest;
|
if path_files.is_empty() {
|
||||||
|
path_files = get_path_files();
|
||||||
|
};
|
||||||
|
if let Some(suggest) = find_similar(typo, &path_files) {
|
||||||
|
suggestions.push(suggest);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
"file" => {
|
||||||
"file" => {
|
if let Some(suggest) = get_best_match_file(typo) {
|
||||||
if let Some(suggest) = get_best_match_file(typo) {
|
suggestions.push(suggest);
|
||||||
suggestion = suggest;
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
_ => {}
|
} else if let Some(suggest) = find_similar(typo, candidates) {
|
||||||
|
suggestions.push(suggest);
|
||||||
}
|
}
|
||||||
} else if let Some(suggest) = find_similar(typo, candidates) {
|
|
||||||
suggestion = suggest;
|
|
||||||
}
|
}
|
||||||
suggestion
|
suggestions.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_similar(typo: &str, candidates: Vec<String>) -> Option<String> {
|
pub fn find_similar(typo: &str, candidates: &[String]) -> Option<String> {
|
||||||
let mut min_distance = 10;
|
let mut min_distance = 10;
|
||||||
let mut min_distance_index = None;
|
let mut min_distance_index = None;
|
||||||
for (i, candidate) in candidates.iter().enumerate() {
|
for (i, candidate) in candidates.iter().enumerate() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue