diff options
author | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2019-05-26 18:28:58 -0400 |
---|---|---|
committer | Jiayi Zhao <jeff.no.zhao@gmail.com> | 2019-05-26 18:28:58 -0400 |
commit | 829d8b9ff0806ffc2da692f12b9e8a6f5c228aa4 (patch) | |
tree | fb018bafc4c8568d447825e5da3c17263d74466e | |
parent | 397506b398aa1cc6d03a154ae1792815131f8125 (diff) |
update commands to use new textfield
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/commands/command_line.rs | 40 | ||||
-rw-r--r-- | src/commands/mod.rs | 145 | ||||
-rw-r--r-- | src/commands/new_directory.rs | 31 | ||||
-rw-r--r-- | src/commands/open_file.rs | 2 | ||||
-rw-r--r-- | src/commands/rename_file.rs | 38 | ||||
-rw-r--r-- | src/commands/search.rs | 2 | ||||
-rw-r--r-- | src/commands/selection.rs | 2 | ||||
-rw-r--r-- | src/commands/set_mode.rs | 12 | ||||
-rw-r--r-- | src/textfield.rs | 32 |
10 files changed, 178 insertions, 128 deletions
@@ -44,6 +44,8 @@ features = [ "extended_colors", "panel", "wide" ] [dependencies.wordexp] version = "^0" +git = "https://github.com/kamiyaa/wordexp-rs" +branch="dev" # path = "lib/wordexp-rs" [features] diff --git a/src/commands/command_line.rs b/src/commands/command_line.rs index e6f490f..80e907b 100644 --- a/src/commands/command_line.rs +++ b/src/commands/command_line.rs @@ -7,21 +7,22 @@ use crate::window::JoshutoView; #[derive(Clone, Debug)] pub struct CommandLine { - prefix: Option<String>, + pub prefix: String, + pub suffix: String, } impl CommandLine { - pub fn new(prefix: Option<String>) -> Self { - CommandLine { prefix } + pub fn new(prefix: String, suffix: String) -> Self { + CommandLine { prefix, suffix } } pub const fn command() -> &'static str { "console" } pub fn readline( + &self, context: &mut JoshutoContext, view: &JoshutoView, - prefix: Option<&String>, ) -> Result<(), JoshutoError> { const PROMPT: &str = ":"; let (term_rows, term_cols) = ui::getmaxyx(); @@ -31,11 +32,10 @@ impl CommandLine { term_cols, (term_rows as usize - 1, 0), PROMPT.to_string(), + self.prefix.clone(), + self.suffix.clone(), ); - match prefix { - Some(s) => textfield.readline_with_initial((s, "")), - None => textfield.readline(), - } + textfield.readline() }; if let Some(s) = user_input { @@ -44,12 +44,17 @@ impl CommandLine { Some(ind) => { let (command, xs) = trimmed.split_at(ind); let xs = xs.trim_start(); - match commands::from_args(command, xs) { + let wexp = wordexp::wordexp(xs, wordexp::Wordexp::new(0), 0); + let args: Vec<&str> = match wexp.as_ref() { + Ok(wexp) => wexp.iter().collect(), + Err(_) => Vec::new(), + }; + match commands::from_args(command, &args) { Ok(s) => s.execute(context, view), Err(e) => Err(JoshutoError::Keymap(e)), } } - None => match commands::from_args(trimmed, "") { + None => match commands::from_args(trimmed, &Vec::new()) { Ok(s) => s.execute(context, view), Err(e) => Err(JoshutoError::Keymap(e)), }, @@ -58,16 +63,21 @@ impl CommandLine { Ok(()) } } + pub fn readline_with( + context: &mut JoshutoContext, + view: &JoshutoView, + textfield: JoshutoTextField, + ) -> Result<(), JoshutoError> { + drop(textfield); + Ok(()) + } } impl JoshutoCommand for CommandLine {} impl std::fmt::Display for CommandLine { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self.prefix.as_ref() { - Some(s) => write!(f, "{}: {}", Self::command(), s), - None => write!(f, "{}", Self::command()), - } + write!(f, "{}: {} {}", Self::command(), self.prefix, self.suffix) } } @@ -77,7 +87,7 @@ impl JoshutoRunnable for CommandLine { context: &mut JoshutoContext, view: &JoshutoView, ) -> Result<(), JoshutoError> { - let res = Self::readline(context, view, self.prefix.as_ref()); + let res = self.readline(context, view); ncurses::doupdate(); res } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 8cea62a..23ad4f2 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -75,52 +75,62 @@ pub struct ProgressInfo { pub total_bytes: u64, } -pub fn from_args(command: &str, args: &str) -> Result<Box<JoshutoCommand>, KeymapError> { +pub fn from_args(command: &str, args: &Vec<&str>) -> Result<Box<JoshutoCommand>, KeymapError> { match command { - "cd" => match args { - "" => match HOME_DIR.as_ref() { + "cd" => match args.len() { + 0 => match HOME_DIR.as_ref() { Some(s) => Ok(Box::new(self::ChangeDirectory::new(s.clone()))), None => Err(KeymapError::new( Some("cd"), String::from("Cannot find home directory"), )), }, - ".." => Ok(Box::new(self::ParentDirectory::new())), - args => match wordexp::wordexp(args, wordexp::Wordexp::new(0), wordexp::WRDE_NOCMD) { - Ok(mut exp_strs) => match exp_strs.next() { - Some(exp_str) => { - Ok(Box::new(self::ChangeDirectory::new(PathBuf::from(exp_str)))) - } - None => Err(KeymapError::new( - Some("cd"), - format!("Failed to parse: {}", args), - )), - }, - Err(_) => Err(KeymapError::new( - Some("cd"), - format!("Failed to parse: {}", args), - )), + 1 => match args[0] { + ".." => Ok(Box::new(self::ParentDirectory::new())), + arg => Ok(Box::new(self::ChangeDirectory::new(PathBuf::from(arg)))), }, + i => Err(KeymapError::new( + Some("cd"), + format!("Expected 1 argument, got {}", i), + )), }, "close_tab" => Ok(Box::new(self::CloseTab::new())), "copy_files" => Ok(Box::new(self::CopyFiles::new())), - "console" => match args { - "" => Ok(Box::new(self::CommandLine::new(None))), - args => Ok(Box::new(self::CommandLine::new(Some(String::from(args))))), + "console" => match args.len() { + 0 => Ok(Box::new(self::CommandLine::new( + String::new(), + String::new(), + ))), + 1 => Ok(Box::new(self::CommandLine::new( + String::from(args[0]), + String::new(), + ))), + i => Err(KeymapError::new( + Some("console"), + format!("Expected 0 or 2 arguments, got {}", i), + )), }, - "cursor_move_down" => match args { - "" => Ok(Box::new(self::CursorMoveDown::new(1))), - args => match args.parse::<usize>() { + "cursor_move_down" => match args.len() { + 0 => Ok(Box::new(self::CursorMoveDown::new(1))), + 1 => match args[0].parse::<usize>() { Ok(s) => Ok(Box::new(self::CursorMoveDown::new(s))), Err(e) => Err(KeymapError::new(Some("cursor_move_down"), e.to_string())), }, + i => Err(KeymapError::new( + Some("cursor_move_down"), + format!("Expected 0 or 1 arguments, got {}", i), + )), }, - "cursor_move_up" => match args { - "" => Ok(Box::new(self::CursorMoveUp::new(1))), - args => match args.parse::<usize>() { + "cursor_move_up" => match args.len() { + 0 => Ok(Box::new(self::CursorMoveUp::new(1))), + 1 => match args[0].parse::<usize>() { Ok(s) => Ok(Box::new(self::CursorMoveUp::new(s))), - Err(e) => Err(KeymapError::new(Some("cursor_move_up"), e.to_string())), + Err(e) => Err(KeymapError::new(Some("cursor_move_down"), e.to_string())), }, + i => Err(KeymapError::new( + Some("cursor_move_down"), + format!("Expected 0 or 1 arguments, got {}", i), + )), }, "cursor_move_home" => Ok(Box::new(self::CursorMoveHome::new())), "cursor_move_end" => Ok(Box::new(self::CursorMoveEnd::new())), @@ -129,32 +139,24 @@ pub fn from_args(command: &str, args: &str) -> Result<Box<JoshutoCommand>, Keyma "cut_files" => Ok(Box::new(self::CutFiles::new())), "delete_files" => Ok(Box::new(self::DeleteFiles::new())), "force_quit" => Ok(Box::new(self::ForceQuit::new())), - "mkdir" => match args { - "" => Err(KeymapError::new( - Some("mkdir"), - String::from("mkdir requires additional parameter"), - )), - args => match wordexp::wordexp(args, wordexp::Wordexp::new(0), wordexp::WRDE_NOCMD) { - Ok(mut exp_strs) => match exp_strs.next() { - Some(exp_str) => Ok(Box::new(self::NewDirectory::new(PathBuf::from(exp_str)))), - None => Err(KeymapError::new( - Some("mkdir"), - format!("Failed to parse: {}", args), - )), - }, - Err(_) => Err(KeymapError::new( + "mkdir" => { + if args.len() == 0 { + Err(KeymapError::new( Some("mkdir"), - format!("Failed to parse: {}", args), - )), - }, - }, + String::from("mkdir requires additional parameter"), + )) + } else { + let paths: Vec<PathBuf> = args.iter().map(|s| PathBuf::from(s)).collect(); + Ok(Box::new(self::NewDirectory::new(paths))) + } + } "new_tab" => Ok(Box::new(self::NewTab::new())), "open_file" => Ok(Box::new(self::OpenFile::new())), "open_file_with" => Ok(Box::new(self::OpenFileWith::new())), "paste_files" => { let mut options = fs_extra::dir::CopyOptions::new(); - for arg in args.split_whitespace() { - match arg { + for arg in args { + match *arg { "--overwrite" => options.overwrite = true, "--skip_exist" => options.skip_exist = true, _ => { @@ -170,12 +172,20 @@ pub fn from_args(command: &str, args: &str) -> Result<Box<JoshutoCommand>, Keyma "quit" => Ok(Box::new(self::Quit::new())), "reload_dir_list" => Ok(Box::new(self::ReloadDirList::new())), "rename_file" => { - let method: RenameFileMethod = match args { - "prepend" => self::RenameFileMethod::Prepend, - "overwrite" => self::RenameFileMethod::Overwrite, - "append" => self::RenameFileMethod::Append, - _ => self::RenameFileMethod::Overwrite, - }; + let mut method: RenameFileMethod = self::RenameFileMethod::Append; + for arg in args { + match *arg { + "--prepend" => method = self::RenameFileMethod::Prepend, + "--overwrite" => method = self::RenameFileMethod::Overwrite, + "--append" => method = self::RenameFileMethod::Append, + _ => { + return Err(KeymapError::new( + Some("rename_file"), + format!("unknown option {}", arg), + )); + } + } + } Ok(Box::new(self::RenameFile::new(method))) } "search" => Ok(Box::new(self::Search::new())), @@ -184,8 +194,8 @@ pub fn from_args(command: &str, args: &str) -> Result<Box<JoshutoCommand>, Keyma "select_files" => { let mut toggle = false; let mut all = false; - for arg in args.split_whitespace() { - match arg { + for arg in args { + match *arg { "--toggle" => toggle = true, "--all" => all = true, _ => { @@ -199,16 +209,19 @@ pub fn from_args(command: &str, args: &str) -> Result<Box<JoshutoCommand>, Keyma Ok(Box::new(self::SelectFiles::new(toggle, all))) } "set_mode" => Ok(Box::new(self::SetMode::new())), - "tab_switch" => match args { - "" => Err(KeymapError::new( - Some("tab_switch"), - String::from("No option provided"), - )), - args => match args.parse::<i32>() { - Ok(s) => Ok(Box::new(self::TabSwitch::new(s))), - Err(e) => Err(KeymapError::new(Some("tab_switch"), e.to_string())), - }, - }, + "tab_switch" => { + if args.len() == 1 { + match args[0].parse::<i32>() { + Ok(s) => Ok(Box::new(self::TabSwitch::new(s))), + Err(e) => Err(KeymapError::new(Some("tab_switch"), e.to_string())), + } + } else { + Err(KeymapError::new( + Some("tab_switch"), + String::from("No option provided"), + )) + } + } "toggle_hidden" => Ok(Box::new(self::ToggleHiddenFiles::new())), inp => Err(KeymapError::new(None, format!("Unknown command: {}", inp))), } diff --git a/src/commands/new_directory.rs b/src/commands/new_directory.rs index 022ebe9..b388aa7 100644 --- a/src/commands/new_directory.rs +++ b/src/commands/new_directory.rs @@ -7,27 +7,16 @@ use crate::window::JoshutoView; #[derive(Clone, Debug)] pub struct NewDirectory { - path: path::PathBuf, + paths: Vec<path::PathBuf>, } impl NewDirectory { - pub fn new(path: path::PathBuf) -> Self { - NewDirectory { path } + pub fn new(paths: Vec<path::PathBuf>) -> Self { + NewDirectory { paths } } pub const fn command() -> &'static str { "mkdir" } - - fn new_directory( - context: &mut JoshutoContext, - view: &JoshutoView, - path: &path::Path, - ) -> Result<(), std::io::Error> { - std::fs::create_dir_all(path)?; - ReloadDirList::reload(context, view)?; - ncurses::doupdate(); - Ok(()) - } } impl JoshutoCommand for NewDirectory {} @@ -44,9 +33,17 @@ impl JoshutoRunnable for NewDirectory { context: &mut JoshutoContext, view: &JoshutoView, ) -> Result<(), JoshutoError> { - match Self::new_directory(context, view, self.path.as_path()) { - Ok(_) => Ok(()), - Err(e) => Err(JoshutoError::IO(e)), + for path in &self.paths { + match std::fs::create_dir_all(path) { + Ok(_) => {} + Err(e) => return Err(JoshutoError::IO(e)), + } + } + match ReloadDirList::reload(context, view) { + Ok(_) => {} + Err(e) => return Err(JoshutoError::IO(e)), } + ncurses::doupdate(); + Ok(()) } } diff --git a/src/commands/open_file.rs b/src/commands/open_file.rs index df66764..98d0c67 100644 --- a/src/commands/open_file.rs +++ b/src/commands/open_file.rs @@ -205,6 +205,8 @@ impl OpenFileWith { term_cols, (term_rows as usize - 1, 0), PROMPT.to_string(), + String::from(""), + String::from(""), ); user_input = textfield.readline(); } diff --git a/src/commands/rename_file.rs b/src/commands/rename_file.rs index b4fa83c..558ce74 100644 --- a/src/commands/rename_file.rs +++ b/src/commands/rename_file.rs @@ -32,29 +32,41 @@ impl RenameFile { path: &path::PathBuf, context: &mut JoshutoContext, view: &JoshutoView, - start_str: String, + initial: String, ) -> Result<(), std::io::Error> { const PROMPT: &str = ":rename_file "; let (term_rows, term_cols) = ui::getmaxyx(); let user_input: Option<String> = { - let textfield = JoshutoTextField::new( - 1, - term_cols, - (term_rows as usize - 1, 0), - PROMPT.to_string(), - ); - + let prefix: String; + let suffix: String; match self.method { RenameFileMethod::Append => { - if let Some(ext) = start_str.rfind('.') { - textfield.readline_with_initial((&start_str[0..ext], &start_str[ext..])) + if let Some(ext) = initial.rfind('.') { + prefix = String::from(&initial[0..ext]); + suffix = String::from(&initial[ext..]); } else { - textfield.readline_with_initial((&start_str, "")) + prefix = initial; + suffix = String::new(); } } - RenameFileMethod::Prepend => textfield.readline_with_initial(("", &start_str)), - RenameFileMethod::Overwrite => textfield.readline(), + RenameFileMethod::Prepend => { + prefix = String::new(); + suffix = initial; + } + RenameFileMethod::Overwrite => { + prefix = String::new(); + suffix = String::new(); + } } + let textfield = JoshutoTextField::new( + 1, + term_cols, + (term_rows as usize - 1, 0), + PROMPT.to_string(), + prefix, + suffix, + ); + textfield.readline() }; if let Some(s) = user_input { diff --git a/src/commands/search.rs b/src/commands/search.rs index 96db9b9..974568d 100644 --- a/src/commands/search.rs +++ b/src/commands/search.rs @@ -84,6 +84,8 @@ impl JoshutoRunnable for Search { term_cols, (term_rows as usize - 1, 0), PROMPT.to_string(), + String::new(), + String::new(), ); textfield.readline() diff --git a/src/commands/selection.rs b/src/commands/selection.rs index b27a238..c9a6982 100644 --- a/src/commands/selection.rs +++ b/src/commands/selection.rs @@ -53,6 +53,7 @@ impl JoshutoRunnable for SelectFiles { curr.selected = !curr.selected; } curr_tab.refresh_curr(&view.mid_win, context.config_t.scroll_offset); + ncurses::doupdate(); } } else { if !self.all { @@ -67,6 +68,7 @@ impl JoshutoRunnable for SelectFiles { curr.selected = true; } curr_tab.refresh_curr(&view.mid_win, context.config_t.scroll_offset); + ncurses::doupdate(); } } Ok(()) diff --git a/src/commands/set_mode.rs b/src/commands/set_mode.rs index eb55a99..4d5e6b8 100644 --- a/src/commands/set_mode.rs +++ b/src/commands/set_mode.rs @@ -30,23 +30,23 @@ impl SetMode { "set_mode" } - pub fn set_mode(&self, entry: &mut JoshutoDirEntry, start_str: String) -> bool { + pub fn set_mode(&self, entry: &mut JoshutoDirEntry, initial: String) -> bool { use std::os::unix::fs::PermissionsExt; const PROMPT: &str = ":set_mode "; let (term_rows, term_cols) = ui::getmaxyx(); - let user_input: Option<String>; - { + let user_input: Option<String> = { let textfield = JoshutoTextField::new( 1, term_cols, (term_rows as usize - 1, 0), PROMPT.to_string(), + initial, + String::new(), ); - - user_input = textfield.readline_with_initial((&start_str, "")); - } + textfield.readline() + }; ncurses::doupdate(); match user_input { diff --git a/src/textfield.rs b/src/textfield.rs index c1e7657..7942b88 100644 --- a/src/textfield.rs +++ b/src/textfield.rs @@ -25,20 +25,30 @@ impl CompletionTracker { pub struct JoshutoTextField { pub win: window::JoshutoPanel, pub prompt: String, + pub prefix: String, + pub suffix: String, } impl JoshutoTextField { - pub fn new(rows: i32, cols: i32, coord: (usize, usize), prompt: String) -> Self { + pub fn new( + rows: i32, + cols: i32, + coord: (usize, usize), + prompt: String, + prefix: String, + suffix: String, + ) -> Self { let win = window::JoshutoPanel::new(rows, cols, coord); ncurses::keypad(win.win, true); - JoshutoTextField { win, prompt } + JoshutoTextField { + win, + prompt, + prefix, + suffix, + } } pub fn readline(&self) -> Option<String> { - self.readline_with_initial(("", "")) - } - - pub fn readline_with_initial(&self, initial: (&str, &str)) -> Option<String> { self.win.move_to_top(); ncurses::timeout(-1); let win = self.win.win; @@ -51,13 +61,13 @@ impl JoshutoTextField { let mut line_buffer = line_buffer::LineBuffer::with_capacity(255); let completer = FilenameCompleter::new(); - line_buffer.insert_str(0, &initial.0); - line_buffer.insert_str(line_buffer.len(), &initial.1); - line_buffer.set_pos(initial.0.as_bytes().len()); + line_buffer.insert_str(0, &self.prefix); + line_buffer.insert_str(line_buffer.len(), &self.suffix); + line_buffer.set_pos(self.prefix.as_bytes().len()); let mut completion_tracker: Option<CompletionTracker> = None; - let mut curr_pos = unicode_width::UnicodeWidthStr::width(initial.0); + let mut curr_pos = unicode_width::UnicodeWidthStr::width(self.prefix.as_str()); loop { ncurses::mvwaddstr(win, coord.0, coord.1 as i32, line_buffer.as_str()); ncurses::wclrtoeol(win); @@ -155,7 +165,7 @@ impl JoshutoTextField { if line_buffer.as_str().is_empty() { None } else { -// let strin = rustyline::completion::unescape(line_buffer.as_str(), ESCAPE_CHAR).into_owned(); + // let strin = rustyline::completion::unescape(line_buffer.as_str(), ESCAPE_CHAR).into_owned(); let strin = line_buffer.to_string(); Some(strin) } |