use crate::keymap::{Action, render_chord};
use crate::transient::TransientKind;
use super::App;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Command {
pub action: Action,
pub label: &'static str,
pub chord: String,
}
impl App {
pub(crate) fn command_index_haystack(&self) -> (Vec<Command>, Vec<String>) {
let commands = self.command_index();
let haystack = commands
.iter()
.map(|c| format!("{} {} {}", c.label, c.action.name(), c.chord))
.collect();
(commands, haystack)
}
pub(crate) fn command_index(&self) -> Vec<Command> {
let keymap = self.active_keymap();
let mut commands: Vec<Command> = keymap
.bindings()
.iter()
.map(|(chord, action)| Command {
action: *action,
label: action.label(),
chord: render_chord(chord),
})
.collect();
for kind in TransientKind::ALL {
let Some(prefix) = keymap
.prefix_chord(kind)
.filter(|_| self.offers_transient(kind))
else {
continue;
};
commands.extend(
self.transient(kind)
.flat_entries()
.map(|(key, entry)| Command {
action: entry.action,
label: entry.action.label(),
chord: format!("{prefix} {key}"),
}),
);
}
commands.extend(
self.tabs_keymap()
.bindings()
.iter()
.map(|(chord, action)| Command {
action: *action,
label: action.label(),
chord: render_chord(chord),
}),
);
commands
}
}
#[cfg(test)]
mod tests {
use crate::app::App;
use crate::config::LoadedConfig;
use crate::keymap::Action;
use crate::test_support::standard_fixture;
#[test]
fn status_index_covers_bindings_and_transient_leaves() {
let fixture = standard_fixture();
let app = App::new(fixture.review(), LoadedConfig::default());
let commands = app.command_index();
let find = |action: Action| {
commands
.iter()
.find(|c| c.action == action)
.unwrap_or_else(|| panic!("{} listed", action.name()))
};
assert_eq!(find(Action::Stage).chord, "s");
assert_eq!(find(Action::CommitAmend).chord, "c a");
assert_eq!(find(Action::PushSetUpstream).chord, "P u");
}
#[test]
fn every_action_has_a_nonempty_label() {
for action in Action::ALL {
assert!(!action.label().is_empty(), "{} labelled", action.name());
}
}
}