diff --git a/yazi-core/src/which/commands/show.rs b/yazi-core/src/which/commands/show.rs index 9a5ae428d..9210a1d6f 100644 --- a/yazi-core/src/which/commands/show.rs +++ b/yazi-core/src/which/commands/show.rs @@ -1,6 +1,6 @@ -use std::str::FromStr; +use std::{collections::HashMap, str::FromStr}; -use yazi_config::{keymap::{Control, Key}, KEYMAP}; +use yazi_config::{keymap::{Control, ControlCow, Key}, KEYMAP}; use yazi_shared::{event::Cmd, render, Layer}; use crate::which::{Which, WhichSorter}; @@ -45,12 +45,7 @@ impl Which { pub fn show_with(&mut self, key: &Key, layer: Layer) { self.layer = layer; self.times = 1; - self.cands = KEYMAP - .get(layer) - .iter() - .filter(|c| c.on.len() > 1 && &c.on[0] == key) - .map(|c| c.into()) - .collect(); + self.cands = keymap_candidates(layer, key); WhichSorter::default().sort(&mut self.cands); self.visible = true; @@ -58,3 +53,61 @@ impl Which { render!(); } } + +fn keymap_candidates(layer: Layer, key: &Key) -> Vec { + let mut results: HashMap<&Vec, ControlCow> = HashMap::new(); + + let matches = KEYMAP.get(layer).iter().filter(|c| c.on.len() > 1 && &c.on[0] == key); + for c in matches { + if !results.contains_key(&c.on) { + results.insert(&c.on, c.into()); + } + } + + results.into_values().collect() +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use super::*; + + fn key(char: char) -> Key { + Key { code: crossterm::event::KeyCode::Char(char), alt: false, ctrl: false, shift: false } + } + + #[test] + fn test_candidates_removes_duplicates() { + // When there are duplicate mappings in the [manager] section's prepend_keymap + // and keymap definitions, only the mapping in the prepend_keymap section will + // match. We should only display that one as a suggestion to the user. + let first = Control { + on: vec![key('g'), key('c')], + run: vec![Cmd { name: "noop".to_string(), args: HashMap::new() }], + desc: Some("do nothing".to_string()), + }; + let second = Control { + on: vec![key('g'), key('c')], + run: vec![Cmd { name: "noop".to_string(), args: HashMap::new() }], + desc: Some("do nothing 2".to_string()), + }; + + KEYMAP.init(yazi_config::keymap::Keymap { + tasks: vec![], + select: vec![], + input: vec![], + help: vec![], + completion: vec![], + manager: vec![first, second], + }); + + let cands = keymap_candidates(Layer::Manager, &key('g')); + + // duplicates have been removed + assert_eq!(cands.len(), 1); + + // the first one is kept + assert_eq!(cands[0].desc_or_run(), "do nothing"); + } +}