diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-17 01:41:17 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-17 01:41:17 +0300 |
| commit | 3ecacfddae86d603bfd0d1a0c01602b1d34b1df3 (patch) | |
| tree | 277941c065295af2bd161c6be6fd7a2555c1f060 /src/app | |
| parent | a36da363f14639085bec91d7a378d6c2eeaa6c58 (diff) | |
feat: add direct terminal attach stream
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/input/mouse.rs | 4 | ||||
| -rw-r--r-- | src/app/input/navigate.rs | 5 | ||||
| -rw-r--r-- | src/app/input/terminal.rs | 45 | ||||
| -rw-r--r-- | src/app/mod.rs | 1 | ||||
| -rw-r--r-- | src/app/state.rs | 6 |
5 files changed, 37 insertions, 24 deletions
diff --git a/src/app/input/mouse.rs b/src/app/input/mouse.rs index 10ef9c18..827e37e3 100644 --- a/src/app/input/mouse.rs +++ b/src/app/input/mouse.rs @@ -1143,10 +1143,10 @@ impl AppState { } fn forward_pane_reported_wheel(&self, info: &PaneInfo, mouse: MouseEvent) -> bool { - let Some(ws) = self.active.and_then(|i| self.workspaces.get(i)) else { + let Some(ws_idx) = self.active else { return false; }; - let Some(rt) = ws.runtimes.get(&info.id) else { + let Some(rt) = self.runtime_for_pane_in_workspace(ws_idx, info.id) else { return false; }; if !rt diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs index 9fc11605..6445b6ab 100644 --- a/src/app/input/navigate.rs +++ b/src/app/input/navigate.rs @@ -261,8 +261,9 @@ impl App { let pane_id = ws .focused_pane_id() .ok_or_else(|| std::io::Error::other("no focused pane"))?; - let scrollback = ws - .focused_runtime() + let scrollback = self + .state + .runtime_for_pane_in_workspace(ws_idx, pane_id) .ok_or_else(|| std::io::Error::other("focused pane has no scrollback runtime"))? .recent_text(usize::MAX); diff --git a/src/app/input/terminal.rs b/src/app/input/terminal.rs index 3f0bff2c..90a1a0e2 100644 --- a/src/app/input/terminal.rs +++ b/src/app/input/terminal.rs @@ -508,16 +508,18 @@ mod tests { app.state.mode = Mode::Terminal; app.state.view.pane_infos = pane_infos; - let start_metrics = app.state.workspaces[0] - .runtime(pane_id) + let start_metrics = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("initial scroll metrics"); assert_eq!(start_metrics.offset_from_bottom, 0); app.handle_terminal_key_headless(TerminalKey::new(KeyCode::PageUp, KeyModifiers::empty())); - let end_metrics = app.state.workspaces[0] - .runtime(pane_id) + let end_metrics = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageUp"); assert_eq!( @@ -550,8 +552,9 @@ mod tests { app.state.view.pane_infos = pane_infos; app.handle_terminal_key_headless(TerminalKey::new(KeyCode::PageUp, KeyModifiers::empty())); - let after_up = app.state.workspaces[0] - .runtime(pane_id) + let after_up = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageUp"); assert!(after_up.offset_from_bottom > 0); @@ -560,8 +563,9 @@ mod tests { KeyCode::PageDown, KeyModifiers::empty(), )); - let after_down = app.state.workspaces[0] - .runtime(pane_id) + let after_down = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageDown"); assert_eq!(after_down.offset_from_bottom, 0); @@ -591,8 +595,9 @@ mod tests { app.state.view.pane_infos = pane_infos; app.handle_terminal_key_headless(TerminalKey::new(KeyCode::PageUp, KeyModifiers::empty())); - let after_press = app.state.workspaces[0] - .runtime(pane_id) + let after_press = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageUp press"); assert_eq!( @@ -605,8 +610,9 @@ mod tests { .with_kind(KeyEventKind::Release), ); - let after_release = app.state.workspaces[0] - .runtime(pane_id) + let after_release = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageUp release"); assert_eq!( @@ -640,8 +646,9 @@ mod tests { app.handle_terminal_key_headless(TerminalKey::new(KeyCode::PageUp, KeyModifiers::CONTROL)); - let metrics = app.state.workspaces[0] - .runtime(pane_id) + let metrics = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after modified PageUp"); assert_eq!(metrics.offset_from_bottom, 0); @@ -672,16 +679,18 @@ mod tests { app.state.mode = Mode::Terminal; app.state.view.pane_infos = pane_infos; - let start_metrics = app.state.workspaces[0] - .runtime(pane_id) + let start_metrics = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("initial scroll metrics"); assert_eq!(start_metrics.offset_from_bottom, 0); app.handle_terminal_key_headless(TerminalKey::new(KeyCode::PageUp, KeyModifiers::empty())); - let end_metrics = app.state.workspaces[0] - .runtime(pane_id) + let end_metrics = app + .state + .runtime_for_pane_in_workspace(0, pane_id) .and_then(crate::pane::PaneRuntime::scroll_metrics) .expect("scroll metrics after PageUp"); // Forwarded to pane, so test runtime doesn't process it — scroll stays at bottom. diff --git a/src/app/mod.rs b/src/app/mod.rs index b1fb9775..c5654db2 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -312,6 +312,7 @@ impl App { let mut state = AppState { terminals: std::collections::HashMap::new(), terminal_runtimes: std::collections::HashMap::new(), + direct_attach_resize_locks: std::collections::HashSet::new(), workspaces, active, selected, diff --git a/src/app/state.rs b/src/app/state.rs index daed47f0..ff5357b2 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -822,6 +822,8 @@ pub struct AppState { std::collections::HashMap<crate::terminal::TerminalId, crate::terminal::TerminalState>, pub terminal_runtimes: std::collections::HashMap<crate::terminal::TerminalId, crate::terminal::TerminalRuntime>, + /// Terminal ids whose size is currently owned by a direct attach client. + pub direct_attach_resize_locks: std::collections::HashSet<crate::terminal::TerminalId>, pub workspaces: Vec<Workspace>, pub active: Option<usize>, pub selected: usize, @@ -933,8 +935,7 @@ impl AppState { self.mode == Mode::Terminal && self .active - .and_then(|idx| self.workspaces.get(idx)) - .and_then(crate::workspace::Workspace::focused_runtime) + .and_then(|idx| self.focused_runtime_in_workspace(idx)) .and_then(crate::pane::PaneRuntime::input_state) .is_some_and(crate::pane::InputState::mouse_reporting_enabled) } @@ -1060,6 +1061,7 @@ impl AppState { Self { terminals: std::collections::HashMap::new(), terminal_runtimes: std::collections::HashMap::new(), + direct_attach_resize_locks: std::collections::HashSet::new(), workspaces: Vec::new(), active: None, selected: 0, |
