Skip to content

Commit

Permalink
feat(plugins): API to change floating pane coordinates (#3958)
Browse files Browse the repository at this point in the history
* basic functionality through the cli

* added to plugin api

* add display area and viewport size to TabInfo

* fix tests and add new one

* some cleanups

* refactor: extract pane_id parsing logic

* style(fmt): rustfmt
  • Loading branch information
imsnif authored Jan 30, 2025
1 parent 382a075 commit c4cb9d3
Show file tree
Hide file tree
Showing 26 changed files with 464 additions and 44 deletions.
23 changes: 22 additions & 1 deletion zellij-server/src/panes/floating_panes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub mod floating_pane_grid;
use zellij_utils::{
data::{Direction, PaneInfo, ResizeStrategy},
data::{Direction, FloatingPaneCoordinates, PaneInfo, ResizeStrategy},
position::Position,
};

Expand Down Expand Up @@ -728,6 +728,27 @@ impl FloatingPanes {
let _ = self.set_pane_frames();
}
}
pub fn change_pane_coordinates(
&mut self,
pane_id: PaneId,
new_coordinates: FloatingPaneCoordinates,
) -> Result<()> {
let err_context = || format!("Failed to change_pane_coordinates");

{
let viewport = { self.viewport.borrow().clone() };
let pane = self.get_pane_mut(pane_id).with_context(err_context)?;
let mut pane_geom = pane.position_and_size();
if let Some(pinned) = new_coordinates.pinned.as_ref() {
pane.set_pinned(*pinned);
}
pane_geom.adjust_coordinates(new_coordinates, viewport);
pane.set_geom(pane_geom);
pane.set_should_render(true);
}
let _ = self.set_pane_frames();
Ok(())
}
pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) {
let active_panes: Vec<(ClientId, PaneId)> = self
.active_panes
Expand Down
21 changes: 21 additions & 0 deletions zellij-server/src/plugins/zellij_exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,15 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
PluginCommand::StackPanes(pane_ids) => {
stack_panes(env, pane_ids.into_iter().map(|p_id| p_id.into()).collect())
},
PluginCommand::ChangeFloatingPanesCoordinates(pane_ids_and_coordinates) => {
change_floating_panes_coordinates(
env,
pane_ids_and_coordinates
.into_iter()
.map(|(p_id, coordinates)| (p_id.into(), coordinates))
.collect(),
)
},
},
(PermissionStatus::Denied, permission) => {
log::error!(
Expand Down Expand Up @@ -1530,6 +1539,17 @@ fn stack_panes(env: &PluginEnv, pane_ids: Vec<PaneId>) {
.send_to_screen(ScreenInstruction::StackPanes(pane_ids));
}

fn change_floating_panes_coordinates(
env: &PluginEnv,
pane_ids_and_coordinates: Vec<(PaneId, FloatingPaneCoordinates)>,
) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ChangeFloatingPanesCoordinates(
pane_ids_and_coordinates,
));
}

fn scan_host_folder(env: &PluginEnv, folder_to_scan: PathBuf) {
if !folder_to_scan.starts_with("/host") {
log::error!(
Expand Down Expand Up @@ -1950,6 +1970,7 @@ fn check_command_permission(
| PluginCommand::LoadNewPlugin { .. }
| PluginCommand::SetFloatingPanePinned(..)
| PluginCommand::StackPanes(..)
| PluginCommand::ChangeFloatingPanesCoordinates(..)
| PluginCommand::KillSessions(..) => PermissionType::ChangeApplicationState,
PluginCommand::UnblockCliPipeInput(..)
| PluginCommand::BlockCliPipeInput(..)
Expand Down
8 changes: 8 additions & 0 deletions zellij-server/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,14 @@ pub(crate) fn route_action(
))
.with_context(err_context)?;
},
Action::ChangeFloatingPaneCoordinates(pane_id, coordinates) => {
senders
.send_to_screen(ScreenInstruction::ChangeFloatingPanesCoordinates(vec![(
pane_id.into(),
coordinates,
)]))
.with_context(err_context)?;
},
}
Ok(should_break)
}
Expand Down
35 changes: 35 additions & 0 deletions zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ pub enum ScreenInstruction {
TogglePanePinned(ClientId),
SetFloatingPanePinned(PaneId, bool),
StackPanes(Vec<PaneId>),
ChangeFloatingPanesCoordinates(Vec<(PaneId, FloatingPaneCoordinates)>),
}

impl From<&ScreenInstruction> for ScreenContext {
Expand Down Expand Up @@ -609,6 +610,9 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::TogglePanePinned(..) => ScreenContext::TogglePanePinned,
ScreenInstruction::SetFloatingPanePinned(..) => ScreenContext::SetFloatingPanePinned,
ScreenInstruction::StackPanes(..) => ScreenContext::StackPanes,
ScreenInstruction::ChangeFloatingPanesCoordinates(..) => {
ScreenContext::ChangeFloatingPanesCoordinates
},
}
}
}
Expand Down Expand Up @@ -1528,6 +1532,8 @@ impl Screen {
.copied()
.collect();
let (active_swap_layout_name, is_swap_layout_dirty) = tab.swap_layout_info();
let tab_viewport = tab.get_viewport();
let tab_display_area = tab.get_display_area();
let tab_info_for_screen = TabInfo {
position: tab.position,
name: tab.name.clone(),
Expand All @@ -1539,6 +1545,10 @@ impl Screen {
other_focused_clients: all_focused_clients,
active_swap_layout_name,
is_swap_layout_dirty,
viewport_rows: tab_viewport.rows,
viewport_columns: tab_viewport.cols,
display_area_rows: tab_display_area.rows,
display_area_columns: tab_display_area.cols,
};
tab_infos_for_screen_state.insert(tab.position, tab_info_for_screen);
}
Expand All @@ -1558,6 +1568,8 @@ impl Screen {
.collect()
};
let (active_swap_layout_name, is_swap_layout_dirty) = tab.swap_layout_info();
let tab_viewport = tab.get_viewport();
let tab_display_area = tab.get_display_area();
let tab_info_for_plugins = TabInfo {
position: tab.position,
name: tab.name.clone(),
Expand All @@ -1569,6 +1581,10 @@ impl Screen {
other_focused_clients,
active_swap_layout_name,
is_swap_layout_dirty,
viewport_rows: tab_viewport.rows,
viewport_columns: tab_viewport.cols,
display_area_rows: tab_display_area.rows,
display_area_columns: tab_display_area.cols,
};
plugin_tab_updates.push(tab_info_for_plugins);
}
Expand Down Expand Up @@ -2573,6 +2589,20 @@ impl Screen {
.get_mut(&root_tab_id)
.map(|t| t.stack_panes(root_pane_id, panes_to_stack));
}
pub fn change_floating_panes_coordinates(
&mut self,
pane_ids_and_coordinates: Vec<(PaneId, FloatingPaneCoordinates)>,
) {
for (pane_id, coordinates) in pane_ids_and_coordinates {
for (_tab_id, tab) in self.tabs.iter_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.change_floating_pane_coordinates(&pane_id, coordinates)
.non_fatal();
break;
}
}
}
}
fn unblock_input(&self) -> Result<()> {
self.bus
.senders
Expand Down Expand Up @@ -4756,6 +4786,11 @@ pub(crate) fn screen_thread_main(
let _ = screen.unblock_input();
let _ = screen.render(None);
},
ScreenInstruction::ChangeFloatingPanesCoordinates(pane_ids_and_coordinates) => {
screen.change_floating_panes_coordinates(pane_ids_and_coordinates);
let _ = screen.unblock_input();
let _ = screen.render(None);
},
}
}
Ok(())
Expand Down
17 changes: 17 additions & 0 deletions zellij-server/src/tab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4495,6 +4495,23 @@ impl Tab {
self.tiled_panes.expand_pane_in_stack(root_pane_id);
}
}
pub fn change_floating_pane_coordinates(
&mut self,
pane_id: &PaneId,
floating_pane_coordinates: FloatingPaneCoordinates,
) -> Result<()> {
self.floating_panes
.change_pane_coordinates(*pane_id, floating_pane_coordinates)?;
self.set_force_render();
self.swap_layouts.set_is_floating_damaged();
Ok(())
}
pub fn get_viewport(&self) -> Viewport {
self.viewport.borrow().clone()
}
pub fn get_display_area(&self) -> Size {
self.display_area.borrow().clone()
}
fn new_scrollback_editor_pane(&self, pid: u32) -> TerminalPane {
let next_terminal_position = self.get_next_terminal_position();
let mut new_pane = TerminalPane::new(
Expand Down
2 changes: 0 additions & 2 deletions zellij-server/src/tab/unit/tab_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3460,8 +3460,6 @@ fn pane_in_sgr_any_event_tracking_mouse_mode() {
let sgr_mouse_mode_any_button = String::from("\u{1b}[?1003;1006h"); // any event tracking (1003) with SGR encoding (1006)
tab.handle_pty_bytes(1, sgr_mouse_mode_any_button.as_bytes().to_vec())
.unwrap();
// TODO: CONTINUE HERE - make sure these pass, then add some button-less motions and see what
// we track them
tab.handle_mouse_event(
&MouseEvent::new_left_press_event(Position::new(5, 71)),
client_id,
Expand Down
43 changes: 43 additions & 0 deletions zellij-server/src/unit/screen_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3689,3 +3689,46 @@ pub fn send_cli_stack_panes_action() {
}
assert_snapshot!(format!("{}", snapshot_count));
}

#[test]
pub fn send_cli_change_floating_pane_coordinates_action() {
let size = Size { cols: 80, rows: 10 };
let client_id = 10; // fake client id should not appear in the screen's state
let initial_tiled_layout = TiledPaneLayout::default();
let initial_floating_panes = vec![FloatingPaneLayout::default()];
let mut mock_screen = MockScreen::new(size);
let session_metadata = mock_screen.clone_session_metadata();
let screen_thread = mock_screen.run(Some(initial_tiled_layout), initial_floating_panes);

let received_server_instructions = Arc::new(Mutex::new(vec![]));
let server_receiver = mock_screen.server_receiver.take().unwrap();
let server_thread = log_actions_in_thread!(
received_server_instructions,
ServerInstruction::KillSession,
server_receiver
);
let change_floating_pane_coordinates_action = CliAction::ChangeFloatingPaneCoordinates {
pane_id: "0".to_owned(),
x: Some("0".to_owned()),
y: Some("0".to_owned()),
width: Some("10".to_owned()),
height: Some("10".to_owned()),
pinned: None,
};
send_cli_action_to_server(
&session_metadata,
change_floating_pane_coordinates_action,
client_id,
);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
let snapshots = take_snapshots_and_cursor_coordinates_from_render_events(
received_server_instructions.lock().unwrap().iter(),
size,
);
let snapshot_count = snapshots.len();
for (_cursor_coordinates, snapshot) in snapshots {
assert_snapshot!(format!("{}", snapshot));
}
assert_snapshot!(format!("{}", snapshot_count));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
source: zellij-server/src/./unit/screen_tests.rs
assertion_line: 3725
expression: "format!(\"{}\", snapshot)"
---
00 (C): ┌ P[..]2 ┐─────────────────────────────────────────────────────────────────────┐
01 (C): │ │ │
02 (C): │ │ │
03 (C): │ │ │
04 (C): │ │ │
05 (C): │ │ │
06 (C): │ │ │
07 (C): │ │ │
08 (C): │ │ │
09 (C): └────────┘─────────────────────────────────────────────────────────────────────┘

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
assertion_line: 3727
expression: "format!(\"{}\", snapshot_count)"
---
2
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
source: zellij-server/src/./unit/screen_tests.rs
assertion_line: 3725
expression: "format!(\"{}\", snapshot)"
---
00 (C): ┌ Pane #1 ─────────────────────────────────────────────────────────────────────┐
01 (C): │ │
02 (C): │ │
03 (C): │ ┌ Pane #2 ──────────────────── PIN [ ] ┐ │
04 (C): │ │ │ │
05 (C): │ │ │ │
06 (C): │ │ │ │
07 (C): │ └──────────────────────────────────────┘ │
08 (C): │ │
09 (C): └──────────────────────────────────────────────────────────────────────────────┘

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
assertion_line: 2448
assertion_line: 2926
expression: "format!(\"{:#?}\", plugin_rename_tab_instruction)"
---
Some(
Expand All @@ -26,6 +26,10 @@ Some(
"BASE",
),
is_swap_layout_dirty: false,
viewport_rows: 10,
viewport_columns: 80,
display_area_rows: 10,
display_area_columns: 80,
},
],
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
assertion_line: 2486
assertion_line: 2976
expression: "format!(\"{:#?}\", plugin_undo_rename_tab_instruction)"
---
Some(
Expand All @@ -26,6 +26,10 @@ Some(
"BASE",
),
is_swap_layout_dirty: false,
viewport_rows: 10,
viewport_columns: 80,
display_area_rows: 10,
display_area_columns: 80,
},
],
),
Expand Down
9 changes: 9 additions & 0 deletions zellij-tile/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,15 @@ pub fn stack_panes(pane_ids: Vec<PaneId>) {
unsafe { host_run_plugin_command() };
}

pub fn change_floating_panes_coordinates(
pane_ids_and_coordinates: Vec<(PaneId, FloatingPaneCoordinates)>,
) {
let plugin_command = PluginCommand::ChangeFloatingPanesCoordinates(pane_ids_and_coordinates);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}

// Utility Functions

#[allow(unused)]
Expand Down
8 changes: 8 additions & 0 deletions zellij-utils/assets/prost/api.event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,14 @@ pub struct TabInfo {
pub active_swap_layout_name: ::core::option::Option<::prost::alloc::string::String>,
#[prost(bool, tag = "10")]
pub is_swap_layout_dirty: bool,
#[prost(uint32, tag = "11")]
pub viewport_rows: u32,
#[prost(uint32, tag = "12")]
pub viewport_columns: u32,
#[prost(uint32, tag = "13")]
pub display_area_rows: u32,
#[prost(uint32, tag = "14")]
pub display_area_columns: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down
Loading

0 comments on commit c4cb9d3

Please sign in to comment.