use std::cmp::min;
use serial_unit_testing::utils::{self, TextFormat, NewlineFormat};
#[derive(Debug, Clone)]
pub struct TextStorage {
input: String,
pub input_format: TextFormat,
input_history: Vec<String>,
input_history_index: i32,
input_backup: String,
cursor_position: usize,
pub escape_input: bool,
pub newline_format: NewlineFormat,
output: String,
pub output_format: TextFormat,
pub output_line: usize,
scroll_output: bool,
last_output_size: usize
}
impl TextStorage {
pub fn get_input(&self) -> String {
self.input.clone()
}
pub fn is_input_empty(&self) -> bool {
self.input.is_empty()
}
pub fn input_add(&mut self, c: char) {
if self.cursor_position < utils::char_count(&self.input) {
utils::insert_char(&mut self.input, self.cursor_position, c);
} else {
self.input.push(c);
}
self.advance_cursor();
}
pub fn output_add_str(&mut self, str: &str) {
self.output.push_str(str);
if self.scroll_output {
self.output_line = self.output.lines().count();
}
}
pub fn get_cursor_position(&self) -> usize {
self.cursor_position
}
pub fn reset_input(&mut self) {
self.input.clear();
self.cursor_position = 1;
self.input_history_index = -1;
self.input_backup.clear();
}
pub fn reset_output(&mut self) {
self.output.clear();
self.output_line = 0;
}
pub fn advance_cursor(&mut self) {
if self.cursor_position < utils::char_count(&self.input) {
self.cursor_position += 1;
}
}
pub fn retreat_cursor(&mut self) {
if self.cursor_position > 1 {
self.cursor_position -= 1;
}
}
pub fn cursor_at_beginning(&mut self) {
self.cursor_position = 0;
}
pub fn cursor_at_end(&mut self) {
self.cursor_position = utils::char_count(&self.input);
}
pub fn advance_output(&mut self) {
let lines = self.output.lines().count();
if self.output_line < lines {
self.output_line += 1;
}
if self.output_line == lines {
self.scroll_output = true;
}
}
pub fn retreat_output(&mut self) {
if self.output_line > 1 {
self.output_line -= 1;
}
self.scroll_output = false;
}
pub fn advance_output_page(&mut self) {
let lines = self.output.lines().count();
if self.output_line < lines {
self.output_line += self.last_output_size;
if self.output_line > lines {
self.output_line = lines;
}
}
if self.output_line == lines {
self.scroll_output = true;
}
}
pub fn retreat_output_page(&mut self) {
if self.output_line > 1 {
self.output_line -= self.last_output_size;
if self.output_line < 1 {
self.output_line = 1;
}
}
self.scroll_output = false;
}
pub fn remove_character(&mut self, advance_cursor: bool) {
let char_count = utils::char_count(&self.input);
if self.input.is_empty() || (advance_cursor && self.cursor_position == 0) || (advance_cursor == false && self.cursor_position >= char_count) {
return;
}
let offset = match advance_cursor {
true => 1,
false => 0
};
if self.cursor_position < char_count {
utils::remove_char(&mut self.input, self.cursor_position - offset);
} else {
self.input.pop();
}
if advance_cursor {
self.retreat_cursor();
}
}
pub fn add_history_entry(&mut self) {
if let Some(last_input) = self.input_history.first() {
if *last_input != self.input {
self.input_history.insert(0, self.input.clone());
}
} else {
self.input_history.insert(0, self.input.clone());
}
}
pub fn advance_history(&mut self) {
if self.input_history.is_empty() {
return;
}
if self.input_history_index == -1 {
self.input_backup = self.input.clone();
}
self.input_history_index += 1;
let max_index = self.input_history.len() as i32;
if self.input_history_index >= max_index {
self.input_history_index = max_index - 1;
}
self.input = self.input_history[self.input_history_index as usize].clone();
self.cursor_at_end();
}
pub fn retreat_history(&mut self) {
if self.input_history_index == -1 {
return;
}
self.input_history_index -= 1;
if self.input_history_index < 0 {
self.input_history_index = -1;
}
if self.input_history_index >= 0 {
self.input = self.input_history[self.input_history_index as usize].clone();
} else {
self.input = self.input_backup.clone();
}
self.cursor_at_end();
}
pub fn get_output_lines(&mut self, visible_lines: usize) -> (String, String) {
let total_count = self.output.lines().count();
if self.output_line < visible_lines {
self.output_line = min(visible_lines, total_count);
}
let text = self.output
.lines()
.rev()
.skip(total_count - self.output_line)
.take(visible_lines)
.fold("".to_string(), |current, line| {
let mut result = line.to_string();
result.push('\n');
result.push_str(¤t);
result
});
let counter = if total_count > 0 {
let start_line = if self.output_line > visible_lines {
self.output_line - visible_lines + 1
} else {
1
};
format!("({}-{}/{})", start_line, self.output_line, total_count)
} else {
"(0-0/0)".to_string()
};
self.last_output_size = visible_lines;
(text, counter)
}
}
impl Default for TextStorage {
fn default() -> Self {
TextStorage {
input: String::new(),
input_format: TextFormat::Text,
input_history: vec!(),
input_history_index: -1,
input_backup: String::new(),
cursor_position: 1,
escape_input: false,
newline_format: NewlineFormat::LineFeed,
output: String::new(),
output_format: TextFormat::Text,
output_line: 1,
scroll_output: true,
last_output_size: 0
}
}
}