summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2019-05-26 18:28:58 -0400
committerJiayi Zhao <jeff.no.zhao@gmail.com>2019-05-26 18:28:58 -0400
commit829d8b9ff0806ffc2da692f12b9e8a6f5c228aa4 (patch)
treefb018bafc4c8568d447825e5da3c17263d74466e
parent397506b398aa1cc6d03a154ae1792815131f8125 (diff)
update commands to use new textfield
-rw-r--r--Cargo.toml2
-rw-r--r--src/commands/command_line.rs40
-rw-r--r--src/commands/mod.rs145
-rw-r--r--src/commands/new_directory.rs31
-rw-r--r--src/commands/open_file.rs2
-rw-r--r--src/commands/rename_file.rs38
-rw-r--r--src/commands/search.rs2
-rw-r--r--src/commands/selection.rs2
-rw-r--r--src/commands/set_mode.rs12
-rw-r--r--src/textfield.rs32
10 files changed, 178 insertions, 128 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 65f6fa0..8a4ceec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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)
}