aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/shell/composition.rs96
-rw-r--r--src/client/shell/tests/chrome_context.rs45
2 files changed, 102 insertions, 39 deletions
diff --git a/src/client/shell/composition.rs b/src/client/shell/composition.rs
index 523cec87..92cf3c46 100644
--- a/src/client/shell/composition.rs
+++ b/src/client/shell/composition.rs
@@ -40,35 +40,55 @@ impl ClientShellState {
.navigate_workspace_id
.as_ref()
.is_some_and(|target| self.navigation_target_valid(target));
- super::endpoint_sidebar::render_expanded(
- &mut buffer,
- sidebar,
- self.snapshot.as_deref(),
- &self.config,
- &mut render::ShellRenderState {
- endpoints: &self.endpoints,
- active_endpoint_id: &self.active_endpoint_id,
- collapsed_endpoints: &self.collapsed_endpoints,
- collapsed_groups: &self.collapsed_groups,
- remote_collapsed_groups: &self.remote_collapsed_groups,
- workspace_scroll: &mut self.workspace_scroll,
- agent_scroll: &mut self.agent_scroll,
- tab_scroll: &mut self.tab_scroll,
- reveal_focused_workspace: &mut self.reveal_focused_workspace,
- reveal_focused_tab: &mut self.reveal_focused_tab,
- sidebar_collapsed: false,
- sidebar_section_split: self.sidebar_section_split,
- tab_drag_insert_index: None,
- selected_workspace_id: self
- .navigate_workspace_id
- .as_ref()
- .filter(|_| valid_navigation_target),
- reveal_navigation_workspace: &mut self.reveal_navigation_workspace,
- dragged_workspace_id: None,
- workspace_drop_indicator_row: None,
- },
- &mut self.hits,
- );
+ // A resize invalidates pane geometry, not the healthy Local workspace chrome.
+ let local_snapshot = self.snapshot.as_deref().filter(|_| {
+ self.endpoints.len() == 1
+ && !self.sidebar_collapsed
+ && layout.sidebar.width > 0
+ && self.endpoint_status(&self.active_endpoint_id)
+ == Some(ClientEndpointStatus::Online)
+ });
+ let mut render_state = render::ShellRenderState {
+ endpoints: &self.endpoints,
+ active_endpoint_id: &self.active_endpoint_id,
+ collapsed_endpoints: &self.collapsed_endpoints,
+ collapsed_groups: &self.collapsed_groups,
+ remote_collapsed_groups: &self.remote_collapsed_groups,
+ workspace_scroll: &mut self.workspace_scroll,
+ agent_scroll: &mut self.agent_scroll,
+ tab_scroll: &mut self.tab_scroll,
+ reveal_focused_workspace: &mut self.reveal_focused_workspace,
+ reveal_focused_tab: &mut self.reveal_focused_tab,
+ sidebar_collapsed: false,
+ sidebar_section_split: self.sidebar_section_split,
+ tab_drag_insert_index: None,
+ selected_workspace_id: self
+ .navigate_workspace_id
+ .as_ref()
+ .filter(|_| valid_navigation_target),
+ reveal_navigation_workspace: &mut self.reveal_navigation_workspace,
+ dragged_workspace_id: None,
+ workspace_drop_indicator_row: None,
+ };
+ if let Some(snapshot) = local_snapshot {
+ render::render_sidebar(
+ &mut buffer,
+ sidebar,
+ snapshot,
+ &self.config,
+ &mut render_state,
+ &mut self.hits,
+ );
+ } else {
+ super::endpoint_sidebar::render_expanded(
+ &mut buffer,
+ sidebar,
+ self.snapshot.as_deref(),
+ &self.config,
+ &mut render_state,
+ &mut self.hits,
+ );
+ }
if !self.config.mouse_capture {
self.hits = ShellHitMap::default();
}
@@ -87,14 +107,16 @@ impl ClientShellState {
} else {
Rect::new(0, 0, cols, 1)
};
- render::put_text(
- &mut buffer,
- message_area.x,
- message_area.y,
- message_area.width,
- &message,
- Style::default().fg(self.config.palette.overlay0),
- );
+ if local_snapshot.is_none() || self.endpoint_error.is_some() {
+ render::put_text(
+ &mut buffer,
+ message_area.x,
+ message_area.y,
+ message_area.width,
+ &message,
+ Style::default().fg(self.config.palette.overlay0),
+ );
+ }
render::render_mode_bar(
&mut buffer,
Rect::new(0, 0, cols, rows),
diff --git a/src/client/shell/tests/chrome_context.rs b/src/client/shell/tests/chrome_context.rs
index ff611a9b..5747bb97 100644
--- a/src/client/shell/tests/chrome_context.rs
+++ b/src/client/shell/tests/chrome_context.rs
@@ -99,6 +99,7 @@ fn client_owned_sidebar_dividers_resize_live() {
state.set_snapshot(Box::new(snapshot()));
state.set_pane_surface(surface());
state.compose(106, 30).expect("expanded sidebar");
+ assert!(state.hits.machines.is_empty());
let workspace_body = state.hits.workspace_body;
let needless_scroll =
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
@@ -128,15 +129,55 @@ fn client_owned_sidebar_dividers_resize_live() {
assert!(state.sidebar_width_manual);
assert!(resize.repaint);
assert!(resize.resize);
+ let waiting_frame = state.compose(106, 30).expect("waiting for resized surface");
+ let waiting_text: String = waiting_frame
+ .cells
+ .iter()
+ .map(|cell| cell.symbol.as_str())
+ .collect();
+ assert!(
+ waiting_text.contains(" spaces"),
+ "local sidebar must keep spaces while resizing: {waiting_text}"
+ );
+ assert!(!waiting_text.contains(" machines"));
+ assert!(!waiting_text.contains("Select a connected machine"));
+ assert!(!waiting_text.contains("LIVE"));
+ assert!(waiting_frame.cursor.is_none());
+ assert!(state.pane_surface.is_none());
+ assert!(state.hits.panes.is_empty());
+ assert!(state.hits.pane_splits.is_empty());
+ assert!(state.hits.machines.is_empty());
+ assert_eq!(state.hits.sidebar_divider.x, 31);
+ assert_eq!(state.hits.workspaces[0].workspace_id, "ws_1");
+
+ let next_resize =
+ state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
+ kind: MouseEventKind::Drag(MouseButton::Left),
+ column: 32,
+ row: width_divider.y + 2,
+ modifiers: KeyModifiers::empty(),
+ })]);
+ assert!(next_resize.resize);
+ state.compose(106, 30).expect("continued resize");
+ assert_eq!(state.hits.sidebar_divider.x, 32);
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
kind: MouseEventKind::Up(MouseButton::Left),
- column: 31,
+ column: 32,
row: width_divider.y + 2,
modifiers: KeyModifiers::empty(),
})]);
+ assert!(state.chrome_drag.is_none());
state.set_pane_surface(surface());
- state.compose(106, 30).expect("resized sidebar");
+ let recovered_frame = state.compose(106, 30).expect("resized sidebar");
+ let recovered_text: String = recovered_frame
+ .cells
+ .iter()
+ .map(|cell| cell.symbol.as_str())
+ .collect();
+ assert!(recovered_text.contains(" spaces"));
+ assert!(recovered_text.contains("LIVE"));
+ assert!(!state.hits.panes.is_empty());
let section_divider = state.hits.sidebar_section_divider;
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
kind: MouseEventKind::Down(MouseButton::Left),