diff options
Diffstat (limited to 'src/app/input')
| -rw-r--r-- | src/app/input/mouse.rs | 109 | ||||
| -rw-r--r-- | src/app/input/navigate.rs | 48 |
2 files changed, 147 insertions, 10 deletions
diff --git a/src/app/input/mouse.rs b/src/app/input/mouse.rs index 99157d0d..779af3ed 100644 --- a/src/app/input/mouse.rs +++ b/src/app/input/mouse.rs @@ -581,19 +581,24 @@ impl AppState { } } - MouseEventKind::ScrollUp | MouseEventKind::ScrollDown if !in_sidebar => { - if self.on_tab_bar(mouse.column, mouse.row) { - match mouse.kind { - MouseEventKind::ScrollUp => self.scroll_tabs_left(), - MouseEventKind::ScrollDown => self.scroll_tabs_right(), - _ => {} - } - } else if !self.scroll_selection_with_wheel(mouse) { - self.selection = None; - self.handle_terminal_wheel(mouse); + MouseEventKind::ScrollUp | MouseEventKind::ScrollDown + if self.on_tab_bar(mouse.column, mouse.row) => + { + match mouse.kind { + MouseEventKind::ScrollUp => self.previous_tab(), + MouseEventKind::ScrollDown => self.next_tab(), + _ => {} } } + MouseEventKind::ScrollUp | MouseEventKind::ScrollDown + if !in_sidebar && self.scroll_selection_with_wheel(mouse) => {} + + MouseEventKind::ScrollUp | MouseEventKind::ScrollDown if !in_sidebar => { + self.selection = None; + self.handle_terminal_wheel(mouse); + } + MouseEventKind::ScrollUp if in_sidebar => { let agent_area = self.agent_panel_rect(); let over_agent_panel = agent_area != Rect::default() @@ -1568,6 +1573,90 @@ mod tests { } #[test] + fn wheel_over_tab_bar_switches_tabs() { + let mut app = app_for_mouse_test(); + let mut ws = Workspace::test_new("one"); + ws.test_add_tab(Some("two")); + ws.test_add_tab(Some("three")); + app.state.workspaces = vec![ws]; + app.state.active = Some(0); + app.state.selected = 0; + app.state.mode = Mode::Terminal; + + crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20)); + let tab_bar = app.state.view.tab_bar_rect; + + app.handle_mouse(mouse(MouseEventKind::ScrollDown, tab_bar.x + 1, tab_bar.y)); + assert_eq!(app.state.workspaces[0].active_tab, 1); + + app.handle_mouse(mouse(MouseEventKind::ScrollUp, tab_bar.x + 1, tab_bar.y)); + assert_eq!(app.state.workspaces[0].active_tab, 0); + + app.handle_mouse(mouse(MouseEventKind::ScrollUp, tab_bar.x + 1, tab_bar.y)); + assert_eq!(app.state.workspaces[0].active_tab, 2); + + app.handle_mouse(mouse( + MouseEventKind::ScrollDown, + tab_bar.x + tab_bar.width.saturating_sub(1), + tab_bar.y, + )); + assert_eq!(app.state.workspaces[0].active_tab, 0); + } + + #[test] + fn wheel_over_overflowing_tab_bar_switches_tabs() { + let mut app = app_for_mouse_test(); + let mut ws = Workspace::test_new("one"); + ws.tabs[0].set_custom_name("very-long-one".into()); + ws.test_add_tab(Some("very-long-two")); + ws.test_add_tab(Some("very-long-three")); + app.state.workspaces = vec![ws]; + app.state.active = Some(0); + app.state.selected = 0; + app.state.mode = Mode::Terminal; + + crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 65, 20)); + assert!(app.state.view.tab_scroll_right_hit_area.width > 0); + let tab_bar = app.state.view.tab_bar_rect; + + app.handle_mouse(mouse( + MouseEventKind::ScrollDown, + tab_bar.x + tab_bar.width.saturating_sub(2), + tab_bar.y, + )); + assert_eq!(app.state.workspaces[0].active_tab, 1); + + app.handle_mouse(mouse( + MouseEventKind::ScrollDown, + tab_bar.x + tab_bar.width.saturating_sub(2), + tab_bar.y, + )); + assert_eq!(app.state.workspaces[0].active_tab, 2); + } + + #[test] + fn wheel_outside_tab_bar_does_not_switch_tabs() { + let mut app = app_for_mouse_test(); + let mut ws = Workspace::test_new("one"); + ws.test_add_tab(Some("two")); + app.state.workspaces = vec![ws]; + app.state.active = Some(0); + app.state.selected = 0; + app.state.mode = Mode::Terminal; + + crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20)); + let terminal = app.state.view.terminal_area; + + app.handle_mouse(mouse( + MouseEventKind::ScrollDown, + terminal.x + 1, + terminal.y + 1, + )); + + assert_eq!(app.state.workspaces[0].active_tab, 0); + } + + #[test] fn mobile_switch_button_opens_switcher_and_workspace_row_switches_workspace() { let mut app = app_for_mouse_test(); app.state.workspaces = vec![Workspace::test_new("one"), Workspace::test_new("two")]; diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs index ce3d9cf4..6dfaf475 100644 --- a/src/app/input/navigate.rs +++ b/src/app/input/navigate.rs @@ -31,6 +31,18 @@ pub(crate) fn terminal_direct_navigation_action( return Some(NavigateAction::NextWorkspace); } if kb + .previous_agent + .is_some_and(|(code, mods)| key_matches(key, code, mods)) + { + return Some(NavigateAction::PreviousAgent); + } + if kb + .next_agent + .is_some_and(|(code, mods)| key_matches(key, code, mods)) + { + return Some(NavigateAction::NextAgent); + } + if kb .previous_tab .is_some_and(|(code, mods)| key_matches(key, code, mods)) { @@ -363,6 +375,8 @@ pub(crate) enum NavigateAction { CloseWorkspace, PreviousWorkspace, NextWorkspace, + PreviousAgent, + NextAgent, NewTab, RenameTab, PreviousTab, @@ -407,6 +421,18 @@ fn navigate_action_for_key(state: &AppState, key: &KeyEvent) -> Option<NavigateA { return Some(NavigateAction::NextWorkspace); } + if kb + .previous_agent + .is_some_and(|(code, mods)| key_matches(key, code, mods)) + { + return Some(NavigateAction::PreviousAgent); + } + if kb + .next_agent + .is_some_and(|(code, mods)| key_matches(key, code, mods)) + { + return Some(NavigateAction::NextAgent); + } if key_matches(key, kb.new_tab.0, kb.new_tab.1) { return Some(NavigateAction::NewTab); } @@ -508,6 +534,14 @@ pub(super) fn execute_navigate_action(state: &mut AppState, action: NavigateActi state.next_workspace(); leave_navigate_mode(state); } + NavigateAction::PreviousAgent => { + state.previous_agent(); + leave_navigate_mode(state); + } + NavigateAction::NextAgent => { + state.next_agent(); + leave_navigate_mode(state); + } NavigateAction::NewTab => super::modal::open_new_tab_dialog(state), NavigateAction::RenameTab => super::modal::open_rename_active_tab(state, false), NavigateAction::PreviousTab => { @@ -730,6 +764,20 @@ mod tests { } #[test] + fn terminal_direct_agent_shortcut_maps_to_navigation_action() { + let mut state = state_with_workspaces(&["test"]); + state.keybinds.next_agent = Some((KeyCode::Char('a'), KeyModifiers::ALT)); + state.keybinds.next_agent_label = Some("alt+a".into()); + + let action = terminal_direct_navigation_action( + &state, + &KeyEvent::new(KeyCode::Char('a'), KeyModifiers::ALT), + ); + + assert_eq!(action, Some(NavigateAction::NextAgent)); + } + + #[test] fn terminal_direct_focus_pane_shortcut_maps_to_navigation_action() { let mut state = state_with_workspaces(&["test"]); state.keybinds.focus_pane_left = Some((KeyCode::Left, KeyModifiers::ALT)); |
