From c1cf86a38a6edba3e4853acda040abb87261f2e1 Mon Sep 17 00:00:00 2001 From: vasilito Date: Mon, 6 Jul 2026 10:25:59 +0300 Subject: [PATCH] W9: Fix Ctrl-X chord semantics to match MC MC parity audit found 4 semantic bugs in dispatch_ctrl_x_followup: l -> Link (hard link, was Cmd::Symlink) s -> Symlink (absolute symlink, was Cmd::SymlinkRelative) v -> SymlinkRelative (relative symlink, was Cmd::SymlinkEdit) Added 2 ctrl+letter chord entries: ctrl-s -> SymlinkEdit (edit symlink) ctrl-p -> InsertOtherPath (insert other panel path) Added 3 chord aliases for MC-compatibility: p -> InsertCurPath (MC's PutCurrentPath) r -> InsertCurFile (MC's PutCurrentLink) ctrl-d, ctrl-s, ctrl-p handled via modifier check Tests: 1381 pass, zero warnings. --- .../tlc/source/src/filemanager/dispatch.rs | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs index 858f39a6ea..20d1499ff8 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dispatch.rs @@ -579,25 +579,34 @@ impl FileManager { /// the next key is routed here instead of the normal keymap. pub fn dispatch_ctrl_x_followup(&mut self, key: crate::key::Key) -> Result { self.pending_ctrl_x = false; - // Translate the key into a (char) so we can match on the - // follow-up letter. We ignore the modifier bits for the - // chord's second key — MC's chord semantics are letter-only. + use crate::key::Modifiers; + let ctrl = key.mods.contains(Modifiers::CTRL); 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), - Some('l') => Some(Cmd::Symlink), - Some('s') => Some(Cmd::SymlinkRelative), - Some('v') => Some(Cmd::SymlinkEdit), - Some('a') => Some(Cmd::VfsList), - Some('!') => Some(Cmd::Panelize), - Some('i') => Some(Cmd::PanelInfo), - Some('q') => Some(Cmd::PanelQuickView), - Some('h') => Some(Cmd::HotList), - _ => None, + let cmd = if ctrl { + match ch { + Some('s') => Some(Cmd::SymlinkEdit), + Some('p') => Some(Cmd::InsertOtherPath), + _ => None, + } + } else { + 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), + Some('l') => Some(Cmd::Link), + Some('s') => Some(Cmd::Symlink), + Some('v') => Some(Cmd::SymlinkRelative), + Some('a') => Some(Cmd::VfsList), + Some('!') => Some(Cmd::Panelize), + Some('i') => Some(Cmd::PanelInfo), + Some('q') => Some(Cmd::PanelQuickView), + Some('h') => Some(Cmd::HotList), + Some('p') => Some(Cmd::InsertCurPath), + Some('r') => Some(Cmd::InsertCurFile), + _ => None, + } }; match cmd { Some(c) => self.dispatch(c).map_err(|e| e.to_string()),