use crate::domain::filter::{Tab, TabKind};
use crate::keymap::Action;
const SECTIONS_GROUP: (&str, &[Action]) = (
"Sections",
&[
Action::ManageSections,
Action::SectionJump,
Action::ToggleGrouping,
Action::ReorderUp,
Action::ReorderDown,
],
);
const VIEW_GROUP: (&str, &[Action]) = (
"View",
&[
Action::ToggleSelect,
Action::Filter,
Action::ChangesFilter,
Action::Columns,
Action::Sort,
Action::ToggleFavFloat,
Action::ToggleSlugs,
Action::CopyPath,
Action::Github,
],
);
const PANEL_GROUP: (&str, &[Action]) = (
"Panel",
&[
Action::Preview,
Action::PreviewPosition,
Action::PreviewScrollUp,
Action::PreviewGrow,
],
);
const GIT_HINT_GROUPS: &[(&str, &[Action])] = &[
(
"Open",
&[
Action::Jump,
Action::Open,
Action::GitTool,
Action::JumpCd,
Action::OpenApp,
],
),
(
"Manage",
&[
Action::Add,
Action::Edit,
Action::Delete,
Action::ToggleFav,
Action::Archive,
Action::Slug,
Action::Undo,
],
),
("Backup", &[Action::Zip, Action::ZipAll]),
VIEW_GROUP,
PANEL_GROUP,
SECTIONS_GROUP,
(
"Git",
&[
Action::Reload,
Action::ReloadFetch,
Action::RefreshOne,
Action::RefreshOneFetch,
Action::RepairPath,
Action::Errors,
],
),
];
const FILES_HINT_GROUPS: &[(&str, &[Action])] = &[
(
"Open",
&[Action::Jump, Action::Open, Action::JumpCd, Action::OpenApp],
),
(
"Manage",
&[
Action::Add,
Action::Edit,
Action::Delete,
Action::ToggleFav,
Action::Archive,
Action::Slug,
Action::Undo,
],
),
("Backup", &[Action::Zip, Action::ZipAll]),
VIEW_GROUP,
PANEL_GROUP,
SECTIONS_GROUP,
(
"Paths",
&[Action::Reload, Action::RepairPath, Action::Errors],
),
];
pub fn hint_groups(tab: Tab) -> &'static [(&'static str, &'static [Action])] {
match tab.kind() {
TabKind::Git => GIT_HINT_GROUPS,
TabKind::Files => FILES_HINT_GROUPS,
}
}
pub const HELP_SECTIONS: &[(&str, &[(Action, &str)])] = &[
(
"Open",
&[
(
Action::Jump,
"jump only: write path and exit (folder cd, file -> parent)",
),
(
Action::Open,
"open: git -> tool \u{b7} folder -> cd \u{b7} text file -> \
editor \u{b7} else app",
),
(
Action::GitTool,
"git: open the tool (lazygit) as an overlay, then return here",
),
(Action::JumpCd, "jump only: write path and exit"),
(
Action::OpenApp,
"force open with the default app (e.g. a text file in its GUI \
app)",
),
(
Action::Github,
"open on GitHub in the browser (a tab per selected git repo, \
else the cursor)",
),
],
),
(
"Manage",
&[
(
Action::Add,
"add an entry (fill the form; ^O picks the path)",
),
(
Action::Edit,
"edit the entry (or bulk-edit when several are selected)",
),
(
Action::Delete,
"delete (acts on the selection, else the cursor)",
),
(
Action::Undo,
"undo the last change (delete / archive / favourite / edit)",
),
(Action::ToggleFav, "toggle favourite (selection or cursor)"),
(Action::Archive, "archive / restore (selection or cursor)"),
(Action::Slug, "set or change the slug"),
(
Action::CopyPath,
"copy path to the clipboard (all selected, one per line, else \
the cursor)",
),
],
),
(
"Backup",
&[
(
Action::Zip,
"zip the selected/cursor repo or folder to the backup folder",
),
(
Action::ZipAll,
"zip every entry opted into backup (form 'Backup' toggle)",
),
],
),
(
"View",
&[
(
Action::ToggleSelect,
"add or remove the cursor entry from the \
selection",
),
(
Action::Filter,
"live fuzzy filter (Esc clears; matches are highlighted)",
),
(
Action::ChangesFilter,
"toggle showing only git repos with a status change",
),
(
Action::Columns,
"cycle the columns (Standard / Code / Activity)",
),
(
Action::Sort,
"pick the column to sort by (again: flip direction)",
),
(
Action::ToggleFavFloat,
"toggle floating favourites to the top",
),
(
Action::ToggleSlugs,
"toggle the slug column (dim, italic) after the name",
),
],
),
(
"Panel",
&[
(Action::Preview, "show or hide the detail panel"),
(Action::PreviewPosition, "move the panel: right / bottom"),
(Action::PreviewScrollUp, "scroll the panel up"),
(Action::PreviewScrollDown, "scroll the panel down"),
(Action::PreviewPageUp, "scroll the panel up by a page"),
(Action::PreviewPageDown, "scroll the panel down by a page"),
(Action::PreviewShrink, "make the panel smaller"),
(Action::PreviewGrow, "make the panel bigger"),
],
),
(
"Sections",
&[
(
Action::SectionJump,
"jump to a section (in the grouped view)",
),
(
Action::ManageSections,
"manage sections (add / rename / delete / move)",
),
(
Action::ToggleGrouping,
"toggle grouping into sections (off: flat, global sort)",
),
(
Action::ReorderUp,
"move the entry up within its group (custom sort only)",
),
(
Action::ReorderDown,
"move the entry down within its group (custom sort only)",
),
],
),
(
"Git and paths",
&[
(
Action::Reload,
"git tabs: reload status \u{b7} Files: check paths exist",
),
(Action::ReloadFetch, "reload status with a git fetch first"),
(Action::RefreshOne, "refresh the selection or cursor entry"),
(Action::RefreshOneFetch, "refresh it with a git fetch first"),
(Action::RepairPath, "repair a missing path"),
(Action::Errors, "list entries with path errors and fix them"),
],
),
];
pub const GLOBAL_ACTIONS: &[Action] = &[Action::Help, Action::Quit];
pub const NAVIGATION_ACTIONS: &[Action] = &[
Action::Up,
Action::Down,
Action::Top,
Action::Bottom,
Action::PageUp,
Action::PageDown,
Action::HalfPageUp,
Action::HalfPageDown,
Action::ExtendUp,
Action::ExtendDown,
Action::ExtendPageUp,
Action::ExtendPageDown,
Action::TabGit,
Action::TabFiles,
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_help_sections_cover_every_action_exactly_once() {
let mut covered: Vec<Action> = HELP_SECTIONS
.iter()
.flat_map(|(_, rows)| rows.iter().map(|(action, _)| *action))
.collect();
covered.extend_from_slice(NAVIGATION_ACTIONS);
covered.extend_from_slice(GLOBAL_ACTIONS);
for action in Action::all() {
assert!(
covered.contains(&action),
"{action:?} is in no help section; add it to bindings.rs and \
keep the README in sync"
);
}
let total = covered.len();
covered.sort_by_key(|action| format!("{action:?}"));
covered.dedup();
assert_eq!(
covered.len(),
total,
"an action is listed in two help sections"
);
}
#[test]
fn no_tab_lists_the_same_action_twice_in_its_footer() {
for groups in [GIT_HINT_GROUPS, FILES_HINT_GROUPS] {
let mut seen: Vec<Action> = groups
.iter()
.flat_map(|(_, actions)| actions.iter().copied())
.collect();
let total = seen.len();
seen.sort_by_key(|action| format!("{action:?}"));
seen.dedup();
assert_eq!(seen.len(), total, "a footer lists an action twice");
}
}
}