use std::str::FromStr; use super::cursor::{Cursor, CursorMove}; #[derive(Default, Debug, Clone)] pub struct Buffer { lines: Vec, cursor: Cursor, } impl Buffer { pub fn new() -> Self { Self { lines: Vec::new(), cursor: Cursor::new().with_position(0, 0).with_max(0, 0), } } fn refresh_line_max(&mut self) { self.cursor .set_x_max(self.lines[self.cursor.y() as usize].len()) } fn refresh_buffer_max(&mut self) { self.cursor.set_y_max(self.lines.len() - 1); } fn refresh_max(&mut self) { self.refresh_line_max(); self.refresh_buffer_max(); } fn end_balance(&self, level: usize) -> isize { let str = "\t".repeat(level); let start_count = self .lines .iter() .filter(|s| { s.starts_with(&(str.clone() + "if ")) || s.starts_with(&(str.clone() + "for ")) || s.starts_with(&(str.clone() + "while ")) || (s.starts_with(&str) && s.contains("function(") && s.ends_with(")")) }) .count(); let end_count = self .lines .iter() .filter(|s| s.starts_with(&(str.clone() + "end ")) || **s == (str.clone() + "end")) .count(); (end_count as isize) - (start_count as isize) } pub fn insert(&mut self, c: char) { match c { '\n' => { let (a, b) = { let line = self.current_line(); let (a, b) = line.split_at(self.cursor.x()); (a.to_string(), b.to_string()) }; let indent_normalized = a.replace(" ", "\t"); let indent = indent_normalized.len() - indent_normalized.trim_start().len(); let l = a.trim(); let insert_end = (l.starts_with("if ") && l.ends_with(" then")) || ((l.starts_with("for ") || l.starts_with("while ")) && l.ends_with(" do")) || (l.contains("function(") && l.ends_with(")")); let extra_indent = if insert_end { 1 } else { 0 }; { *self.current_line_mut() = a; } self.cursor.move_unchecked(CursorMove::Down(1)); self.cursor.move_unchecked(CursorMove::Begin); self.lines .insert(self.cursor().y(), "\t".repeat(indent + extra_indent) + &b); if insert_end && self.end_balance(indent) < 0 { self.lines .insert(self.cursor().y() + 1, "\t".repeat(indent) + "end"); } self.refresh_max(); self.cursor .move_checked(CursorMove::Right(indent + extra_indent)); } _ => { let x = self.cursor().x(); self.current_line_mut().insert(x, c); self.refresh_line_max(); self.cursor.move_checked(CursorMove::Right(1)); } } } pub fn delete(&mut self) { if self.cursor.is_at_start() && !self.cursor.is_at_top() { let old_line = self.current_line_mut().clone(); self.lines.remove(self.cursor.y()); self.cursor.move_checked(CursorMove::Up(1)); self.refresh_line_max(); let new_x = self.current_line().len(); self.current_line_mut().push_str(&old_line); self.cursor .move_checked(CursorMove::Jump((new_x, self.cursor.y()))); self.refresh_buffer_max() } else { let x = self.cursor.x() - 1; self.current_line_mut().remove(x); self.refresh_line_max(); self.cursor.move_checked(CursorMove::Left(1)); } } pub fn line(&self, index: usize) -> Option<&String> { self.lines.get(index) } fn line_mut(&mut self, index: usize) -> Option<&mut String> { self.lines.get_mut(index) } pub fn current_line(&self) -> &String { self.line(self.cursor.y() as usize).unwrap() } fn current_line_mut(&mut self) -> &mut String { self.line_mut(self.cursor.y() as usize).unwrap() } pub fn cursor(&self) -> &Cursor { &self.cursor } pub fn move_cursor(&mut self, m: CursorMove) { match m { CursorMove::Up(_) | CursorMove::Down(_) | CursorMove::Top | CursorMove::Bottom | CursorMove::Jump(_) => { self.cursor.move_checked(m); self.cursor.set_x_max(self.current_line().len()); self.cursor.correct_cursor_position(); } CursorMove::Left(_) | CursorMove::Right(_) | CursorMove::Begin | CursorMove::End => { self.cursor.move_checked(m) } } } pub fn lines(&self) -> &Vec { &self.lines } pub fn set_lines(&mut self, lines: Vec) { self.lines = lines; self.cursor.move_checked(CursorMove::Jump((0, 0))); self.refresh_max(); } } impl FromStr for Buffer { type Err = (); fn from_str(s: &str) -> Result { let lines: Vec<_> = s.lines().map(|s| s.to_string()).collect(); let mut buffer = Self::new(); buffer.lines = lines; buffer.refresh_max(); Ok(buffer) } }