Added elems to store terminal variables

This commit is contained in:
Justine 2023-03-01 17:00:43 +01:00
parent aec1641024
commit 9e1d0dfcde
2 changed files with 148 additions and 137 deletions

View File

@ -15,7 +15,7 @@ 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:
* Before anything : keep reformating the code. The main loop could use a struct containing current_pos, max_pos, etc.
* 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

View File

@ -3,7 +3,7 @@ pub mod shell {
use std::io::Stdout;
use std::process::Command;
use std::io::stdin;
use std::io::stdout;
use std::io::{stdout, Stdin};
use std::io::Write;
use std::path::Path;
use std::env;
@ -368,215 +368,226 @@ pub mod shell {
}).unwrap();
}
struct TermElements {
//Stores currently typed command
command: String,
//Current cursor position in the line
cur_pos: usize,
//Max position of cursor in the line
max_pos: usize,
//In / out
stdin: Stdin,
stdout: RawTerminal<Stdout>,
//Current history number
current_number: i32,
//Configuration
conf: SqishConf,
}
pub fn run_raw() {
let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap();
//RawTerminal::suspend_raw_mode(&stdout);
let mut mycommand = String::new();
//Used in conjunction with Up arrow to go back in history
//Resetted by pressing Enter
let mut current_number = get_curr_history_number();
//Used to track the location of the cursor inside the command
let mut current_pos: usize = 0;
let mut max_pos: usize = 0;
//Get conf
let mut conf = handle_conf(&mut stdout);
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()),
};
//Handle Ctrl+C
set_ctrlc();
&conf.update_prompt(get_curr_history_number());
&elems.conf.update_prompt(get_curr_history_number());
//Initializing
write!(stdout, "\r\n ---Sqish initializing--- \r\n{}", conf.promptline);
stdout.flush();
write!(elems.stdout, "\r\n ---Sqish initializing--- \r\n{}", elems.conf.promptline);
elems.stdout.flush();
if conf.init != String::from("") {
run_cmd(&mut String::from(&conf.init), &mut current_number, &mut conf, &mut stdout);
if elems.conf.init != String::from("") {
run_cmd(&mut String::from(&elems.conf.init), &mut elems.current_number, &mut elems.conf, &mut elems.stdout);
}
for c in stdin.keys() {
for c in elems.stdin.keys() {
let k = c.unwrap();
match k {
Key::Char('\t') => {
//Do NOT search on an empty command
if *&mycommand.len() == 0 {
if *&elems.command.len() == 0 {
continue;
}
//Search
*&mut mycommand = replace_signs(&mycommand);
let (res, list) = Search::build(&mycommand).unwrap().autocomplete();
if list.len() > 0 { write!(stdout, "{}", list); }
mycommand.clear();
mycommand.push_str(&res);
max_pos = res.len();
current_pos = max_pos;
write!(stdout, "\r\n{}{}", conf.promptline, res);
stdout.flush();
*&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();
}
Key::Char('\n') => {
current_number = get_curr_history_number();
current_pos = 0;
max_pos = 0;
mycommand = transform_alias(&conf, mycommand);
run_cmd(&mut mycommand,
&mut current_number,
&mut conf,
&mut stdout);
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);
},
Key::Ctrl('q'|'d') => {
RawTerminal::suspend_raw_mode(&stdout);
writeln!(stdout, "\r\nThanks for using Sqish !\r\nSayonara \r\n");
RawTerminal::suspend_raw_mode(&elems.stdout);
writeln!(elems.stdout, "\r\nThanks for using Sqish !\r\nSayonara \r\n");
break;
},
Key::Ctrl('c') => {
current_pos = 0;
max_pos = 0;
current_number = get_curr_history_number();
mycommand.clear();
write!(stdout, "\r\n--CANCEL--\r\n");
write!(stdout, "{}", conf.promptline);
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);
},
Key::Ctrl('u') => {
clear_line(&max_pos, &current_pos);
max_pos = 0;
current_pos = 0;
mycommand.clear();
clear_line(&elems.max_pos, &elems.cur_pos);
elems.max_pos = 0;
elems.cur_pos = 0;
elems.command.clear();
},
Key::Ctrl('a') => {
if current_pos != 0 {
write!(stdout, "{}", cursor::Left(current_pos as u16));
current_pos = 0;
if elems.cur_pos != 0 {
write!(elems.stdout, "{}", cursor::Left(elems.cur_pos as u16));
elems.cur_pos = 0;
}
},
Key::Ctrl('e') => {
if current_pos != max_pos {
let chars_left = max_pos - current_pos;
write!(stdout, "{}", cursor::Right(chars_left as u16));
current_pos = max_pos;
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;
}
},
Key::Char(c) => {
write_letter(&mut mycommand, &mut current_pos, &mut max_pos, c);
write_letter(&mut elems.command, &mut elems.cur_pos, &mut elems.max_pos, c);
}
Key::Delete => {
if mycommand.chars().count() == 1
&& current_pos == 0 {
clear_line(&max_pos, &current_pos);
mycommand.clear();
max_pos = 0;
current_pos = 0;
} else if current_pos < max_pos {
mycommand.remove(current_pos);
if current_pos > 0 {
current_pos -= 1;
write!(stdout, "{}", cursor::Left(1));
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));
}
max_pos -= 1;
write!(stdout, "{}", cursor::Save);
clear_line(&max_pos, &current_pos);
write!(stdout, "{}", mycommand);
write!(stdout, "{}", cursor::Restore);
stdout.flush();
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();
}
},
Key::Backspace => {
if current_pos == 0 {
if elems.cur_pos == 0 {
continue;
}
if mycommand.chars().count() == 1 {
clear_line(&max_pos, &current_pos);
mycommand.clear();
current_pos = 0;
max_pos = 0;
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 {
current_pos -= 1;
max_pos -= 1;
mycommand.remove(current_pos);
write!(stdout, "{}", cursor::Left(1));
write!(stdout, "{}", cursor::Save);
clear_line(&max_pos, &current_pos);
write!(stdout, "{}", mycommand);
write!(stdout, "{}", cursor::Restore);
stdout.flush();
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();
}
},
Key::Up => {
if current_number > 2 {
mycommand = delete_current_cmd(mycommand);
current_number -= 1;
let lastcmd = match get_hist_from_number(&current_number) {
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
};
mycommand = lastcmd.trim().to_string();
(max_pos, current_pos) = get_cmd_curs_pos(&mycommand);
write!(stdout, "{}", mycommand);
elems.command = lastcmd.trim().to_string();
(elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command);
write!(elems.stdout, "{}", elems.command);
}
},
Key::Down => {
if current_number < get_curr_history_number() {
mycommand = delete_current_cmd(mycommand);
current_number += 1;
let lastcmd = match get_hist_from_number(&current_number) {
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
};
mycommand = lastcmd.trim().to_string();
(max_pos, current_pos) = get_cmd_curs_pos(&mycommand);
write!(stdout, "{}", mycommand);
elems.command = lastcmd.trim().to_string();
(elems.max_pos, elems.cur_pos) = get_cmd_curs_pos(&elems.command);
write!(elems.stdout, "{}", elems.command);
}
},
Key::Left => {
if current_pos > 0 {
current_pos -= 1;
write!(stdout, "{}", cursor::Left(1));
if elems.cur_pos > 0 {
elems.cur_pos -= 1;
write!(elems.stdout, "{}", cursor::Left(1));
}
},
Key::Right => {
if current_pos < max_pos {
if elems.cur_pos < elems.max_pos {
print!("{}", cursor::Right(1));
current_pos += 1;
elems.cur_pos += 1;
}
},
Key::Ctrl('l') => {
write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1,1));
write!(stdout, "{}{}", conf.promptline, mycommand);
write!(elems.stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1,1));
write!(elems.stdout, "{}{}", elems.conf.promptline, elems.command);
},
Key::Ctrl('p') => {
let steps = find_next_space(&current_pos, &max_pos, &mycommand);
//println!("steps: {:?} cur {:?} max {:?}", steps, current_pos, max_pos);
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));
current_pos += steps;
elems.cur_pos += steps;
}
},
Key::Ctrl('o') => {
let command_rev = mycommand.chars().rev().collect::<String>();
let curr_rev = max_pos - current_pos + 1;
let steps = find_next_space(&curr_rev, &max_pos, &command_rev);
let command_rev = elems.command.chars().rev().collect::<String>();
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));
current_pos -= steps;
elems.cur_pos -= steps;
}
},
@ -584,36 +595,36 @@ pub mod shell {
match x {
'a'..='z' => {
let x = String::from(x);
if conf.hotkeys.contains_key(&x) {
let hotcmd = &conf.hotkeys[&x].clone();
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 mycommand,
&mut current_pos,
&mut max_pos,
write_letter(&mut elems.command,
&mut elems.cur_pos,
&mut elems.max_pos,
c);
} else {
current_pos = 0;
max_pos = 0;
mycommand = transform_alias(&conf, mycommand);
run_cmd(&mut mycommand,
&mut current_number,
&mut conf,
&mut stdout);
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 mycommand, &mut current_pos, &mut max_pos);
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", conf.hotkeys);
cmd = format!("{}\r\n-- ALIASES -->\r\n{:?}\r\n", cmd, conf.aliases);
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!(stdout, "{}", cmd);
write!(elems.stdout, "{}", cmd);
},
_ => (),
@ -623,7 +634,7 @@ pub mod shell {
_ => (),
};
stdout.flush().unwrap();
elems.stdout.flush().unwrap();
}
}