use crate::app::state::rest::AppStateRest; use crate::app::state::types::Overlay; #[derive(Debug, Clone)] pub struct EditorState { pub path: String, pub content: Vec, pub undo_stack: Vec>, pub cursor_line: usize, pub cursor_col: usize, } impl Default for EditorState { fn default() -> Self { EditorState { path: String::new(), content: vec![String::new()], undo_stack: Vec::new(), cursor_line: 0, cursor_col: 0, } } } impl EditorState { pub fn open(path: String, existing_content: Option>) -> Self { let content = existing_content.unwrap_or_else(|| vec![String::new()]); EditorState { path, content, ..Default::default() } } pub fn change_line(&mut self, text: String) { self.save_undo(); if self.cursor_line < self.content.len() { self.content[self.cursor_line] = text; } } pub fn insert_line_after(&mut self) { self.save_undo(); let pos = (self.cursor_line + 1).min(self.content.len()); self.content.insert(pos, String::new()); } pub fn delete_current_line(&mut self) { if self.content.len() <= 1 { return; } self.save_undo(); self.content.remove(self.cursor_line); if self.cursor_line >= self.content.len() { self.cursor_line = self.content.len() - 1; } self.cursor_col = 0; } fn save_undo(&mut self) { self.undo_stack.push(self.content.clone()); if self.undo_stack.len() > 50 { self.undo_stack.remove(0); } } pub fn undo(&mut self) { if let Some(prev) = self.undo_stack.pop() { self.content = prev; self.cursor_line = self.cursor_line.min(self.content.len().saturating_sub(1)); self.cursor_col = 0; } } pub fn cursor_up(&mut self) { if self.cursor_line > 0 { self.cursor_line -= 1; } self.cursor_col = self.cursor_col.min( self.content.get(self.cursor_line).map(|l| l.len()).unwrap_or(0), ); } pub fn cursor_down(&mut self) { if self.cursor_line + 1 < self.content.len() { self.cursor_line += 1; } self.cursor_col = self.cursor_col.min( self.content.get(self.cursor_line).map(|l| l.len()).unwrap_or(0), ); } pub fn cursor_left(&mut self) { if self.cursor_col > 0 { self.cursor_col -= 1; } else if self.cursor_line > 0 { self.cursor_line -= 1; self.cursor_col = self.content.get(self.cursor_line).map(|l| l.len()).unwrap_or(0); } } pub fn cursor_right(&mut self) { if let Some(line) = self.content.get(self.cursor_line) { if self.cursor_col < line.len() { self.cursor_col += 1; } else if self.cursor_line + 1 < self.content.len() { self.cursor_line += 1; self.cursor_col = 0; } } } pub fn insert_char(&mut self, c: char) { self.save_undo(); if let Some(line) = self.content.get_mut(self.cursor_line) { line.insert(self.cursor_col, c); self.cursor_col += 1; } } pub fn delete_left(&mut self) { self.save_undo(); if let Some(line) = self.content.get_mut(self.cursor_line) { if self.cursor_col > 0 { self.cursor_col -= 1; line.remove(self.cursor_col); } else if self.cursor_line > 0 { let prev_len = self.content[self.cursor_line - 1].len(); let rest = self.content.remove(self.cursor_line); self.cursor_line -= 1; self.cursor_col = prev_len; self.content[self.cursor_line].push_str(&rest); } } } pub fn join_lines(&mut self) { if self.cursor_line + 1 >= self.content.len() { return; } self.save_undo(); let next = self.content.remove(self.cursor_line + 1); self.content[self.cursor_line].push_str(&next); } pub fn as_string(&self) -> String { self.content.join("\n") } } pub fn handle_editor_input(state: &mut AppStateRest, text: String) { let editor = &mut state.misc.editor; if editor.is_none() { return; } let ed = editor.as_mut().unwrap(); for c in text.chars() { match c { '\n' | '\r' => { ed.insert_line_after(); ed.cursor_down(); ed.cursor_col = 0; } '\t' => { ed.insert_char(' '); ed.insert_char(' '); } _ => { ed.insert_char(c); } } } state.dirty = true; } pub fn handle_editor_dismiss(state: &mut AppStateRest) { state.misc.editor = None; state.misc.overlay = Overlay::None; state.dirty = true; }