mirror of
https://github.com/veeso/termscp.git
synced 2026-09-26 05:51:20 -07:00
feat: issue 256 - filter files (#266)
This commit is contained in:
@@ -43,6 +43,7 @@ Released on ??
|
|||||||
- [Issue 226](https://github.com/veeso/termscp/issues/226): Use ssh-agent
|
- [Issue 226](https://github.com/veeso/termscp/issues/226): Use ssh-agent
|
||||||
- [Issue 241](https://github.com/veeso/termscp/issues/241): Jump to next entry after select
|
- [Issue 241](https://github.com/veeso/termscp/issues/241): Jump to next entry after select
|
||||||
- [Issue 255](https://github.com/veeso/termscp/issues/255): New keybindings `Ctrl + Shift + A` to deselect all files
|
- [Issue 255](https://github.com/veeso/termscp/issues/255): New keybindings `Ctrl + Shift + A` to deselect all files
|
||||||
|
- [Issue 256](https://github.com/veeso/termscp/issues/256): Filter files in current folder. You can now filter files by pressing `/`. Both wildmatch and regex are accepted to filter files.
|
||||||
- [Issue 257](https://github.com/veeso/termscp/issues/257): CLI remote args cannot handle '@' in the username
|
- [Issue 257](https://github.com/veeso/termscp/issues/257): CLI remote args cannot handle '@' in the username
|
||||||
|
|
||||||
## 0.13.0
|
## 0.13.0
|
||||||
|
|||||||
Generated
+1
@@ -3553,6 +3553,7 @@ dependencies = [
|
|||||||
"open",
|
"open",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
|
"regex",
|
||||||
"remotefs",
|
"remotefs",
|
||||||
"remotefs-aws-s3",
|
"remotefs-aws-s3",
|
||||||
"remotefs-ftp",
|
"remotefs-ftp",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ notify = "=4.0.17"
|
|||||||
notify-rust = { version = "^4.5", default-features = false, features = ["d"] }
|
notify-rust = { version = "^4.5", default-features = false, features = ["d"] }
|
||||||
open = "^5.0"
|
open = "^5.0"
|
||||||
rand = "^0.8.5"
|
rand = "^0.8.5"
|
||||||
|
regex = "^1"
|
||||||
remotefs = "^0.2.0"
|
remotefs = "^0.2.0"
|
||||||
remotefs-aws-s3 = { version = "^0.2.4", default-features = false, features = [
|
remotefs-aws-s3 = { version = "^0.2.4", default-features = false, features = [
|
||||||
"find",
|
"find",
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ Para cambiar de panel, debe escribir `<LEFT>` para mover el panel del explorador
|
|||||||
| `<X>` | Ejecutar un comando | eXecute |
|
| `<X>` | Ejecutar un comando | eXecute |
|
||||||
| `<Y>` | Alternar navegación sincronizada | sYnc |
|
| `<Y>` | Alternar navegación sincronizada | sYnc |
|
||||||
| `<Z>` | Cambiar ppermisos de archivo | |
|
| `<Z>` | Cambiar ppermisos de archivo | |
|
||||||
|
| `</>` | Filtrar archivos (se admite tanto regex como coincidencias con comodines) | |
|
||||||
| `<CTRL+A>` | Seleccionar todos los archivos | |
|
| `<CTRL+A>` | Seleccionar todos los archivos | |
|
||||||
| `<ALT+A>` | Deseleccionar todos los archivos | |
|
| `<ALT+A>` | Deseleccionar todos los archivos | |
|
||||||
| `<CTRL+C>` | Abortar el proceso de transferencia de archivos | |
|
| `<CTRL+C>` | Abortar el proceso de transferencia de archivos | |
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ Pour changer de panneau, vous devez taper `<LEFT>` pour déplacer le panneau de
|
|||||||
| `<X>` | Exécuter une commande | eXecute |
|
| `<X>` | Exécuter une commande | eXecute |
|
||||||
| `<Y>` | Basculer la navigation synchronisée | sYnc |
|
| `<Y>` | Basculer la navigation synchronisée | sYnc |
|
||||||
| `<Z>` | Changer permissions de fichier | |
|
| `<Z>` | Changer permissions de fichier | |
|
||||||
|
| `</>` | Filtrer les fichiers (les expressions régulières et les correspondances génériques sont prises en charge) | |
|
||||||
| `<CTRL+A>` | Sélectionner tous les fichiers | |
|
| `<CTRL+A>` | Sélectionner tous les fichiers | |
|
||||||
| `<ALT+A>` | Desélectionner tous les fichiers | |
|
| `<ALT+A>` | Desélectionner tous les fichiers | |
|
||||||
| `<CTRL+C>` | Abandonner le processus de transfert de fichiers | |
|
| `<CTRL+C>` | Abandonner le processus de transfert de fichiers | |
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ Per cambiare pannello ti puoi muovere con le frecce, `<LEFT>` per andare sul pan
|
|||||||
| `<X>` | Esegui comando shell | eXecute |
|
| `<X>` | Esegui comando shell | eXecute |
|
||||||
| `<Y>` | Abilita/disabilita Sync-Browsing | sYnc |
|
| `<Y>` | Abilita/disabilita Sync-Browsing | sYnc |
|
||||||
| `<Z>` | Modifica permessi file | |
|
| `<Z>` | Modifica permessi file | |
|
||||||
|
| `</>` | Filtra i file (supporta sia regex che wildmatch ) | |
|
||||||
| `<CTRL+A>` | Seleziona tutti i file | |
|
| `<CTRL+A>` | Seleziona tutti i file | |
|
||||||
| `<ALT+A>` | Deseleziona tutti i file | |
|
| `<ALT+A>` | Deseleziona tutti i file | |
|
||||||
| `<CTRL+C>` | Annulla trasferimento file | |
|
| `<CTRL+C>` | Annulla trasferimento file | |
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ In order to change panel you need to type `<LEFT>` to move the remote explorer p
|
|||||||
| `<X>` | Execute a command | eXecute |
|
| `<X>` | Execute a command | eXecute |
|
||||||
| `<Y>` | Toggle synchronized browsing | sYnc |
|
| `<Y>` | Toggle synchronized browsing | sYnc |
|
||||||
| `<Z>` | Change file mode | |
|
| `<Z>` | Change file mode | |
|
||||||
|
| `</>` | Filter files (both regex and wildmatch is supported) | |
|
||||||
| `<CTRL+A>` | Select all files | |
|
| `<CTRL+A>` | Select all files | |
|
||||||
| `<ALT+A>` | Deselect all files | |
|
| `<ALT+A>` | Deselect all files | |
|
||||||
| `<CTRL+C>` | Abort file transfer process | |
|
| `<CTRL+C>` | Abort file transfer process | |
|
||||||
|
|||||||
@@ -257,6 +257,7 @@ Para trocar de painel, você precisa pressionar `<LEFT>` para mover para o paine
|
|||||||
| `<X>` | Executar um comando | Executar |
|
| `<X>` | Executar um comando | Executar |
|
||||||
| `<Y>` | Alternar navegação sincronizada | Sincronizar |
|
| `<Y>` | Alternar navegação sincronizada | Sincronizar |
|
||||||
| `<Z>` | Alterar modo de arquivo | |
|
| `<Z>` | Alterar modo de arquivo | |
|
||||||
|
| `</>` | Filtrar arquivos (suporte tanto para regex quanto para coringa) | |
|
||||||
| `<CTRL+A>` | Selecionar todos os arquivos | |
|
| `<CTRL+A>` | Selecionar todos os arquivos | |
|
||||||
| `<ALT+A>` | Deselecionar todos os arquivos | |
|
| `<ALT+A>` | Deselecionar todos os arquivos | |
|
||||||
| `<CTRL+C>` | Abortir processo de transferência de arquivo | |
|
| `<CTRL+C>` | Abortir processo de transferência de arquivo | |
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ termscp中的文件资源管理器是指你与远程建立连接后可以看到
|
|||||||
| `<X>` | 运行命令 | eXecute |
|
| `<X>` | 运行命令 | eXecute |
|
||||||
| `<Y>` | 是否开启同步浏览 | sYnc |
|
| `<Y>` | 是否开启同步浏览 | sYnc |
|
||||||
| `<Z>` | 更改文件权限 | |
|
| `<Z>` | 更改文件权限 | |
|
||||||
|
| `</>` | 过滤文件(支持正则表达式和通配符匹配) | |
|
||||||
| `<CTRL+A>` | 选中所有文件 | |
|
| `<CTRL+A>` | 选中所有文件 | |
|
||||||
| `<ALT+A>` | 取消选择所有文件 | |
|
| `<ALT+A>` | 取消选择所有文件 | |
|
||||||
| `<CTRL+C>` | 终止文件传输 | |
|
| `<CTRL+C>` | 终止文件传输 | |
|
||||||
|
|||||||
@@ -98,13 +98,6 @@ impl FileExplorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// Return amount of files
|
|
||||||
pub fn count(&self) -> usize {
|
|
||||||
self.files.len()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// Iterate over files
|
/// Iterate over files
|
||||||
/// Filters are applied based on current options (e.g. hidden files not returned)
|
/// Filters are applied based on current options (e.g. hidden files not returned)
|
||||||
pub fn iter_files(&self) -> impl Iterator<Item = &File> + '_ {
|
pub fn iter_files(&self) -> impl Iterator<Item = &File> + '_ {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use remotefs::File;
|
||||||
|
use wildmatch::WildMatch;
|
||||||
|
|
||||||
|
use crate::ui::activities::filetransfer::lib::browser::FileExplorerTab;
|
||||||
|
use crate::ui::activities::filetransfer::FileTransferActivity;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Filter {
|
||||||
|
Regex(Regex),
|
||||||
|
Wildcard(WildMatch),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Filter {
|
||||||
|
type Err = ();
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
// try as regex
|
||||||
|
if let Ok(regex) = Regex::new(s) {
|
||||||
|
Ok(Self::Regex(regex))
|
||||||
|
} else {
|
||||||
|
Ok(Self::Wildcard(WildMatch::new(s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filter {
|
||||||
|
fn matches(&self, s: &str) -> bool {
|
||||||
|
debug!("matching '{s}' with {:?}", self);
|
||||||
|
match self {
|
||||||
|
Self::Regex(re) => re.is_match(s),
|
||||||
|
Self::Wildcard(wm) => wm.matches(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileTransferActivity {
|
||||||
|
pub fn filter(&self, filter: &str) -> Vec<File> {
|
||||||
|
let filter = Filter::from_str(filter).unwrap();
|
||||||
|
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => self.browser.local().iter_files(),
|
||||||
|
FileExplorerTab::Remote => self.browser.remote().iter_files(),
|
||||||
|
_ => return vec![],
|
||||||
|
}
|
||||||
|
.filter(|f| filter.matches(&f.name()))
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ pub(crate) mod copy;
|
|||||||
pub(crate) mod delete;
|
pub(crate) mod delete;
|
||||||
pub(crate) mod edit;
|
pub(crate) mod edit;
|
||||||
pub(crate) mod exec;
|
pub(crate) mod exec;
|
||||||
|
pub(crate) mod filter;
|
||||||
pub(crate) mod find;
|
pub(crate) mod find;
|
||||||
pub(crate) mod mkdir;
|
pub(crate) mod mkdir;
|
||||||
pub(crate) mod newfile;
|
pub(crate) mod newfile;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ mod transfer;
|
|||||||
pub use misc::FooterBar;
|
pub use misc::FooterBar;
|
||||||
pub use popups::{
|
pub use popups::{
|
||||||
ChmodPopup, CopyPopup, DeletePopup, DisconnectPopup, ErrorPopup, ExecPopup, FatalPopup,
|
ChmodPopup, CopyPopup, DeletePopup, DisconnectPopup, ErrorPopup, ExecPopup, FatalPopup,
|
||||||
FileInfoPopup, FindPopup, GoToPopup, KeybindingsPopup, MkdirPopup, NewfilePopup, OpenWithPopup,
|
FileInfoPopup, FilterPopup, FindPopup, GoToPopup, KeybindingsPopup, MkdirPopup, NewfilePopup,
|
||||||
ProgressBarFull, ProgressBarPartial, QuitPopup, RenamePopup, ReplacePopup,
|
OpenWithPopup, ProgressBarFull, ProgressBarPartial, QuitPopup, RenamePopup, ReplacePopup,
|
||||||
ReplacingFilesListPopup, SaveAsPopup, SortingPopup, StatusBarLocal, StatusBarRemote,
|
ReplacingFilesListPopup, SaveAsPopup, SortingPopup, StatusBarLocal, StatusBarRemote,
|
||||||
SymlinkPopup, SyncBrowsingMkdirPopup, WaitPopup, WatchedPathsList, WatcherPopup,
|
SymlinkPopup, SyncBrowsingMkdirPopup, WaitPopup, WatchedPathsList, WatcherPopup,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -111,6 +111,90 @@ impl Component<Msg, NoUserEvent> for CopyPopup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(MockComponent)]
|
||||||
|
pub struct FilterPopup {
|
||||||
|
component: Input,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilterPopup {
|
||||||
|
pub fn new(color: Color) -> Self {
|
||||||
|
Self {
|
||||||
|
component: Input::default()
|
||||||
|
.borders(
|
||||||
|
Borders::default()
|
||||||
|
.color(color)
|
||||||
|
.modifiers(BorderType::Rounded),
|
||||||
|
)
|
||||||
|
.foreground(color)
|
||||||
|
.input_type(InputType::Text)
|
||||||
|
.placeholder(
|
||||||
|
"regex or wildmatch",
|
||||||
|
Style::default().fg(Color::Rgb(128, 128, 128)),
|
||||||
|
)
|
||||||
|
.title("Filter files by regex or wildmatch", Alignment::Center),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component<Msg, NoUserEvent> for FilterPopup {
|
||||||
|
fn on(&mut self, ev: Event<NoUserEvent>) -> Option<Msg> {
|
||||||
|
match ev {
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Left, ..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::Move(Direction::Left));
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Right, ..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::Move(Direction::Right));
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Home, ..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::GoTo(Position::Begin));
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent { code: Key::End, .. }) => {
|
||||||
|
self.perform(Cmd::GoTo(Position::End));
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Delete, ..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::Cancel);
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Backspace,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::Delete);
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Char(ch),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
self.perform(Cmd::Type(ch));
|
||||||
|
Some(Msg::None)
|
||||||
|
}
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Enter, ..
|
||||||
|
}) => match self.state() {
|
||||||
|
State::One(StateValue::String(filter)) => Some(Msg::Ui(UiMsg::FilterFiles(filter))),
|
||||||
|
_ => Some(Msg::None),
|
||||||
|
},
|
||||||
|
Event::Keyboard(KeyEvent { code: Key::Esc, .. }) => {
|
||||||
|
Some(Msg::Ui(UiMsg::CloseFilterPopup))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(MockComponent)]
|
#[derive(MockComponent)]
|
||||||
pub struct DeletePopup {
|
pub struct DeletePopup {
|
||||||
component: Radio,
|
component: Radio,
|
||||||
@@ -790,6 +874,9 @@ impl KeybindingsPopup {
|
|||||||
.add_col(TextSpan::new("<Z>").bold().fg(key_color))
|
.add_col(TextSpan::new("<Z>").bold().fg(key_color))
|
||||||
.add_col(TextSpan::from(" Change file permissions"))
|
.add_col(TextSpan::from(" Change file permissions"))
|
||||||
.add_row()
|
.add_row()
|
||||||
|
.add_col(TextSpan::new("</>").bold().fg(key_color))
|
||||||
|
.add_col(TextSpan::from(" Filter files"))
|
||||||
|
.add_row()
|
||||||
.add_col(TextSpan::new("<DEL|F8|E>").bold().fg(key_color))
|
.add_col(TextSpan::new("<DEL|F8|E>").bold().fg(key_color))
|
||||||
.add_col(TextSpan::from(" Delete selected file"))
|
.add_col(TextSpan::from(" Delete selected file"))
|
||||||
.add_row()
|
.add_row()
|
||||||
|
|||||||
@@ -330,6 +330,10 @@ impl Component<Msg, NoUserEvent> for ExplorerLocal {
|
|||||||
code: Key::Char('z'),
|
code: Key::Char('z'),
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Char('/'),
|
||||||
|
modifiers: KeyModifiers::NONE,
|
||||||
|
}) => Some(Msg::Ui(UiMsg::ShowFilterPopup)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,6 +526,10 @@ impl Component<Msg, NoUserEvent> for ExplorerRemote {
|
|||||||
code: Key::Char('z'),
|
code: Key::Char('z'),
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
}) => Some(Msg::Ui(UiMsg::ShowChmodPopup)),
|
||||||
|
Event::Keyboard(KeyEvent {
|
||||||
|
code: Key::Char('/'),
|
||||||
|
modifiers: KeyModifiers::NONE,
|
||||||
|
}) => Some(Msg::Ui(UiMsg::ShowFilterPopup)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ impl FileTransferActivity {
|
|||||||
/// Update remote file list
|
/// Update remote file list
|
||||||
pub(super) fn update_remote_filelist(&mut self) {
|
pub(super) fn update_remote_filelist(&mut self) {
|
||||||
self.reload_remote_dir();
|
self.reload_remote_dir();
|
||||||
|
|
||||||
let width = self
|
let width = self
|
||||||
.context_mut()
|
.context_mut()
|
||||||
.terminal()
|
.terminal()
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ enum Id {
|
|||||||
ExplorerRemote,
|
ExplorerRemote,
|
||||||
FatalPopup,
|
FatalPopup,
|
||||||
FileInfoPopup,
|
FileInfoPopup,
|
||||||
|
FilterPopup,
|
||||||
FindPopup,
|
FindPopup,
|
||||||
FooterBar,
|
FooterBar,
|
||||||
GlobalListener,
|
GlobalListener,
|
||||||
@@ -130,6 +131,7 @@ enum UiMsg {
|
|||||||
CloseFatalPopup,
|
CloseFatalPopup,
|
||||||
CloseFileInfoPopup,
|
CloseFileInfoPopup,
|
||||||
CloseFileSortingPopup,
|
CloseFileSortingPopup,
|
||||||
|
CloseFilterPopup,
|
||||||
CloseFindExplorer,
|
CloseFindExplorer,
|
||||||
CloseFindPopup,
|
CloseFindPopup,
|
||||||
CloseGotoPopup,
|
CloseGotoPopup,
|
||||||
@@ -144,6 +146,7 @@ enum UiMsg {
|
|||||||
CloseWatchedPathsList,
|
CloseWatchedPathsList,
|
||||||
CloseWatcherPopup,
|
CloseWatcherPopup,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
|
FilterFiles(String),
|
||||||
LogBackTabbed,
|
LogBackTabbed,
|
||||||
Quit,
|
Quit,
|
||||||
ReplacePopupTabbed,
|
ReplacePopupTabbed,
|
||||||
@@ -154,6 +157,7 @@ enum UiMsg {
|
|||||||
ShowExecPopup,
|
ShowExecPopup,
|
||||||
ShowFileInfoPopup,
|
ShowFileInfoPopup,
|
||||||
ShowFileSortingPopup,
|
ShowFileSortingPopup,
|
||||||
|
ShowFilterPopup,
|
||||||
ShowFindPopup,
|
ShowFindPopup,
|
||||||
ShowGotoPopup,
|
ShowGotoPopup,
|
||||||
ShowKeybindingsPopup,
|
ShowKeybindingsPopup,
|
||||||
|
|||||||
@@ -400,6 +400,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
UiMsg::CloseFileInfoPopup => self.umount_file_info(),
|
UiMsg::CloseFileInfoPopup => self.umount_file_info(),
|
||||||
UiMsg::CloseFileSortingPopup => self.umount_file_sorting(),
|
UiMsg::CloseFileSortingPopup => self.umount_file_sorting(),
|
||||||
|
UiMsg::CloseFilterPopup => self.umount_filter(),
|
||||||
UiMsg::CloseFindExplorer => {
|
UiMsg::CloseFindExplorer => {
|
||||||
self.finalize_find();
|
self.finalize_find();
|
||||||
self.umount_find();
|
self.umount_find();
|
||||||
@@ -420,6 +421,33 @@ impl FileTransferActivity {
|
|||||||
self.disconnect();
|
self.disconnect();
|
||||||
self.umount_disconnect();
|
self.umount_disconnect();
|
||||||
}
|
}
|
||||||
|
UiMsg::FilterFiles(filter) => {
|
||||||
|
self.umount_filter();
|
||||||
|
let files = self.filter(&filter);
|
||||||
|
// Get wrkdir
|
||||||
|
let wrkdir = match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => self.local().wrkdir.clone(),
|
||||||
|
_ => self.remote().wrkdir.clone(),
|
||||||
|
};
|
||||||
|
// Create explorer and load files
|
||||||
|
self.browser.set_found(
|
||||||
|
match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => FoundExplorerTab::Local,
|
||||||
|
_ => FoundExplorerTab::Remote,
|
||||||
|
},
|
||||||
|
files,
|
||||||
|
wrkdir.as_path(),
|
||||||
|
);
|
||||||
|
// Mount result widget
|
||||||
|
self.mount_find(&filter);
|
||||||
|
self.update_find_list();
|
||||||
|
// Initialize tab
|
||||||
|
self.browser.change_tab(match self.browser.tab() {
|
||||||
|
FileExplorerTab::Local => FileExplorerTab::FindLocal,
|
||||||
|
FileExplorerTab::Remote => FileExplorerTab::FindRemote,
|
||||||
|
_ => FileExplorerTab::FindLocal,
|
||||||
|
});
|
||||||
|
}
|
||||||
UiMsg::ShowLogPanel => {
|
UiMsg::ShowLogPanel => {
|
||||||
assert!(self.app.active(&Id::Log).is_ok());
|
assert!(self.app.active(&Id::Log).is_ok());
|
||||||
}
|
}
|
||||||
@@ -485,6 +513,7 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UiMsg::ShowFileSortingPopup => self.mount_file_sorting(),
|
UiMsg::ShowFileSortingPopup => self.mount_file_sorting(),
|
||||||
|
UiMsg::ShowFilterPopup => self.mount_filter(),
|
||||||
UiMsg::ShowFindPopup => self.mount_find_input(),
|
UiMsg::ShowFindPopup => self.mount_find_input(),
|
||||||
UiMsg::ShowGotoPopup => self.mount_goto(),
|
UiMsg::ShowGotoPopup => self.mount_goto(),
|
||||||
UiMsg::ShowKeybindingsPopup => self.mount_help(),
|
UiMsg::ShowKeybindingsPopup => self.mount_help(),
|
||||||
|
|||||||
@@ -172,6 +172,11 @@ impl FileTransferActivity {
|
|||||||
f.render_widget(Clear, popup);
|
f.render_widget(Clear, popup);
|
||||||
// make popup
|
// make popup
|
||||||
self.app.view(&Id::ChmodPopup, f, popup);
|
self.app.view(&Id::ChmodPopup, f, popup);
|
||||||
|
} else if self.app.mounted(&Id::FilterPopup) {
|
||||||
|
let popup = Popup(Size::Percentage(50), Size::Unit(3)).draw_in(f.size());
|
||||||
|
f.render_widget(Clear, popup);
|
||||||
|
// make popup
|
||||||
|
self.app.view(&Id::FilterPopup, f, popup);
|
||||||
} else if self.app.mounted(&Id::FindPopup) {
|
} else if self.app.mounted(&Id::FindPopup) {
|
||||||
let popup = Popup(Size::Percentage(40), Size::Unit(3)).draw_in(f.size());
|
let popup = Popup(Size::Percentage(40), Size::Unit(3)).draw_in(f.size());
|
||||||
f.render_widget(Clear, popup);
|
f.render_widget(Clear, popup);
|
||||||
@@ -459,6 +464,23 @@ impl FileTransferActivity {
|
|||||||
let _ = self.app.umount(&Id::ChmodPopup);
|
let _ = self.app.umount(&Id::ChmodPopup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn umount_filter(&mut self) {
|
||||||
|
let _ = self.app.umount(&Id::FilterPopup);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn mount_filter(&mut self) {
|
||||||
|
let input_color = self.theme().misc_input_dialog;
|
||||||
|
assert!(self
|
||||||
|
.app
|
||||||
|
.remount(
|
||||||
|
Id::FilterPopup,
|
||||||
|
Box::new(components::FilterPopup::new(input_color)),
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
assert!(self.app.active(&Id::FilterPopup).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn mount_copy(&mut self) {
|
pub(super) fn mount_copy(&mut self) {
|
||||||
let input_color = self.theme().misc_input_dialog;
|
let input_color = self.theme().misc_input_dialog;
|
||||||
assert!(self
|
assert!(self
|
||||||
@@ -1096,9 +1118,14 @@ impl FileTransferActivity {
|
|||||||
Box::new(SubClause::Not(Box::new(SubClause::IsMounted(
|
Box::new(SubClause::Not(Box::new(SubClause::IsMounted(
|
||||||
Id::ChmodPopup,
|
Id::ChmodPopup,
|
||||||
)))),
|
)))),
|
||||||
Box::new(SubClause::Not(Box::new(SubClause::IsMounted(
|
Box::new(SubClause::And(
|
||||||
Id::WaitPopup,
|
Box::new(SubClause::Not(Box::new(SubClause::IsMounted(
|
||||||
)))),
|
Id::WaitPopup,
|
||||||
|
)))),
|
||||||
|
Box::new(SubClause::Not(Box::new(SubClause::IsMounted(
|
||||||
|
Id::FilterPopup,
|
||||||
|
)))),
|
||||||
|
)),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
|
|||||||
Reference in New Issue
Block a user