diff --git a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs index 5ff302ab1f..d1faed9714 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs @@ -664,7 +664,11 @@ impl FileManager { | Some(DialogState::ScreenList(_)) | Some(DialogState::EditHistory(_)) | Some(DialogState::FilteredView(_)) - | Some(DialogState::Compare(_)) => { + | Some(DialogState::Compare(_)) + | Some(DialogState::Chattr(_)) + | Some(DialogState::PanelFilter(_)) + | Some(DialogState::Encoding(_)) + | Some(DialogState::Connection(_)) => { // No-op: those dialogs clear themselves. } // The Help dialog also clears itself in `handle_dialog_key` @@ -1012,5 +1016,9 @@ fn dialog_label(d: &DialogState) -> String { DialogState::EditHistory(_) => "Directory history".to_string(), DialogState::FilteredView(_) => "Filtered view".to_string(), DialogState::Compare(_) => "Compare files".to_string(), + DialogState::Chattr(_) => "File attributes".to_string(), + DialogState::PanelFilter(_) => "Panel filter".to_string(), + DialogState::Encoding(_) => "Display encoding".to_string(), + DialogState::Connection(_) => "Network connection".to_string(), } } \ No newline at end of file diff --git a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs index 0cf496a138..4aec696e09 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs @@ -12,7 +12,8 @@ use std::sync::Arc; use anyhow::Result; use crate::filemanager::{ - compare, config_dialog, edit_history, external_panelize, filtered_view, + chattr_dialog, compare, config_dialog, connection_dialog, edit_history, + encoding_dialog, external_panelize, filter_dialog, filtered_view, find, format_utils, hotlist, jobs, layout_dialog, link, menubar, panel_options, quickcd_dialog, screen_list, skin_dialog, tree, usermenu, vfs_list, Cmd, DialogState, FileManager, @@ -454,6 +455,32 @@ impl FileManager { .set_message(if was_qv { "Quick view off" } else { "Quick view on" }); Ok(true) } + Cmd::Chattr => { + let p = self.active_panel().cursor_path(); + self.dialog = Some(DialogState::Chattr(Box::new( + chattr_dialog::ChattrDialog::new(p), + ))); + Ok(true) + } + Cmd::PanelFilter => { + let current = self.active_panel().filter().map(|s| s.to_string()); + self.dialog = Some(DialogState::PanelFilter(Box::new( + filter_dialog::FilterDialog::new(current), + ))); + Ok(true) + } + Cmd::Encoding => { + self.dialog = Some(DialogState::Encoding(Box::default())); + Ok(true) + } + Cmd::Connection => { + self.dialog = Some(DialogState::Connection(Box::new( + connection_dialog::ConnectionDialog::new( + connection_dialog::ConnectionKind::Ftp, + ), + ))); + Ok(true) + } } } @@ -470,6 +497,7 @@ impl FileManager { let ch = char::from_u32(key.code); let cmd = match ch { Some('d') => Some(Cmd::CompareDirs), + Some('e') => Some(Cmd::Chattr), Some('j') => Some(Cmd::Jobs), Some('c') => Some(Cmd::Permission), Some('o') => Some(Cmd::Owner), @@ -633,6 +661,59 @@ impl FileManager { } consumed = true; } + Some(DialogState::Chattr(d)) => { + let r = d.handle_key(key); + if matches!(r, chattr_dialog::ChattrResult::Close) { + self.dialog = None; + } + consumed = true; + } + Some(DialogState::PanelFilter(d)) => { + let r = d.handle_key(key); + match r { + filter_dialog::FilterResult::Apply(pat) => { + self.active_panel_mut().set_filter(&pat); + self.dialog = None; + } + filter_dialog::FilterResult::Clear => { + self.active_panel_mut().set_filter(""); + self.dialog = None; + } + filter_dialog::FilterResult::Cancel => { + self.dialog = None; + } + filter_dialog::FilterResult::Running => {} + } + consumed = true; + } + Some(DialogState::Encoding(d)) => { + let r = d.handle_key(key); + match r { + encoding_dialog::EncodingResult::Select(enc) => { + self.status.set_message(format!("Display encoding: {enc}")); + self.dialog = None; + } + encoding_dialog::EncodingResult::Cancel => { + self.dialog = None; + } + encoding_dialog::EncodingResult::Running => {} + } + consumed = true; + } + Some(DialogState::Connection(d)) => { + let r = d.handle_key(key); + match r { + connection_dialog::ConnectionResult::Connect(url) => { + self.status.set_message(format!("Connect: {url}")); + self.dialog = None; + } + connection_dialog::ConnectionResult::Cancel => { + self.dialog = None; + } + connection_dialog::ConnectionResult::Running => {} + } + consumed = true; + } None => return false, } // Apply captured outcomes. diff --git a/local/recipes/tui/tlc/source/src/filemanager/mod.rs b/local/recipes/tui/tlc/source/src/filemanager/mod.rs index 8c8506b130..52575568a6 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/mod.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/mod.rs @@ -80,6 +80,10 @@ use self::owner::OwnerDialog; use self::panel::{Panel, SortField}; use self::panel_options::PanelOptionsDialog; use self::permission::PermissionDialog; +use self::chattr_dialog::ChattrDialog; +use self::filter_dialog::FilterDialog; +use self::encoding_dialog::EncodingDialog; +use self::connection_dialog::ConnectionDialog; /// Which panel is active. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -268,6 +272,14 @@ pub enum DialogState { FilteredView(Box), /// File comparison diff viewer. Compare(Box), + /// C-x e — file attributes viewer. + Chattr(Box), + /// Alt-f — persistent panel filter. + PanelFilter(Box), + /// Alt-e — display encoding selector. + Encoding(Box), + /// Alt-n — network connection dialog. + Connection(Box), } impl DialogState { @@ -319,6 +331,10 @@ impl DialogState { DialogState::EditHistory(_) => false, DialogState::FilteredView(_) => false, DialogState::Compare(_) => false, + DialogState::Chattr(_) => false, + DialogState::PanelFilter(_) => false, + DialogState::Encoding(_) => false, + DialogState::Connection(_) => false, } } } diff --git a/local/recipes/tui/tlc/source/src/filemanager/render.rs b/local/recipes/tui/tlc/source/src/filemanager/render.rs index 7161bb1dcf..563f2e8728 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/render.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/render.rs @@ -124,6 +124,10 @@ impl FileManager { DialogState::EditHistory(d) => d.render(frame, area, &self.theme), DialogState::FilteredView(d) => d.render(frame, area, &self.theme), DialogState::Compare(d) => d.render(frame, area, &self.theme), + DialogState::Chattr(d) => d.render(frame, area, &self.theme), + DialogState::PanelFilter(d) => d.render(frame, area, &self.theme), + DialogState::Encoding(d) => d.render(frame, area, &self.theme), + DialogState::Connection(d) => d.render(frame, area, &self.theme), } } } diff --git a/local/recipes/tui/tlc/source/src/keymap/mod.rs b/local/recipes/tui/tlc/source/src/keymap/mod.rs index 4096c794e9..a0796d592a 100644 --- a/local/recipes/tui/tlc/source/src/keymap/mod.rs +++ b/local/recipes/tui/tlc/source/src/keymap/mod.rs @@ -171,6 +171,14 @@ pub enum Cmd { /// (inline preview of the cursor file) and its prior listing. /// Dispatched via [`crate::filemanager::FileManager`]. PanelQuickView, + /// C-x e — view file attributes (read-only metadata viewer). + Chattr, + /// Alt-f — persistent panel filter (glob pattern). + PanelFilter, + /// Alt-e — change panel display encoding. + Encoding, + /// Alt-n — open a network connection (FTP/SFTP/Shell). + Connection, } impl Cmd { @@ -247,6 +255,10 @@ impl Cmd { Cmd::FilteredView => "Filtered view", Cmd::PanelInfo => "Panel info", Cmd::PanelQuickView => "Panel quick view", + Cmd::Chattr => "File attributes", + Cmd::PanelFilter => "Panel filter", + Cmd::Encoding => "Display encoding", + Cmd::Connection => "Network connection", } } } @@ -385,6 +397,9 @@ pub fn default_keymap() -> Keymap { km.bind(Key::alt('l'), Cmd::ListingCycle); km.bind(Key::alt('g'), Cmd::LayoutDialog); km.bind(Key::alt('p'), Cmd::PanelOptionsDialog); + km.bind(Key::alt('f'), Cmd::PanelFilter); + km.bind(Key::alt('e'), Cmd::Encoding); + km.bind(Key::alt('n'), Cmd::Connection); // C-x prefix family: mapped CTRL|ALT+, matching the existing // C-x c / C-x o / C-x l / C-x s convention above.