From c65438ed6c8a1f1fbb25aace3f187f6b5eba6b14 Mon Sep 17 00:00:00 2001 From: Justine Date: Thu, 2 Feb 2023 18:14:10 +0100 Subject: [PATCH] Better autocomplete, still WIP when searching for folders --- src/shell/autocomplete.rs | 153 +++++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 44 deletions(-) diff --git a/src/shell/autocomplete.rs b/src/shell/autocomplete.rs index 636181f..968a7ba 100644 --- a/src/shell/autocomplete.rs +++ b/src/shell/autocomplete.rs @@ -8,7 +8,13 @@ pub fn autocomplete(input: &String, prev_match: &String) -> (String, String) { if !input.contains(' ') && !input.contains("./") { return autocomplete_cmd(input); } else { - return autocomplete_file(input, prev_match).unwrap(); + match autocomplete_file(input, prev_match) { + Ok(t) => return t, + Err(e) => { + println!("\n\r{}", e); + return (String::from(input), String::new()); + }, + }; } } @@ -17,61 +23,90 @@ pub fn autocomplete(input: &String, prev_match: &String) -> (String, String) { fn autocomplete_file(input: &String, prev_match: &String) -> std::io::Result<(String, String)> { //Keep the last part of the cmd... - let input_searchee = input - .split(' ') - .collect::>() - .last() - .copied(); + let mut input_searchee = match input + .split(' ') + .collect::>() + .last() + .copied() { + Some(c) => c, + None => { + return Ok((String::from(""), String::from(""))); + }, + }; //And also the beginning ! let mut input_buff = input .split(' ') .collect::>(); _ = input_buff.pop(); - let mut input_origin = format!("{} ", input_buff.join(" ")); + let input_origin = format!("{} ", input_buff.join(" ")); - match input_searchee { - Some(s) => { - //Search happens 'round here - let current_dir = env::current_dir()?; - let mut all_res = String::new(); - let mut nbr_found: u16 = 0; - let mut last_found = String::new(); + //Store the results + let mut results = Vec::new(); - for file in fs::read_dir(current_dir)? { - let filepath = file.unwrap().path(); - let filename = filepath - .iter() - .last() - .unwrap() - .to_str() - .unwrap(); - let re = format!("^{}.*$", s); - let regex = Regex::new(&re).unwrap(); - if regex.is_match(filename) { - *&mut nbr_found += 1; - let matchline = format!("\r\n* {}", filename); - &mut all_res.push_str(&matchline); - //No need to find things we already found - if *prev_match != filename { - *&mut last_found = format!("{}{}", &input_origin, filename); - } + //Where do we search ? + let mut folder_to_search = PathBuf::new(); + //Display folder in search result ? + let mut searching_current = false; + //Searching somewhere else... + if input_searchee.contains('/') { + //Remove the last part + let toremove = &input_searchee.split('/').last().unwrap(); + let tosearch = &input_searchee.replace(toremove, ""); + folder_to_search.push(tosearch); + *&mut input_searchee = &toremove; + *&mut searching_current = true; + //Searching the current folder + } else { + folder_to_search = env::current_dir()?; + } + + //Search happens 'round here + let mut all_res = String::new(); + let mut nbr_found: u16 = 0; + let mut last_found = String::new(); + + for file in fs::read_dir(&folder_to_search)? { + let filepath = file.unwrap().path(); + let filename = filepath + .iter() + .last() + .unwrap() + .to_str() + .unwrap(); + let re = format!("^{}.*$", input_searchee); + let regex = Regex::new(&re).unwrap(); + if regex.is_match(filename) { + if !searching_current { + *&mut results.push(format!("{}", filename)); + } else { + *&mut results.push(format!("{}{}", &folder_to_search.display(), filename)); + } + *&mut nbr_found += 1; + let matchline = &format!("\r\n* {}", filename); + &mut all_res.push_str(&matchline); + //No need to find things we already found + if *prev_match != filename { + if searching_current { + *&mut last_found = format!("{}{}{}", &input_origin, &folder_to_search.display(), filename); + } else { + *&mut last_found = format!("{}{}", &input_origin, filename); } } - //Found one or zero, use what has been found directly - if nbr_found < 2 { - return Ok((last_found, String::new())); - //Otherwise, just display a list - } else { - return Ok((String::from(input), all_res)); - } - }, - None => { - return Ok((String::from(""), String::from(""))); - }, - }; + } + } + //Found one or zero, use what has been found directly + if nbr_found < 2 { + return Ok((last_found, String::new())); + //Otherwise, just display a list and use what all the results have in common + } else { + let longest = find_common_chars(results); + let ret_string = format!("{}{}", input_origin, &longest); + return Ok((ret_string, all_res)); + } } + fn autocomplete_cmd(input: &String) -> (String, String) { let found_bins = find_bin(input); if found_bins.len() == 1 { @@ -114,5 +149,35 @@ fn find_bin(command: &String) -> Vec { return binaries; } +fn find_common_chars(mut strvec: Vec) -> String { + let first_word = strvec[0].clone(); + strvec.remove(0); + let mut answer = String::new(); + let mut counter: usize = 0; + + for letter in first_word.chars() { + let mut still_ok = true; + for word in &strvec { + if still_ok == true { + match word.chars().nth(counter) { + Some(l) => { + if l != letter { + *&mut still_ok = false; + } + }, + None => { + *&mut still_ok = false; + }, + }; + } + } + if still_ok == true { + *&mut answer.push(letter); + *&mut counter += 1; + } + } + answer.pop(); + return answer; +}