cleanup
This commit is contained in:
parent
d7fc72e65d
commit
03131fda71
3 changed files with 83 additions and 45 deletions
65
src/data.rs
65
src/data.rs
|
|
@ -1,4 +1,9 @@
|
||||||
use std::{env, fs::{File, OpenOptions}, io::{BufRead, ErrorKind, Write}, path::PathBuf};
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io::{BufRead, ErrorKind, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
|
|
@ -8,7 +13,7 @@ pub struct Data {
|
||||||
history: Vec<String>,
|
history: Vec<String>,
|
||||||
hist_file: String,
|
hist_file: String,
|
||||||
hist_pos: usize,
|
hist_pos: usize,
|
||||||
hist_partial: String
|
hist_partial: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Data {
|
impl Default for Data {
|
||||||
|
|
@ -27,7 +32,7 @@ impl Default for Data {
|
||||||
history,
|
history,
|
||||||
hist_file,
|
hist_file,
|
||||||
hist_pos,
|
hist_pos,
|
||||||
hist_partial
|
hist_partial,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,20 +62,32 @@ impl Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_prev_hist_item(&mut self) -> Option<String> {
|
pub fn get_prev_hist_item(&mut self) -> Option<String> {
|
||||||
if self.history.is_empty() { return None; }
|
if self.history.is_empty() {
|
||||||
if self.hist_pos <= self.history.len() && self.hist_pos > 0 { self.hist_pos -= 1; Some(self.history[self.hist_pos].clone()) }
|
return None;
|
||||||
else { None }
|
}
|
||||||
|
if self.hist_pos <= self.history.len() && self.hist_pos > 0 {
|
||||||
|
self.hist_pos -= 1;
|
||||||
|
Some(self.history[self.hist_pos].clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_hist_item(&mut self) -> Option<String> {
|
pub fn get_next_hist_item(&mut self) -> Option<String> {
|
||||||
if self.hist_pos < self.history.len() { self.hist_pos += 1; }
|
if self.hist_pos < self.history.len() {
|
||||||
if self.hist_pos < self.history.len() { Some(self.history[self.hist_pos].clone()) }
|
self.hist_pos += 1;
|
||||||
else if self.hist_pos == self.history.len() { Some(self.hist_partial.clone()) }
|
}
|
||||||
else { None }
|
if self.hist_pos < self.history.len() {
|
||||||
|
Some(self.history[self.hist_pos].clone())
|
||||||
|
} else if self.hist_pos == self.history.len() {
|
||||||
|
Some(self.hist_partial.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at_hist_end(&self) -> bool {
|
pub fn at_hist_end(&self) -> bool {
|
||||||
self.hist_pos+1 == self.history.len()
|
self.hist_pos + 1 == self.history.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_hist_file(&mut self, hist_file: &str) {
|
pub fn set_hist_file(&mut self, hist_file: &str) {
|
||||||
|
|
@ -78,15 +95,20 @@ impl Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_history(&self) {
|
pub fn save_history(&self) {
|
||||||
let mut hist_file = match OpenOptions::new().create(true).write(true).open(&self.hist_file) {
|
let mut hist_file = match OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&self.hist_file)
|
||||||
|
{
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprint!("\r\n{e}");
|
eprint!("\r\n{e}");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for line in &self.history {
|
for line in &self.history {
|
||||||
write!(hist_file, "{line}\n").unwrap();
|
writeln!(hist_file, "{line}").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,9 +116,12 @@ impl Data {
|
||||||
let hist_file = match File::open(&self.hist_file) {
|
let hist_file = match File::open(&self.hist_file) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if e.kind() == ErrorKind::NotFound {eprint!("\r\nHistory file not found, creating")}
|
if e.kind() == ErrorKind::NotFound {
|
||||||
else { eprint!("\r\n{e}"); }
|
eprint!("\r\nHistory file not found, creating")
|
||||||
return
|
} else {
|
||||||
|
eprint!("\r\n{e}");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let reader = std::io::BufReader::new(hist_file);
|
let reader = std::io::BufReader::new(hist_file);
|
||||||
|
|
@ -106,12 +131,12 @@ impl Data {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
self.history.push(line.trim().to_string());
|
self.history.push(line.trim().to_string());
|
||||||
self.hist_pos += 1;
|
self.hist_pos += 1;
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprint!("\r\n{e}");
|
eprint!("\r\n{e}");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
src/key.rs
13
src/key.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use std::io::{stdin, Read};
|
use std::io::{Read, stdin};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
|
|
@ -10,8 +10,7 @@ pub enum Key {
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
#[allow(dead_code)]
|
Unknown(Vec<u8>),
|
||||||
Unknown(Vec<u8>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for Key {
|
impl From<u8> for Key {
|
||||||
|
|
@ -30,11 +29,11 @@ impl From<u8> for Key {
|
||||||
[b'[', b'B'] => Key::ArrowDown,
|
[b'[', b'B'] => Key::ArrowDown,
|
||||||
[b'[', b'C'] => Key::ArrowRight,
|
[b'[', b'C'] => Key::ArrowRight,
|
||||||
[b'[', b'D'] => Key::ArrowLeft,
|
[b'[', b'D'] => Key::ArrowLeft,
|
||||||
_ => Key::Unknown(vec![27, buf[0], buf[1]])
|
_ => Key::Unknown(vec![27, buf[0], buf[1]]),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
char if char.is_ascii() => Key::Char(byte as char),
|
char if char.is_ascii() => Key::Char(byte as char),
|
||||||
byte => Key::Unknown(vec![byte])
|
byte => Key::Unknown(vec![byte]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
src/main.rs
50
src/main.rs
|
|
@ -1,12 +1,12 @@
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
io::{self, stdin, stdout, Read, Stdin, Stdout, Write},
|
io::{self, Read, Stdin, Stdout, Write, stdin, stdout},
|
||||||
process::Command,
|
process::Command,
|
||||||
str::SplitWhitespace,
|
str::SplitWhitespace,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod raw;
|
mod raw;
|
||||||
use raw::{enable_raw_mode, disable_raw_mode};
|
use raw::{disable_raw_mode, enable_raw_mode};
|
||||||
|
|
||||||
mod key;
|
mod key;
|
||||||
use key::Key;
|
use key::Key;
|
||||||
|
|
@ -16,7 +16,11 @@ use data::Data;
|
||||||
|
|
||||||
fn print_prompt(pre_input: &str, data: &mut Data, newline: bool) -> io::Result<()> {
|
fn print_prompt(pre_input: &str, data: &mut Data, newline: bool) -> io::Result<()> {
|
||||||
if newline {
|
if newline {
|
||||||
print!("\r\n{}\r\n> {}", data.get_current_path().display(), pre_input);
|
print!(
|
||||||
|
"\r\n{}\r\n> {}",
|
||||||
|
data.get_current_path().display(),
|
||||||
|
pre_input
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
print!("\r> {}", pre_input);
|
print!("\r> {}", pre_input);
|
||||||
}
|
}
|
||||||
|
|
@ -55,21 +59,23 @@ fn handle_input(stdin: &mut Stdin, stdout: &mut Stdout, data: &mut Data) -> io::
|
||||||
Key::Escape => continue,
|
Key::Escape => continue,
|
||||||
Key::ArrowUp => {
|
Key::ArrowUp => {
|
||||||
if let Some(hist_command) = data.get_prev_hist_item() {
|
if let Some(hist_command) = data.get_prev_hist_item() {
|
||||||
if data.at_hist_end() { data.save_command(input.clone()); }
|
if data.at_hist_end() {
|
||||||
|
data.save_command(input.clone());
|
||||||
|
}
|
||||||
flush_prompt(input.len())?;
|
flush_prompt(input.len())?;
|
||||||
input = hist_command.clone();
|
input = hist_command.clone();
|
||||||
print_prompt(&input, data, false)?;
|
print_prompt(&input, data, false)?;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Key::ArrowDown => {
|
Key::ArrowDown => {
|
||||||
if let Some(hist_command) = data.get_next_hist_item() {
|
if let Some(hist_command) = data.get_next_hist_item() {
|
||||||
flush_prompt(input.len())?;
|
flush_prompt(input.len())?;
|
||||||
input = hist_command.clone();
|
input = hist_command.clone();
|
||||||
print_prompt(&input, data, false)?;
|
print_prompt(&input, data, false)?;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Key::ArrowLeft => {},
|
Key::ArrowLeft => {}
|
||||||
Key::ArrowRight => {},
|
Key::ArrowRight => {}
|
||||||
Key::Char(c) => {
|
Key::Char(c) => {
|
||||||
input.push(c);
|
input.push(c);
|
||||||
write!(stdout, "{c}")?;
|
write!(stdout, "{c}")?;
|
||||||
|
|
@ -94,13 +100,15 @@ where
|
||||||
|
|
||||||
fn run_command(command: &str, args: SplitWhitespace, data: &mut Data) -> Result<u8, String> {
|
fn run_command(command: &str, args: SplitWhitespace, data: &mut Data) -> Result<u8, String> {
|
||||||
match command {
|
match command {
|
||||||
"exit" => return Ok(1),
|
"exit" => Ok(1),
|
||||||
"cd" => {
|
"cd" => {
|
||||||
let path = args.peekable().peek().map_or("~", |dir| *dir);
|
let path = args.peekable().peek().map_or("~", |dir| *dir);
|
||||||
|
|
||||||
let mut new_path = data.get_current_path();
|
let mut new_path = data.get_current_path();
|
||||||
|
|
||||||
if path.chars().nth(0).unwrap() == '/' { new_path.push("/"); }
|
if path.starts_with('/') {
|
||||||
|
new_path.push("/");
|
||||||
|
}
|
||||||
for subpath in path.split("/") {
|
for subpath in path.split("/") {
|
||||||
match subpath {
|
match subpath {
|
||||||
"-" => {
|
"-" => {
|
||||||
|
|
@ -129,8 +137,11 @@ fn run_command(command: &str, args: SplitWhitespace, data: &mut Data) -> Result<
|
||||||
let child = Command::new(command).args(args).spawn();
|
let child = Command::new(command).args(args).spawn();
|
||||||
|
|
||||||
match child {
|
match child {
|
||||||
Ok(mut child) => { child.wait().unwrap(); Ok(0) }
|
Ok(mut child) => {
|
||||||
Err(e) => { return Err(e.to_string()); }
|
child.wait().unwrap();
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,17 +156,20 @@ fn rush_loop(data: &mut Data, orig: libc::termios) -> io::Result<()> {
|
||||||
|
|
||||||
let input = handle_input(&mut stdin, &mut stdout, data)?;
|
let input = handle_input(&mut stdin, &mut stdout, data)?;
|
||||||
let input = input.trim();
|
let input = input.trim();
|
||||||
if input.is_empty() { continue; }
|
if input.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let input = input.split_whitespace();
|
let input = input.split_whitespace();
|
||||||
let (command, args) = parse_input(input);
|
let (command, args) = parse_input(input);
|
||||||
|
|
||||||
disable_raw_mode(&orig);
|
disable_raw_mode(&orig);
|
||||||
match run_command(command, args, data) {
|
match run_command(command, args, data) {
|
||||||
Ok(status) => match status {
|
Ok(status) => {
|
||||||
1 => return Ok(()),
|
if status == 1 {
|
||||||
_ => {}
|
return Ok(());
|
||||||
},
|
}
|
||||||
Err(e) => eprint!("{e}\r\n")
|
}
|
||||||
|
Err(e) => eprint!("{e}\r\n"),
|
||||||
}
|
}
|
||||||
enable_raw_mode();
|
enable_raw_mode();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue