use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyAction {
MoveUp,
MoveDown,
MoveLeft,
MoveRight,
JumpToTop,
JumpToBottom,
PageUp,
PageDown,
#[allow(dead_code)]
Expand,
#[allow(dead_code)]
Collapse,
ToggleExpand,
DrillDown,
NavigateBack,
#[allow(dead_code)]
OpenFile,
ToggleMark,
Yank,
Cut,
Paste,
Delete,
Rename,
CreateFile,
CreateDirectory,
Take,
Undo,
ToggleDetails,
ToggleHelp,
ToggleTheme,
ToggleLayout,
CyclePreviewMode,
OpenSettings,
Refresh,
Search,
Sort,
ReverseSort,
CommandMode,
GoTo,
#[allow(dead_code)]
Confirm,
Cancel,
#[allow(dead_code)]
ClearMarks,
NextView,
PrevView,
NewDirTab,
CloseDirTab,
NextDirTab,
PrevDirTab,
DirTab(u8),
Quit,
ForceQuit,
None,
}
impl KeyAction {
pub fn from_key_event(event: KeyEvent) -> Self {
match (event.code, event.modifiers) {
(KeyCode::Char('q'), KeyModifiers::NONE) => KeyAction::Quit,
(KeyCode::Char('c'), KeyModifiers::CONTROL) => KeyAction::ForceQuit,
(KeyCode::Esc, _) => KeyAction::Cancel,
(KeyCode::Char('j'), KeyModifiers::NONE) => KeyAction::MoveDown,
(KeyCode::Char('k'), KeyModifiers::NONE) => KeyAction::MoveUp,
(KeyCode::Char('h'), KeyModifiers::NONE) => KeyAction::MoveLeft,
(KeyCode::Char('l'), KeyModifiers::NONE) => KeyAction::MoveRight,
(KeyCode::Down, KeyModifiers::NONE) => KeyAction::MoveDown,
(KeyCode::Up, KeyModifiers::NONE) => KeyAction::MoveUp,
(KeyCode::Left, KeyModifiers::NONE) => KeyAction::MoveLeft,
(KeyCode::Right, KeyModifiers::NONE) => KeyAction::MoveRight,
(KeyCode::Char('g'), KeyModifiers::NONE) => KeyAction::JumpToTop,
(KeyCode::Char('G'), KeyModifiers::SHIFT) => KeyAction::JumpToBottom,
(KeyCode::Home, _) => KeyAction::JumpToTop,
(KeyCode::End, _) => KeyAction::JumpToBottom,
(KeyCode::PageUp, _) => KeyAction::PageUp,
(KeyCode::PageDown, _) => KeyAction::PageDown,
(KeyCode::Char('u'), KeyModifiers::CONTROL) => KeyAction::PageUp,
(KeyCode::Char('d'), KeyModifiers::CONTROL) => KeyAction::PageDown,
(KeyCode::Char(' '), KeyModifiers::NONE) => KeyAction::ToggleMark,
(KeyCode::Char('o'), KeyModifiers::NONE) => KeyAction::ToggleExpand,
(KeyCode::Char('y'), KeyModifiers::NONE) => KeyAction::Yank,
(KeyCode::Char('x'), KeyModifiers::NONE) => KeyAction::Cut,
(KeyCode::Char('p'), KeyModifiers::NONE) => KeyAction::Paste,
(KeyCode::Char('d'), KeyModifiers::NONE) => KeyAction::Delete,
(KeyCode::Char('D'), KeyModifiers::SHIFT) => KeyAction::Delete,
(KeyCode::Delete, _) => KeyAction::Delete,
(KeyCode::Char('r'), KeyModifiers::NONE) => KeyAction::Rename,
(KeyCode::Char('a'), KeyModifiers::NONE) => KeyAction::CreateFile,
(KeyCode::Char('A'), KeyModifiers::SHIFT) => KeyAction::CreateDirectory,
(KeyCode::Char('T'), KeyModifiers::SHIFT) => KeyAction::Take,
(KeyCode::Char('z'), KeyModifiers::CONTROL) => KeyAction::Undo,
(KeyCode::Char('i'), KeyModifiers::NONE) => KeyAction::ToggleDetails,
(KeyCode::Char('?'), KeyModifiers::NONE) => KeyAction::ToggleHelp,
(KeyCode::Char('t'), KeyModifiers::NONE) => KeyAction::ToggleTheme,
(KeyCode::Char('P'), KeyModifiers::SHIFT) => KeyAction::CyclePreviewMode,
(KeyCode::Char('v'), KeyModifiers::NONE) => KeyAction::ToggleLayout,
(KeyCode::Char(','), KeyModifiers::NONE) => KeyAction::OpenSettings,
(KeyCode::Char('R'), KeyModifiers::SHIFT) => KeyAction::Refresh,
(KeyCode::Char('/'), KeyModifiers::NONE) => KeyAction::Search,
(KeyCode::Char('s'), KeyModifiers::NONE) => KeyAction::Sort,
(KeyCode::Char('S'), KeyModifiers::SHIFT) => KeyAction::ReverseSort,
(KeyCode::Enter, _) => KeyAction::DrillDown,
(KeyCode::Backspace, _) => KeyAction::NavigateBack,
(KeyCode::Char('-'), KeyModifiers::NONE) => KeyAction::NavigateBack,
(KeyCode::Char(':'), KeyModifiers::NONE) => KeyAction::CommandMode,
(KeyCode::Char(':'), KeyModifiers::SHIFT) => KeyAction::CommandMode,
(KeyCode::Char('g'), KeyModifiers::CONTROL) => KeyAction::GoTo,
(KeyCode::Char('n'), KeyModifiers::NONE) => KeyAction::Cancel,
(KeyCode::Tab, KeyModifiers::NONE) => KeyAction::NextView,
(KeyCode::BackTab, _) => KeyAction::PrevView,
(KeyCode::Char('t'), KeyModifiers::CONTROL) => KeyAction::NewDirTab,
(KeyCode::Char('w'), KeyModifiers::CONTROL) => KeyAction::CloseDirTab,
(KeyCode::Char(']'), KeyModifiers::NONE) => KeyAction::NextDirTab,
(KeyCode::Char('['), KeyModifiers::NONE) => KeyAction::PrevDirTab,
(KeyCode::Char('1'), KeyModifiers::NONE) => KeyAction::DirTab(1),
(KeyCode::Char('2'), KeyModifiers::NONE) => KeyAction::DirTab(2),
(KeyCode::Char('3'), KeyModifiers::NONE) => KeyAction::DirTab(3),
(KeyCode::Char('4'), KeyModifiers::NONE) => KeyAction::DirTab(4),
(KeyCode::Char('5'), KeyModifiers::NONE) => KeyAction::DirTab(5),
(KeyCode::Char('6'), KeyModifiers::NONE) => KeyAction::DirTab(6),
(KeyCode::Char('7'), KeyModifiers::NONE) => KeyAction::DirTab(7),
(KeyCode::Char('8'), KeyModifiers::NONE) => KeyAction::DirTab(8),
(KeyCode::Char('9'), KeyModifiers::NONE) => KeyAction::DirTab(9),
_ => KeyAction::None,
}
}
}
pub struct HelpSection {
pub title: &'static str,
pub bindings: Vec<KeyBinding>,
}
pub struct KeyBinding {
pub keys: &'static str,
pub description: &'static str,
}
pub fn get_help_sections() -> Vec<HelpSection> {
vec![
HelpSection {
title: "Navigation",
bindings: vec![
KeyBinding { keys: "j/k ↑/↓", description: "Move up/down" },
KeyBinding { keys: "h/l ←/→", description: "Collapse/expand" },
KeyBinding { keys: "Enter", description: "Drill into directory" },
KeyBinding { keys: "Backspace/-", description: "Navigate back" },
KeyBinding { keys: "g/G", description: "Jump to top/bottom" },
KeyBinding { keys: "Ctrl-u/d", description: "Page up/down" },
KeyBinding { keys: "Ctrl-g", description: "Go to directory" },
KeyBinding { keys: "o", description: "Toggle expand node" },
],
},
HelpSection {
title: "Selection & Clipboard",
bindings: vec![
KeyBinding { keys: "Space", description: "Mark item for multi-select" },
KeyBinding { keys: "y", description: "Yank (copy) to clipboard" },
KeyBinding { keys: "x", description: "Cut to clipboard" },
KeyBinding { keys: "p", description: "Paste from clipboard" },
KeyBinding { keys: "Esc", description: "Clear clipboard/marks" },
],
},
HelpSection {
title: "File Operations",
bindings: vec![
KeyBinding { keys: "d/Del", description: "Delete item(s)" },
KeyBinding { keys: "r", description: "Rename" },
KeyBinding { keys: "a", description: "Create file (touch)" },
KeyBinding { keys: "A", description: "Create directory (mkdir)" },
KeyBinding { keys: "T", description: "Take (mkdir + cd)" },
KeyBinding { keys: "Ctrl-z", description: "Undo" },
],
},
HelpSection {
title: "Views & Display",
bindings: vec![
KeyBinding { keys: "Tab/S-Tab", description: "Switch view (Explorer/Dups/Age)" },
KeyBinding { keys: "v", description: "Toggle Tree/Miller" },
KeyBinding { keys: "s", description: "Cycle sort mode" },
KeyBinding { keys: "S", description: "Reverse sort order" },
KeyBinding { keys: "i", description: "Toggle details panel" },
KeyBinding { keys: "t", description: "Toggle dark/light theme" },
KeyBinding { keys: "R", description: "Refresh/rescan" },
],
},
HelpSection {
title: "Duplicates View",
bindings: vec![
KeyBinding { keys: "j/k", description: "Navigate groups/files" },
KeyBinding { keys: "h/l", description: "Collapse/expand group" },
KeyBinding { keys: "d (on group)", description: "Mark all duplicates (keeps 1st)" },
KeyBinding { keys: "d (on file)", description: "Mark single file for deletion" },
KeyBinding { keys: "Space (group)", description: "Select/deselect all in group" },
KeyBinding { keys: "Space (file)", description: "Toggle single file selection" },
],
},
HelpSection {
title: "Directory Tabs",
bindings: vec![
KeyBinding { keys: "Ctrl-t", description: "New tab (current dir)" },
KeyBinding { keys: "Ctrl-w", description: "Close current tab" },
KeyBinding { keys: "]/[", description: "Next/prev tab" },
KeyBinding { keys: "1-9", description: "Jump to tab N" },
],
},
HelpSection {
title: "Commands",
bindings: vec![
KeyBinding { keys: ":", description: "Open command palette" },
KeyBinding { keys: ",", description: "Open settings" },
KeyBinding { keys: "?", description: "Show this help" },
KeyBinding { keys: "q", description: "Quit" },
],
},
]
}
pub fn get_command_help() -> Vec<(&'static str, &'static str)> {
vec![
(":q :quit", "Quit application"),
(":cd <path>", "Change directory"),
(":touch <name>", "Create file"),
(":mkdir <name>", "Create directory"),
(":take <name>", "Create dir and cd into it"),
(":yank :y", "Copy to clipboard"),
(":cut :x", "Cut to clipboard"),
(":paste :p", "Paste from clipboard"),
(":delete :rm", "Delete marked items"),
(":rename <name>", "Rename current item"),
(":clear", "Clear all marks"),
(":theme dark|light", "Set theme"),
(":layout tree|miller", "Set layout"),
(":sort <mode>", "Set sort (size/name/date/count)"),
(":help", "Show help"),
]
}
#[allow(dead_code)]
pub fn get_key_bindings() -> Vec<KeyBinding> {
get_help_sections()
.into_iter()
.flat_map(|s| s.bindings)
.collect()
}