mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Find dialog in view
This commit is contained in:
@@ -32,6 +32,7 @@ Released on FIXME: date
|
|||||||
- Fixed a bug causing termscp to show two equal bookmarks when overwriting one.
|
- Fixed a bug causing termscp to show two equal bookmarks when overwriting one.
|
||||||
- Dependencies:
|
- Dependencies:
|
||||||
- Removed `unicode-width`
|
- Removed `unicode-width`
|
||||||
|
- Added `wildmatch 1.0.13`
|
||||||
- For developers:
|
- For developers:
|
||||||
- Activity refactoring
|
- Activity refactoring
|
||||||
- Developed an internal library used to create components, components are then nested inside a View
|
- Developed an internal library used to create components, components are then nested inside a View
|
||||||
|
|||||||
@@ -127,6 +127,13 @@ impl FileExplorer {
|
|||||||
self.sort();
|
self.sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### del_entry
|
||||||
|
///
|
||||||
|
/// Delete file at provided index
|
||||||
|
pub fn del_entry(&mut self, idx: usize) {
|
||||||
|
self.files.remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// ### count
|
/// ### count
|
||||||
///
|
///
|
||||||
@@ -627,6 +634,23 @@ mod tests {
|
|||||||
assert!(GroupDirs::from_str("omar").is_err());
|
assert!(GroupDirs::from_str("omar").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fs_explorer_del_entry() {
|
||||||
|
let mut explorer: FileExplorer = FileExplorer::default();
|
||||||
|
// Create files (files are then sorted by name)
|
||||||
|
explorer.set_files(vec![
|
||||||
|
make_fs_entry("CONTRIBUTING.md", false),
|
||||||
|
make_fs_entry("docs/", true),
|
||||||
|
make_fs_entry("src/", true),
|
||||||
|
make_fs_entry("README.md", false),
|
||||||
|
]);
|
||||||
|
explorer.del_entry(0);
|
||||||
|
assert_eq!(explorer.files.len(), 3);
|
||||||
|
assert_eq!(explorer.files[0].get_name(), "docs/");
|
||||||
|
explorer.del_entry(5);
|
||||||
|
assert_eq!(explorer.files.len(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry {
|
fn make_fs_entry(name: &str, is_dir: bool) -> FsEntry {
|
||||||
let t_now: SystemTime = SystemTime::now();
|
let t_now: SystemTime = SystemTime::now();
|
||||||
match is_dir {
|
match is_dir {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// locals
|
// locals
|
||||||
use super::{FileTransferActivity, FsEntry, LogLevel};
|
use super::{FileExplorerTab, FileTransferActivity, FsEntry, LogLevel};
|
||||||
use crate::ui::layout::Payload;
|
use crate::ui::layout::Payload;
|
||||||
// externals
|
// externals
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -485,6 +485,124 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> = match self.found.as_ref().unwrap().get(idx) {
|
||||||
|
None => None,
|
||||||
|
Some(e) => Some(e.clone()),
|
||||||
|
};
|
||||||
|
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> = match self.found.as_ref().unwrap().get(idx) {
|
||||||
|
None => None,
|
||||||
|
Some(e) => Some(e.clone()),
|
||||||
|
};
|
||||||
|
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
|
||||||
///
|
///
|
||||||
/// Get local file entry
|
/// Get local file entry
|
||||||
|
|||||||
@@ -111,6 +111,19 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### 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
|
||||||
|
|||||||
@@ -63,23 +63,25 @@ const STORAGE_LOGBOX_WIDTH: &str = "LOGBOX_WIDTH";
|
|||||||
|
|
||||||
const COMPONENT_EXPLORER_LOCAL: &str = "EXPLORER_LOCAL";
|
const COMPONENT_EXPLORER_LOCAL: &str = "EXPLORER_LOCAL";
|
||||||
const COMPONENT_EXPLORER_REMOTE: &str = "EXPLORER_REMOTE";
|
const COMPONENT_EXPLORER_REMOTE: &str = "EXPLORER_REMOTE";
|
||||||
|
const COMPONENT_EXPLORER_FIND: &str = "EXPLORER_FIND";
|
||||||
const COMPONENT_LOG_BOX: &str = "LOG_BOX";
|
const COMPONENT_LOG_BOX: &str = "LOG_BOX";
|
||||||
const COMPONENT_PROGRESS_BAR: &str = "PROGRESS_BAR";
|
const COMPONENT_PROGRESS_BAR: &str = "PROGRESS_BAR";
|
||||||
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";
|
|
||||||
const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR";
|
const COMPONENT_TEXT_ERROR: &str = "TEXT_ERROR";
|
||||||
const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT";
|
|
||||||
const COMPONENT_TEXT_FATAL: &str = "TEXT_FATAL";
|
const COMPONENT_TEXT_FATAL: &str = "TEXT_FATAL";
|
||||||
|
const COMPONENT_TEXT_HELP: &str = "TEXT_HELP";
|
||||||
|
const COMPONENT_TEXT_WAIT: &str = "TEXT_WAIT";
|
||||||
const COMPONENT_INPUT_COPY: &str = "INPUT_COPY";
|
const COMPONENT_INPUT_COPY: &str = "INPUT_COPY";
|
||||||
const COMPONENT_INPUT_EXEC: &str = "INPUT_EXEC";
|
const COMPONENT_INPUT_EXEC: &str = "INPUT_EXEC";
|
||||||
const COMPONENT_INPUT_MKDIR: &str = "INPUT_MKDIR";
|
const COMPONENT_INPUT_FIND: &str = "INPUT_FIND";
|
||||||
const COMPONENT_INPUT_GOTO: &str = "INPUT_GOTO";
|
const COMPONENT_INPUT_GOTO: &str = "INPUT_GOTO";
|
||||||
const COMPONENT_INPUT_SAVEAS: &str = "INPUT_SAVEAS";
|
const COMPONENT_INPUT_MKDIR: &str = "INPUT_MKDIR";
|
||||||
const COMPONENT_INPUT_NEWFILE: &str = "INPUT_NEWFILE";
|
const COMPONENT_INPUT_NEWFILE: &str = "INPUT_NEWFILE";
|
||||||
const COMPONENT_INPUT_RENAME: &str = "INPUT_RENAME";
|
const COMPONENT_INPUT_RENAME: &str = "INPUT_RENAME";
|
||||||
const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT";
|
const COMPONENT_INPUT_SAVEAS: &str = "INPUT_SAVEAS";
|
||||||
const COMPONENT_RADIO_DISCONNECT: &str = "RADIO_DISCONNECT";
|
|
||||||
const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING";
|
|
||||||
const COMPONENT_RADIO_DELETE: &str = "RADIO_DELETE";
|
const COMPONENT_RADIO_DELETE: &str = "RADIO_DELETE";
|
||||||
|
const COMPONENT_RADIO_DISCONNECT: &str = "RADIO_DISCONNECT";
|
||||||
|
const COMPONENT_RADIO_QUIT: &str = "RADIO_QUIT";
|
||||||
|
const COMPONENT_RADIO_SORTING: &str = "RADIO_SORTING";
|
||||||
const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
|
const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
|
||||||
|
|
||||||
/// ## FileExplorerTab
|
/// ## FileExplorerTab
|
||||||
@@ -88,6 +90,8 @@ const COMPONENT_LIST_FILEINFO: &str = "LIST_FILEINFO";
|
|||||||
enum FileExplorerTab {
|
enum FileExplorerTab {
|
||||||
Local,
|
Local,
|
||||||
Remote,
|
Remote,
|
||||||
|
FindLocal, // Find result tab
|
||||||
|
FindRemote, // Find result tab
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## LogLevel
|
/// ## LogLevel
|
||||||
@@ -206,6 +210,7 @@ pub struct FileTransferActivity {
|
|||||||
client: Box<dyn FileTransfer>, // File transfer client
|
client: Box<dyn FileTransfer>, // File transfer client
|
||||||
local: FileExplorer, // Local File explorer state
|
local: FileExplorer, // Local File explorer state
|
||||||
remote: FileExplorer, // Remote File explorer state
|
remote: FileExplorer, // Remote File explorer state
|
||||||
|
found: Option<FileExplorer>, // File explorer for find result
|
||||||
tab: FileExplorerTab, // Current selected tab
|
tab: FileExplorerTab, // Current selected tab
|
||||||
log_index: usize, // Current log index entry selected
|
log_index: usize, // Current log index entry selected
|
||||||
log_records: VecDeque<LogRecord>, // Log records
|
log_records: VecDeque<LogRecord>, // Log records
|
||||||
@@ -235,6 +240,7 @@ impl FileTransferActivity {
|
|||||||
},
|
},
|
||||||
local: Self::build_explorer(config_client.as_ref()),
|
local: Self::build_explorer(config_client.as_ref()),
|
||||||
remote: Self::build_explorer(config_client.as_ref()),
|
remote: Self::build_explorer(config_client.as_ref()),
|
||||||
|
found: None,
|
||||||
tab: FileExplorerTab::Local,
|
tab: FileExplorerTab::Local,
|
||||||
log_index: 0,
|
log_index: 0,
|
||||||
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
|
log_records: VecDeque::with_capacity(256), // 256 events is enough I guess
|
||||||
|
|||||||
@@ -27,9 +27,10 @@
|
|||||||
extern crate bytesize;
|
extern crate bytesize;
|
||||||
// locals
|
// locals
|
||||||
use super::{
|
use super::{
|
||||||
FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_LOCAL,
|
FileExplorerTab, FileTransferActivity, LogLevel, COMPONENT_EXPLORER_FIND,
|
||||||
COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY, COMPONENT_INPUT_EXEC, COMPONENT_INPUT_GOTO,
|
COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE, COMPONENT_INPUT_COPY,
|
||||||
COMPONENT_INPUT_MKDIR, COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS,
|
COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO, COMPONENT_INPUT_MKDIR,
|
||||||
|
COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS,
|
||||||
COMPONENT_LIST_FILEINFO, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR, COMPONENT_RADIO_DELETE,
|
COMPONENT_LIST_FILEINFO, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR, COMPONENT_RADIO_DELETE,
|
||||||
COMPONENT_RADIO_DISCONNECT, COMPONENT_RADIO_QUIT, COMPONENT_RADIO_SORTING,
|
COMPONENT_RADIO_DISCONNECT, COMPONENT_RADIO_QUIT, COMPONENT_RADIO_SORTING,
|
||||||
COMPONENT_TEXT_ERROR, COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
|
COMPONENT_TEXT_ERROR, COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
|
||||||
@@ -37,7 +38,9 @@ use super::{
|
|||||||
use crate::fs::explorer::FileSorting;
|
use crate::fs::explorer::FileSorting;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
use crate::ui::activities::keymap::*;
|
use crate::ui::activities::keymap::*;
|
||||||
use crate::ui::layout::props::{PropValue, TableBuilder, TextParts, TextSpan, TextSpanBuilder};
|
use crate::ui::layout::props::{
|
||||||
|
PropValue, PropsBuilder, TableBuilder, TextParts, TextSpan, TextSpanBuilder,
|
||||||
|
};
|
||||||
use crate::ui::layout::{Msg, Payload};
|
use crate::ui::layout::{Msg, Payload};
|
||||||
// externals
|
// externals
|
||||||
use bytesize::ByteSize;
|
use bytesize::ByteSize;
|
||||||
@@ -314,6 +317,11 @@ impl FileTransferActivity {
|
|||||||
self.mount_mkdir();
|
self.mount_mkdir();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_F)
|
||||||
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_F) => {
|
||||||
|
self.mount_find_input();
|
||||||
|
None
|
||||||
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_G)
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_G)
|
||||||
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_G) => {
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_G) => {
|
||||||
self.mount_goto();
|
self.mount_goto();
|
||||||
@@ -342,7 +350,8 @@ impl FileTransferActivity {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_S)
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_S)
|
||||||
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_S) => {
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_S)
|
||||||
|
| (COMPONENT_EXPLORER_FIND, &MSG_KEY_CHAR_S) => {
|
||||||
// Mount save as
|
// Mount save as
|
||||||
self.mount_saveas();
|
self.mount_saveas();
|
||||||
None
|
None
|
||||||
@@ -362,10 +371,50 @@ impl FileTransferActivity {
|
|||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_DEL)
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_DEL)
|
||||||
| (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_E)
|
| (COMPONENT_EXPLORER_LOCAL, &MSG_KEY_CHAR_E)
|
||||||
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_DEL)
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_DEL)
|
||||||
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_E) => {
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_CHAR_E)
|
||||||
|
| (COMPONENT_EXPLORER_FIND, &MSG_KEY_DEL)
|
||||||
|
| (COMPONENT_EXPLORER_FIND, &MSG_KEY_CHAR_E) => {
|
||||||
self.mount_radio_delete();
|
self.mount_radio_delete();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
// -- find result explorer
|
||||||
|
(COMPONENT_EXPLORER_FIND, &MSG_KEY_ESC) => {
|
||||||
|
// Umount find
|
||||||
|
self.umount_find();
|
||||||
|
// Finalize find
|
||||||
|
self.finalize_find();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(COMPONENT_EXPLORER_FIND, Msg::OnSubmit(Payload::Unsigned(idx))) => {
|
||||||
|
// Find changedir
|
||||||
|
self.action_find_changedir(*idx);
|
||||||
|
// Umount find
|
||||||
|
self.umount_find();
|
||||||
|
// Finalize find
|
||||||
|
self.finalize_find();
|
||||||
|
// Reload files
|
||||||
|
match self.tab {
|
||||||
|
FileExplorerTab::Local => self.update_local_filelist(),
|
||||||
|
FileExplorerTab::Remote => self.update_remote_filelist(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(COMPONENT_EXPLORER_FIND, &MSG_KEY_SPACE) => {
|
||||||
|
// Get entry
|
||||||
|
match self.view.get_value(COMPONENT_EXPLORER_FIND) {
|
||||||
|
Some(Payload::Unsigned(idx)) => {
|
||||||
|
self.action_find_transfer(idx, None);
|
||||||
|
// Reload files
|
||||||
|
match self.tab {
|
||||||
|
// NOTE: swapped by purpose
|
||||||
|
FileExplorerTab::FindLocal => self.update_remote_filelist(),
|
||||||
|
FileExplorerTab::FindRemote => self.update_local_filelist(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
// -- switch to log
|
// -- switch to log
|
||||||
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_TAB)
|
(COMPONENT_EXPLORER_LOCAL, &MSG_KEY_TAB)
|
||||||
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_TAB) => {
|
| (COMPONENT_EXPLORER_REMOTE, &MSG_KEY_TAB) => {
|
||||||
@@ -387,12 +436,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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"),
|
||||||
}
|
}
|
||||||
self.umount_copy();
|
self.umount_copy();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- exec popup
|
// -- exec popup
|
||||||
@@ -405,14 +456,53 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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"),
|
||||||
}
|
}
|
||||||
self.umount_exec();
|
self.umount_exec();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// -- find popup
|
||||||
|
(COMPONENT_INPUT_FIND, &MSG_KEY_ESC) => {
|
||||||
|
self.umount_find_input();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::Text(input))) => {
|
||||||
|
self.umount_find_input();
|
||||||
|
// Find
|
||||||
|
let res: Result<Vec<FsEntry>, String> = match self.tab {
|
||||||
|
FileExplorerTab::Local => self.action_local_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"),
|
||||||
|
};
|
||||||
|
// Match result
|
||||||
|
match res {
|
||||||
|
Err(err) => {
|
||||||
|
// Mount error
|
||||||
|
self.mount_error(err.as_str());
|
||||||
|
}
|
||||||
|
Ok(files) => {
|
||||||
|
// Create explorer and load files
|
||||||
|
let mut explorer = Self::build_found_explorer();
|
||||||
|
explorer.set_files(files);
|
||||||
|
self.found = Some(explorer);
|
||||||
|
// Mount result widget
|
||||||
|
self.mount_find(input);
|
||||||
|
self.update_find_list();
|
||||||
|
// Initialize tab
|
||||||
|
self.tab = match self.tab {
|
||||||
|
FileExplorerTab::Local => FileExplorerTab::FindLocal,
|
||||||
|
FileExplorerTab::Remote => FileExplorerTab::FindRemote,
|
||||||
|
_ => FileExplorerTab::FindLocal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
// -- goto popup
|
// -- goto popup
|
||||||
(COMPONENT_INPUT_GOTO, &MSG_KEY_ESC) => {
|
(COMPONENT_INPUT_GOTO, &MSG_KEY_ESC) => {
|
||||||
self.umount_goto();
|
self.umount_goto();
|
||||||
@@ -422,6 +512,7 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => self.action_change_local_dir(input.to_string()),
|
FileExplorerTab::Local => self.action_change_local_dir(input.to_string()),
|
||||||
FileExplorerTab::Remote => self.action_change_remote_dir(input.to_string()),
|
FileExplorerTab::Remote => self.action_change_remote_dir(input.to_string()),
|
||||||
|
_ => panic!("Found tab doesn't support GOTO"),
|
||||||
}
|
}
|
||||||
// Umount
|
// Umount
|
||||||
self.umount_goto();
|
self.umount_goto();
|
||||||
@@ -429,6 +520,7 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- make directory
|
// -- make directory
|
||||||
@@ -440,12 +532,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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"),
|
||||||
}
|
}
|
||||||
self.umount_mkdir();
|
self.umount_mkdir();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- new file
|
// -- new file
|
||||||
@@ -457,12 +551,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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"),
|
||||||
}
|
}
|
||||||
self.umount_newfile();
|
self.umount_newfile();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- rename
|
// -- rename
|
||||||
@@ -474,12 +570,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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"),
|
||||||
}
|
}
|
||||||
self.umount_rename();
|
self.umount_rename();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- save as
|
// -- save as
|
||||||
@@ -491,6 +589,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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 => {
|
||||||
|
// Get entry
|
||||||
|
if let Some(Payload::Unsigned(idx)) =
|
||||||
|
self.view.get_value(COMPONENT_EXPLORER_FIND)
|
||||||
|
{
|
||||||
|
self.action_find_transfer(idx, Some(input.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.umount_saveas();
|
self.umount_saveas();
|
||||||
// Reload files
|
// Reload files
|
||||||
@@ -498,6 +604,8 @@ impl FileTransferActivity {
|
|||||||
// 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(),
|
||||||
|
FileExplorerTab::FindLocal => self.update_remote_filelist(),
|
||||||
|
FileExplorerTab::FindRemote => self.update_local_filelist(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- fileinfo
|
// -- fileinfo
|
||||||
@@ -517,12 +625,25 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.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 => {
|
||||||
|
// Get entry
|
||||||
|
if let Some(Payload::Unsigned(idx)) =
|
||||||
|
self.view.get_value(COMPONENT_EXPLORER_FIND)
|
||||||
|
{
|
||||||
|
self.action_find_delete(idx);
|
||||||
|
// Reload entries
|
||||||
|
self.found.as_mut().unwrap().del_entry(idx);
|
||||||
|
self.update_find_list();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.umount_radio_delete();
|
self.umount_radio_delete();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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::FindRemote => self.update_remote_filelist(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- disconnect
|
// -- disconnect
|
||||||
@@ -547,6 +668,7 @@ impl FileTransferActivity {
|
|||||||
self.umount_quit();
|
self.umount_quit();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
// -- sorting
|
||||||
(COMPONENT_RADIO_SORTING, &MSG_KEY_ESC) => {
|
(COMPONENT_RADIO_SORTING, &MSG_KEY_ESC) => {
|
||||||
self.umount_file_sorting();
|
self.umount_file_sorting();
|
||||||
None
|
None
|
||||||
@@ -562,12 +684,14 @@ impl FileTransferActivity {
|
|||||||
match self.tab {
|
match self.tab {
|
||||||
FileExplorerTab::Local => self.local.sort_by(sorting),
|
FileExplorerTab::Local => self.local.sort_by(sorting),
|
||||||
FileExplorerTab::Remote => self.remote.sort_by(sorting),
|
FileExplorerTab::Remote => self.remote.sort_by(sorting),
|
||||||
|
_ => panic!("Found result doesn't support SORTING"),
|
||||||
}
|
}
|
||||||
self.umount_file_sorting();
|
self.umount_file_sorting();
|
||||||
// Reload files
|
// Reload files
|
||||||
match self.tab {
|
match self.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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -- error
|
// -- error
|
||||||
@@ -809,6 +933,43 @@ impl FileTransferActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ### finalize_find
|
||||||
|
///
|
||||||
|
/// Finalize find process
|
||||||
|
fn finalize_find(&mut self) {
|
||||||
|
// Set found to none
|
||||||
|
self.found = None;
|
||||||
|
// Restore tab
|
||||||
|
self.tab = match self.tab {
|
||||||
|
FileExplorerTab::FindLocal => FileExplorerTab::Local,
|
||||||
|
FileExplorerTab::FindRemote => FileExplorerTab::Remote,
|
||||||
|
_ => FileExplorerTab::Local,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_find_list(&mut self) -> Option<(String, Msg)> {
|
||||||
|
match self.view.get_props(COMPONENT_EXPLORER_FIND).as_mut() {
|
||||||
|
None => None,
|
||||||
|
Some(props) => {
|
||||||
|
let props = props.build();
|
||||||
|
let title: String = props.texts.title.clone().unwrap_or(String::new());
|
||||||
|
let mut props = PropsBuilder::from(props.clone());
|
||||||
|
// Prepare files
|
||||||
|
let file_texts: Vec<TextSpan> = self
|
||||||
|
.found
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter_files()
|
||||||
|
.map(|x: &FsEntry| TextSpan::from(self.found.as_ref().unwrap().fmt_file(x)))
|
||||||
|
.collect();
|
||||||
|
let props = props
|
||||||
|
.with_texts(TextParts::new(Some(title), Some(file_texts)))
|
||||||
|
.build();
|
||||||
|
self.view.update(COMPONENT_EXPLORER_FIND, props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// ### elide_wrkdir_path
|
/// ### elide_wrkdir_path
|
||||||
///
|
///
|
||||||
/// Elide working directory path if longer than width + host.len
|
/// Elide working directory path if longer than width + host.len
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ use super::{Context, FileExplorerTab, FileTransferActivity};
|
|||||||
use crate::fs::explorer::FileSorting;
|
use crate::fs::explorer::FileSorting;
|
||||||
use crate::fs::FsEntry;
|
use crate::fs::FsEntry;
|
||||||
use crate::ui::layout::components::{
|
use crate::ui::layout::components::{
|
||||||
msgbox::MsgBox, file_list::FileList, input::Input, logbox::LogBox, progress_bar::ProgressBar,
|
file_list::FileList, input::Input, logbox::LogBox, msgbox::MsgBox, progress_bar::ProgressBar,
|
||||||
radio_group::RadioGroup, table::Table,
|
radio_group::RadioGroup, table::Table,
|
||||||
};
|
};
|
||||||
use crate::ui::layout::props::{
|
use crate::ui::layout::props::{
|
||||||
@@ -138,6 +138,14 @@ impl FileTransferActivity {
|
|||||||
// Draw log box
|
// Draw log box
|
||||||
self.view.render(super::COMPONENT_LOG_BOX, f, chunks[1]);
|
self.view.render(super::COMPONENT_LOG_BOX, f, chunks[1]);
|
||||||
// Draw popups
|
// Draw popups
|
||||||
|
if let Some(mut props) = self.view.get_props(super::COMPONENT_EXPLORER_FIND) {
|
||||||
|
if props.build().visible {
|
||||||
|
let popup = draw_area_in(f.size(), 60, 80);
|
||||||
|
f.render_widget(Clear, popup);
|
||||||
|
// make popup
|
||||||
|
self.view.render(super::COMPONENT_EXPLORER_FIND, f, popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_COPY) {
|
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_COPY) {
|
||||||
if props.build().visible {
|
if props.build().visible {
|
||||||
let popup = draw_area_in(f.size(), 40, 10);
|
let popup = draw_area_in(f.size(), 40, 10);
|
||||||
@@ -146,6 +154,14 @@ impl FileTransferActivity {
|
|||||||
self.view.render(super::COMPONENT_INPUT_COPY, f, popup);
|
self.view.render(super::COMPONENT_INPUT_COPY, f, popup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_FIND) {
|
||||||
|
if props.build().visible {
|
||||||
|
let popup = draw_area_in(f.size(), 40, 10);
|
||||||
|
f.render_widget(Clear, popup);
|
||||||
|
// make popup
|
||||||
|
self.view.render(super::COMPONENT_INPUT_FIND, f, popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_GOTO) {
|
if let Some(mut props) = self.view.get_props(super::COMPONENT_INPUT_GOTO) {
|
||||||
if props.build().visible {
|
if props.build().visible {
|
||||||
let popup = draw_area_in(f.size(), 40, 10);
|
let popup = draw_area_in(f.size(), 40, 10);
|
||||||
@@ -435,6 +451,55 @@ impl FileTransferActivity {
|
|||||||
self.view.umount(super::COMPONENT_INPUT_EXEC);
|
self.view.umount(super::COMPONENT_INPUT_EXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn mount_find(&mut self, search: &str) {
|
||||||
|
// Get color
|
||||||
|
let color: Color = match self.tab {
|
||||||
|
FileExplorerTab::Local | FileExplorerTab::FindLocal => Color::Yellow,
|
||||||
|
FileExplorerTab::Remote | FileExplorerTab::FindRemote => Color::LightBlue,
|
||||||
|
};
|
||||||
|
// Mount component
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_EXPLORER_FIND,
|
||||||
|
Box::new(FileList::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_texts(TextParts::new(
|
||||||
|
Some(format!("Search results for \"{}\"", search)),
|
||||||
|
Some(vec![]),
|
||||||
|
))
|
||||||
|
.with_background(color)
|
||||||
|
.with_foreground(color)
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Give focus to explorer findd
|
||||||
|
self.view.active(super::COMPONENT_EXPLORER_FIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn umount_find(&mut self) {
|
||||||
|
self.view.umount(super::COMPONENT_EXPLORER_FIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn mount_find_input(&mut self) {
|
||||||
|
self.view.mount(
|
||||||
|
super::COMPONENT_INPUT_FIND,
|
||||||
|
Box::new(Input::new(
|
||||||
|
PropsBuilder::default()
|
||||||
|
.with_texts(TextParts::new(
|
||||||
|
Some(String::from("Search files by name")),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
// Give focus to input find
|
||||||
|
self.view.active(super::COMPONENT_INPUT_FIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn umount_find_input(&mut self) {
|
||||||
|
// Umount input find
|
||||||
|
self.view.umount(super::COMPONENT_INPUT_FIND);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn mount_goto(&mut self) {
|
pub(super) fn mount_goto(&mut self) {
|
||||||
self.view.mount(
|
self.view.mount(
|
||||||
super::COMPONENT_INPUT_GOTO,
|
super::COMPONENT_INPUT_GOTO,
|
||||||
@@ -543,6 +608,7 @@ impl FileTransferActivity {
|
|||||||
let sorting: FileSorting = match self.tab {
|
let sorting: FileSorting = match self.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"),
|
||||||
};
|
};
|
||||||
let index: usize = match sorting {
|
let index: usize = match sorting {
|
||||||
FileSorting::ByCreationTime => 2,
|
FileSorting::ByCreationTime => 2,
|
||||||
|
|||||||
@@ -91,12 +91,10 @@ pub const MSG_KEY_CHAR_E: Msg = Msg::OnKey(KeyEvent {
|
|||||||
code: KeyCode::Char('e'),
|
code: KeyCode::Char('e'),
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
pub const MSG_KEY_CHAR_F: Msg = Msg::OnKey(KeyEvent {
|
pub const MSG_KEY_CHAR_F: Msg = Msg::OnKey(KeyEvent {
|
||||||
code: KeyCode::Char('f'),
|
code: KeyCode::Char('f'),
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
pub const MSG_KEY_CHAR_G: Msg = Msg::OnKey(KeyEvent {
|
pub const MSG_KEY_CHAR_G: Msg = Msg::OnKey(KeyEvent {
|
||||||
code: KeyCode::Char('g'),
|
code: KeyCode::Char('g'),
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
|
|||||||
Reference in New Issue
Block a user