diff --git a/src/config/lastline_cmd.rs b/src/config/lastline_cmd.rs index 35a2b1c..2d3ceeb 100644 --- a/src/config/lastline_cmd.rs +++ b/src/config/lastline_cmd.rs @@ -70,7 +70,7 @@ impl LastLineCommand { } } - const fn is_split_char(x: char) -> bool { + pub const fn is_split_char(x: char) -> bool { x == ',' || x == ';' || x == ':' || x == '/' || x.is_ascii_whitespace() } diff --git a/src/utils/buffer.rs b/src/utils/buffer.rs index b0471e9..5bc7b0c 100644 --- a/src/utils/buffer.rs +++ b/src/utils/buffer.rs @@ -6,6 +6,7 @@ use std::{ atomic::{AtomicUsize, Ordering}, RwLock, }, + usize, }; use bitflags::bitflags; @@ -145,6 +146,18 @@ impl EditBuffer { Some(ret) } + pub fn get_linesize_absoluted(&self, line: u16) -> u16 { + let buf = self.buf.read().unwrap(); + let line = buf.get(line as usize); + if line.is_none() { + return 0; + } + + let line = line.unwrap(); + + line.data.len() as u16 + } + pub fn get_linesize(&self, line: u16) -> u16 { let buf = self.buf.read().unwrap(); let line = buf.get(self.offset.load(Ordering::SeqCst) + line as usize); @@ -178,6 +191,23 @@ impl EditBuffer { line.unwrap().data.drain(x..x + n); } + pub fn remove_str_abs(&self, x: u16, y: u16, n: usize) { + let mut buf = self.buf.write().unwrap(); + let line = buf.get_mut(y as usize); + if line.is_none() { + return; + } + let x = x as usize; + match n { + usize::MAX => { + line.unwrap().data.drain(x..); + } + n => { + line.unwrap().data.drain(x..x + n); + } + } + } + /// 获取一份对应行的拷贝 pub fn get_line(&self, line: u16) -> LineBuffer { let buf = self.buf.read().unwrap(); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2427952..4b9ef5f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,3 +9,4 @@ pub mod style; pub mod term_io; pub mod terminal; pub mod ui; +mod undotree; diff --git a/src/utils/ui/event.rs b/src/utils/ui/event.rs index b223065..61cb8c6 100644 --- a/src/utils/ui/event.rs +++ b/src/utils/ui/event.rs @@ -161,6 +161,13 @@ pub trait KeyEventCallback { ui: &mut MutexGuard, data: &[u8], ) -> io::Result; + + // 测试用,有需要的话可以删除此函数 + // fn t(&self, ui: &mut MutexGuard) -> io::Result { + // ui.delete_range((4,3), (6,9))?; + // // ui.goto_line("15,8")?; + // Ok(WarpUiCallBackType::None) + // } } #[derive(Debug, PartialEq)] diff --git a/src/utils/ui/mode/mode.rs b/src/utils/ui/mode/mode.rs index 42ecf3f..cb6ddab 100644 --- a/src/utils/ui/mode/mode.rs +++ b/src/utils/ui/mode/mode.rs @@ -519,6 +519,12 @@ impl KeyEventCallback for Command { return Ok(WarpUiCallBackType::None); } + // 测试用,有需要的话可以删除此函数 + // b"t" => { + // self.t(ui)?; + // Ok(WarpUiCallBackType::None) + // } + _ => { return Ok(WarpUiCallBackType::None); } diff --git a/src/utils/ui/uicore.rs b/src/utils/ui/uicore.rs index b6ae810..9ae8249 100644 --- a/src/utils/ui/uicore.rs +++ b/src/utils/ui/uicore.rs @@ -1,6 +1,7 @@ use std::{ io, sync::{atomic::AtomicU16, Arc, Mutex, MutexGuard, Once, RwLock, Weak}, + usize, }; use crossterm::{ @@ -10,7 +11,7 @@ use crossterm::{ use lazy_static::lazy_static; use crate::{ - config::appconfig::AppSetting, + config::{appconfig::AppSetting, lastline_cmd::LastLineCommand}, utils::{ buffer::EditBuffer, cursor::CursorCrtl, style::StyleManager, terminal::TermManager, ui::InfoLevel, @@ -231,6 +232,146 @@ impl UiCore { Ok(()) } + + /// 删除指定坐标里的内容 + /// 可以多行,下标从1开始,最开始的字符会被删除,选中内容的最后一个字符不会被删除 + pub fn delete_range(&mut self, start_pos: (u16, u16), end_pos: (u16, u16)) -> io::Result<()> { + let content_winsize = *CONTENT_WINSIZE.read().unwrap(); + let content_line_max = content_winsize.rows; + + if start_pos.0 > end_pos.0 || start_pos.1 > end_pos.1 { + APP_INFO.lock().unwrap().info = + "Useage: {delete}|{d} {start_row}{start_col} {end_row}{end_col}".to_string(); + return Ok(()); + } + + let (start_y, mut start_x) = start_pos; + let (end_y, mut end_x) = end_pos; + + let buffer_line_max = self.buffer.line_count() as u16; + let mut start_y = start_y.min(buffer_line_max - 1); + let mut end_y = end_y.min(buffer_line_max - 1); + let start_y_line_count = self.buffer.get_linesize_absoluted(start_y); + let end_y_line_count = self.buffer.get_linesize_absoluted(end_y); + start_x = start_x.min(start_y_line_count); + end_x = end_x.min(end_y_line_count - 1); + // let end_y_line_count = self.buffer.get_linesize_absoluted(end_y); + + // 以便后面能够得到正确的索引 + if start_y == 0 { + start_y += 1; + } + if start_x == 0 { + start_x += 1; + } + if end_x == 0 { + end_x += 1; + } + if end_y == 0 { + end_y += 1; + } + + start_x -= 1; + start_y -= 1; + end_y -= 1; + end_x -= 1; + + if start_y == end_y { + self.buffer + .remove_str_abs(start_x, start_y, (end_x - start_x + 1) as usize); + } else { + self.buffer.remove_str_abs(start_x, start_y, usize::MAX); + self.buffer.remove_str_abs(0, end_y, end_x as usize); + if start_y.max(end_y) - start_y.min(end_y) > 1 { + self.buffer + .delete_lines((start_y + 1) as usize, (end_y - 1) as usize); + } + } + if self.buffer.offset() > self.buffer.line_count() { + self.buffer.set_offset(self.buffer.line_count()); + } + + // let y = self.cursor.y(); + self.goto_line(&format!("{}", start_y + 1))?; + + self.cursor.store_pos(); + self.cursor.set_prefix_mode(true); + self.cursor.restore_pos().unwrap(); + + let pos = self.cursor.store_tmp_pos(); + // self.render_content(y, (content_winsize.rows - y) as usize - 1) + // .unwrap(); + self.render_content(0, content_line_max as usize).unwrap(); + + self.cursor.restore_tmp_pos(pos)?; + + self.cursor.highlight(Some(self.cursor.y() - 1))?; + Ok(()) + } + + /// 跳转到指定坐标(下标从1开始) + pub fn goto_line(&mut self, args: &str) -> io::Result<()> { + if args.is_empty() { + let mut info = APP_INFO.lock().unwrap(); + info.level = InfoLevel::Info; + info.info = "Useage: {goto}|{gt} {row}{' '|','|';'|':'|'/'}{col}".to_string(); + return Ok(()); + } + let (y, x) = { + let a = args + .split(|x| LastLineCommand::is_split_char(x)) + .collect::>(); + + if a.len() == 1 { + (u16::from_str_radix(a[0], 10), Ok(1)) + } else { + (u16::from_str_radix(a[0], 10), u16::from_str_radix(a[1], 10)) + } + }; + if y.is_err() { + let mut info = APP_INFO.lock().unwrap(); + info.level = InfoLevel::Info; + info.info = "Useage: goto {row}({' '|','|';'|':'|'/'}{col})".to_string(); + } + + let content_winsize = *CONTENT_WINSIZE.read().unwrap(); + let content_line_max = content_winsize.rows; + let buf_line_max = self.buffer.line_count() as u16; + let mut y = y.unwrap().min(buf_line_max); + let mut x = x.unwrap_or(1).min(self.buffer.get_linesize_absoluted(y)); + + // 以便后面能够得到正确的索引 + if y == 0 { + y += 1; + } + if x == 0 { + x += 1; + } + + x -= 1; + y -= 1; + + self.cursor.store_pos(); + self.cursor.set_prefix_mode(true); + self.cursor.restore_pos().unwrap(); + + let lasty = self.cursor.y(); + let y = self.buffer.goto_line(y as usize); + self.cursor.move_to(x, y).unwrap(); + + let pos = self.cursor.store_tmp_pos(); + self.render_content(0, content_line_max as usize).unwrap(); + self.cursor.restore_tmp_pos(pos).unwrap(); + + self.cursor.highlight(Some(lasty)).unwrap(); + + Ok(()) + } + + pub fn insert_str_with_newline(&mut self, _x: u16, _y: u16, _s: &str) -> io::Result<()> { + + Ok(()) + } } #[derive(Debug)] diff --git a/src/utils/undotree.rs b/src/utils/undotree.rs new file mode 100644 index 0000000..78751d7 --- /dev/null +++ b/src/utils/undotree.rs @@ -0,0 +1,321 @@ +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +/// 编辑命令 +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub struct EditCommand { + // 删除动作,如果有的话 + action_delete: Option, + + // 插入操作,如果有的话 + action_insert: Option, + + // 对于第几行进行的操作(目前就只实现针对单独一个文件的) + line_number: u16, +} + +impl Default for EditCommand { + fn default() -> Self { + Self { + action_delete: None, + action_insert: None, + line_number: 0, + } + } +} + +impl EditCommand { + pub fn new(action_delete: Action, action_insert: Action, line_number: u16) -> Self { + Self { + action_delete: Some(action_delete), + action_insert: Some(action_insert), + line_number, + } + } + + /// 处理命令,返回对应的反向命令 + pub fn process(&self) -> Result { + let mut content_to_insert = String::new(); + let mut content_to_delete = String::new(); + let action_insert; + let action_delete; + if let Action::Delete(s) = self.action_delete.as_ref().unwrap() { + content_to_insert = s.clone(); + } + if let Action::Insert(s) = self.action_insert.as_ref().unwrap() { + content_to_delete = s.clone(); + } + action_delete = Action::Delete(content_to_delete); + action_insert = Action::Insert(content_to_insert); + + let res = EditCommand::new(action_delete, action_insert, self.line_number); + + Ok(res) + } + + /// 拿到这命令里的删除内容用于删除 + pub fn get_delete_content(&self) -> Option { + if let Some(Action::Delete(s)) = self.action_delete.as_ref() { + return Some(s.clone()); + } + None + } + + /// 拿到这命令里的插入内容用于重新插入 + pub fn get_insert_content(&self) -> Option { + if let Some(Action::Insert(s)) = self.action_insert.as_ref() { + return Some(s.clone()); + } + None + } +} + +/// 编辑动作 +#[allow(unused)] +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub enum Action { + // 插入内容 + Insert(String), + + // 删除内容 + Delete(String), + + // 移动(未实现) + Move, + + // 其他动作 + None, +} + +#[derive(Debug)] +pub struct UndoTreeNode { + // 父节点 + parent: Weak>, + // 子节点 + children: Vec>>, + // 命令 + command: EditCommand, + // 指向自身的弱引用 + self_pointer: Weak>, + // 指向UndoTree的弱引用 + tree_pointer: Weak>, + // 是不是移动操作(未实现) + // is_move: bool, + // 指向上一次操作的指针,用于另一种撤销方式 + last_operation_pointer: Option, + // 指向下一次操作的指针,用于另一种撤销方式 + next_operation_pointer: Option, +} + +// impl Clone for UndoTreeNode { +// fn clone(&self) -> Self { +// Self { +// parent: self.parent.clone(), +// children: self.children.clone(), +// command: self.command.clone(), +// self_pointer: self.self_pointer.clone(), +// tree_pointer: self.tree_pointer.clone(), +// } +// } +// } + +impl UndoTreeNode { + pub fn new(command: EditCommand) -> Node { + let result = Rc::new(RefCell::new(UndoTreeNode { + parent: Weak::new(), + children: Vec::new(), + command, + self_pointer: Weak::new(), + tree_pointer: Weak::new(), + last_operation_pointer: None, + next_operation_pointer: None, + })); + result.borrow_mut().self_pointer = Rc::downgrade(&result); + result.borrow_mut().parent = Rc::downgrade(&result); + result + } + + pub fn get_command(&self) -> EditCommand { + self.command.clone() + } + + pub fn set_parent(&mut self, parent: &Node) { + self.parent = Rc::downgrade(parent); + } + + pub fn set_tree_pointer(&mut self, root: &Rc>) { + self.tree_pointer = Rc::downgrade(root); + } + + pub fn insert_with_command(&mut self, command: EditCommand) { + let new_node = UndoTreeNode::new(command); + self.insert(new_node); + } + + /// 插入子节点 + pub fn insert(&mut self, node: Node) { + node.borrow_mut().parent = self.self_pointer.clone(); + node.borrow_mut() + .set_tree_pointer(&self.tree_pointer.upgrade().unwrap()); + let self_pointer = self.self_pointer.upgrade().unwrap().clone(); + node.borrow_mut().last_operation_pointer = Some(self_pointer); + self.next_operation_pointer = Some(node.clone()); + self.children.push(node); + } + + /// 删除自身以及子节点 + pub fn delete(&mut self) { + for child in &self.children { + child.borrow_mut().delete(); + } + if let Some(parent) = self.parent.upgrade() { + match parent.borrow().next_operation_pointer { + Some(ref next_node) + if Rc::ptr_eq(next_node, &self.self_pointer.upgrade().unwrap()) => + { + parent.borrow_mut().next_operation_pointer = None; + } + _ => {} + } + parent + .borrow_mut() + .children + .retain(|x| !Rc::ptr_eq(x, &self.self_pointer.upgrade().unwrap())); + } + } + + pub fn get_parent(&self) -> Option { + self.parent.upgrade() + } + + pub fn get_children(&self) -> Vec { + self.children.clone() + } +} + +#[allow(dead_code)] +#[derive(Debug)] +/// 撤销树 +/// 用于记录编辑历史,实现撤销和恢复功能 +/// 支持两种撤销方式,可以根据用户的需要来选择哪种撤销方式 +/// 此撤销树仅用于记录和返回相关操作,相对独立于其他部分 +pub struct UndoTree { + /// 根节点 + root: Node, + /// 当前节点 + current_node: Node, + /// 待撤销的节点,代表操作 + to_undo: Vec, + /// 待恢复的节点,代表操作 + to_redo: Vec, +} + +type Node = Rc>; + +#[allow(dead_code)] +impl UndoTree { + pub fn new(command: EditCommand) -> UndoTree { + let root = UndoTreeNode::new(command); + UndoTree { + root: root.clone(), + current_node: root, + to_undo: vec![], + to_redo: vec![], + } + } + + pub fn get_root(&self) -> Node { + self.root.clone() + } + + pub fn get_current_node(&self) -> Node { + self.current_node.clone() + } + + pub fn set_current_node(&mut self, node: Node) { + self.current_node = node; + } + + fn get_to_redo(&mut self) -> Result { + match self.to_redo.pop() { + Some(node) => Ok(node.borrow().get_command()), + None => Err(()), + } + } + + fn get_to_undo(&mut self) -> Result { + match self.to_undo.pop() { + Some(node) => Ok(node.borrow().get_command().process()?), + None => Err(()), + } + } + + /// 插入新操作,生成新节点 + pub fn push(&mut self, new_node: Node) { + self.current_node.borrow_mut().insert(new_node.clone()); + self.current_node = new_node; + self.to_undo.push(self.current_node.clone()); + } + + pub fn push_with_command(&mut self, command: EditCommand) { + let new_node = UndoTreeNode::new(command); + self.push(new_node); + } + + /// 撤销操作,返回对应的反向操作 + pub fn undo(&mut self) -> Result { + match self.get_to_undo() { + Ok(command) => { + let current_node = self.current_node.clone(); + if let Some(parent) = current_node.borrow().get_parent() { + self.to_redo.push(self.current_node.clone()); + self.current_node = parent; + } + Ok(command) + } + Err(e) => Err(e), + } + } + + /// 恢复操作,返回对应的正向操作 + pub fn redo(&mut self) -> Result { + match self.get_to_redo() { + Ok(command) => { + let current_node = self.current_node.borrow(); + if let Some(child) = current_node.get_children().first().cloned() { + drop(current_node); + self.current_node = child; + self.to_undo.push(self.current_node.clone()); + } + Ok(command) + } + Err(e) => Err(e), + } + } + + /// 另一种撤销方式,会跟踪上一次操作的指针,返回对应的反向操作 + pub fn undo_last_operation(&mut self) -> Result { + let last_node = self.current_node.borrow().last_operation_pointer.clone(); + if let Some(node) = last_node { + let command = self.current_node.borrow().get_command(); + node.borrow_mut().next_operation_pointer = Some(self.current_node.clone()); + self.current_node.borrow_mut().last_operation_pointer = Some(node.clone()); + self.current_node = node; + Ok(command.process()?) + } else { + Err(()) + } + } + + /// 另一种撤销方式,会跟踪下一次操作的指针,返回对应的正向操作 + pub fn redo_next_operation(&mut self) -> Result { + let next_node = self.current_node.borrow().next_operation_pointer.clone(); + if let Some(node) = next_node { + let command = self.current_node.borrow().get_command(); + self.current_node = node; + Ok(command) + } else { + Err(()) + } + } +}