From 3901ed54c6df1a9c7e6244a80ac341234a0889db Mon Sep 17 00:00:00 2001 From: ChristianVisintin Date: Mon, 21 Dec 2020 11:11:29 +0100 Subject: [PATCH] Copy feature in ui; new keybinding --- CHANGELOG.md | 5 +- README.md | 1 + src/host/mod.rs | 24 ++++++- .../filetransfer_activity/callbacks.rs | 71 +++++++++++++++++++ .../activities/filetransfer_activity/input.rs | 42 +++++++---- .../filetransfer_activity/layout.rs | 10 +++ 6 files changed, 137 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e62bdb4..78d3f22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ ## 0.2.0 -Released on ?? +Released on 21/12/2020 > The Bookmarks Update @@ -24,6 +24,9 @@ Released on ?? - **Text Editor** - Added text editor feature to explorer view - Added `o` to keybindings to open a text file +- Keybindings: + - `C`: Copy file/directory + - `O`: Open text file in editor - Enhancements: - User interface - Collpased borders to make everything more *aesthetic* diff --git a/README.md b/README.md index cd6318a..cc474f3 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ Text editor is automatically found using this [awesome crate](https://github.com | `` | Move down in selected list by 8 rows | | `` | Enter directory | | `` | Upload / download selected file | +| `` | Copy file/directory | | `` | Make directory | | `` | Delete file (Same as `CANC`) | | `` | Go to supplied path | diff --git a/src/host/mod.rs b/src/host/mod.rs index 3eab785..404c5fc 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -830,7 +830,7 @@ mod tests { #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] #[test] - fn test_host_copy_file() { + fn test_host_copy_file_absolute() { let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap(); // Create file in tmpdir let mut file1_path: PathBuf = PathBuf::from(tmpdir.path()); @@ -851,6 +851,28 @@ mod tests { assert_eq!(host.files.len(), 2); } + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] + #[test] + fn test_host_copy_file_relative() { + let tmpdir: tempfile::TempDir = tempfile::TempDir::new().unwrap(); + // Create file in tmpdir + let mut file1_path: PathBuf = PathBuf::from(tmpdir.path()); + file1_path.push("foo.txt"); + // Write file 1 + let mut file1: File = File::create(file1_path.as_path()).ok().unwrap(); + assert!(file1.write_all(b"Hello world!\n").is_ok()); + // Get file 2 path + let file2_path: PathBuf = PathBuf::from("bar.txt"); + // Create host + let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap(); + let file1_entry: FsEntry = host.files.get(0).unwrap().clone(); + assert_eq!(file1_entry.get_name(), String::from("foo.txt")); + // Copy + assert!(host.copy(&file1_entry, file2_path.as_path()).is_ok()); + // Verify host has two files + assert_eq!(host.files.len(), 2); + } + #[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))] #[test] fn test_hop_copy_directory_absolute() { diff --git a/src/ui/activities/filetransfer_activity/callbacks.rs b/src/ui/activities/filetransfer_activity/callbacks.rs index 08df7eb..e6330a2 100644 --- a/src/ui/activities/filetransfer_activity/callbacks.rs +++ b/src/ui/activities/filetransfer_activity/callbacks.rs @@ -62,6 +62,77 @@ impl FileTransferActivity { } } + /// ### callback_copy + /// + /// Callback for COPY command (both from local and remote) + pub(super) fn callback_copy(&mut self, input: String) { + let dest_path: PathBuf = PathBuf::from(input); + match self.tab { + FileExplorerTab::Local => { + // Get selected entry + if self.local.files.get(self.local.index).is_some() { + let entry: FsEntry = self.local.files.get(self.local.index).unwrap().clone(); + if let Some(ctx) = self.context.as_mut() { + match ctx.local.copy(&entry, dest_path.as_path()) { + Ok(_) => { + self.log( + LogLevel::Info, + format!( + "Copied \"{}\" to \"{}\"", + entry.get_abs_path().display(), + dest_path.display() + ) + .as_str(), + ); + // Reload entries + let wrkdir: PathBuf = self.local.wrkdir.clone(); + self.local_scan(wrkdir.as_path()); + } + Err(err) => self.log_and_alert( + LogLevel::Error, + format!( + "Could not copy \"{}\" to \"{}\": {}", + entry.get_abs_path().display(), + dest_path.display(), + err + ), + ), + } + } + } + } + FileExplorerTab::Remote => { + // Get selected entry + if self.remote.files.get(self.remote.index).is_some() { + let entry: FsEntry = self.remote.files.get(self.remote.index).unwrap().clone(); + match self.client.as_mut().copy(&entry, dest_path.as_path()) { + Ok(_) => { + self.log( + LogLevel::Info, + format!( + "Copied \"{}\" to \"{}\"", + entry.get_abs_path().display(), + dest_path.display() + ) + .as_str(), + ); + self.reload_remote_dir(); + } + Err(err) => self.log_and_alert( + LogLevel::Error, + format!( + "Could not copy \"{}\" to \"{}\": {}", + entry.get_abs_path().display(), + dest_path.display(), + err + ), + ), + } + } + } + } + } + /// ### callback_mkdir /// /// Callback for MKDIR command (supports both local and remote) diff --git a/src/ui/activities/filetransfer_activity/input.rs b/src/ui/activities/filetransfer_activity/input.rs index 16888a4..0b728aa 100644 --- a/src/ui/activities/filetransfer_activity/input.rs +++ b/src/ui/activities/filetransfer_activity/input.rs @@ -177,6 +177,20 @@ impl FileTransferActivity { } } KeyCode::Char(ch) => match ch { + 'c' | 'C' => { + // Copy + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("Insert destination name"), + FileTransferActivity::callback_copy, + )); + } + 'd' | 'D' => { + // Make directory + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("Insert directory name"), + FileTransferActivity::callback_mkdir, + )); + } 'e' | 'E' => { // Get file at index if let Some(entry) = self.local.files.get(self.local.index) { @@ -201,13 +215,6 @@ impl FileTransferActivity { FileTransferActivity::callback_change_directory, )); } - 'd' | 'D' => { - // Make directory - self.input_mode = InputMode::Popup(PopupType::Input( - String::from("Insert directory name"), - FileTransferActivity::callback_mkdir, - )); - } 'h' | 'H' => { // Show help self.input_mode = InputMode::Popup(PopupType::Help); @@ -389,6 +396,20 @@ impl FileTransferActivity { } } KeyCode::Char(ch) => match ch { + 'c' | 'C' => { + // Copy + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("Insert destination name"), + FileTransferActivity::callback_copy, + )); + } + 'd' | 'D' => { + // Make directory + self.input_mode = InputMode::Popup(PopupType::Input( + String::from("Insert directory name"), + FileTransferActivity::callback_mkdir, + )); + } 'e' | 'E' => { // Get file at index if let Some(entry) = self.remote.files.get(self.remote.index) { @@ -405,13 +426,6 @@ impl FileTransferActivity { )) } } - 'd' | 'D' => { - // Make directory - self.input_mode = InputMode::Popup(PopupType::Input( - String::from("Insert directory name"), - FileTransferActivity::callback_mkdir, - )); - } 'g' | 'G' => { // Goto // Show input popup diff --git a/src/ui/activities/filetransfer_activity/layout.rs b/src/ui/activities/filetransfer_activity/layout.rs index fe16831..f6d79e0 100644 --- a/src/ui/activities/filetransfer_activity/layout.rs +++ b/src/ui/activities/filetransfer_activity/layout.rs @@ -716,6 +716,16 @@ impl FileTransferActivity { Span::raw(" "), Span::raw("Delete file"), ])), + ListItem::new(Spans::from(vec![ + Span::styled( + "", + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ), + Span::raw(" "), + Span::raw("Copy"), + ])), ListItem::new(Spans::from(vec![ Span::styled( "",