summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKamiyaa <jeff.no.zhao@gmail.com>2020-06-06 15:00:15 -0400
committerKamiyaa <jeff.no.zhao@gmail.com>2020-06-06 15:00:15 -0400
commit4f3842b56f1729dcd8e81c77f98253ed9dfb23b3 (patch)
treea9cb1b5c300fcbdbcdfad34f0076919e30f03c88
parenta462ebe2140323a6085ce5a064727288fa4dff3c (diff)
shell command now parses correctly
- rework file operations - simpler model for listening on io_worker progress - cargo fmt/clippy
-rw-r--r--Cargo.toml9
-rw-r--r--src/commands/bulk_rename.rs4
-rw-r--r--src/commands/file_ops/copy.rs13
-rw-r--r--src/commands/file_ops/cut.rs13
-rw-r--r--src/commands/file_ops/local_state.rs49
-rw-r--r--src/commands/file_ops/mod.rs9
-rw-r--r--src/commands/file_ops/paste.rs32
-rw-r--r--src/commands/file_ops/paste_copy.rs82
-rw-r--r--src/commands/file_ops/paste_cut.rs94
-rw-r--r--src/commands/mod.rs39
-rw-r--r--src/commands/open_file.rs2
-rw-r--r--src/commands/quit.rs2
-rw-r--r--src/commands/shell.rs44
-rw-r--r--src/commands/show_hidden.rs5
-rw-r--r--src/commands/sort.rs1
-rw-r--r--src/config/keymap.rs4
-rw-r--r--src/config/mimetype.rs8
-rw-r--r--src/config/theme.rs2
-rw-r--r--src/context.rs72
-rw-r--r--src/fs/dirlist.rs15
-rw-r--r--src/fs/entry.rs2
-rw-r--r--src/history.rs13
-rw-r--r--src/io/io_worker.rs147
-rw-r--r--src/io/mod.rs4
-rw-r--r--src/io/name_resolution.rs (renamed from src/commands/file_ops/name_resolution.rs)0
-rw-r--r--src/run.rs83
-rw-r--r--src/ui/widgets/tui_dirlist.rs42
-rw-r--r--src/ui/widgets/tui_footer.rs9
-rw-r--r--src/ui/widgets/tui_menu.rs5
-rw-r--r--src/ui/widgets/tui_textfield.rs2
-rw-r--r--src/ui/widgets/tui_view.rs4
-rw-r--r--src/util/event.rs7
-rw-r--r--src/util/key_mapping.rs4
33 files changed, 392 insertions, 429 deletions
diff --git a/Cargo.toml b/Cargo.toml
index dfab733..ecaab1d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ rand = "^0"
rustyline = "^4"
serde = "^1"
serde_derive = "^1"
+shell-words = "^1"
structopt = "^0"
termion = "^1"
toml = "^0"
@@ -38,10 +39,10 @@ xdg = "^2"
# whoami = "*"
# xdg = "*"
-[dependencies.wordexp]
-version = "^0"
-git = "https://github.com/kamiyaa/wordexp-rs"
-branch="dev"
+# [dependencies.wordexp]
+# version = "^0"
+# git = "https://github.com/kamiyaa/wordexp-rs"
+# branch="dev"
# path = "lib/wordexp-rs"
[features]
diff --git a/src/commands/bulk_rename.rs b/src/commands/bulk_rename.rs
index 2fff733..dc60c67 100644
--- a/src/commands/bulk_rename.rs
+++ b/src/commands/bulk_rename.rs
@@ -56,8 +56,8 @@ impl BulkRename {
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(&[b'\n'])?;
+ file.write_all(file_name_as_bytes)?;
+ file.write_all(&[b'\n'])?;
}
}
diff --git a/src/commands/file_ops/copy.rs b/src/commands/file_ops/copy.rs
index a7edbef..7e05752 100644
--- a/src/commands/file_ops/copy.rs
+++ b/src/commands/file_ops/copy.rs
@@ -1,9 +1,10 @@
use crate::commands::{JoshutoCommand, JoshutoRunnable};
use crate::context::JoshutoContext;
use crate::error::JoshutoResult;
+use crate::io::FileOp;
use crate::ui::TuiBackend;
-use super::local_state::{FileOp, LocalState};
+use super::local_state::LocalState;
#[derive(Clone, Debug)]
pub struct CopyFiles;
@@ -28,13 +29,9 @@ impl std::fmt::Display for CopyFiles {
impl JoshutoRunnable for CopyFiles {
fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
let curr_tab = context.curr_tab_ref();
- match curr_tab.curr_list_ref() {
- Some(list) => {
- LocalState::repopulated_selected_files(list)?;
- LocalState::set_file_op(FileOp::Copy);
- LocalState::set_tab_src(context.curr_tab_index);
- }
- None => {}
+ if let Some(list) = curr_tab.curr_list_ref() {
+ LocalState::repopulate(list)?;
+ LocalState::set_file_op(FileOp::Copy);
}
Ok(())
}
diff --git a/src/commands/file_ops/cut.rs b/src/commands/file_ops/cut.rs
index 42ec7f2..772e091 100644
--- a/src/commands/file_ops/cut.rs
+++ b/src/commands/file_ops/cut.rs
@@ -1,9 +1,10 @@
use crate::commands::{JoshutoCommand, JoshutoRunnable};
use crate::context::JoshutoContext;
use crate::error::JoshutoResult;
+use crate::io::FileOp;
use crate::ui::TuiBackend;
-use super::local_state::{FileOp, LocalState};
+use super::local_state::LocalState;
#[derive(Clone, Debug)]
pub struct CutFiles;
@@ -28,13 +29,9 @@ impl std::fmt::Display for CutFiles {
impl JoshutoRunnable for CutFiles {
fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
let curr_tab = context.curr_tab_ref();
- match curr_tab.curr_list_ref() {
- Some(list) => {
- LocalState::repopulated_selected_files(list)?;
- LocalState::set_file_op(FileOp::Cut);
- LocalState::set_tab_src(context.curr_tab_index);
- }
- None => {}
+ if let Some(list) = curr_tab.curr_list_ref() {
+ LocalState::repopulate(list)?;
+ LocalState::set_file_op(FileOp::Cut);
}
Ok(())
}
diff --git a/src/commands/file_ops/local_state.rs b/src/commands/file_ops/local_state.rs
index 12ffa6c..f8a4782 100644
--- a/src/commands/file_ops/local_state.rs
+++ b/src/commands/file_ops/local_state.rs
@@ -1,35 +1,33 @@
use lazy_static::lazy_static;
-use std::path;
-use std::sync::{atomic, Mutex};
-
use crate::fs::JoshutoDirList;
+use crate::io::FileOp;
+use std::path;
+use std::sync::Mutex;
lazy_static! {
- static ref SELECTED_FILES: Mutex<Option<Vec<path::PathBuf>>> = Mutex::new(None);
- static ref FILE_OPERATION: Mutex<FileOp> = Mutex::new(FileOp::Copy);
- static ref TAB_SRC: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+ static ref LOCAL_STATE: Mutex<LocalState> = Mutex::new(LocalState::new());
}
-#[derive(Clone, Debug)]
-pub enum FileOp {
- Cut,
- Copy,
+pub struct LocalState {
+ pub paths: Vec<path::PathBuf>,
+ pub file_op: FileOp,
}
-pub struct LocalState;
-
impl LocalState {
- pub fn set_file_op(operation: FileOp) {
- let mut data = FILE_OPERATION.lock().unwrap();
- *data = operation;
+ pub fn new() -> Self {
+ Self {
+ paths: Vec::new(),
+ file_op: FileOp::Copy,
+ }
}
- pub fn set_tab_src(tab_index: usize) {
- TAB_SRC.store(tab_index, atomic::Ordering::Release);
+ pub fn set_file_op(operation: FileOp) {
+ let mut data = LOCAL_STATE.lock().unwrap();
+ (*data).file_op = operation;
}
- pub fn repopulated_selected_files(dirlist: &JoshutoDirList) -> std::io::Result<()> {
+ pub fn repopulate(dirlist: &JoshutoDirList) -> std::io::Result<()> {
let selected = dirlist.get_selected_paths();
if selected.is_empty() {
Err(std::io::Error::new(
@@ -39,17 +37,16 @@ impl LocalState {
} else {
let selected_clone: Vec<path::PathBuf> =
selected.iter().map(|p| (*p).clone()).collect();
- let mut data = SELECTED_FILES.lock().unwrap();
- *data = Some(selected_clone);
+ let mut data = LOCAL_STATE.lock().unwrap();
+ (*data).paths = selected_clone;
Ok(())
}
}
- pub fn take_selected_files() -> Option<Vec<path::PathBuf>> {
- SELECTED_FILES.lock().unwrap().take()
- }
-
- pub fn get_file_operation() -> FileOp {
- (*FILE_OPERATION.lock().unwrap()).clone()
+ pub fn take() -> LocalState {
+ let mut m = LOCAL_STATE.lock().unwrap();
+ let mut v = LocalState::new();
+ std::mem::swap(&mut (*m), &mut v);
+ v
}
}
diff --git a/src/commands/file_ops/mod.rs b/src/commands/file_ops/mod.rs
index e4a0da3..1ed8030 100644
--- a/src/commands/file_ops/mod.rs
+++ b/src/commands/file_ops/mod.rs
@@ -1,11 +1,8 @@
mod copy;
mod cut;
mod local_state;
-mod name_resolution;
mod paste;
-mod paste_copy;
-mod paste_cut;
-pub use self::copy::CopyFiles;
-pub use self::cut::CutFiles;
-pub use self::paste::PasteFiles;
+pub use copy::CopyFiles;
+pub use cut::CutFiles;
+pub use paste::PasteFiles;
diff --git a/src/commands/file_ops/paste.rs b/src/commands/file_ops/paste.rs
index 74136c6..019a558 100644
--- a/src/commands/file_ops/paste.rs
+++ b/src/commands/file_ops/paste.rs
@@ -1,15 +1,13 @@
use crate::commands::{JoshutoCommand, JoshutoRunnable};
use crate::context::JoshutoContext;
-use crate::error::JoshutoResult;
-use crate::io::Options;
+use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
+use crate::io::{IOWorkerOptions, IOWorkerThread};
use crate::ui::TuiBackend;
-use super::local_state::{FileOp, LocalState};
-use super::paste_copy::paste_copy;
-use super::paste_cut::paste_cut;
+use super::local_state::LocalState;
pub struct PasteFiles {
- options: Options,
+ options: IOWorkerOptions,
}
impl JoshutoCommand for PasteFiles {}
@@ -34,19 +32,25 @@ impl std::fmt::Debug for PasteFiles {
impl JoshutoRunnable for PasteFiles {
fn execute(&self, context: &mut JoshutoContext, _: &mut TuiBackend) -> JoshutoResult<()> {
- let file_operation = LocalState::get_file_operation();
- let thread = match file_operation {
- FileOp::Copy => paste_copy(context, self.options.clone()),
- FileOp::Cut => paste_cut(context, self.options.clone()),
- };
- let thread = thread?;
- context.add_new_worker(thread);
+ let state = LocalState::take();
+ if state.paths.is_empty() {
+ Err(JoshutoError::new(
+ JoshutoErrorKind::IOInvalidData,
+ "no files selected".to_string(),
+ ))?;
+ }
+ let tab_dest = context.curr_tab_index;
+ let dest = context.tabs[tab_dest].curr_path.clone();
+ let mut options = self.options.clone();
+ options.kind = state.file_op;
+ let worker_thread = IOWorkerThread::new(options, state.paths, dest);
+ context.push_worker_thread(worker_thread);
Ok(())
}
}
impl PasteFiles {
- pub fn new(options: Options) -> Self {
+ pub fn new(options: IOWorkerOptions) -> Self {
PasteFiles { options }
}
pub const fn command() -> &'static str {
diff --git a/src/commands/file_ops/paste_copy.rs b/src/commands/file_ops/paste_copy.rs
deleted file mode 100644
index 5fad0e4..0000000
--- a/src/commands/file_ops/paste_copy.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::fs;
-use std::path::Path;
-use std::sync::mpsc;
-use std::thread;
-
-use crate::context::JoshutoContext;
-use crate::io::{IOWorkerThread, Options};
-
-use super::local_state::LocalState;
-use super::name_resolution::rename_filename_conflict;
-
-pub fn recursive_copy(dest: &Path, src: &Path, options: &Options) -> std::io::Result<u64> {
- let mut dest_buf = dest.to_path_buf();
- if let Some(s) = src.file_name() {
- dest_buf.push(s);
- }
- rename_filename_conflict(&mut dest_buf);
- let file_type = fs::symlink_metadata(src)?.file_type();
- if file_type.is_dir() {
- fs::create_dir(dest_buf.as_path())?;
- let mut total = 0;
- for entry in fs::read_dir(src)? {
- let entry = entry?;
- let entry_path = entry.path();
- total += recursive_copy(dest_buf.as_path(), entry_path.as_path(), options)?;
- }
- Ok(total)
- } else if file_type.is_file() {
- fs::copy(src, dest_buf)
- } else if file_type.is_symlink() {
- let link_path = fs::read_link(src)?;
- std::os::unix::fs::symlink(link_path, dest_buf)?;
- Ok(0)
- } else {
- Ok(0)
- }
-}
-
-pub fn paste_copy(
- context: &mut JoshutoContext,
- options: Options,
-) -> std::io::Result<IOWorkerThread> {
- let paths = LocalState::take_selected_files()
- .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "no files selected"))?;
- if paths.is_empty() {
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
- "no files selected",
- ));
- }
-
- let tab_dest = context.curr_tab_index;
- let thread_dest = context.tabs[tab_dest].curr_path.clone();
- let dest = thread_dest.clone();
- let src = paths[0].parent().unwrap().to_path_buf();
-
- let (tx_start, rx_start) = mpsc::channel();
- let (tx, rx) = mpsc::channel();
-
- let handle: thread::JoinHandle<std::io::Result<u64>> =
- thread::spawn(move || match rx_start.recv() {
- Ok(_) => {
- let mut total = 0;
- for path in paths {
- total += recursive_copy(thread_dest.as_path(), path.as_path(), &options)?;
- tx.send(total);
- }
- Ok(total)
- }
- Err(_) => Ok(0),
- });
-
- let thread = IOWorkerThread {
- src,
- dest,
- handle,
- tx_start,
- rx,
- };
-
- Ok(thread)
-}
diff --git a/src/commands/file_ops/paste_cut.rs b/src/commands/file_ops/paste_cut.rs
deleted file mode 100644
index 6ae1569..0000000
--- a/src/commands/file_ops/paste_cut.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use std::fs;
-use std::path::Path;
-use std::sync::mpsc;
-use std::thread;
-
-use crate::context::JoshutoContext;
-use crate::io::{IOWorkerThread, Options};
-
-use super::local_state::LocalState;
-use super::name_resolution::rename_filename_conflict;
-
-pub fn recursive_cut(dest: &Path, src: &Path, options: &Options) -> std::io::Result<u64> {
- let mut dest_buf = dest.to_path_buf();
- if let Some(s) = src.file_name() {
- dest_buf.push(s);
- }
- rename_filename_conflict(&mut dest_buf);
- let metadata = fs::symlink_metadata(src)?;
- let file_type = metadata.file_type();
- if file_type.is_dir() {
- match fs::rename(src, dest_buf.as_path()) {
- Ok(_) => Ok(metadata.len()),
- Err(_) => {
- let mut total = 0;
- fs::create_dir(dest_buf.as_path())?;
- for entry in fs::read_dir(src)? {
- let entry = entry?;
- let entry_path = entry.path();
- total += recursive_cut(dest_buf.as_path(), entry_path.as_path(), options)?;
- }
- fs::remove_dir(src)?;
- Ok(total)
- }
- }
- } else if file_type.is_file() {
- if fs::rename(src, dest_buf.as_path()).is_err() {
- fs::copy(src, dest_buf.as_path())?;
- fs::remove_file(src)?;
- }
- Ok(metadata.len())
- } else if file_type.is_symlink() {
- let link_path = fs::read_link(src)?;
- std::os::unix::fs::symlink(link_path, dest_buf)?;
- fs::remove_file(src)?;
- Ok(metadata.len())
- } else {
- Ok(0)
- }
-}
-
-pub fn paste_cut(
- context: &mut JoshutoContext,
- options: Options,
-) -> std::io::Result<IOWorkerThread> {
- let paths = LocalState::take_selected_files()
- .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "no files selected"))?;
- if paths.is_empty() {
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
- "no files selected",
- ));
- }
-
- let tab_dest = context.curr_tab_index;
- let thread_dest = context.tabs[tab_dest].curr_path.clone();
- let dest = thread_dest.clone();
- let src = paths[0].parent().unwrap().to_path_buf();
-
- let (tx_start, rx_start) = mpsc::channel();
- let (tx, rx) = mpsc::channel();
-
- let handle: thread::JoinHandle<std::io::Result<u64>> =
- thread::spawn(move || match rx_start.recv() {
- Ok(_) => {
- let mut total = 0;
- for path in paths {
- total += recursive_cut(thread_dest.as_path(), path.as_path(), &options)?;
- tx.send(total);
- }
- Ok(total)
- }
- Err(_) => Ok(0),
- });
-
- let thread = IOWorkerThread {
- src,
- dest,
- handle,
- tx_start,
- rx,
- };
-
- Ok(thread)
-}
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index f276d8d..6c5940d 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -40,7 +40,7 @@ pub use self::selection::SelectFiles;
pub use self::set_mode::SetMode;
pub use self::shell::ShellCommand;
pub use self::show_hidden::ToggleHiddenFiles;
-pub use self::sort::{Sort,SortReverse};
+pub use self::sort::{Sort, SortReverse};
pub use self::tab_operations::{CloseTab, NewTab};
pub use self::tab_switch::TabSwitch;
@@ -49,7 +49,7 @@ use std::path::PathBuf;
use crate::config::JoshutoCommandMapping;
use crate::context::JoshutoContext;
use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult};
-use crate::io::Options;
+use crate::io::IOWorkerOptions;
use crate::ui::TuiBackend;
use crate::util::sort::SortType;
@@ -78,7 +78,7 @@ pub trait JoshutoCommand: JoshutoRunnable + std::fmt::Display + std::fmt::Debug
pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
let (command, arg) = match s.find(' ') {
- Some(i) => (&s[..i], s[i+1..].trim_start()),
+ Some(i) => (&s[..i], s[i + 1..].trim_start()),
None => (s, ""),
};
@@ -94,10 +94,13 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
},
".." => Ok(Box::new(self::ParentDirectory::new())),
arg => Ok(Box::new(self::ChangeDirectory::new(PathBuf::from(arg)))),
- }
+ },
"close_tab" => Ok(Box::new(self::CloseTab::new())),
"copy_files" => Ok(Box::new(self::CopyFiles::new())),
- "console" => Ok(Box::new(self::CommandLine::new(arg.to_owned(), "".to_owned()))),
+ "console" => Ok(Box::new(self::CommandLine::new(
+ arg.to_owned(),
+ "".to_owned(),
+ ))),
"cursor_move_home" => Ok(Box::new(self::CursorMoveHome::new())),
"cursor_move_end" => Ok(Box::new(self::CursorMoveEnd::new())),
"cursor_move_page_up" => Ok(Box::new(self::CursorMovePageUp::new())),
@@ -111,7 +114,7 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
e.to_string(),
)),
},
- }
+ },
"cursor_move_up" => match arg {
"" => Ok(Box::new(self::CursorMoveUp::new(1))),
arg => match arg.parse::<usize>() {
@@ -121,7 +124,7 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
e.to_string(),
)),
},
- }
+ },
"cut_files" => Ok(Box::new(self::CutFiles::new())),
"delete_files" => Ok(Box::new(self::DeleteFiles::new())),
"force_quit" => Ok(Box::new(self::ForceQuit::new())),
@@ -131,13 +134,13 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
format!("{}: missing additional parameter", command),
)),
arg => Ok(Box::new(self::NewDirectory::new(PathBuf::from(arg)))),
- }
+ },
"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 = Options::default();
+ let mut options = IOWorkerOptions::default();
for arg in arg.split_whitespace() {
match arg {
"--overwrite" => options.overwrite = true,
@@ -157,7 +160,7 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
"rename" => match arg {
"" => Err(JoshutoError::new(
JoshutoErrorKind::IOInvalidData,
- format!("rename_file: Expected 1, got 0"),
+ format!("{}: Expected 1, got 0", command),
)),
arg => {
let path: PathBuf = PathBuf::from(arg);
@@ -193,7 +196,17 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
Ok(Box::new(self::SelectFiles::new(toggle, all)))
}
"set_mode" => Ok(Box::new(self::SetMode::new())),
- "shell" => Ok(Box::new(self::ShellCommand::new(arg.to_owned()))),
+ "shell" => match shell_words::split(arg) {
+ Ok(s) if !s.is_empty() => Ok(Box::new(self::ShellCommand::new(s))),
+ Ok(_) => Err(JoshutoError::new(
+ JoshutoErrorKind::IOInvalidData,
+ format!("sort: args {}", arg),
+ )),
+ Err(e) => Err(JoshutoError::new(
+ JoshutoErrorKind::IOInvalidData,
+ format!("{}: {}", arg, e),
+ )),
+ },
"sort" => match arg {
"reverse" => Ok(Box::new(self::SortReverse::new())),
arg => match SortType::parse(arg) {
@@ -215,8 +228,8 @@ pub fn parse_command(s: &str) -> JoshutoResult<Box<dyn JoshutoCommand>> {
JoshutoErrorKind::IOInvalidData,
format!("{}: {}", command, e.to_string()),
)),
- }
- }
+ },
+ },
"toggle_hidden" => Ok(Box::new(self::ToggleHiddenFiles::new())),
inp => Err(JoshutoError::new(
JoshutoErrorKind::UnknownCommand,
diff --git a/src/commands/open_file.rs b/src/commands/open_file.rs
index 5c3c966..f7af489 100644
--- a/src/commands/open_file.rs
+++ b/src/commands/open_file.rs
@@ -1,5 +1,3 @@
-use std::path::Path;
-
use crate::commands::{ChangeDirectory, JoshutoCommand, JoshutoRunnable};
use crate::config::mimetype::JoshutoMimetypeEntry;
use crate::context::JoshutoContext;
diff --git a/src/commands/quit.rs b/src/commands/quit.rs
index 45283c1..2da6f6b 100644
--- a/src/commands/quit.rs
+++ b/src/commands/quit.rs
@@ -15,7 +15,7 @@ impl Quit {
}
pub fn quit(context: &mut JoshutoContext) -> JoshutoResult<()> {
- if context.worker_busy {
+ if context.worker.is_busy() {
Err(JoshutoError::new(
JoshutoErrorKind::IOOther,
String::from("operations running in background, use force_quit to quit"),
diff --git a/src/commands/shell.rs b/src/commands/shell.rs
index 19e901d..b9cbd1c 100644
--- a/src/commands/shell.rs
+++ b/src/commands/shell.rs
@@ -1,26 +1,48 @@
use std::process;
-use crate::commands::{self, JoshutoCommand, JoshutoRunnable};
+use crate::commands::{JoshutoCommand, JoshutoRunnable, ReloadDirList};
use crate::context::JoshutoContext;
use crate::error::JoshutoResult;
-use crate::ui::widgets::TuiTextField;
use crate::ui::TuiBackend;
#[derive(Clone, Debug)]
pub struct ShellCommand {
- pub command: String,
+ pub words: Vec<String>,
}
impl ShellCommand {
- pub fn new(command: String) -> Self {
- Self { command }
+ pub fn new(words: Vec<String>) -> Self {
+ Self { words }
}
pub const fn command() -> &'static str {
"console"
}
- pub fn shell_command(command: &str) -> std::io::Result<()> {
- let mut command = process::Command::new("sh").arg("-c").arg(command).spawn()?;
+ pub fn shell_command(&self, context: &mut JoshutoContext) -> std::io::Result<()> {
+ let mut command = process::Command::new(self.words[0].clone());
+ for word in self.words.iter().skip(1) {
+ match word.as_str() {
+ "%s" => {
+ let curr_tab = context.curr_tab_ref();
+ if let Some(curr_list) = curr_tab.curr_list_ref() {
+ let mut i = 0;
+ for entry in curr_list.selected_entries().map(|e| e.file_name()) {
+ command.arg(entry);
+ i += 1;
+ }
+ if i == 0 {
+ if let Some(entry) = curr_list.get_curr_ref() {
+ command.arg(entry.file_name());
+ }
+ }
+ }
+ }
+ s => {
+ command.arg(s);
+ }
+ };
+ }
+ command.status()?;
Ok(())
}
}
@@ -29,14 +51,18 @@ impl JoshutoCommand for ShellCommand {}
impl std::fmt::Display for ShellCommand {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "{}: sh -c '{}'", Self::command(), self.command)
+ write!(f, "{}: {:?}", Self::command(), self.words.join(" "))
}
}
impl JoshutoRunnable for ShellCommand {
fn execute(&self, context: &mut JoshutoContext, backend: &mut TuiBackend) -> JoshutoResult<()> {
backend.terminal_drop();
- let res = Self::shell_command(self.command.as_str());
+ let res = self.shell_command(context);
+ ReloadDirList::soft_reload(context.curr_tab_index, context)?;
+ context
+ .message_queue
+ .push_back(format!("Finished: {}", self.words.join(" ")));
backend.terminal_restore()?;
res?;
Ok(())
diff --git a/src/commands/show_hidden.rs b/src/commands/show_hidden.rs
index 0a22c53..6dd7736 100644
--- a/src/commands/show_hidden.rs
+++ b/src/commands/show_hidden.rs
@@ -20,9 +20,8 @@ impl ToggleHiddenFiles {
for tab in &mut context.tabs {
tab.history.depreciate_all_entries();
- match tab.curr_list_mut() {
- Some(s) => s.depreciate(),
- None => {}
+ if let Some(s) = tab.curr_list_mut() {
+ s.depreciate();
}
}
}
diff --git a/src/commands/sort.rs b/src/commands/sort.rs
index 93882f6..4f9601c 100644
--- a/src/commands/sort.rs
+++ b/src/commands/sort.rs
@@ -72,4 +72,3 @@ impl JoshutoRunnable for SortReverse {
Ok(())
}
}
-
diff --git a/src/config/keymap.rs b/src/config/keymap.rs
index 328132d..e79069b 100644
--- a/src/config/keymap.rs
+++ b/src/config/keymap.rs
@@ -6,7 +6,7 @@ use termion::event::Key;
use super::{parse_to_config_file, ConfigStructure, Flattenable};
use crate::commands::{self, CommandKeybind, JoshutoCommand};
-use crate::io::Options;
+use crate::io::IOWorkerOptions;
use crate::util::key_mapping::str_to_key;
use crate::KEYMAP_FILE;
@@ -136,7 +136,7 @@ impl JoshutoCommandMapping {
let keys = [Key::Char('y'), Key::Char('y')];
insert_keycommand(&mut m, cmd, &keys)?;
- let cmd = Box::new(commands::PasteFiles::new(Options::default()));
+ let cmd = Box::new(commands::PasteFiles::new(IOWorkerOptions::default()));
let keys = [Key::Char('p'), Key::Char('p')];
insert_keycommand(&mut m, cmd, &keys)?;
diff --git a/src/config/mimetype.rs b/src/config/mimetype.rs
index 189dd29..9b82f08 100644
--- a/src/config/mimetype.rs
+++ b/src/config/mimetype.rs
@@ -2,7 +2,6 @@ use serde_derive::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::io::Read;
-use std::path::Path;
use std::process;
use super::{parse_config_file, ConfigStructure};
@@ -83,9 +82,10 @@ impl JoshutoMimetypeEntry {
}
pub fn execute_with<I, S>(&self, paths: I) -> std::io::Result<()>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<std::ffi::OsStr>, {
+ where
+ I: IntoIterator<Item = S>,
+ S: AsRef<std::ffi::OsStr>,
+ {
let program = String::from(self.get_command());
let mut command = process::Command::new(program);
diff --git a/src/config/theme.rs b/src/config/theme.rs
index 02f9a03..fe88a5d 100644
--- a/src/config/theme.rs
+++ b/src/config/theme.rs
@@ -1,7 +1,7 @@
use serde_derive::Deserialize;
use std::collections::HashMap;
-use tui::style::{Color, Modifier, Style};
+use tui::style::{Color, Modifier};
use crate::THEME_FILE;
diff --git a/src/context.rs b/src/cont