summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiayi Zhao <jeff.no.zhao@gmail.com>2019-06-30 10:52:12 -0400
committerJiayi Zhao <jeff.no.zhao@gmail.com>2019-06-30 10:52:12 -0400
commit242bae74d7b97e4542afbd9b1c708b45919e9695 (patch)
tree30523aa94179d7535982ac5dfb2c9d0c21c8a566
parent9a082fe7f0633593a6e07feb404f6434bb944511 (diff)
add bulk_rename command
-rw-r--r--Cargo.toml1
-rw-r--r--src/commands/bulk_rename.rs127
-rw-r--r--src/commands/cursor_move.rs7
-rw-r--r--src/commands/delete_files.rs7
-rw-r--r--src/commands/mod.rs5
-rw-r--r--src/error.rs2
6 files changed, 145 insertions, 4 deletions
diff --git a/Cargo.toml b/Cargo.toml
index da8f523..438dd17 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,7 @@ lazy_static = "^1"
libc = "^0.2"
notify = "^4"
open = "1.2.2"
+rand = "^0"
rustyline = "^4.1"
serde = "^1"
serde_derive = "^1"
diff --git a/src/commands/bulk_rename.rs b/src/commands/bulk_rename.rs
new file mode 100644
index 0000000..2db758f
--- /dev/null
+++ b/src/commands/bulk_rename.rs
@@ -0,0 +1,127 @@
+use std::io::{BufRead, Write};
+use std::path;
+use std::process;
+
+use rand::Rng;
+
+use crate::context::JoshutoContext;
+use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
+use crate::window::JoshutoView;
+use crate::commands::{JoshutoCommand, JoshutoRunnable, ReloadDirList};
+
+#[derive(Clone, Debug)]
+pub struct BulkRename;
+
+impl BulkRename {
+ pub fn new() -> Self {
+ BulkRename {}
+ }
+ pub const fn command() -> &'static str {
+ "bulk_rename"
+ }
+
+ pub fn bulk_rename(context: &mut JoshutoContext) -> JoshutoResult<()> {
+ const PREFIX: &str = "joshuto-";
+ let editor = match std::env::var("EDITOR") {
+ Ok(s) => s,
+ Err(_) => return Err(JoshutoError::new(
+ JoshutoErrorKind::EnvVarNotPresent,
+ String::from("EDITOR environment variable not set"),
+ )),
+ };
+
+ let curr_tab = &context.tabs[context.curr_tab_index];
+
+ let paths = curr_tab.curr_list.get_selected_paths();
+ let mut rand_str = String::with_capacity(PREFIX.len() + 10);
+ rand_str.push_str(PREFIX);
+
+ rand::thread_rng()
+ .sample_iter(&rand::distributions::Alphanumeric)
+ .take(10)
+ .for_each(|ch| rand_str.push(ch));
+
+ let mut file_path = path::PathBuf::from("/tmp");
+ file_path.push(rand_str);
+
+ {
+ let mut file = std::fs::File::create(&file_path)?;
+ for path in &paths {
+ let file_name = path.file_name().unwrap();
+ let file_name_as_bytes = file_name.to_str().unwrap().as_bytes();
+ file.write(file_name_as_bytes)?;
+ file.write(&['\n' as u8])?;
+ }
+ }
+
+ let mut command = process::Command::new(editor);
+ command.arg(&file_path);
+
+ /* exit curses and launch program */
+ {
+ ncurses::savetty();
+ ncurses::endwin();
+ let mut handle = command.spawn()?;
+ handle.wait()?;
+ }
+
+ let mut paths_renamed: Vec<path::PathBuf> = Vec::with_capacity(paths.len());
+ {
+ let file = std::fs::File::open(&file_path)?;
+
+ let reader = std::io::BufReader::new(file);
+ for line in reader.lines() {
+ let line2 = line?;
+ let line = line2.trim();
+ if line.len() == 0 {
+ continue;
+ }
+ let path = path::PathBuf::from(line);
+ paths_renamed.push(path);
+ }
+ }
+
+ for (p, q) in paths.iter().zip(paths_renamed.iter()) {
+ println!("{:?} -> {:?}", p, q);
+ }
+ print!("Continue with rename? (y/N): ");
+ std::io::stdout().flush()?;
+
+ let mut user_input = String::with_capacity(4);
+ std::io::stdin().read_line(&mut user_input)?;
+ user_input = user_input.to_lowercase();
+
+ let user_input_trimmed = user_input.trim();
+ if user_input_trimmed == "y" || user_input_trimmed == "yes" {
+ for (p, q) in paths.iter().zip(paths_renamed.iter()) {
+ std::fs::rename(p, q)?;
+ }
+ }
+ std::fs::remove_file(file_path)?;
+
+ /* restore ncurses */
+ ncurses::resetty();
+ ncurses::refresh();
+ ncurses::doupdate();
+ Ok(())
+ }
+}
+
+impl JoshutoCommand for BulkRename {}
+
+impl std::fmt::Display for BulkRename {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "{}", Self::command())
+ }
+}
+
+impl JoshutoRunnable for BulkRename {
+ fn execute(&self, context: &mut JoshutoContext, view: &JoshutoView) -> JoshutoResult<()> {
+ Self::bulk_rename(context)?;
+ ReloadDirList::reload(context.curr_tab_index, context)?;
+ let curr_tab = &mut context.tabs[context.curr_tab_index];
+ curr_tab.refresh(view, &context.config_t);
+ ncurses::doupdate();
+ Ok(())
+ }
+}
diff --git a/src/commands/cursor_move.rs b/src/commands/cursor_move.rs
index 1ed3537..adc7266 100644
--- a/src/commands/cursor_move.rs
+++ b/src/commands/cursor_move.rs
@@ -22,7 +22,12 @@ pub fn cursor_move(mut new_index: usize, context: &mut JoshutoContext, view: &Jo
}
}
- curr_tab.refresh(&view, &context.config_t);
+ curr_tab.refresh_curr(&view.mid_win, &context.config_t);
+ if context.config_t.show_preview {
+ curr_tab.refresh_preview(&view.right_win, &context.config_t);
+ }
+ curr_tab.refresh_path_status(&view.top_win, &context.config_t);
+ curr_tab.refresh_file_status(&view.bot_win);
ncurses::doupdate();
}
diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs
index ac66c9d..adaed07 100644
--- a/src/commands/delete_files.rs
+++ b/src/commands/delete_files.rs
@@ -77,7 +77,12 @@ impl JoshutoRunnable for DeleteFiles {
fn execute(&self, context: &mut JoshutoContext, view: &JoshutoView) -> JoshutoResult<()> {
Self::delete_files(context, view)?;
let curr_tab = &mut context.tabs[context.curr_tab_index];
- curr_tab.refresh(view, &context.config_t);
+ curr_tab.refresh_curr(&view.mid_win, &context.config_t);
+ if context.config_t.show_preview {
+ curr_tab.refresh_preview(&view.right_win, &context.config_t);
+ }
+ curr_tab.refresh_path_status(&view.top_win, &context.config_t);
+ curr_tab.refresh_file_status(&view.bot_win);
ncurses::doupdate();
Ok(())
}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 1656af9..1009c69 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -1,3 +1,4 @@
+mod bulk_rename;
mod change_directory;
mod command_line;
mod cursor_move;
@@ -16,6 +17,7 @@ mod show_hidden;
mod tab_operations;
mod tab_switch;
+pub use self::bulk_rename::BulkRename;
pub use self::change_directory::ChangeDirectory;
pub use self::command_line::CommandLine;
pub use self::cursor_move::{
@@ -70,11 +72,12 @@ impl std::fmt::Display for CommandKeybind {
pub fn from_args(command: &str, args: &[&str]) -> JoshutoResult<Box<JoshutoCommand>> {
match command {
+ "bulk_rename" => Ok(Box::new(self::BulkRename::new())),
"cd" => match args.len() {
0 => match HOME_DIR.as_ref() {
Some(s) => Ok(Box::new(self::ChangeDirectory::new(s.clone()))),
None => Err(JoshutoError::new(
- JoshutoErrorKind::EnvVarNotFound,
+ JoshutoErrorKind::EnvVarNotPresent,
format!("{}: Cannot find home directory", command),
)),
},
diff --git a/src/error.rs b/src/error.rs
index 963964d..43d1d3e 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -24,7 +24,7 @@ pub enum JoshutoErrorKind {
IOUnexpectedEof,
// environment variable not found
- EnvVarNotFound,
+ EnvVarNotPresent,
ParseError,
UnknownCommand,