diff --git a/src/application/handler/workspace.rs b/src/application/handler/workspace.rs index ef88548..6e17fc7 100644 --- a/src/application/handler/workspace.rs +++ b/src/application/handler/workspace.rs @@ -4,7 +4,11 @@ use crate::errors::*; pub fn to_normal_mode(app: &mut Application) -> Result<()> { if let ModeData::Workspace(ref mode) = app.mode { - app.workspace.select_buffer(mode.prev_buffer_id); + if let Some(buffer_id) = mode.prev_buffer_id { + app.workspace.select_buffer(buffer_id); + } else { + return Ok(()); + } } app.switch_mode(ModeKey::Normal); Ok(()) diff --git a/src/application/mod.rs b/src/application/mod.rs index 53eb73a..f92f69b 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -15,9 +15,7 @@ use state::ApplicationStateData; use std::{cell::RefCell, collections::HashMap, mem, rc::Rc, sync::Arc}; use crate::{ - config::appconfig::AppSetting, modules::perferences::{Perferences, PerferencesManager}, - utils::{file::FileManager, ui::uicore::Ui}, view::monitor::Monitor, workspace::Workspace, }; @@ -28,9 +26,6 @@ pub mod plugin_interafce; pub mod state; pub struct Application { - file_manager: FileManager, - bak: bool, - ui: Arc, pub workspace: Workspace, pub monitor: Monitor, pub perferences: Rc>, @@ -50,19 +45,7 @@ pub struct Application { } impl Application { - pub fn new(file_path: Option, setting: AppSetting, args: &[String]) -> Result { - let bak; - let mut file = if file_path.is_some() { - bak = true; - FileManager::new(file_path.unwrap())? - } else { - bak = false; - FileManager::new("held.tmp".to_string())? - }; - - // 将文件数据读入buf - let buf = file.init(bak)?; - + pub fn new(args: &[String]) -> Result { let perferences = PerferencesManager::load()?; let plugin_system = Rc::new(RefCell::new(PluginSystem::init_system( @@ -72,10 +55,8 @@ impl Application { let input_map = InputLoader::load(perferences.borrow().input_config_path()?)?; let mut monitor = Monitor::new(perferences.clone(), plugin_system.clone())?; let workspace = Workspace::create_workspace(&mut monitor, perferences.borrow(), args)?; + Ok(Self { - file_manager: file, - bak, - ui: Ui::new(Arc::new(buf), setting), workspace, monitor, perferences, @@ -90,15 +71,8 @@ impl Application { } fn init(&mut self) -> Result<()> { - // Ui::init_ui()?; - // PluginSystem::init_system(); - // self.monitor.terminal.clear().unwrap(); self.init_modes()?; self.plugin_system.borrow().init(); - // if !self.bak { - // self.ui.start_page_ui()?; - // } - Ok(()) } @@ -122,12 +96,16 @@ impl Application { self.mode_history.insert(ModeKey::Delete, ModeData::Delete); self.mode_history .insert(ModeKey::Search, ModeData::Search(SearchData::new())); + + if self.workspace.current_buffer.is_none() { + self.switch_mode(ModeKey::Workspace); + } + Ok(()) } pub fn run(&mut self) -> Result<()> { self.init()?; - loop { self.render()?; self.listen_event()?; @@ -137,24 +115,6 @@ impl Application { return Ok(()); } } - - // 主线程 - match self.ui.ui_loop() { - Ok(store) => { - if store { - let buffer = &self.ui.core.lock().unwrap().buffer; - self.file_manager.store(buffer)? - } else if self.file_manager.is_first_open() { - self.file_manager.delete_files()?; - } - } - Err(_) => { - // 补救措施:恢复备份文件 - todo!() - } - } - disable_raw_mode()?; - Ok(()) } fn listen_event(&mut self) -> Result<()> { diff --git a/src/application/mode/delete.rs b/src/application/mode/delete.rs index 57fa23c..51e6ab3 100644 --- a/src/application/mode/delete.rs +++ b/src/application/mode/delete.rs @@ -16,7 +16,6 @@ impl ModeRenderer for DeleteRenderer { let mut presenter = monitor.build_presenter()?; if let Some(buffer) = &workspace.current_buffer { - warn!("Delete buffer id: {}", buffer.id.unwrap()); let data = buffer.data(); presenter.print_buffer(buffer, &data, &workspace.syntax_set, None, None)?; diff --git a/src/application/mode/normal.rs b/src/application/mode/normal.rs index 83aeb8d..e75dbfd 100644 --- a/src/application/mode/normal.rs +++ b/src/application/mode/normal.rs @@ -16,7 +16,6 @@ impl ModeRenderer for NormalRenderer { let mut presenter = monitor.build_presenter()?; if let Some(buffer) = &workspace.current_buffer { - warn!("normal buffer id: {}", buffer.id.unwrap()); let data = buffer.data(); presenter.print_buffer(buffer, &data, &workspace.syntax_set, None, None)?; diff --git a/src/application/mode/workspace.rs b/src/application/mode/workspace.rs index 3eddb1e..a04b71d 100644 --- a/src/application/mode/workspace.rs +++ b/src/application/mode/workspace.rs @@ -24,7 +24,7 @@ pub struct WorkspaceModeData { max_index: usize, opened_dir_inos: HashSet, buffer_id: usize, - pub prev_buffer_id: usize, + pub prev_buffer_id: Option, highlight_ranges: Vec<(Range, CharStyle, Colors)>, } @@ -37,19 +37,23 @@ impl WorkspaceModeData { let mut opened_dir_inos = HashSet::new(); opened_dir_inos.insert(workspace.path.metadata()?.ino()); - let prev_buffer_id = workspace.current_buffer.as_ref().unwrap().id()?; - + let mut prev_buffer_id = None; + if let Some(current_buffer) = workspace.current_buffer.as_ref() { + prev_buffer_id = Some(current_buffer.id()?); + } let buffer = Buffer::new(); let buffer_id = workspace.add_buffer(buffer); - monitor.init_buffer(workspace.current_buffer.as_mut().unwrap())?; + monitor.init_buffer(workspace.get_buffer_mut(buffer_id).unwrap())?; - workspace.select_buffer(prev_buffer_id); + if let Some(id) = prev_buffer_id { + workspace.select_buffer(id); + } Ok(WorkspaceModeData { path: workspace.path.clone(), selected_index: 0, opened_dir_inos, - buffer_id: buffer_id, + buffer_id, prev_buffer_id, highlight_ranges: Vec::new(), current_render_index: 0, @@ -276,10 +280,9 @@ impl WorkspaceModeData { Ok(false) } else { let buffer = Buffer::from_file(&self.selected_path)?; - let id = workspace.add_buffer(buffer); - workspace.select_buffer(id); + let id = workspace.add_buffer_with_select(buffer); monitor.init_buffer(workspace.current_buffer.as_mut().unwrap())?; - self.prev_buffer_id = id; + self.prev_buffer_id = Some(id); Ok(true) } } diff --git a/src/config/appconfig.rs b/src/config/appconfig.rs deleted file mode 100644 index a0869c6..0000000 --- a/src/config/appconfig.rs +++ /dev/null @@ -1,163 +0,0 @@ -use crossterm::style::Color; - -#[derive(Debug, serde::Deserialize, Default)] -pub struct DeserializeAppOption { - pub line: Option, -} - -#[derive(Debug)] -pub struct AppSetting { - pub line: LineSetting, -} - -#[derive(Debug, serde::Deserialize, Clone, Copy)] -pub struct DeserializeLineOption { - pub number: Option, - pub highlight: Option, -} - -#[derive(Debug, Clone, Copy)] -pub struct LineSetting { - pub line_num: LineNumberSetting, - pub highlight: HighLightSetting, - - pub prefix_width: usize, -} - -#[derive(Debug, serde::Deserialize, Clone, Copy)] -pub struct DeserializeLineNumber { - pub enable: bool, - pub background: Option, - pub frontground: Option, -} - -impl DeserializeLineNumber { - pub fn to_line_number_setting(setting: Option) -> LineNumberSetting { - let mut ret = LineNumberSetting::default(); - if setting.is_none() { - return ret; - } else { - let setting = setting.unwrap(); - if setting.background.is_some() { - let color = setting.background.unwrap(); - let r = (color & 0xff0000) >> 16; - let g = (color & 0x00ff00) >> 8; - let b = color & 0x0000ff; - - ret.background = Color::Rgb { - r: r as u8, - g: g as u8, - b: b as u8, - } - } - - if setting.frontground.is_some() { - let color = setting.frontground.unwrap(); - let r = (color & 0xff0000) >> 16; - let g = (color & 0x00ff00) >> 8; - let b = color & 0x0000ff; - - ret.frontground = Color::Rgb { - r: r as u8, - g: g as u8, - b: b as u8, - } - } - - return ret; - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct LineNumberSetting { - pub enable: bool, - pub background: Color, - pub frontground: Color, -} - -impl Default for LineNumberSetting { - fn default() -> Self { - Self { - enable: true, - background: Color::DarkGreen, - frontground: Color::White, - } - } -} - -impl Default for LineSetting { - fn default() -> Self { - Self { - line_num: LineNumberSetting::default(), - highlight: Default::default(), - prefix_width: 0, - } - } -} - -// 高亮选项 -#[derive(Debug, serde::Deserialize, Clone, Copy)] -pub struct DeserializeHighLightSetting { - pub enable: bool, - pub color: u32, -} - -impl DeserializeHighLightSetting { - pub fn to_highlight_setting(&self) -> HighLightSetting { - let r = (self.color & 0xff0000) >> 16; - let g = (self.color & 0x00ff00) >> 8; - let b = self.color & 0x0000ff; - - HighLightSetting { - enable: self.enable, - color: Color::Rgb { - r: r as u8, - g: g as u8, - b: b as u8, - }, - } - } -} - -// 高亮选项 -#[derive(Debug, Clone, Copy)] -pub struct HighLightSetting { - pub enable: bool, - pub color: Color, -} - -impl Default for HighLightSetting { - fn default() -> Self { - Self { - enable: true, - color: Color::DarkYellow, - } - } -} - -impl DeserializeAppOption { - pub fn to_app_setting(&self) -> AppSetting { - let line_setting = match self.line { - Some(setting) => setting.to_line_setting(), - None => LineSetting::default(), - }; - - AppSetting { line: line_setting } - } -} - -impl DeserializeLineOption { - pub fn to_line_setting(&self) -> LineSetting { - let mut highlight = HighLightSetting::default(); - if self.highlight.is_some() { - let h = self.highlight.unwrap(); - highlight = h.to_highlight_setting(); - } - LineSetting { - line_num: DeserializeLineNumber::to_line_number_setting(self.number), - highlight, - prefix_width: 0, - } - } -} diff --git a/src/config/cmd.rs b/src/config/cmd.rs deleted file mode 100644 index f7f0e10..0000000 --- a/src/config/cmd.rs +++ /dev/null @@ -1,16 +0,0 @@ -use clap::Parser; -use log::LevelFilter; - -#[derive(Parser)] -#[command(name = "held")] -#[command(author = "heyicong@dragonos.org")] -#[command(version = "1.0")] -#[command(about = "a termial editor", long_about = None)] -pub struct CmdConfig { - /// open file - pub file: Option, - - /// log level - #[arg(value_enum, short, long, default_value = "warn")] - pub level: LevelFilter, -} diff --git a/src/config/lastline_cmd.rs b/src/config/lastline_cmd.rs deleted file mode 100644 index 15e520a..0000000 --- a/src/config/lastline_cmd.rs +++ /dev/null @@ -1,328 +0,0 @@ -use std::{collections::HashMap, sync::MutexGuard}; - -use lazy_static::lazy_static; - -use crate::utils::{ - buffer::LineState, - ui::{ - event::WarpUiCallBackType, - uicore::{UiCore, APP_INTERNAL_INFOMATION, CONTENT_WINSIZE}, - InfoLevel, - }, -}; - -lazy_static! { - static ref COMMAND: HashMap<&'static str, fn(&mut MutexGuard, &str) -> WarpUiCallBackType> = { - let mut map: HashMap<&str, fn(&mut MutexGuard, &str) -> WarpUiCallBackType> = - HashMap::new(); - map.insert(":q!", LastLineCommand::force_exit); - map.insert(":q", LastLineCommand::exit_without_store); - map.insert(":wq", LastLineCommand::exit); - - // 跳转 - map.insert(":goto", LastLineCommand::goto); - map.insert(":gt", LastLineCommand::goto); - - // 标记或锁定 - map.insert(":flag", LastLineCommand::flag); - map.insert(":lock", LastLineCommand::lock); - map.insert(":unflag", LastLineCommand::unflag); - map.insert(":unlock", LastLineCommand::unlock); - - map.insert(":delete", LastLineCommand::delete_lines); - map.insert(":dl", LastLineCommand::delete_lines); - - map - }; -} - -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, - pub args: Vec, -} - -/// 提供给用户的命令行功能 -impl LastLineCommand { - pub fn process(ui: &mut MutexGuard, cmd: String) -> WarpUiCallBackType { - let args = cmd - .splitn(2, |x: char| x.is_ascii_whitespace()) - .collect::>(); - - if let Some(func) = COMMAND.get(args[0]) { - let ret = if args.len() == 1 { - func(ui, "") - } else { - func(ui, &args[1]) - }; - - ret - } else { - let mut info = APP_INTERNAL_INFOMATION.lock().unwrap(); - info.level = InfoLevel::Info; - info.info = NOT_FOUNT_CMD.to_string(); - return WarpUiCallBackType::None; - } - } - - const fn is_split_char(x: char) -> bool { - x == ',' || x == ';' || x == ':' || x == '/' || x.is_ascii_whitespace() - } - - fn force_exit(_ui: &mut MutexGuard, _args: &str) -> WarpUiCallBackType { - WarpUiCallBackType::Exit(false) - } - - fn exit_without_store(ui: &mut MutexGuard, _args: &str) -> WarpUiCallBackType { - if ui.edited() { - // 编辑过但不保存? - // 更新警示信息 - let mut info = APP_INTERNAL_INFOMATION.lock().unwrap(); - info.level = InfoLevel::Warn; - info.info = EDITED_NO_STORE.to_string(); - return WarpUiCallBackType::None; - } - WarpUiCallBackType::Exit(false) - } - - fn exit(_ui: &mut MutexGuard, _args: &str) -> WarpUiCallBackType { - WarpUiCallBackType::Exit(true) - } - - fn goto(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { - if args.is_empty() { - let mut info = APP_INTERNAL_INFOMATION.lock().unwrap(); - info.level = InfoLevel::Info; - info.info = "Useage: {goto}|{gt} {row}{' '|','|';'|':'|'/'}{col}".to_string(); - return WarpUiCallBackType::None; - } - let (y, x) = { - let a = args.split(|x| Self::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_INTERNAL_INFOMATION.lock().unwrap(); - info.level = InfoLevel::Info; - info.info = "Useage: goto {row}({' '|','|';'|':'|'/'}{col})".to_string(); - return WarpUiCallBackType::None; - } - - let buf_line_max = ui.buffer.line_count() as u16; - let content_line_max = CONTENT_WINSIZE.read().unwrap().rows; - let mut y = y.unwrap().min(buf_line_max); - let mut x = x.unwrap_or(1).min(ui.buffer.get_linesize(y)); - - if y == 0 { - y += 1; - } - if x == 0 { - x += 1; - } - - x -= 1; - y -= 1; - - ui.cursor.set_prefix_mode(true); - - ui.cursor.restore_pos().unwrap(); - - // if y < ui.buffer.offset() as u16 + content_line_max { - // ui.buffer.set_offset(0); - // } else { - // ui.buffer.set_offset((y - content_line_max) as usize); - // } - - let lasty = ui.cursor.y(); - let y = ui.buffer.goto_line(y as usize); - ui.cursor.move_to(x, y).unwrap(); - - let pos = ui.cursor.store_tmp_pos(); - ui.render_content(0, content_line_max as usize).unwrap(); - ui.cursor.restore_tmp_pos(pos).unwrap(); - - ui.cursor.highlight(Some(lasty)).unwrap(); - - ui.cursor.store_pos(); - - return WarpUiCallBackType::None; - } - - // 标记行 - pub fn flag(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::FLAGED); - } - - for s in args { - let line = usize::from_str_radix(s, 10); - if line.is_err() { - APP_INTERNAL_INFOMATION.lock().unwrap().info = format!("\"{s}\" is not a number"); - return WarpUiCallBackType::None; - } - - let line = line.unwrap(); - ui.buffer.add_line_flags(line - 1, LineState::FLAGED); - } - - WarpUiCallBackType::None - } - - // 锁定行 - pub fn lock(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { - 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) - } - _ => { - //有参数,锁定指定行 - for arg in args { - let line = usize::from_str_radix(arg, 10); - if line.is_err() { - APP_INTERNAL_INFOMATION.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); - } - } - } - - WarpUiCallBackType::None - } - - // 标记行 - pub fn unflag(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { - 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) - } - _ => { - //有参数,解除标记指定行 - for arg in args { - let line = usize::from_str_radix(arg, 10); - if line.is_err() { - APP_INTERNAL_INFOMATION.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); - } - } - } - - WarpUiCallBackType::None - } - - // 解除锁定行 - pub fn unlock(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { - 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) - } - _ => { - //有参数,解除锁定指定行 - for arg in args { - let line = usize::from_str_radix(arg, 10); - if line.is_err() { - APP_INTERNAL_INFOMATION.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); - } - } - } - - WarpUiCallBackType::None - } - - pub fn delete_lines(ui: &mut MutexGuard, args: &str) -> WarpUiCallBackType { - let args = args.split(|x| x == '-').collect::>(); - - 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_INTERNAL_INFOMATION.lock().unwrap().info = - format!("Successfully deleted {count} row"); - } - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) - .unwrap(); - return WarpUiCallBackType::None; - } - 1 => { - let line = usize::from_str_radix(args[0], 10); - if line.is_err() { - APP_INTERNAL_INFOMATION.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_INTERNAL_INFOMATION.lock().unwrap().info = - format!("Successfully deleted {count} row"); - } - 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_INTERNAL_INFOMATION.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_INTERNAL_INFOMATION.lock().unwrap().info = - format!("Successfully deleted {count} row"); - } - - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) - .unwrap(); - } - } - return WarpUiCallBackType::None; - } -} diff --git a/src/config/mod.rs b/src/config/mod.rs index 0a269b8..f7f0e10 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,16 @@ -pub mod appconfig; -pub mod cmd; -pub mod lastline_cmd; +use clap::Parser; +use log::LevelFilter; + +#[derive(Parser)] +#[command(name = "held")] +#[command(author = "heyicong@dragonos.org")] +#[command(version = "1.0")] +#[command(about = "a termial editor", long_about = None)] +pub struct CmdConfig { + /// open file + pub file: Option, + + /// log level + #[arg(value_enum, short, long, default_value = "warn")] + pub level: LevelFilter, +} diff --git a/src/main.rs b/src/main.rs index 63dc707..2781b87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,9 @@ -#![feature(duration_millis_float)] - -use std::{env, fs::File}; +use std::env; use application::Application; use clap::Parser; -use config::{appconfig::DeserializeAppOption, cmd::CmdConfig}; -use utils::log_util::Log; +use config::CmdConfig; +use util::log_util::Log; mod application; mod buffer; @@ -14,7 +12,6 @@ mod errors; mod modules; mod plugin; mod util; -mod utils; mod view; mod workspace; @@ -35,16 +32,7 @@ fn main() -> Result<()> { let config = CmdConfig::parse(); Log::init(config.level)?; - let setting; - - let file = File::open("config.yaml"); - if file.is_err() { - setting = DeserializeAppOption::default(); - } else { - setting = serde_yaml::from_reader::(file?).unwrap_or_default(); - } - - let application = Application::new(config.file, setting.to_app_setting(), &args)?; + let application = Application::new(&args)?; unsafe { APPLICATION = Some(application); diff --git a/src/modules/perferences/mod.rs b/src/modules/perferences/mod.rs index 251b4d3..8179282 100644 --- a/src/modules/perferences/mod.rs +++ b/src/modules/perferences/mod.rs @@ -1,12 +1,12 @@ -use crate::{errors::*, utils::ui::uicore::APP_INTERNAL_INFOMATION}; -use app_dirs2::{app_dir, AppDataType, AppInfo}; +use crate::errors::*; +use app_dirs2::{app_dir, AppDataType}; use std::{ cell::RefCell, path::{Path, PathBuf}, rc::Rc, }; use yaml::YamlPerferences; -use yaml_rust::{Yaml, YamlLoader}; +use yaml_rust::YamlLoader; use super::APP_INFO; @@ -135,7 +135,7 @@ impl Perferences for DummyPerferences { todo!() } - fn syntax_definition_name(&self, path: &Path) -> Option { + fn syntax_definition_name(&self, _path: &Path) -> Option { todo!() } diff --git a/src/util/log_util.rs b/src/util/log_util.rs new file mode 100644 index 0000000..f5e3a9b --- /dev/null +++ b/src/util/log_util.rs @@ -0,0 +1,19 @@ +use std::{fs::File, io}; + +use log::LevelFilter; +use simplelog::{CombinedLogger, WriteLogger}; + +pub struct Log; + +impl Log { + pub fn init(level: LevelFilter) -> io::Result<()> { + CombinedLogger::init(vec![WriteLogger::new( + level, + simplelog::Config::default(), + File::create("held.log")?, + )]) + .unwrap(); + + Ok(()) + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 1132c78..7202b82 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1 +1,2 @@ pub mod line_iterator; +pub mod log_util; diff --git a/src/utils/buffer.rs b/src/utils/buffer.rs deleted file mode 100644 index 628d2f0..0000000 --- a/src/utils/buffer.rs +++ /dev/null @@ -1,589 +0,0 @@ -use std::{ - collections::HashMap, - io, - ops::Deref, - sync::{ - atomic::{AtomicUsize, Ordering}, - RwLock, - }, -}; - -use bitflags::bitflags; -use crossterm::style::Color; - -use super::{ - style::StyleManager, - ui::uicore::{APP_INTERNAL_INFOMATION, CONTENT_WINSIZE}, -}; - -#[derive(Debug, Default, Clone)] -pub struct LineBuffer { - id: usize, - - pub data: Vec, - - // 是否被标记 - pub flags: LineState, -} - -impl Deref for LineBuffer { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.data - } -} - -impl LineBuffer { - pub fn new(data: Vec) -> Self { - static LINE_ID_ALLOCTOR: AtomicUsize = AtomicUsize::new(0); - Self { - id: LINE_ID_ALLOCTOR.fetch_add(1, Ordering::SeqCst), - data, - flags: LineState::empty(), - } - } - - #[inline] - pub fn remove(&mut self, idx: usize) { - self.data.remove(idx); - } - - #[inline] - pub fn size(&self) -> usize { - self.data.len() - } - - #[inline] - pub fn extend(&mut self, other: LineBuffer) { - self.data.extend(other.data) - } - - #[inline] - pub fn insert(&mut self, idx: usize, data: u8) { - self.data.insert(idx, data) - } -} - -#[derive(Debug, Default)] -pub struct EditBuffer { - buf: RwLock>, - - // 记录当前页第一行对应buf中的index - offset: AtomicUsize, - - // 记录被标记的行,行ID -> 行index - flag_lines: RwLock>, - - // 记录锁定行 - locked_lines: RwLock>, -} - -impl EditBuffer { - pub fn new(buf: Vec) -> Self { - let mut lines = buf - .split_inclusive(|x| *x == '\n' as u8) - .map(|slice| slice.to_vec()) - .collect::>>(); - - let last = lines.last(); - if last.is_none() { - lines.push(vec!['\n' as u8]) - } else { - let last = last.unwrap(); - if !last.ends_with(&['\n' as u8]) { - lines.last_mut().unwrap().push('\n' as u8) - } - } - - let mut buf = Vec::new(); - for v in lines { - buf.push(LineBuffer::new(v)); - } - - Self { - buf: RwLock::new(buf), - offset: AtomicUsize::new(0), - flag_lines: RwLock::new(HashMap::new()), - locked_lines: RwLock::new(HashMap::new()), - } - } - - #[inline] - pub fn set_offset(&self, mut offset: usize) { - offset = offset.min(self.buf.read().unwrap().len() - 1); - self.offset.store(offset, Ordering::SeqCst); - } - - #[inline] - pub fn offset(&self) -> usize { - self.offset.load(Ordering::SeqCst) - } - - pub fn line_count(&self) -> usize { - self.buf.read().unwrap().len() - } - - /// 获取一部分上下文 - pub fn get_content( - &self, - mut start_y: usize, - mut line_count: usize, - ) -> Option> { - start_y += self.offset.load(Ordering::SeqCst); - line_count = line_count.min(self.line_count() - start_y); - let buf = self.buf.read().unwrap(); - if start_y > buf.len() { - return None; - } - let end = buf.len().min(start_y + line_count); - - let mut ret = Vec::with_capacity(end - start_y); - ret.resize(end - start_y, LineBuffer::default()); - ret[..].clone_from_slice(&buf[start_y..end]); - Some(ret) - } - - 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); - if line.is_none() { - return 0; - } - - let line = line.unwrap(); - - line.data.len() as u16 - } - - pub fn get_linesize_abs(&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 - } - - /// 外部接口,本结构体内部方法不应该使用,因为涉及offset计算 - pub fn remove_char(&self, x: u16, y: u16) { - let mut buf = self.buf.write().unwrap(); - let line = buf.get_mut(self.offset.load(Ordering::SeqCst) + y as usize); - if line.is_none() { - return; - } - - line.unwrap().remove(x as usize); - } - - pub fn remove_str(&self, x: u16, y: u16, n: usize) { - let mut buf = self.buf.write().unwrap(); - let line = buf.get_mut(self.offset.load(Ordering::SeqCst) + y as usize); - if line.is_none() { - return; - } - let x = x as usize; - line.unwrap().data.drain(x..x + n); - } - - /// 获取一份对应行的拷贝 - pub fn get_line(&self, line: u16) -> LineBuffer { - let buf = self.buf.read().unwrap(); - let line = buf.get(self.offset.load(Ordering::SeqCst) + line as usize); - if line.is_none() { - LineBuffer::default() - } else { - line.unwrap().clone() - } - } - - /// 向缓冲区插入一行数据 - pub fn insert_line(&self, idx: usize, element: &LineBuffer) { - let mut buf = self.buf.write().unwrap(); - buf.insert(idx, element.clone()); - } - - /// 将某行数据与上一行合并 - /// 返回合并是否成功,以及被合并行之前的长度 - pub fn merge_line(&self, line: u16) -> (bool, usize) { - let line = self.offset.load(Ordering::SeqCst) + line as usize; - if line == 0 { - // 没有上一行 - return (false, 0); - } - - let mut buf = self.buf.write().unwrap(); - let cur_line = buf.get(line as usize).unwrap().clone(); - - let previous_line = buf.get_mut(line - 1).unwrap(); - - if previous_line.flags.contains(LineState::LOCKED) - || cur_line.flags.contains(LineState::LOCKED) - { - APP_INTERNAL_INFOMATION.lock().unwrap().info = "Row is locked".to_string(); - return (false, 0); - } - - let p_len = previous_line.size(); - // 移除最后的\n - previous_line.remove(p_len - 1); - previous_line.extend(cur_line); - - buf.remove(line as usize); - - return (true, p_len - 1); - } - - /// 屏幕坐标 - #[inline] - pub fn insert_char(&self, ch: u8, x: u16, y: u16) { - let mut buf = self.buf.write().unwrap(); - let line = buf.get_mut(self.offset() + y as usize); - match line { - Some(line) => line.insert(x as usize, ch), - None => { - let newline = vec!['\n' as u8]; - buf.push(LineBuffer::new(newline)); - } - } - } - - #[inline] - pub fn all_buffer(&self) -> Vec { - self.buf.read().unwrap().clone() - } - - /// 输入enter时buf的更新操作 - pub fn input_enter(&self, x: u16, y: u16) { - let y = self.offset.load(Ordering::SeqCst) + y as usize; - - let mut buf = self.buf.write().unwrap(); - let linesize = buf.get(y).unwrap().size(); - if x as usize == linesize { - buf.insert(y, LineBuffer::new(vec!['\n' as u8])); - } - - let oldline = buf.get_mut(y).unwrap(); - let mut newline = Vec::new(); - newline.extend_from_slice(&oldline.data[x as usize..]); - - oldline.data.resize(x as usize, 0); - oldline.data.push('\n' as u8); - - buf.insert(y + 1, LineBuffer::new(newline)); - } - - pub fn add_line_flags(&self, line_index: usize, flags: LineState) { - let mut buf = self.buf.write().unwrap(); - - let line = buf.get_mut(line_index); - - if line.is_none() { - return; - } - - let line = line.unwrap(); - - line.flags.insert(flags); - - let mut flag_map = self.flag_lines.write().unwrap(); - if flags.contains(LineState::FLAGED) { - flag_map.insert(line.id, line_index); - } - - let mut locked_map = self.locked_lines.write().unwrap(); - if flags.contains(LineState::LOCKED) { - locked_map.insert(line.id, line_index); - } - } - - pub fn remove_line_flags(&self, line_index: usize, flags: LineState) { - let mut buf = self.buf.write().unwrap(); - - let line = buf.get_mut(line_index); - - if line.is_none() { - return; - } - - let line = line.unwrap(); - - line.flags.remove(flags); - - let mut flag_map = self.flag_lines.write().unwrap(); - if flags.contains(LineState::FLAGED) { - flag_map.remove(&line.id); - } - - let mut locked_map = self.locked_lines.write().unwrap(); - if flags.contains(LineState::LOCKED) { - locked_map.remove(&line.id); - } - } - - #[inline] - pub fn line_flags(&self, line: u16) -> LineState { - self.get_line(line).flags - } - - // 定位到指定行数,返回在正文窗口中的y坐标 - pub fn goto_line(&self, mut line_idx: usize) -> u16 { - let max_line = self.line_count(); - - if line_idx > max_line - 1 { - line_idx = max_line - 1 - } - - let size = *CONTENT_WINSIZE.read().unwrap(); - - // 先将其坐标定位在正文中央 - let win_rows = size.rows as usize; - let mut y = win_rows / 2; - - if line_idx < y { - self.set_offset(0); - return line_idx as u16; - } - - let mut offset = line_idx - y; - - if offset + win_rows > max_line { - // 最底下无数据,则调整 - let adapt_offset = max_line - win_rows; - - y += offset - adapt_offset; - offset = adapt_offset; - } - - self.set_offset(offset); - - y as u16 - } - - /// 删除行,不会删除锁定行,返回删除成功的行数 - pub fn delete_lines(&self, start: usize, mut end: usize) -> usize { - let max = self.line_count(); - if start >= max { - return 0; - } - - end = end.min(max); - let mut index = start; - let mut count = 0; - let mut buffer = self.buf.write().unwrap(); - - for _ in start..=end { - let line = buffer.get(index).unwrap(); - if line.flags.contains(LineState::LOCKED) { - index += 1; - } else { - buffer.remove(index); - count += 1; - } - } - - count - } - - pub fn delete_line(&self, y: usize) { - let mut buffer = self.buf.write().unwrap(); - let line = buffer.get(y); - if line.is_none() { - return; - } - let line = line.unwrap(); - if line.data.is_empty() { - return; - } - - if !line.flags.contains(LineState::LOCKED) { - buffer.remove(y); - } - } - - /// 删除 y 行 0..x 的字符 - pub fn delete_until_line_beg(&self, x: usize, y: usize) -> Option { - let mut buffer = self.buf.write().unwrap(); - let line = buffer.get_mut(y).unwrap(); - - let len = line.data.len(); - if len < 2 { - return None; - } - line.data.drain(0..x.min(len - 1)); - return Some(x - 1); - } - - /// 删除 y 行 x..end 的字符 - pub fn delete_until_endl(&self, x: usize, y: usize) -> Option { - let mut buffer = self.buf.write().unwrap(); - let line = buffer.get_mut(y).unwrap(); - let len = line.data.len(); - if len < 2 { - return None; - } - line.data.drain(x..len - 1); - return Some(x); - } - - /// 返回下一个单词的起始位置 - /// 如果为该行最后一单词,返回该行长度 - pub fn search_nextw_begin(&self, x: u16, y: u16) -> usize { - let mut left = x as usize; - let mut right = left; - let linesize = self.get_linesize(y) as usize; - let buf = self.buf.read().unwrap(); - let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) { - Some(line) => line, - None => return x as usize, - }; - - while left <= right && right < linesize { - let lchar = line[left] as char; - let rchar = line[right] as char; - if rchar.is_ascii_punctuation() && right != x as usize { - break; - } - if !(lchar == ' ' || lchar == '\t') { - left += 1; - right += 1; - continue; - } - if rchar != ' ' && rchar != '\t' { - break; - } - right += 1; - } - - return right; - } - - /// 搜索下一个单词的末尾 - /// 如果为该行最后一单词,返回该行长度 - pub fn search_nextw_end(&self, x: u16, y: u16) -> usize { - let mut left = x as usize; - let mut right = left; - let linesize = self.get_linesize(y) as usize; - let buf = self.buf.read().unwrap(); - let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) { - Some(line) => line, - None => return x as usize, - }; - - while left <= right && right < linesize { - let lchar = line[left] as char; - let rchar = line[right] as char; - if rchar.is_ascii_punctuation() && right != x as usize { - break; - } - if lchar == ' ' || lchar == '\t' { - left += 1; - right += 1; - continue; - } - if rchar == ' ' || rchar == '\t' { - if right == x as usize + 1 { - left = right; - continue; - } - right -= 1; - break; - } - right += 1; - } - - return right; - } - - /// 返回前一单词首字母位置,如果是当前行首单词,返回 None - pub fn search_prevw_begin(&self, x: u16, y: u16) -> Option { - let mut left = x as i32; - let mut right = left; - let buf = self.buf.read().unwrap(); - let line = match buf.get(self.offset.load(Ordering::SeqCst) + y as usize) { - Some(line) => line, - None => return Some(x as usize), - }; - while left <= right && left >= 0 { - let lchar = line[left as usize] as char; - let rchar = line[right as usize] as char; - - if lchar.is_ascii_punctuation() && left != x as i32 { - return Some(left as usize); - } - if rchar == ' ' || rchar == '\t' { - left -= 1; - right -= 1; - continue; - } - - if lchar == ' ' || lchar == '\t' { - if left + 1 == x as i32 { - right = left; - continue; - } - return Some(left as usize + 1); - } - - left -= 1; - } - return None; - } - pub fn search_prevw_begin_abs(&self, x: u16, abs_y: u16) -> usize { - let mut left = x as i32; - let mut right = left; - let buf = self.buf.read().unwrap(); - let line = buf.get(abs_y as usize).unwrap(); - while left <= right && left >= 0 { - let lchar = line[left as usize] as char; - let rchar = line[right as usize] as char; - - if lchar.is_ascii_punctuation() && left != x as i32 { - return left as usize; - } - if rchar == ' ' || rchar == '\t' { - left -= 1; - right -= 1; - continue; - } - - if lchar == ' ' || lchar == '\t' { - if left + 1 == x as i32 { - right = left; - continue; - } - return left as usize + 1; - } - - left -= 1; - } - return 0; - } -} - -bitflags! { - #[derive(Debug, Default, Clone,Copy)] - pub struct LineState: u32 { - /// 该行被标记 - const FLAGED = 1 << 1; - /// 锁定该行不能被更改 - const LOCKED = 1 << 2; - } -} - -impl LineState { - pub fn set_style(&self) -> io::Result<()> { - if self.contains(Self::FLAGED) { - StyleManager::set_background_color(Color::Cyan)?; - } - - if self.contains(Self::LOCKED) { - StyleManager::set_background_color(Color::DarkRed)?; - } - - Ok(()) - } -} diff --git a/src/utils/cursor.rs b/src/utils/cursor.rs deleted file mode 100644 index 7fdf777..0000000 --- a/src/utils/cursor.rs +++ /dev/null @@ -1,495 +0,0 @@ -use std::{ - fmt::Display, - io::{self, stdout, Write}, - sync::Arc, -}; - -use crossterm::{ - cursor::{ - Hide, MoveDown, MoveLeft, MoveRight, MoveTo, MoveToColumn, MoveToNextLine, - MoveToPreviousLine, MoveToRow, MoveUp, RestorePosition, SavePosition, Show, - }, - ExecutableCommand, -}; - -use crate::config::appconfig::LineSetting; - -use super::{ - buffer::{EditBuffer, LineBuffer}, - style::StyleManager, - term_io::TermIO, - terminal::TermManager, - ui::uicore::{CONTENT_WINSIZE, DEF_STYLE, WINSIZE}, -}; - -struct CursorManager; - -#[allow(dead_code)] -impl CursorManager { - #[inline] - pub fn move_to(x: u16, y: u16) -> io::Result<()> { - stdout().execute(MoveTo(x, y)).unwrap().flush() - } - - #[inline] - pub fn move_to_nextline(lines: u16) -> io::Result<()> { - stdout().execute(MoveToNextLine(lines)).unwrap().flush() - } - - #[inline] - pub fn move_to_previous_line(lines: u16) -> io::Result<()> { - stdout().execute(MoveToPreviousLine(lines)).unwrap().flush() - } - - #[inline] - pub fn move_to_columu(col: u16) -> io::Result<()> { - stdout().execute(MoveToColumn(col)).unwrap().flush() - } - - #[inline] - pub fn move_to_row(row: u16) -> io::Result<()> { - stdout().execute(MoveToRow(row)).unwrap().flush() - } - - #[inline] - pub fn move_up(count: u16) -> io::Result<()> { - stdout().execute(MoveUp(count)).unwrap().flush() - } - - #[inline] - pub fn move_down(count: u16) -> io::Result<()> { - stdout().execute(MoveDown(count)).unwrap().flush() - } - - #[inline] - pub fn move_left(count: u16) -> io::Result<()> { - stdout().execute(MoveLeft(count)).unwrap().flush() - } - - #[inline] - pub fn move_right(count: u16) -> io::Result<()> { - stdout().execute(MoveRight(count)).unwrap().flush() - } - - #[inline] - pub fn save_position() -> io::Result<()> { - stdout().execute(SavePosition).unwrap().flush() - } - - #[inline] - pub fn restore_position() -> io::Result<()> { - stdout().execute(RestorePosition).unwrap().flush() - } - - #[inline] - pub fn hide() -> io::Result<()> { - stdout().execute(Hide).unwrap().flush() - } - - #[inline] - pub fn show() -> io::Result<()> { - stdout().execute(Show).unwrap().flush() - } -} - -#[derive(Debug)] -pub struct CursorCrtl { - x: u16, - y: u16, - - // 用于处理状态位置 - stored_x: u16, - stored_y: u16, - - line_prefix_width: u16, - store_flag: bool, - - // 正文模式会输出前缀,这个标志表示是否需要以正文前缀模式调整坐标 - prefix_mode: bool, - - line_setting: LineSetting, - - buf: Arc, -} - -#[allow(dead_code)] -impl CursorCrtl { - pub const PREFIX_COL: u16 = 1; - pub fn new(buf: Arc, line_setting: LineSetting) -> Self { - Self { - x: 0, - y: 0, - stored_x: 0, - stored_y: 0, - store_flag: false, - line_prefix_width: Self::PREFIX_COL, - prefix_mode: true, - line_setting, - buf, - } - } - - pub fn x(&self) -> u16 { - if self.prefix_mode { - if self.x < self.line_prefix_width { - return 0; - } - self.x - self.line_prefix_width - } else { - self.x - } - } - - pub fn y(&self) -> u16 { - self.y - } - - pub fn cmd_y(&self) -> u16 { - if self.store_flag { - self.stored_y - } else { - self.y - } - } - - #[inline] - pub fn set_prefix_mode(&mut self, on: bool) { - self.prefix_mode = on; - if on && self.x < self.line_prefix_width { - self.x = self.line_prefix_width; - self.move_to_columu(0).unwrap(); - } - } - - pub fn move_to(&mut self, mut x: u16, y: u16) -> io::Result<()> { - if self.prefix_mode { - x += self.line_prefix_width; - } - let size = *WINSIZE.read().unwrap(); - CursorManager::move_to(x, y)?; - self.x = (size.cols - 1).min(x); - self.y = (size.rows - 1).min(y); - Ok(()) - } - - pub fn move_to_nextline(&mut self, mut lines: u16) -> io::Result<()> { - let size = *WINSIZE.read().unwrap(); - if self.y + lines >= size.rows { - // 向上滚动 - // 保存位置 - 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)?; - if self.prefix_mode { - self.x = self.line_prefix_width; - self.move_to_columu(0)?; - } else { - self.x = 0; - } - - self.y += lines; - Ok(()) - } - - 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(); - // 计算需要滚动的行数 - 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)?; - - self.y -= lines; - if self.prefix_mode { - self.x = self.line_prefix_width; - self.move_to_columu(0)?; - } else { - self.x = 0; - } - Ok(()) - } - - pub fn move_to_columu(&mut self, mut col: u16) -> io::Result<()> { - if self.prefix_mode { - col += self.line_prefix_width; - } - let size = *WINSIZE.read().unwrap(); - CursorManager::move_to_columu(col)?; - self.x = (size.cols - 1).min(col); - Ok(()) - } - - pub fn move_to_row(&mut self, row: u16) -> io::Result<()> { - let size = *WINSIZE.read().unwrap(); - CursorManager::move_to_row(row)?; - self.y = (size.rows - 1).min(row); - Ok(()) - } - - pub fn move_up(&mut self, count: u16) -> io::Result<()> { - CursorManager::move_up(count)?; - self.y -= count; - - Ok(()) - } - - pub fn move_down(&mut self, count: u16) -> io::Result<()> { - CursorManager::move_down(count)?; - - self.y += count; - Ok(()) - } - - pub fn move_left(&mut self, count: u16) -> io::Result<()> { - // 如果当前光标位置小于或等于行前缀宽度,或者移动的距离大于当前光标位置,则直接移动到行前缀末尾 - 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 - }; - - // 执行光标左移操作 - CursorManager::move_left(actual_move)?; - - // 更新光标位置 - self.x -= actual_move; - - Ok(()) - } - - pub fn move_right(&mut self, count: u16) -> io::Result<()> { - let mut linesize = self.buf.get_linesize(self.y()) - 1; - let mut size = *WINSIZE.read().unwrap(); - if self.prefix_mode { - size.cols -= self.line_prefix_width; - linesize += self.line_prefix_width; - } - if self.x == size.cols - 1 { - return Ok(()); - } - - if self.x + count > linesize { - CursorManager::move_to_columu(linesize)?; - self.x = linesize; - } else { - CursorManager::move_right(count)?; - self.x += count; - } - - Ok(()) - } - - pub fn write(&mut self, str: D) -> io::Result<()> { - let str = str.to_string(); - - let ss = str.split_terminator(|x| x == '\n').collect::>(); - for s in ss { - self.write_line(s)?; - } - Ok(()) - } - - fn write_line(&mut self, str: &str) -> io::Result<()> { - let len = str.len() as u16; - - let mut size = *WINSIZE.read().unwrap(); - - if self.prefix_mode { - size.cols -= self.line_prefix_width; - } - - if self.x + len > size.cols { - let ss = str.split_at((size.cols - self.x) as usize); - TermIO::write_str(ss.0)?; - self.move_to_nextline(1)?; - self.write_line(ss.1)?; - } else { - TermIO::write_str(str)?; - if str.ends_with(|x| x == '\n') { - self.move_to_nextline(1)?; - } else { - self.x += str.len() as u16; - } - } - - Ok(()) - } - - pub fn write_with_pos( - &mut self, - str: D, - x: u16, - y: u16, - stroe: bool, - ) -> io::Result<()> { - let mut pos = (0, 0); - if stroe { - pos = self.store_tmp_pos(); - } - self.move_to(x, y)?; - self.write(str)?; - if stroe { - self.restore_tmp_pos(pos)?; - } - Ok(()) - } - - pub fn store_pos(&mut self) { - if self.store_flag { - panic!("Stored val doesn't restore") - } - self.stored_x = self.x; - self.stored_y = self.y; - self.store_flag = true; - } - - pub fn restore_pos(&mut self) -> io::Result<()> { - if !self.store_flag { - panic!("No val stored") - } - self.x = self.stored_x; - self.y = self.stored_y; - self.store_flag = false; - CursorManager::move_to(self.stored_x, self.stored_y) - } - - #[inline] - pub fn store_tmp_pos(&mut self) -> (u16, u16) { - (self.x(), self.y()) - } - - pub fn restore_tmp_pos(&mut self, pos: (u16, u16)) -> io::Result<()> { - self.move_to(pos.0, pos.1) - } - - /// 更新前缀列 - pub fn update_line_prefix( - &mut self, - content: &Vec, - start: u16, - number_len: usize, - ) -> io::Result<()> { - let startline = self.buf.offset() + 1; - let size = *CONTENT_WINSIZE.read().unwrap(); - let max_line = startline + size.rows as usize; - - // 先关闭prefix模式 - self.set_prefix_mode(false); - - // 绝对坐标 - let (x, y) = (self.x(), self.y()); - - // 更新第一列flags - for (num, line) in content.iter().enumerate() { - // 设置颜色 - StyleManager::set_background_color(self.line_setting.line_num.background)?; - StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?; - self.move_to(0, start + num as u16)?; - let flags = line.flags; - flags.set_style()?; - self.write("~")?; - StyleManager::reset_color()?; - } - - // 更新页面行号 - if self.line_setting.line_num.enable { - let len = number_len + 2; - self.line_prefix_width = len as u16 + Self::PREFIX_COL; - - // 设置颜色 - StyleManager::set_background_color(self.line_setting.line_num.background)?; - StyleManager::set_foreground_color(self.line_setting.line_num.frontground)?; - for line in startline..max_line { - self.move_to(Self::PREFIX_COL, (line - startline) as u16)?; - let mut prefix = line.to_string(); - - prefix.insert(0, ' '); - unsafe { - let data = prefix.as_mut_vec(); - data.resize(len, ' ' as u8); - }; - - self.write(prefix)?; - } - StyleManager::reset_color()?; - } - // 恢复绝对坐标 - self.move_to(x, y)?; - - self.set_prefix_mode(true); - - Ok(()) - } - - pub fn clear_current_line(&mut self) -> io::Result<()> { - if self.prefix_mode { - let tmp = self.x(); - self.move_to_columu(0)?; - TermManager::clear_until_new_line()?; - self.move_to_columu(tmp) - } else { - TermManager::clear_current_line() - } - } - - pub fn highlight(&mut self, last_line: Option) -> io::Result<()> { - if !self.line_setting.highlight.enable { - return Ok(()); - } - DEF_STYLE.read().unwrap().set_content_style()?; - - if last_line.is_some() { - let last_line = last_line.unwrap(); - // 清除上一行高光 - let pos = self.store_tmp_pos(); - self.move_to(0, last_line)?; - self.clear_current_line()?; - self.write(String::from_utf8_lossy(&self.buf.get_line(last_line)))?; - self.restore_tmp_pos(pos)?; - } - - let pos = self.store_tmp_pos(); - // 设置高光 - StyleManager::set_background_color(self.line_setting.highlight.color)?; - self.clear_current_line()?; - self.move_to_columu(0)?; - self.write(String::from_utf8_lossy(&self.buf.get_line(self.y())))?; - self.restore_tmp_pos(pos)?; - - Ok(()) - } -} diff --git a/src/utils/file.rs b/src/utils/file.rs deleted file mode 100644 index 129c698..0000000 --- a/src/utils/file.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::{ - fs::{self, File}, - io::{self, Read, Seek, Write}, -}; - -use super::buffer::EditBuffer; - -use std::path::PathBuf; - -pub const BAK_SUFFIX: &'static str = ".heldbak"; - -pub struct FileManager { - name: String, - file: File, - 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(); - - let file = File::options() - .write(true) - .read(true) - .create(true) - .open(file_path.clone())?; - - Ok(Self { - file, - is_first_open: ifo_flag, - name: file_path, - bak: None, - }) - } - - pub fn init(&mut self, bak: bool) -> io::Result { - let mut buf = Vec::new(); - // 是否备份 - if bak { - self.do_bak(&mut buf)?; - } else { - self.file.read_to_end(&mut buf)?; - } - - Ok(EditBuffer::new(buf)) - } - - // 备份 - fn do_bak(&mut self, buf: &mut Vec) -> io::Result<()> { - let mut bak = File::options() - .write(true) - .read(true) - .create(true) - .open(format!("{}{}", self.name, BAK_SUFFIX))?; - - bak.set_len(0)?; - - self.file.read_to_end(buf)?; - bak.write_all(&buf)?; - - self.file.seek(io::SeekFrom::Start(0))?; - - if self.bak.is_some() { - error!("The backup already exists. The operation may cause data loss."); - } - - self.bak = Some(bak); - - Ok(()) - } - - pub fn store(&mut self, buf: &EditBuffer) -> io::Result<()> { - let data = buf.all_buffer(); - - self.file.set_len(0)?; - - for (idx, line) in data.iter().enumerate() { - if idx == data.len() - 1 { - self.file.write(&line[..line.len()])?; - } else { - self.file.write(&line)?; - } - } - - if self.bak.is_some() { - fs::remove_file(format!("{}{}", self.name, BAK_SUFFIX))?; - } - self.is_first_open = false; - - Ok(()) - } - - pub fn is_first_open(&mut self) -> bool { - self.is_first_open - } - - pub fn delete_files(&mut self) -> io::Result<()> { - if !self.name.is_empty() { - fs::remove_file(self.name.clone())?; - } - - if self.bak.is_some() { - fs::remove_file(format!("{}{}", self.name, BAK_SUFFIX))?; - } - 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/input.rs b/src/utils/input.rs deleted file mode 100644 index 9106c74..0000000 --- a/src/utils/input.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io::{self, Read}; - -pub struct Input; - -impl Input { - pub fn wait_keydown() -> io::Result { - let buf: &mut [u8] = &mut [0; 8]; - let count = io::stdin().read(buf)?; - Ok(KeyCodeParser::parse(&buf[0..count])) - } -} - -struct KeyCodeParser; - -impl KeyCodeParser { - pub fn parse(bytes: &[u8]) -> KeyEventType { - if bytes[0] == 224 { - // 控制字符 - return Self::parse_ctrl(&bytes[1..]); - } - match bytes { - // Enter key - b"\n" => KeyEventType::Enter, - // Tab key - b"\t" => KeyEventType::Tab, - // Esc - [0] => KeyEventType::Esc, - - [8] => KeyEventType::Backspace, - - // ASCII 字符 - [byte] if *byte >= 32 && *byte <= 126 => KeyEventType::Common(bytes[0]), - // Unknown bytes - bytes => { - error!("unknown bytes {bytes:?}"); - KeyEventType::Unknown(bytes.to_vec()) - } - } - } - - fn parse_ctrl(bytes: &[u8]) -> KeyEventType { - match bytes { - [72] => KeyEventType::Up, - [80] => KeyEventType::Down, - [75] => KeyEventType::Left, - [77] => KeyEventType::Right, - bytes => { - error!("unknown ctrl bytes {bytes:?}"); - KeyEventType::Unknown(bytes.to_vec()) - } - } - } -} - -#[derive(Debug, Clone)] -pub enum KeyEventType { - Common(u8), - - Up, - Down, - Right, - Left, - - Enter, - Tab, - Backspace, - - Esc, - - Unknown(Vec), -} diff --git a/src/utils/log_util.rs b/src/utils/log_util.rs deleted file mode 100644 index fc6b3f6..0000000 --- a/src/utils/log_util.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::{fs::File, io}; - -use log::LevelFilter; -use simplelog::{CombinedLogger, WriteLogger}; - -pub struct Log; - -impl Log { - pub fn init(level: LevelFilter) -> io::Result<()> { - CombinedLogger::init(vec![ - // TermLogger::new( - // level.to_simplelog_filter(), - // simplelog::Config::default(), - // simplelog::TerminalMode::default(), - // simplelog::ColorChoice::Auto, - // ), - WriteLogger::new( - level, - simplelog::Config::default(), - File::create("held.log")?, - ), - ]) - .unwrap(); - - Ok(()) - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs deleted file mode 100644 index 2427952..0000000 --- a/src/utils/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod buffer; -pub mod cursor; -pub mod file; -/// 暂时写在这适配DragonOS -#[cfg(feature = "dragonos")] -pub mod input; -pub mod log_util; -pub mod style; -pub mod term_io; -pub mod terminal; -pub mod ui; diff --git a/src/utils/style.rs b/src/utils/style.rs deleted file mode 100644 index ac768bd..0000000 --- a/src/utils/style.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::io::{self, stdout, Write}; - -use crossterm::{style::*, ExecutableCommand}; - -pub struct StyleManager; - -#[allow(dead_code)] -impl StyleManager { - #[inline] - pub fn set_foreground_color(color: Color) -> io::Result<()> { - stdout().execute(SetForegroundColor(color)).unwrap().flush() - } - - #[inline] - pub fn set_background_color(color: Color) -> io::Result<()> { - stdout().execute(SetBackgroundColor(color)).unwrap().flush() - } - - #[inline] - pub fn set_underline_color(color: Color) -> io::Result<()> { - stdout().execute(SetUnderlineColor(color)).unwrap().flush() - } - - #[inline] - pub fn set_color(fg: Option, bg: Option) -> io::Result<()> { - stdout() - .execute(SetColors(Colors { - foreground: fg, - background: bg, - })) - .unwrap() - .flush() - } - - #[inline] - pub fn set_attr(attr: Attribute) -> io::Result<()> { - stdout().execute(SetAttribute(attr)).unwrap().flush() - } - - #[inline] - pub fn set_attrs(attr: Attributes) -> io::Result<()> { - stdout().execute(SetAttributes(attr)).unwrap().flush() - } - - #[inline] - pub fn set_style(style: ContentStyle) -> io::Result<()> { - stdout().execute(SetStyle(style)).unwrap().flush() - } - - #[inline] - pub fn reset_color() -> io::Result<()> { - stdout().execute(ResetColor).unwrap().flush() - } -} diff --git a/src/utils/term_io.rs b/src/utils/term_io.rs deleted file mode 100644 index 8890959..0000000 --- a/src/utils/term_io.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::{ - fmt::Display, - io::{self, stdout, Write}, -}; - -use crossterm::{style::Print, ExecutableCommand}; - -pub struct TermIO; - -impl TermIO { - pub fn write_str(str: D) -> io::Result<()> { - stdout().execute(Print(str)).unwrap().flush()?; - Ok(()) - } -} diff --git a/src/utils/terminal.rs b/src/utils/terminal.rs deleted file mode 100644 index ec3c194..0000000 --- a/src/utils/terminal.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::io::{self, stdout, Write}; - -use crossterm::{terminal::*, ExecutableCommand}; - -use super::ui::uicore::DEF_STYLE; - -pub struct TermManager; - -#[allow(dead_code)] -impl TermManager { - pub fn init_term() -> io::Result<()> { - DEF_STYLE.read().unwrap().set_content_style()?; - Self::clear_all() - } - - #[inline] - pub fn disable_line_warp() -> io::Result<()> { - stdout().execute(DisableLineWrap).unwrap().flush() - } - - #[inline] - pub fn enable_line_warp() -> io::Result<()> { - stdout().execute(EnableLineWrap).unwrap().flush() - } - - #[inline] - pub fn leave_alternate_screen() -> io::Result<()> { - stdout().execute(LeaveAlternateScreen).unwrap().flush() - } - - #[inline] - pub fn enter_alternate_screen() -> io::Result<()> { - stdout().execute(EnterAlternateScreen).unwrap().flush() - } - - #[inline] - pub fn scroll_up(lines: u16) -> io::Result<()> { - stdout().execute(ScrollUp(lines)).unwrap().flush() - } - - #[inline] - pub fn scroll_down(lines: u16) -> io::Result<()> { - stdout().execute(ScrollDown(lines)).unwrap().flush() - } - - #[inline] - pub fn clear_all() -> io::Result<()> { - stdout().execute(Clear(ClearType::All)).unwrap().flush() - } - - #[inline] - pub fn clear_purge() -> io::Result<()> { - stdout().execute(Clear(ClearType::Purge)).unwrap().flush() - } - - #[inline] - pub fn clear_under_cursor() -> io::Result<()> { - stdout() - .execute(Clear(ClearType::FromCursorDown)) - .unwrap() - .flush() - } - - #[inline] - pub fn clear_up_cursor() -> io::Result<()> { - stdout() - .execute(Clear(ClearType::FromCursorUp)) - .unwrap() - .flush() - } - - #[inline] - pub fn clear_current_line() -> io::Result<()> { - stdout() - .execute(Clear(ClearType::CurrentLine)) - .unwrap() - .flush() - } - - #[inline] - pub fn clear_until_new_line() -> io::Result<()> { - stdout() - .execute(Clear(ClearType::UntilNewLine)) - .unwrap() - .flush() - } -} diff --git a/src/utils/ui/event.rs b/src/utils/ui/event.rs deleted file mode 100644 index 6fad963..0000000 --- a/src/utils/ui/event.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::{io, sync::MutexGuard}; - -use crate::utils::{buffer::LineState, cursor::CursorCrtl, style::StyleManager}; - -use super::{ - mode::mode::ModeType, - uicore::{UiCore, APP_INTERNAL_INFOMATION, CONTENT_WINSIZE, DEF_STYLE, UI_CMD_HEIGHT}, -}; - -pub const TAB_STR: &'static str = " "; - -pub trait KeyEventCallback { - fn enter(&self, ui: &mut MutexGuard) -> io::Result; - fn tab(&self, ui: &mut MutexGuard) -> io::Result; - fn backspace(&self, ui: &mut MutexGuard) -> io::Result { - if ui.cursor.x() == 0 { - let y = ui.cursor.y(); - let (merged, linelen) = ui.buffer.merge_line(y); - if merged { - // 需要向上翻页 - if ui.cursor.y() == 0 { - ui.scroll_down(1)?; - ui.cursor.move_to_nextline(1)?; - } - // 重新渲染 - ui.cursor.move_up(1)?; - - let y = ui.cursor.y(); - let ret = - ui.render_content(y, (CONTENT_WINSIZE.read().unwrap().rows - y + 1) as usize)?; - - // 清除之前显示行 - // 计算需要clear的行号 - let clear_y = if ui.cursor.y() == 0 { y + 1 } else { y }; - let row = clear_y + ret as u16; - - ui.cursor.move_to_row(row)?; - - DEF_STYLE.read().unwrap().set_content_style()?; - - ui.cursor.set_prefix_mode(false); - StyleManager::reset_color()?; - ui.cursor.move_to_columu(0)?; - ui.cursor - .write(&TAB_STR[..CursorCrtl::PREFIX_COL as usize])?; - ui.cursor.set_prefix_mode(true); - - ui.cursor.clear_current_line()?; - - ui.cursor.move_to_row(y)?; - ui.cursor.move_to_columu(linelen as u16)?; - ui.cursor.highlight(Some(clear_y))?; - ui.set_edited(); - return Ok(WarpUiCallBackType::None); - } else { - return Ok(WarpUiCallBackType::None); - } - } - - let y = ui.cursor.y(); - let x = ui.cursor.x(); - - let line = ui.buffer.get_line(y); - if line.flags.contains(LineState::LOCKED) { - APP_INTERNAL_INFOMATION.lock().unwrap().info = "Row is locked".to_string(); - return Ok(WarpUiCallBackType::None); - } - self.left(ui)?; - - ui.buffer.remove_char(x - 1, y); - - let line = ui.buffer.get_line(y); - - ui.cursor.write(format!( - "{} ", - String::from_utf8_lossy(&line.data[x as usize..]) - ))?; - - ui.cursor.highlight(None)?; - - ui.cursor.move_to_columu(x - 1)?; - - Ok(WarpUiCallBackType::None) - } - fn up(&self, ui: &mut MutexGuard) -> io::Result { - if ui.cursor.y() == 0 { - if ui.buffer.offset() == 0 { - // 上面没有数据 - return Ok(WarpUiCallBackType::None); - } - // 向上滚动 - ui.scroll_down(1)?; - - let linesize = ui.buffer.get_linesize(ui.cursor.y()); - - // 考虑\n - if linesize - 1 < ui.cursor.x() { - ui.cursor.move_to_columu(linesize - 1)?; - } - return Ok(WarpUiCallBackType::None); - } - let linesize = ui.buffer.get_linesize(ui.cursor.y() - 1); - - if linesize == 0 { - return Ok(WarpUiCallBackType::None); - } - - ui.cursor.move_up(1)?; - - // 考虑\n - if linesize - 1 < ui.cursor.x() { - ui.cursor.move_to_columu(linesize - 1)?; - } - - let last_y = ui.cursor.y() + 1; - ui.cursor.highlight(Some(last_y))?; - - Ok(WarpUiCallBackType::None) - } - fn down(&self, ui: &mut MutexGuard) -> io::Result { - let size = *CONTENT_WINSIZE.read().unwrap(); - let mut linesize = ui.buffer.get_linesize(ui.cursor.y() + 1); - - if linesize == 0 { - return Ok(WarpUiCallBackType::None); - } - - if ui.cursor.y() == size.rows - UI_CMD_HEIGHT { - // 向shang滚动 - ui.scroll_up(1)?; - if linesize < ui.cursor.x() { - ui.cursor.move_to_columu(linesize - 1)?; - } - return Ok(WarpUiCallBackType::None); - } - - // \n - linesize -= 1; - - ui.cursor.move_down(1)?; - - if linesize < ui.cursor.x() { - ui.cursor.move_to_columu(linesize)?; - } - let last_y = ui.cursor.y() - 1; - ui.cursor.highlight(Some(last_y))?; - - Ok(WarpUiCallBackType::None) - } - fn left(&self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_left(1)?; - Ok(WarpUiCallBackType::None) - } - fn right(&self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_right(1)?; - Ok(WarpUiCallBackType::None) - } - fn esc(&self, ui: &mut MutexGuard) -> io::Result; - fn input_data( - &self, - ui: &mut MutexGuard, - data: &[u8], - ) -> io::Result; -} - -#[derive(Debug, PartialEq)] -pub enum WarpUiCallBackType { - ChangMode(ModeType), - Exit(bool), - None, -} diff --git a/src/utils/ui/mod.rs b/src/utils/ui/mod.rs deleted file mode 100644 index ebd1132..0000000 --- a/src/utils/ui/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::io; - -use crossterm::style::Color; - -use super::style::StyleManager; - -pub mod event; -pub mod mode; -pub mod uicore; - -#[derive(Debug)] -pub struct AppInternalInfomation { - pub level: InfoLevel, - pub info: String, -} - -impl AppInternalInfomation { - pub fn reset(&mut self) { - self.level = InfoLevel::Info; - self.info = String::new(); - } -} - -#[allow(dead_code)] -#[derive(Debug)] -pub enum InfoLevel { - Info, - Warn, - Error, -} - -impl InfoLevel { - pub fn set_style(&self) -> io::Result<()> { - match self { - InfoLevel::Info => {} - InfoLevel::Warn => { - StyleManager::set_background_color(Color::DarkYellow)?; - } - InfoLevel::Error => { - StyleManager::set_background_color(Color::DarkRed)?; - } - } - - Ok(()) - } -} diff --git a/src/utils/ui/mode/common.rs b/src/utils/ui/mode/common.rs deleted file mode 100644 index d0fa72c..0000000 --- a/src/utils/ui/mode/common.rs +++ /dev/null @@ -1,150 +0,0 @@ -use std::{io, sync::MutexGuard}; - -use crate::utils::{ - terminal::TermManager, - ui::{ - event::KeyEventCallback, - uicore::{UiCore, CONTENT_WINSIZE}, - }, -}; - -pub trait CommonOp: KeyEventCallback { - /// 删除一行 - fn remove_line(&self, ui: &mut MutexGuard) -> io::Result<()> { - TermManager::clear_current_line()?; - TermManager::clear_under_cursor()?; - let y = ui.cursor.y() as usize; - let old_line_count = ui.buffer.line_count(); - let old_offset = ui.buffer.offset(); - - let count = old_line_count - y as usize; - ui.buffer.delete_line(y + ui.buffer.offset() as usize); - ui.render_content(y as u16, count.max(1))?; - - if y + old_offset == old_line_count - 1 { - self.up(ui)?; - } - - if old_line_count == 1 { - ui.cursor.move_to_columu(0)?; - ui.buffer.insert_char('\n' as u8, 0, 0); - ui.render_content(0, 1)?; - } - - Ok(()) - } - - /// 删除数行 - fn remove_n_line(&self, ui: &mut MutexGuard, n: u16) -> io::Result<()> { - let linecount = ui.buffer.line_count() as u16; - let y = ui.cursor.y(); - - // 实际能删除的行数 - let to_delete = n.min(linecount - y); - for _ in 0..to_delete { - self.remove_line(ui)?; - } - Ok(()) - } - /// 删除一个单词 - fn remove_word(&self, ui: &mut MutexGuard) -> io::Result<()> { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - let next_word_pos = ui.buffer.search_nextw_begin(x, y); - let linesize = ui.buffer.get_linesize(y); - - // 如果下一个单词在当前行,则删除当前单词 - if next_word_pos < linesize.into() { - ui.buffer.remove_str(x, y, next_word_pos - x as usize); - } else { - // 如果下一个单词在下一行,则删除当前行剩余部分 - self.left(ui)?; - ui.buffer.delete_line(y.into()); - self.down(ui)?; - } - ui.render_content(y, 1)?; - return Ok(()); - } - /// 移动到指定行 - fn move_to_line(&self, ui: &mut MutexGuard, line: u16) -> io::Result<()> { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - let new_y = ui.buffer.goto_line(line as usize); - let new_x = x.min(ui.buffer.get_linesize(new_y)) as u16; - ui.cursor.move_to(new_x, new_y)?; - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.highlight(Some(y))?; - return Ok(()); - } - - /// 定位到上一个单词的首字母,返回绝对坐标 - fn locate_prevw_begin(&self, ui: &mut MutexGuard, x: u16, abs_y: u16) -> (u16, u16) { - // 如果光标已在行首,则尝试移动到上一行的单词首字母 - if x == 0 { - if abs_y == 0 { - return (0, 0); - } - let last_y = abs_y - 1; - let end_of_prev_line = ui.buffer.get_linesize_abs(last_y) - 1; - let prev_word_pos = ui.buffer.search_prevw_begin_abs(end_of_prev_line, last_y); - return (prev_word_pos as u16, last_y); - } - - let prev_word_pos = ui.buffer.search_prevw_begin_abs(x, abs_y); - - return (prev_word_pos as u16, abs_y); - } - - /// 定位到下一个单词的末尾,返回绝对坐标 - fn locate_nextw_ending(&self, ui: &mut MutexGuard, x: u16, abs_y: u16) -> (u16, u16) { - let linesize = ui.buffer.get_linesize_abs(abs_y) as usize; - - // 如果光标已经在当前行的末尾或最后一个字符(x + 2),则尝试移动到下一行的末尾或单词末尾 - if x as usize + 2 >= linesize { - if abs_y < ui.buffer.line_count() as u16 - 1 { - let offset = ui.buffer.offset() as u16; - let next_end_pos = ui.buffer.search_nextw_end(0, abs_y + 1 - offset) as u16; - return (next_end_pos, abs_y + 1); - } else { - // 如果已经是最后一行,则保持光标在当前行的末尾 - let x = if linesize > 0 { linesize - 1 } else { 0 }; - return (x as u16, abs_y); - } - } - - let offset = ui.buffer.offset() as u16; - let next_end_pos = ui.buffer.search_nextw_end(x, abs_y - offset) as u16; - // 如果下一个单词的末尾在当前行,则移动光标到该单词的末尾 - return (next_end_pos.min(linesize as u16 - 1), abs_y); - } - - /// 定位到下一个单词的首字母,返回绝对坐标 - fn locate_next_word(&self, ui: &mut MutexGuard, abs_pos: (u16, u16)) -> (u16, u16) { - let linesize = ui.buffer.get_linesize_abs(abs_pos.1) as usize; - if abs_pos.0 as usize + 2 >= linesize { - if abs_pos.1 < ui.buffer.line_count() as u16 - 1 { - let offset = ui.buffer.offset() as u16; - let next_end_pos = ui.buffer.search_nextw_begin(0, abs_pos.1 + 1 - offset) as u16; - return (next_end_pos, abs_pos.1 + 1); - } else { - let x = if linesize > 0 { linesize - 1 } else { 0 }; - return (x as u16, abs_pos.1); - } - } - let offset = ui.buffer.offset() as u16; - let next_end_pos = ui.buffer.search_nextw_begin(abs_pos.0, abs_pos.1 - offset) as u16; - return (next_end_pos.min(linesize as u16 - 1), abs_pos.1); - } - fn move_to_nlines_of_screen(&self, ui: &mut MutexGuard, n: usize) -> io::Result<()> { - let y = ui.cursor.y() as usize; - - let offset = ui.buffer.offset(); - - let new_y = ui.buffer.goto_line(offset + n); - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.move_to_row(new_y)?; - ui.cursor.highlight(Some(y as u16))?; - - Ok(()) - } -} diff --git a/src/utils/ui/mode/mod.rs b/src/utils/ui/mode/mod.rs deleted file mode 100644 index 42da31a..0000000 --- a/src/utils/ui/mode/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod common; -pub mod mode; -pub mod normal; -pub mod state; diff --git a/src/utils/ui/mode/mode.rs b/src/utils/ui/mode/mode.rs deleted file mode 100644 index a83bd7f..0000000 --- a/src/utils/ui/mode/mode.rs +++ /dev/null @@ -1,778 +0,0 @@ -use std::io::Read; -use std::sync::atomic::Ordering; -use std::sync::{Mutex, MutexGuard}; -use std::{fmt::Debug, io}; - -use crate::config::lastline_cmd::LastLineCommand; -use crate::utils::buffer::LineState; -#[cfg(feature = "dragonos")] -use crate::utils::input::KeyEventType; - -use crate::utils::terminal::TermManager; - -use crate::utils::ui::uicore::{UiCore, APP_INTERNAL_INFOMATION, TAB_SIZE}; -use crate::utils::ui::{ - event::KeyEventCallback, - uicore::{CONTENT_WINSIZE, DEF_STYLE}, -}; - -use crate::utils::ui::event::WarpUiCallBackType; - -use super::normal::Normal; - -pub trait InputMode: KeyEventCallback + Debug { - fn mode_type(&self) -> ModeType; - - #[cfg(not(feature = "dragonos"))] - fn event_route( - &self, - ui: &mut MutexGuard, - event: crossterm::event::Event, - ) -> io::Result { - match event { - crossterm::event::Event::FocusGained => todo!(), - crossterm::event::Event::FocusLost => todo!(), - crossterm::event::Event::Key(key) => self.key_event_route(ui, key), - crossterm::event::Event::Mouse(_) => todo!(), - crossterm::event::Event::Paste(_) => todo!(), - crossterm::event::Event::Resize(_, _) => todo!(), - } - } - - #[cfg(not(feature = "dragonos"))] - fn key_event_route( - &self, - ui: &mut MutexGuard, - keyev: crossterm::event::KeyEvent, - ) -> io::Result { - let callback = match keyev.code { - crossterm::event::KeyCode::Backspace => self.backspace(ui)?, - crossterm::event::KeyCode::Enter => self.enter(ui)?, - crossterm::event::KeyCode::Left => self.left(ui)?, - crossterm::event::KeyCode::Right => self.right(ui)?, - crossterm::event::KeyCode::Up => self.up(ui)?, - crossterm::event::KeyCode::Down => self.down(ui)?, - crossterm::event::KeyCode::Home => todo!(), - crossterm::event::KeyCode::End => todo!(), - crossterm::event::KeyCode::PageUp => todo!(), - crossterm::event::KeyCode::PageDown => todo!(), - crossterm::event::KeyCode::Tab => self.tab(ui)?, - crossterm::event::KeyCode::BackTab => todo!(), - crossterm::event::KeyCode::Delete => todo!(), - crossterm::event::KeyCode::Insert => todo!(), - crossterm::event::KeyCode::F(_) => todo!(), - crossterm::event::KeyCode::Char(c) => self.input_data(ui, &[c as u8])?, - crossterm::event::KeyCode::Null => todo!(), - crossterm::event::KeyCode::Esc => self.esc(ui)?, - crossterm::event::KeyCode::CapsLock => todo!(), - crossterm::event::KeyCode::ScrollLock => todo!(), - crossterm::event::KeyCode::NumLock => todo!(), - crossterm::event::KeyCode::PrintScreen => todo!(), - crossterm::event::KeyCode::Pause => todo!(), - crossterm::event::KeyCode::Menu => todo!(), - crossterm::event::KeyCode::KeypadBegin => todo!(), - crossterm::event::KeyCode::Media(_) => todo!(), - crossterm::event::KeyCode::Modifier(_) => todo!(), - }; - - Ok(callback) - } - - #[cfg(feature = "dragonos")] - fn key_event_route( - &self, - ui: &mut MutexGuard, - key: KeyEventType, - ) -> io::Result { - match key { - KeyEventType::Common(c) => self.input_data(ui, &[c]), - KeyEventType::Up => self.up(ui), - KeyEventType::Down => self.down(ui), - KeyEventType::Right => self.right(ui), - KeyEventType::Left => self.left(ui), - KeyEventType::Enter => self.enter(ui), - KeyEventType::Tab => self.tab(ui), - KeyEventType::Backspace => self.backspace(ui), - KeyEventType::Esc => self.esc(ui), - KeyEventType::Unknown(_) => { - ui.update_bottom_state_bar()?; - Ok(WarpUiCallBackType::None) - } - } - } -} - -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum ModeType { - Command, - LastLine, - Insert, - Normal, -} - -impl InputMode for Command { - fn mode_type(&self) -> ModeType { - ModeType::Command - } -} -impl InputMode for LastLine { - fn mode_type(&self) -> ModeType { - ModeType::LastLine - } -} -impl InputMode for Insert { - fn mode_type(&self) -> ModeType { - ModeType::Insert - } -} -impl InputMode for Normal { - fn mode_type(&self) -> ModeType { - ModeType::Normal - } -} - -#[derive(Debug)] -pub struct Command; - -impl Command { - pub fn jump_to_next_flag( - &self, - ui: &mut MutexGuard, - flags: LineState, - ) -> io::Result<()> { - let offset = ui.buffer.offset(); - let y = ui.cursor.y() as usize; - - let start_line_number = offset + y + 1; - if start_line_number >= ui.buffer.line_count() { - return Ok(()); - } - - let content = &ui.buffer.all_buffer()[start_line_number..]; - - // 下一个flaged位置 - let idx = content.iter().position(|x| x.flags.contains(flags)); - - if idx.is_some() { - // y + idx - let line_number = start_line_number + idx.unwrap(); - let new_y = ui.buffer.goto_line(line_number); - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.move_to_row(new_y)?; - ui.cursor.highlight(Some(y as u16))?; - } - - Ok(()) - } - - pub fn jump_to_previous_flag( - &self, - ui: &mut MutexGuard, - flags: LineState, - ) -> io::Result<()> { - let offset = ui.buffer.offset(); - let y = ui.cursor.y() as usize; - if offset == 0 && y == 0 { - return Ok(()); - } - let end_linenumber = offset + y - 1; - - let content = &ui.buffer.all_buffer()[0..end_linenumber]; - - // 下一个flaged位置 - let idx = content.iter().rposition(|x| x.flags.contains(flags)); - - if idx.is_some() { - // y + idx - let new_y = ui.buffer.goto_line(idx.unwrap()); - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.move_to_row(new_y)?; - ui.cursor.highlight(Some(y as u16))?; - } - - Ok(()) - } - - fn jump_to_first_char(&self, ui: &mut MutexGuard) -> io::Result { - // 移动到行第一个单词的首字母 - let first_char = { - let line = ui.buffer.get_line(ui.cursor.y()).data; - let mut idx = 0; - for char in line { - if char == b" "[0] { - idx += 1; - } else if char == b"\t"[0] { - idx += 4; - } - } - idx - }; - ui.cursor.move_to_columu(first_char)?; - return Ok(WarpUiCallBackType::None); - } - - fn do_delete_on_d_clicked( - &self, - ui: &mut MutexGuard, - ) -> io::Result { - let buf: &mut [u8] = &mut [0; 8]; - let _ = io::stdin().read(buf)?; - - match buf[0] { - b'd' => { - TermManager::clear_current_line()?; - TermManager::clear_under_cursor()?; - let y = ui.cursor.y() as usize; - let old_line_count = ui.buffer.line_count(); - - let count = old_line_count - y as usize; - ui.buffer.delete_line(y); - ui.render_content(y as u16, count.max(1))?; - - if y == old_line_count - 1 { - self.up(ui)?; - } - - if old_line_count == 1 { - ui.cursor.move_to_columu(0)?; - ui.buffer.insert_char('\n' as u8, 0, 0); - ui.render_content(0, 1)?; - } - } - b'0' => { - let x = ui.cursor.x() as usize; - let y = ui.cursor.y() as usize; - match ui.buffer.delete_until_line_beg(x, y) { - Some(..) => { - // 文本变动重新渲染 - ui.cursor.move_to_columu(0)?; - ui.render_content(y as u16, 1)?; - } - None => {} - }; - } - b'$' => { - let x = ui.cursor.x() as usize; - let y = ui.cursor.y() as usize; - match ui.buffer.delete_until_endl(x, y) { - Some(..) => { - ui.cursor.move_left(1)?; - ui.render_content(y as u16, 1)?; - } - None => {} - } - } - - b'w' | b'e' => { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - let next_word_pos = ui.buffer.search_nextw_begin(x, y); - let linesize = ui.buffer.get_linesize(y); - - // 如果下一个单词在当前行,则删除当前单词 - if next_word_pos < linesize.into() { - ui.buffer.remove_str(x, y, next_word_pos - x as usize); - } else { - // 如果下一个单词在下一行,则删除当前行剩余部分 - self.left(ui)?; - ui.buffer.delete_until_endl(x.into(), y.into()); - } - ui.render_content(y, 1)?; - } - - b'b' => { - let old_x = ui.cursor.x(); - let old_y = ui.cursor.y(); - - self.jump_to_prevw_beg(ui)?; - - let x = ui.cursor.x(); - let y = ui.cursor.y(); - if old_y == y { - ui.buffer.remove_str(x, y, old_x as usize - x as usize); - ui.render_content(y, 1)?; - } else { - ui.buffer.delete_until_endl(x as usize, y as usize); - ui.buffer - .delete_until_line_beg(old_x as usize, old_y as usize); - ui.buffer.merge_line(old_y); - let linecount = ui.buffer.line_count(); - TermManager::clear_under_cursor()?; - ui.render_content(y, linecount - y as usize - 1)?; - } - } - _ => {} - } - return Ok(WarpUiCallBackType::None); - } - - fn jump_to_next_word(&self, ui: &mut MutexGuard) -> io::Result { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - let pos = ui.buffer.search_nextw_begin(x, y); - let linesize = ui.buffer.get_linesize(y); - - if pos < linesize as usize { - // 如果下一个单词在当前行,则移动光标到该单词的起始位置 - ui.cursor.move_to_columu(pos as u16)?; - } else if y + 1 < ui.buffer.line_count() as u16 { - // 如果当前行不是最后一行,则移动到下一行的开头 - self.down(ui)?; - ui.cursor.move_to_columu(0)?; - } else { - // 如果当前行是最后一行,则移动到当前行的末尾 - ui.cursor.move_to_columu(linesize as u16 - 1)?; - } - return Ok(WarpUiCallBackType::None); - } - - fn jump_to_nextw_ending(&self, ui: &mut MutexGuard) -> io::Result { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - let linesize = ui.buffer.get_linesize(y) as usize; - - // 如果光标已经在当前行的末尾或最后一个字符,则尝试移动到下一行的末尾或单词末尾 - let final_char_pos = linesize - 2; - if x as usize >= final_char_pos { - if y < ui.buffer.line_count() as u16 - 1 { - let next_end_pos = ui.buffer.search_nextw_end(0, y + 1) as u16; - ui.cursor.move_to(next_end_pos, y + 1)?; - ui.cursor.highlight(Some(y))?; - } else { - // 如果已经是最后一行,则保持光标在当前行的末尾 - ui.cursor.move_to_columu(linesize as u16 - 1)?; - } - return Ok(WarpUiCallBackType::None); - } - - let next_end_pos = ui.buffer.search_nextw_end(x, y) as u16; - // 如果下一个单词的末尾在当前行,则移动光标到该单词的末尾 - ui.cursor - .move_to_columu(next_end_pos.min(linesize as u16 - 2))?; - return Ok(WarpUiCallBackType::None); - } - - fn jump_to_prevw_beg(&self, ui: &mut MutexGuard) -> io::Result { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - - // 如果光标已在行首,则尝试移动到上一行的单词首字母 - if x == 0 { - if y > 0 { - let end_of_prev_line = ui.buffer.get_linesize(y - 1) - 1; - let prev_word_pos = match ui.buffer.search_prevw_begin(end_of_prev_line, y - 1) { - Some(pos) => pos, - None => 0, - }; - ui.cursor.move_to(prev_word_pos as u16, y - 1)?; - ui.cursor.highlight(Some(y))?; - } else { - // 如果已经是第一行,则保持光标在当前行的起始位置 - ui.cursor.move_to_columu(0)?; - } - return Ok(WarpUiCallBackType::None); - } - - let prev_word_pos = match ui.buffer.search_prevw_begin(x, y) { - Some(pos) => pos, - None => 0, - }; - - ui.cursor.move_to(prev_word_pos as u16, y)?; - return Ok(WarpUiCallBackType::None); - } - - pub fn move_to_nlines_of_screen( - &self, - ui: &mut MutexGuard, - n: usize, - ) -> io::Result<()> { - let y = ui.cursor.y() as usize; - - let offset = ui.buffer.offset(); - - let new_y = ui.buffer.goto_line(offset + n); - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.move_to_row(new_y)?; - ui.cursor.highlight(Some(y as u16))?; - - Ok(()) - } -} - -impl KeyEventCallback for Command { - fn backspace(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - fn enter(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn tab(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn esc(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn input_data( - &self, - ui: &mut MutexGuard, - data: &[u8], - ) -> io::Result { - match data { - b":" => { - // 保存位置 - ui.cursor.store_pos(); - return Ok(WarpUiCallBackType::ChangMode(ModeType::LastLine)); - } - - b"i" => { - // 切换Insert模式,从光标前开始插入字符 - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - b"I" => { - // 切换Insert模式,从行首开始插入字符 - ui.cursor.move_to_columu(0)?; - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - b"a" => { - // 切换Insert模式,在光标后开始输入文本 - ui.cursor.move_right(1)?; - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - b"A" => { - // 切换Insert模式,在行尾开始输入文本 - let linesize = ui.buffer.get_linesize(ui.cursor.y()); - ui.cursor.move_to_columu(linesize - 1)?; - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - b"o" => { - // 切换Insert模式,在当前行的下方插入一个新行开始输入文本 - let linesize = ui.buffer.get_linesize(ui.cursor.y()); - ui.cursor.move_to_columu(linesize - 1)?; - ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y()); - ui.cursor.move_to_nextline(1)?; - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - b"O" => { - // 切换Insert模式,在当前行的上方插入一个新行开始输入文本 - ui.cursor.move_to_columu(0)?; - ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y()); - return Ok(WarpUiCallBackType::ChangMode(ModeType::Insert)); - } - - // hjkl 与 Vim 的效果一致 - b"h" => self.left(ui), - - // 向下 - b"j" => self.down(ui), - - // 向上 - b"k" => self.up(ui), - - // 向右 - b"l" => self.right(ui), - - // 移动到当前屏幕最后一行 - b"L" => { - let win_size = CONTENT_WINSIZE.read().unwrap().rows as usize; - self.move_to_nlines_of_screen(ui, win_size - 1)?; - return Ok(WarpUiCallBackType::None); - } - - b"f" | b"F" => { - // 设置当前行flag - let flag = ui.buffer.line_flags(ui.cursor.y()); - let offset = ui.buffer.offset(); - if flag.contains(LineState::FLAGED) { - ui.buffer - .remove_line_flags(offset + ui.cursor.y() as usize, LineState::FLAGED); - } else { - ui.buffer - .add_line_flags(offset + ui.cursor.y() as usize, LineState::FLAGED); - } - - let y = ui.cursor.y(); - ui.render_content(y, 1)?; - return Ok(WarpUiCallBackType::None); - } - - b"q" | b"Q" => { - // 跳转到上一个flag行 - self.jump_to_previous_flag(ui, LineState::FLAGED)?; - return Ok(WarpUiCallBackType::None); - } - - b"w" => self.jump_to_next_word(ui), - - b"e" => self.jump_to_nextw_ending(ui), - - b"b" => self.jump_to_prevw_beg(ui), - - b"W" => { - // 跳转到下一个flag行 - self.jump_to_next_flag(ui, LineState::FLAGED)?; - return Ok(WarpUiCallBackType::None); - } - - b"s" | b"S" => { - self.jump_to_next_flag(ui, LineState::LOCKED)?; - return Ok(WarpUiCallBackType::None); - } - - b"0" => { - // 移动到行首 - ui.cursor.move_to_columu(0)?; - return Ok(WarpUiCallBackType::None); - } - - b"^" => self.jump_to_first_char(ui), - - b"$" => { - // 移动到行末 - let line_end = ui.buffer.get_linesize(ui.cursor.y()) - 1; - ui.cursor.move_to_columu(line_end)?; - return Ok(WarpUiCallBackType::None); - } - - b"d" => self.do_delete_on_d_clicked(ui), - - b"x" => { - let y = ui.cursor.y(); - let x = ui.cursor.x(); - if x < ui.buffer.get_linesize(y) - 1 { - ui.buffer.remove_char(x, y); - ui.render_content(y, 1)?; - } - return Ok(WarpUiCallBackType::None); - } - - b"G" => { - // 移动到最后一行 - let line_count = ui.buffer.line_count() as u16; - let y = ui.cursor.y(); - let new_y = ui.buffer.goto_line(line_count as usize - 1); - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - ui.cursor.move_to_row(new_y)?; - ui.cursor.highlight(Some(y))?; - return Ok(WarpUiCallBackType::None); - } - - b"n" => { - return Ok(WarpUiCallBackType::ChangMode(ModeType::Normal)); - } - - b"H" => { - self.move_to_nlines_of_screen(ui, 0)?; - return Ok(WarpUiCallBackType::None); - } - - b"M" => { - let win_size = CONTENT_WINSIZE.read().unwrap().rows as usize; - self.move_to_nlines_of_screen(ui, win_size / 2)?; - return Ok(WarpUiCallBackType::None); - } - - _ => { - return Ok(WarpUiCallBackType::None); - } - } - } -} - -#[derive(Debug)] -pub struct Insert; -impl KeyEventCallback for Insert { - fn enter(&self, ui: &mut MutexGuard) -> io::Result { - let line_idx = ui.cursor.y(); - let col = ui.cursor.x(); - - let line = ui.buffer.get_line(line_idx); - if line.flags.contains(LineState::LOCKED) { - APP_INTERNAL_INFOMATION.lock().unwrap().info = "Row is locked".to_string(); - return Ok(WarpUiCallBackType::None); - } - ui.buffer.input_enter(col, line_idx); - - DEF_STYLE.read().unwrap().set_content_style()?; - // 清空改行光标后的内容 - TermManager::clear_until_new_line()?; - - // 执行渲染后续文本 - ui.cursor.move_to_nextline(1)?; - ui.cursor.clear_current_line()?; - - let ret = ui.render_content( - line_idx + 1, - (CONTENT_WINSIZE.read().unwrap().rows - line_idx) as usize, - )?; - - if ret == 0 { - ui.scroll_up(1)?; - ui.render_content( - line_idx + 1, - (CONTENT_WINSIZE.read().unwrap().rows - line_idx) as usize, - )?; - - ui.cursor.move_up(1)?; - } - - let last = ui.cursor.y() - 1; - ui.cursor.highlight(Some(last))?; - ui.set_edited(); - Ok(WarpUiCallBackType::None) - } - - fn tab(&self, ui: &mut MutexGuard) -> io::Result { - ui.set_edited(); - let x = ui.cursor.x(); - - let tab_size = TAB_SIZE.load(Ordering::SeqCst); - let space_size = tab_size - (x % tab_size); - - for _ in 0..space_size { - ui.buffer - .insert_char(' ' as u8, ui.cursor.x(), ui.cursor.y()); - } - - let y = ui.cursor.y(); - ui.render_content(y, 1)?; - - ui.cursor.move_right(space_size)?; - - Ok(WarpUiCallBackType::None) - } - - fn esc(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::ChangMode(ModeType::Command)) - } - - fn input_data( - &self, - ui: &mut MutexGuard, - data: &[u8], - ) -> io::Result { - let x = ui.cursor.x(); - let y = ui.cursor.y(); - - let line = ui.buffer.get_line(y); - if line.flags.contains(LineState::LOCKED) { - APP_INTERNAL_INFOMATION.lock().unwrap().info = "Row is locked".to_string(); - return Ok(WarpUiCallBackType::None); - } - - for (idx, ch) in data.iter().enumerate() { - ui.buffer.insert_char(*ch, x + idx as u16, y); - } - - let line_data = ui.buffer.get_line(y); - - // 考虑长度包含\n,所以要减1 - ui.cursor.write(String::from_utf8_lossy( - &line_data.data[x as usize..(line_data.size() - 1)], - ))?; - - ui.cursor.move_to_columu(x + data.len() as u16)?; - ui.set_edited(); - ui.cursor.highlight(None)?; - Ok(WarpUiCallBackType::None) - } -} - -#[derive(Debug)] -pub struct LastLine { - buf: Mutex>, -} - -impl LastLine { - pub fn new() -> Self { - Self { - buf: Mutex::new(vec![':' as u8]), - } - } - - pub fn reset(&self) { - self.buf.lock().unwrap().resize(1, ':' as u8); - } -} - -impl KeyEventCallback for LastLine { - fn enter(&self, ui: &mut MutexGuard) -> io::Result { - let mut buf = self.buf.lock().unwrap(); - let cmd = String::from_utf8_lossy(&buf).to_string(); - - let ret = LastLineCommand::process(ui, cmd); - - ui.cursor.move_to(1, u16::MAX - 1)?; - // ui.cursor.move_to_columu(1)?; - TermManager::clear_until_new_line()?; - ui.cursor.move_to(1, u16::MAX - 1)?; - - buf.resize(1, 0); - if ret == WarpUiCallBackType::None { - ui.cursor.restore_pos()?; - return Ok(WarpUiCallBackType::ChangMode(ModeType::Command)); - } - - Ok(ret) - } - - fn tab(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn backspace(&self, ui: &mut MutexGuard) -> io::Result { - if ui.cursor.x() == 1 { - return Ok(WarpUiCallBackType::None); - } - - self.left(ui)?; - self.buf.lock().unwrap().remove(ui.cursor.x() as usize); - - ui.cursor.write(' ')?; - self.left(ui)?; - - Ok(WarpUiCallBackType::None) - } - - fn up(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn down(&self, _ui: &mut MutexGuard) -> io::Result { - Ok(WarpUiCallBackType::None) - } - - fn esc(&self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.restore_pos()?; - Ok(WarpUiCallBackType::ChangMode(ModeType::Command)) - } - - fn input_data( - &self, - ui: &mut MutexGuard, - data: &[u8], - ) -> io::Result { - let mut buf = self.buf.lock().unwrap(); - - if ui.cursor.x() == buf.len() as u16 { - buf.extend(data); - } else { - let index = ui.cursor.x() as usize; - for (i, &item) in data.iter().enumerate() { - buf.insert(index + i, item); - } - } - - ui.cursor.write(String::from_utf8_lossy(&data))?; - - Ok(WarpUiCallBackType::None) - } -} diff --git a/src/utils/ui/mode/normal.rs b/src/utils/ui/mode/normal.rs deleted file mode 100644 index 9bd99ca..0000000 --- a/src/utils/ui/mode/normal.rs +++ /dev/null @@ -1,722 +0,0 @@ -use lazy_static::lazy_static; - -use crate::utils::ui::event::KeyEventCallback; -use crate::utils::ui::event::WarpUiCallBackType; -use crate::utils::ui::uicore::UiCore; -use crate::utils::ui::uicore::CONTENT_WINSIZE; -use std::io; -use std::sync::{Mutex, MutexGuard}; - -use super::common::CommonOp; -use super::mode::ModeType; -use super::state::StateMachine; -use crate::utils::ui::mode::state::StateCallback; - -#[derive(Debug)] -#[allow(dead_code)] -pub enum BufOpArg { - Around, // 操作引号内乃至引号的内容 - Inside, // 操作引号内的内容 - Line, // 操作整行 - Word, // 操作单词 - WordEnd, // 操作单词的末尾 - WordBegin, // 操作单词的开头 - Block, // 操作块 -} - -#[derive(Debug)] -pub struct NormalState { - pub cmdchar: Option, - pub count: Option, - pub count0: bool, - pub start_pos: Option<(u16, u16)>, - pub end_pos: Option<(u16, u16)>, - pub cmdbuf: Vec, - pub buf_op_arg: Option, -} - -impl CommonOp for NormalState {} - -lazy_static! { - static ref NORMALSTATE: Mutex = Mutex::new(NormalState { - cmdchar: None, // 命令开头的字符,通常决定了一类功能,如dw,dd系列命令 - count: None, // 命令的重复次数,如3j,4k - count0: false, // 是否将0作为命令的一部分,在normal模式下,0是一个独立的命令,也可能是一个数字的一部分 - start_pos: None, // 作用区域的起始位置 - end_pos: None, // 作用区域的结束位置 - cmdbuf: Vec::new(), // 用于存储输入的命令,可以与状态的显示通用? - buf_op_arg: None // 用于指定操作的区域,如daw,diw - }); -} - -#[derive(Debug)] -pub(crate) struct Normal; -impl Normal { - pub fn new() -> Self { - Self {} - } -} - -impl KeyEventCallback for Normal { - fn backspace(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::None); - } - fn esc(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::ChangMode(ModeType::Command)); - } - - fn enter(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::None); - } - fn tab(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::None); - } - fn input_data( - &self, - ui: &mut MutexGuard, - data: &[u8], - ) -> io::Result { - let mut normal_state = NORMALSTATE.lock().unwrap(); - normal_state.cmdbuf.extend_from_slice(data); - match data { - b"h" => normal_state.on_h_clicked(), - - b"j" => normal_state.on_j_clicked(), - - b"k" => normal_state.on_k_clicked(), - - b"l" => normal_state.on_l_clicked(), - - b"i" => normal_state.on_i_clicked(), - - b"d" => normal_state.on_d_clicked(), - - [b'1'..=b'9'] => normal_state.on_nonzero_clicked(data), - - b"0" => normal_state.on_zero_clicked(), - - b"w" => normal_state.on_w_clicked(ui), - - b"g" => normal_state.on_g_clicked(), - - b"G" => normal_state.on_G_clicked(ui), - - b"b" => normal_state.on_b_clicked(ui), - - b":" => { - if normal_state.cmdchar.is_none() { - ui.cursor.store_pos(); - return Ok(WarpUiCallBackType::ChangMode(ModeType::LastLine)); - } - } - - b"$" => normal_state.on_dollar_clicked(), - - b"e" => normal_state.on_e_clicked(ui), - - b"f" => normal_state.on_f_clicked(), - - b"F" => normal_state.on_F_clicked(), - - b"x" => normal_state.on_x_clicked(), - - b"o" => normal_state.on_o_clicked(), - - b"O" => normal_state.on_O_clicked(), - - b"a" => normal_state.on_a_clicked(), - - b"A" => normal_state.on_A_clicked(), - - b"I" => normal_state.on_I_clicked(), - - b"H" => normal_state.on_H_clicked(), - - b"M" => normal_state.on_M_clicked(), - - _ => {} - } - return normal_state.handle(ui); - } -} - -impl KeyEventCallback for NormalState { - fn backspace(&self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_left(1)?; - return Ok(WarpUiCallBackType::None); - } - - fn esc(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::ChangMode(ModeType::Command)); - } - - fn enter(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::None); - } - - fn tab(&self, _ui: &mut MutexGuard) -> io::Result { - return Ok(WarpUiCallBackType::None); - } - - fn input_data( - &self, - _ui: &mut MutexGuard, - _data: &[u8], - ) -> io::Result { - return Ok(WarpUiCallBackType::None); - } -} -impl NormalState { - pub fn exec_0_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_to_columu(0)?; - return Ok(StateCallback::Reset); - } - - pub fn on_h_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('h'); - } - } - /// 向左移动数列 - pub fn exec_h_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let old_x = ui.cursor.x(); - let exec_count = match self.count { - Some(count) => count.min(old_x as usize), - None => { - if old_x == 0 { - 0 - } else { - 1 - } - } // 如果在第一列,不再向左移动,防止溢出 - }; - let new_x = old_x - exec_count as u16; - ui.cursor.move_to_columu(new_x)?; - return Ok(StateCallback::Reset); - } - - pub fn on_j_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('j'); - } - } - /// 向下移动数行 - pub fn exec_j_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let old_y = ui.cursor.y(); - let old_abs_y = old_y + ui.buffer.offset() as u16; - // 限制最大移动行数 - let exec_count = match self.count { - Some(count) => count.min(ui.buffer.line_count() - old_abs_y as usize - 1), - None => 1, // goto_line 会自动处理最大值 - }; - let old_offset = ui.buffer.offset(); - let new_y = ui.buffer.goto_line(old_abs_y as usize + exec_count); - let new_linesize = ui.buffer.get_linesize(new_y); - let new_x = if new_linesize < ui.cursor.x() { - // 如果新行的长度小于原来的x坐标,将光标移动到新行的最后一个字符 - new_linesize - 1 - } else { - ui.cursor.x() - }; - ui.cursor.move_to(new_x, new_y)?; - ui.cursor.highlight(Some(old_y))?; - // 如果移动后,buffer的offset发生了变化,需要重新渲染 - if ui.buffer.offset() != old_offset { - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - } - return Ok(StateCallback::Reset); - } - pub fn on_k_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('k'); - } - } - - /// 向上移动数行 - pub fn exec_k_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let old_y = ui.cursor.y(); - let old_abs_y = old_y + ui.buffer.offset() as u16; - // 限制最大移动行数 - let exec_count = match self.count { - Some(count) => count.min(old_y as usize + ui.buffer.offset()), - None => { - if old_abs_y == 0 { - 0 - } else { - 1 - } - } // 如果在第一行,不再向上移动,防止溢出 - }; - let to_line = old_abs_y as usize - exec_count; - let old_offset = ui.buffer.offset(); - let new_y = ui.buffer.goto_line(to_line); - let new_linesize = ui.buffer.get_linesize(new_y); - let new_x = if new_linesize < ui.cursor.x() { - // 如果新行的长度小于原来的x坐标,将光标移动到新行的最后一个字符 - new_linesize - 1 - } else { - ui.cursor.x() - }; - ui.cursor.move_to(new_x, new_y)?; - ui.cursor.highlight(Some(old_y))?; - // 如果移动后,buffer的offset发生了变化,需要重新渲染 - if old_offset != ui.buffer.offset() { - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - } - return Ok(StateCallback::Reset); - } - - pub fn on_l_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('l'); - } - } - - /// 向右移动数列 - pub fn exec_l_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let old_x = ui.cursor.x(); - let linesize = ui.buffer.get_linesize(ui.cursor.y()) as usize; - let max_count = linesize - old_x as usize - 1; - let exec_count = match self.count { - Some(count) => count.min(max_count), - None => { - if old_x == linesize as u16 - 1 { - 0 - } else { - 1 - } - } - }; - let new_x = old_x + exec_count as u16; - ui.cursor.move_to_columu(new_x)?; - return Ok(StateCallback::Reset); - } - - pub fn on_i_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('i'); - } - } - pub fn exec_i_cmd(&mut self, _ui: &mut MutexGuard) -> io::Result { - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - #[allow(non_snake_case)] - pub fn on_I_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('I'); - } - } - - // 切换Insert模式,从行首开始插入字符 - #[allow(non_snake_case)] - pub fn exec_I_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_to_columu(0)?; - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - pub fn on_a_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('a'); - } - } - - // 切换Insert模式,从当前位置的下一个字符开始插入 - pub fn exec_a_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - self.right(ui)?; - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - #[allow(non_snake_case)] - pub fn on_A_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('A'); - } - } - - // 切换Insert模式,从行尾开始插入字符 - #[allow(non_snake_case)] - pub fn exec_A_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let line_end = ui.buffer.get_linesize(ui.cursor.y()) - 1; - ui.cursor.move_to_columu(line_end)?; - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - pub fn on_o_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('o'); - } - } - - // 切换Insert模式,在当前行的下方插入一个新行开始输入文本 - pub fn exec_o_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let linesize = ui.buffer.get_linesize(ui.cursor.y()); - ui.cursor.move_to_columu(linesize - 1)?; - ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y()); - ui.cursor.move_to_nextline(1)?; - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - #[allow(non_snake_case)] - pub fn on_O_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('O'); - } - } - - // 切换Insert模式,在当前行的上方插入一个新行开始输入文本 - #[allow(non_snake_case)] - pub fn exec_O_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - ui.cursor.move_to_columu(0)?; - ui.buffer.input_enter(ui.cursor.x(), ui.cursor.y()); - return Ok(StateCallback::Exit(ModeType::Insert)); - } - - /// 处理输入的非零数字 - pub fn on_nonzero_clicked(&mut self, data: &[u8]) { - let count = self.count; - if count.is_none() { - // 如果count为空,将第一个输入的数字作为count - let count = data[0] - b'0'; - self.count = Some(count as usize); - } else { - // 如果count不为空,将输入的数字添加到count的末尾 - let mut count = count.unwrap(); - count = count * 10 + (data[0] - b'0') as usize; - self.count = Some(count); - } - self.count0 = true; // 将后续输入的0作为执行次数的一部分 - } - - /// 处理输入的0 - pub fn on_zero_clicked(&mut self) { - // 如果0是命令的一部分,不再处理 - if !self.count0 && self.cmdchar.is_none() { - self.cmdchar = Some('0'); - self.count0 = true; - } - let count = self.count; - // 如果输入的是0,且count不为空,将count扩大10倍 - if count.is_some() { - let mut count = count.unwrap(); - count = count * 10; - self.count = Some(count); - } - } - - /// 处理输入的d - pub fn on_d_clicked(&mut self) { - match self.cmdchar { - None => { - // 处理d - self.cmdchar = Some('d'); - } - Some('d') => { - // 处理dd - self.buf_op_arg = Some(BufOpArg::Line); - } - _ => { - self.reset(); - } - } - } - - pub fn exec_d_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let count = match self.count { - Some(count) => count as u16, - None => 1, - }; - match self.buf_op_arg { - Some(BufOpArg::Line) => { - // 删除行 - self.remove_n_line(ui, count)?; - return Ok(StateCallback::Reset); - } - Some(BufOpArg::Word) => { - // 删除单词 - for _ in 0..count { - self.remove_word(ui)?; - } - return Ok(StateCallback::Reset); - } - _ => { - return Ok(StateCallback::None); - } - } - } - - pub fn on_w_clicked(&mut self, ui: &mut MutexGuard) { - if self.cmdchar.is_none() { - // 按单词移动 - self.cmdchar = Some('w'); - let count = match self.count { - Some(count) => count, - None => 1, - }; - let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16); - for _ in 0..count { - pos = self.locate_next_word(ui, pos); - } - self.end_pos = Some(pos); - } else { - // 按单词操作,具体由self.cmdchar决定 - self.buf_op_arg = Some(BufOpArg::Word); - } - } - - pub fn exec_w_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - self.end_pos.map(|pos| { - self.move_to_line(ui, pos.1).unwrap(); - ui.cursor.move_to_columu(pos.0).unwrap(); - }); - return Ok(StateCallback::Reset); - } - - fn on_g_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('g'); - } else { - self.end_pos = Some((0, 0)); - } - } - - fn exec_g_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let rs = self - .end_pos - .map(|pos| self.move_to_line(ui, pos.1).unwrap()); - if let None = rs { - return Ok(StateCallback::None); - } - return Ok(StateCallback::Reset); - } - - #[allow(non_snake_case)] - fn on_G_clicked(&mut self, _ui: &mut MutexGuard) { - if self.cmdchar.is_none() { - self.cmdchar = Some('G'); - } - } - - #[allow(non_snake_case)] - fn exec_G_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let lineidx = match self.count { - Some(count) => count - 1, - None => ui.buffer.line_count() - 1, - }; - self.move_to_line(ui, lineidx as u16)?; - return Ok(StateCallback::Reset); - } - - fn on_b_clicked(&mut self, ui: &mut MutexGuard) { - if self.cmdchar.is_none() { - self.cmdchar = Some('b'); - } else { - self.buf_op_arg = Some(BufOpArg::WordBegin); - } - let count = match self.count { - Some(count) => count, - None => 1, - }; - let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16); - self.start_pos = Some(pos); - for _ in 0..count { - pos = self.locate_prevw_begin(ui, pos.0, pos.1); - } - self.end_pos = Some(pos); - } - - fn exec_b_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let end_pos = self.end_pos.unwrap(); - self.move_to_line(ui, end_pos.1)?; - ui.cursor.move_to_columu(end_pos.0)?; - return Ok(StateCallback::Reset); - } - - fn on_dollar_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('$'); - } - } - - fn exec_dollar_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let line_end = ui.buffer.get_linesize(ui.cursor.y()) as u16 - 1; - ui.cursor.move_to_columu(line_end)?; - return Ok(StateCallback::Reset); - } - - fn on_e_clicked(&mut self, ui: &mut MutexGuard) { - if self.cmdchar.is_none() { - self.cmdchar = Some('e'); - } else { - self.buf_op_arg = Some(BufOpArg::WordEnd); - } - let count = match self.count { - Some(count) => count, - None => 1, - }; - let mut pos = (ui.cursor.x(), ui.cursor.y() + ui.buffer.offset() as u16); - for _ in 0..count { - pos = self.locate_nextw_ending(ui, pos.0, pos.1); - } - self.end_pos = Some(pos); - } - - fn exec_e_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let end_pos = self.end_pos; - if end_pos.is_none() { - return Ok(StateCallback::None); - } - let end_pos = end_pos.unwrap(); - self.move_to_line(ui, end_pos.1)?; - ui.cursor.move_to_columu(end_pos.0)?; - return Ok(StateCallback::Reset); - } - - fn on_f_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('f'); - } - } - - fn exec_f_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - if self.cmdbuf.len() < 2 { - return Ok(StateCallback::None); - } - let to_find = self.cmdbuf.last().unwrap().clone() as char; - let old_x = ui.cursor.x(); - let old_y = ui.cursor.y(); - let line = - String::from_utf8_lossy(&ui.buffer.get_line(old_y)[old_x as usize..]).to_string(); - let pos = line.find(to_find); - if pos.is_none() { - return Ok(StateCallback::None); - } - ui.cursor - .move_to_columu((old_x + pos.unwrap() as u16) as u16)?; - return Ok(StateCallback::Reset); - } - - #[allow(non_snake_case)] - fn on_F_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('F'); - } - } - - #[allow(non_snake_case)] - fn exec_F_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - if self.cmdbuf.len() < 2 { - return Ok(StateCallback::None); - } - let to_find = self.cmdbuf.last().unwrap().clone() as char; - let old_x = ui.cursor.x(); - let old_y = ui.cursor.y(); - let line = - String::from_utf8_lossy(&ui.buffer.get_line(old_y)[..old_x as usize]).to_string(); - let pos = line.rfind(to_find); - if pos.is_none() { - return Ok(StateCallback::None); - } - ui.cursor.move_to_columu(pos.unwrap() as u16)?; - return Ok(StateCallback::Reset); - } - - fn on_x_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('x'); - } - } - - fn exec_x_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let y = ui.cursor.y(); - let x = ui.cursor.x(); - if x < ui.buffer.get_linesize(y) - 1 { - ui.buffer.remove_char(x, y); - ui.render_content(y, 1)?; - } - return Ok(StateCallback::Reset); - } - - #[allow(non_snake_case)] - fn on_H_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('H'); - } - } - - #[allow(non_snake_case)] - fn exec_H_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - self.move_to_nlines_of_screen(ui, 0)?; - return Ok(StateCallback::Reset); - } - #[allow(non_snake_case)] - fn on_M_clicked(&mut self) { - if self.cmdchar.is_none() { - self.cmdchar = Some('M'); - } - } - - #[allow(non_snake_case)] - fn exec_M_cmd(&mut self, ui: &mut MutexGuard) -> io::Result { - let win_size = CONTENT_WINSIZE.read().unwrap().rows as usize; - self.move_to_nlines_of_screen(ui, win_size / 2)?; - return Ok(StateCallback::Reset); - } -} - -impl StateMachine for NormalState { - fn reset(&mut self) { - self.cmdchar = None; - self.count = None; - self.count0 = false; - self.start_pos = None; - self.end_pos = None; - self.cmdbuf.clear(); - self.buf_op_arg = None; - } - fn handle(&mut self, ui: &mut MutexGuard) -> io::Result { - if self.cmdchar.is_none() { - return Ok(WarpUiCallBackType::None); - } - let state_callback = match self.cmdchar.unwrap() { - 'h' => self.exec_h_cmd(ui), - 'j' => self.exec_j_cmd(ui), - 'k' => self.exec_k_cmd(ui), - 'l' => self.exec_l_cmd(ui), - 'i' => self.exec_i_cmd(ui), - '0' => self.exec_0_cmd(ui), - 'd' => self.exec_d_cmd(ui), - 'w' => self.exec_w_cmd(ui), - 'g' => self.exec_g_cmd(ui), - 'G' => self.exec_G_cmd(ui), - 'b' => self.exec_b_cmd(ui), - '$' => self.exec_dollar_cmd(ui), - 'e' => self.exec_e_cmd(ui), - 'f' => self.exec_f_cmd(ui), - 'F' => self.exec_F_cmd(ui), - 'x' => self.exec_x_cmd(ui), - 'o' => self.exec_o_cmd(ui), - 'O' => self.exec_O_cmd(ui), - 'a' => self.exec_a_cmd(ui), - 'A' => self.exec_A_cmd(ui), - 'I' => self.exec_I_cmd(ui), - 'H' => self.exec_H_cmd(ui), - 'M' => self.exec_M_cmd(ui), - _ => Ok(StateCallback::None), - }; - return match state_callback { - Ok(StateCallback::None) => Ok(WarpUiCallBackType::None), - Ok(StateCallback::Reset) => { - self.reset(); - Ok(WarpUiCallBackType::None) - } - Ok(StateCallback::Exit(mode)) => self.exit(WarpUiCallBackType::ChangMode(mode)), - Err(e) => Err(e), - }; - } - - fn exit(&mut self, callback: WarpUiCallBackType) -> io::Result { - self.reset(); - Ok(callback) - } -} diff --git a/src/utils/ui/mode/state.rs b/src/utils/ui/mode/state.rs deleted file mode 100644 index 07dd3a1..0000000 --- a/src/utils/ui/mode/state.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::{io, sync::MutexGuard}; - -use crate::utils::ui::{event::WarpUiCallBackType, uicore::UiCore}; - -use super::mode::ModeType; - -pub enum StateCallback { - None, - Reset, - Exit(ModeType), -} - -pub trait StateMachine { - fn handle(&mut self, ui: &mut MutexGuard) -> io::Result; - fn exit(&mut self, callback: WarpUiCallBackType) -> io::Result; - fn reset(&mut self); -} diff --git a/src/utils/ui/uicore.rs b/src/utils/ui/uicore.rs deleted file mode 100644 index bc59032..0000000 --- a/src/utils/ui/uicore.rs +++ /dev/null @@ -1,430 +0,0 @@ -use std::{ - io, - sync::{atomic::AtomicU16, Arc, Mutex, MutexGuard, Once, RwLock, Weak}, -}; - -use crossterm::{ - style::Color, - terminal::{self}, -}; -use lazy_static::lazy_static; - -use crate::{ - config::appconfig::AppSetting, - utils::{ - buffer::EditBuffer, cursor::CursorCrtl, style::StyleManager, terminal::TermManager, - ui::InfoLevel, - }, -}; - -#[cfg(feature = "dragonos")] -use crate::utils::input::Input; - -use super::{ - mode::mode::{Command, InputMode, Insert, LastLine, ModeType}, - mode::normal::Normal, - AppInternalInfomation, -}; - -lazy_static! { - static ref COMMAND: Arc = Arc::new(Command); - static ref INSERT: Arc = Arc::new(Insert); - static ref LASTLINE: Arc = Arc::new(LastLine::new()); - static ref NORMAL: Arc = Arc::new(Normal::new()); - pub static ref APP_INTERNAL_INFOMATION: Mutex = - Mutex::new(AppInternalInfomation { - level: InfoLevel::Info, - info: String::new() - }); -} - -pub static TAB_SIZE: AtomicU16 = AtomicU16::new(4); - -#[derive(Debug, Clone, Copy)] -pub struct WinSize { - pub cols: u16, - pub rows: u16, -} - -#[derive(Debug)] -pub struct UiCore { - pub buffer: Arc, - pub cursor: CursorCrtl, - - #[allow(dead_code)] - setting: AppSetting, - container: Weak, - - edited: bool, - edited_once: Once, -} - -impl UiCore { - pub fn new(buf: Arc, cursor: CursorCrtl, setting: AppSetting) -> Self { - Self { - buffer: buf, - cursor, - container: Weak::new(), - setting, - edited: false, - edited_once: Once::new(), - } - } - - pub fn edited(&self) -> bool { - self.edited - } - - pub fn set_edited(&mut self) { - self.edited_once.call_once(|| self.edited = true) - } - - pub fn update_bottom_state_bar(&mut self) -> io::Result<()> { - let container = self.container.upgrade().unwrap(); - let mode = container.mode.read().unwrap().mode_type(); - if mode == ModeType::LastLine { - return Ok(()); - } - - let size = *WINSIZE.read().unwrap(); - - let store_x = self.cursor.x(); - let store_y = self.cursor.y(); - - self.cursor.set_prefix_mode(false); - - DEF_STYLE.read().unwrap().set_cmd_style()?; - let cmd_y = size.rows - 1; - self.cursor.move_to_row(cmd_y)?; - self.cursor.clear_current_line()?; - self.cursor - .write_with_pos(format!("{mode:?}"), 0, cmd_y, false)?; - - let (buf_x, buf_y) = (store_x, store_y + 1 + self.buffer.offset() as u16); - let index_info = format!("row:{buf_y} col:{buf_x}"); - let len = index_info.len() as u16; - self.cursor - .write_with_pos(index_info, size.cols - len, cmd_y, false)?; - - self.cursor.set_prefix_mode(true); - self.cursor.move_to(store_x, store_y)?; - - let mut info = APP_INTERNAL_INFOMATION.lock().unwrap(); - info.level.set_style()?; - self.cursor - .write_with_pos(&info.info, size.cols / 3, cmd_y, false)?; - - info.reset(); - self.cursor.move_to(store_x, store_y)?; - - StyleManager::reset_color()?; - - Ok(()) - } - - /// 渲染部分文件内容,从y行开始渲染count行 - /// 返回实际渲染行数 - pub fn render_content(&mut self, mut y: u16, mut count: usize) -> io::Result { - y += UI_HEAD_OFFSET; - let content_winsize = *CONTENT_WINSIZE.read().unwrap(); - - // 超出正文范围 - if y + count as u16 > content_winsize.rows { - count = (content_winsize.rows - y) as usize; - } - - let def_style = *DEF_STYLE.read().unwrap(); - - let content = self.buffer.get_content(y as usize, count); - - if content.is_none() { - return Ok(0); - } - let content = content.unwrap(); - - // 保存光标 - let pos = self.cursor.store_tmp_pos(); - - let tmp = y; - - let num_len = (tmp + content_winsize.rows).to_string().len(); - - self.cursor.set_prefix_mode(false); - for line in content.iter() { - let str = String::from_utf8_lossy(&line.data).to_string(); - def_style.set_content_style()?; - - // 移动 - self.cursor - .move_to(num_len as u16 + 2 + CursorCrtl::PREFIX_COL, y)?; - self.cursor.clear_current_line()?; - self.cursor.write(str)?; - y += 1; - StyleManager::reset_color()?; - } - - self.cursor.update_line_prefix(&content, tmp, num_len)?; - self.cursor.set_prefix_mode(true); - - self.cursor.restore_tmp_pos(pos)?; - - self.cursor.highlight(None)?; - - Ok(content.len()) - } - - // 将正文向上滚动count行 - pub fn scroll_up(&mut self, mut count: u16) -> io::Result<()> { - let winsize = *CONTENT_WINSIZE.read().unwrap(); - - let pos = self.cursor.store_tmp_pos(); - - // 计算最多还能滚动多少行 - let offset = self.buffer.offset(); - - // 最多出两行 - let linecount = self.buffer.line_count(); - if offset + winsize.rows as usize + count as usize >= linecount { - count = linecount as u16 - offset as u16 - winsize.rows; - } - self.buffer.set_offset(offset + count as usize); - // 将光标移动到滚动后的位置 - self.cursor.move_to_row(winsize.rows - count)?; - - // 执行滚动 - TermManager::scroll_up(count)?; - - // 清除光标以下的内容 - TermManager::clear_under_cursor()?; - - // 渲染count行数据 - self.render_content(self.cursor.y(), count as usize)?; - - self.cursor.restore_tmp_pos(pos)?; - - self.cursor.highlight(Some(self.cursor.y() - count))?; - Ok(()) - } - - pub fn scroll_down(&mut self, mut count: u16) -> io::Result<()> { - let pos = self.cursor.store_tmp_pos(); - - // 计算最多还能滚动多少行 - let offset = self.buffer.offset(); - if offset < count as usize { - count = offset as u16; - } - - self.buffer.set_offset(offset - count as usize); - - // 执行滚动 - TermManager::scroll_down(count)?; - - // 将光标移动第count行 - self.cursor.move_to_row(count - 1)?; - // 清除光标以上的内容 - TermManager::clear_up_cursor()?; - - // 渲染count行数据 - self.render_content(0, count as usize)?; - - self.cursor.restore_tmp_pos(pos)?; - - self.cursor.highlight(Some(self.cursor.y() + count))?; - - Ok(()) - } -} - -#[derive(Debug)] -pub struct Ui { - pub core: Arc>, - pub mode: RwLock>, -} - -lazy_static! { - pub static ref WINSIZE: RwLock = { - let size = terminal::size().unwrap(); - RwLock::new(WinSize { - cols: size.0, - rows: size.1, - }) - }; - pub static ref CONTENT_WINSIZE: RwLock = { - let size = *WINSIZE.read().unwrap(); - RwLock::new(WinSize { - cols: size.cols, - rows: size.rows - UI_CMD_HEIGHT - UI_HEAD_OFFSET, - }) - }; - pub static ref DEF_STYLE: RwLock = { - let style = UiStyle { - content_fg: Some(Color::White), - content_bg: None, - cmd_line_fg: Some(Color::White), - cmd_line_bg: Some(Color::DarkCyan), - }; - - RwLock::new(style) - }; -} - -pub static UI_HEAD_OFFSET: u16 = 0; -pub const UI_CMD_HEIGHT: u16 = 1; - -impl Ui { - pub fn new(buf: Arc, setting: AppSetting) -> Arc { - let mut cursor = CursorCrtl::new(buf.clone(), setting.line); - cursor.move_to(0, 0).unwrap(); - - let core = Arc::new(Mutex::new(UiCore::new(buf, cursor, setting))); - let ret = Arc::new(Self { - mode: RwLock::new(Arc::new(Command)), - core: core.clone(), - }); - - core.lock().unwrap().container = Arc::downgrade(&ret); - - ret - } - pub fn init_ui() -> io::Result<()> { - TermManager::init_term()?; - Ok(()) - } - - pub fn start_page_ui(&self) -> io::Result<()> { - StyleManager::set_foreground_color(Color::Cyan)?; - let mut core = self.core.lock().unwrap(); - core.cursor - .write_with_pos("Held - DragonOS/Linux Term Editor\n", 5, 0, false)?; - StyleManager::set_foreground_color(Color::Green)?; - core.cursor - .write_with_pos("Author: heyicong@dragonos.org\n", 7, 1, false)?; - StyleManager::set_foreground_color(Color::DarkMagenta)?; - core.cursor - .write_with_pos("Type any key to continue ><\n", 8, 2, false)?; - StyleManager::reset_color()?; - - core.cursor.move_to(0, 0)?; - - #[cfg(feature = "dragonos")] - let _ = Input::wait_keydown(); - - #[cfg(not(feature = "dragonos"))] - loop { - let ev = crossterm::event::read()?; - if let crossterm::event::Event::Key(_) = ev { - break; - } - } - - TermManager::clear_all()?; - - Ok(()) - } - - pub fn ui_loop(&self) -> io::Result { - let mut core = self.core.lock().unwrap(); - core.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - core.update_bottom_state_bar()?; - core.cursor.move_to(0, 0)?; - core.cursor.highlight(None)?; - loop { - #[cfg(feature = "dragonos")] - let callback = { - let key = Input::wait_keydown()?; - self.mode.read().unwrap().key_event_route(&mut core, key)? - }; - - #[cfg(not(feature = "dragonos"))] - let callback = { - let ev = crossterm::event::read()?; - self.mode.read().unwrap().event_route(&mut core, ev)? - }; - - match callback { - super::event::WarpUiCallBackType::ChangMode(mode) => { - self.set_mode(mode, &mut core)? - } - super::event::WarpUiCallBackType::None => {} - super::event::WarpUiCallBackType::Exit(store) => { - self.ui_exit(); - return Ok(store); - } - } - - if self.mode.read().unwrap().mode_type() != ModeType::LastLine { - core.update_bottom_state_bar()?; - } - } - } - - fn set_mode(&self, mode: ModeType, ui: &mut MutexGuard) -> io::Result<()> { - if mode != ModeType::LastLine { - ui.cursor.set_prefix_mode(true); - - ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize)?; - } - match mode { - ModeType::Command => *self.mode.write().unwrap() = COMMAND.clone(), - ModeType::LastLine => { - ui.cursor.set_prefix_mode(false); - let lastline = LASTLINE.clone(); - lastline.reset(); - *self.mode.write().unwrap() = lastline; - - ui.cursor.move_to(0, u16::MAX - 1)?; - DEF_STYLE.read().unwrap().set_cmd_style()?; - // 写一个空行 - ui.cursor.clear_current_line()?; - ui.cursor.move_to_columu(0)?; - ui.cursor.write(':')?; - } - ModeType::Insert => *self.mode.write().unwrap() = INSERT.clone(), - ModeType::Normal => *self.mode.write().unwrap() = NORMAL.clone(), - } - - Ok(()) - } - - fn ui_exit(&self) { - // 处理未保存退出时的提醒 - - // 解决退出程序后颜色没改变的问题 - StyleManager::reset_color().unwrap(); - } -} - -#[derive(Debug, Clone, Copy)] -pub struct UiStyle { - pub content_fg: Option, - pub content_bg: Option, - pub cmd_line_fg: Option, - pub cmd_line_bg: Option, -} - -impl UiStyle { - pub fn set_cmd_style(&self) -> io::Result<()> { - StyleManager::reset_color()?; - if self.cmd_line_bg.is_some() { - StyleManager::set_background_color(self.cmd_line_bg.unwrap())?; - } - if self.cmd_line_fg.is_some() { - StyleManager::set_foreground_color(self.cmd_line_fg.unwrap())?; - } - - Ok(()) - } - - pub fn set_content_style(&self) -> io::Result<()> { - StyleManager::reset_color()?; - if self.content_bg.is_some() { - StyleManager::set_background_color(self.content_bg.unwrap())?; - } - if self.content_fg.is_some() { - StyleManager::set_foreground_color(self.content_fg.unwrap())?; - } - - Ok(()) - } -} diff --git a/src/view/presenter.rs b/src/view/presenter.rs index f9888f3..5ca3793 100644 --- a/src/view/presenter.rs +++ b/src/view/presenter.rs @@ -97,7 +97,6 @@ impl<'a> Presenter<'a> { }; let len = content.len(); - warn!("line {line}, offset {offset}, content {content}"); self.print(&Position { line, offset }, data.style, data.color, content); offset += len; } diff --git a/src/view/theme_loadler.rs b/src/view/theme_loadler.rs index 074ceb6..0c169cc 100644 --- a/src/view/theme_loadler.rs +++ b/src/view/theme_loadler.rs @@ -1,6 +1,4 @@ use crate::errors::*; -use app_dirs2::{app_dir, AppDataType}; -use error_chain::bail; use std::{ collections::BTreeMap, ffi::OsStr, diff --git a/src/workspace.rs b/src/workspace.rs index 7371eca..391dc45 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -78,7 +78,7 @@ impl Workspace { buffer }; - workspace.add_buffer(buffer); + workspace.add_buffer_with_select(buffer); monitor.init_buffer(workspace.current_buffer.as_mut().unwrap())?; } @@ -118,17 +118,21 @@ impl Workspace { } self.buffers.insert(id, buffer); - self.select_buffer(id); - - if let Some(buffer) = self.current_buffer.as_ref() { + if let Some(buffer) = self.get_buffer(id) { if buffer.syntax_definition.is_none() { - let _ = self.update_current_syntax(); + let _ = self.update_buffer_syntax(id); } } return id; } + pub fn add_buffer_with_select(&mut self, buffer: Buffer) -> usize { + let id = self.add_buffer(buffer); + self.select_buffer(id); + return id; + } + fn alloc_buffer_id(&mut self) -> usize { self.buffer_ida += 1; self.buffer_ida @@ -143,6 +147,15 @@ impl Workspace { return self.buffers.get(&id); } + pub fn get_buffer_mut(&mut self, id: usize) -> Option<&mut Buffer> { + if let Some(ref mut buffer) = self.current_buffer { + if buffer.id.unwrap() == id { + return Some(buffer); + } + } + return self.buffers.get_mut(&id); + } + pub fn get_buffer_with_ino(&self, ino: u64) -> Option<&Buffer> { if let Some(id) = self.buffers_ino_map.get(&ino) { return self.get_buffer(*id); @@ -169,17 +182,18 @@ impl Workspace { false } - pub fn update_current_syntax(&mut self) -> Result<()> { - let buffer = self - .current_buffer - .as_mut() - .ok_or(ErrorKind::EmptyWorkspace)?; + fn update_buffer_syntax(&mut self, id: usize) -> Result<()> { + let buffer = self.get_buffer(id).ok_or(ErrorKind::EmptyWorkspace)?; let definition = buffer .file_extension() .and_then(|ex| self.syntax_set.find_syntax_by_extension(&ex)) .or_else(|| Some(self.syntax_set.find_syntax_plain_text())) .cloned(); - buffer.syntax_definition = definition; + + drop(buffer); + self.get_buffer_mut(id) + .ok_or(ErrorKind::EmptyWorkspace)? + .syntax_definition = definition; Ok(()) }