use super::Imiop;
use crate::config::Config;
use crate::runtime::print_err;
use crate::shell::Shell;
use crate::translator::ioprocessor::IOProcessor;
use crate::utils::buffer;
use crate::utils::console::{self, InputEvent};
pub(crate) struct SubProcIop {
input_buffer: Vec<char>,
input_buffer_cursor: usize,
config: Config,
processor: IOProcessor,
}
impl SubProcIop {
pub fn new(config: Config, processor: IOProcessor) -> SubProcIop {
SubProcIop {
input_buffer: Vec::with_capacity(2048),
input_buffer_cursor: 0,
config: config,
processor: processor,
}
}
fn clear_buffer(&mut self) {
self.input_buffer.clear();
self.input_buffer_cursor = 0;
}
fn backspace(&mut self) {
if self.input_buffer_cursor > 0 {
self.input_buffer_cursor -= 1;
if self.input_buffer.len() > self.input_buffer_cursor {
self.input_buffer.remove(self.input_buffer_cursor);
}
console::backspace();
}
}
fn perform_enter(&mut self, shell: &mut Shell) {
let stdin_input: String = buffer::chars_to_string(&self.input_buffer);
if stdin_input.trim().len() > 0 {
let input: String = self.processor.text_to_latin(&stdin_input);
if let Err(err) = shell.write(input) {
print_err(
String::from(err.to_string()),
self.config.output_config.translate_output,
&self.processor,
);
}
}
self.clear_buffer();
}
}
impl Imiop for SubProcIop {
fn handle_input_event(&mut self, ev: InputEvent, shell: &mut Shell) {
match ev {
InputEvent::ArrowDown => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::ArrowUp => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::ArrowLeft => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::ArrowRight => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::Backspace => {
self.backspace();
}
InputEvent::CarriageReturn => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::Ctrl(_) => {
let _ = shell.write(console::input_event_to_string(ev));
}
InputEvent::Key(k) => {
for ch in k.chars() {
self.input_buffer.insert(self.input_buffer_cursor, ch);
self.input_buffer_cursor += 1;
}
console::print(k);
}
InputEvent::Enter => {
self.perform_enter(shell);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::Config;
use crate::translator::ioprocessor::IOProcessor;
use crate::translator::lang::Language;
use crate::translator::new_translator;
use std::thread::sleep;
use std::time::Duration;
#[test]
fn test_runtimeprops_new() {
let processor = new_subprociop();
assert!(processor.config.get_alias(&String::from("ll")).is_none());
assert_eq!(processor.processor.language, Language::Russian);
assert_eq!(processor.input_buffer.capacity(), 2048);
assert_eq!(processor.input_buffer_cursor, 0);
}
#[test]
fn test_runtimeprops_backspace() {
let mut processor = new_subprociop();
processor.input_buffer = vec!['a', 'b', 'c'];
processor.backspace();
assert_eq!(processor.input_buffer_cursor, 0);
assert_eq!(processor.input_buffer.len(), 3);
processor.input_buffer_cursor = 3;
processor.backspace();
assert_eq!(processor.input_buffer_cursor, 2);
assert_eq!(processor.input_buffer, vec!['a', 'b']);
processor.input_buffer_cursor = 1;
processor.backspace();
assert_eq!(processor.input_buffer_cursor, 0);
assert_eq!(processor.input_buffer, vec!['b']);
processor.input_buffer = vec!['a', 'b', 'c'];
processor.input_buffer_cursor = 4;
processor.backspace();
assert_eq!(processor.input_buffer_cursor, 3);
assert_eq!(processor.input_buffer.len(), 3);
}
#[test]
fn test_runtimeprops_handle_input_event_not_interactive() {
let mut processor = new_subprociop();
let mut shell: Shell = Shell::start(
String::from("sh"),
Vec::new(),
&processor.config.prompt_config,
)
.unwrap();
sleep(Duration::from_millis(500)); processor.input_buffer = vec!['l', 's'];
processor.input_buffer_cursor = 2;
processor.handle_input_event(InputEvent::Enter, &mut shell);
assert_eq!(processor.input_buffer.len(), 0);
assert_eq!(processor.input_buffer_cursor, 0);
processor.handle_input_event(InputEvent::Enter, &mut shell);
assert_eq!(processor.input_buffer.len(), 0);
assert_eq!(processor.input_buffer_cursor, 0);
processor.handle_input_event(InputEvent::ArrowDown, &mut shell);
processor.handle_input_event(InputEvent::ArrowLeft, &mut shell);
processor.handle_input_event(InputEvent::ArrowRight, &mut shell);
processor.handle_input_event(InputEvent::ArrowUp, &mut shell);
processor.handle_input_event(InputEvent::Ctrl(3), &mut shell);
sleep(Duration::from_millis(500)); let _ = shell.stop();
sleep(Duration::from_millis(500)); processor.handle_input_event(InputEvent::Ctrl(2), &mut shell);
processor.input_buffer = vec!['l', 's'];
processor.input_buffer_cursor = 2;
processor.handle_input_event(InputEvent::Enter, &mut shell);
assert_eq!(processor.input_buffer.len(), 0);
assert_eq!(processor.input_buffer_cursor, 0);
sleep(Duration::from_millis(500)); }
fn new_subprociop() -> SubProcIop {
SubProcIop::new(
Config::default(),
IOProcessor::new(Language::Russian, new_translator(Language::Russian)),
)
}
}