summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-06-15 17:07:40 +0200
committerGitHub <noreply@github.com>2023-06-15 17:07:40 +0200
commitbcbd940bf94cd76751af9b5fad64b716ce2cd3e6 (patch)
tree3bfed3792edd57f074c4aed9093c90bc6ed215fe
parent8d6f20cfd95927b604f9806a2ceb72727901ff1c (diff)
feat(plugins): plugin pane state events (#2545)
* feat(plugins): report pane state to plugins * refactor(plugins): rename some stuff * tests(plugins): adjust for new behavior * style(fmt): rustfmt
-rw-r--r--zellij-server/src/panes/active_panes.rs6
-rw-r--r--zellij-server/src/panes/floating_panes/mod.rs17
-rw-r--r--zellij-server/src/panes/plugin_pane.rs7
-rw-r--r--zellij-server/src/panes/terminal_pane.rs25
-rw-r--r--zellij-server/src/panes/tiled_panes/mod.rs17
-rw-r--r--zellij-server/src/screen.rs144
-rw-r--r--zellij-server/src/tab/mod.rs67
-rw-r--r--zellij-server/src/unit/screen_tests.rs42
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_rename_tab.snap426
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_undo_rename_tab.snap479
-rw-r--r--zellij-tile/src/lib.rs2
-rw-r--r--zellij-utils/src/data.rs33
12 files changed, 313 insertions, 952 deletions
diff --git a/zellij-server/src/panes/active_panes.rs b/zellij-server/src/panes/active_panes.rs
index c726bafe1..039c71c61 100644
--- a/zellij-server/src/panes/active_panes.rs
+++ b/zellij-server/src/panes/active_panes.rs
@@ -98,4 +98,10 @@ impl ActivePanes {
}
}
}
+ pub fn pane_id_is_focused(&self, pane_id: &PaneId) -> bool {
+ self.active_panes
+ .values()
+ .find(|p_id| **p_id == *pane_id)
+ .is_some()
+ }
}
diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs
index 071f6e7c2..98c6046bf 100644
--- a/zellij-server/src/panes/floating_panes/mod.rs
+++ b/zellij-server/src/panes/floating_panes/mod.rs
@@ -1,11 +1,11 @@
mod floating_pane_grid;
use zellij_utils::{
- data::{Direction, ResizeStrategy},
+ data::{Direction, PaneInfo, ResizeStrategy},
position::Position,
};
use crate::resize_pty;
-use crate::tab::Pane;
+use crate::tab::{pane_info_for_pane, Pane};
use floating_pane_grid::FloatingPaneGrid;
use crate::{
@@ -885,4 +885,17 @@ impl FloatingPanes {
Err(anyhow!("Pane not found"))
}
}
+ pub fn pane_info(&self) -> Vec<PaneInfo> {
+ let mut pane_infos = vec![];
+ for (pane_id, pane) in self.panes.iter() {
+ let mut pane_info_for_pane = pane_info_for_pane(pane_id, pane);
+ let is_focused = self.active_panes.pane_id_is_focused(pane_id);
+ pane_info_for_pane.is_floating = true;
+ pane_info_for_pane.is_suppressed = false;
+ pane_info_for_pane.is_focused = is_focused;
+ pane_info_for_pane.is_fullscreen = false;
+ pane_infos.push(pane_info_for_pane);
+ }
+ pane_infos
+ }
}
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index d1d595f23..557769f02 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -564,6 +564,13 @@ impl Pane for PluginPane {
self.loading_indication.to_string().as_bytes().to_vec(),
);
}
+ fn current_title(&self) -> String {
+ if self.pane_name.is_empty() {
+ self.pane_title.to_owned()
+ } else {
+ self.pane_name.to_owned()
+ }
+ }
}
impl PluginPane {
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index c9e125b8d..df74afd69 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -720,6 +720,31 @@ impl Pane for TerminalPane {
fn set_title(&mut self, title: String) {
self.pane_title = title;
}
+ fn current_title(&self) -> String {
+ if self.pane_name.is_empty() {
+ self.grid
+ .title
+ .as_deref()
+ .unwrap_or(&self.pane_title)
+ .into()
+ } else {
+ self.pane_name.to_owned()
+ }
+ }
+ fn exit_status(&self) -> Option<i32> {
+ self.is_held
+ .as_ref()
+ .and_then(|(exit_status, _, _)| *exit_status)
+ }
+ fn is_held(&self) -> bool {
+ self.is_held.is_some()
+ }
+ fn exited(&self) -> bool {
+ match self.is_held {
+ Some((_, is_first_run, _)) => !is_first_run,
+ None => false,
+ }
+ }
}
impl TerminalPane {
diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs
index 3734214af..424053405 100644
--- a/zellij-server/src/panes/tiled_panes/mod.rs
+++ b/zellij-server/src/panes/tiled_panes/mod.rs
@@ -10,7 +10,7 @@ use crate::{
output::Output,
panes::{ActivePanes, PaneId},
plugins::PluginInstruction,
- tab::{Pane, MIN_TERMINAL_HEIGHT, MIN_TERMINAL_WIDTH},
+ tab::{pane_info_for_pane, Pane, MIN_TERMINAL_HEIGHT, MIN_TERMINAL_WIDTH},
thread_bus::ThreadSenders,
ui::boundaries::Boundaries,
ui::pane_contents_and_ui::PaneContentsAndUi,
@@ -18,7 +18,7 @@ use crate::{
};
use stacked_panes::StackedPanes;
use zellij_utils::{
- data::{Direction, ModeInfo, ResizeStrategy, Style},
+ data::{Direction, ModeInfo, PaneInfo, ResizeStrategy, Style},
errors::prelude::*,
input::{
command::RunCommand,
@@ -1709,6 +1709,19 @@ impl TiledPanes {
.find(|(_id, s_p)| s_p.invoked_with() == &run)
.map(|(id, _)| *id)
}
+ pub fn pane_info(&self) -> Vec<PaneInfo> {
+ let mut pane_infos = vec![];
+ for (pane_id, pane) in self.panes.iter() {
+ let mut pane_info_for_pane = pane_info_for_pane(pane_id, pane);
+ let is_focused = self.active_panes.pane_id_is_focused(pane_id);
+ pane_info_for_pane.is_floating = false;
+ pane_info_for_pane.is_suppressed = false;
+ pane_info_for_pane.is_focused = is_focused;
+ pane_info_for_pane.is_fullscreen = is_focused && self.fullscreen_is_active();
+ pane_infos.push(pane_info_for_pane);
+ }
+ pane_infos
+ }
}
#[allow(clippy::borrowed_box)]
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 811777481..ae62be379 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -6,7 +6,7 @@ use std::path::PathBuf;
use std::rc::Rc;
use std::str;
-use zellij_utils::data::{Direction, Resize, ResizeStrategy};
+use zellij_utils::data::{Direction, PaneManifest, Resize, ResizeStrategy};
use zellij_utils::errors::prelude::*;
use zellij_utils::input::command::RunCommand;
use zellij_utils::input::options::Clipboard;
@@ -714,7 +714,8 @@ impl Screen {
.non_fatal();
}
- self.update_tabs().with_context(err_context)?;
+ self.report_tab_state().with_context(err_context)?;
+ self.report_pane_state().with_context(err_context)?;
return self.render().with_context(err_context);
},
Err(err) => Err::<(), _>(err).with_context(err_context).non_fatal(),
@@ -843,7 +844,8 @@ impl Screen {
t.position -= 1;
}
}
- self.update_tabs().with_context(err_context)?;
+ self.report_tab_state().with_context(err_context)?;
+ self.report_pane_state().with_context(err_context)?;
self.render().with_context(err_context)
}
}
@@ -880,6 +882,7 @@ impl Screen {
.with_context(err_context)?;
tab.set_force_render();
}
+ self.report_pane_state().with_context(err_context)?;
self.render().with_context(err_context)
}
@@ -1145,9 +1148,10 @@ impl Screen {
self.add_client(client_id).with_context(err_context)?;
}
- self.update_tabs()
+ self.report_tab_state()
.and_then(|_| self.render())
- .with_context(err_context)
+ .with_context(err_context)?;
+ self.report_pane_state().with_context(err_context)
}
pub fn add_client(&mut self, client_id: ClientId) -> Result<()> {
@@ -1198,10 +1202,10 @@ impl Screen {
self.tab_history.remove(&client_id);
}
self.connected_clients.borrow_mut().remove(&client_id);
- self.update_tabs().with_context(err_context)
+ self.report_tab_state().with_context(err_context)
}
- pub fn update_tabs(&self) -> Result<()> {
+ pub fn report_tab_state(&self) -> Result<()> {
let mut plugin_updates = vec![];
for (client_id, active_tab_index) in self.active_tab_indices.iter() {
let mut tab_data = vec![];
@@ -1240,6 +1244,21 @@ impl Screen {
.context("failed to update tabs")?;
Ok(())
}
+ fn report_pane_state(&self) -> Result<()> {
+ let mut pane_manifest = PaneManifest::default();
+ for tab in self.tabs.values() {
+ pane_manifest.panes.insert(tab.position, tab.pane_infos());
+ }
+ self.bus
+ .senders
+ .send_to_plugin(PluginInstruction::Update(vec![(
+ None,
+ None,
+ Event::PaneUpdate(pane_manifest),
+ )]))
+ .context("failed to update tabs")?;
+ Ok(())
+ }
pub fn update_active_tab_name(&mut self, buf: Vec<u8>, client_id: ClientId) -> Result<()> {
let err_context =
@@ -1273,7 +1292,7 @@ impl Screen {
}
},
}
- self.update_tabs().with_context(err_context)
+ self.report_tab_state().with_context(err_context)
},
Err(err) => {
Err::<(), _>(err).with_context(err_context).non_fatal();
@@ -1298,7 +1317,7 @@ impl Screen {
Ok(active_tab) => {
if active_tab.name != active_tab.prev_name {
active_tab.name = active_tab.prev_name.clone();
- self.update_tabs()
+ self.report_tab_state()
.context("failed to undo renaming of active tab")?;
}
},
@@ -1418,6 +1437,7 @@ impl Screen {
Err(err) => Err::<(), _>(err).with_context(err_context).non_fatal(),
};
}
+ self.report_pane_state().with_context(err_context)?;
Ok(())
}
pub fn move_focus_right_or_next_tab(&mut self, client_id: ClientId) -> Result<()> {
@@ -1452,6 +1472,7 @@ impl Screen {
Err(err) => Err::<(), _>(err).with_context(err_context).non_fatal(),
};
}
+ self.report_pane_state().with_context(err_context)?;
Ok(())
}
pub fn toggle_tab(&mut self, client_id: ClientId) -> Result<()> {
@@ -1464,7 +1485,8 @@ impl Screen {
.context("failed to toggle tabs")?;
};
- self.update_tabs().context("failed to toggle tabs")?;
+ self.report_tab_state().context("failed to toggle tabs")?;
+ self.report_pane_state().context("failed to toggle tabs")?;
self.render()
}
@@ -1492,6 +1514,7 @@ impl Screen {
.with_context(err_context)?
.focus_pane_with_id(plugin_pane_id, should_float, client_id)
.context("failed to focus plugin pane")?;
+ self.report_pane_state().with_context(err_context)?;
Ok(true)
},
None => Ok(false),
@@ -1631,7 +1654,8 @@ pub(crate) fn screen_thread_main(
},
};
screen.unblock_input()?;
- screen.update_tabs()?;
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
screen.render()?;
},
@@ -1639,7 +1663,8 @@ pub(crate) fn screen_thread_main(
active_tab!(screen, client_id, |tab: &mut Tab| tab
.suppress_active_pane(pid, client_id), ?);
screen.unblock_input()?;
- screen.update_tabs()?;
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
screen.render()?;
},
@@ -1647,7 +1672,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| tab
.toggle_pane_embed_or_floating(client_id), ?);
screen.unblock_input()?;
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_pane_state()?;
screen.render()?;
},
@@ -1655,7 +1681,8 @@ pub(crate) fn screen_thread_main(
active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| tab
.toggle_floating_panes(Some(client_id), default_shell), ?);
screen.unblock_input()?;
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_pane_state()?;
screen.render()?;
},
@@ -1685,7 +1712,8 @@ pub(crate) fn screen_thread_main(
);
}
screen.unblock_input()?;
- screen.update_tabs()?;
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
screen.render()?;
},
ScreenInstruction::VerticalSplit(
@@ -1714,11 +1742,12 @@ pub(crate) fn screen_thread_main(
);
}
screen.unblock_input()?;
- screen.update_tabs()?;
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
screen.render()?;
},
ScreenInstruction::WriteCharacter(bytes, client_id) => {
- let mut should_update_tabs = false;
+ let mut state_changed = false;
active_tab_and_connected_client_id!(
screen,
client_id,
@@ -1728,14 +1757,15 @@ pub(crate) fn screen_thread_main(
false => tab.write_to_active_terminal(bytes, client_id),
};
if let Ok(true) = write_result {
- should_update_tabs = true;
+ state_changed = true;
}
write_result
},
?
);
- if should_update_tabs {
- screen.update_tabs()?;
+ if state_changed {
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
}
},
ScreenInstruction::Resize(client_id, strategy) => {
@@ -1747,7 +1777,8 @@ pub(crate) fn screen_thread_main(
);
screen.unblock_input()?;
screen.render()?;
- screen.update_tabs()?; // TODO: no every time
+ screen.report_tab_state()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::SwitchFocus(client_id) => {
active_tab_and_connected_client_id!(
@@ -1757,6 +1788,7 @@ pub(crate) fn screen_thread_main(
);
screen.unblock_input()?;
screen.render()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::FocusNextPane(client_id) => {
active_tab_and_connected_client_id!(
@@ -1775,6 +1807,7 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusLeft(client_id) => {
active_tab_and_connected_client_id!(
@@ -1785,11 +1818,13 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id) => {
screen.move_focus_left_or_previous_tab(client_id)?;
screen.unblock_input()?;
screen.render()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusDown(client_id) => {
active_tab_and_connected_client_id!(
@@ -1800,6 +1835,7 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusRight(client_id) => {
active_tab_and_connected_client_id!(
@@ -1810,11 +1846,13 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusRightOrNextTab(client_id) => {
screen.move_focus_right_or_next_tab(client_id)?;
screen.unblock_input()?;
screen.render()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MoveFocusUp(client_id) => {
active_tab_and_connected_client_id!(
@@ -1825,6 +1863,7 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::ClearScreen(client_id) => {
active_tab_and_connected_client_id!(
@@ -1860,6 +1899,7 @@ pub(crate) fn screen_thread_main(
?
);
screen.render()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::ScrollUp(client_id) => {
active_tab_and_connected_client_id!(
@@ -1876,9 +1916,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MovePaneBackwards(client_id) => {
active_tab_and_connected_client_id!(
@@ -1886,9 +1927,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_backwards(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MovePaneDown(client_id) => {
active_tab_and_connected_client_id!(
@@ -1896,9 +1938,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_down(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MovePaneUp(client_id) => {
active_tab_and_connected_client_id!(
@@ -1906,9 +1949,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_up(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MovePaneRight(client_id) => {
active_tab_and_connected_client_id!(
@@ -1916,9 +1960,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_right(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::MovePaneLeft(client_id) => {
active_tab_and_connected_client_id!(
@@ -1926,9 +1971,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.move_active_pane_left(client_id)
);
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::ScrollUpAt(point, client_id) => {
active_tab_and_connected_client_id!(
@@ -2035,9 +2081,10 @@ pub(crate) fn screen_thread_main(
client_id,
|tab: &mut Tab, client_id: ClientId| tab.close_focused_pane(client_id), ?
);
- screen.update_tabs()?;
+ screen.report_tab_state()?;
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::SetSelectable(id, selectable, tab_index) => {
screen.get_indexed_tab_mut(tab_index).map_or_else(
@@ -2052,6 +2099,7 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::ClosePane(id, client_id) => {
match client_id {
@@ -2071,8 +2119,9 @@ pub(crate) fn screen_thread_main(
}
},
}
- screen.update_tabs()?;
+ screen.report_tab_state()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::HoldPane(id, exit_status, run_command, tab_index, client_id) => {
let is_first_run = false;
@@ -2101,8 +2150,9 @@ pub(crate) fn screen_thread_main(
}
},
}
- screen.update_tabs()?;
+ screen.report_tab_state()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::UpdatePaneName(c, client_id) => {
active_tab_and_connected_client_id!(
@@ -2112,6 +2162,7 @@ pub(crate) fn screen_thread_main(
);
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::UndoRenamePane(client_id) => {
active_tab_and_connected_client_id!(
@@ -2129,9 +2180,10 @@ pub(crate) fn screen_thread_main(
|tab: &mut Tab, client_id: ClientId| tab
.toggle_active_pane_fullscreen(client_id)
);
- screen.update_tabs()?;
+ screen.report_tab_state()?;
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::TogglePaneFrames => {
screen.draw_pane_frames = !screen.draw_pane_frames;
@@ -2140,6 +2192,7 @@ pub(crate) fn screen_thread_main(
}
screen.render()?;
screen.unblock_input()?;
+ screen.report_pane_state()?;
},
ScreenInstruction::SwitchTabNext(client_id) => {
screen.switch_tab_next(None, client_id)?;
@@ -2287,7 +2340,7 @@ pub(crate) fn screen_thread_main(
},
ScreenInstruction::TerminalResize(new_size) => {
screen.resize_to_screen(new_size)?;
- screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins
+ screen.report_tab_state()?; // update tabs so that the ui indication will be send to the plugins
screen.render()?;
},
ScreenInstruc