summaryrefslogtreecommitdiffstats
path: root/zellij-server/src/tab
diff options
context:
space:
mode:
Diffstat (limited to 'zellij-server/src/tab')
-rw-r--r--zellij-server/src/tab/mod.rs134
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_tiled_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_tiled_pane_is_suppressed.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane_embed_it_and_close_it.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_tiled_pane.snap26
-rw-r--r--zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_tiled_pane_float_it_and_close.snap26
-rw-r--r--zellij-server/src/tab/unit/tab_integration_tests.rs213
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs3
11 files changed, 550 insertions, 8 deletions
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index cdd968c3e..5c3d04341 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -5,6 +5,8 @@ mod clipboard;
mod copy_command;
use copy_command::CopyCommand;
+use std::env::temp_dir;
+use uuid::Uuid;
use zellij_tile::prelude::Style;
use zellij_utils::position::{Column, Line};
use zellij_utils::{position::Position, serde, zellij_tile};
@@ -70,6 +72,7 @@ pub(crate) struct Tab {
pub name: String,
tiled_panes: TiledPanes,
floating_panes: FloatingPanes,
+ suppressed_panes: HashMap<PaneId, Box<dyn Pane>>,
max_panes: Option<usize>,
viewport: Rc<RefCell<Viewport>>, // includes all non-UI panes
display_area: Rc<RefCell<Size>>, // includes all panes (including eg. the status bar and tab bar in the default layout)
@@ -268,6 +271,9 @@ pub trait Pane {
fn borderless(&self) -> bool;
fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {}
fn mouse_mode(&self) -> bool;
+ fn get_line_number(&self) -> Option<usize> {
+ None
+ }
}
impl Tab {
@@ -339,6 +345,7 @@ impl Tab {
position,
tiled_panes,
floating_panes,
+ suppressed_panes: HashMap::new(),
name,
max_panes,
viewport,
@@ -577,7 +584,8 @@ impl Tab {
if let Some(focused_floating_pane_id) = self.floating_panes.active_pane_id(client_id) {
if self.tiled_panes.has_room_for_new_pane() {
// this unwrap is safe because floating panes should not be visible if there are no floating panes
- let floating_pane_to_embed = self.close_pane(focused_floating_pane_id).unwrap();
+ let floating_pane_to_embed =
+ self.close_pane(focused_floating_pane_id, true).unwrap();
self.tiled_panes
.insert_pane(focused_floating_pane_id, floating_pane_to_embed);
self.should_clear_display_before_rendering = true;
@@ -592,7 +600,7 @@ impl Tab {
// don't close the only pane on screen...
return;
}
- if let Some(mut embedded_pane_to_float) = self.close_pane(focused_pane_id) {
+ if let Some(mut embedded_pane_to_float) = self.close_pane(focused_pane_id, true) {
embedded_pane_to_float.set_geom(new_pane_geom);
resize_pty!(embedded_pane_to_float, self.os_api);
embedded_pane_to_float.set_active_at(Instant::now());
@@ -691,6 +699,47 @@ impl Tab {
}
}
}
+ pub fn suppress_active_pane(&mut self, pid: PaneId, client_id: ClientId) {
+ // this method creates a new pane from pid and replaces it with the active pane
+ // the active pane is then suppressed (hidden and not rendered) until the current
+ // created pane is closed, in which case it will be replaced back by it
+ match pid {
+ PaneId::Terminal(pid) => {
+ let next_terminal_position = self.get_next_terminal_position(); // TODO: this is not accurate in this case
+ let new_pane = TerminalPane::new(
+ pid,
+ PaneGeom::default(), // the initial size will be set later
+ self.style,
+ next_terminal_position,
+ String::new(),
+ self.link_handler.clone(),
+ self.character_cell_size.clone(),
+ self.terminal_emulator_colors.clone(),
+ );
+ let replaced_pane = if self.floating_panes.panes_are_visible() {
+ self.floating_panes
+ .replace_active_pane(Box::new(new_pane), client_id)
+ } else {
+ self.tiled_panes
+ .replace_active_pane(Box::new(new_pane), client_id)
+ };
+ match replaced_pane {
+ Some(replaced_pane) => {
+ self.suppressed_panes
+ .insert(PaneId::Terminal(pid), replaced_pane);
+ let current_active_pane = self.get_active_pane(client_id).unwrap(); // this will be the newly replaced pane we just created
+ resize_pty!(current_active_pane, self.os_api);
+ }
+ None => {
+ log::error!("Could not find editor pane to replace - is no pane focused?")
+ }
+ }
+ }
+ PaneId::Plugin(_pid) => {
+ // TBD, currently unsupported
+ }
+ }
+ }
pub fn horizontal_split(&mut self, pid: PaneId, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
return;
@@ -792,12 +841,22 @@ impl Tab {
pub fn has_terminal_pid(&self, pid: RawFd) -> bool {
self.tiled_panes.panes_contain(&PaneId::Terminal(pid))
|| self.floating_panes.panes_contain(&PaneId::Terminal(pid))
+ || self
+ .suppressed_panes
+ .values()
+ .find(|s_p| s_p.pid() == PaneId::Terminal(pid))
+ .is_some()
}
pub fn handle_pty_bytes(&mut self, pid: RawFd, bytes: VteBytes) {
if let Some(terminal_output) = self
.tiled_panes
.get_pane_mut(PaneId::Terminal(pid))
.or_else(|| self.floating_panes.get_pane_mut(PaneId::Terminal(pid)))
+ .or_else(|| {
+ self.suppressed_panes
+ .values_mut()
+ .find(|s_p| s_p.pid() == PaneId::Terminal(pid))
+ })
{
// If the pane is scrolled buffer the vte events
if terminal_output.is_scrolled() {
@@ -827,6 +886,11 @@ impl Tab {
.tiled_panes
.get_pane_mut(PaneId::Terminal(pid))
.or_else(|| self.floating_panes.get_pane_mut(PaneId::Terminal(pid)))
+ .or_else(|| {
+ self.suppressed_panes
+ .values_mut()
+ .find(|s_p| s_p.pid() == PaneId::Terminal(pid))
+ })
{
terminal_output.handle_pty_bytes(bytes);
let messages_to_pty = terminal_output.drain_messages_to_pty();
@@ -1070,6 +1134,7 @@ impl Tab {
}
pub fn resize_whole_tab(&mut self, new_screen_size: Size) {
self.floating_panes.resize(new_screen_size);
+ self.floating_panes.resize_pty_all_panes(&mut self.os_api); // we need to do this explicitly because floating_panes.resize does not do this
self.tiled_panes.resize(new_screen_size);
self.should_clear_display_before_rendering = true;
}
@@ -1308,7 +1373,7 @@ impl Tab {
self.senders
.send_to_pty(PtyInstruction::ClosePane(pid))
.unwrap();
- self.close_pane(pid);
+ self.close_pane(pid, false);
}
}
}
@@ -1345,7 +1410,20 @@ impl Tab {
}
}
}
- pub fn close_pane(&mut self, id: PaneId) -> Option<Box<dyn Pane>> {
+ pub fn close_pane(
+ &mut self,
+ id: PaneId,
+ ignore_suppressed_panes: bool,
+ ) -> Option<Box<dyn Pane>> {
+ // we need to ignore suppressed panes when we toggle a pane to be floating/embedded(tiled)
+ // this is because in that case, while we do use this logic, we're not actually closing the
+ // pane, we're moving it
+ //
+ // TODO: separate the "close_pane" logic and the "move_pane_somewhere_else" logic, they're
+ // overloaded here and that's not great
+ if !ignore_suppressed_panes && self.suppressed_panes.contains_key(&id) {
+ return self.replace_pane_with_suppressed_pane(id);
+ }
if self.floating_panes.panes_contain(&id) {
let closed_pane = self.floating_panes.remove_pane(id);
self.floating_panes.move_clients_out_of_pane(id);
@@ -1365,10 +1443,38 @@ impl Tab {
closed_pane
}
}
+ pub fn replace_pane_with_suppressed_pane(&mut self, pane_id: PaneId) -> Option<Box<dyn Pane>> {
+ self.suppressed_panes
+ .remove(&pane_id)
+ .and_then(|suppressed_pane| {
+ let suppressed_pane_id = suppressed_pane.pid();
+ let replaced_pane = if self.are_floating_panes_visible() {
+ self.floating_panes.replace_pane(pane_id, suppressed_pane)
+ } else {
+ self.tiled_panes.replace_pane(pane_id, suppressed_pane)
+ };
+ if let Some(suppressed_pane) = self
+ .floating_panes
+ .get_pane(suppressed_pane_id)
+ .or_else(|| self.tiled_panes.get_pane(suppressed_pane_id))
+ {
+ // You may be thinking: why aren't we using the original "suppressed_pane" here,
+ // isn't it the same one?
+ //
+ // Yes, you are right! However, we moved it into its correct environment above
+ // (either floating_panes or tiled_panes) where it received a new geometry based on
+ // the pane there we replaced. Now, we need to update its pty about its new size.
+ // We couldn't do that before, and we can't use the original moved item now - so we
+ // need to refetch it
+ resize_pty!(suppressed_pane, self.os_api);
+ }
+ replaced_pane
+ })
+ }
pub fn close_focused_pane(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() {
if let Some(active_floating_pane_id) = self.floating_panes.active_pane_id(client_id) {
- self.close_pane(active_floating_pane_id);
+ self.close_pane(active_floating_pane_id, false);
self.senders
.send_to_pty(PtyInstruction::ClosePane(active_floating_pane_id))
.unwrap();
@@ -1376,7 +1482,7 @@ impl Tab {
}
}
if let Some(active_pane_id) = self.tiled_panes.get_active_pane_id(client_id) {
- self.close_pane(active_pane_id);
+ self.close_pane(active_pane_id, false);
self.senders
.send_to_pty(PtyInstruction::ClosePane(active_pane_id))
.unwrap();
@@ -1388,6 +1494,22 @@ impl Tab {
self.os_api.write_to_file(dump, file);
}
}
+ pub fn edit_scrollback(&mut self, client_id: ClientId) {
+ let mut file = temp_dir();
+ file.push(format!("{}.dump", Uuid::new_v4()));
+ self.dump_active_terminal_screen(Some(String::from(file.to_string_lossy())), client_id);
+ // let line_number = self.get_active_pane(client_id).map(|a_t| a_t.get_line_number());
+ let line_number = self
+ .get_active_pane(client_id)
+ .and_then(|a_t| a_t.get_line_number());
+ self.senders
+ .send_to_pty(PtyInstruction::OpenInPlaceEditor(
+ file,
+ line_number,
+ client_id,
+ ))
+ .unwrap();
+ }
pub fn scroll_active_terminal_up(&mut self, client_id: ClientId) {
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
active_pane.scroll_up(1, client_id);
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap
new file mode 100644
index 000000000..91910115e
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_floating_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1352
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #2 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ │ │
+08 (C): │ │ │ │
+09 (C): │ │I am the original pane │ │
+10 (C): │ │ │ │
+11 (C): │ │ │ │
+12 (C): │ │ │ │
+13 (C): │ │ │ │
+14 (C): │ └──────────────────────────────────────────────────────────┘ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_tiled_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_tiled_pane.snap
new file mode 100644
index 000000000..f2f195162
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__close_suppressing_tiled_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1318
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │I am the original pane │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap
new file mode 100644
index 000000000..a339044fa
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_floting_pane_is_suppressed.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1474
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ────────────────────┌ Pane #3 ─────────────────────────────────────────────────┐─────────┐
+01 (C): │ │ │ │
+02 (C): │ │ │ │
+03 (C): │ │ │ │
+04 (C): │ │I am an editor pane │ │
+05 (C): │ │ │ │
+06 (C): │ │ │ │
+07 (C): │ │ │ │
+08 (C): │ │ │ │
+09 (C): └─────────────────────────────└──────────────────────────────────────────────────────────┘─────────┘
+10 (C):
+11 (C):
+12 (C):
+13 (C):
+14 (C):
+15 (C):
+16 (C):
+17 (C):
+18 (C):
+19 (C):
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_tiled_pane_is_suppressed.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_tiled_pane_is_suppressed.snap
new file mode 100644
index 000000000..8d17504f6
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__resize_whole_tab_while_tiled_pane_is_suppressed.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1444
+expression: snapshot
+---
+00 (C): ┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │I am an editor pane │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────┘
+10 (C):
+11 (C):
+12 (C):
+13 (C):
+14 (C):
+15 (C):
+16 (C):
+17 (C):
+18 (C):
+19 (C):
+
diff --git a/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap
new file mode 100644
index 000000000..2b7d6a211
--- /dev/null
+++ b/zellij-server/src/tab/unit/snapshots/zellij_server__tab__tab_integration_tests__suppress_floating_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/tab/./unit/tab_integration_tests.rs
+assertion_line: 1288
+expression: snapshot
+---
+00 (C): ┌ Pane #1 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
+01 (C): │ │
+02 (C): │ │
+03 (C): │ │
+04 (C): │ │
+05 (C): │ ┌ Pane #3 ─────────────────────────────────────────────────┐ │
+06 (C): │ │ │ │
+07 (C): │ │ │ │
+08 (C): │ │ │ │
+09 (C): │ │I am an editor pane │ │
+10 (C): │ │ │ │
+11 (C): │ │ │ │
+12 (C): │ │ │ │
+13 (C): │ │ │ │
+14 (C): │ └──────────────────────────────────────────────────────────┘ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): └───────────────────────────────────────────────────────────────────────