From 6780adfc26282e6996fb07883ac409e93edde65f Mon Sep 17 00:00:00 2001 From: sparkzky <146502758+sparkzky@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:58:09 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E9=87=8D=E6=9E=84lastline=5Fcmd=E9=83=A8?= =?UTF-8?q?=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/lastline_cmd.rs | 170 +++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/src/config/lastline_cmd.rs b/src/config/lastline_cmd.rs index 9069318..37de655 100644 --- a/src/config/lastline_cmd.rs +++ b/src/config/lastline_cmd.rs @@ -184,20 +184,22 @@ impl LastLineCommand { pub fn lock(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { let args = args.split(|x| Self::is_split_char(x)).collect::>(); - if args.len() == 0 { - ui.buffer - .add_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED); - } - - for s in args { - let line = usize::from_str_radix(s, 10); - if line.is_err() { - APP_INFO.lock().unwrap().info = format!("\"{s}\" is not a number"); - return WarpUiCallBackType::None; + match args.len() { + 0 => { //没有参数,锁定当前行 + ui.buffer.add_line_flags(ui.cursor.cmd_y() as usize -1, LineState::LOCKED) + } + _ => { //有参数,锁定指定行 + for arg in args { + let line = usize::from_str_radix(arg, 10); + if line.is_err() { + APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); + return WarpUiCallBackType::None; + } + + let line = line.unwrap(); + ui.buffer.add_line_flags(line - 1, LineState::LOCKED); + } } - - let line = line.unwrap(); - ui.buffer.add_line_flags(line - 1, LineState::LOCKED); } WarpUiCallBackType::None @@ -207,43 +209,47 @@ impl LastLineCommand { pub fn unflag(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { let args = args.split(|x| Self::is_split_char(x)).collect::>(); - if args.len() == 0 { - ui.buffer - .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::FLAGED); - } - - for s in args { - let line = usize::from_str_radix(s, 10); - if line.is_err() { - APP_INFO.lock().unwrap().info = format!("\"{s}\" is not a number"); - return WarpUiCallBackType::None; + match args.len() { + 0 => { //没有参数,解除标记当前行 + ui.buffer.remove_line_flags(ui.cursor.cmd_y() as usize -1, LineState::FLAGED) + } + _ => { //有参数,解除标记指定行 + for arg in args { + let line = usize::from_str_radix(arg, 10); + if line.is_err() { + APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); + return WarpUiCallBackType::None; + } + + let line = line.unwrap(); + ui.buffer.remove_line_flags(line - 1, LineState::FLAGED); + } } - - let line = line.unwrap(); - ui.buffer.remove_line_flags(line - 1, LineState::FLAGED); } WarpUiCallBackType::None } - // 锁定行 + // 解除锁定行 pub fn unlock(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { let args = args.split(|x| Self::is_split_char(x)).collect::>(); - if args.len() == 0 { - ui.buffer - .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED); - } - - for s in args { - let line = usize::from_str_radix(s, 10); - if line.is_err() { - APP_INFO.lock().unwrap().info = format!("\"{s}\" is not a number"); - return WarpUiCallBackType::None; + match args.len() { + 0 => { //没有参数,解除锁定当前行 + ui.buffer.remove_line_flags(ui.cursor.cmd_y() as usize -1, LineState::LOCKED) + } + _ => { //有参数,解除锁定指定行 + for arg in args { + let line = usize::from_str_radix(arg, 10); + if line.is_err() { + APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); + return WarpUiCallBackType::None; + } + + let line = line.unwrap(); + ui.buffer.remove_line_flags(line - 1, LineState::LOCKED); + } } - - let line = line.unwrap(); - ui.buffer.remove_line_flags(line - 1, LineState::LOCKED); } WarpUiCallBackType::None @@ -252,53 +258,53 @@ impl LastLineCommand { pub fn delete_lines(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { let args = args.split(|x| x == '-').collect::>(); - if args.len() == 0 { - // 删除当前行 - let offset = ui.buffer.offset() + ui.cursor.y() as usize; - let count = ui.buffer.delete_lines(offset, offset + 1); - if count != 0 { - APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); + match args.len() { + 0 => { + let offset = ui.buffer.offset() + ui.cursor.y() as usize; + let count = ui.buffer.delete_lines(offset, offset + 1); + if count != 0 { + APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); + } + ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) + .unwrap(); + return WarpUiCallBackType::None; } - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) - .unwrap(); - return WarpUiCallBackType::None; - } - - if args.len() == 1 { - let line = usize::from_str_radix(args[0], 10); - if line.is_err() { - APP_INFO.lock().unwrap().info = format!("\"{}\" is not a number", args[0]); + 1 => { + let line = usize::from_str_radix(args[0], 10); + if line.is_err() { + APP_INFO.lock().unwrap().info = format!("\"{}\" is not a number", args[0]); + return WarpUiCallBackType::None; + } + + let line = line.unwrap(); + + let offset = ui.buffer.offset() + line; + let count = ui.buffer.delete_lines(offset, offset + 1); + if count != 0 { + APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); + } + ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) + .unwrap(); return WarpUiCallBackType::None; } - - let line = line.unwrap(); - - let offset = ui.buffer.offset() + line; - let count = ui.buffer.delete_lines(offset, offset + 1); - if count != 0 { - APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); + _ => { + let start = usize::from_str_radix(args[0], 10); + let end = usize::from_str_radix(args[1], 10); + + if start.is_err() || end.is_err() { + APP_INFO.lock().unwrap().info = "Useage: (dl)|(delete) {start}({'-'}{end})".to_string(); + return WarpUiCallBackType::None; + } + + let count = ui.buffer.delete_lines(start.unwrap() - 1, end.unwrap() - 1); + if count != 0 { + APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); + } + + ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) + .unwrap(); } - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) - .unwrap(); - return WarpUiCallBackType::None; } - - let start = usize::from_str_radix(args[0], 10); - let end = usize::from_str_radix(args[1], 10); - - if start.is_err() || end.is_err() { - APP_INFO.lock().unwrap().info = "Useage: (dl)|(delete) {start}({'-'}{end})".to_string(); - return WarpUiCallBackType::None; - } - - let count = ui.buffer.delete_lines(start.unwrap() - 1, end.unwrap() - 1); - if count != 0 { - APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); - } - - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) - .unwrap(); - return WarpUiCallBackType::None; } } From dd279e5047dd976dc6877660e5d6f56bc51f2c57 Mon Sep 17 00:00:00 2001 From: sparkzky <146502758+sparkzky@users.noreply.github.com> Date: Sat, 20 Jul 2024 16:27:30 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=9C=A8TermIO=E4=B8=AD=E5=8A=A0?= =?UTF-8?q?=E5=85=A5queue=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/cursor.rs | 38 +++++++++++++------------------------- src/utils/file.rs | 1 + src/utils/term_io.rs | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index aaa4d20..e0c2eda 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs @@ -243,32 +243,20 @@ impl CursorCrtl { } pub fn move_left(&mut self, mut count: u16) -> io::Result<()> { - if count > self.x { - return self.move_to_columu(0); - } - if self.prefix_mode { - if self.x == self.line_prefix_width - 1 { - return Ok(()); - } - if self.x - count < self.line_prefix_width { - return self.move_to_columu(0); + let result = match self.x { + x if x == 0 => Ok(()), + x if x < count => self.move_to_columu(0), + x => match self.prefix_mode { + true if x == self.line_prefix_width - 1 => Ok(()), + true if x - count < self.line_prefix_width => self.move_to_columu(0), + _ => { + self.x -= count; + self.move_to_columu(x - count) + }, } - } - if self.x == 0 { - return Ok(()); - } - if count > self.x { - count = self.x - self.line_prefix_width - } - CursorManager::move_left(count)?; - - if count > self.x { - self.x = self.line_prefix_width - 1; - } else { - self.x -= count; - } - - Ok(()) + }; + + result } pub fn move_right(&mut self, count: u16) -> io::Result<()> { diff --git a/src/utils/file.rs b/src/utils/file.rs index 280cdf9..ed2606a 100644 --- a/src/utils/file.rs +++ b/src/utils/file.rs @@ -86,6 +86,7 @@ impl FileManager { if self.bak.is_some() { fs::remove_file(format!("{}{}", self.name, BAK_SUFFIX))?; } + self.is_first_open = false; Ok(()) } diff --git a/src/utils/term_io.rs b/src/utils/term_io.rs index 8890959..d2fbf5d 100644 --- a/src/utils/term_io.rs +++ b/src/utils/term_io.rs @@ -12,4 +12,26 @@ impl TermIO { stdout().execute(Print(str)).unwrap().flush()?; Ok(()) } + pub fn enqueue(cmd: impl Command) -> io::Result<()> { + match stdout().queue(cmd) { + Ok(_) => Ok(()), + Err(e) => { + eprintln!("Failed to enqueue command Error: {}", e); + Err(io::Error::new(io::ErrorKind::Other, e)) + }, + } + } + pub fn execute(cmd: impl Command) -> io::Result<()> { + match stdout().execute(cmd) { + Ok(_) => Ok(()), + Err(e) => { + eprintln!("Failed to execute command Error: {}", e); + Err(io::Error::new(io::ErrorKind::Other, e)) + }, + } + } + pub fn execute_queue() -> io::Result<()> { + stdout().flush()?; + Ok(()) + } } From 1311f6634137c1b8b8452b53afc8a26f2f6e92fe Mon Sep 17 00:00:00 2001 From: sparkzky <146502758+sparkzky@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:11:10 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E8=BF=98=E5=8E=9F=E5=8E=9F=E6=9D=A5?= =?UTF-8?q?=E7=9A=84TermIO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/term_io.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/utils/term_io.rs b/src/utils/term_io.rs index d2fbf5d..8890959 100644 --- a/src/utils/term_io.rs +++ b/src/utils/term_io.rs @@ -12,26 +12,4 @@ impl TermIO { stdout().execute(Print(str)).unwrap().flush()?; Ok(()) } - pub fn enqueue(cmd: impl Command) -> io::Result<()> { - match stdout().queue(cmd) { - Ok(_) => Ok(()), - Err(e) => { - eprintln!("Failed to enqueue command Error: {}", e); - Err(io::Error::new(io::ErrorKind::Other, e)) - }, - } - } - pub fn execute(cmd: impl Command) -> io::Result<()> { - match stdout().execute(cmd) { - Ok(_) => Ok(()), - Err(e) => { - eprintln!("Failed to execute command Error: {}", e); - Err(io::Error::new(io::ErrorKind::Other, e)) - }, - } - } - pub fn execute_queue() -> io::Result<()> { - stdout().flush()?; - Ok(()) - } } From 084558c5045e31e39bc2ca741131cec3f62341de Mon Sep 17 00:00:00 2001 From: sparkzky Date: Tue, 23 Jul 2024 22:21:36 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8E=A5=E5=8F=A3inser?= =?UTF-8?q?t=5Fline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/buffer.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/buffer.rs b/src/utils/buffer.rs index 45ddf9a..e1333d3 100644 --- a/src/utils/buffer.rs +++ b/src/utils/buffer.rs @@ -178,6 +178,10 @@ impl EditBuffer { } } + pub fn insert_line(&self, idx: usize, element: &LineBuffer) { + + } + /// 将某行数据与上一行合并 /// 返回合并是否成功,以及被合并行之前的长度 pub fn merge_line(&self, line: u16) -> (bool, usize) { From 6c7bc911faae6879e12b5ef4293e505705926a30 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Tue, 23 Jul 2024 22:53:30 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E7=BB=86=E8=8A=82?= =?UTF-8?q?=E8=A7=A3=E5=86=B3warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/lastline_cmd.rs | 1 + src/utils/buffer.rs | 5 ++++- src/utils/cursor.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/config/lastline_cmd.rs b/src/config/lastline_cmd.rs index 37de655..6d1f380 100644 --- a/src/config/lastline_cmd.rs +++ b/src/config/lastline_cmd.rs @@ -40,6 +40,7 @@ const EDITED_NO_STORE: &'static str = "Changes have not been saved"; const NOT_FOUNT_CMD: &'static str = "Command Not Fount"; #[derive(Debug)] +#[allow(unused)] pub struct LastLineCommand { /// Command pub command: String, diff --git a/src/utils/buffer.rs b/src/utils/buffer.rs index e1333d3..039d5b7 100644 --- a/src/utils/buffer.rs +++ b/src/utils/buffer.rs @@ -79,6 +79,7 @@ pub struct EditBuffer { locked_lines: RwLock>, } +#[allow(unused)] impl EditBuffer { pub fn new(buf: Vec) -> Self { let mut lines = buf @@ -178,8 +179,10 @@ impl EditBuffer { } } + /// 向缓冲区插入一行数据 pub fn insert_line(&self, idx: usize, element: &LineBuffer) { - + let mut buf = self.buf.write().unwrap(); + buf.insert(idx, element.clone()); } /// 将某行数据与上一行合并 diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index e0c2eda..504c559 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs @@ -242,7 +242,7 @@ impl CursorCrtl { Ok(()) } - pub fn move_left(&mut self, mut count: u16) -> io::Result<()> { + pub fn move_left(&mut self, count: u16) -> io::Result<()> { let result = match self.x { x if x == 0 => Ok(()), x if x < count => self.move_to_columu(0), From 9fe22f9e5d0ada8109b6b3b28b685d3fd8722d2d Mon Sep 17 00:00:00 2001 From: sparkzky Date: Fri, 26 Jul 2024 21:26:43 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E6=92=A4=E9=94=80=E6=A0=91=E7=9A=84=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/cursor.rs | 37 +++- src/utils/file.rs | 28 ++- src/utils/ui/mod.rs | 1 + src/utils/ui/undotree.rs | 382 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 438 insertions(+), 10 deletions(-) create mode 100644 src/utils/ui/undotree.rs diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index 504c559..2eb35fb 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs @@ -172,11 +172,23 @@ impl CursorCrtl { Ok(()) } - pub fn move_to_nextline(&mut self, lines: u16) -> io::Result<()> { + pub fn move_to_nextline(&mut self, mut lines: u16) -> io::Result<()> { let size = *WINSIZE.read().unwrap(); if self.y + lines >= size.rows { // 向上滚动 - todo!() + + // 保存位置 + let pos = self.store_tmp_pos(); + // 计算需要滚动的行数 + let offset = self.buf.offset(); + if offset < lines as usize { + lines = offset as u16; + } + // 重新设置偏移位置 + self.buf.set_offset(offset - lines as usize); + //翻页并恢复位置 + TermManager::scroll_up(lines)?; + self.restore_tmp_pos(pos)?; } CursorManager::move_to_nextline(lines)?; @@ -191,12 +203,23 @@ impl CursorCrtl { Ok(()) } - pub fn move_to_previous_line(&mut self, lines: u16) -> io::Result<()> { - let size = *WINSIZE.read().unwrap(); - - if self.y() - lines > size.rows { + pub fn move_to_previous_line(&mut self, mut lines: u16) -> io::Result<()> { + if self.y() < lines { // 溢出,则向下滚动 - todo!() + + // 保存位置 + let pos = self.store_tmp_pos(); + let offset = self.buf.offset(); + // 计算需要滚动的行数 + let line_count = self.buf.line_count(); + if line_count < offset + lines as usize { + lines = (line_count - offset) as u16; + } + // 重新设置偏移位置 + self.buf.set_offset(offset + lines as usize); + //翻页并恢复位置 + TermManager::scroll_up(lines)?; + self.restore_tmp_pos(pos)?; } CursorManager::move_to_previous_line(lines)?; diff --git a/src/utils/file.rs b/src/utils/file.rs index ed2606a..396ce81 100644 --- a/src/utils/file.rs +++ b/src/utils/file.rs @@ -1,6 +1,5 @@ use std::{ - fs::{self, File}, - io::{self, Read, Seek, Write}, + fs::{self, File}, io::{self, Read, Seek, Write}, }; use super::buffer::EditBuffer; @@ -15,7 +14,7 @@ pub struct FileManager { is_first_open: bool, bak: Option, } - +#[allow(unused)] impl FileManager { pub fn new(file_path: String) -> io::Result { let ifo_flag = !PathBuf::from(file_path.clone()).exists(); @@ -105,4 +104,27 @@ impl FileManager { } Ok(()) } + + pub fn get_heldbak(&mut self) -> Option { + match self.bak.take() { + Some(file) => Some(file), + None => None, + } + } + + pub fn restore(&mut self) -> io::Result<()> { + if self.bak.is_some() { + let bak_file = self.bak.as_mut().unwrap(); + bak_file.seek(io::SeekFrom::Start(0)).unwrap(); + + let mut buf = Vec::new(); + bak_file.read_to_end(&mut buf).unwrap(); + + self.file.write_all(&buf)?; + + self.file.seek(io::SeekFrom::Start(0))?; + bak_file.seek(io::SeekFrom::Start(0))?; + } + Ok(()) + } } diff --git a/src/utils/ui/mod.rs b/src/utils/ui/mod.rs index 1b7646f..31a8fff 100644 --- a/src/utils/ui/mod.rs +++ b/src/utils/ui/mod.rs @@ -7,6 +7,7 @@ use super::style::StyleManager; pub mod event; pub mod mode; pub mod uicore; +pub mod undotree; #[derive(Debug)] pub struct AppInfo { diff --git a/src/utils/ui/undotree.rs b/src/utils/ui/undotree.rs new file mode 100644 index 0000000..3797a78 --- /dev/null +++ b/src/utils/ui/undotree.rs @@ -0,0 +1,382 @@ +// use std::{any::Any, borrow::BorrowMut, cell::RefCell, rc::Weak, sync::{Arc, Mutex, RwLock}}; + +// use serde::de; + + +// #[allow(unused)] + +// /// 编辑命令 +// #[derive(Debug)] +// struct EditCommand { +// action: Action, +// params: Vec, +// } + +// impl Default for EditCommand { +// fn default() -> Self { +// Self { +// action: Action::Insert(String::new()), +// params: Vec::new(), +// } +// } +// } + +// /// 编辑动作 +// #[allow(unused)] +// #[derive(Debug)] +// enum Action { +// Insert(String), +// Delete(String ,String),// 删除的起始位置和结束位置 +// Replace(String ,String ,String),// 替换的起始位置、结束位置和替换内容 +// Move(String ,String),// 移动的起始位置和结束位置 +// } + +// #[allow(unused)] +// #[derive(Debug)] +// struct UndoTreeNode { +// parent: Weak, +// children: Vec>, +// commands: EditCommand, +// self_pointer: Weak, +// tree_pointer: Weak, +// } + +// #[allow(unused)] +// impl UndoTreeNode { +// fn new(command: EditCommand) -> Self { +// Self { +// parent: None, +// children: RwLock::new(Vec::new()), +// commands: vec![command], +// self_pointer: Weak::new(), +// } +// } + +// fn add_child(&mut self, child: Arc) { +// self.children.write().unwrap().push(child.clone()); +// child +// .as_ref() +// .borrow_mut() +// .parent = Some(Arc::new(self)) +// } +// } + +// #[derive(Debug)] +// struct LockedUndoTreeNode(Arc>); + +// #[allow(unused)] +// struct UndoTree { +// root: Arc, +// current_node: Arc, +// } + +// impl UndoTree { +// fn root_node(&self) -> Arc { +// self.root.clone() +// } +// fn as_any_ref(&self) -> &dyn Any { +// self +// } +// pub fn new() -> Arc { +// let root: Arc = Arc::new(LockedUndoTreeNode(Arc::new(Mutex::new(UndoTreeNode{ +// parent: Weak::default(), +// children: Vec::new(), +// commands: EditCommand::default(), +// self_pointer: Weak::default(), +// tree_pointer: Weak::default(), +// })))); + +// let result: Arc = Arc::new(UndoTree { +// root: root.clone(), +// current_node: root, +// }); + +// let mut root_guard = result.root.0.lock().unwrap(); +// root_guard.parent = Arc::downgrade(&result.root); +// } +// } + + +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +/// 编辑命令 +#[allow(unused)] +#[derive(Debug,Clone,PartialEq, PartialOrd)] +pub struct EditCommand { + // 每个命令所执行的动作 + action: Action, + + // 每个命令所需要的参数, 如插入内容、删除的起始位置和结束位置等 + params: Vec, +} + +impl Default for EditCommand { + fn default() -> Self { + Self { + action: Action::None, + params: Vec::new(), + } + } +} + +#[allow(unused)] +impl EditCommand { + pub fn new(action: Action, params: Vec) -> Self { + Self { + action, + params, + } + } + /// 处理命令,返回对应的反向命令 + pub fn process(&self) -> Result { + let res = match self.action { + Action::Insert => { + EditCommand::new(Action::Delete, self.params.clone()) + } + Action::Delete => { + EditCommand::new(Action::Insert, self.params.clone()) + } + Action::Replace => { + EditCommand::new(Action::Restore, self.params.clone()) + } + Action::Restore => { + EditCommand::new(Action::Replace, self.params.clone()) + } + Action::Move => { + EditCommand::new(Action::Move, self.params.clone()) + } + _ => EditCommand::default() + }; + + Ok(res) + } +} + +/// 编辑动作 +#[allow(unused)] +#[derive(Debug,Clone,PartialEq, PartialOrd)] +pub enum Action { + // 在起始位置的插入内容 + Insert, + + // 删除的起始位置和结束位置 + Delete, + + // 替换的起始位置、结束位置和替换内容 + Replace, + + // 恢复的位置和内容 + Restore, + + // 移动的起始位置和结束位置 + Move, + + // 其他动作 + None, +} + + +#[allow(unused)] +#[derive(Debug)] +pub struct UndoTreeNode { + parent: Weak>, + children: Vec>>, + command: EditCommand, + self_pointer: Weak>, + tree_pointer: Weak>, +} + +#[allow(unused)] +impl UndoTreeNode { + pub fn new(command: EditCommand) -> Rc> { + let result = Rc::new(RefCell::new(UndoTreeNode { + parent: Weak::new(), + children: Vec::new(), + command, + self_pointer: Weak::new(), + tree_pointer: Weak::new(), + })); + result.borrow_mut().self_pointer = Rc::downgrade(&result); + result + } + + pub fn get_command(&self) -> EditCommand { + self.command.clone() + } + + pub fn set_parent(&mut self, parent: &Rc>){ + 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); + new_node.borrow_mut().parent = self.self_pointer.clone(); + new_node.borrow_mut().tree_pointer = self.tree_pointer.clone(); + self.children.push(new_node.clone()); + } + + pub fn insert(&mut self, node: Rc>) { + node.borrow_mut().parent = self.self_pointer.clone(); + node.borrow_mut().tree_pointer = self.tree_pointer.clone(); + self.children.push(node.clone()); + } + + pub fn delete_with_command(&mut self, command: EditCommand) { + self.children + .remove(self.children.iter().position(|x| x.borrow().get_command() == command).unwrap()); + } + + pub fn delete(&mut self, node: Rc>) { + self.children + .remove(self.children.iter().position(|x| x.borrow().get_command() == node.borrow().get_command()).unwrap()); + } + + pub fn get_parent(&self) -> Option>> { + self.parent.upgrade() + } + +} + +#[allow(unused)] +#[derive(Debug)] +pub struct UndoTree { + root: Rc>, + current_node: Rc>, + to_undo: Vec>>, + to_redo: Vec>> +} + +type Node = Rc>; + +#[allow(unused)] +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) -> Rc> { + self.root.clone() + } + + pub fn get_current_node(&self) -> Rc> { + self.current_node.clone() + } + + pub fn set_current_node(&mut self, node: Rc>) { + self.current_node = node; + } + + pub fn get_to_redo(&mut self) -> Result { + Ok( + self + .to_redo + .pop() + .unwrap() + ) + } + + pub fn get_to_undo(&mut self) -> Result { + match self.to_undo.pop().unwrap().borrow().get_command() { + EditCommand{action: Action::Insert, params} => { + + } + EditCommand{action: Action::Delete, params} => {} + EditCommand{action: Action::Move, params} => {} + EditCommand{action: Action::Replace, params} => {} + EditCommand{action: Action::Restore, params} => {} + _ => {} + }; + Ok(EditCommand::default()) + } + + pub fn add_child_with_command(&mut self, command: EditCommand) { + self.current_node.borrow_mut().insert_with_command(command) + } + + pub fn delete_child_with_command(&mut self, command: EditCommand) { + self.current_node.borrow_mut().delete_with_command(command) + } + + pub fn insert(&mut self, node: Rc>) { + self.current_node.borrow_mut().insert(node) + } + + pub fn delete(&mut self, node: Rc>) { + self.current_node.borrow_mut().delete(node) + } + + pub fn push_with_command(&mut self, command: EditCommand) { + let new_node = UndoTreeNode::new(command); + self.current_node.borrow_mut().insert(new_node.clone()); + self.current_node = new_node; + self.to_undo.push(self.current_node.clone()); + } + + pub fn undo(&mut self) -> Result{ + let current_node = self.current_node.borrow(); + if let Some(parent) = current_node.get_parent() { + drop(current_node); + let undo_node = self.current_node.clone(); + self.to_redo.push(self.current_node.clone()); + self.current_node = parent.clone(); + let command = match undo_node.borrow().get_command() { + EditCommand{action: Action::Insert, params} => { + EditCommand{action: Action::Delete, params } + } + EditCommand{action: Action::Delete, params} => { + EditCommand{action: Action::Insert,params} + } + EditCommand{action: Action::Move, params} => { + EditCommand{action: Action::Move, params} + } + EditCommand{action: Action::Replace, params} => { + EditCommand{action: Action::Replace, params} + } + EditCommand{action: Action::Restore, params} => { + EditCommand{action: Action::Replace, params} + } + _ => {EditCommand::default()} + }; + + return Ok(command); + } + + Ok(EditCommand::default()) + } + + pub fn redo(&mut self) -> Result{ + let redo_node = self.get_to_redo().unwrap(); + self.current_node = redo_node.clone(); + self.to_undo.push(redo_node.clone()); + let command = redo_node.borrow().get_command(); + Ok(command) + } +} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test(){ + let node = UndoTree::new(EditCommand::default()).get_root(); + let command = node.borrow().get_command(); + assert_eq!(command.action, Action::None); + } +} + + + + From 13661ac1a021f13b2acc02c04236003c191c3123 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Sun, 4 Aug 2024 23:55:41 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E7=BB=86=E8=8A=82=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/ui/mod.rs | 1 - src/utils/ui/undotree.rs | 382 --------------------------------------- 2 files changed, 383 deletions(-) delete mode 100644 src/utils/ui/undotree.rs diff --git a/src/utils/ui/mod.rs b/src/utils/ui/mod.rs index 31a8fff..1b7646f 100644 --- a/src/utils/ui/mod.rs +++ b/src/utils/ui/mod.rs @@ -7,7 +7,6 @@ use super::style::StyleManager; pub mod event; pub mod mode; pub mod uicore; -pub mod undotree; #[derive(Debug)] pub struct AppInfo { diff --git a/src/utils/ui/undotree.rs b/src/utils/ui/undotree.rs deleted file mode 100644 index 3797a78..0000000 --- a/src/utils/ui/undotree.rs +++ /dev/null @@ -1,382 +0,0 @@ -// use std::{any::Any, borrow::BorrowMut, cell::RefCell, rc::Weak, sync::{Arc, Mutex, RwLock}}; - -// use serde::de; - - -// #[allow(unused)] - -// /// 编辑命令 -// #[derive(Debug)] -// struct EditCommand { -// action: Action, -// params: Vec, -// } - -// impl Default for EditCommand { -// fn default() -> Self { -// Self { -// action: Action::Insert(String::new()), -// params: Vec::new(), -// } -// } -// } - -// /// 编辑动作 -// #[allow(unused)] -// #[derive(Debug)] -// enum Action { -// Insert(String), -// Delete(String ,String),// 删除的起始位置和结束位置 -// Replace(String ,String ,String),// 替换的起始位置、结束位置和替换内容 -// Move(String ,String),// 移动的起始位置和结束位置 -// } - -// #[allow(unused)] -// #[derive(Debug)] -// struct UndoTreeNode { -// parent: Weak, -// children: Vec>, -// commands: EditCommand, -// self_pointer: Weak, -// tree_pointer: Weak, -// } - -// #[allow(unused)] -// impl UndoTreeNode { -// fn new(command: EditCommand) -> Self { -// Self { -// parent: None, -// children: RwLock::new(Vec::new()), -// commands: vec![command], -// self_pointer: Weak::new(), -// } -// } - -// fn add_child(&mut self, child: Arc) { -// self.children.write().unwrap().push(child.clone()); -// child -// .as_ref() -// .borrow_mut() -// .parent = Some(Arc::new(self)) -// } -// } - -// #[derive(Debug)] -// struct LockedUndoTreeNode(Arc>); - -// #[allow(unused)] -// struct UndoTree { -// root: Arc, -// current_node: Arc, -// } - -// impl UndoTree { -// fn root_node(&self) -> Arc { -// self.root.clone() -// } -// fn as_any_ref(&self) -> &dyn Any { -// self -// } -// pub fn new() -> Arc { -// let root: Arc = Arc::new(LockedUndoTreeNode(Arc::new(Mutex::new(UndoTreeNode{ -// parent: Weak::default(), -// children: Vec::new(), -// commands: EditCommand::default(), -// self_pointer: Weak::default(), -// tree_pointer: Weak::default(), -// })))); - -// let result: Arc = Arc::new(UndoTree { -// root: root.clone(), -// current_node: root, -// }); - -// let mut root_guard = result.root.0.lock().unwrap(); -// root_guard.parent = Arc::downgrade(&result.root); -// } -// } - - -use std::cell::RefCell; -use std::rc::{Rc, Weak}; - -/// 编辑命令 -#[allow(unused)] -#[derive(Debug,Clone,PartialEq, PartialOrd)] -pub struct EditCommand { - // 每个命令所执行的动作 - action: Action, - - // 每个命令所需要的参数, 如插入内容、删除的起始位置和结束位置等 - params: Vec, -} - -impl Default for EditCommand { - fn default() -> Self { - Self { - action: Action::None, - params: Vec::new(), - } - } -} - -#[allow(unused)] -impl EditCommand { - pub fn new(action: Action, params: Vec) -> Self { - Self { - action, - params, - } - } - /// 处理命令,返回对应的反向命令 - pub fn process(&self) -> Result { - let res = match self.action { - Action::Insert => { - EditCommand::new(Action::Delete, self.params.clone()) - } - Action::Delete => { - EditCommand::new(Action::Insert, self.params.clone()) - } - Action::Replace => { - EditCommand::new(Action::Restore, self.params.clone()) - } - Action::Restore => { - EditCommand::new(Action::Replace, self.params.clone()) - } - Action::Move => { - EditCommand::new(Action::Move, self.params.clone()) - } - _ => EditCommand::default() - }; - - Ok(res) - } -} - -/// 编辑动作 -#[allow(unused)] -#[derive(Debug,Clone,PartialEq, PartialOrd)] -pub enum Action { - // 在起始位置的插入内容 - Insert, - - // 删除的起始位置和结束位置 - Delete, - - // 替换的起始位置、结束位置和替换内容 - Replace, - - // 恢复的位置和内容 - Restore, - - // 移动的起始位置和结束位置 - Move, - - // 其他动作 - None, -} - - -#[allow(unused)] -#[derive(Debug)] -pub struct UndoTreeNode { - parent: Weak>, - children: Vec>>, - command: EditCommand, - self_pointer: Weak>, - tree_pointer: Weak>, -} - -#[allow(unused)] -impl UndoTreeNode { - pub fn new(command: EditCommand) -> Rc> { - let result = Rc::new(RefCell::new(UndoTreeNode { - parent: Weak::new(), - children: Vec::new(), - command, - self_pointer: Weak::new(), - tree_pointer: Weak::new(), - })); - result.borrow_mut().self_pointer = Rc::downgrade(&result); - result - } - - pub fn get_command(&self) -> EditCommand { - self.command.clone() - } - - pub fn set_parent(&mut self, parent: &Rc>){ - 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); - new_node.borrow_mut().parent = self.self_pointer.clone(); - new_node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children.push(new_node.clone()); - } - - pub fn insert(&mut self, node: Rc>) { - node.borrow_mut().parent = self.self_pointer.clone(); - node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children.push(node.clone()); - } - - pub fn delete_with_command(&mut self, command: EditCommand) { - self.children - .remove(self.children.iter().position(|x| x.borrow().get_command() == command).unwrap()); - } - - pub fn delete(&mut self, node: Rc>) { - self.children - .remove(self.children.iter().position(|x| x.borrow().get_command() == node.borrow().get_command()).unwrap()); - } - - pub fn get_parent(&self) -> Option>> { - self.parent.upgrade() - } - -} - -#[allow(unused)] -#[derive(Debug)] -pub struct UndoTree { - root: Rc>, - current_node: Rc>, - to_undo: Vec>>, - to_redo: Vec>> -} - -type Node = Rc>; - -#[allow(unused)] -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) -> Rc> { - self.root.clone() - } - - pub fn get_current_node(&self) -> Rc> { - self.current_node.clone() - } - - pub fn set_current_node(&mut self, node: Rc>) { - self.current_node = node; - } - - pub fn get_to_redo(&mut self) -> Result { - Ok( - self - .to_redo - .pop() - .unwrap() - ) - } - - pub fn get_to_undo(&mut self) -> Result { - match self.to_undo.pop().unwrap().borrow().get_command() { - EditCommand{action: Action::Insert, params} => { - - } - EditCommand{action: Action::Delete, params} => {} - EditCommand{action: Action::Move, params} => {} - EditCommand{action: Action::Replace, params} => {} - EditCommand{action: Action::Restore, params} => {} - _ => {} - }; - Ok(EditCommand::default()) - } - - pub fn add_child_with_command(&mut self, command: EditCommand) { - self.current_node.borrow_mut().insert_with_command(command) - } - - pub fn delete_child_with_command(&mut self, command: EditCommand) { - self.current_node.borrow_mut().delete_with_command(command) - } - - pub fn insert(&mut self, node: Rc>) { - self.current_node.borrow_mut().insert(node) - } - - pub fn delete(&mut self, node: Rc>) { - self.current_node.borrow_mut().delete(node) - } - - pub fn push_with_command(&mut self, command: EditCommand) { - let new_node = UndoTreeNode::new(command); - self.current_node.borrow_mut().insert(new_node.clone()); - self.current_node = new_node; - self.to_undo.push(self.current_node.clone()); - } - - pub fn undo(&mut self) -> Result{ - let current_node = self.current_node.borrow(); - if let Some(parent) = current_node.get_parent() { - drop(current_node); - let undo_node = self.current_node.clone(); - self.to_redo.push(self.current_node.clone()); - self.current_node = parent.clone(); - let command = match undo_node.borrow().get_command() { - EditCommand{action: Action::Insert, params} => { - EditCommand{action: Action::Delete, params } - } - EditCommand{action: Action::Delete, params} => { - EditCommand{action: Action::Insert,params} - } - EditCommand{action: Action::Move, params} => { - EditCommand{action: Action::Move, params} - } - EditCommand{action: Action::Replace, params} => { - EditCommand{action: Action::Replace, params} - } - EditCommand{action: Action::Restore, params} => { - EditCommand{action: Action::Replace, params} - } - _ => {EditCommand::default()} - }; - - return Ok(command); - } - - Ok(EditCommand::default()) - } - - pub fn redo(&mut self) -> Result{ - let redo_node = self.get_to_redo().unwrap(); - self.current_node = redo_node.clone(); - self.to_undo.push(redo_node.clone()); - let command = redo_node.borrow().get_command(); - Ok(command) - } -} - - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test(){ - let node = UndoTree::new(EditCommand::default()).get_root(); - let command = node.borrow().get_command(); - assert_eq!(command.action, Action::None); - } -} - - - - From e29dd574e126c79aa860a70a5c1b88d596b65f26 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Mon, 5 Aug 2024 10:04:32 +0800 Subject: [PATCH 08/15] make-fmt --- src/config/lastline_cmd.rs | 30 ++++++++++++++++++++---------- src/utils/cursor.rs | 8 ++++---- src/utils/file.rs | 9 +++++---- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/config/lastline_cmd.rs b/src/config/lastline_cmd.rs index 6d1f380..35a2b1c 100644 --- a/src/config/lastline_cmd.rs +++ b/src/config/lastline_cmd.rs @@ -186,10 +186,13 @@ impl LastLineCommand { let args = args.split(|x| Self::is_split_char(x)).collect::>(); match args.len() { - 0 => { //没有参数,锁定当前行 - ui.buffer.add_line_flags(ui.cursor.cmd_y() as usize -1, LineState::LOCKED) + 0 => { + //没有参数,锁定当前行 + ui.buffer + .add_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED) } - _ => { //有参数,锁定指定行 + _ => { + //有参数,锁定指定行 for arg in args { let line = usize::from_str_radix(arg, 10); if line.is_err() { @@ -211,10 +214,13 @@ impl LastLineCommand { let args = args.split(|x| Self::is_split_char(x)).collect::>(); match args.len() { - 0 => { //没有参数,解除标记当前行 - ui.buffer.remove_line_flags(ui.cursor.cmd_y() as usize -1, LineState::FLAGED) + 0 => { + //没有参数,解除标记当前行 + ui.buffer + .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::FLAGED) } - _ => { //有参数,解除标记指定行 + _ => { + //有参数,解除标记指定行 for arg in args { let line = usize::from_str_radix(arg, 10); if line.is_err() { @@ -236,10 +242,13 @@ impl LastLineCommand { let args = args.split(|x| Self::is_split_char(x)).collect::>(); match args.len() { - 0 => { //没有参数,解除锁定当前行 - ui.buffer.remove_line_flags(ui.cursor.cmd_y() as usize -1, LineState::LOCKED) + 0 => { + //没有参数,解除锁定当前行 + ui.buffer + .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED) } - _ => { //有参数,解除锁定指定行 + _ => { + //有参数,解除锁定指定行 for arg in args { let line = usize::from_str_radix(arg, 10); if line.is_err() { @@ -293,7 +302,8 @@ impl LastLineCommand { let end = usize::from_str_radix(args[1], 10); if start.is_err() || end.is_err() { - APP_INFO.lock().unwrap().info = "Useage: (dl)|(delete) {start}({'-'}{end})".to_string(); + APP_INFO.lock().unwrap().info = + "Useage: (dl)|(delete) {start}({'-'}{end})".to_string(); return WarpUiCallBackType::None; } diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index 2eb35fb..695504e 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs @@ -206,7 +206,7 @@ impl CursorCrtl { pub fn move_to_previous_line(&mut self, mut lines: u16) -> io::Result<()> { if self.y() < lines { // 溢出,则向下滚动 - + // 保存位置 let pos = self.store_tmp_pos(); let offset = self.buf.offset(); @@ -275,10 +275,10 @@ impl CursorCrtl { _ => { self.x -= count; self.move_to_columu(x - count) - }, - } + } + }, }; - + result } diff --git a/src/utils/file.rs b/src/utils/file.rs index 396ce81..129c698 100644 --- a/src/utils/file.rs +++ b/src/utils/file.rs @@ -1,5 +1,6 @@ use std::{ - fs::{self, File}, io::{self, Read, Seek, Write}, + fs::{self, File}, + io::{self, Read, Seek, Write}, }; use super::buffer::EditBuffer; @@ -116,12 +117,12 @@ impl FileManager { if self.bak.is_some() { let bak_file = self.bak.as_mut().unwrap(); bak_file.seek(io::SeekFrom::Start(0)).unwrap(); - + let mut buf = Vec::new(); bak_file.read_to_end(&mut buf).unwrap(); - + self.file.write_all(&buf)?; - + self.file.seek(io::SeekFrom::Start(0))?; bak_file.seek(io::SeekFrom::Start(0))?; } From 02394c76e2bf3bca21f9fde550d3d234771e7326 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Tue, 6 Aug 2024 20:13:02 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=80=80=E5=87=BA?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=90=8E=E7=BB=88=E7=AB=AF=E9=A2=9C=E8=89=B2?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=E4=BB=A5=E5=8F=8A=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?move=5Fleft=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/cursor.rs | 34 ++++++++++++++++++++++------------ src/utils/ui/uicore.rs | 3 +++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs index e251817..7fdf777 100644 --- a/src/utils/cursor.rs +++ b/src/utils/cursor.rs @@ -265,20 +265,30 @@ impl CursorCrtl { } pub fn move_left(&mut self, count: u16) -> io::Result<()> { - let result = match self.x { - x if x == 0 => Ok(()), - x if x < count => self.move_to_columu(0), - x => match self.prefix_mode { - true if x == self.line_prefix_width - 1 => Ok(()), - true if x - count < self.line_prefix_width => self.move_to_columu(0), - _ => { - self.x -= count; - self.move_to_columu(x - count) - } - }, + // 如果当前光标位置小于或等于行前缀宽度,或者移动的距离大于当前光标位置,则直接移动到行前缀末尾 + if self.x <= self.line_prefix_width || count > self.x { + return self.move_to_columu(0); + } + + // 如果启用了前缀模式且光标在前缀区域内,不进行移动 + if self.prefix_mode && self.x <= self.line_prefix_width { + return Ok(()); + } + + // 计算实际移动的距离 + let actual_move = if count > self.x - self.line_prefix_width { + self.x - self.line_prefix_width + } else { + count }; - result + // 执行光标左移操作 + CursorManager::move_left(actual_move)?; + + // 更新光标位置 + self.x -= actual_move; + + Ok(()) } pub fn move_right(&mut self, count: u16) -> io::Result<()> { diff --git a/src/utils/ui/uicore.rs b/src/utils/ui/uicore.rs index 38206bf..b6ae810 100644 --- a/src/utils/ui/uicore.rs +++ b/src/utils/ui/uicore.rs @@ -385,6 +385,9 @@ impl Ui { fn ui_exit(&self) { // 处理未保存退出时的提醒 + + // 解决退出程序后颜色没改变的问题 + StyleManager::reset_color().unwrap(); } } From 934f1445ab4b7894ebbda31de9b0d69b62b68d9f Mon Sep 17 00:00:00 2001 From: sparkzky Date: Tue, 6 Aug 2024 20:25:34 +0800 Subject: [PATCH 10/15] =?UTF-8?q?undotree=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/mod.rs | 1 + src/utils/undotree.rs | 271 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 src/utils/undotree.rs diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2427952..9b1699d 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; \ No newline at end of file diff --git a/src/utils/undotree.rs b/src/utils/undotree.rs new file mode 100644 index 0000000..c9d4e67 --- /dev/null +++ b/src/utils/undotree.rs @@ -0,0 +1,271 @@ +use std::cell::RefCell; +use std::rc::{Rc, Weak}; + +/// 编辑命令 +#[allow(dead_code)] +#[derive(Debug,Clone,PartialEq, PartialOrd)] +pub struct EditCommand { + // 每个命令所执行的动作 + action: Action, + + // 每个命令所需要的参数, 如操作的起始位置[0],结束位置[1],插入内容[2]等 + params: Vec, +} + +impl Default for EditCommand { + fn default() -> Self { + Self { + action: Action::None, + params: Vec::new(), + } + } +} + +#[allow(dead_code)] +impl EditCommand { + pub fn new(action: Action, params: Vec) -> Self { + Self { + action, + params, + } + } + /// 处理命令,返回对应的反向命令 + pub fn process(&self) -> Result { + let res = match self.action { + Action::Insert => { + EditCommand::new(Action::Delete, self.params.clone()) + } + Action::Delete => { + EditCommand::new(Action::Insert, self.params.clone()) + } + Action::Replace => { + EditCommand::new(Action::Restore, self.params.clone()) + } + Action::Restore => { + EditCommand::new(Action::Replace, self.params.clone()) + } + Action::Move => { + EditCommand::new(Action::Move, vec![self.params[1].clone(), self.params[0].clone()]) + } + _ => EditCommand::default() + }; + + Ok(res) + } +} + +/// 编辑动作 +#[allow(unused)] +#[derive(Debug,Clone,PartialEq, PartialOrd)] +pub enum Action { + // 在起始位置的插入内容 + Insert, + + // 删除的起始位置和结束位置 + Delete, + + // 替换的起始位置、结束位置和替换内容 + Replace, + + // 恢复的位置和内容 + Restore, + + // 移动的起始位置和结束位置 + Move, + + // 其他动作 + None, +} + + +#[allow(dead_code)] +#[derive(Debug)] +pub struct UndoTreeNode { + // 父节点 + parent: Weak>, + // 子节点 + children: Weak>, + // 命令 + command: EditCommand, + // 指向自身的弱引用 + self_pointer: Weak>, + // 指向UndoTree的弱引用 + tree_pointer: Weak>, +} + +#[allow(dead_code)] +impl UndoTreeNode { + pub fn new(command: EditCommand) -> Node { + let result = Rc::new(RefCell::new(UndoTreeNode { + parent: Weak::new(), + children: Weak::new(), + command, + self_pointer: Weak::new(), + tree_pointer: Weak::new(), + })); + 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: &Rc>){ + 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); + new_node.borrow_mut().parent = self.self_pointer.clone(); + new_node.borrow_mut().tree_pointer = self.tree_pointer.clone(); + self.children=Rc::downgrade(&new_node); + } + + /// 插入子节点 + pub fn insert(&mut self, node: Node) { + node.borrow_mut().parent = self.self_pointer.clone(); + node.borrow_mut().tree_pointer = self.tree_pointer.clone(); + self.children=Rc::downgrade(&node); + } + + /// 删除自身以及子节点 + pub fn delete(&mut self) { + match self.children.upgrade() { + Some(children) => {children.borrow_mut().delete();} + None => { + let parent = self.get_parent().unwrap(); + parent.borrow_mut().children = Weak::new(); + }, + } + } + + pub fn get_parent(&self) -> Option { + self.parent.upgrade() + } + + pub fn get_children(&self) -> Option { + self.children.upgrade() + } + +} + +#[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; + } + + pub fn get_to_redo(&mut self) -> Result { + match self.to_redo.pop() { + Some(node) => Ok(node.borrow().get_command()), + None => Err(()) + } + } + + pub 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) { + match self.current_node.borrow().children.upgrade() { + Some(child) => child.borrow_mut().delete(), + None => {} + }; + + 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{ + let command = self.get_to_undo().unwrap(); + let current_node = self.current_node.borrow(); + let parent = match current_node.get_parent(){ + Some(parent) => parent, + None => { + return Ok(EditCommand::default()); + } + }; + drop(current_node); + + self.to_redo.push(self.current_node.clone()); + + self.current_node = parent; + + Ok(command) + } + + /// 恢复操作,返回对应的正向操作 + pub fn redo(&mut self) -> Result{ + let command = self.get_to_redo().unwrap(); + let current_node = self.current_node.borrow(); + let child = match current_node.get_children(){ + Some(child) => child, + None => { + return Ok(EditCommand::default()); + } + }; + drop(current_node); + + self.current_node = child; + + self.to_undo.push(self.current_node.clone()); + + Ok(command) + } +} + + + + + From 833836ace2b61c11c9b65667ddcb0b2210ba634e Mon Sep 17 00:00:00 2001 From: sparkzky Date: Tue, 6 Aug 2024 20:28:59 +0800 Subject: [PATCH 11/15] make fmt --- src/utils/mod.rs | 2 +- src/utils/undotree.rs | 75 +++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 9b1699d..4b9ef5f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -9,4 +9,4 @@ pub mod style; pub mod term_io; pub mod terminal; pub mod ui; -mod undotree; \ No newline at end of file +mod undotree; diff --git a/src/utils/undotree.rs b/src/utils/undotree.rs index c9d4e67..f62da7b 100644 --- a/src/utils/undotree.rs +++ b/src/utils/undotree.rs @@ -3,7 +3,7 @@ use std::rc::{Rc, Weak}; /// 编辑命令 #[allow(dead_code)] -#[derive(Debug,Clone,PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct EditCommand { // 每个命令所执行的动作 action: Action, @@ -24,30 +24,20 @@ impl Default for EditCommand { #[allow(dead_code)] impl EditCommand { pub fn new(action: Action, params: Vec) -> Self { - Self { - action, - params, - } + Self { action, params } } /// 处理命令,返回对应的反向命令 pub fn process(&self) -> Result { let res = match self.action { - Action::Insert => { - EditCommand::new(Action::Delete, self.params.clone()) - } - Action::Delete => { - EditCommand::new(Action::Insert, self.params.clone()) - } - Action::Replace => { - EditCommand::new(Action::Restore, self.params.clone()) - } - Action::Restore => { - EditCommand::new(Action::Replace, self.params.clone()) - } - Action::Move => { - EditCommand::new(Action::Move, vec![self.params[1].clone(), self.params[0].clone()]) - } - _ => EditCommand::default() + Action::Insert => EditCommand::new(Action::Delete, self.params.clone()), + Action::Delete => EditCommand::new(Action::Insert, self.params.clone()), + Action::Replace => EditCommand::new(Action::Restore, self.params.clone()), + Action::Restore => EditCommand::new(Action::Replace, self.params.clone()), + Action::Move => EditCommand::new( + Action::Move, + vec![self.params[1].clone(), self.params[0].clone()], + ), + _ => EditCommand::default(), }; Ok(res) @@ -56,7 +46,7 @@ impl EditCommand { /// 编辑动作 #[allow(unused)] -#[derive(Debug,Clone,PartialEq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum Action { // 在起始位置的插入内容 Insert, @@ -77,7 +67,6 @@ pub enum Action { None, } - #[allow(dead_code)] #[derive(Debug)] pub struct UndoTreeNode { @@ -112,11 +101,11 @@ impl UndoTreeNode { self.command.clone() } - pub fn set_parent(&mut self, parent: &Rc>){ + pub fn set_parent(&mut self, parent: &Rc>) { self.parent = Rc::downgrade(parent); } - pub fn set_tree_pointer(&mut self, root: &Rc>){ + pub fn set_tree_pointer(&mut self, root: &Rc>) { self.tree_pointer = Rc::downgrade(root); } @@ -124,24 +113,26 @@ impl UndoTreeNode { let new_node = UndoTreeNode::new(command); new_node.borrow_mut().parent = self.self_pointer.clone(); new_node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children=Rc::downgrade(&new_node); + self.children = Rc::downgrade(&new_node); } /// 插入子节点 pub fn insert(&mut self, node: Node) { node.borrow_mut().parent = self.self_pointer.clone(); node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children=Rc::downgrade(&node); + self.children = Rc::downgrade(&node); } /// 删除自身以及子节点 pub fn delete(&mut self) { match self.children.upgrade() { - Some(children) => {children.borrow_mut().delete();} + Some(children) => { + children.borrow_mut().delete(); + } None => { let parent = self.get_parent().unwrap(); parent.borrow_mut().children = Weak::new(); - }, + } } } @@ -152,7 +143,6 @@ impl UndoTreeNode { pub fn get_children(&self) -> Option { self.children.upgrade() } - } #[allow(dead_code)] @@ -166,7 +156,7 @@ pub struct UndoTree { /// 待撤销的节点代表操作 to_undo: Vec, /// 待恢复的节点代表操作 - to_redo: Vec + to_redo: Vec, } type Node = Rc>; @@ -198,14 +188,14 @@ impl UndoTree { pub fn get_to_redo(&mut self) -> Result { match self.to_redo.pop() { Some(node) => Ok(node.borrow().get_command()), - None => Err(()) + None => Err(()), } } pub fn get_to_undo(&mut self) -> Result { match self.to_undo.pop() { - Some(node) => Ok(node.borrow().get_command().process()?) , - None => Err(()) + Some(node) => Ok(node.borrow().get_command().process()?), + None => Err(()), } } @@ -215,7 +205,7 @@ impl UndoTree { Some(child) => child.borrow_mut().delete(), None => {} }; - + self.current_node.borrow_mut().insert(new_node.clone()); self.current_node = new_node; self.to_undo.push(self.current_node.clone()); @@ -227,10 +217,10 @@ impl UndoTree { } /// 撤销操作,返回对应的反向操作 - pub fn undo(&mut self) -> Result{ + pub fn undo(&mut self) -> Result { let command = self.get_to_undo().unwrap(); let current_node = self.current_node.borrow(); - let parent = match current_node.get_parent(){ + let parent = match current_node.get_parent() { Some(parent) => parent, None => { return Ok(EditCommand::default()); @@ -246,10 +236,10 @@ impl UndoTree { } /// 恢复操作,返回对应的正向操作 - pub fn redo(&mut self) -> Result{ + pub fn redo(&mut self) -> Result { let command = self.get_to_redo().unwrap(); let current_node = self.current_node.borrow(); - let child = match current_node.get_children(){ + let child = match current_node.get_children() { Some(child) => child, None => { return Ok(EditCommand::default()); @@ -260,12 +250,7 @@ impl UndoTree { self.current_node = child; self.to_undo.push(self.current_node.clone()); - + Ok(command) } } - - - - - From 76bd2a9f2012b3a24378782c4f247ab55e4bb996 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Sat, 10 Aug 2024 02:08:22 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E5=9C=A8UiCore=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=89=80=E9=9C=80=E8=A6=81=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/lastline_cmd.rs | 2 +- src/utils/ui/uicore.rs | 97 +++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) 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/ui/uicore.rs b/src/utils/ui/uicore.rs index b6ae810..ea1edfc 100644 --- a/src/utils/ui/uicore.rs +++ b/src/utils/ui/uicore.rs @@ -10,7 +10,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 +231,101 @@ impl UiCore { Ok(()) } + + pub fn delete_range(&mut self, start_pos: (u16, u16), end_pos: (u16, u16)) -> io::Result<()> { + let content_winsize = *CONTENT_WINSIZE.read().unwrap(); + + 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_x, start_y) = start_pos; + let (end_x, end_y) = end_pos; + + let buffer_line_max = self.buffer.line_count() as u16; + let strat_y = start_y.min(buffer_line_max - 1); + let end_y = end_y.min(buffer_line_max - 1); + + if strat_y == end_y { + self.buffer + .remove_str(start_x, start_y, (end_x - start_x + 1) as usize); + } else { + self.buffer.remove_str(start_x, start_y, usize::MAX); + self.buffer.remove_str(0, end_y, end_x as usize + 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.render_content(y, (content_winsize.rows - y) as usize - 1) + .unwrap(); + Ok(()) + } + + 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(y)); + + // 以便后面能够得到正确的索引 + if y == 0 { + y += 1; + } + if x == 0 { + x += 1; + } + + x -= 1; + y -= 1; + + 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(); + + self.cursor.store_pos(); + + Ok(()) + } } #[derive(Debug)] From aa364c8af71e64da5e209c49da6d434a2276a7a4 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Sat, 10 Aug 2024 07:05:16 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E5=B0=86=E5=8E=9F=E5=85=88=E9=93=BE?= =?UTF-8?q?=E8=A1=A8=E7=BB=93=E6=9E=84=E7=9A=84=E6=92=A4=E9=94=80=E6=A0=91?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=A0=91=E7=8A=B6=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/undotree.rs | 105 ++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/src/utils/undotree.rs b/src/utils/undotree.rs index f62da7b..4ee50ff 100644 --- a/src/utils/undotree.rs +++ b/src/utils/undotree.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::rc::{Rc, Weak}; /// 编辑命令 -#[allow(dead_code)] #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct EditCommand { // 每个命令所执行的动作 @@ -21,7 +20,6 @@ impl Default for EditCommand { } } -#[allow(dead_code)] impl EditCommand { pub fn new(action: Action, params: Vec) -> Self { Self { action, params } @@ -67,13 +65,12 @@ pub enum Action { None, } -#[allow(dead_code)] #[derive(Debug)] pub struct UndoTreeNode { // 父节点 parent: Weak>, // 子节点 - children: Weak>, + children: Vec>>, // 命令 command: EditCommand, // 指向自身的弱引用 @@ -82,12 +79,23 @@ pub struct UndoTreeNode { tree_pointer: Weak>, } -#[allow(dead_code)] +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: Weak::new(), + children: Vec::new(), command, self_pointer: Weak::new(), tree_pointer: Weak::new(), @@ -101,7 +109,7 @@ impl UndoTreeNode { self.command.clone() } - pub fn set_parent(&mut self, parent: &Rc>) { + pub fn set_parent(&mut self, parent: &Node) { self.parent = Rc::downgrade(parent); } @@ -111,28 +119,27 @@ impl UndoTreeNode { pub fn insert_with_command(&mut self, command: EditCommand) { let new_node = UndoTreeNode::new(command); - new_node.borrow_mut().parent = self.self_pointer.clone(); - new_node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children = Rc::downgrade(&new_node); + self.insert(new_node); } /// 插入子节点 pub fn insert(&mut self, node: Node) { node.borrow_mut().parent = self.self_pointer.clone(); - node.borrow_mut().tree_pointer = self.tree_pointer.clone(); - self.children = Rc::downgrade(&node); + node.borrow_mut() + .set_tree_pointer(&self.tree_pointer.upgrade().unwrap()); + self.children.push(node); } /// 删除自身以及子节点 pub fn delete(&mut self) { - match self.children.upgrade() { - Some(children) => { - children.borrow_mut().delete(); - } - None => { - let parent = self.get_parent().unwrap(); - parent.borrow_mut().children = Weak::new(); - } + for child in &self.children { + child.borrow_mut().delete(); + } + if let Some(parent) = self.parent.upgrade() { + parent + .borrow_mut() + .children + .retain(|x| !Rc::ptr_eq(x, &self.self_pointer.upgrade().unwrap())); } } @@ -140,8 +147,8 @@ impl UndoTreeNode { self.parent.upgrade() } - pub fn get_children(&self) -> Option { - self.children.upgrade() + pub fn get_children(&self) -> Vec { + self.children.clone() } } @@ -201,11 +208,6 @@ impl UndoTree { /// 插入新操作,生成新节点 pub fn push(&mut self, new_node: Node) { - match self.current_node.borrow().children.upgrade() { - Some(child) => child.borrow_mut().delete(), - None => {} - }; - self.current_node.borrow_mut().insert(new_node.clone()); self.current_node = new_node; self.to_undo.push(self.current_node.clone()); @@ -218,39 +220,32 @@ impl UndoTree { /// 撤销操作,返回对应的反向操作 pub fn undo(&mut self) -> Result { - let command = self.get_to_undo().unwrap(); - let current_node = self.current_node.borrow(); - let parent = match current_node.get_parent() { - Some(parent) => parent, - None => { - return Ok(EditCommand::default()); + 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) } - }; - drop(current_node); - - self.to_redo.push(self.current_node.clone()); - - self.current_node = parent; - - Ok(command) + Err(e) => Err(e), + } } /// 恢复操作,返回对应的正向操作 pub fn redo(&mut self) -> Result { - let command = self.get_to_redo().unwrap(); - let current_node = self.current_node.borrow(); - let child = match current_node.get_children() { - Some(child) => child, - None => { - return Ok(EditCommand::default()); + 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) } - }; - drop(current_node); - - self.current_node = child; - - self.to_undo.push(self.current_node.clone()); - - Ok(command) + Err(e) => Err(e), + } } } From 5342e6b150511b7192bd6753ca92e03fa119ef05 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Thu, 29 Aug 2024 05:24:27 +0800 Subject: [PATCH 14/15] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=A6=E4=B8=80?= =?UTF-8?q?=E7=A7=8D=E6=92=A4=E9=94=80=E6=96=B9=E5=BC=8F=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/ui/event.rs | 4 + src/utils/ui/mode/mode.rs | 5 ++ src/utils/ui/uicore.rs | 7 +- src/utils/undotree.rs | 149 ++++++++++++++++++++++++++------------ 4 files changed, 115 insertions(+), 50 deletions(-) diff --git a/src/utils/ui/event.rs b/src/utils/ui/event.rs index b223065..030810c 100644 --- a/src/utils/ui/event.rs +++ b/src/utils/ui/event.rs @@ -161,6 +161,10 @@ pub trait KeyEventCallback { ui: &mut MutexGuard, data: &[u8], ) -> io::Result; + fn t(&self, ui: &mut MutexGuard) -> io::Result { + ui.delete_range((2,3), (9,4))?; + Ok(WarpUiCallBackType::None) + } } #[derive(Debug, PartialEq)] diff --git a/src/utils/ui/mode/mode.rs b/src/utils/ui/mode/mode.rs index 42ecf3f..8ed9070 100644 --- a/src/utils/ui/mode/mode.rs +++ b/src/utils/ui/mode/mode.rs @@ -519,6 +519,11 @@ 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 ea1edfc..17be87f 100644 --- a/src/utils/ui/uicore.rs +++ b/src/utils/ui/uicore.rs @@ -235,7 +235,7 @@ impl UiCore { pub fn delete_range(&mut self, start_pos: (u16, u16), end_pos: (u16, u16)) -> io::Result<()> { let content_winsize = *CONTENT_WINSIZE.read().unwrap(); - if start_pos.0 < end_pos.0 || start_pos.1 < end_pos.1 { + 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(()); @@ -263,7 +263,7 @@ impl UiCore { let y = self.cursor.y(); - self.render_content(y, (content_winsize.rows - y) as usize - 1) + self.render_content(y - 1, (content_winsize.rows - y) as usize - 1) .unwrap(); Ok(()) } @@ -309,6 +309,7 @@ impl UiCore { x -= 1; y -= 1; + self.cursor.store_pos(); self.cursor.set_prefix_mode(true); self.cursor.restore_pos().unwrap(); @@ -322,8 +323,6 @@ impl UiCore { self.cursor.highlight(Some(lasty)).unwrap(); - self.cursor.store_pos(); - Ok(()) } } diff --git a/src/utils/undotree.rs b/src/utils/undotree.rs index 4ee50ff..c0c5505 100644 --- a/src/utils/undotree.rs +++ b/src/utils/undotree.rs @@ -4,61 +4,83 @@ use std::rc::{Rc, Weak}; /// 编辑命令 #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct EditCommand { - // 每个命令所执行的动作 - action: Action, + // 删除动作,如果有的话 + action_delete: Option, - // 每个命令所需要的参数, 如操作的起始位置[0],结束位置[1],插入内容[2]等 - params: Vec, + // 插入操作,如果有的话 + action_insert: Option, + + // 对于第几行进行的操作(目前就只实现针对单独一个文件的) + line_number: u16, } impl Default for EditCommand { fn default() -> Self { Self { - action: Action::None, - params: Vec::new(), + action_delete: None, + action_insert: None, + line_number: 0, } } } impl EditCommand { - pub fn new(action: Action, params: Vec) -> Self { - Self { action, params } + 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 res = match self.action { - Action::Insert => EditCommand::new(Action::Delete, self.params.clone()), - Action::Delete => EditCommand::new(Action::Insert, self.params.clone()), - Action::Replace => EditCommand::new(Action::Restore, self.params.clone()), - Action::Restore => EditCommand::new(Action::Replace, self.params.clone()), - Action::Move => EditCommand::new( - Action::Move, - vec![self.params[1].clone(), self.params[0].clone()], - ), - _ => EditCommand::default(), - }; + 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, + // 插入内容 + Insert(String), - // 删除的起始位置和结束位置 - Delete, + // 删除内容 + Delete(String), - // 替换的起始位置、结束位置和替换内容 - Replace, - - // 恢复的位置和内容 - Restore, - - // 移动的起始位置和结束位置 + // 移动(未实现) Move, // 其他动作 @@ -77,19 +99,25 @@ pub struct UndoTreeNode { 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 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 { @@ -99,6 +127,8 @@ impl UndoTreeNode { 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); @@ -154,15 +184,18 @@ impl UndoTreeNode { #[allow(dead_code)] #[derive(Debug)] -/// 编辑树 +/// 撤销树 +/// 用于记录编辑历史,实现撤销和恢复功能 +/// 支持两种撤销方式,可以根据用户的需要来选择哪种撤销方式 +/// 此撤销树仅用于记录和返回相关操作,相对独立于其他部分 pub struct UndoTree { /// 根节点 root: Node, /// 当前节点 current_node: Node, - /// 待撤销的节点代表操作 + /// 待撤销的节点,代表操作 to_undo: Vec, - /// 待恢复的节点代表操作 + /// 待恢复的节点,代表操作 to_redo: Vec, } @@ -192,14 +225,14 @@ impl UndoTree { self.current_node = node; } - pub fn get_to_redo(&mut self) -> Result { + fn get_to_redo(&mut self) -> Result { match self.to_redo.pop() { Some(node) => Ok(node.borrow().get_command()), None => Err(()), } } - pub fn get_to_undo(&mut self) -> Result { + fn get_to_undo(&mut self) -> Result { match self.to_undo.pop() { Some(node) => Ok(node.borrow().get_command().process()?), None => Err(()), @@ -248,4 +281,28 @@ impl UndoTree { 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(); + 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(()) + } + } } From 30134f8d32a375d4a39d2dd753a1f88db27ff584 Mon Sep 17 00:00:00 2001 From: sparkzky Date: Sat, 31 Aug 2024 21:51:26 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E5=AE=9E=E7=8E=B0UiCore.delete=5Frange(&?= =?UTF-8?q?mut=20self,=20start=5Fpos:=20(u16,=20u16),=20end=5Fpos:=20(u16,?= =?UTF-8?q?=20u16))=20=20Uicore.goto=5Fline()=20=20=E5=BE=AE=E8=B0=83?= =?UTF-8?q?=E6=92=A4=E9=94=80=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/buffer.rs | 30 ++++++++++++++++ src/utils/ui/event.rs | 11 +++--- src/utils/ui/mode/mode.rs | 9 ++--- src/utils/ui/uicore.rs | 75 +++++++++++++++++++++++++++++++-------- src/utils/undotree.rs | 13 +++++++ 5 files changed, 116 insertions(+), 22 deletions(-) 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/ui/event.rs b/src/utils/ui/event.rs index 030810c..61cb8c6 100644 --- a/src/utils/ui/event.rs +++ b/src/utils/ui/event.rs @@ -161,10 +161,13 @@ pub trait KeyEventCallback { ui: &mut MutexGuard, data: &[u8], ) -> io::Result; - fn t(&self, ui: &mut MutexGuard) -> io::Result { - ui.delete_range((2,3), (9,4))?; - Ok(WarpUiCallBackType::None) - } + + // 测试用,有需要的话可以删除此函数 + // 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 8ed9070..cb6ddab 100644 --- a/src/utils/ui/mode/mode.rs +++ b/src/utils/ui/mode/mode.rs @@ -519,10 +519,11 @@ impl KeyEventCallback for Command { return Ok(WarpUiCallBackType::None); } - b"t" => { - self.t(ui)?; - 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 17be87f..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::{ @@ -232,8 +233,11 @@ 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 = @@ -241,33 +245,71 @@ impl UiCore { return Ok(()); } - let (start_x, start_y) = start_pos; - let (end_x, end_y) = end_pos; + 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 strat_y = start_y.min(buffer_line_max - 1); - let end_y = end_y.min(buffer_line_max - 1); + 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 strat_y == 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(start_x, start_y, (end_x - start_x + 1) as usize); + .remove_str_abs(start_x, start_y, (end_x - start_x + 1) as usize); } else { - self.buffer.remove_str(start_x, start_y, usize::MAX); - self.buffer.remove_str(0, end_y, end_x as usize + 1); - self.buffer - .delete_lines((start_y + 1) as usize, (end_y - 1) as usize); + 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(); + // 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.render_content(y - 1, (content_winsize.rows - y) as usize - 1) - .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(); @@ -296,7 +338,7 @@ impl UiCore { 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(y)); + let mut x = x.unwrap_or(1).min(self.buffer.get_linesize_absoluted(y)); // 以便后面能够得到正确的索引 if y == 0 { @@ -325,6 +367,11 @@ impl UiCore { 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 index c0c5505..78751d7 100644 --- a/src/utils/undotree.rs +++ b/src/utils/undotree.rs @@ -157,6 +157,9 @@ impl UndoTreeNode { 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); } @@ -166,6 +169,14 @@ impl UndoTreeNode { 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 @@ -287,6 +298,8 @@ impl UndoTree { 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 {