mirror of
https://github.com/veeso/termscp.git
synced 2026-09-26 05:51:20 -07:00
Merge pull request #31 from veeso/mini-refactoring-file-transfer-activity
Mini refactoring file transfer activity
This commit is contained in:
+13
-7
@@ -56,6 +56,7 @@ pub enum NextActivity {
|
|||||||
pub struct ActivityManager {
|
pub struct ActivityManager {
|
||||||
context: Option<Context>,
|
context: Option<Context>,
|
||||||
interval: Duration,
|
interval: Duration,
|
||||||
|
local_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActivityManager {
|
impl ActivityManager {
|
||||||
@@ -64,19 +65,16 @@ impl ActivityManager {
|
|||||||
/// Initializes a new Activity Manager
|
/// Initializes a new Activity Manager
|
||||||
pub fn new(local_dir: &Path, interval: Duration) -> Result<ActivityManager, HostError> {
|
pub fn new(local_dir: &Path, interval: Duration) -> Result<ActivityManager, HostError> {
|
||||||
// Prepare Context
|
// Prepare Context
|
||||||
let host: Localhost = match Localhost::new(local_dir.to_path_buf()) {
|
|
||||||
Ok(h) => h,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
// Initialize configuration client
|
// Initialize configuration client
|
||||||
let (config_client, error): (Option<ConfigClient>, Option<String>) =
|
let (config_client, error): (Option<ConfigClient>, Option<String>) =
|
||||||
match Self::init_config_client() {
|
match Self::init_config_client() {
|
||||||
Ok(cli) => (Some(cli), None),
|
Ok(cli) => (Some(cli), None),
|
||||||
Err(err) => (None, Some(err)),
|
Err(err) => (None, Some(err)),
|
||||||
};
|
};
|
||||||
let ctx: Context = Context::new(host, config_client, error);
|
let ctx: Context = Context::new(config_client, error);
|
||||||
Ok(ActivityManager {
|
Ok(ActivityManager {
|
||||||
context: Some(ctx),
|
context: Some(ctx),
|
||||||
|
local_dir: local_dir.to_path_buf(),
|
||||||
interval,
|
interval,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -182,7 +180,7 @@ impl ActivityManager {
|
|||||||
/// Returns the next activity to run
|
/// Returns the next activity to run
|
||||||
fn run_filetransfer(&mut self) -> Option<NextActivity> {
|
fn run_filetransfer(&mut self) -> Option<NextActivity> {
|
||||||
// Get context
|
// Get context
|
||||||
let ctx: Context = match self.context.take() {
|
let mut ctx: Context = match self.context.take() {
|
||||||
Some(ctx) => ctx,
|
Some(ctx) => ctx,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
@@ -193,7 +191,15 @@ impl ActivityManager {
|
|||||||
};
|
};
|
||||||
// Prepare activity
|
// Prepare activity
|
||||||
let protocol: FileTransferProtocol = ft_params.protocol;
|
let protocol: FileTransferProtocol = ft_params.protocol;
|
||||||
let mut activity: FileTransferActivity = FileTransferActivity::new(protocol);
|
let host: Localhost = match Localhost::new(self.local_dir.clone()) {
|
||||||
|
Ok(host) => host,
|
||||||
|
Err(err) => {
|
||||||
|
// Set error in context
|
||||||
|
ctx.set_error(format!("Could not initialize localhost: {}", err));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut activity: FileTransferActivity = FileTransferActivity::new(host, protocol);
|
||||||
// Prepare result
|
// Prepare result
|
||||||
let result: Option<NextActivity>;
|
let result: Option<NextActivity>;
|
||||||
// Create activity
|
// Create activity
|
||||||
|
|||||||
@@ -185,9 +185,8 @@ impl FtpFileTransfer {
|
|||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
// Get symlink
|
// Get symlink
|
||||||
let symlink: Option<Box<FsEntry>> = match symlink_path {
|
let symlink: Option<Box<FsEntry>> = symlink_path.map(|p| {
|
||||||
None => None,
|
Box::new(match p.to_string_lossy().ends_with('/') {
|
||||||
Some(p) => Some(Box::new(match p.to_string_lossy().ends_with('/') {
|
|
||||||
true => {
|
true => {
|
||||||
// NOTE: is_dir becomes true
|
// NOTE: is_dir becomes true
|
||||||
is_dir = true;
|
is_dir = true;
|
||||||
@@ -226,8 +225,8 @@ impl FtpFileTransfer {
|
|||||||
group: gid,
|
group: gid,
|
||||||
unix_pex: Some(unix_pex),
|
unix_pex: Some(unix_pex),
|
||||||
}),
|
}),
|
||||||
})),
|
})
|
||||||
};
|
});
|
||||||
let mut abs_path: PathBuf = PathBuf::from(path);
|
let mut abs_path: PathBuf = PathBuf::from(path);
|
||||||
abs_path.push(file_name.as_str());
|
abs_path.push(file_name.as_str());
|
||||||
let abs_path: PathBuf = Self::resolve(abs_path.as_path());
|
let abs_path: PathBuf = Self::resolve(abs_path.as_path());
|
||||||
|
|||||||
@@ -1,760 +0,0 @@
|
|||||||
//! ## FileTransferActivity
|
|
||||||
//!
|
|
||||||
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* termscp - Copyright (c) 2021 Christian Visintin
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
// locals
|
|
||||||
use super::{FileExplorerTab, FileTransferActivity, FsEntry, LogLevel};
|
|
||||||
use tuirealm::{Payload, Value};
|
|
||||||
// externals
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
impl FileTransferActivity {
|
|
||||||
/// ### action_enter_local_dir
|
|
||||||
///
|
|
||||||
/// Enter a directory on local host from entry
|
|
||||||
/// Return true whether the directory changed
|
|
||||||
pub(super) fn action_enter_local_dir(&mut self, entry: FsEntry, block_sync: bool) -> bool {
|
|
||||||
match entry {
|
|
||||||
FsEntry::Directory(dir) => {
|
|
||||||
self.local_changedir(dir.abs_path.as_path(), true);
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_remote_dir(dir.name, true);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
FsEntry::File(file) => {
|
|
||||||
match &file.symlink {
|
|
||||||
Some(symlink_entry) => {
|
|
||||||
// If symlink and is directory, point to symlink
|
|
||||||
match &**symlink_entry {
|
|
||||||
FsEntry::Directory(dir) => {
|
|
||||||
self.local_changedir(dir.abs_path.as_path(), true);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_remote_dir(dir.name.clone(), true);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_enter_remote_dir
|
|
||||||
///
|
|
||||||
/// Enter a directory on local host from entry
|
|
||||||
/// Return true whether the directory changed
|
|
||||||
pub(super) fn action_enter_remote_dir(&mut self, entry: FsEntry, block_sync: bool) -> bool {
|
|
||||||
match entry {
|
|
||||||
FsEntry::Directory(dir) => {
|
|
||||||
self.remote_changedir(dir.abs_path.as_path(), true);
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_local_dir(dir.name, true);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
FsEntry::File(file) => {
|
|
||||||
match &file.symlink {
|
|
||||||
Some(symlink_entry) => {
|
|
||||||
// If symlink and is directory, point to symlink
|
|
||||||
match &**symlink_entry {
|
|
||||||
FsEntry::Directory(dir) => {
|
|
||||||
self.remote_changedir(dir.abs_path.as_path(), true);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_local_dir(dir.name.clone(), true);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_change_local_dir
|
|
||||||
///
|
|
||||||
/// Change local directory reading value from input
|
|
||||||
pub(super) fn action_change_local_dir(&mut self, input: String, block_sync: bool) {
|
|
||||||
let dir_path: PathBuf = self.local_to_abs_path(PathBuf::from(input.as_str()).as_path());
|
|
||||||
self.local_changedir(dir_path.as_path(), true);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_remote_dir(input, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_change_remote_dir
|
|
||||||
///
|
|
||||||
/// Change remote directory reading value from input
|
|
||||||
pub(super) fn action_change_remote_dir(&mut self, input: String, block_sync: bool) {
|
|
||||||
let dir_path: PathBuf = self.remote_to_abs_path(PathBuf::from(input.as_str()).as_path());
|
|
||||||
self.remote_changedir(dir_path.as_path(), true);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_change_local_dir(input, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_go_to_previous_local_dir
|
|
||||||
///
|
|
||||||
/// Go to previous directory from localhost
|
|
||||||
pub(super) fn action_go_to_previous_local_dir(&mut self, block_sync: bool) {
|
|
||||||
if let Some(d) = self.local.popd() {
|
|
||||||
self.local_changedir(d.as_path(), false);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_go_to_previous_remote_dir(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_go_to_previous_remote_dir
|
|
||||||
///
|
|
||||||
/// Go to previous directory from remote host
|
|
||||||
pub(super) fn action_go_to_previous_remote_dir(&mut self, block_sync: bool) {
|
|
||||||
if let Some(d) = self.remote.popd() {
|
|
||||||
self.remote_changedir(d.as_path(), false);
|
|
||||||
// Check whether to sync
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_go_to_previous_local_dir(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_go_to_local_upper_dir
|
|
||||||
///
|
|
||||||
/// Go to upper directory on local host
|
|
||||||
pub(super) fn action_go_to_local_upper_dir(&mut self, block_sync: bool) {
|
|
||||||
// Get pwd
|
|
||||||
let path: PathBuf = self.local.wrkdir.clone();
|
|
||||||
// Go to parent directory
|
|
||||||
if let Some(parent) = path.as_path().parent() {
|
|
||||||
self.local_changedir(parent, true);
|
|
||||||
// If sync is enabled update remote too
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_go_to_remote_upper_dir(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// #### action_go_to_remote_upper_dir
|
|
||||||
///
|
|
||||||
/// Go to upper directory on remote host
|
|
||||||
pub(super) fn action_go_to_remote_upper_dir(&mut self, block_sync: bool) {
|
|
||||||
// Get pwd
|
|
||||||
let path: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
// Go to parent directory
|
|
||||||
if let Some(parent) = path.as_path().parent() {
|
|
||||||
self.remote_changedir(parent, true);
|
|
||||||
// If sync is enabled update local too
|
|
||||||
if self.browser.sync_browsing && !block_sync {
|
|
||||||
self.action_go_to_local_upper_dir(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_local_copy
|
|
||||||
///
|
|
||||||
/// Copy file on local
|
|
||||||
pub(super) fn action_local_copy(&mut self, input: String) {
|
|
||||||
if let Some(idx) = self.get_local_file_idx() {
|
|
||||||
let dest_path: PathBuf = PathBuf::from(input);
|
|
||||||
let entry: FsEntry = self.local.get(idx).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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### action_remote_copy
|
|
||||||
///
|
|
||||||
/// Copy file on remote
|
|
||||||
pub(super) fn action_remote_copy(&mut self, input: String) {
|
|
||||||
if let Some(idx) = self.get_remote_file_idx() {
|
|
||||||
let dest_path: PathBuf = PathBuf::from(input);
|
|
||||||
let entry: FsEntry = self.remote.get(idx).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
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_mkdir(&mut self, input: String) {
|
|
||||||
match self
|
|
||||||
.context
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.mkdir(PathBuf::from(input.as_str()).as_path())
|
|
||||||
{
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Created directory \"{}\"", input).as_ref(),
|
|
||||||
);
|
|
||||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(wrkdir.as_path());
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Report err
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not create directory \"{}\": {}", input, err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(super) fn action_remote_mkdir(&mut self, input: String) {
|
|
||||||
match self
|
|
||||||
.client
|
|
||||||
.as_mut()
|
|
||||||
.mkdir(PathBuf::from(input.as_str()).as_path())
|
|
||||||
{
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Created directory \"{}\"", input).as_ref(),
|
|
||||||
);
|
|
||||||
self.reload_remote_dir();
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Report err
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not create directory \"{}\": {}", input, err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_rename(&mut self, input: String) {
|
|
||||||
let entry: Option<FsEntry> = self.get_local_file_entry().cloned();
|
|
||||||
if let Some(entry) = entry {
|
|
||||||
let mut dst_path: PathBuf = PathBuf::from(input);
|
|
||||||
// Check if path is relative
|
|
||||||
if dst_path.as_path().is_relative() {
|
|
||||||
let mut wrkdir: PathBuf = self.local.wrkdir.clone();
|
|
||||||
wrkdir.push(dst_path);
|
|
||||||
dst_path = wrkdir;
|
|
||||||
}
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Rename file or directory and report status as popup
|
|
||||||
match self
|
|
||||||
.context
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.rename(&entry, dst_path.as_path())
|
|
||||||
{
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
let path: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(path.as_path());
|
|
||||||
// Log
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!(
|
|
||||||
"Renamed file \"{}\" to \"{}\"",
|
|
||||||
full_path.display(),
|
|
||||||
dst_path.display()
|
|
||||||
)
|
|
||||||
.as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not rename file \"{}\": {}", full_path.display(), err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_rename(&mut self, input: String) {
|
|
||||||
if let Some(idx) = self.get_remote_file_idx() {
|
|
||||||
if let Some(entry) = self.remote.get(idx) {
|
|
||||||
let dst_path: PathBuf = PathBuf::from(input);
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Rename file or directory and report status as popup
|
|
||||||
match self.client.as_mut().rename(entry, dst_path.as_path()) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
let path: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
self.remote_scan(path.as_path());
|
|
||||||
// Log
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!(
|
|
||||||
"Renamed file \"{}\" to \"{}\"",
|
|
||||||
full_path.display(),
|
|
||||||
dst_path.display()
|
|
||||||
)
|
|
||||||
.as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not rename file \"{}\": {}", full_path.display(), err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_delete(&mut self) {
|
|
||||||
let entry: Option<FsEntry> = self.get_local_file_entry().cloned();
|
|
||||||
if let Some(entry) = entry {
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Delete file or directory and report status as popup
|
|
||||||
match self.context.as_mut().unwrap().local.remove(&entry) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
let p: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(p.as_path());
|
|
||||||
// Log
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Removed file \"{}\"", full_path.display()).as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not delete file \"{}\": {}", full_path.display(), err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_delete(&mut self) {
|
|
||||||
if let Some(idx) = self.get_remote_file_idx() {
|
|
||||||
// Check if file entry exists
|
|
||||||
if let Some(entry) = self.remote.get(idx) {
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Delete file
|
|
||||||
match self.client.remove(entry) {
|
|
||||||
Ok(_) => {
|
|
||||||
self.reload_remote_dir();
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Removed file \"{}\"", full_path.display()).as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not delete file \"{}\": {}", full_path.display(), err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_saveas(&mut self, input: String) {
|
|
||||||
if let Some(idx) = self.get_local_file_idx() {
|
|
||||||
// Get pwd
|
|
||||||
let wrkdir: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
if self.local.get(idx).is_some() {
|
|
||||||
let file: FsEntry = self.local.get(idx).unwrap().clone();
|
|
||||||
// Call upload; pass realfile, keep link name
|
|
||||||
self.filetransfer_send(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_saveas(&mut self, input: String) {
|
|
||||||
if let Some(idx) = self.get_remote_file_idx() {
|
|
||||||
// Get pwd
|
|
||||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
|
||||||
if self.remote.get(idx).is_some() {
|
|
||||||
let file: FsEntry = self.remote.get(idx).unwrap().clone();
|
|
||||||
// Call upload; pass realfile, keep link name
|
|
||||||
self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_newfile(&mut self, input: String) {
|
|
||||||
// Check if file exists
|
|
||||||
let mut file_exists: bool = false;
|
|
||||||
for file in self.local.iter_files_all() {
|
|
||||||
if input == file.get_name() {
|
|
||||||
file_exists = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if file_exists {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Warn,
|
|
||||||
format!("File \"{}\" already exists", input,),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Create file
|
|
||||||
let file_path: PathBuf = PathBuf::from(input.as_str());
|
|
||||||
if let Some(ctx) = self.context.as_mut() {
|
|
||||||
if let Err(err) = ctx.local.open_file_write(file_path.as_path()) {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not create file \"{}\": {}", file_path.display(), err),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Created file \"{}\"", file_path.display()).as_str(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Reload files
|
|
||||||
let path: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(path.as_path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_newfile(&mut self, input: String) {
|
|
||||||
// Check if file exists
|
|
||||||
let mut file_exists: bool = false;
|
|
||||||
for file in self.remote.iter_files_all() {
|
|
||||||
if input == file.get_name() {
|
|
||||||
file_exists = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if file_exists {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Warn,
|
|
||||||
format!("File \"{}\" already exists", input,),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Get path on remote
|
|
||||||
let file_path: PathBuf = PathBuf::from(input.as_str());
|
|
||||||
// Create file (on local)
|
|
||||||
match tempfile::NamedTempFile::new() {
|
|
||||||
Err(err) => self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not create tempfile: {}", err),
|
|
||||||
),
|
|
||||||
Ok(tfile) => {
|
|
||||||
// Stat tempfile
|
|
||||||
if let Some(ctx) = self.context.as_mut() {
|
|
||||||
let local_file: FsEntry = match ctx.local.stat(tfile.path()) {
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not stat tempfile: {}", err),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Ok(f) => f,
|
|
||||||
};
|
|
||||||
if let FsEntry::File(local_file) = local_file {
|
|
||||||
// Create file
|
|
||||||
match self.client.send_file(&local_file, file_path.as_path()) {
|
|
||||||
Err(err) => self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!(
|
|
||||||
"Could not create file \"{}\": {}",
|
|
||||||
file_path.display(),
|
|
||||||
err
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Ok(writer) => {
|
|
||||||
// Finalize write
|
|
||||||
if let Err(err) = self.client.on_sent(writer) {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Warn,
|
|
||||||
format!("Could not finalize file: {}", err),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Created file \"{}\"", file_path.display())
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Reload files
|
|
||||||
let path: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
self.remote_scan(path.as_path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_exec(&mut self, input: String) {
|
|
||||||
match self.context.as_mut().unwrap().local.exec(input.as_str()) {
|
|
||||||
Ok(output) => {
|
|
||||||
// Reload files
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("\"{}\": {}", input, output).as_ref(),
|
|
||||||
);
|
|
||||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(wrkdir.as_path());
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Report err
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not execute command \"{}\": {}", input, err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_exec(&mut self, input: String) {
|
|
||||||
match self.client.as_mut().exec(input.as_str()) {
|
|
||||||
Ok(output) => {
|
|
||||||
// Reload files
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("\"{}\": {}", input, output).as_ref(),
|
|
||||||
);
|
|
||||||
self.reload_remote_dir();
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Report err
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!("Could not execute command \"{}\": {}", input, err),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_local_find(&mut self, input: String) -> Result<Vec<FsEntry>, String> {
|
|
||||||
match self.context.as_mut().unwrap().local.find(input.as_str()) {
|
|
||||||
Ok(entries) => Ok(entries),
|
|
||||||
Err(err) => Err(format!("Could not search for files: {}", err)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_remote_find(&mut self, input: String) -> Result<Vec<FsEntry>, String> {
|
|
||||||
match self.client.as_mut().find(input.as_str()) {
|
|
||||||
Ok(entries) => Ok(entries),
|
|
||||||
Err(err) => Err(format!("Could not search for files: {}", err)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_find_changedir(&mut self, idx: usize) {
|
|
||||||
// Match entry
|
|
||||||
if let Some(entry) = self.found.as_ref().unwrap().get(idx) {
|
|
||||||
// Get path: if a directory, use directory path; if it is a File, get parent path
|
|
||||||
let path: PathBuf = match entry {
|
|
||||||
FsEntry::Directory(dir) => dir.abs_path.clone(),
|
|
||||||
FsEntry::File(file) => match file.abs_path.parent() {
|
|
||||||
None => PathBuf::from("."),
|
|
||||||
Some(p) => p.to_path_buf(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// Change directory
|
|
||||||
match self.tab {
|
|
||||||
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
|
||||||
self.local_changedir(path.as_path(), true)
|
|
||||||
}
|
|
||||||
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
|
||||||
self.remote_changedir(path.as_path(), true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_find_transfer(&mut self, idx: usize, name: Option<String>) {
|
|
||||||
let entry: Option<FsEntry> = self.found.as_ref().unwrap().get(idx).cloned();
|
|
||||||
if let Some(entry) = entry {
|
|
||||||
// Download file
|
|
||||||
match self.tab {
|
|
||||||
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
|
||||||
let wrkdir: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
self.filetransfer_send(&entry.get_realfile(), wrkdir.as_path(), name);
|
|
||||||
}
|
|
||||||
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
|
||||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.filetransfer_recv(&entry.get_realfile(), wrkdir.as_path(), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn action_find_delete(&mut self, idx: usize) {
|
|
||||||
let entry: Option<FsEntry> = self.found.as_ref().unwrap().get(idx).cloned();
|
|
||||||
if let Some(entry) = entry {
|
|
||||||
// Download file
|
|
||||||
match self.tab {
|
|
||||||
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Delete file or directory and report status as popup
|
|
||||||
match self.context.as_mut().unwrap().local.remove(&entry) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload files
|
|
||||||
let p: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(p.as_path());
|
|
||||||
// Log
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Removed file \"{}\"", full_path.display()).as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!(
|
|
||||||
"Could not delete file \"{}\": {}",
|
|
||||||
full_path.display(),
|
|
||||||
err
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
|
||||||
let full_path: PathBuf = entry.get_abs_path();
|
|
||||||
// Delete file
|
|
||||||
match self.client.remove(&entry) {
|
|
||||||
Ok(_) => {
|
|
||||||
self.reload_remote_dir();
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Removed file \"{}\"", full_path.display()).as_ref(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
self.log_and_alert(
|
|
||||||
LogLevel::Error,
|
|
||||||
format!(
|
|
||||||
"Could not delete file \"{}\": {}",
|
|
||||||
full_path.display(),
|
|
||||||
err
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### get_local_file_entry
|
|
||||||
///
|
|
||||||
/// Get local file entry
|
|
||||||
pub(super) fn get_local_file_entry(&self) -> Option<&FsEntry> {
|
|
||||||
match self.get_local_file_idx() {
|
|
||||||
None => None,
|
|
||||||
Some(idx) => self.local.get(idx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### get_remote_file_entry
|
|
||||||
///
|
|
||||||
/// Get remote file entry
|
|
||||||
pub(super) fn get_remote_file_entry(&self) -> Option<&FsEntry> {
|
|
||||||
match self.get_remote_file_idx() {
|
|
||||||
None => None,
|
|
||||||
Some(idx) => self.remote.get(idx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- private
|
|
||||||
|
|
||||||
/// ### get_local_file_idx
|
|
||||||
///
|
|
||||||
/// Get index of selected file in the local tab
|
|
||||||
fn get_local_file_idx(&self) -> Option<usize> {
|
|
||||||
match self.view.get_state(super::COMPONENT_EXPLORER_LOCAL) {
|
|
||||||
Some(Payload::One(Value::Usize(idx))) => Some(idx),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### get_remote_file_idx
|
|
||||||
///
|
|
||||||
/// Get index of selected file in the remote file
|
|
||||||
fn get_remote_file_idx(&self) -> Option<usize> {
|
|
||||||
match self.view.get_state(super::COMPONENT_EXPLORER_REMOTE) {
|
|
||||||
Some(Payload::One(Value::Usize(idx))) => Some(idx),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
/// ### action_enter_local_dir
|
||||||
|
///
|
||||||
|
/// Enter a directory on local host from entry
|
||||||
|
/// Return true whether the directory changed
|
||||||
|
pub(crate) fn action_enter_local_dir(&mut self, entry: FsEntry, block_sync: bool) -> bool {
|
||||||
|
match entry {
|
||||||
|
FsEntry::Directory(dir) => {
|
||||||
|
self.local_changedir(dir.abs_path.as_path(), true);
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_remote_dir(dir.name, true);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
FsEntry::File(file) => {
|
||||||
|
match &file.symlink {
|
||||||
|
Some(symlink_entry) => {
|
||||||
|
// If symlink and is directory, point to symlink
|
||||||
|
match &**symlink_entry {
|
||||||
|
FsEntry::Directory(dir) => {
|
||||||
|
self.local_changedir(dir.abs_path.as_path(), true);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_remote_dir(dir.name.clone(), true);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_enter_remote_dir
|
||||||
|
///
|
||||||
|
/// Enter a directory on local host from entry
|
||||||
|
/// Return true whether the directory changed
|
||||||
|
pub(crate) fn action_enter_remote_dir(&mut self, entry: FsEntry, block_sync: bool) -> bool {
|
||||||
|
match entry {
|
||||||
|
FsEntry::Directory(dir) => {
|
||||||
|
self.remote_changedir(dir.abs_path.as_path(), true);
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_local_dir(dir.name, true);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
FsEntry::File(file) => {
|
||||||
|
match &file.symlink {
|
||||||
|
Some(symlink_entry) => {
|
||||||
|
// If symlink and is directory, point to symlink
|
||||||
|
match &**symlink_entry {
|
||||||
|
FsEntry::Directory(dir) => {
|
||||||
|
self.remote_changedir(dir.abs_path.as_path(), true);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_local_dir(dir.name.clone(), true);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_change_local_dir
|
||||||
|
///
|
||||||
|
/// Change local directory reading value from input
|
||||||
|
pub(crate) fn action_change_local_dir(&mut self, input: String, block_sync: bool) {
|
||||||
|
let dir_path: PathBuf = self.local_to_abs_path(PathBuf::from(input.as_str()).as_path());
|
||||||
|
self.local_changedir(dir_path.as_path(), true);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_remote_dir(input, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_change_remote_dir
|
||||||
|
///
|
||||||
|
/// Change remote directory reading value from input
|
||||||
|
pub(crate) fn action_change_remote_dir(&mut self, input: String, block_sync: bool) {
|
||||||
|
let dir_path: PathBuf = self.remote_to_abs_path(PathBuf::from(input.as_str()).as_path());
|
||||||
|
self.remote_changedir(dir_path.as_path(), true);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_change_local_dir(input, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_go_to_previous_local_dir
|
||||||
|
///
|
||||||
|
/// Go to previous directory from localhost
|
||||||
|
pub(crate) fn action_go_to_previous_local_dir(&mut self, block_sync: bool) {
|
||||||
|
if let Some(d) = self.local_mut().popd() {
|
||||||
|
self.local_changedir(d.as_path(), false);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_go_to_previous_remote_dir(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_go_to_previous_remote_dir
|
||||||
|
///
|
||||||
|
/// Go to previous directory from remote host
|
||||||
|
pub(crate) fn action_go_to_previous_remote_dir(&mut self, block_sync: bool) {
|
||||||
|
if let Some(d) = self.remote_mut().popd() {
|
||||||
|
self.remote_changedir(d.as_path(), false);
|
||||||
|
// Check whether to sync
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_go_to_previous_local_dir(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_go_to_local_upper_dir
|
||||||
|
///
|
||||||
|
/// Go to upper directory on local host
|
||||||
|
pub(crate) fn action_go_to_local_upper_dir(&mut self, block_sync: bool) {
|
||||||
|
// Get pwd
|
||||||
|
let path: PathBuf = self.local().wrkdir.clone();
|
||||||
|
// Go to parent directory
|
||||||
|
if let Some(parent) = path.as_path().parent() {
|
||||||
|
self.local_changedir(parent, true);
|
||||||
|
// If sync is enabled update remote too
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_go_to_remote_upper_dir(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// #### action_go_to_remote_upper_dir
|
||||||
|
///
|
||||||
|
/// Go to upper directory on remote host
|
||||||
|
pub(crate) fn action_go_to_remote_upper_dir(&mut self, block_sync: bool) {
|
||||||
|
// Get pwd
|
||||||
|
let path: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
// Go to parent directory
|
||||||
|
if let Some(parent) = path.as_path().parent() {
|
||||||
|
self.remote_changedir(parent, true);
|
||||||
|
// If sync is enabled update local too
|
||||||
|
if self.browser.sync_browsing && !block_sync {
|
||||||
|
self.action_go_to_local_upper_dir(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
/// ### action_local_copy
|
||||||
|
///
|
||||||
|
/// Copy file on local
|
||||||
|
pub(crate) fn action_local_copy(&mut self, input: String) {
|
||||||
|
if let Some(idx) = self.get_local_file_idx() {
|
||||||
|
let dest_path: PathBuf = PathBuf::from(input);
|
||||||
|
let entry: FsEntry = self.local().get(idx).unwrap().clone();
|
||||||
|
match self.host.copy(&entry, dest_path.as_path()) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!(
|
||||||
|
"Copied \"{}\" to \"{}\"",
|
||||||
|
entry.get_abs_path().display(),
|
||||||
|
dest_path.display()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// 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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### action_remote_copy
|
||||||
|
///
|
||||||
|
/// Copy file on remote
|
||||||
|
pub(crate) fn action_remote_copy(&mut self, input: String) {
|
||||||
|
if let Some(idx) = self.get_remote_file_idx() {
|
||||||
|
let dest_path: PathBuf = PathBuf::from(input);
|
||||||
|
let entry: FsEntry = self.remote().get(idx).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()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_delete(&mut self) {
|
||||||
|
let entry: Option<FsEntry> = self.get_local_file_entry().cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Delete file or directory and report status as popup
|
||||||
|
match self.host.remove(&entry) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
let p: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(p.as_path());
|
||||||
|
// Log
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Removed file \"{}\"", full_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not delete file \"{}\": {}", full_path.display(), err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_delete(&mut self) {
|
||||||
|
if let Some(idx) = self.get_remote_file_idx() {
|
||||||
|
// Check if file entry exists
|
||||||
|
let entry = self.remote().get(idx).cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Delete file
|
||||||
|
match self.client.remove(&entry) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.reload_remote_dir();
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Removed file \"{}\"", full_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not delete file \"{}\": {}", full_path.display(), err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_edit_local_file(&mut self) {
|
||||||
|
if self.get_local_file_entry().is_some() {
|
||||||
|
let fsentry: FsEntry = self.get_local_file_entry().unwrap().clone();
|
||||||
|
// Check if file
|
||||||
|
if fsentry.is_file() {
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Opening file \"{}\"...", fsentry.get_abs_path().display()),
|
||||||
|
);
|
||||||
|
// Edit file
|
||||||
|
match self.edit_local_file(fsentry.get_abs_path().as_path()) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload directory
|
||||||
|
let pwd: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(pwd.as_path());
|
||||||
|
}
|
||||||
|
Err(err) => self.log_and_alert(LogLevel::Error, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_edit_remote_file(&mut self) {
|
||||||
|
if self.get_remote_file_entry().is_some() {
|
||||||
|
let fsentry: FsEntry = self.get_remote_file_entry().unwrap().clone();
|
||||||
|
// Check if file
|
||||||
|
if let FsEntry::File(file) = fsentry.clone() {
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Opening file \"{}\"...", fsentry.get_abs_path().display()),
|
||||||
|
);
|
||||||
|
// Edit file
|
||||||
|
match self.edit_remote_file(&file) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload directory
|
||||||
|
let pwd: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
self.remote_scan(pwd.as_path());
|
||||||
|
}
|
||||||
|
Err(err) => self.log_and_alert(LogLevel::Error, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_exec(&mut self, input: String) {
|
||||||
|
match self.host.exec(input.as_str()) {
|
||||||
|
Ok(output) => {
|
||||||
|
// Reload files
|
||||||
|
self.log(LogLevel::Info, format!("\"{}\": {}", input, output));
|
||||||
|
let wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(wrkdir.as_path());
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
// Report err
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not execute command \"{}\": {}", input, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_exec(&mut self, input: String) {
|
||||||
|
match self.client.as_mut().exec(input.as_str()) {
|
||||||
|
Ok(output) => {
|
||||||
|
// Reload files
|
||||||
|
self.log(LogLevel::Info, format!("\"{}\": {}", input, output));
|
||||||
|
self.reload_remote_dir();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
// Report err
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not execute command \"{}\": {}", input, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::super::browser::FileExplorerTab;
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_find(&mut self, input: String) -> Result<Vec<FsEntry>, String> {
|
||||||
|
match self.host.find(input.as_str()) {
|
||||||
|
Ok(entries) => Ok(entries),
|
||||||
|
Err(err) => Err(format!("Could not search for files: {}", err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_find(&mut self, input: String) -> Result<Vec<FsEntry>, String> {
|
||||||
|
match self.client.as_mut().find(input.as_str()) {
|
||||||
|
Ok(entries) => Ok(entries),
|
||||||
|
Err(err) => Err(format!("Could not search for files: {}", err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_find_changedir(&mut self, idx: usize) {
|
||||||
|
// Match entry
|
||||||
|
if let Some(entry) = self.found().as_ref().unwrap().get(idx) {
|
||||||
|
// Get path: if a directory, use directory path; if it is a File, get parent path
|
||||||
|
let path: PathBuf = match entry {
|
||||||
|
FsEntry::Directory(dir) => dir.abs_path.clone(),
|
||||||
|
FsEntry::File(file) => match file.abs_path.parent() {
|
||||||
|
None => PathBuf::from("."),
|
||||||
|
Some(p) => p.to_path_buf(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// Change directory
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
||||||
|
self.local_changedir(path.as_path(), true)
|
||||||
|
}
|
||||||
|
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
||||||
|
self.remote_changedir(path.as_path(), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_find_transfer(&mut self, idx: usize, name: Option<String>) {
|
||||||
|
let entry: Option<FsEntry> = self.found().as_ref().unwrap().get(idx).cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
// Download file
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
||||||
|
let wrkdir: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
self.filetransfer_send(&entry.get_realfile(), wrkdir.as_path(), name);
|
||||||
|
}
|
||||||
|
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
||||||
|
let wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.filetransfer_recv(&entry.get_realfile(), wrkdir.as_path(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_find_delete(&mut self, idx: usize) {
|
||||||
|
let entry: Option<FsEntry> = self.found().as_ref().unwrap().get(idx).cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
// Download file
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::FindLocal | FileExplorerTab::Local => {
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Delete file or directory and report status as popup
|
||||||
|
match self.host.remove(&entry) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
let p: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(p.as_path());
|
||||||
|
// Log
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Removed file \"{}\"", full_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!(
|
||||||
|
"Could not delete file \"{}\": {}",
|
||||||
|
full_path.display(),
|
||||||
|
err
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileExplorerTab::FindRemote | FileExplorerTab::Remote => {
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Delete file
|
||||||
|
match self.client.remove(&entry) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.reload_remote_dir();
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Removed file \"{}\"", full_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!(
|
||||||
|
"Could not delete file \"{}\": {}",
|
||||||
|
full_path.display(),
|
||||||
|
err
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_mkdir(&mut self, input: String) {
|
||||||
|
match self.host.mkdir(PathBuf::from(input.as_str()).as_path()) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
self.log(LogLevel::Info, format!("Created directory \"{}\"", input));
|
||||||
|
let wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(wrkdir.as_path());
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
// Report err
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not create directory \"{}\": {}", input, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) fn action_remote_mkdir(&mut self, input: String) {
|
||||||
|
match self
|
||||||
|
.client
|
||||||
|
.as_mut()
|
||||||
|
.mkdir(PathBuf::from(input.as_str()).as_path())
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
self.log(LogLevel::Info, format!("Created directory \"{}\"", input));
|
||||||
|
self.reload_remote_dir();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
// Report err
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not create directory \"{}\": {}", input, err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
pub(self) use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use tuirealm::{Payload, Value};
|
||||||
|
|
||||||
|
// actions
|
||||||
|
pub(crate) mod change_dir;
|
||||||
|
pub(crate) mod copy;
|
||||||
|
pub(crate) mod delete;
|
||||||
|
pub(crate) mod edit;
|
||||||
|
pub(crate) mod exec;
|
||||||
|
pub(crate) mod find;
|
||||||
|
pub(crate) mod mkdir;
|
||||||
|
pub(crate) mod newfile;
|
||||||
|
pub(crate) mod rename;
|
||||||
|
pub(crate) mod save;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
/// ### get_local_file_entry
|
||||||
|
///
|
||||||
|
/// Get local file entry
|
||||||
|
pub(crate) fn get_local_file_entry(&self) -> Option<&FsEntry> {
|
||||||
|
match self.get_local_file_idx() {
|
||||||
|
None => None,
|
||||||
|
Some(idx) => self.local().get(idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### get_remote_file_entry
|
||||||
|
///
|
||||||
|
/// Get remote file entry
|
||||||
|
pub(crate) fn get_remote_file_entry(&self) -> Option<&FsEntry> {
|
||||||
|
match self.get_remote_file_idx() {
|
||||||
|
None => None,
|
||||||
|
Some(idx) => self.remote().get(idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- private
|
||||||
|
|
||||||
|
/// ### get_local_file_idx
|
||||||
|
///
|
||||||
|
/// Get index of selected file in the local tab
|
||||||
|
fn get_local_file_idx(&self) -> Option<usize> {
|
||||||
|
match self.view.get_state(super::COMPONENT_EXPLORER_LOCAL) {
|
||||||
|
Some(Payload::One(Value::Usize(idx))) => Some(idx),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### get_remote_file_idx
|
||||||
|
///
|
||||||
|
/// Get index of selected file in the remote file
|
||||||
|
fn get_remote_file_idx(&self) -> Option<usize> {
|
||||||
|
match self.view.get_state(super::COMPONENT_EXPLORER_REMOTE) {
|
||||||
|
Some(Payload::One(Value::Usize(idx))) => Some(idx),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_newfile(&mut self, input: String) {
|
||||||
|
// Check if file exists
|
||||||
|
let mut file_exists: bool = false;
|
||||||
|
for file in self.local().iter_files_all() {
|
||||||
|
if input == file.get_name() {
|
||||||
|
file_exists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if file_exists {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Warn,
|
||||||
|
format!("File \"{}\" already exists", input,),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create file
|
||||||
|
let file_path: PathBuf = PathBuf::from(input.as_str());
|
||||||
|
if let Err(err) = self.host.open_file_write(file_path.as_path()) {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not create file \"{}\": {}", file_path.display(), err),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Created file \"{}\"", file_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Reload files
|
||||||
|
let path: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(path.as_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_newfile(&mut self, input: String) {
|
||||||
|
// Check if file exists
|
||||||
|
let mut file_exists: bool = false;
|
||||||
|
for file in self.remote().iter_files_all() {
|
||||||
|
if input == file.get_name() {
|
||||||
|
file_exists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if file_exists {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Warn,
|
||||||
|
format!("File \"{}\" already exists", input,),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Get path on remote
|
||||||
|
let file_path: PathBuf = PathBuf::from(input.as_str());
|
||||||
|
// Create file (on local)
|
||||||
|
match tempfile::NamedTempFile::new() {
|
||||||
|
Err(err) => self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not create tempfile: {}", err),
|
||||||
|
),
|
||||||
|
Ok(tfile) => {
|
||||||
|
// Stat tempfile
|
||||||
|
let local_file: FsEntry = match self.host.stat(tfile.path()) {
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not stat tempfile: {}", err),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(f) => f,
|
||||||
|
};
|
||||||
|
if let FsEntry::File(local_file) = local_file {
|
||||||
|
// Create file
|
||||||
|
match self.client.send_file(&local_file, file_path.as_path()) {
|
||||||
|
Err(err) => self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not create file \"{}\": {}", file_path.display(), err),
|
||||||
|
),
|
||||||
|
Ok(writer) => {
|
||||||
|
// Finalize write
|
||||||
|
if let Err(err) = self.client.on_sent(writer) {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Warn,
|
||||||
|
format!("Could not finalize file: {}", err),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!("Created file \"{}\"", file_path.display()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Reload files
|
||||||
|
let path: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
self.remote_scan(path.as_path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry, LogLevel};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_rename(&mut self, input: String) {
|
||||||
|
let entry: Option<FsEntry> = self.get_local_file_entry().cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
let mut dst_path: PathBuf = PathBuf::from(input);
|
||||||
|
// Check if path is relative
|
||||||
|
if dst_path.as_path().is_relative() {
|
||||||
|
let mut wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
|
wrkdir.push(dst_path);
|
||||||
|
dst_path = wrkdir;
|
||||||
|
}
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Rename file or directory and report status as popup
|
||||||
|
match self.host.rename(&entry, dst_path.as_path()) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
let path: PathBuf = self.local().wrkdir.clone();
|
||||||
|
self.local_scan(path.as_path());
|
||||||
|
// Log
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!(
|
||||||
|
"Renamed file \"{}\" to \"{}\"",
|
||||||
|
full_path.display(),
|
||||||
|
dst_path.display()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not rename file \"{}\": {}", full_path.display(), err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_rename(&mut self, input: String) {
|
||||||
|
if let Some(idx) = self.get_remote_file_idx() {
|
||||||
|
let entry = self.remote().get(idx).cloned();
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
let dst_path: PathBuf = PathBuf::from(input);
|
||||||
|
let full_path: PathBuf = entry.get_abs_path();
|
||||||
|
// Rename file or directory and report status as popup
|
||||||
|
match self.client.as_mut().rename(&entry, dst_path.as_path()) {
|
||||||
|
Ok(_) => {
|
||||||
|
// Reload files
|
||||||
|
let path: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
self.remote_scan(path.as_path());
|
||||||
|
// Log
|
||||||
|
self.log(
|
||||||
|
LogLevel::Info,
|
||||||
|
format!(
|
||||||
|
"Renamed file \"{}\" to \"{}\"",
|
||||||
|
full_path.display(),
|
||||||
|
dst_path.display()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
self.log_and_alert(
|
||||||
|
LogLevel::Error,
|
||||||
|
format!("Could not rename file \"{}\": {}", full_path.display(), err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
// locals
|
||||||
|
use super::{FileTransferActivity, FsEntry};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub(crate) fn action_local_saveas(&mut self, input: String) {
|
||||||
|
if let Some(idx) = self.get_local_file_idx() {
|
||||||
|
// Get pwd
|
||||||
|
let wrkdir: PathBuf = self.remote().wrkdir.clone();
|
||||||
|
if self.local().get(idx).is_some() {
|
||||||
|
let file: FsEntry = self.local().get(idx).unwrap().clone();
|
||||||
|
// Call upload; pass realfile, keep link name
|
||||||
|
self.filetransfer_send(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn action_remote_saveas(&mut self, input: String) {
|
||||||
|
if let Some(idx) = self.get_remote_file_idx() {
|
||||||
|
// Get pwd
|
||||||
|
let wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
|
if self.remote().get(idx).is_some() {
|
||||||
|
let file: FsEntry = self.remote().get(idx).unwrap().clone();
|
||||||
|
// Call upload; pass realfile, keep link name
|
||||||
|
self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
//! ## FileTransferActivity
|
||||||
|
//!
|
||||||
|
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* termscp - Copyright (c) 2021 Christian Visintin
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSorting, GroupDirs};
|
||||||
|
use crate::fs::FsEntry;
|
||||||
|
use crate::system::config_client::ConfigClient;
|
||||||
|
|
||||||
|
/// ## FileExplorerTab
|
||||||
|
///
|
||||||
|
/// File explorer tab
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) enum FileExplorerTab {
|
||||||
|
Local,
|
||||||
|
Remote,
|
||||||
|
FindLocal, // Find result tab
|
||||||
|
FindRemote, // Find result tab
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## Browser
|
||||||
|
///
|
||||||
|
/// Browser contains the browser options
|
||||||
|
pub(super) struct Browser {
|
||||||
|
local: FileExplorer, // Local File explorer state
|
||||||
|
remote: FileExplorer, // Remote File explorer state
|
||||||
|
found: Option<FileExplorer>, // File explorer for find result
|
||||||
|
tab: FileExplorerTab, // Current selected tab
|
||||||
|
pub sync_browsing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Browser {
|
||||||
|
/// ### new
|
||||||
|
///
|
||||||
|
/// Build a new `Browser` struct
|
||||||
|
pub(super) fn new(cli: Option<&ConfigClient>) -> Self {
|
||||||
|
Self {
|
||||||
|
local: Self::build_local_explorer(cli),
|
||||||
|
remote: Self::build_remote_explorer(cli),
|
||||||
|
found: None,
|
||||||
|
tab: FileExplorerTab::Local,
|
||||||
|
sync_browsing: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local(&self) -> &FileExplorer {
|
||||||
|
&self.local
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local_mut(&mut self) -> &mut FileExplorer {
|
||||||
|
&mut self.local
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remote(&self) -> &FileExplorer {
|
||||||
|
&self.remote
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remote_mut(&mut self) -> &mut FileExplorer {
|
||||||
|
&mut self.remote
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn found(&self) -> Option<&FileExplorer> {
|
||||||
|
self.found.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn found_mut(&mut self) -> Option<&mut FileExplorer> {
|
||||||
|
self.found.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_found(&mut self, files: Vec<FsEntry>) {
|
||||||
|
let mut explorer = Self::build_found_explorer();
|
||||||
|
explorer.set_files(files);
|
||||||
|
self.found = Some(explorer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn del_found(&mut self) {
|
||||||
|
self.found = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn tab(&self) -> FileExplorerTab {
|
||||||
|
self.tab
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### change_tab
|
||||||
|
///
|
||||||
|
/// Update tab value
|
||||||
|
pub(super) fn change_tab(&mut self, tab: FileExplorerTab) {
|
||||||
|
self.tab = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### toggle_sync_browsing
|
||||||
|
///
|
||||||
|
/// Invert the current state for the sync browsing
|
||||||
|
pub fn toggle_sync_browsing(&mut self) {
|
||||||
|
self.sync_browsing = !self.sync_browsing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### build_local_explorer
|
||||||
|
///
|
||||||
|
/// Build a file explorer with local host setup
|
||||||
|
pub fn build_local_explorer(cli: Option<&ConfigClient>) -> FileExplorer {
|
||||||
|
let mut builder = Self::build_explorer(cli);
|
||||||
|
if let Some(cli) = cli {
|
||||||
|
builder.with_formatter(cli.get_local_file_fmt().as_deref());
|
||||||
|
}
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### build_remote_explorer
|
||||||
|
///
|
||||||
|
/// Build a file explorer with remote host setup
|
||||||
|
pub fn build_remote_explorer(cli: Option<&ConfigClient>) -> FileExplorer {
|
||||||
|
let mut builder = Self::build_explorer(cli);
|
||||||
|
if let Some(cli) = cli {
|
||||||
|
builder.with_formatter(cli.get_remote_file_fmt().as_deref());
|
||||||
|
}
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### build_explorer
|
||||||
|
///
|
||||||
|
/// Build explorer reading configuration from `ConfigClient`
|
||||||
|
fn build_explorer(cli: Option<&ConfigClient>) -> FileExplorerBuilder {
|
||||||
|
let mut builder: FileExplorerBuilder = FileExplorerBuilder::new();
|
||||||
|
// Set common keys
|
||||||
|
builder
|
||||||
|
.with_file_sorting(FileSorting::ByName)
|
||||||
|
.with_stack_size(16);
|
||||||
|
match &cli {
|
||||||
|
Some(cli) => {
|
||||||
|
builder // Build according to current configuration
|
||||||
|
.with_group_dirs(cli.get_group_dirs())
|
||||||
|
.with_hidden_files(cli.get_show_hidden_files());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
builder // Build default
|
||||||
|
.with_group_dirs(Some(GroupDirs::First));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
builder
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ### build_found_explorer
|
||||||
|
///
|
||||||
|
/// Build explorer reading from `ConfigClient`, for found result (has some differences)
|
||||||
|
fn build_found_explorer() -> FileExplorer {
|
||||||
|
FileExplorerBuilder::new()
|
||||||
|
.with_file_sorting(FileSorting::ByName)
|
||||||
|
.with_group_dirs(Some(GroupDirs::First))
|
||||||
|
.with_hidden_files(true)
|
||||||
|
.with_stack_size(0)
|
||||||
|
.with_formatter(Some("{NAME} {SYMLINK}"))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,22 +23,23 @@
|
|||||||
*/
|
*/
|
||||||
// Locals
|
// Locals
|
||||||
use super::{ConfigClient, FileTransferActivity, LogLevel, LogRecord};
|
use super::{ConfigClient, FileTransferActivity, LogLevel, LogRecord};
|
||||||
use crate::fs::explorer::{builder::FileExplorerBuilder, FileExplorer, FileSorting, GroupDirs};
|
|
||||||
use crate::system::environment;
|
use crate::system::environment;
|
||||||
use crate::system::sshkey_storage::SshKeyStorage;
|
use crate::system::sshkey_storage::SshKeyStorage;
|
||||||
// Ext
|
// Ext
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
const LOG_CAPACITY: usize = 256;
|
||||||
|
|
||||||
impl FileTransferActivity {
|
impl FileTransferActivity {
|
||||||
/// ### log
|
/// ### log
|
||||||
///
|
///
|
||||||
/// Add message to log events
|
/// Add message to log events
|
||||||
pub(super) fn log(&mut self, level: LogLevel, msg: &str) {
|
pub(super) fn log(&mut self, level: LogLevel, msg: String) {
|
||||||
// Create log record
|
// Create log record
|
||||||
let record: LogRecord = LogRecord::new(level, msg);
|
let record: LogRecord = LogRecord::new(level, msg);
|
||||||
//Check if history overflows the size
|
//Check if history overflows the size
|
||||||
if self.log_records.len() + 1 > self.log_size {
|
if self.log_records.len() + 1 > LOG_CAPACITY {
|
||||||
self.log_records.pop_back(); // Start cleaning events from back
|
self.log_records.pop_back(); // Start cleaning events from back
|
||||||
}
|
}
|
||||||
// Eventually push front the new record
|
// Eventually push front the new record
|
||||||
@@ -52,8 +53,8 @@ impl FileTransferActivity {
|
|||||||
///
|
///
|
||||||
/// Add message to log events and also display it as an alert
|
/// Add message to log events and also display it as an alert
|
||||||
pub(super) fn log_and_alert(&mut self, level: LogLevel, msg: String) {
|
pub(super) fn log_and_alert(&mut self, level: LogLevel, msg: String) {
|
||||||
self.log(level, msg.as_str());
|
|
||||||
self.mount_error(msg.as_str());
|
self.mount_error(msg.as_str());
|
||||||
|
self.log(level, msg);
|
||||||
// Update log
|
// Update log
|
||||||
let msg = self.update_logbox();
|
let msg = self.update_logbox();
|
||||||
self.update(msg);
|
self.update(msg);
|
||||||
@@ -91,64 +92,6 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### build_explorer
|
|
||||||
///
|
|
||||||
/// Build explorer reading configuration from `ConfigClient`
|
|
||||||
fn build_explorer(cli: Option<&ConfigClient>) -> FileExplorerBuilder {
|
|
||||||
let mut builder: FileExplorerBuilder = FileExplorerBuilder::new();
|
|
||||||
// Set common keys
|
|
||||||
builder
|
|
||||||
.with_file_sorting(FileSorting::ByName)
|
|
||||||
.with_stack_size(16);
|
|
||||||
match &cli {
|
|
||||||
Some(cli) => {
|
|
||||||
builder // Build according to current configuration
|
|
||||||
.with_group_dirs(cli.get_group_dirs())
|
|
||||||
.with_hidden_files(cli.get_show_hidden_files());
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
builder // Build default
|
|
||||||
.with_group_dirs(Some(GroupDirs::First));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
builder
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### build_local_explorer
|
|
||||||
///
|
|
||||||
/// Build a file explorer with local host setup
|
|
||||||
pub(super) fn build_local_explorer(cli: Option<&ConfigClient>) -> FileExplorer {
|
|
||||||
let mut builder = Self::build_explorer(cli);
|
|
||||||
if let Some(cli) = cli {
|
|
||||||
builder.with_formatter(cli.get_local_file_fmt().as_deref());
|
|
||||||
}
|
|
||||||
builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### build_remote_explorer
|
|
||||||
///
|
|
||||||
/// Build a file explorer with remote host setup
|
|
||||||
pub(super) fn build_remote_explorer(cli: Option<&ConfigClient>) -> FileExplorer {
|
|
||||||
let mut builder = Self::build_explorer(cli);
|
|
||||||
if let Some(cli) = cli {
|
|
||||||
builder.with_formatter(cli.get_remote_file_fmt().as_deref());
|
|
||||||
}
|
|
||||||
builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### build_found_explorer
|
|
||||||
///
|
|
||||||
/// Build explorer reading from `ConfigClient`, for found result (has some differences)
|
|
||||||
pub(super) fn build_found_explorer() -> FileExplorer {
|
|
||||||
FileExplorerBuilder::new()
|
|
||||||
.with_file_sorting(FileSorting::ByName)
|
|
||||||
.with_group_dirs(Some(GroupDirs::First))
|
|
||||||
.with_hidden_files(true)
|
|
||||||
.with_stack_size(0)
|
|
||||||
.with_formatter(Some("{NAME} {SYMLINK}"))
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### setup_text_editor
|
/// ### setup_text_editor
|
||||||
///
|
///
|
||||||
/// Set text editor to use
|
/// Set text editor to use
|
||||||
@@ -182,7 +125,7 @@ impl FileTransferActivity {
|
|||||||
pub(super) fn local_to_abs_path(&self, path: &Path) -> PathBuf {
|
pub(super) fn local_to_abs_path(&self, path: &Path) -> PathBuf {
|
||||||
match path.is_relative() {
|
match path.is_relative() {
|
||||||
true => {
|
true => {
|
||||||
let mut d: PathBuf = self.local.wrkdir.clone();
|
let mut d: PathBuf = self.local().wrkdir.clone();
|
||||||
d.push(path);
|
d.push(path);
|
||||||
d
|
d
|
||||||
}
|
}
|
||||||
@@ -196,7 +139,7 @@ impl FileTransferActivity {
|
|||||||
pub(super) fn remote_to_abs_path(&self, path: &Path) -> PathBuf {
|
pub(super) fn remote_to_abs_path(&self, path: &Path) -> PathBuf {
|
||||||
match path.is_relative() {
|
match path.is_relative() {
|
||||||
true => {
|
true => {
|
||||||
let mut wrkdir: PathBuf = self.remote.wrkdir.clone();
|
let mut wrkdir: PathBuf = self.remote().wrkdir.clone();
|
||||||
wrkdir.push(path);
|
wrkdir.push(path);
|
||||||
wrkdir
|
wrkdir
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,12 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
// This module is split into files, cause it's just too big
|
// This module is split into files, cause it's just too big
|
||||||
mod actions;
|
pub(self) mod actions;
|
||||||
mod misc;
|
pub(self) mod browser;
|
||||||
mod session;
|
pub(self) mod misc;
|
||||||
mod update;
|
pub(self) mod session;
|
||||||
mod view;
|
pub(self) mod update;
|
||||||
|
pub(self) mod view;
|
||||||
|
|
||||||
// Dependencies
|
// Dependencies
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
@@ -46,7 +47,9 @@ use crate::filetransfer::sftp_transfer::SftpFileTransfer;
|
|||||||
use crate::filetransfer::{FileTransfer, FileTransferProtocol};
|
use crate::filetransfer::{FileTransfer, FileTransferProtocol};
|
||||||
use crate::fs::explorer::FileExplorer;
|
use crate::fs::explorer::FileExplorer;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
|
use crate::host::Localhost;
|
||||||
use crate::system::config_client::ConfigClient;
|
use crate::system::config_client::ConfigClient;
|
||||||
|
use browser::Browser;
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
@@ -59,7 +62,6 @@ use tuirealm::View;
|
|||||||
// -- Storage keys
|
// -- Storage keys
|
||||||
|
|
||||||
const STORAGE_EXPLORER_WIDTH: &str = "FILETRANSFER_EXPLORER_WIDTH";
|
const STORAGE_EXPLORER_WIDTH: &str = "FILETRANSFER_EXPLORER_WIDTH";
|
||||||
const STORAGE_LOGBOX_WIDTH: &str = "LOGBOX_WIDTH";
|
|
||||||
|
|
||||||
// -- components
|
// -- components
|
||||||
|
|
||||||
@@ -87,16 +89,6 @@ const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING";
|
|||||||
const COMPONENT_SPAN_STATUS_BAR: &str = "STATUS_BAR";
|
const COMPONENT_SPAN_STATUS_BAR: &str = "STATUS_BAR";
|
||||||
const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
|
const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
|
||||||
|
|
||||||
/// ## FileExplorerTab
|
|
||||||
///
|
|
||||||
/// File explorer tab
|
|
||||||
enum FileExplorerTab {
|
|
||||||
Local,
|
|
||||||
Remote,
|
|
||||||
FindLocal, // Find result tab
|
|
||||||
FindRemote, // Find result tab
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## LogLevel
|
/// ## LogLevel
|
||||||
///
|
///
|
||||||
/// Log level type
|
/// Log level type
|
||||||
@@ -119,11 +111,11 @@ impl LogRecord {
|
|||||||
/// ### new
|
/// ### new
|
||||||
///
|
///
|
||||||
/// Instantiates a new LogRecord
|
/// Instantiates a new LogRecord
|
||||||
pub fn new(level: LogLevel, msg: &str) -> LogRecord {
|
pub fn new(level: LogLevel, msg: String) -> LogRecord {
|
||||||
LogRecord {
|
LogRecord {
|
||||||
time: Local::now(),
|
time: Local::now(),
|
||||||
level,
|
level,
|
||||||
msg: String::from(msg),
|
msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,30 +195,6 @@ impl Default for TransferStates {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## Browser
|
|
||||||
///
|
|
||||||
/// Browser contains the browser options
|
|
||||||
struct Browser {
|
|
||||||
pub sync_browsing: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Browser {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
sync_browsing: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Browser {
|
|
||||||
/// ### toggle_sync_browsing
|
|
||||||
///
|
|
||||||
/// Invert the current state for the sync browsing
|
|
||||||
pub fn toggle_sync_browsing(&mut self) {
|
|
||||||
self.sync_browsing = !self.sync_browsing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## FileTransferActivity
|
/// ## FileTransferActivity
|
||||||
///
|
///
|
||||||
/// FileTransferActivity is the data holder for the file transfer activity
|
/// FileTransferActivity is the data holder for the file transfer activity
|
||||||
@@ -234,28 +202,25 @@ pub struct FileTransferActivity {
|
|||||||
exit_reason: Option<ExitReason>, // Exit reason
|
exit_reason: Option<ExitReason>, // Exit reason
|
||||||
context: Option<Context>, // Context holder
|
context: Option<Context>, // Context holder
|
||||||
view: View, // View
|
view: View, // View
|
||||||
|
host: Localhost, // Localhost
|
||||||
client: Box<dyn FileTransfer>, // File transfer client
|
client: Box<dyn FileTransfer>, // File transfer client
|
||||||
local: FileExplorer, // Local File explorer state
|
browser: Browser, // Browser
|
||||||
remote: FileExplorer, // Remote File explorer state
|
|
||||||
found: Option<FileExplorer>, // File explorer for find result
|
|
||||||
tab: FileExplorerTab, // Current selected tab
|
|
||||||
log_records: VecDeque<LogRecord>, // Log records
|
log_records: VecDeque<LogRecord>, // Log records
|
||||||
log_size: usize, // Log records size (max)
|
|
||||||
transfer: TransferStates, // Transfer states
|
transfer: TransferStates, // Transfer states
|
||||||
browser: Browser, // Browser states
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileTransferActivity {
|
impl FileTransferActivity {
|
||||||
/// ### new
|
/// ### new
|
||||||
///
|
///
|
||||||
/// Instantiates a new FileTransferActivity
|
/// Instantiates a new FileTransferActivity
|
||||||
pub fn new(protocol: FileTransferProtocol) -> FileTransferActivity {
|
pub fn new(host: Localhost, protocol: FileTransferProtocol) -> FileTransferActivity {
|
||||||
// Get config client
|
// Get config client
|
||||||
let config_client: Option<ConfigClient> = Self::init_config_client();
|
let config_client: Option<ConfigClient> = Self::init_config_client();
|
||||||
FileTransferActivity {
|
FileTransferActivity {
|
||||||
exit_reason: None,
|
exit_reason: None,
|
||||||
context: None,
|
context: None,
|
||||||
view: View::init(),
|
view: View::init(),
|
||||||
|
host,
|
||||||
client: match protocol {
|
client: match protocol {
|
||||||
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new(
|
FileTransferProtocol::Sftp => Box::new(SftpFileTransfer::new(
|
||||||
Self::make_ssh_storage(config_client.as_ref()),
|
Self::make_ssh_storage(config_client.as_ref()),
|
||||||
@@ -265,16 +230,35 @@ impl FileTransferActivity {
|
|||||||
Self::make_ssh_storage(config_client.as_ref()),
|
Self::make_ssh_storage(config_client.as_ref()),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
local: Self::build_local_explorer(config_client.as_ref()),
|
browser: Browser::new(config_client.as_ref()),
|
||||||
remote: Self::build_remote_explorer(config_client.as_ref()),
|
|
||||||
found: None,
|
|
||||||
tab: FileExplorerTab::Local,
|
|
||||||
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
|
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
|
||||||
log_size: 256, // Must match with capacity
|
|
||||||
transfer: TransferStates::default(),
|
transfer: TransferStates::default(),
|
||||||
browser: Browser::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn local(&self) -> &FileExplorer {
|
||||||
|
self.browser.local()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn local_mut(&mut self) -> &mut FileExplorer {
|
||||||
|
self.browser.local_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remote(&self) -> &FileExplorer {
|
||||||
|
self.browser.remote()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn remote_mut(&mut self) -> &mut FileExplorer {
|
||||||
|
self.browser.remote_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn found(&self) -> Option<&FileExplorer> {
|
||||||
|
self.browser.found()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn found_mut(&mut self) -> Option<&mut FileExplorer> {
|
||||||
|
self.browser.found_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,10 +280,10 @@ impl Activity for FileTransferActivity {
|
|||||||
// Put raw mode on enabled
|
// Put raw mode on enabled
|
||||||
let _ = enable_raw_mode();
|
let _ = enable_raw_mode();
|
||||||
// Set working directory
|
// Set working directory
|
||||||
let pwd: PathBuf = self.context.as_ref().unwrap().local.pwd();
|
let pwd: PathBuf = self.host.pwd();
|
||||||
// Get files at current wd
|
// Get files at current wd
|
||||||
self.local_scan(pwd.as_path());
|
self.local_scan(pwd.as_path());
|
||||||
self.local.wrkdir = pwd;
|
self.local_mut().wrkdir = pwd;
|
||||||
// Configure text editor
|
// Configure text editor
|
||||||
self.setup_text_editor();
|
self.setup_text_editor();
|
||||||
// init view
|
// init view
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ impl FileTransferActivity {
|
|||||||
// Log welcome
|
// Log welcome
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Established connection with '{}': \"{}\"", addr, banner).as_ref(),
|
format!("Established connection with '{}': \"{}\"", addr, banner),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Try to change directory to entry directory
|
// Try to change directory to entry directory
|
||||||
@@ -141,7 +141,7 @@ impl FileTransferActivity {
|
|||||||
if let Ok(pwd) = self.client.pwd() {
|
if let Ok(pwd) = self.client.pwd() {
|
||||||
self.remote_scan(pwd.as_path());
|
self.remote_scan(pwd.as_path());
|
||||||
// Set wrkdir
|
// Set wrkdir
|
||||||
self.remote.wrkdir = pwd;
|
self.remote_mut().wrkdir = pwd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,8 +192,7 @@ impl FileTransferActivity {
|
|||||||
"Could not remove created file {}: {}",
|
"Could not remove created file {}: {}",
|
||||||
remote_path.display(),
|
remote_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_str(),
|
|
||||||
),
|
),
|
||||||
Ok(entry) => {
|
Ok(entry) => {
|
||||||
if let Err(err) = self.client.remove(&entry) {
|
if let Err(err) = self.client.remove(&entry) {
|
||||||
@@ -203,8 +202,7 @@ impl FileTransferActivity {
|
|||||||
"Could not remove created file {}: {}",
|
"Could not remove created file {}: {}",
|
||||||
remote_path.display(),
|
remote_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_str(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,16 +216,10 @@ impl FileTransferActivity {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Created directory \"{}\"", remote_path.display()).as_ref(),
|
format!("Created directory \"{}\"", remote_path.display()),
|
||||||
);
|
);
|
||||||
// Get files in dir
|
// Get files in dir
|
||||||
match self
|
match self.host.scan_dir(dir.abs_path.as_path()) {
|
||||||
.context
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.scan_dir(dir.abs_path.as_path())
|
|
||||||
{
|
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
// Iterate over files
|
// Iterate over files
|
||||||
for entry in entries.iter() {
|
for entry in entries.iter() {
|
||||||
@@ -265,7 +257,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Scan dir on remote
|
// Scan dir on remote
|
||||||
let path: PathBuf = self.remote.wrkdir.clone();
|
let path: PathBuf = self.remote().wrkdir.clone();
|
||||||
self.remote_scan(path.as_path());
|
self.remote_scan(path.as_path());
|
||||||
// If aborted; show popup
|
// If aborted; show popup
|
||||||
if self.transfer.aborted {
|
if self.transfer.aborted {
|
||||||
@@ -322,28 +314,25 @@ impl FileTransferActivity {
|
|||||||
err,
|
err,
|
||||||
TransferErrorReason::Abrupted | TransferErrorReason::LocalIoError(_)
|
TransferErrorReason::Abrupted | TransferErrorReason::LocalIoError(_)
|
||||||
) {
|
) {
|
||||||
let local = &mut self.context.as_mut().unwrap().local;
|
|
||||||
// Stat file
|
// Stat file
|
||||||
match local.stat(local_file_path.as_path()) {
|
match self.host.stat(local_file_path.as_path()) {
|
||||||
Err(err) => self.log(
|
Err(err) => self.log(
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!(
|
format!(
|
||||||
"Could not remove created file {}: {}",
|
"Could not remove created file {}: {}",
|
||||||
local_file_path.display(),
|
local_file_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_str(),
|
|
||||||
),
|
),
|
||||||
Ok(entry) => {
|
Ok(entry) => {
|
||||||
if let Err(err) = local.remove(&entry) {
|
if let Err(err) = self.host.remove(&entry) {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!(
|
format!(
|
||||||
"Could not remove created file {}: {}",
|
"Could not remove created file {}: {}",
|
||||||
local_file_path.display(),
|
local_file_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_str(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,24 +348,12 @@ impl FileTransferActivity {
|
|||||||
None => local_dir_path.push(dir.name.as_str()),
|
None => local_dir_path.push(dir.name.as_str()),
|
||||||
}
|
}
|
||||||
// Create directory on local
|
// Create directory on local
|
||||||
match self
|
match self.host.mkdir_ex(local_dir_path.as_path(), true) {
|
||||||
.context
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.mkdir_ex(local_dir_path.as_path(), true)
|
|
||||||
{
|
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Apply file mode to directory
|
// Apply file mode to directory
|
||||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||||
if let Some(pex) = dir.unix_pex {
|
if let Some(pex) = dir.unix_pex {
|
||||||
if let Err(err) = self
|
if let Err(err) = self.host.chmod(local_dir_path.as_path(), pex) {
|
||||||
.context
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.chmod(local_dir_path.as_path(), pex)
|
|
||||||
{
|
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!(
|
format!(
|
||||||
@@ -384,14 +361,13 @@ impl FileTransferActivity {
|
|||||||
pex,
|
pex,
|
||||||
local_dir_path.display(),
|
local_dir_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Created directory \"{}\"", local_dir_path.display()).as_ref(),
|
format!("Created directory \"{}\"", local_dir_path.display()),
|
||||||
);
|
);
|
||||||
// Get files in dir
|
// Get files in dir
|
||||||
match self.client.list_dir(dir.abs_path.as_path()) {
|
match self.client.list_dir(dir.abs_path.as_path()) {
|
||||||
@@ -426,8 +402,7 @@ impl FileTransferActivity {
|
|||||||
"Failed to create directory \"{}\": {}",
|
"Failed to create directory \"{}\": {}",
|
||||||
local_dir_path.display(),
|
local_dir_path.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,13 +439,7 @@ impl FileTransferActivity {
|
|||||||
) -> Result<(), TransferErrorReason> {
|
) -> Result<(), TransferErrorReason> {
|
||||||
// Upload file
|
// Upload file
|
||||||
// Try to open local file
|
// Try to open local file
|
||||||
match self
|
match self.host.open_file_read(local.abs_path.as_path()) {
|
||||||
.context
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.local
|
|
||||||
.open_file_read(local.abs_path.as_path())
|
|
||||||
{
|
|
||||||
Ok(mut fhnd) => match self.client.send_file(local, remote) {
|
Ok(mut fhnd) => match self.client.send_file(local, remote) {
|
||||||
Ok(mut rhnd) => {
|
Ok(mut rhnd) => {
|
||||||
// Write file
|
// Write file
|
||||||
@@ -544,7 +513,7 @@ impl FileTransferActivity {
|
|||||||
if let Err(err) = self.client.on_sent(rhnd) {
|
if let Err(err) = self.client.on_sent(rhnd) {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Warn,
|
LogLevel::Warn,
|
||||||
format!("Could not finalize remote stream: \"{}\"", err).as_str(),
|
format!("Could not finalize remote stream: \"{}\"", err),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// if upload was abrupted, return error
|
// if upload was abrupted, return error
|
||||||
@@ -559,8 +528,7 @@ impl FileTransferActivity {
|
|||||||
remote.display(),
|
remote.display(),
|
||||||
fmt_millis(self.transfer.started.elapsed()),
|
fmt_millis(self.transfer.started.elapsed()),
|
||||||
ByteSize(self.transfer.bytes_per_second()),
|
ByteSize(self.transfer.bytes_per_second()),
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(err) => return Err(TransferErrorReason::FileTransferError(err)),
|
Err(err) => return Err(TransferErrorReason::FileTransferError(err)),
|
||||||
@@ -580,7 +548,7 @@ impl FileTransferActivity {
|
|||||||
file_name: String,
|
file_name: String,
|
||||||
) -> Result<(), TransferErrorReason> {
|
) -> Result<(), TransferErrorReason> {
|
||||||
// Try to open local file
|
// Try to open local file
|
||||||
match self.context.as_ref().unwrap().local.open_file_write(local) {
|
match self.host.open_file_write(local) {
|
||||||
Ok(mut local_file) => {
|
Ok(mut local_file) => {
|
||||||
// Download file from remote
|
// Download file from remote
|
||||||
match self.client.recv_file(remote) {
|
match self.client.recv_file(remote) {
|
||||||
@@ -647,7 +615,7 @@ impl FileTransferActivity {
|
|||||||
if let Err(err) = self.client.on_recv(rhnd) {
|
if let Err(err) = self.client.on_recv(rhnd) {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Warn,
|
LogLevel::Warn,
|
||||||
format!("Could not finalize remote stream: \"{}\"", err).as_str(),
|
format!("Could not finalize remote stream: \"{}\"", err),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// If download was abrupted, return Error
|
// If download was abrupted, return Error
|
||||||
@@ -657,8 +625,7 @@ impl FileTransferActivity {
|
|||||||
// Apply file mode to file
|
// Apply file mode to file
|
||||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||||
if let Some(pex) = remote.unix_pex {
|
if let Some(pex) = remote.unix_pex {
|
||||||
if let Err(err) = self.context.as_ref().unwrap().local.chmod(local, pex)
|
if let Err(err) = self.host.chmod(local, pex) {
|
||||||
{
|
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
format!(
|
format!(
|
||||||
@@ -666,8 +633,7 @@ impl FileTransferActivity {
|
|||||||
pex,
|
pex,
|
||||||
local.display(),
|
local.display(),
|
||||||
err
|
err
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -680,8 +646,7 @@ impl FileTransferActivity {
|
|||||||
local.display(),
|
local.display(),
|
||||||
fmt_millis(self.transfer.started.elapsed()),
|
fmt_millis(self.transfer.started.elapsed()),
|
||||||
ByteSize(self.transfer.bytes_per_second()),
|
ByteSize(self.transfer.bytes_per_second()),
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(err) => return Err(TransferErrorReason::FileTransferError(err)),
|
Err(err) => return Err(TransferErrorReason::FileTransferError(err)),
|
||||||
@@ -696,10 +661,10 @@ impl FileTransferActivity {
|
|||||||
///
|
///
|
||||||
/// Scan current local directory
|
/// Scan current local directory
|
||||||
pub(super) fn local_scan(&mut self, path: &Path) {
|
pub(super) fn local_scan(&mut self, path: &Path) {
|
||||||
match self.context.as_ref().unwrap().local.scan_dir(path) {
|
match self.host.scan_dir(path) {
|
||||||
Ok(files) => {
|
Ok(files) => {
|
||||||
// Set files and sort (sorting is implicit)
|
// Set files and sort (sorting is implicit)
|
||||||
self.local.set_files(files);
|
self.local_mut().set_files(files);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.log_and_alert(
|
self.log_and_alert(
|
||||||
@@ -717,7 +682,7 @@ impl FileTransferActivity {
|
|||||||
match self.client.list_dir(path) {
|
match self.client.list_dir(path) {
|
||||||
Ok(files) => {
|
Ok(files) => {
|
||||||
// Set files and sort (sorting is implicit)
|
// Set files and sort (sorting is implicit)
|
||||||
self.remote.set_files(files);
|
self.remote_mut().set_files(files);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.log_and_alert(
|
self.log_and_alert(
|
||||||
@@ -733,21 +698,21 @@ impl FileTransferActivity {
|
|||||||
/// Change directory for local
|
/// Change directory for local
|
||||||
pub(super) fn local_changedir(&mut self, path: &Path, push: bool) {
|
pub(super) fn local_changedir(&mut self, path: &Path, push: bool) {
|
||||||
// Get current directory
|
// Get current directory
|
||||||
let prev_dir: PathBuf = self.local.wrkdir.clone();
|
let prev_dir: PathBuf = self.local().wrkdir.clone();
|
||||||
// Change directory
|
// Change directory
|
||||||
match self.context.as_mut().unwrap().local.change_wrkdir(path) {
|
match self.host.change_wrkdir(path) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Changed directory on local: {}", path.display()).as_str(),
|
format!("Changed directory on local: {}", path.display()),
|
||||||
);
|
);
|
||||||
// Reload files
|
// Reload files
|
||||||
self.local_scan(path);
|
self.local_scan(path);
|
||||||
// Set wrkdir
|
// Set wrkdir
|
||||||
self.local.wrkdir = PathBuf::from(path);
|
self.local_mut().wrkdir = PathBuf::from(path);
|
||||||
// Push prev_dir to stack
|
// Push prev_dir to stack
|
||||||
if push {
|
if push {
|
||||||
self.local.pushd(prev_dir.as_path())
|
self.local_mut().pushd(prev_dir.as_path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -762,21 +727,21 @@ impl FileTransferActivity {
|
|||||||
|
|
||||||
pub(super) fn remote_changedir(&mut self, path: &Path, push: bool) {
|
pub(super) fn remote_changedir(&mut self, path: &Path, push: bool) {
|
||||||
// Get current directory
|
// Get current directory
|
||||||
let prev_dir: PathBuf = self.remote.wrkdir.clone();
|
let prev_dir: PathBuf = self.remote().wrkdir.clone();
|
||||||
// Change directory
|
// Change directory
|
||||||
match self.client.as_mut().change_dir(path) {
|
match self.client.as_mut().change_dir(path) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("Changed directory on remote: {}", path.display()).as_str(),
|
format!("Changed directory on remote: {}", path.display()),
|
||||||
);
|
);
|
||||||
// Update files
|
// Update files
|
||||||
self.remote_scan(path);
|
self.remote_scan(path);
|
||||||
// Set wrkdir
|
// Set wrkdir
|
||||||
self.remote.wrkdir = PathBuf::from(path);
|
self.remote_mut().wrkdir = PathBuf::from(path);
|
||||||
// Push prev_dir to stack
|
// Push prev_dir to stack
|
||||||
if push {
|
if push {
|
||||||
self.remote.pushd(prev_dir.as_path())
|
self.remote_mut().pushd(prev_dir.as_path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -826,8 +791,7 @@ impl FileTransferActivity {
|
|||||||
format!(
|
format!(
|
||||||
"Changes performed through editor saved to \"{}\"!",
|
"Changes performed through editor saved to \"{}\"!",
|
||||||
path.display()
|
path.display()
|
||||||
)
|
),
|
||||||
.as_str(),
|
|
||||||
),
|
),
|
||||||
Err(err) => return Err(format!("Could not open editor: {}", err)),
|
Err(err) => return Err(format!("Could not open editor: {}", err)),
|
||||||
}
|
}
|
||||||
@@ -858,8 +822,7 @@ impl FileTransferActivity {
|
|||||||
return Err(format!("Could not open file {}: {}", file.name, err));
|
return Err(format!("Could not open file {}: {}", file.name, err));
|
||||||
}
|
}
|
||||||
// Get current file modification time
|
// Get current file modification time
|
||||||
let prev_mtime: SystemTime = match self.context.as_ref().unwrap().local.stat(tmpfile.path())
|
let prev_mtime: SystemTime = match self.host.stat(tmpfile.path()) {
|
||||||
{
|
|
||||||
Ok(e) => e.get_last_change_time(),
|
Ok(e) => e.get_last_change_time(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -874,8 +837,7 @@ impl FileTransferActivity {
|
|||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
// Get local fs entry
|
// Get local fs entry
|
||||||
let tmpfile_entry: FsEntry = match self.context.as_ref().unwrap().local.stat(tmpfile.path())
|
let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) {
|
||||||
{
|
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -893,21 +855,19 @@ impl FileTransferActivity {
|
|||||||
format!(
|
format!(
|
||||||
"File \"{}\" has changed; writing changes to remote",
|
"File \"{}\" has changed; writing changes to remote",
|
||||||
file.abs_path.display()
|
file.abs_path.display()
|
||||||
)
|
),
|
||||||
.as_ref(),
|
|
||||||
);
|
);
|
||||||
// Get local fs entry
|
// Get local fs entry
|
||||||
let tmpfile_entry: FsEntry =
|
let tmpfile_entry: FsEntry = match self.host.stat(tmpfile.path()) {
|
||||||
match self.context.as_ref().unwrap().local.stat(tmpfile.path()) {
|
Ok(e) => e,
|
||||||
Ok(e) => e,
|
Err(err) => {
|
||||||
Err(err) => {
|
return Err(format!(
|
||||||
return Err(format!(
|
"Could not stat \"{}\": {}",
|
||||||
"Could not stat \"{}\": {}",
|
tmpfile.path().display(),
|
||||||
tmpfile.path().display(),
|
err
|
||||||
err
|
))
|
||||||
))
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
// Write file
|
// Write file
|
||||||
let tmpfile_entry: &FsFile = match &tmpfile_entry {
|
let tmpfile_entry: &FsFile = match &tmpfile_entry {
|
||||||
FsEntry::Directory(_) => panic!("tempfile is a directory for some reason"),
|
FsEntry::Directory(_) => panic!("tempfile is a directory for some reason"),
|
||||||
@@ -929,7 +889,7 @@ impl FileTransferActivity {
|
|||||||
false => {
|
false => {
|
||||||
self.log(
|
self.log(
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
format!("File \"{}\" hasn't changed", file.abs_path.display()).as_ref(),
|
format!("File \"{}\" hasn't changed", file.abs_path.display()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
extern crate bytesize;
|
extern crate bytesize;
|
||||||
// locals
|
// locals
|
||||||
use super::{
|
use super::{
|
||||||
FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_FIND,
|
browser::FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_FIND,
|
||||||
COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY,
|
COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY,
|
||||||
COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO, COMPONENT_INPUT_MKDIR,
|
COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO, COMPONENT_INPUT_MKDIR,
|
||||||
COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS,
|
COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS,
|
||||||
@@ -68,7 +68,7 @@ impl FileTransferActivity {
|
|||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_RIGHT) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_RIGHT) => {
|
||||||
// Change tab
|
// Change tab
|
||||||
self.view.active(COMPONENT_EXPLORER_REMOTE);
|
self.view.active(COMPONENT_EXPLORER_REMOTE);
|
||||||
self.tab = FileExplorerTab::Remote;
|
self.browser.change_tab(FileExplorerTab::Remote);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_BACKSPACE) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_BACKSPACE) => {
|
||||||
@@ -83,7 +83,7 @@ impl FileTransferActivity {
|
|||||||
(COMPONENT_EXPLORER_LOCAL, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
|
(COMPONENT_EXPLORER_LOCAL, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
|
||||||
// Match selected file
|
// Match selected file
|
||||||
let mut entry: Option<FsEntry> = None;
|
let mut entry: Option<FsEntry> = None;
|
||||||
if let Some(e) = self.local.get(*idx) {
|
if let Some(e) = self.local().get(*idx) {
|
||||||
entry = Some(e.clone());
|
entry = Some(e.clone());
|
||||||
}
|
}
|
||||||
if let Some(entry) = entry {
|
if let Some(entry) = entry {
|
||||||
@@ -102,7 +102,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_SPACE) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_SPACE) => {
|
||||||
// Get pwd
|
// Get pwd
|
||||||
let wrkdir: PathBuf = self.remote.wrkdir.clone();
|
let wrkdir: PathBuf = self.remote().wrkdir.clone();
|
||||||
// Get file and clone (due to mutable / immutable stuff...)
|
// Get file and clone (due to mutable / immutable stuff...)
|
||||||
if self.get_local_file_entry().is_some() {
|
if self.get_local_file_entry().is_some() {
|
||||||
let file: FsEntry = self.get_local_file_entry().unwrap().clone();
|
let file: FsEntry = self.get_local_file_entry().unwrap().clone();
|
||||||
@@ -116,7 +116,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_A) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_A) => {
|
||||||
// Toggle hidden files
|
// Toggle hidden files
|
||||||
self.local.toggle_hidden_files();
|
self.local_mut().toggle_hidden_files();
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_local_filelist()
|
self.update_local_filelist()
|
||||||
}
|
}
|
||||||
@@ -129,33 +129,13 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_L) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_L) => {
|
||||||
// Reload directory
|
// Reload directory
|
||||||
let pwd: PathBuf = self.local.wrkdir.clone();
|
let pwd: PathBuf = self.local().wrkdir.clone();
|
||||||
self.local_scan(pwd.as_path());
|
self.local_scan(pwd.as_path());
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_local_filelist()
|
self.update_local_filelist()
|
||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_O) => {
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_O) => {
|
||||||
// Clone entry due to mutable stuff...
|
self.action_edit_local_file();
|
||||||
if self.get_local_file_entry().is_some() {
|
|
||||||
let fsentry: FsEntry = self.get_local_file_entry().unwrap().clone();
|
|
||||||
// Check if file
|
|
||||||
if fsentry.is_file() {
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Opening file \"{}\"...", fsentry.get_abs_path().display())
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
// Edit file
|
|
||||||
match self.edit_local_file(fsentry.get_abs_path().as_path()) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload directory
|
|
||||||
let pwd: PathBuf = self.local.wrkdir.clone();
|
|
||||||
self.local_scan(pwd.as_path());
|
|
||||||
}
|
|
||||||
Err(err) => self.log_and_alert(LogLevel::Error, err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_local_filelist()
|
self.update_local_filelist()
|
||||||
}
|
}
|
||||||
@@ -171,13 +151,13 @@ impl FileTransferActivity {
|
|||||||
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_LEFT) => {
|
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_LEFT) => {
|
||||||
// Change tab
|
// Change tab
|
||||||
self.view.active(COMPONENT_EXPLORER_LOCAL);
|
self.view.active(COMPONENT_EXPLORER_LOCAL);
|
||||||
self.tab = FileExplorerTab::Local;
|
self.browser.change_tab(FileExplorerTab::Local);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_REMOTE, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
|
(COMPONENT_EXPLORER_REMOTE, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
|
||||||
// Match selected file
|
// Match selected file
|
||||||
let mut entry: Option<FsEntry> = None;
|
let mut entry: Option<FsEntry> = None;
|
||||||
if let Some(e) = self.remote.get(*idx) {
|
if let Some(e) = self.remote().get(*idx) {
|
||||||
entry = Some(e.clone());
|
entry = Some(e.clone());
|
||||||
}
|
}
|
||||||
if let Some(entry) = entry {
|
if let Some(entry) = entry {
|
||||||
@@ -200,7 +180,7 @@ impl FileTransferActivity {
|
|||||||
let file: FsEntry = self.get_remote_file_entry().unwrap().clone();
|
let file: FsEntry = self.get_remote_file_entry().unwrap().clone();
|
||||||
let name: String = file.get_name().to_string();
|
let name: String = file.get_name().to_string();
|
||||||
// Call upload; pass realfile, keep link name
|
// Call upload; pass realfile, keep link name
|
||||||
let wrkdir: PathBuf = self.local.wrkdir.clone();
|
let wrkdir: PathBuf = self.local().wrkdir.clone();
|
||||||
self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(name));
|
self.filetransfer_recv(&file.get_realfile(), wrkdir.as_path(), Some(name));
|
||||||
self.update_local_filelist()
|
self.update_local_filelist()
|
||||||
} else {
|
} else {
|
||||||
@@ -219,7 +199,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_A) => {
|
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_A) => {
|
||||||
// Toggle hidden files
|
// Toggle hidden files
|
||||||
self.remote.toggle_hidden_files();
|
self.remote_mut().toggle_hidden_files();
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_remote_filelist()
|
self.update_remote_filelist()
|
||||||
}
|
}
|
||||||
@@ -232,33 +212,14 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_L) => {
|
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_L) => {
|
||||||
// Reload directory
|
// Reload directory
|
||||||
let pwd: PathBuf = self.remote.wrkdir.clone();
|
let pwd: PathBuf = self.remote().wrkdir.clone();
|
||||||
self.remote_scan(pwd.as_path());
|
self.remote_scan(pwd.as_path());
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_remote_filelist()
|
self.update_remote_filelist()
|
||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_O) => {
|
(COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_O) => {
|
||||||
// Clone entry due to mutable stuff...
|
// Edit file
|
||||||
if self.get_remote_file_entry().is_some() {
|
self.action_edit_remote_file();
|
||||||
let fsentry: FsEntry = self.get_remote_file_entry().unwrap().clone();
|
|
||||||
// Check if file
|
|
||||||
if let FsEntry::File(file) = fsentry.clone() {
|
|
||||||
self.log(
|
|
||||||
LogLevel::Info,
|
|
||||||
format!("Opening file \"{}\"...", fsentry.get_abs_path().display())
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
// Edit file
|
|
||||||
match self.edit_remote_file(&file) {
|
|
||||||
Ok(_) => {
|
|
||||||
// Reload directory
|
|
||||||
let pwd: PathBuf = self.remote.wrkdir.clone();
|
|
||||||
self.remote_scan(pwd.as_path());
|
|
||||||
}
|
|
||||||
Err(err) => self.log_and_alert(LogLevel::Error, err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reload file list component
|
// Reload file list component
|
||||||
self.update_remote_filelist()
|
self.update_remote_filelist()
|
||||||
}
|
}
|
||||||
@@ -371,7 +332,7 @@ impl FileTransferActivity {
|
|||||||
// Finalize find
|
// Finalize find
|
||||||
self.finalize_find();
|
self.finalize_find();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -383,7 +344,7 @@ impl FileTransferActivity {
|
|||||||
Some(Payload::One(Value::Usize(idx))) => {
|
Some(Payload::One(Value::Usize(idx))) => {
|
||||||
self.action_find_transfer(idx, None);
|
self.action_find_transfer(idx, None);
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
// NOTE: swapped by purpose
|
// NOTE: swapped by purpose
|
||||||
FileExplorerTab::FindLocal => self.update_remote_filelist(),
|
FileExplorerTab::FindLocal => self.update_remote_filelist(),
|
||||||
FileExplorerTab::FindRemote => self.update_local_filelist(),
|
FileExplorerTab::FindRemote => self.update_local_filelist(),
|
||||||
@@ -411,14 +372,14 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_INPUT_COPY, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_COPY, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
// Copy file
|
// Copy file
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_copy(input.to_string()),
|
FileExplorerTab::Local => self.action_local_copy(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_copy(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_copy(input.to_string()),
|
||||||
_ => panic!("Found tab doesn't support COPY"),
|
_ => panic!("Found tab doesn't support COPY"),
|
||||||
}
|
}
|
||||||
self.umount_copy();
|
self.umount_copy();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -431,14 +392,14 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_INPUT_EXEC, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_EXEC, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
// Exex command
|
// Exex command
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_exec(input.to_string()),
|
FileExplorerTab::Local => self.action_local_exec(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_exec(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_exec(input.to_string()),
|
||||||
_ => panic!("Found tab doesn't support EXEC"),
|
_ => panic!("Found tab doesn't support EXEC"),
|
||||||
}
|
}
|
||||||
self.umount_exec();
|
self.umount_exec();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -452,7 +413,7 @@ impl FileTransferActivity {
|
|||||||
(COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
self.umount_find_input();
|
self.umount_find_input();
|
||||||
// Find
|
// Find
|
||||||
let res: Result<Vec<FsEntry>, String> = match self.tab {
|
let res: Result<Vec<FsEntry>, String> = match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_find(input.to_string()),
|
FileExplorerTab::Local => self.action_local_find(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_find(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_find(input.to_string()),
|
||||||
_ => panic!("Trying to search for files, while already in a find result"),
|
_ => panic!("Trying to search for files, while already in a find result"),
|
||||||
@@ -465,18 +426,16 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
Ok(files) => {
|
Ok(files) => {
|
||||||
// Create explorer and load files
|
// Create explorer and load files
|
||||||
let mut explorer = Self::build_found_explorer();
|
self.browser.set_found(files);
|
||||||
explorer.set_files(files);
|
|
||||||
self.found = Some(explorer);
|
|
||||||
// Mount result widget
|
// Mount result widget
|
||||||
self.mount_find(input);
|
self.mount_find(input);
|
||||||
self.update_find_list();
|
self.update_find_list();
|
||||||
// Initialize tab
|
// Initialize tab
|
||||||
self.tab = match self.tab {
|
self.browser.change_tab(match self.browser.tab() {
|
||||||
FileExplorerTab::Local => FileExplorerTab::FindLocal,
|
FileExplorerTab::Local => FileExplorerTab::FindLocal,
|
||||||
FileExplorerTab::Remote => FileExplorerTab::FindRemote,
|
FileExplorerTab::Remote => FileExplorerTab::FindRemote,
|
||||||
_ => FileExplorerTab::FindLocal,
|
_ => FileExplorerTab::FindLocal,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -487,7 +446,7 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_GOTO, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_GOTO, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => {
|
FileExplorerTab::Local => {
|
||||||
self.action_change_local_dir(input.to_string(), false)
|
self.action_change_local_dir(input.to_string(), false)
|
||||||
}
|
}
|
||||||
@@ -500,14 +459,14 @@ impl FileTransferActivity {
|
|||||||
self.umount_goto();
|
self.umount_goto();
|
||||||
// Reload files if sync
|
// Reload files if sync
|
||||||
if self.browser.sync_browsing {
|
if self.browser.sync_browsing {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Remote => self.update_local_filelist(),
|
FileExplorerTab::Remote => self.update_local_filelist(),
|
||||||
FileExplorerTab::Local => self.update_remote_filelist(),
|
FileExplorerTab::Local => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -519,14 +478,14 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_MKDIR, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_MKDIR, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_mkdir(input.to_string()),
|
FileExplorerTab::Local => self.action_local_mkdir(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_mkdir(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_mkdir(input.to_string()),
|
||||||
_ => panic!("Found tab doesn't support MKDIR"),
|
_ => panic!("Found tab doesn't support MKDIR"),
|
||||||
}
|
}
|
||||||
self.umount_mkdir();
|
self.umount_mkdir();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -538,14 +497,14 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_NEWFILE, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_NEWFILE, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_newfile(input.to_string()),
|
FileExplorerTab::Local => self.action_local_newfile(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_newfile(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_newfile(input.to_string()),
|
||||||
_ => panic!("Found tab doesn't support NEWFILE"),
|
_ => panic!("Found tab doesn't support NEWFILE"),
|
||||||
}
|
}
|
||||||
self.umount_newfile();
|
self.umount_newfile();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -557,14 +516,14 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_RENAME, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_RENAME, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_rename(input.to_string()),
|
FileExplorerTab::Local => self.action_local_rename(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_rename(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_rename(input.to_string()),
|
||||||
_ => panic!("Found tab doesn't support RENAME"),
|
_ => panic!("Found tab doesn't support RENAME"),
|
||||||
}
|
}
|
||||||
self.umount_rename();
|
self.umount_rename();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -576,7 +535,7 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_INPUT_SAVEAS, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
(COMPONENT_INPUT_SAVEAS, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_saveas(input.to_string()),
|
FileExplorerTab::Local => self.action_local_saveas(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_remote_saveas(input.to_string()),
|
FileExplorerTab::Remote => self.action_remote_saveas(input.to_string()),
|
||||||
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
|
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
|
||||||
@@ -590,7 +549,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
self.umount_saveas();
|
self.umount_saveas();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
// NOTE: Swapped is intentional
|
// NOTE: Swapped is intentional
|
||||||
FileExplorerTab::Local => self.update_remote_filelist(),
|
FileExplorerTab::Local => self.update_remote_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_local_filelist(),
|
FileExplorerTab::Remote => self.update_local_filelist(),
|
||||||
@@ -612,7 +571,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
(COMPONENT_RADIO_DELETE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
|
(COMPONENT_RADIO_DELETE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
|
||||||
// Choice is 'YES'
|
// Choice is 'YES'
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.action_local_delete(),
|
FileExplorerTab::Local => self.action_local_delete(),
|
||||||
FileExplorerTab::Remote => self.action_remote_delete(),
|
FileExplorerTab::Remote => self.action_remote_delete(),
|
||||||
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
|
FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
|
||||||
@@ -622,14 +581,14 @@ impl FileTransferActivity {
|
|||||||
{
|
{
|
||||||
self.action_find_delete(idx);
|
self.action_find_delete(idx);
|
||||||
// Reload entries
|
// Reload entries
|
||||||
self.found.as_mut().unwrap().del_entry(idx);
|
self.found_mut().unwrap().del_entry(idx);
|
||||||
self.update_find_list();
|
self.update_find_list();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.umount_radio_delete();
|
self.umount_radio_delete();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
FileExplorerTab::FindLocal => self.update_local_filelist(),
|
FileExplorerTab::FindLocal => self.update_local_filelist(),
|
||||||
@@ -672,15 +631,15 @@ impl FileTransferActivity {
|
|||||||
3 => FileSorting::BySize,
|
3 => FileSorting::BySize,
|
||||||
_ => FileSorting::ByName,
|
_ => FileSorting::ByName,
|
||||||
};
|
};
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.local.sort_by(sorting),
|
FileExplorerTab::Local => self.local_mut().sort_by(sorting),
|
||||||
FileExplorerTab::Remote => self.remote.sort_by(sorting),
|
FileExplorerTab::Remote => self.remote_mut().sort_by(sorting),
|
||||||
_ => panic!("Found result doesn't support SORTING"),
|
_ => panic!("Found result doesn't support SORTING"),
|
||||||
}
|
}
|
||||||
// Update status bar
|
// Update status bar
|
||||||
self.refresh_status_bar();
|
self.refresh_status_bar();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.update_local_filelist(),
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
FileExplorerTab::Remote => self.update_remote_filelist(),
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -739,16 +698,16 @@ impl FileTransferActivity {
|
|||||||
"{}:{} ",
|
"{}:{} ",
|
||||||
hostname,
|
hostname,
|
||||||
FileTransferActivity::elide_wrkdir_path(
|
FileTransferActivity::elide_wrkdir_path(
|
||||||
self.local.wrkdir.as_path(),
|
self.local().wrkdir.as_path(),
|
||||||
hostname.as_str(),
|
hostname.as_str(),
|
||||||
width
|
width
|
||||||
)
|
)
|
||||||
.display()
|
.display()
|
||||||
);
|
);
|
||||||
let files: Vec<String> = self
|
let files: Vec<String> = self
|
||||||
.local
|
.local()
|
||||||
.iter_files()
|
.iter_files()
|
||||||
.map(|x: &FsEntry| self.local.fmt_file(x))
|
.map(|x: &FsEntry| self.local().fmt_file(x))
|
||||||
.collect();
|
.collect();
|
||||||
// Update
|
// Update
|
||||||
let props = FileListPropsBuilder::from(props)
|
let props = FileListPropsBuilder::from(props)
|
||||||
@@ -780,16 +739,16 @@ impl FileTransferActivity {
|
|||||||
"{}:{} ",
|
"{}:{} ",
|
||||||
params.address,
|
params.address,
|
||||||
FileTransferActivity::elide_wrkdir_path(
|
FileTransferActivity::elide_wrkdir_path(
|
||||||
self.remote.wrkdir.as_path(),
|
self.remote().wrkdir.as_path(),
|
||||||
params.address.as_str(),
|
params.address.as_str(),
|
||||||
width
|
width
|
||||||
)
|
)
|
||||||
.display()
|
.display()
|
||||||
);
|
);
|
||||||
let files: Vec<String> = self
|
let files: Vec<String> = self
|
||||||
.remote
|
.remote()
|
||||||
.iter_files()
|
.iter_files()
|
||||||
.map(|x: &FsEntry| self.remote.fmt_file(x))
|
.map(|x: &FsEntry| self.remote().fmt_file(x))
|
||||||
.collect();
|
.collect();
|
||||||
// Update
|
// Update
|
||||||
let props = FileListPropsBuilder::from(props)
|
let props = FileListPropsBuilder::from(props)
|
||||||
@@ -807,19 +766,9 @@ impl FileTransferActivity {
|
|||||||
pub(super) fn update_logbox(&mut self) -> Option<(String, Msg)> {
|
pub(super) fn update_logbox(&mut self) -> Option<(String, Msg)> {
|
||||||
match self.view.get_props(super::COMPONENT_LOG_BOX) {
|
match self.view.get_props(super::COMPONENT_LOG_BOX) {
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
// Get width
|
|
||||||
let width: usize = self
|
|
||||||
.context
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.store
|
|
||||||
.get_unsigned(super::STORAGE_LOGBOX_WIDTH)
|
|
||||||
.unwrap_or(256);
|
|
||||||
// Make log entries
|
// Make log entries
|
||||||
let mut table: TableBuilder = TableBuilder::default();
|
let mut table: TableBuilder = TableBuilder::default();
|
||||||
for (idx, record) in self.log_records.iter().enumerate() {
|
for (idx, record) in self.log_records.iter().enumerate() {
|
||||||
// Split rows by width NOTE: -37 'cause log prefix -3 cause of log line cursor
|
|
||||||
let record_rows = textwrap::wrap(record.msg.as_str(), (width as usize) - 40);
|
|
||||||
// Add row if not first row
|
// Add row if not first row
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
table.add_row();
|
table.add_row();
|
||||||
@@ -829,42 +778,29 @@ impl FileTransferActivity {
|
|||||||
LogLevel::Warn => Color::Yellow,
|
LogLevel::Warn => Color::Yellow,
|
||||||
LogLevel::Info => Color::Green,
|
LogLevel::Info => Color::Green,
|
||||||
};
|
};
|
||||||
for (idx, row) in record_rows.iter().enumerate() {
|
table
|
||||||
match idx {
|
.add_col(TextSpan::from(format!(
|
||||||
0 => {
|
"{}",
|
||||||
// First row
|
record.time.format("%Y-%m-%dT%H:%M:%S%Z")
|
||||||
table
|
)))
|
||||||
.add_col(TextSpan::from(format!(
|
.add_col(TextSpan::from(" ["))
|
||||||
"{}",
|
.add_col(
|
||||||
record.time.format("%Y-%m-%dT%H:%M:%S%Z")
|
TextSpanBuilder::new(
|
||||||
)))
|
format!(
|
||||||
.add_col(TextSpan::from(" ["))
|
"{:5}",
|
||||||
.add_col(
|
match record.level {
|
||||||
TextSpanBuilder::new(
|
LogLevel::Error => "ERROR",
|
||||||
format!(
|
LogLevel::Warn => "WARN",
|
||||||
"{:5}",
|
LogLevel::Info => "INFO",
|
||||||
match record.level {
|
}
|
||||||
LogLevel::Error => "ERROR",
|
)
|
||||||
LogLevel::Warn => "WARN",
|
.as_str(),
|
||||||
LogLevel::Info => "INFO",
|
)
|
||||||
}
|
.with_foreground(fg)
|
||||||
)
|
.build(),
|
||||||
.as_str(),
|
)
|
||||||
)
|
.add_col(TextSpan::from("]: "))
|
||||||
.with_foreground(fg)
|
.add_col(TextSpan::from(record.msg.as_ref()));
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.add_col(TextSpan::from("]: "))
|
|
||||||
.add_col(TextSpan::from(row.as_ref()));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
table.add_col(TextSpan::from(textwrap::indent(
|
|
||||||
row.as_ref(),
|
|
||||||
" ",
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let table = table.build();
|
let table = table.build();
|
||||||
let props = LogboxPropsBuilder::from(props)
|
let props = LogboxPropsBuilder::from(props)
|
||||||
@@ -911,13 +847,13 @@ impl FileTransferActivity {
|
|||||||
/// Finalize find process
|
/// Finalize find process
|
||||||
fn finalize_find(&mut self) {
|
fn finalize_find(&mut self) {
|
||||||
// Set found to none
|
// Set found to none
|
||||||
self.found = None;
|
self.browser.del_found();
|
||||||
// Restore tab
|
// Restore tab
|
||||||
self.tab = match self.tab {
|
self.browser.change_tab(match self.browser.tab() {
|
||||||
FileExplorerTab::FindLocal => FileExplorerTab::Local,
|
FileExplorerTab::FindLocal => FileExplorerTab::Local,
|
||||||
FileExplorerTab::FindRemote => FileExplorerTab::Remote,
|
FileExplorerTab::FindRemote => FileExplorerTab::Remote,
|
||||||
_ => FileExplorerTab::Local,
|
_ => FileExplorerTab::Local,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_find_list(&mut self) -> Option<(String, Msg)> {
|
fn update_find_list(&mut self) -> Option<(String, Msg)> {
|
||||||
@@ -927,11 +863,10 @@ impl FileTransferActivity {
|
|||||||
let title: String = props.texts.title.clone().unwrap_or_default();
|
let title: String = props.texts.title.clone().unwrap_or_default();
|
||||||
// Prepare files
|
// Prepare files
|
||||||
let files: Vec<String> = self
|
let files: Vec<String> = self
|
||||||
.found
|
.found()
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter_files()
|
.iter_files()
|
||||||
.map(|x: &FsEntry| self.found.as_ref().unwrap().fmt_file(x))
|
.map(|x: &FsEntry| self.found().unwrap().fmt_file(x))
|
||||||
.collect();
|
.collect();
|
||||||
let props = FileListPropsBuilder::from(props)
|
let props = FileListPropsBuilder::from(props)
|
||||||
.with_files(Some(title), files)
|
.with_files(Some(title), files)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern crate hostname;
|
|||||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||||
extern crate users;
|
extern crate users;
|
||||||
// locals
|
// locals
|
||||||
use super::{Context, FileExplorerTab, FileTransferActivity};
|
use super::{browser::FileExplorerTab, Context, FileTransferActivity};
|
||||||
use crate::fs::explorer::FileSorting;
|
use crate::fs::explorer::FileSorting;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
use crate::ui::components::{
|
use crate::ui::components::{
|
||||||
@@ -148,12 +148,9 @@ impl FileTransferActivity {
|
|||||||
if !store.isset(super::STORAGE_EXPLORER_WIDTH) {
|
if !store.isset(super::STORAGE_EXPLORER_WIDTH) {
|
||||||
store.set_unsigned(super::STORAGE_EXPLORER_WIDTH, tabs_chunks[0].width as usize);
|
store.set_unsigned(super::STORAGE_EXPLORER_WIDTH, tabs_chunks[0].width as usize);
|
||||||
}
|
}
|
||||||
if !store.isset(super::STORAGE_LOGBOX_WIDTH) {
|
|
||||||
store.set_unsigned(super::STORAGE_LOGBOX_WIDTH, chunks[1].width as usize);
|
|
||||||
}
|
|
||||||
// Draw explorers
|
// Draw explorers
|
||||||
// @! Local explorer (Find or default)
|
// @! Local explorer (Find or default)
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::FindLocal => {
|
FileExplorerTab::FindLocal => {
|
||||||
self.view
|
self.view
|
||||||
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[0])
|
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[0])
|
||||||
@@ -163,7 +160,7 @@ impl FileTransferActivity {
|
|||||||
.render(super::COMPONENT_EXPLORER_LOCAL, f, tabs_chunks[0]),
|
.render(super::COMPONENT_EXPLORER_LOCAL, f, tabs_chunks[0]),
|
||||||
}
|
}
|
||||||
// @! Remote explorer (Find or default)
|
// @! Remote explorer (Find or default)
|
||||||
match self.tab {
|
match self.browser.tab() {
|
||||||
FileExplorerTab::FindRemote => {
|
FileExplorerTab::FindRemote => {
|
||||||
self.view
|
self.view
|
||||||
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[1])
|
.render(super::COMPONENT_EXPLORER_FIND, f, tabs_chunks[1])
|
||||||
@@ -489,7 +486,7 @@ impl FileTransferActivity {
|
|||||||
|
|
||||||
pub(super) fn mount_find(&mut self, search: &str) {
|
pub(super) fn mount_find(&mut self, search: &str) {
|
||||||
// Get color
|
// Get color
|
||||||
let color: Color = match self.tab {
|
let color: Color = match self.browser.tab() {
|
||||||
FileExplorerTab::Local | FileExplorerTab::FindLocal => Color::Yellow,
|
FileExplorerTab::Local | FileExplorerTab::FindLocal => Color::Yellow,
|
||||||
FileExplorerTab::Remote | FileExplorerTab::FindRemote => Color::LightBlue,
|
FileExplorerTab::Remote | FileExplorerTab::FindRemote => Color::LightBlue,
|
||||||
};
|
};
|
||||||
@@ -637,9 +634,9 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn mount_file_sorting(&mut self) {
|
pub(super) fn mount_file_sorting(&mut self) {
|
||||||
let sorting: FileSorting = match self.tab {
|
let sorting: FileSorting = match self.browser.tab() {
|
||||||
FileExplorerTab::Local => self.local.get_file_sorting(),
|
FileExplorerTab::Local => self.local().get_file_sorting(),
|
||||||
FileExplorerTab::Remote => self.remote.get_file_sorting(),
|
FileExplorerTab::Remote => self.remote().get_file_sorting(),
|
||||||
_ => panic!("You can't mount file sorting when in found result"),
|
_ => panic!("You can't mount file sorting when in found result"),
|
||||||
};
|
};
|
||||||
let index: usize = match sorting {
|
let index: usize = match sorting {
|
||||||
@@ -824,14 +821,14 @@ impl FileTransferActivity {
|
|||||||
TextSpanBuilder::new(" Localhost file sorting: ")
|
TextSpanBuilder::new(" Localhost file sorting: ")
|
||||||
.with_foreground(Color::LightYellow)
|
.with_foreground(Color::LightYellow)
|
||||||
.build(),
|
.build(),
|
||||||
TextSpanBuilder::new(Self::get_file_sorting_str(self.local.get_file_sorting()))
|
TextSpanBuilder::new(Self::get_file_sorting_str(self.local().get_file_sorting()))
|
||||||
.with_foreground(Color::LightYellow)
|
.with_foreground(Color::LightYellow)
|
||||||
.reversed()
|
.reversed()
|
||||||
.build(),
|
.build(),
|
||||||
TextSpanBuilder::new(" Remote host file sorting: ")
|
TextSpanBuilder::new(" Remote host file sorting: ")
|
||||||
.with_foreground(Color::LightBlue)
|
.with_foreground(Color::LightBlue)
|
||||||
.build(),
|
.build(),
|
||||||
TextSpanBuilder::new(Self::get_file_sorting_str(self.remote.get_file_sorting()))
|
TextSpanBuilder::new(Self::get_file_sorting_str(self.remote().get_file_sorting()))
|
||||||
.with_foreground(Color::LightBlue)
|
.with_foreground(Color::LightBlue)
|
||||||
.reversed()
|
.reversed()
|
||||||
.build(),
|
.build(),
|
||||||
|
|||||||
@@ -202,12 +202,13 @@ impl Component for LogBox {
|
|||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
fn render(&self, render: &mut Canvas, area: Rect) {
|
fn render(&self, render: &mut Canvas, area: Rect) {
|
||||||
if self.props.visible {
|
if self.props.visible {
|
||||||
|
let width: usize = area.width as usize - 4;
|
||||||
// Make list
|
// Make list
|
||||||
let list_items: Vec<ListItem> = match self.props.texts.table.as_ref() {
|
let list_items: Vec<ListItem> = match self.props.texts.table.as_ref() {
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
Some(table) => table
|
Some(table) => table
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| ListItem::new(wrap_spans(row, area.width.into(), &self.props)))
|
.map(|row| ListItem::new(wrap_spans(row, width, &self.props)))
|
||||||
.collect(), // Make List item from TextSpan
|
.collect(), // Make List item from TextSpan
|
||||||
};
|
};
|
||||||
let w = List::new(list_items)
|
let w = List::new(list_items)
|
||||||
|
|||||||
+6
-17
@@ -33,7 +33,6 @@ extern crate tuirealm;
|
|||||||
use super::input::InputHandler;
|
use super::input::InputHandler;
|
||||||
use super::store::Store;
|
use super::store::Store;
|
||||||
use crate::filetransfer::FileTransferProtocol;
|
use crate::filetransfer::FileTransferProtocol;
|
||||||
use crate::host::Localhost;
|
|
||||||
use crate::system::config_client::ConfigClient;
|
use crate::system::config_client::ConfigClient;
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
@@ -49,7 +48,6 @@ use tuirealm::tui::Terminal;
|
|||||||
///
|
///
|
||||||
/// Context holds data structures used by the ui
|
/// Context holds data structures used by the ui
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub local: Localhost,
|
|
||||||
pub ft_params: Option<FileTransferParams>,
|
pub ft_params: Option<FileTransferParams>,
|
||||||
pub(crate) config_client: Option<ConfigClient>,
|
pub(crate) config_client: Option<ConfigClient>,
|
||||||
pub(crate) store: Store,
|
pub(crate) store: Store,
|
||||||
@@ -74,16 +72,11 @@ impl Context {
|
|||||||
/// ### new
|
/// ### new
|
||||||
///
|
///
|
||||||
/// Instantiates a new Context
|
/// Instantiates a new Context
|
||||||
pub fn new(
|
pub fn new(config_client: Option<ConfigClient>, error: Option<String>) -> Context {
|
||||||
local: Localhost,
|
|
||||||
config_client: Option<ConfigClient>,
|
|
||||||
error: Option<String>,
|
|
||||||
) -> Context {
|
|
||||||
// Create terminal
|
// Create terminal
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
assert!(execute!(stdout, EnterAlternateScreen).is_ok());
|
assert!(execute!(stdout, EnterAlternateScreen).is_ok());
|
||||||
Context {
|
Context {
|
||||||
local,
|
|
||||||
ft_params: None,
|
ft_params: None,
|
||||||
config_client,
|
config_client,
|
||||||
store: Store::init(),
|
store: Store::init(),
|
||||||
@@ -93,14 +86,12 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: in case is necessary
|
|
||||||
/// ### set_error
|
/// ### set_error
|
||||||
///
|
///
|
||||||
/// Set context error
|
/// Set context error
|
||||||
pub fn set_error(&mut self, err: String) {
|
pub fn set_error(&mut self, err: String) {
|
||||||
self.error = Some(err);
|
self.error = Some(err);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/// ### get_error
|
/// ### get_error
|
||||||
///
|
///
|
||||||
@@ -165,7 +156,6 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ui_context_ft_params() {
|
fn test_ui_context_ft_params() {
|
||||||
@@ -181,16 +171,15 @@ mod tests {
|
|||||||
#[cfg(not(feature = "githubActions"))]
|
#[cfg(not(feature = "githubActions"))]
|
||||||
fn test_ui_context() {
|
fn test_ui_context() {
|
||||||
// Prepare stuff
|
// Prepare stuff
|
||||||
let wrkdir: PathBuf = std::env::current_dir().unwrap_or(PathBuf::from("/"));
|
let mut ctx: Context = Context::new(None, Some(String::from("alles kaput")));
|
||||||
let mut ctx: Context = Context::new(
|
|
||||||
Localhost::new(wrkdir).ok().unwrap(),
|
|
||||||
None,
|
|
||||||
Some(String::from("alles kaput")),
|
|
||||||
);
|
|
||||||
assert!(ctx.error.is_some());
|
assert!(ctx.error.is_some());
|
||||||
assert_eq!(ctx.get_error().unwrap().as_str(), "alles kaput");
|
assert_eq!(ctx.get_error().unwrap().as_str(), "alles kaput");
|
||||||
assert!(ctx.error.is_none());
|
assert!(ctx.error.is_none());
|
||||||
assert!(ctx.get_error().is_none());
|
assert!(ctx.get_error().is_none());
|
||||||
|
ctx.set_error(String::from("err"));
|
||||||
|
assert!(ctx.error.is_some());
|
||||||
|
assert!(ctx.get_error().is_some());
|
||||||
|
assert!(ctx.get_error().is_none());
|
||||||
// Try other methods
|
// Try other methods
|
||||||
ctx.enter_alternate_screen();
|
ctx.enter_alternate_screen();
|
||||||
ctx.clear_screen();
|
ctx.clear_screen();
|
||||||
|
|||||||
Reference in New Issue
Block a user