diff --git a/src/ui.rs b/src/ui.rs index 71c11482..041cb232 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1257,4 +1257,39 @@ mod tests { assert!(rendered_help.contains("open lazygit")); assert!(rendered_help.contains("custom command")); } + + #[test] + fn keybind_help_compacts_multiple_indexed_ranges() { + let config: crate::config::Config = toml::from_str( + r#" +[keys] +switch_tab = ["prefix+1..9", "alt+1..9"] +switch_workspace = "ctrl+1..9" +"#, + ) + .expect("config parses"); + + let mut app = crate::app::state::AppState::test_new(); + app.keybinds = config.keybinds(); + + let workspace_tab = keybind_help_groups(&app) + .into_iter() + .find(|(name, _)| *name == "workspaces / tabs") + .expect("workspace tab group") + .1; + + let switch_tab_key = workspace_tab + .iter() + .find(|(_, label)| label.as_ref() == "switch tab 1-9") + .map(|(key, _)| key.as_str()) + .expect("switch tab help entry"); + let switch_workspace_key = workspace_tab + .iter() + .find(|(_, label)| label.as_ref() == "switch workspace 1-9") + .map(|(key, _)| key.as_str()) + .expect("switch workspace help entry"); + + assert_eq!(switch_tab_key, "prefix+1..9 / alt+1..9"); + assert_eq!(switch_workspace_key, "ctrl+1..9"); + } } diff --git a/src/ui/keybind_help.rs b/src/ui/keybind_help.rs index 76a68f0d..8385af36 100644 --- a/src/ui/keybind_help.rs +++ b/src/ui/keybind_help.rs @@ -29,25 +29,34 @@ fn keybind_label(bindings: &crate::config::ActionKeybinds) -> String { fn indexed_label(bindings: &[crate::config::IndexedKeybind]) -> String { if bindings.is_empty() { - "unset".to_string() - } else if bindings.len() == 9 { - let first = &bindings[0].label; - if first.ends_with('1') { - format!("{}1..9", first.trim_end_matches('1')) - } else { - bindings - .iter() - .map(|binding| binding.label.clone()) - .collect::>() - .join(" / ") - } - } else { - bindings - .iter() - .map(|binding| binding.label.clone()) - .collect::>() - .join(" / ") + return "unset".to_string(); } + + let mut parts = Vec::new(); + let mut index = 0; + while index < bindings.len() { + if let Some(prefix) = indexed_range_prefix(&bindings[index..]) { + parts.push(format!("{prefix}1..9")); + index += 9; + } else { + parts.push(bindings[index].label.clone()); + index += 1; + } + } + + parts.join(" / ") +} + +fn indexed_range_prefix(bindings: &[crate::config::IndexedKeybind]) -> Option<&str> { + let run = bindings.get(..9)?; + let prefix = run[0].label.strip_suffix('1')?; + for (offset, binding) in run.iter().enumerate() { + let digit = char::from(b'1' + offset as u8); + if binding.label.strip_suffix(digit) != Some(prefix) { + return None; + } + } + Some(prefix) } pub(super) fn keybind_help_groups(app: &AppState) -> Vec {