diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-19 15:43:47 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-19 15:43:47 +0300 |
| commit | e0507237ad8d41f60aece10d00ef29ce2339ca34 (patch) | |
| tree | 829503bc869cf76285953866367b74a90927a19d /src/client/shell/overlay_input.rs | |
| parent | cc7c696cd0772e466da403eb4e3f00f4e8d8ae1e (diff) | |
feat: show every agent and terminal in the go to picker (#4384)
Diffstat (limited to 'src/client/shell/overlay_input.rs')
| -rw-r--r-- | src/client/shell/overlay_input.rs | 105 |
1 files changed, 54 insertions, 51 deletions
diff --git a/src/client/shell/overlay_input.rs b/src/client/shell/overlay_input.rs index 7cf151cb..e4248304 100644 --- a/src/client/shell/overlay_input.rs +++ b/src/client/shell/overlay_input.rs @@ -191,21 +191,12 @@ impl ClientShellState { } pub(super) fn open_navigator_overlay(&mut self) { - let expanded_workspaces = - super::aggregate_navigation::cached_endpoint_snapshots(&self.endpoints) - .flat_map(|endpoint| { - endpoint.snapshot.workspaces.iter().map(move |workspace| { - (endpoint.endpoint_id.clone(), workspace.workspace_id.clone()) - }) - }) - .collect(); let mut navigator = ClientNavigatorOverlay { query: TextEditor::default(), search_focused: false, selected: None, scroll: 0, filter: None, - expanded_workspaces, }; let rows = render::client_navigator_rows(&self.endpoints, &self.active_endpoint_id, &navigator); @@ -233,6 +224,55 @@ impl ClientShellState { navigator.selected = Some(rows[next].target.clone()); } + pub(super) fn scroll_navigator_to(&mut self, scroll: usize, viewport_rows: usize) { + let Some(ClientShellOverlay::Navigator(navigator)) = self.overlay.as_mut() else { + return; + }; + let rows = + render::client_navigator_rows(&self.endpoints, &self.active_endpoint_id, navigator); + let viewport_rows = viewport_rows.max(1); + navigator.scroll = scroll.min(rows.len().saturating_sub(viewport_rows)); + let selected = + super::aggregate_navigation::navigator_selected_index(&rows, navigator).unwrap_or(0); + // Keep the selection in the dragged viewport so rendering does not snap back to it. + let selected = selected.clamp(navigator.scroll, navigator.scroll + viewport_rows - 1); + navigator.selected = rows.get(selected).map(|row| row.target.clone()); + } + + fn move_navigator_workspace(&mut self, forward: bool) { + let Some(ClientShellOverlay::Navigator(navigator)) = self.overlay.as_mut() else { + return; + }; + let rows = + render::client_navigator_rows(&self.endpoints, &self.active_endpoint_id, navigator); + let Some(selected) = + super::aggregate_navigation::navigator_selected_index(&rows, navigator) + else { + return; + }; + let section = rows[..=selected] + .iter() + .rposition(|row| !matches!(row.target, ClientNavigatorTarget::Pane { .. })) + .unwrap_or(selected); + let mut destinations = rows.windows(2).enumerate().filter(|(index, pair)| { + matches!(pair[0].target, ClientNavigatorTarget::Workspace { .. }) + && matches!(pair[1].target, ClientNavigatorTarget::Pane { .. }) + && if forward { + *index > section + } else { + *index < section + } + }); + let destination = if forward { + destinations.next() + } else { + destinations.next_back() + }; + if let Some((_, pair)) = destination { + navigator.selected = Some(pair[1].target.clone()); + } + } + pub(super) fn accept_navigator_selection(&mut self, outcome: &mut ClientShellInput) { let target = self.overlay.as_ref().and_then(|overlay| match overlay { ClientShellOverlay::Navigator(navigator) => { @@ -260,12 +300,6 @@ impl ClientShellState { ClientEndpointFocusTarget::Workspace(workspace_id), outcome, ), - ClientNavigatorTarget::Tab { - endpoint_id, - tab_id, - } => { - self.focus_or_activate(endpoint_id, ClientEndpointFocusTarget::Tab(tab_id), outcome) - } ClientNavigatorTarget::Pane { endpoint_id, pane_id, @@ -281,37 +315,6 @@ impl ClientShellState { outcome.repaint = true; } - pub(super) fn toggle_selected_navigator_workspace(&mut self) { - let workspace_key = self.overlay.as_ref().and_then(|overlay| match overlay { - ClientShellOverlay::Navigator(navigator) => { - let rows = render::client_navigator_rows( - &self.endpoints, - &self.active_endpoint_id, - navigator, - ); - super::aggregate_navigation::selected_navigator_target(&rows, navigator).and_then( - |target| match target { - ClientNavigatorTarget::Workspace { - endpoint_id, - workspace_id, - } => Some((endpoint_id, workspace_id)), - _ => None, - }, - ) - } - _ => None, - }); - if let (Some(workspace_key), Some(ClientShellOverlay::Navigator(navigator))) = - (workspace_key, self.overlay.as_mut()) - { - if !navigator.expanded_workspaces.remove(&workspace_key) { - navigator.expanded_workspaces.insert(workspace_key); - } - navigator.selected = None; - navigator.scroll = 0; - } - } - pub(super) fn workspace_action_id(&self) -> Option<String> { self.navigate_workspace_id .as_ref() @@ -676,6 +679,11 @@ impl ClientShellState { } return; } + if matches!(code, KeyCode::Left | KeyCode::Right) && modifiers.is_empty() { + self.move_navigator_workspace(code == KeyCode::Right); + outcome.repaint = true; + return; + } if code == KeyCode::Backspace && modifiers.is_empty() { if let Some(ClientShellOverlay::Navigator(navigator)) = self.overlay.as_mut() { if navigator.filter.take().is_some() { @@ -762,11 +770,6 @@ impl ClientShellState { outcome.repaint = true; return; } - if code == KeyCode::Char(' ') && modifiers.is_empty() { - self.toggle_selected_navigator_workspace(); - outcome.repaint = true; - return; - } return; } |
