1 use std::{collections::HashMap, sync::MutexGuard}; 2 3 use lazy_static::lazy_static; 4 5 use crate::utils::{ 6 buffer::LineState, 7 ui::{ 8 event::WarpUiCallBackType, 9 uicore::{UiCore, APP_INFO, CONTENT_WINSIZE}, 10 InfoLevel, 11 }, 12 }; 13 14 lazy_static! { 15 static ref COMMAND: HashMap<&'static str, fn(&mut MutexGuard<UiCore>, &str) -> WarpUiCallBackType> = { 16 let mut map: HashMap<&str, fn(&mut MutexGuard<UiCore>, &str) -> WarpUiCallBackType> = 17 HashMap::new(); 18 map.insert(":q!", LastLineCommand::force_exit); 19 map.insert(":q", LastLineCommand::exit_without_store); 20 map.insert(":wq", LastLineCommand::exit); 21 22 // 跳转 23 map.insert(":goto", LastLineCommand::goto); 24 map.insert(":gt", LastLineCommand::goto); 25 26 // 标记或锁定 27 map.insert(":flag", LastLineCommand::flag); 28 map.insert(":lock", LastLineCommand::lock); 29 map.insert(":unflag", LastLineCommand::unflag); 30 map.insert(":unlock", LastLineCommand::unlock); 31 32 map.insert(":delete", LastLineCommand::delete_lines); 33 map.insert(":dl", LastLineCommand::delete_lines); 34 35 map 36 }; 37 } 38 39 const EDITED_NO_STORE: &'static str = "Changes have not been saved"; 40 const NOT_FOUNT_CMD: &'static str = "Command Not Fount"; 41 42 #[derive(Debug)] 43 #[allow(unused)] 44 pub struct LastLineCommand { 45 /// Command 46 pub command: String, 47 pub args: Vec<String>, 48 } 49 50 /// 提供给用户的命令行功能 51 impl LastLineCommand { process(ui: &mut MutexGuard<UiCore>, cmd: String) -> WarpUiCallBackType52 pub fn process(ui: &mut MutexGuard<UiCore>, cmd: String) -> WarpUiCallBackType { 53 let args = cmd 54 .splitn(2, |x: char| x.is_ascii_whitespace()) 55 .collect::<Vec<_>>(); 56 57 if let Some(func) = COMMAND.get(args[0]) { 58 let ret = if args.len() == 1 { 59 func(ui, "") 60 } else { 61 func(ui, &args[1]) 62 }; 63 64 ret 65 } else { 66 let mut info = APP_INFO.lock().unwrap(); 67 info.level = InfoLevel::Info; 68 info.info = NOT_FOUNT_CMD.to_string(); 69 return WarpUiCallBackType::None; 70 } 71 } 72 is_split_char(x: char) -> bool73 const fn is_split_char(x: char) -> bool { 74 x == ',' || x == ';' || x == ':' || x == '/' || x.is_ascii_whitespace() 75 } 76 force_exit(_ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType77 fn force_exit(_ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType { 78 WarpUiCallBackType::Exit(false) 79 } 80 exit_without_store(ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType81 fn exit_without_store(ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType { 82 if ui.edited() { 83 // 编辑过但不保存? 84 // 更新警示信息 85 let mut info = APP_INFO.lock().unwrap(); 86 info.level = InfoLevel::Warn; 87 info.info = EDITED_NO_STORE.to_string(); 88 return WarpUiCallBackType::None; 89 } 90 WarpUiCallBackType::Exit(false) 91 } 92 exit(_ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType93 fn exit(_ui: &mut MutexGuard<UiCore>, _args: &str) -> WarpUiCallBackType { 94 WarpUiCallBackType::Exit(true) 95 } 96 goto(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType97 fn goto(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 98 if args.is_empty() { 99 let mut info = APP_INFO.lock().unwrap(); 100 info.level = InfoLevel::Info; 101 info.info = "Useage: {goto}|{gt} {row}{' '|','|';'|':'|'/'}{col}".to_string(); 102 return WarpUiCallBackType::None; 103 } 104 let (y, x) = { 105 let a = args.split(|x| Self::is_split_char(x)).collect::<Vec<_>>(); 106 107 if a.len() == 1 { 108 (u16::from_str_radix(a[0], 10), Ok(1)) 109 } else { 110 (u16::from_str_radix(a[0], 10), u16::from_str_radix(a[1], 10)) 111 } 112 }; 113 114 if y.is_err() { 115 let mut info = APP_INFO.lock().unwrap(); 116 info.level = InfoLevel::Info; 117 info.info = "Useage: goto {row}({' '|','|';'|':'|'/'}{col})".to_string(); 118 return WarpUiCallBackType::None; 119 } 120 121 let buf_line_max = ui.buffer.line_count() as u16; 122 let content_line_max = CONTENT_WINSIZE.read().unwrap().rows; 123 let mut y = y.unwrap().min(buf_line_max); 124 let mut x = x.unwrap_or(1).min(ui.buffer.get_linesize(y)); 125 126 if y == 0 { 127 y += 1; 128 } 129 if x == 0 { 130 x += 1; 131 } 132 133 x -= 1; 134 y -= 1; 135 136 ui.cursor.set_prefix_mode(true); 137 138 ui.cursor.restore_pos().unwrap(); 139 140 // if y < ui.buffer.offset() as u16 + content_line_max { 141 // ui.buffer.set_offset(0); 142 // } else { 143 // ui.buffer.set_offset((y - content_line_max) as usize); 144 // } 145 146 let lasty = ui.cursor.y(); 147 let y = ui.buffer.goto_line(y as usize); 148 ui.cursor.move_to(x, y).unwrap(); 149 150 let pos = ui.cursor.store_tmp_pos(); 151 ui.render_content(0, content_line_max as usize).unwrap(); 152 ui.cursor.restore_tmp_pos(pos).unwrap(); 153 154 ui.cursor.highlight(Some(lasty)).unwrap(); 155 156 ui.cursor.store_pos(); 157 158 return WarpUiCallBackType::None; 159 } 160 161 // 标记行 flag(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType162 pub fn flag(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 163 let args = args.split(|x| Self::is_split_char(x)).collect::<Vec<_>>(); 164 165 if args.len() == 0 { 166 ui.buffer 167 .add_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::FLAGED); 168 } 169 170 for s in args { 171 let line = usize::from_str_radix(s, 10); 172 if line.is_err() { 173 APP_INFO.lock().unwrap().info = format!("\"{s}\" is not a number"); 174 return WarpUiCallBackType::None; 175 } 176 177 let line = line.unwrap(); 178 ui.buffer.add_line_flags(line - 1, LineState::FLAGED); 179 } 180 181 WarpUiCallBackType::None 182 } 183 184 // 锁定行 lock(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType185 pub fn lock(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 186 let args = args.split(|x| Self::is_split_char(x)).collect::<Vec<_>>(); 187 188 match args.len() { 189 0 => { 190 //没有参数,锁定当前行 191 ui.buffer 192 .add_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED) 193 } 194 _ => { 195 //有参数,锁定指定行 196 for arg in args { 197 let line = usize::from_str_radix(arg, 10); 198 if line.is_err() { 199 APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); 200 return WarpUiCallBackType::None; 201 } 202 203 let line = line.unwrap(); 204 ui.buffer.add_line_flags(line - 1, LineState::LOCKED); 205 } 206 } 207 } 208 209 WarpUiCallBackType::None 210 } 211 212 // 标记行 unflag(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType213 pub fn unflag(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 214 let args = args.split(|x| Self::is_split_char(x)).collect::<Vec<_>>(); 215 216 match args.len() { 217 0 => { 218 //没有参数,解除标记当前行 219 ui.buffer 220 .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::FLAGED) 221 } 222 _ => { 223 //有参数,解除标记指定行 224 for arg in args { 225 let line = usize::from_str_radix(arg, 10); 226 if line.is_err() { 227 APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); 228 return WarpUiCallBackType::None; 229 } 230 231 let line = line.unwrap(); 232 ui.buffer.remove_line_flags(line - 1, LineState::FLAGED); 233 } 234 } 235 } 236 237 WarpUiCallBackType::None 238 } 239 240 // 解除锁定行 unlock(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType241 pub fn unlock(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 242 let args = args.split(|x| Self::is_split_char(x)).collect::<Vec<_>>(); 243 244 match args.len() { 245 0 => { 246 //没有参数,解除锁定当前行 247 ui.buffer 248 .remove_line_flags(ui.cursor.cmd_y() as usize - 1, LineState::LOCKED) 249 } 250 _ => { 251 //有参数,解除锁定指定行 252 for arg in args { 253 let line = usize::from_str_radix(arg, 10); 254 if line.is_err() { 255 APP_INFO.lock().unwrap().info = format!("\"{arg}\" is not a number"); 256 return WarpUiCallBackType::None; 257 } 258 259 let line = line.unwrap(); 260 ui.buffer.remove_line_flags(line - 1, LineState::LOCKED); 261 } 262 } 263 } 264 265 WarpUiCallBackType::None 266 } 267 delete_lines(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType268 pub fn delete_lines(ui: &mut MutexGuard<UiCore>, args: &str) -> WarpUiCallBackType { 269 let args = args.split(|x| x == '-').collect::<Vec<_>>(); 270 271 match args.len() { 272 0 => { 273 let offset = ui.buffer.offset() + ui.cursor.y() as usize; 274 let count = ui.buffer.delete_lines(offset, offset + 1); 275 if count != 0 { 276 APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); 277 } 278 ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) 279 .unwrap(); 280 return WarpUiCallBackType::None; 281 } 282 1 => { 283 let line = usize::from_str_radix(args[0], 10); 284 if line.is_err() { 285 APP_INFO.lock().unwrap().info = format!("\"{}\" is not a number", args[0]); 286 return WarpUiCallBackType::None; 287 } 288 289 let line = line.unwrap(); 290 291 let offset = ui.buffer.offset() + line; 292 let count = ui.buffer.delete_lines(offset, offset + 1); 293 if count != 0 { 294 APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); 295 } 296 ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) 297 .unwrap(); 298 return WarpUiCallBackType::None; 299 } 300 _ => { 301 let start = usize::from_str_radix(args[0], 10); 302 let end = usize::from_str_radix(args[1], 10); 303 304 if start.is_err() || end.is_err() { 305 APP_INFO.lock().unwrap().info = 306 "Useage: (dl)|(delete) {start}({'-'}{end})".to_string(); 307 return WarpUiCallBackType::None; 308 } 309 310 let count = ui.buffer.delete_lines(start.unwrap() - 1, end.unwrap() - 1); 311 if count != 0 { 312 APP_INFO.lock().unwrap().info = format!("Successfully deleted {count} row"); 313 } 314 315 ui.render_content(0, CONTENT_WINSIZE.read().unwrap().rows as usize) 316 .unwrap(); 317 } 318 } 319 return WarpUiCallBackType::None; 320 } 321 } 322