diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-08-02 11:38:19 +0200 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-08-02 11:38:19 +0200 |
| commit | 04a5a938994ddb95cfaa9a74b180e457d3a2b5d0 (patch) | |
| tree | 31ce9525ed3f3423678397323b65c910d63eadb1 /src/state/editor/buffer.rs | |
| parent | fe0938b1de0c46fc2afcaa3dcd6a0f4ec870d21a (diff) | |
implement new lua interface
Diffstat (limited to 'src/state/editor/buffer.rs')
| -rw-r--r-- | src/state/editor/buffer.rs | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/state/editor/buffer.rs b/src/state/editor/buffer.rs new file mode 100644 index 0000000..fa26eb7 --- /dev/null +++ b/src/state/editor/buffer.rs @@ -0,0 +1,191 @@ +use std::str::FromStr; + +use crate::cursor::{Cursor, CursorMove}; + +#[derive(Default, Debug, Clone)] +pub struct Buffer { + lines: Vec<String>, + cursor: Cursor, +} + +impl Buffer { + pub const 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()].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()).unwrap() + } + + fn current_line_mut(&mut self) -> &mut String { + self.line_mut(self.cursor.y()).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::Relative(_) + | 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<String> { + &self.lines + } + + pub fn set_lines(&mut self, lines: Vec<String>) { + self.lines = lines; + self.cursor.move_checked(CursorMove::Jump((0, 0))); + self.refresh_max(); + } + + pub fn set_lines_from_string<S>(&mut self, content: S) + where + S: AsRef<str>, + { + self.set_lines(content.as_ref().lines().map(|s| s.to_string()).collect()) + } + + pub fn as_string(&self) -> String { + self.lines.join("\n") + } +} + +impl FromStr for Buffer { + type Err = (); + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let lines: Vec<_> = s.lines().map(|s| s.to_string()).collect(); + let mut buffer = Self::new(); + buffer.lines = lines; + + buffer.refresh_max(); + + Ok(buffer) + } +} |