From 4c64bb803840f6eb967165c4fb2b184ccdc4ee81 Mon Sep 17 00:00:00 2001 From: Justine Date: Wed, 1 Mar 2023 17:40:03 +0100 Subject: [PATCH] Reformatted the code to use elems --- README.md | 1 - src/lib.rs | 399 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 229 insertions(+), 171 deletions(-) diff --git a/README.md b/README.md index 74e16d6..e91b0d8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ Sqish is now my default shell on my home computer, and I'll keep adding features Also keep in mind I'm a beginner in Rust, so the code is pretty dirty; I will probably come around to reformating it once I have all the features I want and ironed out all the bugs. TODO: -* Use elems in all function, subdivide Keys actions into functions taking termelems. * Allow redirecting >> to the end of a file ? * Allow && in commands ? * Improve word jumping diff --git a/src/lib.rs b/src/lib.rs index f208b2a..babd18c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ pub mod shell { use std::io::Stdout; use std::process::Command; use std::io::stdin; - use std::io::{stdout, Stdin}; + use std::io::{stdout}; use std::io::Write; use std::path::Path; use std::env; @@ -258,8 +258,6 @@ pub mod shell { } - - fn run_cmd(mycommand: &mut String, current_number: &mut i32, conf: &mut SqishConf, @@ -368,6 +366,156 @@ pub mod shell { }).unwrap(); } + fn tab(elems: &mut TermElements) { + //Do NOT search on an empty command + if *&elems.command.len() == 0 { + return; + } + //Search + *&mut elems.command = replace_signs(&elems.command); + let (res, list) = Search::build(&elems.command).unwrap().autocomplete(); + if list.len() > 1 { write!(elems.stdout, "\r\n{}", list); } + elems.command.clear(); + elems.command.push_str(&res); + elems.max_pos = res.len(); + elems.cur_pos = elems.max_pos; + write!(elems.stdout, "\r\n{}{}", elems.conf.promptline, res); + elems.stdout.flush(); + } + + fn enter(elems: &mut TermElements) { + elems.current_number = get_curr_history_number(); + elems.cur_pos = 0; + elems.max_pos = 0; + *&mut elems.command = transform_alias(&elems.conf, elems.command.clone()); + run_cmd(&mut elems.command, + &mut elems.current_number, + &mut elems.conf, + &mut elems.stdout); + } + + fn cmd_clear(elems: &mut TermElements) { + elems.cur_pos = 0; + elems.max_pos = 0; + elems.current_number = get_curr_history_number(); + elems.command.clear(); + write!(elems.stdout, "\r\n--CANCEL--\r\n"); + write!(elems.stdout, "{}", elems.conf.promptline); + } + + fn undo_line(elems: &mut TermElements) { + clear_line(&elems.max_pos, &elems.cur_pos); + elems.max_pos = 0; + elems.cur_pos = 0; + elems.command.clear(); + } + + fn jmp_start(elems: &mut TermElements) { + if elems.cur_pos != 0 { + write!(elems.stdout, "{}", cursor::Left(elems.cur_pos as u16)); + elems.cur_pos = 0; + } + } + + fn jmp_end(elems: &mut TermElements) { + if elems.cur_pos != elems.max_pos { + let chars_left = elems.max_pos - elems.cur_pos; + write!(elems.stdout, "{}", cursor::Right(chars_left as u16)); + elems.cur_pos = elems.max_pos; + } + } + + fn press_del(elems: &mut TermElements) { + if elems.command.chars().count() == 1 + && elems.cur_pos == 0 { + clear_line(&elems.max_pos, &elems.cur_pos); + elems.command.clear(); + elems.max_pos = 0; + elems.cur_pos = 0; + } else if elems.cur_pos < elems.max_pos { + elems.command.remove(elems.cur_pos); + if elems.cur_pos > 0 { + elems.cur_pos -= 1; + write!(elems.stdout, "{}", cursor::Left(1)); + } + elems.max_pos -= 1; + write!(elems.stdout, "{}", cursor::Save); + clear_line(&elems.max_pos, &elems.cur_pos); + write!(elems.stdout, "{}", elems.command); + write!(elems.stdout, "{}", cursor::Restore); + elems.stdout.flush(); + } + } + + fn backspace(elems: &mut TermElements) { + if elems.cur_pos == 0 { + return; + } + if elems.command.chars().count() == 1 { + clear_line(&elems.max_pos, &elems.cur_pos); + elems.command.clear(); + elems.cur_pos = 0; + elems.max_pos = 0; + } else { + elems.cur_pos -= 1; + elems.max_pos -= 1; + elems.command.remove(elems.cur_pos); + write!(elems.stdout, "{}", cursor::Left(1)); + write!(elems.stdout, "{}", cursor::Save); + clear_line(&elems.max_pos, &elems.cur_pos); + write!(elems.stdout, "{}", elems.command); + write!(elems.stdout, "{}", cursor::Restore); + elems.stdout.flush(); + } + } + + fn uparrow(elems: &mut TermElements) { + if elems.current_number > 2 { + elems.command = delete_current_cmd(elems.command.clone()); + elems.current_number -= 1; + let lastcmd = match get_hist_from_number(&elems.current_number) { + Some(c) => c, + None => return + }; + elems.command = lastcmd.trim().to_string(); + (elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command); + write!(elems.stdout, "{}", elems.command); + } + } + + fn downarrow(elems: &mut TermElements) { + if elems.current_number < get_curr_history_number() { + elems.command = delete_current_cmd(elems.command.clone()); + elems.current_number += 1; + let lastcmd = match get_hist_from_number(&elems.current_number) { + Some(c) => c, + None => return + }; + elems.command = lastcmd.trim().to_string(); + (elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command); + write!(elems.stdout, "{}", elems.command); + } + } + + fn leftarrow(elems: &mut TermElements) { + if elems.cur_pos > 0 { + elems.cur_pos -= 1; + write!(elems.stdout, "{}", cursor::Left(1)); + } + } + + fn rightarrow(elems: &mut TermElements) { + if elems.cur_pos < elems.max_pos { + print!("{}", cursor::Right(1)); + elems.cur_pos += 1; + } + } + + fn screen_clear(elems: &mut TermElements) { + write!(elems.stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1,1)); + write!(elems.stdout, "{}{}", elems.conf.promptline, elems.command); + } + struct TermElements { //Stores currently typed command command: String, @@ -375,8 +523,6 @@ pub mod shell { cur_pos: usize, //Max position of cursor in the line max_pos: usize, - //In / out - stdin: Stdin, stdout: RawTerminal, //Current history number current_number: i32, @@ -384,18 +530,78 @@ pub mod shell { conf: SqishConf, } + fn jmp_nxt_word(elems: &mut TermElements) { + let steps = find_next_space(&elems.cur_pos, &elems.max_pos, &elems.command); + //println!("steps: {:?} cur {:?} max {:?}", steps, elems.cur_pos, elems.max_pos); + if steps > 0 { + print!("{}", cursor::Right(steps as u16)); + elems.cur_pos += steps; + } + } + + fn jmp_prev_word(elems: &mut TermElements) { + let command_rev = elems.command.chars().rev().collect::(); + let curr_rev = elems.max_pos - elems.cur_pos + 1; + let steps = find_next_space(&curr_rev, &elems.max_pos, &command_rev); + if steps > 0 { + print!("{}", cursor::Left(steps as u16)); + elems.cur_pos -= steps; + } + } + + fn press_alt(elems: &mut TermElements, x: char) { + match x { + 'a'..='z' => { + let x = String::from(x); + if elems.conf.hotkeys.contains_key(&x) { + let hotcmd = &elems.conf.hotkeys[&x].clone(); + for c in hotcmd.chars() { + if c != '\n' { + write_letter(&mut elems.command, + &mut elems.cur_pos, + &mut elems.max_pos, + c); + } else { + elems.cur_pos = 0; + elems.max_pos = 0; + elems.command = transform_alias(&elems.conf, elems.command.clone()); + run_cmd(&mut elems.command, + &mut elems.current_number, + &mut elems.conf, + &mut elems.stdout); + } + + } + } + }, + '.' => { + append_prev_arg(&mut elems.command, &mut elems.cur_pos, &mut elems.max_pos); + }, + '!' => { + let mut cmd = format!("\r\n-- HOTKEYS --> \r\n{:?}\r\n", elems.conf.hotkeys); + cmd = format!("{}\r\n-- ALIASES -->\r\n{:?}\r\n", cmd, elems.conf.aliases); + cmd = cmd.replace(",", "\r\n"); + cmd = cmd.replace('"', ""); + write!(elems.stdout, "{}", cmd); + }, + _ => (), + }; + } + + //THE ENTRYPOINT FUNCTION pub fn run_raw() { let mut elems = TermElements { command: String::new(), cur_pos: 0, max_pos: 0, - stdin: stdin(), stdout: stdout().into_raw_mode().unwrap(), current_number: get_curr_history_number(), conf: handle_conf(&mut stdout().into_raw_mode().unwrap()), }; + let stdin = stdin(); + //Handle Ctrl+C set_ctrlc(); @@ -409,71 +615,35 @@ pub mod shell { run_cmd(&mut String::from(&elems.conf.init), &mut elems.current_number, &mut elems.conf, &mut elems.stdout); } - for c in elems.stdin.keys() { + for c in stdin.keys() { let k = c.unwrap(); match k { Key::Char('\t') => { - //Do NOT search on an empty command - if *&elems.command.len() == 0 { - continue; - } - //Search - *&mut elems.command = replace_signs(&elems.command); - let (res, list) = Search::build(&elems.command).unwrap().autocomplete(); - if list.len() > 1 { write!(elems.stdout, "\r\n{}", list); } - elems.command.clear(); - elems.command.push_str(&res); - elems.max_pos = res.len(); - elems.cur_pos = elems.max_pos; - write!(elems.stdout, "\r\n{}{}", elems.conf.promptline, res); - elems.stdout.flush(); + tab(&mut elems); } Key::Char('\n') => { - elems.current_number = get_curr_history_number(); - elems.cur_pos = 0; - elems.max_pos = 0; - elems.command = transform_alias(&elems.conf, elems.command); - run_cmd(&mut elems.command, - &mut elems.current_number, - &mut elems.conf, - &mut elems.stdout); + enter(&mut elems); }, Key::Ctrl('q'|'d') => { - RawTerminal::suspend_raw_mode(&elems.stdout); writeln!(elems.stdout, "\r\nThanks for using Sqish !\r\nSayonara \r\n"); break; }, Key::Ctrl('c') => { - elems.cur_pos = 0; - elems.max_pos = 0; - elems.current_number = get_curr_history_number(); - elems.command.clear(); - write!(elems.stdout, "\r\n--CANCEL--\r\n"); - write!(elems.stdout, "{}", elems.conf.promptline); + cmd_clear(&mut elems); }, Key::Ctrl('u') => { - clear_line(&elems.max_pos, &elems.cur_pos); - elems.max_pos = 0; - elems.cur_pos = 0; - elems.command.clear(); + undo_line(&mut elems); }, Key::Ctrl('a') => { - if elems.cur_pos != 0 { - write!(elems.stdout, "{}", cursor::Left(elems.cur_pos as u16)); - elems.cur_pos = 0; - } + jmp_start(&mut elems); }, Key::Ctrl('e') => { - if elems.cur_pos != elems.max_pos { - let chars_left = elems.max_pos - elems.cur_pos; - write!(elems.stdout, "{}", cursor::Right(chars_left as u16)); - elems.cur_pos = elems.max_pos; - } + jmp_end(&mut elems); }, Key::Char(c) => { @@ -481,154 +651,43 @@ pub mod shell { } Key::Delete => { - if elems.command.chars().count() == 1 - && elems.cur_pos == 0 { - clear_line(&elems.max_pos, &elems.cur_pos); - elems.command.clear(); - elems.max_pos = 0; - elems.cur_pos = 0; - } else if elems.cur_pos < elems.max_pos { - elems.command.remove(elems.cur_pos); - if elems.cur_pos > 0 { - elems.cur_pos -= 1; - write!(elems.stdout, "{}", cursor::Left(1)); - } - elems.max_pos -= 1; - write!(elems.stdout, "{}", cursor::Save); - clear_line(&elems.max_pos, &elems.cur_pos); - write!(elems.stdout, "{}", elems.command); - write!(elems.stdout, "{}", cursor::Restore); - elems.stdout.flush(); - } + press_del(&mut elems); }, Key::Backspace => { - if elems.cur_pos == 0 { - continue; - } - if elems.command.chars().count() == 1 { - clear_line(&elems.max_pos, &elems.cur_pos); - elems.command.clear(); - elems.cur_pos = 0; - elems.max_pos = 0; - } else { - elems.cur_pos -= 1; - elems.max_pos -= 1; - elems.command.remove(elems.cur_pos); - write!(elems.stdout, "{}", cursor::Left(1)); - write!(elems.stdout, "{}", cursor::Save); - clear_line(&elems.max_pos, &elems.cur_pos); - write!(elems.stdout, "{}", elems.command); - write!(elems.stdout, "{}", cursor::Restore); - elems.stdout.flush(); - } + backspace(&mut elems); }, Key::Up => { - if elems.current_number > 2 { - elems.command = delete_current_cmd(elems.command); - elems.current_number -= 1; - let lastcmd = match get_hist_from_number(&elems.current_number) { - Some(c) => c, - None => continue - }; - elems.command = lastcmd.trim().to_string(); - (elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command); - write!(elems.stdout, "{}", elems.command); - } + uparrow(&mut elems); }, Key::Down => { - if elems.current_number < get_curr_history_number() { - elems.command = delete_current_cmd(elems.command); - elems.current_number += 1; - let lastcmd = match get_hist_from_number(&elems.current_number) { - Some(c) => c, - None => continue - }; - elems.command = lastcmd.trim().to_string(); - (elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command); - write!(elems.stdout, "{}", elems.command); - } + downarrow(&mut elems); }, Key::Left => { - if elems.cur_pos > 0 { - elems.cur_pos -= 1; - write!(elems.stdout, "{}", cursor::Left(1)); - } + leftarrow(&mut elems); }, Key::Right => { - if elems.cur_pos < elems.max_pos { - print!("{}", cursor::Right(1)); - elems.cur_pos += 1; - } + rightarrow(&mut elems); }, Key::Ctrl('l') => { - write!(elems.stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1,1)); - write!(elems.stdout, "{}{}", elems.conf.promptline, elems.command); - + screen_clear(&mut elems); }, Key::Ctrl('p') => { - let steps = find_next_space(&elems.cur_pos, &elems.max_pos, &elems.command); - //println!("steps: {:?} cur {:?} max {:?}", steps, elems.cur_pos, elems.max_pos); - if steps > 0 { - print!("{}", cursor::Right(steps as u16)); - elems.cur_pos += steps; - } + jmp_nxt_word(&mut elems); }, Key::Ctrl('o') => { - let command_rev = elems.command.chars().rev().collect::(); - let curr_rev = elems.max_pos - elems.cur_pos + 1; - let steps = find_next_space(&curr_rev, &elems.max_pos, &command_rev); - if steps > 0 { - print!("{}", cursor::Left(steps as u16)); - elems.cur_pos -= steps; - } + jmp_prev_word(&mut elems); }, Key::Alt(x) => { - match x { - 'a'..='z' => { - let x = String::from(x); - if elems.conf.hotkeys.contains_key(&x) { - let hotcmd = &elems.conf.hotkeys[&x].clone(); - for c in hotcmd.chars() { - if c != '\n' { - write_letter(&mut elems.command, - &mut elems.cur_pos, - &mut elems.max_pos, - c); - } else { - elems.cur_pos = 0; - elems.max_pos = 0; - elems.command = transform_alias(&elems.conf, elems.command); - run_cmd(&mut elems.command, - &mut elems.current_number, - &mut elems.conf, - &mut elems.stdout); - } - - } - } - }, - '.' => { - append_prev_arg(&mut elems.command, &mut elems.cur_pos, &mut elems.max_pos); - }, - '!' => { - let mut cmd = format!("\r\n-- HOTKEYS --> \r\n{:?}\r\n", elems.conf.hotkeys); - cmd = format!("{}\r\n-- ALIASES -->\r\n{:?}\r\n", cmd, elems.conf.aliases); - cmd = cmd.replace(",", "\r\n"); - cmd = cmd.replace('"', ""); - write!(elems.stdout, "{}", cmd); - }, - - _ => (), - }; + press_alt(&mut elems, x); }, _ => (),