mirror of
https://github.com/veeso/termscp.git
synced 2026-09-28 15:01:19 -07:00
Sync browsing prompts to create dir (#85)
This commit is contained in:
@@ -26,84 +26,87 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
// locals
|
||||
use super::FileTransferActivity;
|
||||
use super::{FileExplorerTab, FileTransferActivity, LogLevel, Msg, PendingActionMsg};
|
||||
|
||||
use remotefs::Directory;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Describes destination for sync browsing
|
||||
enum SyncBrowsingDestination {
|
||||
Path(String),
|
||||
ParentDir,
|
||||
PreviousDir,
|
||||
}
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Enter a directory on local host from entry
|
||||
/// Return true whether the directory changed
|
||||
pub(crate) fn action_enter_local_dir(&mut self, dir: Directory, block_sync: bool) -> bool {
|
||||
pub(crate) fn action_enter_local_dir(&mut self, dir: Directory) {
|
||||
self.local_changedir(dir.path.as_path(), true);
|
||||
if self.browser.sync_browsing && !block_sync {
|
||||
self.action_change_remote_dir(dir.name, true);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::Path(dir.name));
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Enter a directory on local host from entry
|
||||
/// Return true whether the directory changed
|
||||
pub(crate) fn action_enter_remote_dir(&mut self, dir: Directory, block_sync: bool) -> bool {
|
||||
pub(crate) fn action_enter_remote_dir(&mut self, dir: Directory) {
|
||||
self.remote_changedir(dir.path.as_path(), true);
|
||||
if self.browser.sync_browsing && !block_sync {
|
||||
self.action_change_local_dir(dir.name, true);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::Path(dir.name));
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Change local directory reading value from input
|
||||
pub(crate) fn action_change_local_dir(&mut self, input: String, block_sync: bool) {
|
||||
pub(crate) fn action_change_local_dir(&mut self, input: String) {
|
||||
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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::Path(input));
|
||||
}
|
||||
}
|
||||
|
||||
/// Change remote directory reading value from input
|
||||
pub(crate) fn action_change_remote_dir(&mut self, input: String, block_sync: bool) {
|
||||
pub(crate) fn action_change_remote_dir(&mut self, input: String) {
|
||||
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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::Path(input));
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to previous directory from localhost
|
||||
pub(crate) fn action_go_to_previous_local_dir(&mut self, block_sync: bool) {
|
||||
pub(crate) fn action_go_to_previous_local_dir(&mut self) {
|
||||
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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::PreviousDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to previous directory from remote host
|
||||
pub(crate) fn action_go_to_previous_remote_dir(&mut self, block_sync: bool) {
|
||||
pub(crate) fn action_go_to_previous_remote_dir(&mut self) {
|
||||
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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::PreviousDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Go to upper directory on local host
|
||||
pub(crate) fn action_go_to_local_upper_dir(&mut self, block_sync: bool) {
|
||||
pub(crate) fn action_go_to_local_upper_dir(&mut self) {
|
||||
// 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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::ParentDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,15 +114,140 @@ impl FileTransferActivity {
|
||||
/// #### 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) {
|
||||
pub(crate) fn action_go_to_remote_upper_dir(&mut self) {
|
||||
// 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);
|
||||
if self.browser.sync_browsing {
|
||||
self.synchronize_browsing(SyncBrowsingDestination::ParentDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- sync browsing
|
||||
|
||||
/// Synchronize browsing on the target browser.
|
||||
/// If destination doesn't exist, then prompt for directory creation.
|
||||
fn synchronize_browsing(&mut self, destination: SyncBrowsingDestination) {
|
||||
// Get destination path
|
||||
let path = match self.resolve_sync_browsing_destination(&destination) {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
};
|
||||
trace!("Synchronizing browsing to path {}", path.display());
|
||||
// Check whether destination exists on host
|
||||
let exists = match self.browser.tab() {
|
||||
FileExplorerTab::Local => match self.client.exists(path.as_path()) {
|
||||
Ok(e) => e,
|
||||
Err(err) => {
|
||||
error!(
|
||||
"Failed to check whether {} exists on remote: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
FileExplorerTab::Remote => self.host.file_exists(path.as_path()),
|
||||
_ => return,
|
||||
};
|
||||
let name = path
|
||||
.file_name()
|
||||
.map(|x| x.to_string_lossy().to_string())
|
||||
.unwrap();
|
||||
// If file doesn't exist, ask whether to create directory
|
||||
if !exists {
|
||||
trace!("Directory doesn't exist; asking to user if I should create it");
|
||||
// Mount dialog
|
||||
self.mount_sync_browsing_mkdir_popup(&name);
|
||||
// Wait for dialog dismiss
|
||||
if self.wait_for_pending_msg(&[
|
||||
Msg::PendingAction(PendingActionMsg::MakePendingDirectory),
|
||||
Msg::PendingAction(PendingActionMsg::CloseSyncBrowsingMkdirPopup),
|
||||
]) == Msg::PendingAction(PendingActionMsg::MakePendingDirectory)
|
||||
{
|
||||
trace!("User wants to create the unexisting directory");
|
||||
// Make directory
|
||||
match self.browser.tab() {
|
||||
FileExplorerTab::Local => self.action_remote_mkdir(name.clone()),
|
||||
FileExplorerTab::Remote => self.action_local_mkdir(name.clone()),
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
// Do not synchronize, disable sync browsing and return
|
||||
trace!("The user doesn't want to create the directory; disabling synchronized browsing");
|
||||
self.log(
|
||||
LogLevel::Warn,
|
||||
format!(
|
||||
"Refused to create '{}'; synchronized browsing disabled",
|
||||
name
|
||||
),
|
||||
);
|
||||
self.browser.toggle_sync_browsing();
|
||||
self.refresh_remote_status_bar();
|
||||
self.umount_sync_browsing_mkdir_popup();
|
||||
return;
|
||||
}
|
||||
// Umount dialog
|
||||
self.umount_sync_browsing_mkdir_popup();
|
||||
}
|
||||
trace!("Entering on the other explorer directory {}", name);
|
||||
// Enter directory
|
||||
match destination {
|
||||
SyncBrowsingDestination::ParentDir => match self.browser.tab() {
|
||||
FileExplorerTab::Local => self.remote_changedir(path.as_path(), true),
|
||||
FileExplorerTab::Remote => self.local_changedir(path.as_path(), true),
|
||||
_ => {}
|
||||
},
|
||||
SyncBrowsingDestination::Path(_) => match self.browser.tab() {
|
||||
FileExplorerTab::Local => self.remote_changedir(path.as_path(), true),
|
||||
FileExplorerTab::Remote => self.local_changedir(path.as_path(), true),
|
||||
_ => {}
|
||||
},
|
||||
SyncBrowsingDestination::PreviousDir => match self.browser.tab() {
|
||||
FileExplorerTab::Local => self.remote_changedir(path.as_path(), false),
|
||||
FileExplorerTab::Remote => self.local_changedir(path.as_path(), false),
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve synchronized browsing destination
|
||||
fn resolve_sync_browsing_destination(
|
||||
&mut self,
|
||||
destination: &SyncBrowsingDestination,
|
||||
) -> Option<PathBuf> {
|
||||
match (destination, self.browser.tab()) {
|
||||
// NOTE: tab and methods are switched on purpose
|
||||
(SyncBrowsingDestination::ParentDir, FileExplorerTab::Local) => {
|
||||
self.remote().wrkdir.parent().map(|x| x.to_path_buf())
|
||||
}
|
||||
(SyncBrowsingDestination::ParentDir, FileExplorerTab::Remote) => {
|
||||
self.local().wrkdir.parent().map(|x| x.to_path_buf())
|
||||
}
|
||||
(SyncBrowsingDestination::PreviousDir, FileExplorerTab::Local) => {
|
||||
if let Some(p) = self.remote_mut().popd() {
|
||||
Some(p)
|
||||
} else {
|
||||
warn!("Cannot synchronize browsing: remote has no previous directory in stack");
|
||||
None
|
||||
}
|
||||
}
|
||||
(SyncBrowsingDestination::PreviousDir, FileExplorerTab::Remote) => {
|
||||
if let Some(p) = self.local_mut().popd() {
|
||||
Some(p)
|
||||
} else {
|
||||
warn!("Cannot synchronize browsing: local has no previous directory in stack");
|
||||
None
|
||||
}
|
||||
}
|
||||
(SyncBrowsingDestination::Path(p), _) => Some(PathBuf::from(p.as_str())),
|
||||
_ => {
|
||||
warn!("Cannot synchronize browsing for current explorer");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
pub(self) use super::{
|
||||
browser::FileExplorerTab, FileTransferActivity, Id, LogLevel, TransferOpts, TransferPayload,
|
||||
browser::FileExplorerTab, FileTransferActivity, Id, LogLevel, Msg, PendingActionMsg,
|
||||
TransferOpts, TransferPayload,
|
||||
};
|
||||
pub(self) use remotefs::Entry;
|
||||
use tuirealm::{State, StateValue};
|
||||
@@ -41,6 +42,7 @@ pub(crate) mod find;
|
||||
pub(crate) mod mkdir;
|
||||
pub(crate) mod newfile;
|
||||
pub(crate) mod open;
|
||||
mod pending;
|
||||
pub(crate) mod rename;
|
||||
pub(crate) mod save;
|
||||
pub(crate) mod submit;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//! ## Pending actions
|
||||
//!
|
||||
//! this little module exposes the routine to create a pending action on the file transfer activity.
|
||||
//! A pending action is an action which blocks the execution of the application in await of a certain `Msg`.
|
||||
|
||||
/**
|
||||
* 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 super::{FileTransferActivity, Msg};
|
||||
|
||||
use tuirealm::PollStrategy;
|
||||
|
||||
impl FileTransferActivity {
|
||||
/// Block execution of activity, preventing ANY kind of message not specified in the `wait_for` argument.
|
||||
/// Once `wait_for` clause is satisfied, the function returns.
|
||||
///
|
||||
/// Returns the message which satisfied the clause
|
||||
///
|
||||
/// NOTE: The view is redrawn as usual
|
||||
pub(super) fn wait_for_pending_msg(&mut self, wait_for: &[Msg]) -> Msg {
|
||||
self.redraw = true;
|
||||
loop {
|
||||
// Poll
|
||||
match self.app.tick(PollStrategy::Once) {
|
||||
Ok(messages) => {
|
||||
if !messages.is_empty() {
|
||||
self.redraw = true;
|
||||
}
|
||||
if let Some(msg) = messages.into_iter().find(|m| wait_for.contains(m)) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Application error: {}", err);
|
||||
}
|
||||
}
|
||||
// Redraw
|
||||
if self.redraw {
|
||||
self.view();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ enum SubmitAction {
|
||||
impl FileTransferActivity {
|
||||
/// Decides which action to perform on submit for local explorer
|
||||
/// Return true whether the directory changed
|
||||
pub(crate) fn action_submit_local(&mut self, entry: Entry) -> bool {
|
||||
pub(crate) fn action_submit_local(&mut self, entry: Entry) {
|
||||
let (action, entry) = match &entry {
|
||||
Entry::Directory(_) => (SubmitAction::ChangeDir, entry),
|
||||
Entry::File(File {
|
||||
@@ -67,18 +67,14 @@ impl FileTransferActivity {
|
||||
}
|
||||
Entry::File(_) => (SubmitAction::None, entry),
|
||||
};
|
||||
match (action, entry) {
|
||||
(SubmitAction::ChangeDir, Entry::Directory(dir)) => {
|
||||
self.action_enter_local_dir(dir, false)
|
||||
}
|
||||
(SubmitAction::ChangeDir, _) => false,
|
||||
(SubmitAction::None, _) => false,
|
||||
if let (SubmitAction::ChangeDir, Entry::Directory(dir)) = (action, entry) {
|
||||
self.action_enter_local_dir(dir)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decides which action to perform on submit for remote explorer
|
||||
/// Return true whether the directory changed
|
||||
pub(crate) fn action_submit_remote(&mut self, entry: Entry) -> bool {
|
||||
pub(crate) fn action_submit_remote(&mut self, entry: Entry) {
|
||||
let (action, entry) = match &entry {
|
||||
Entry::Directory(_) => (SubmitAction::ChangeDir, entry),
|
||||
Entry::File(File {
|
||||
@@ -107,12 +103,8 @@ impl FileTransferActivity {
|
||||
}
|
||||
Entry::File(_) => (SubmitAction::None, entry),
|
||||
};
|
||||
match (action, entry) {
|
||||
(SubmitAction::ChangeDir, Entry::Directory(dir)) => {
|
||||
self.action_enter_remote_dir(dir, false)
|
||||
}
|
||||
(SubmitAction::ChangeDir, _) => false,
|
||||
(SubmitAction::None, _) => false,
|
||||
if let (SubmitAction::ChangeDir, Entry::Directory(dir)) = (action, entry) {
|
||||
self.action_enter_remote_dir(dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user