|
|
|
|
@ -20,7 +20,7 @@ pub struct ReaderState {
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum InitTTYError {
|
|
|
|
|
NotATTY
|
|
|
|
|
NotATTY,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
@ -51,7 +51,11 @@ macro_rules! edit_cmd {
|
|
|
|
|
|
|
|
|
|
impl ReaderState {
|
|
|
|
|
pub fn new(prompt: &str) -> Self {
|
|
|
|
|
ReaderState { prompt: String::from(prompt), max_len: prompt.len(), ..Default::default() }
|
|
|
|
|
ReaderState {
|
|
|
|
|
prompt: String::from(prompt),
|
|
|
|
|
max_len: prompt.len(),
|
|
|
|
|
..Default::default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pub fn print(&mut self, txt: String) {
|
|
|
|
|
eprint!("{}", txt);
|
|
|
|
|
@ -66,7 +70,7 @@ impl ReaderState {
|
|
|
|
|
}
|
|
|
|
|
pub fn init_tty(&mut self) -> Result<(), InitTTYError> {
|
|
|
|
|
unsafe {
|
|
|
|
|
use libc::{isatty, termios, ECHO, ICANON, INPCK, TCSANOW, tcgetattr, tcsetattr};
|
|
|
|
|
use libc::{ECHO, ICANON, INPCK, TCSANOW, isatty, tcgetattr, tcsetattr, termios};
|
|
|
|
|
if !(isatty(0) == 1) {
|
|
|
|
|
return Result::Err(InitTTYError::NotATTY);
|
|
|
|
|
}
|
|
|
|
|
@ -82,7 +86,7 @@ impl ReaderState {
|
|
|
|
|
|
|
|
|
|
pub fn restore_tty(&self) -> Result<(), ()> {
|
|
|
|
|
unsafe {
|
|
|
|
|
use libc::{tcsetattr, TCSANOW};
|
|
|
|
|
use libc::{TCSANOW, tcsetattr};
|
|
|
|
|
if self.saved_termios.is_none() {
|
|
|
|
|
Err(())
|
|
|
|
|
} else {
|
|
|
|
|
@ -101,18 +105,20 @@ impl ReaderState {
|
|
|
|
|
|
|
|
|
|
fn current_hist(&mut self) -> Option<String> {
|
|
|
|
|
let i: usize = self.history_inx.unwrap();
|
|
|
|
|
let line = self.history.get(self.history.len().saturating_sub(i+1));
|
|
|
|
|
let line = self.history.get(self.history.len().saturating_sub(i + 1));
|
|
|
|
|
return line.map(|s| s.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_current_hist(&mut self, str: String) {
|
|
|
|
|
let i: usize = self.history_inx.unwrap();
|
|
|
|
|
let len = self.history.len();
|
|
|
|
|
self.history[len.saturating_sub(i+1)] = str;
|
|
|
|
|
self.history[len.saturating_sub(i + 1)] = str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn insert_at_cursor_hist(&mut self, txt: String) {
|
|
|
|
|
let mut line = self.current_hist().expect("Trying to modify a non-existent history entry");
|
|
|
|
|
let mut line = self
|
|
|
|
|
.current_hist()
|
|
|
|
|
.expect("Trying to modify a non-existent history entry");
|
|
|
|
|
line.insert_str(self.cursor, txt.as_str());
|
|
|
|
|
self.history_reset();
|
|
|
|
|
self.set_line(line.clone());
|
|
|
|
|
@ -133,7 +139,7 @@ impl ReaderState {
|
|
|
|
|
let mut read_stat = esc_parse::SequenceState::new();
|
|
|
|
|
let mut out_buf: Vec<esc_parse::InputChar> = Vec::new();
|
|
|
|
|
unsafe {
|
|
|
|
|
use libc::{read, c_void};
|
|
|
|
|
use libc::{c_void, read};
|
|
|
|
|
self.redraw();
|
|
|
|
|
loop {
|
|
|
|
|
read(0, esc_buf.as_mut_ptr() as *mut c_void, 1);
|
|
|
|
|
@ -154,7 +160,7 @@ impl ReaderState {
|
|
|
|
|
Down => edit_cmd!(HistoryNext),
|
|
|
|
|
Left => edit_cmd!(CursorBack),
|
|
|
|
|
Right => edit_cmd!(CursorForward),
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if chr == InputChar::NewLine {
|
|
|
|
|
break;
|
|
|
|
|
@ -203,24 +209,22 @@ impl ReaderState {
|
|
|
|
|
let line = self.line.clone();
|
|
|
|
|
self.submit_line(line.clone());
|
|
|
|
|
println!("{}", line);
|
|
|
|
|
return Ok(line)
|
|
|
|
|
},
|
|
|
|
|
CursorBack => {
|
|
|
|
|
self.move_left()
|
|
|
|
|
},
|
|
|
|
|
return Ok(line);
|
|
|
|
|
}
|
|
|
|
|
CursorBack => self.move_left(),
|
|
|
|
|
CursorForward => {
|
|
|
|
|
self.move_right();
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
DeleteBack => {
|
|
|
|
|
self.backspace();
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
HistoryPrevious => {
|
|
|
|
|
self.history_back();
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
HistoryNext => {
|
|
|
|
|
self.history_front();
|
|
|
|
|
},
|
|
|
|
|
Exit => return Err(ReadError::Exited)
|
|
|
|
|
}
|
|
|
|
|
Exit => return Err(ReadError::Exited),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -249,7 +253,7 @@ impl ReaderState {
|
|
|
|
|
pub fn history_back(&mut self) {
|
|
|
|
|
let h = self.history.clone();
|
|
|
|
|
let mut i = self.history_inx;
|
|
|
|
|
if i.map_or(h.len() == 0, |v| v+1 == h.len()) {
|
|
|
|
|
if i.map_or(h.len() == 0, |v| v + 1 == h.len()) {
|
|
|
|
|
bell();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -257,11 +261,11 @@ impl ReaderState {
|
|
|
|
|
i = Some(0);
|
|
|
|
|
self.history_saved = Some(self.line.clone());
|
|
|
|
|
} else {
|
|
|
|
|
i = i.map(|v| { v + 1 });
|
|
|
|
|
i = i.map(|v| v + 1);
|
|
|
|
|
}
|
|
|
|
|
self.history_inx = i;
|
|
|
|
|
let i: usize = i.unwrap();
|
|
|
|
|
let line = h.get(h.len().saturating_sub(i+1));
|
|
|
|
|
let line = h.get(h.len().saturating_sub(i + 1));
|
|
|
|
|
if line.is_some() {
|
|
|
|
|
self.set_line(line.unwrap().to_string());
|
|
|
|
|
} else {
|
|
|
|
|
@ -285,11 +289,11 @@ impl ReaderState {
|
|
|
|
|
self.history_reset();
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
i = i.map(|v| { v - 1 });
|
|
|
|
|
i = i.map(|v| v - 1);
|
|
|
|
|
self.history_inx = i;
|
|
|
|
|
}
|
|
|
|
|
let i = i.unwrap();
|
|
|
|
|
let line = h.get(h.len().saturating_sub(i+1));
|
|
|
|
|
let line = h.get(h.len().saturating_sub(i + 1));
|
|
|
|
|
if line.is_some() {
|
|
|
|
|
self.set_line(line.unwrap().to_string());
|
|
|
|
|
} else {
|
|
|
|
|
@ -299,7 +303,7 @@ impl ReaderState {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn move_left(&mut self) {
|
|
|
|
|
use esc_parse::{cursor_left, bell};
|
|
|
|
|
use esc_parse::{bell, cursor_left};
|
|
|
|
|
if self.cursor > 0 {
|
|
|
|
|
self.cursor -= 1;
|
|
|
|
|
cursor_left();
|
|
|
|
|
@ -310,7 +314,7 @@ impl ReaderState {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn move_right(&mut self) {
|
|
|
|
|
use esc_parse::{cursor_right, bell};
|
|
|
|
|
use esc_parse::{bell, cursor_right};
|
|
|
|
|
if self.cursor < self.line.len() {
|
|
|
|
|
self.cursor += 1;
|
|
|
|
|
cursor_right();
|
|
|
|
|
@ -326,7 +330,7 @@ impl ReaderState {
|
|
|
|
|
self.max_len = inx;
|
|
|
|
|
}
|
|
|
|
|
esc_parse::cursor_left_nr(self.max_len);
|
|
|
|
|
esc_parse::cursor_right_nr(inx+self.prompt.len());
|
|
|
|
|
esc_parse::cursor_right_nr(inx + self.prompt.len());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn cursor_at(&mut self, inx: usize) {
|
|
|
|
|
@ -337,8 +341,10 @@ impl ReaderState {
|
|
|
|
|
pub fn backspace(&mut self) {
|
|
|
|
|
if self.history_inx.is_some() {
|
|
|
|
|
if self.cursor > 0 {
|
|
|
|
|
let mut line = self.current_hist().expect("Trying to modify a non-existent history entry");
|
|
|
|
|
line.remove(self.cursor-1);
|
|
|
|
|
let mut line = self
|
|
|
|
|
.current_hist()
|
|
|
|
|
.expect("Trying to modify a non-existent history entry");
|
|
|
|
|
line.remove(self.cursor - 1);
|
|
|
|
|
self.move_left();
|
|
|
|
|
self.history_reset();
|
|
|
|
|
self.set_line(line);
|
|
|
|
|
@ -347,7 +353,7 @@ impl ReaderState {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if self.cursor > 0 {
|
|
|
|
|
self.line.remove(self.cursor-1);
|
|
|
|
|
self.line.remove(self.cursor - 1);
|
|
|
|
|
self.move_left();
|
|
|
|
|
} else {
|
|
|
|
|
bell();
|
|
|
|
|
|