use std::collections::VecDeque; use crate::FormattedText; use crate::parser::substitute_cursor; use crate::Context; const PROMPT_STR: &str = "==> "; #[derive(Debug)] pub struct PromptBuffer { // History hist: VecDeque, hist_maxlen: usize, // Counts from back of hist. // 0 means "not on history", // 1 means "on last item of history" hist_cursor: usize, pub buffer: String, buffer_changed: bool, cursor: usize, last_print_len: usize } impl PromptBuffer { // Same as write_primpt, but pretends there is no cursor pub fn write_prompt_nocursor(&mut self, context: &Context) -> FormattedText { let tmp = self.cursor; self.cursor = 0; let r = self.write_prompt(context); self.cursor = tmp; return r; } pub fn write_prompt(&mut self, context: &Context) -> FormattedText { let l = self.buffer.chars().count(); let i = if l == 0 {0} else {l - self.cursor}; // Draw prettyprinted expression let (display_c, s) = substitute_cursor(context, &self.get_contents(), i); let mut tx = FormattedText::new("".to_string()); tx.push(&format!("\r[p]{PROMPT_STR}[n]{s}")); // If this string is shorter, clear the remaining old one. if s.chars().count() < self.last_print_len { tx.push(&" ".repeat(self.last_print_len - s.chars().count())); } let q = (display_c + PROMPT_STR.chars().count()) as u16; tx.push(&format!("\r[cursorright{q}]")); self.last_print_len = s.chars().count(); return tx; } } impl PromptBuffer { pub fn new(maxlen: usize) -> PromptBuffer { return PromptBuffer { hist: VecDeque::with_capacity(maxlen/2), hist_maxlen: maxlen, hist_cursor: 0, buffer: String::with_capacity(64), buffer_changed: false, cursor: 0, last_print_len: 0, }; } // Prompt methods pub fn get_contents(&self) -> &String {&self.buffer} pub fn enter(&mut self) -> String { // Don't trim input string so that linelocations are correct //let s = String::from(self.buffer.trim()); let s = self.buffer.clone(); self.buffer.clear(); self.hist_cursor = 0; self.cursor = 0; self.buffer_changed = false; if s != "" { self.hist.push_back(s.clone()); } while self.hist.len() > self.hist_maxlen { self.hist.pop_front(); } return s; } // Buffer manipulation pub fn add_char(&mut self, c: char) { self.buffer_changed = true; if self.cursor == 0 { self.buffer.push(c); } else { let l = self.buffer.chars().count(); let i = l - self.cursor; self.buffer.insert(i, c); } } pub fn backspace(&mut self) { if self.buffer.len() == 0 { return } self.buffer_changed = true; let l = self.buffer.chars().count(); if self.cursor == 0 { self.buffer.pop(); } else if self.cursor != l { let i = l - self.cursor; self.buffer.remove(i-1); if self.cursor >= l { self.cursor = l-1; } } } pub fn delete(&mut self) { if self.cursor != 0 { self.cursor -= 1; self.backspace(); } } // Cursor manipulation pub fn cursor_left(&mut self) { let l = self.buffer.chars().count(); if self.cursor < l { self.cursor += 1; } } pub fn cursor_right(&mut self) { if self.cursor > 0 { self.cursor -= 1; } } // History manipulation pub fn hist_up(&mut self) { if self.buffer_changed && self.buffer.len() != 0 { return; } if self.hist_cursor < self.hist.len() { if self.buffer.len() != 0 || !self.buffer_changed { self.hist_cursor += 1; } self.buffer_changed = false; if self.hist_cursor == 0 { self.buffer.clear(); } else { self.buffer = self.hist[self.hist.len() - self.hist_cursor].clone(); } } } pub fn hist_down(&mut self) { if self.buffer_changed && self.buffer.len() != 0 { return; } if self.hist_cursor > 0 { self.hist_cursor -= 1; self.buffer_changed = false; if self.hist_cursor == 0 { self.buffer.clear(); } else { self.buffer = self.hist[self.hist.len() - self.hist_cursor].clone(); } } else { self.buffer.clear(); } } }