From 65831280226a12879aff6dcd3acc9e1e696482c6 Mon Sep 17 00:00:00 2001 From: Justine Date: Tue, 31 Jan 2023 12:01:33 +0100 Subject: [PATCH] Autocomplete fonctionne --- Cargo.lock | 58 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/lib.rs | 61 ++++++++++++--------------------------- src/shell/autocomplete.rs | 50 +++++++++++++++++++++++++++++--- src/shell/history.rs | 1 + src/shell/prompt.rs | 42 +++++++++++++++++++++++++++ 6 files changed, 168 insertions(+), 46 deletions(-) create mode 100644 src/shell/prompt.rs diff --git a/Cargo.lock b/Cargo.lock index 5c56024..2ef228e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -34,6 +43,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "gethostname" version = "0.4.1" @@ -70,12 +85,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "numtoa" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + [[package]] name = "proc-macro2" version = "1.0.47" @@ -123,15 +150,34 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + [[package]] name = "sqish" version = "0.1.0" dependencies = [ "dirs", "gethostname", + "regex", "termion", "unicode-segmentation", "users", + "which", ] [[package]] @@ -205,6 +251,18 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", + "regex", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 00eb645..64921d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,5 @@ users = "0.11.0" gethostname = "0.4.1" termion = "2.0.1" unicode-segmentation = "1.6.0" +which = { version = "4.4.0", features = ["regex"] } +regex = "1.7.1" diff --git a/src/lib.rs b/src/lib.rs index 49a1670..21850c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,11 +8,10 @@ pub mod shell { use std::env; use std::str; use std::process::Stdio; - use users::{get_user_by_uid, get_current_uid}; use termion::event::Key; use termion::input::TermRead; use termion::raw::IntoRawMode; - use termion::{color, cursor}; + use termion::cursor; use unicode_segmentation::UnicodeSegmentation; mod history; @@ -21,6 +20,8 @@ pub mod shell { mod autocomplete; use crate::shell::autocomplete::*; + mod prompt; + use crate::shell::prompt::*; //used for home directory extern crate dirs; @@ -54,6 +55,11 @@ pub mod shell { Err(e) => eprintln!(" Err: {}", e), } }, + "ssh" => { + let ssh_args = args.peekable().peek().map_or(" ", |x| *x); + let mut child = Command::new("ssh").arg(ssh_args).spawn().unwrap(); + let _ = child.wait().unwrap(); + }, command => { if commands.peek().is_some() { let stdin = match previous_command { @@ -104,44 +110,6 @@ pub mod shell { return resultat; } - fn build_prompt(curr_number: &i32) -> String { - - let user = String::from( - get_user_by_uid(get_current_uid()) - .unwrap() - .name() - .to_str() - .unwrap() - ); - - let host = String::from( - gethostname::gethostname() - .to_str() - .unwrap() - ); - - let current_dir = String::from( - env::current_dir() - .unwrap() - .to_str() - .unwrap() - ); - - let s = current_dir.split('/'); - let dir_last = String::from( - s.last() - .unwrap() - ); - - let prompt = String::from(format!("{}{}{}[{}@{} in {}]{} ", - color::Fg(color::LightBlack), - curr_number, - color::Fg(color::LightCyan), - user, host, dir_last, - color::Fg(color::Reset))); - return prompt; - } - fn replace_signs(line: &String) -> String { let mut ayo = String::from(line); if ayo.contains('~') { @@ -242,9 +210,12 @@ pub mod shell { match c.unwrap() { Key::Char('\t') => { - let res = autocomplete(&mycommand); + let (res, list) = autocomplete(&mycommand); + write!(stdout, "\r\n{}\r\n", list); mycommand.clear(); mycommand.push_str(&res); + max_pos = res.len(); + current_pos = max_pos; write!(stdout, "\r\n{}{}", prompt, res); stdout.flush(); } @@ -281,7 +252,13 @@ pub mod shell { }, Key::Ctrl('c') => { - continue; + current_pos = 0; + max_pos = 0; + mycommand.clear(); + write!(stdout, "\r\n--CANCEL--\r\n"); + current_number = get_curr_history_number(); + prompt = build_prompt(¤t_number); + write!(stdout, "{}", prompt); }, Key::Ctrl('t') => { diff --git a/src/shell/autocomplete.rs b/src/shell/autocomplete.rs index 032671a..39a36e0 100644 --- a/src/shell/autocomplete.rs +++ b/src/shell/autocomplete.rs @@ -1,8 +1,50 @@ -pub fn autocomplete(input: &String) -> String { +use which::which_re; +use regex::Regex; +use std::path::PathBuf; + +pub fn autocomplete(input: &String) -> (String, String) { let faketab = format!(" --This is a fake output for autocomplete from {input}-- "); - //In reality, we would keep the input and append to it - let aaa = String::from(faketab); - return aaa; + + let found_bins = find_bin(input); + if found_bins.len() == 1 { + let aaa = found_bins.clone(); + let bbb = &aaa[0] + .iter() + .last() + .unwrap(); + let res_string = String::from(bbb.to_str().unwrap()); + let res_list = res_string.clone(); + return (res_string, res_list); + } else if found_bins.len() == 0 { + let list = String::from("Nothing adequate."); + let res = String::from(input); + return (res, list); + } else { + let mut all_res = String::new(); + for path in found_bins { + let buff = String::from(path + .iter() + .last() + .unwrap() + .to_str() + .unwrap()); + let res_line = format!("* {}\r\n", buff); + all_res.push_str(&res_line); + } + let first_res = String::from(input); + return(first_res, all_res) + + } +} + +///Takes a string and returns a Vector of PathBuf containing all matchings +///commands +fn find_bin(command: &String) -> Vec { + let re = format!("^{}.*", command); + let re = Regex::new(&re).unwrap(); + let binaries: Vec = which_re(re).unwrap().collect(); + return binaries; } + diff --git a/src/shell/history.rs b/src/shell/history.rs index fb03608..2e06b1b 100644 --- a/src/shell/history.rs +++ b/src/shell/history.rs @@ -53,6 +53,7 @@ pub fn get_history() -> Result { let myline = format!("\r\n{}", line.unwrap()); res.push_str(&myline); } + res.push_str("\r\n"); return Ok(res); } diff --git a/src/shell/prompt.rs b/src/shell/prompt.rs new file mode 100644 index 0000000..9a26b48 --- /dev/null +++ b/src/shell/prompt.rs @@ -0,0 +1,42 @@ +use users::{get_user_by_uid, get_current_uid}; +use termion::color; +use std::env; + +pub fn build_prompt(curr_number: &i32) -> String { + + let user = String::from( + get_user_by_uid(get_current_uid()) + .unwrap() + .name() + .to_str() + .unwrap() + ); + + let host = String::from( + gethostname::gethostname() + .to_str() + .unwrap() + ); + + let current_dir = String::from( + env::current_dir() + .unwrap() + .to_str() + .unwrap() + ); + + let s = current_dir.split('/'); + let dir_last = String::from( + s.last() + .unwrap() + ); + + let prompt = String::from(format!("{}{}{}[{}@{} in {}]{} ", + color::Fg(color::LightBlack), + curr_number, + color::Fg(color::LightCyan), + user, host, dir_last, + color::Fg(color::Reset))); + return prompt; +} +