feat: add notification target keybind
This commit is contained in:
parent
fe693f613a
commit
8d5dca8cfe
|
|
@ -94,6 +94,7 @@ new_workspace = "n"
|
|||
rename_workspace = "shift+n"
|
||||
close_workspace = "shift+d"
|
||||
reload_config = "" # optional, unset by default
|
||||
open_notification_target = "" # optional, unset by default
|
||||
new_tab = "c"
|
||||
split_vertical = "v"
|
||||
split_horizontal = "-"
|
||||
|
|
@ -122,6 +123,7 @@ focus_pane_right = "alt+l"
|
|||
| `close_workspace` | `shift+d` | close selected workspace |
|
||||
| `detach` | unset | optional explicit detach shortcut in the persistent session |
|
||||
| `reload_config` | unset | reload `config.toml` in the running app/server |
|
||||
| `open_notification_target` | unset | jump to the currently visible notification target |
|
||||
| `previous_workspace` | unset | switch to the previous workspace directly from terminal mode |
|
||||
| `next_workspace` | unset | switch to the next workspace directly from terminal mode |
|
||||
| `new_tab` | `c` | create a new tab |
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ impl AppState {
|
|||
&& rect_contains(self.view.toast_hit_area, col, row)
|
||||
}
|
||||
|
||||
fn focus_toast_target(&mut self) {
|
||||
pub(crate) fn focus_toast_target(&mut self) {
|
||||
let Some(target) = self.toast.as_ref().and_then(|toast| toast.target.clone()) else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ pub(crate) enum NavigateAction {
|
|||
EnterResizeMode,
|
||||
ToggleSidebar,
|
||||
ReloadConfig,
|
||||
OpenNotificationTarget,
|
||||
Detach,
|
||||
}
|
||||
|
||||
|
|
@ -463,6 +464,12 @@ fn navigate_action_for_key(state: &AppState, key: &KeyEvent) -> Option<NavigateA
|
|||
{
|
||||
return Some(NavigateAction::ReloadConfig);
|
||||
}
|
||||
if kb
|
||||
.open_notification_target
|
||||
.is_some_and(|(code, mods)| key_matches(key, code, mods))
|
||||
{
|
||||
return Some(NavigateAction::OpenNotificationTarget);
|
||||
}
|
||||
if kb
|
||||
.detach
|
||||
.is_some_and(|(code, mods)| key_matches(key, code, mods))
|
||||
|
|
@ -553,6 +560,12 @@ pub(super) fn execute_navigate_action(state: &mut AppState, action: NavigateActi
|
|||
state.request_reload_config = true;
|
||||
leave_navigate_mode(state);
|
||||
}
|
||||
NavigateAction::OpenNotificationTarget => {
|
||||
state.focus_toast_target();
|
||||
if state.mode == Mode::Navigate {
|
||||
leave_navigate_mode(state);
|
||||
}
|
||||
}
|
||||
NavigateAction::Detach => {
|
||||
state.detach_requested = true;
|
||||
leave_navigate_mode(state);
|
||||
|
|
@ -652,6 +665,38 @@ mod tests {
|
|||
assert_eq!(state.mode, Mode::Terminal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_open_notification_key_focuses_current_toast_target() {
|
||||
let mut state = state_with_workspaces(&["one", "two"]);
|
||||
state.active = Some(0);
|
||||
state.selected = 0;
|
||||
state.mode = Mode::Navigate;
|
||||
state.keybinds.open_notification_target = Some((KeyCode::Char('g'), KeyModifiers::empty()));
|
||||
state.keybinds.open_notification_target_label = Some("g".into());
|
||||
let target_workspace_id = state.workspaces[1].id.clone();
|
||||
let target_pane = state.workspaces[1].tabs[0].root_pane;
|
||||
state.toast = Some(crate::app::state::ToastNotification {
|
||||
kind: crate::app::state::ToastKind::NeedsAttention,
|
||||
title: "pi needs attention".into(),
|
||||
context: "two".into(),
|
||||
target: Some(crate::app::state::ToastTarget {
|
||||
workspace_id: target_workspace_id,
|
||||
pane_id: target_pane,
|
||||
}),
|
||||
});
|
||||
|
||||
handle_navigate_key(
|
||||
&mut state,
|
||||
KeyEvent::new(KeyCode::Char('g'), KeyModifiers::empty()),
|
||||
);
|
||||
|
||||
assert_eq!(state.active, Some(1));
|
||||
assert_eq!(state.selected, 1);
|
||||
assert_eq!(state.workspaces[1].focused_pane_id(), Some(target_pane));
|
||||
assert!(state.toast.is_none());
|
||||
assert_eq!(state.mode, Mode::Terminal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn movement_action_stays_in_navigate_mode() {
|
||||
let mut state = state_with_workspaces(&["a", "b"]);
|
||||
|
|
|
|||
|
|
@ -897,6 +897,8 @@ impl AppState {
|
|||
detach_label: None,
|
||||
reload_config: None,
|
||||
reload_config_label: None,
|
||||
open_notification_target: None,
|
||||
open_notification_target_label: None,
|
||||
previous_workspace: None,
|
||||
previous_workspace_label: None,
|
||||
next_workspace: None,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ pub struct Keybinds {
|
|||
pub detach_label: Option<String>,
|
||||
pub reload_config: Option<(KeyCode, KeyModifiers)>,
|
||||
pub reload_config_label: Option<String>,
|
||||
pub open_notification_target: Option<(KeyCode, KeyModifiers)>,
|
||||
pub open_notification_target_label: Option<String>,
|
||||
pub previous_workspace: Option<(KeyCode, KeyModifiers)>,
|
||||
pub previous_workspace_label: Option<String>,
|
||||
pub next_workspace: Option<(KeyCode, KeyModifiers)>,
|
||||
|
|
@ -345,6 +347,12 @@ impl Config {
|
|||
&self.keys.reload_config,
|
||||
&mut diagnostics,
|
||||
),
|
||||
optional_binding(
|
||||
BindingScope::Navigate,
|
||||
"keys.open_notification_target",
|
||||
&self.keys.open_notification_target,
|
||||
&mut diagnostics,
|
||||
),
|
||||
optional_binding(
|
||||
BindingScope::Navigate,
|
||||
"keys.previous_workspace",
|
||||
|
|
@ -596,30 +604,32 @@ impl Config {
|
|||
detach_label: optional_bindings[0].label.clone(),
|
||||
reload_config: optional_bindings[1].value,
|
||||
reload_config_label: optional_bindings[1].label.clone(),
|
||||
previous_workspace: optional_bindings[2].value,
|
||||
previous_workspace_label: optional_bindings[2].label.clone(),
|
||||
next_workspace: optional_bindings[3].value,
|
||||
next_workspace_label: optional_bindings[3].label.clone(),
|
||||
open_notification_target: optional_bindings[2].value,
|
||||
open_notification_target_label: optional_bindings[2].label.clone(),
|
||||
previous_workspace: optional_bindings[3].value,
|
||||
previous_workspace_label: optional_bindings[3].label.clone(),
|
||||
next_workspace: optional_bindings[4].value,
|
||||
next_workspace_label: optional_bindings[4].label.clone(),
|
||||
new_tab: bindings[3].value,
|
||||
new_tab_label: bindings[3].label.clone(),
|
||||
rename_tab: optional_bindings[4].value,
|
||||
rename_tab_label: optional_bindings[4].label.clone(),
|
||||
previous_tab: optional_bindings[5].value,
|
||||
previous_tab_label: optional_bindings[5].label.clone(),
|
||||
next_tab: optional_bindings[6].value,
|
||||
next_tab_label: optional_bindings[6].label.clone(),
|
||||
close_tab: optional_bindings[7].value,
|
||||
close_tab_label: optional_bindings[7].label.clone(),
|
||||
rename_pane: optional_bindings[8].value,
|
||||
rename_pane_label: optional_bindings[8].label.clone(),
|
||||
focus_pane_left: optional_bindings[9].value,
|
||||
focus_pane_left_label: optional_bindings[9].label.clone(),
|
||||
focus_pane_down: optional_bindings[10].value,
|
||||
focus_pane_down_label: optional_bindings[10].label.clone(),
|
||||
focus_pane_up: optional_bindings[11].value,
|
||||
focus_pane_up_label: optional_bindings[11].label.clone(),
|
||||
focus_pane_right: optional_bindings[12].value,
|
||||
focus_pane_right_label: optional_bindings[12].label.clone(),
|
||||
rename_tab: optional_bindings[5].value,
|
||||
rename_tab_label: optional_bindings[5].label.clone(),
|
||||
previous_tab: optional_bindings[6].value,
|
||||
previous_tab_label: optional_bindings[6].label.clone(),
|
||||
next_tab: optional_bindings[7].value,
|
||||
next_tab_label: optional_bindings[7].label.clone(),
|
||||
close_tab: optional_bindings[8].value,
|
||||
close_tab_label: optional_bindings[8].label.clone(),
|
||||
rename_pane: optional_bindings[9].value,
|
||||
rename_pane_label: optional_bindings[9].label.clone(),
|
||||
focus_pane_left: optional_bindings[10].value,
|
||||
focus_pane_left_label: optional_bindings[10].label.clone(),
|
||||
focus_pane_down: optional_bindings[11].value,
|
||||
focus_pane_down_label: optional_bindings[11].label.clone(),
|
||||
focus_pane_up: optional_bindings[12].value,
|
||||
focus_pane_up_label: optional_bindings[12].label.clone(),
|
||||
focus_pane_right: optional_bindings[13].value,
|
||||
focus_pane_right_label: optional_bindings[13].label.clone(),
|
||||
split_vertical: bindings[4].value,
|
||||
split_vertical_label: bindings[4].label.clone(),
|
||||
split_horizontal: bindings[5].value,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ pub struct KeysConfig {
|
|||
pub detach: String,
|
||||
/// Reload config.toml in the running app/server. Unset by default.
|
||||
pub reload_config: String,
|
||||
/// Focus the currently visible notification target. Unset by default.
|
||||
pub open_notification_target: String,
|
||||
/// Select the previous workspace. Unset by default.
|
||||
pub previous_workspace: String,
|
||||
/// Select the next workspace. Unset by default.
|
||||
|
|
@ -157,6 +159,7 @@ impl Default for KeysConfig {
|
|||
close_workspace: "shift+d".into(),
|
||||
detach: "".into(),
|
||||
reload_config: "".into(),
|
||||
open_notification_target: "".into(),
|
||||
previous_workspace: "".into(),
|
||||
next_workspace: "".into(),
|
||||
new_tab: "c".into(),
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ const DEFAULT_CONFIG: &str = r##"# herdr configuration
|
|||
# next_workspace = "" # optional, unset by default
|
||||
# detach = "" # optional explicit detach shortcut in server/client mode
|
||||
# reload_config = "" # optional shortcut to reload config.toml without restarting
|
||||
# open_notification_target = "" # optional shortcut to jump to the visible notification target
|
||||
# new_tab = "c"
|
||||
# rename_tab = "" # optional, unset by default
|
||||
# previous_tab = "" # optional, unset by default
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ pub(super) fn keybind_help_groups(
|
|||
(kb.new_workspace_label.clone(), "new workspace"),
|
||||
(kb.rename_workspace_label.clone(), "rename workspace"),
|
||||
(kb.close_workspace_label.clone(), "close workspace"),
|
||||
(
|
||||
optional_keybind_label(&kb.open_notification_target_label),
|
||||
"open notification target",
|
||||
),
|
||||
(
|
||||
optional_keybind_label(&kb.previous_workspace_label),
|
||||
"previous workspace",
|
||||
|
|
|
|||
Loading…
Reference in New Issue