feat(plugins): add plugin APIs to affect other panes (#3576)

* resize_pane_with_id and close_pane_with_id

* focus_pane_with_id and edit_scrollback_for_pane_with_id

* write_to_pane_id and write_chars_to_pane_id

* lots more commands

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2024-08-29 17:35:21 +02:00 committed by GitHub
parent 240a53aa1a
commit 1776d240da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 3469 additions and 431 deletions

View file

@ -364,6 +364,57 @@ impl ZellijPlugin for State {
BareKey::Char('d') if key.has_modifiers(&[KeyModifier::Alt]) => { BareKey::Char('d') if key.has_modifiers(&[KeyModifier::Alt]) => {
rerun_command_pane(1); rerun_command_pane(1);
}, },
BareKey::Char('e') if key.has_modifiers(&[KeyModifier::Alt]) => {
resize_pane_with_id(
ResizeStrategy::new(Resize::Increase, Some(Direction::Left)),
PaneId::Terminal(2),
);
},
BareKey::Char('f') if key.has_modifiers(&[KeyModifier::Alt]) => {
edit_scrollback_for_pane_with_id(PaneId::Terminal(2));
},
BareKey::Char('g') if key.has_modifiers(&[KeyModifier::Alt]) => {
write_to_pane_id(vec![102, 111, 111], PaneId::Terminal(2));
},
BareKey::Char('h') if key.has_modifiers(&[KeyModifier::Alt]) => {
write_chars_to_pane_id("foo\n", PaneId::Terminal(2));
},
BareKey::Char('i') if key.has_modifiers(&[KeyModifier::Alt]) => {
move_pane_with_pane_id(PaneId::Terminal(2));
},
BareKey::Char('j') if key.has_modifiers(&[KeyModifier::Alt]) => {
move_pane_with_pane_id_in_direction(PaneId::Terminal(2), Direction::Left);
},
BareKey::Char('k') if key.has_modifiers(&[KeyModifier::Alt]) => {
clear_screen_for_pane_id(PaneId::Terminal(2));
},
BareKey::Char('l') if key.has_modifiers(&[KeyModifier::Alt]) => {
scroll_up_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('m') if key.has_modifiers(&[KeyModifier::Alt]) => {
scroll_down_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('n') if key.has_modifiers(&[KeyModifier::Alt]) => {
scroll_to_top_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('o') if key.has_modifiers(&[KeyModifier::Alt]) => {
scroll_to_bottom_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('p') if key.has_modifiers(&[KeyModifier::Alt]) => {
page_scroll_up_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('q') if key.has_modifiers(&[KeyModifier::Alt]) => {
page_scroll_down_in_pane_id(PaneId::Terminal(2));
},
BareKey::Char('r') if key.has_modifiers(&[KeyModifier::Alt]) => {
toggle_pane_id_fullscreen(PaneId::Terminal(2));
},
BareKey::Char('s') if key.has_modifiers(&[KeyModifier::Alt]) => {
toggle_pane_embed_or_eject_for_pane_id(PaneId::Terminal(2));
},
BareKey::Char('t') if key.has_modifiers(&[KeyModifier::Alt]) => {
close_tab_with_index(2);
},
_ => {}, _ => {},
}, },
Event::CustomMessage(message, payload) => { Event::CustomMessage(message, payload) => {

View file

@ -408,12 +408,20 @@ impl FloatingPanes {
strategy: &ResizeStrategy, strategy: &ResizeStrategy,
) -> Result<bool> { ) -> Result<bool> {
// true => successfully resized // true => successfully resized
let err_context = if let Some(active_floating_pane_id) = self.active_panes.get(&client_id) {
|| format!("failed to {strategy} for active floating pane for client {client_id}"); return self.resize_pane_with_id(*strategy, *active_floating_pane_id);
}
Ok(false)
}
pub fn resize_pane_with_id(
&mut self,
strategy: ResizeStrategy,
pane_id: PaneId,
) -> Result<bool> {
// true => successfully resized
let err_context = || format!("Failed to resize pane with id: {:?}", pane_id);
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow(); let viewport = *self.viewport.borrow();
if let Some(active_floating_pane_id) = self.active_panes.get(&client_id) {
let mut floating_pane_grid = FloatingPaneGrid::new( let mut floating_pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
&mut self.desired_pane_positions, &mut self.desired_pane_positions,
@ -422,8 +430,8 @@ impl FloatingPanes {
); );
floating_pane_grid floating_pane_grid
.change_pane_size( .change_pane_size(
active_floating_pane_id, &pane_id,
strategy, &strategy,
(RESIZE_INCREMENT_WIDTH, RESIZE_INCREMENT_HEIGHT), (RESIZE_INCREMENT_WIDTH, RESIZE_INCREMENT_HEIGHT),
) )
.with_context(err_context)?; .with_context(err_context)?;
@ -433,9 +441,7 @@ impl FloatingPanes {
.with_context(err_context)?; .with_context(err_context)?;
} }
self.set_force_render(); self.set_force_render();
return Ok(true); Ok(true)
}
Ok(false)
} }
fn set_pane_active_at(&mut self, pane_id: PaneId) { fn set_pane_active_at(&mut self, pane_id: PaneId) {
@ -545,61 +551,73 @@ impl FloatingPanes {
} }
pub fn move_active_pane_down(&mut self, client_id: ClientId) { pub fn move_active_pane_down(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
self.move_pane_down(*active_pane_id);
}
}
pub fn move_pane_down(&mut self, pane_id: PaneId) {
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow(); let viewport = *self.viewport.borrow();
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
let mut floating_pane_grid = FloatingPaneGrid::new( let mut floating_pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
&mut self.desired_pane_positions, &mut self.desired_pane_positions,
display_area, display_area,
viewport, viewport,
); );
floating_pane_grid.move_pane_down(active_pane_id).unwrap(); floating_pane_grid.move_pane_down(&pane_id).non_fatal();
self.set_force_render(); self.set_force_render();
} }
}
pub fn move_active_pane_up(&mut self, client_id: ClientId) { pub fn move_active_pane_up(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
self.move_pane_up(*active_pane_id);
}
}
pub fn move_pane_up(&mut self, pane_id: PaneId) {
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow(); let viewport = *self.viewport.borrow();
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
let mut floating_pane_grid = FloatingPaneGrid::new( let mut floating_pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
&mut self.desired_pane_positions, &mut self.desired_pane_positions,
display_area, display_area,
viewport, viewport,
); );
floating_pane_grid.move_pane_up(active_pane_id).unwrap(); floating_pane_grid.move_pane_up(&pane_id).non_fatal();
self.set_force_render(); self.set_force_render();
} }
}
pub fn move_active_pane_left(&mut self, client_id: ClientId) { pub fn move_active_pane_left(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
self.move_pane_left(*active_pane_id);
}
}
pub fn move_pane_left(&mut self, pane_id: PaneId) {
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow(); let viewport = *self.viewport.borrow();
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
let mut floating_pane_grid = FloatingPaneGrid::new( let mut floating_pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
&mut self.desired_pane_positions, &mut self.desired_pane_positions,
display_area, display_area,
viewport, viewport,
); );
floating_pane_grid.move_pane_left(active_pane_id).unwrap(); floating_pane_grid.move_pane_left(&pane_id).unwrap();
self.set_force_render(); self.set_force_render();
} }
}
pub fn move_active_pane_right(&mut self, client_id: ClientId) { pub fn move_active_pane_right(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
self.move_pane_right(*active_pane_id);
}
}
pub fn move_pane_right(&mut self, pane_id: PaneId) {
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow(); let viewport = *self.viewport.borrow();
if let Some(active_pane_id) = self.active_panes.get(&client_id) {
let mut floating_pane_grid = FloatingPaneGrid::new( let mut floating_pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
&mut self.desired_pane_positions, &mut self.desired_pane_positions,
display_area, display_area,
viewport, viewport,
); );
floating_pane_grid.move_pane_right(active_pane_id).unwrap(); floating_pane_grid.move_pane_right(&pane_id).unwrap();
self.set_force_render(); self.set_force_render();
} }
}
pub fn move_active_pane( pub fn move_active_pane(
&mut self, &mut self,
search_backwards: bool, search_backwards: bool,
@ -607,7 +625,9 @@ impl FloatingPanes {
client_id: ClientId, client_id: ClientId,
) { ) {
let active_pane_id = self.get_active_pane_id(client_id).unwrap(); let active_pane_id = self.get_active_pane_id(client_id).unwrap();
self.move_pane(search_backwards, active_pane_id)
}
pub fn move_pane(&mut self, search_backwards: bool, pane_id: PaneId) {
let new_position_id = { let new_position_id = {
let pane_grid = FloatingPaneGrid::new( let pane_grid = FloatingPaneGrid::new(
&mut self.panes, &mut self.panes,
@ -616,13 +636,13 @@ impl FloatingPanes {
*self.viewport.borrow(), *self.viewport.borrow(),
); );
if search_backwards { if search_backwards {
pane_grid.previous_selectable_pane_id(&active_pane_id) pane_grid.previous_selectable_pane_id(&pane_id)
} else { } else {
pane_grid.next_selectable_pane_id(&active_pane_id) pane_grid.next_selectable_pane_id(&pane_id)
} }
}; };
if let Some(new_position_id) = new_position_id { if let Some(new_position_id) = new_position_id {
let current_position = self.panes.get(&active_pane_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -635,7 +655,7 @@ impl FloatingPanes {
} }
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(&active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);

View file

@ -1155,7 +1155,7 @@ impl Grid {
self.mark_for_rerender(); self.mark_for_rerender();
} }
/// Dumps all lines above terminal vieport and the viewport itself to a string /// Dumps all lines above terminal vieport and the viewport itself to a string
pub fn dump_screen(&mut self, full: bool) -> String { pub fn dump_screen(&self, full: bool) -> String {
let viewport: String = dump_screen!(self.viewport); let viewport: String = dump_screen!(self.viewport);
if !full { if !full {
return viewport; return viewport;

View file

@ -515,7 +515,7 @@ impl Pane for TerminalPane {
self.geom.y -= count; self.geom.y -= count;
self.reflow_lines(); self.reflow_lines();
} }
fn dump_screen(&mut self, _client_id: ClientId, full: bool) -> String { fn dump_screen(&self, full: bool) -> String {
self.grid.dump_screen(full) self.grid.dump_screen(full)
} }
fn clear_screen(&mut self) { fn clear_screen(&mut self) {

View file

@ -67,7 +67,7 @@ pub struct TiledPanes {
active_panes: ActivePanes, active_panes: ActivePanes,
draw_pane_frames: bool, draw_pane_frames: bool,
panes_to_hide: HashSet<PaneId>, panes_to_hide: HashSet<PaneId>,
fullscreen_is_active: bool, fullscreen_is_active: Option<PaneId>,
senders: ThreadSenders, senders: ThreadSenders,
window_title: Option<String>, window_title: Option<String>,
client_id_to_boundaries: HashMap<ClientId, Boundaries>, client_id_to_boundaries: HashMap<ClientId, Boundaries>,
@ -103,7 +103,7 @@ impl TiledPanes {
active_panes: ActivePanes::new(&os_api), active_panes: ActivePanes::new(&os_api),
draw_pane_frames, draw_pane_frames,
panes_to_hide: HashSet::new(), panes_to_hide: HashSet::new(),
fullscreen_is_active: false, fullscreen_is_active: None,
senders, senders,
window_title: None, window_title: None,
client_id_to_boundaries: HashMap::new(), client_id_to_boundaries: HashMap::new(),
@ -833,10 +833,15 @@ impl TiledPanes {
client_id: ClientId, client_id: ClientId,
strategy: &ResizeStrategy, strategy: &ResizeStrategy,
) -> Result<()> { ) -> Result<()> {
let err_context =
|| format!("failed to {strategy} for active tiled pane for client {client_id}");
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.resize_pane_with_id(*strategy, active_pane_id)?;
}
Ok(())
}
pub fn resize_pane_with_id(&mut self, strategy: ResizeStrategy, pane_id: PaneId) -> Result<()> {
let err_context = || format!("failed to resize pand with id: {:?}", pane_id);
let mut pane_grid = TiledPaneGrid::new( let mut pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
&self.panes_to_hide, &self.panes_to_hide,
@ -845,7 +850,7 @@ impl TiledPanes {
); );
match pane_grid match pane_grid
.change_pane_size(&active_pane_id, strategy, (RESIZE_PERCENT, RESIZE_PERCENT)) .change_pane_size(&pane_id, &strategy, (RESIZE_PERCENT, RESIZE_PERCENT))
.with_context(err_context) .with_context(err_context)
{ {
Ok(_) => {}, Ok(_) => {},
@ -854,17 +859,15 @@ impl TiledPanes {
// try once more with double the resize percent, but let's keep it at that // try once more with double the resize percent, but let's keep it at that
match pane_grid match pane_grid
.change_pane_size( .change_pane_size(
&active_pane_id, &pane_id,
strategy, &strategy,
(RESIZE_PERCENT * 2.0, RESIZE_PERCENT * 2.0), (RESIZE_PERCENT * 2.0, RESIZE_PERCENT * 2.0),
) )
.with_context(err_context) .with_context(err_context)
{ {
Ok(_) => {}, Ok(_) => {},
Err(err) => match err.downcast_ref::<ZellijError>() { Err(err) => match err.downcast_ref::<ZellijError>() {
Some(ZellijError::PaneSizeUnchanged) => { Some(ZellijError::PaneSizeUnchanged) => Err::<(), _>(err).non_fatal(),
Err::<(), _>(err).non_fatal()
},
_ => { _ => {
return Err(err); return Err(err);
}, },
@ -881,8 +884,6 @@ impl TiledPanes {
resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap(); resize_pty!(pane, self.os_api, self.senders, self.character_cell_size).unwrap();
} }
self.reset_boundaries(); self.reset_boundaries();
}
Ok(()) Ok(())
} }
@ -1225,7 +1226,9 @@ impl TiledPanes {
} }
pub fn move_active_pane(&mut self, search_backwards: bool, client_id: ClientId) { pub fn move_active_pane(&mut self, search_backwards: bool, client_id: ClientId) {
let active_pane_id = self.get_active_pane_id(client_id).unwrap(); let active_pane_id = self.get_active_pane_id(client_id).unwrap();
self.move_pane(search_backwards, active_pane_id)
}
pub fn move_pane(&mut self, search_backwards: bool, pane_id: PaneId) {
let new_position_id = { let new_position_id = {
let pane_grid = TiledPaneGrid::new( let pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
@ -1234,9 +1237,9 @@ impl TiledPanes {
*self.viewport.borrow(), *self.viewport.borrow(),
); );
if search_backwards { if search_backwards {
pane_grid.previous_selectable_pane_id(&active_pane_id) pane_grid.previous_selectable_pane_id(&pane_id)
} else { } else {
pane_grid.next_selectable_pane_id(&active_pane_id) pane_grid.next_selectable_pane_id(&pane_id)
} }
}; };
if self if self
@ -1250,7 +1253,7 @@ impl TiledPanes {
self.reapply_pane_frames(); self.reapply_pane_frames();
} }
let current_position = self.panes.get(&active_pane_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -1270,7 +1273,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(&active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);
@ -1283,10 +1286,15 @@ impl TiledPanes {
) )
.unwrap(); .unwrap();
current_position.set_should_render(true); current_position.set_should_render(true);
self.reapply_pane_focus();
self.set_pane_frames(self.draw_pane_frames); self.set_pane_frames(self.draw_pane_frames);
} }
pub fn move_active_pane_down(&mut self, client_id: ClientId) { pub fn move_active_pane_down(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.move_pane_down(active_pane_id);
}
}
pub fn move_pane_down(&mut self, pane_id: PaneId) {
let mut pane_grid = TiledPaneGrid::new( let mut pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
&self.panes_to_hide, &self.panes_to_hide,
@ -1294,11 +1302,10 @@ impl TiledPanes {
*self.viewport.borrow(), *self.viewport.borrow(),
); );
let next_index = pane_grid let next_index = pane_grid
.next_selectable_pane_id_below(&active_pane_id) .next_selectable_pane_id_below(&pane_id)
.or_else(|| pane_grid.progress_stack_down_if_in_stack(&active_pane_id)); .or_else(|| pane_grid.progress_stack_down_if_in_stack(&pane_id));
if let Some(p) = next_index { if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -1318,7 +1325,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);
@ -1331,22 +1338,25 @@ impl TiledPanes {
) )
.unwrap(); .unwrap();
current_position.set_should_render(true); current_position.set_should_render(true);
self.reapply_pane_focus();
self.set_pane_frames(self.draw_pane_frames); self.set_pane_frames(self.draw_pane_frames);
} }
} }
}
pub fn move_active_pane_left(&mut self, client_id: ClientId) { pub fn move_active_pane_left(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.move_pane_left(active_pane_id);
}
}
pub fn move_pane_left(&mut self, pane_id: PaneId) {
let pane_grid = TiledPaneGrid::new( let pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
&self.panes_to_hide, &self.panes_to_hide,
*self.display_area.borrow(), *self.display_area.borrow(),
*self.viewport.borrow(), *self.viewport.borrow(),
); );
let next_index = pane_grid.next_selectable_pane_id_to_the_left(&active_pane_id); let next_index = pane_grid.next_selectable_pane_id_to_the_left(&pane_id);
if let Some(p) = next_index { if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -1366,7 +1376,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);
@ -1379,22 +1389,25 @@ impl TiledPanes {
) )
.unwrap(); .unwrap();
current_position.set_should_render(true); current_position.set_should_render(true);
self.reapply_pane_focus();
self.set_pane_frames(self.draw_pane_frames); self.set_pane_frames(self.draw_pane_frames);
} }
} }
}
pub fn move_active_pane_right(&mut self, client_id: ClientId) { pub fn move_active_pane_right(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.move_pane_right(active_pane_id);
}
}
pub fn move_pane_right(&mut self, pane_id: PaneId) {
let pane_grid = TiledPaneGrid::new( let pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
&self.panes_to_hide, &self.panes_to_hide,
*self.display_area.borrow(), *self.display_area.borrow(),
*self.viewport.borrow(), *self.viewport.borrow(),
); );
let next_index = pane_grid.next_selectable_pane_id_to_the_right(&active_pane_id); let next_index = pane_grid.next_selectable_pane_id_to_the_right(&pane_id);
if let Some(p) = next_index { if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -1414,7 +1427,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);
@ -1427,12 +1440,16 @@ impl TiledPanes {
) )
.unwrap(); .unwrap();
current_position.set_should_render(true); current_position.set_should_render(true);
self.reapply_pane_focus();
self.set_pane_frames(self.draw_pane_frames); self.set_pane_frames(self.draw_pane_frames);
} }
} }
}
pub fn move_active_pane_up(&mut self, client_id: ClientId) { pub fn move_active_pane_up(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.move_pane_up(active_pane_id);
}
}
pub fn move_pane_up(&mut self, pane_id: PaneId) {
let mut pane_grid = TiledPaneGrid::new( let mut pane_grid = TiledPaneGrid::new(
&mut self.panes, &mut self.panes,
&self.panes_to_hide, &self.panes_to_hide,
@ -1440,11 +1457,10 @@ impl TiledPanes {
*self.viewport.borrow(), *self.viewport.borrow(),
); );
let next_index = pane_grid let next_index = pane_grid
.next_selectable_pane_id_above(&active_pane_id) .next_selectable_pane_id_above(&pane_id)
.or_else(|| pane_grid.progress_stack_up_if_in_stack(&active_pane_id)); .or_else(|| pane_grid.progress_stack_up_if_in_stack(&pane_id));
if let Some(p) = next_index { if let Some(p) = next_index {
let active_pane_id = self.active_panes.get(&client_id).unwrap(); let current_position = self.panes.get(&pane_id).unwrap();
let current_position = self.panes.get(active_pane_id).unwrap();
let prev_geom = current_position.position_and_size(); let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override(); let prev_geom_override = current_position.geom_override();
@ -1464,7 +1480,7 @@ impl TiledPanes {
.unwrap(); .unwrap();
new_position.set_should_render(true); new_position.set_should_render(true);
let current_position = self.panes.get_mut(active_pane_id).unwrap(); let current_position = self.panes.get_mut(&pane_id).unwrap();
current_position.set_geom(next_geom); current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override { if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom); current_position.set_geom_override(geom);
@ -1477,10 +1493,10 @@ impl TiledPanes {
) )
.unwrap(); .unwrap();
current_position.set_should_render(true); current_position.set_should_render(true);
self.reapply_pane_focus();
self.set_pane_frames(self.draw_pane_frames); self.set_pane_frames(self.draw_pane_frames);
} }
} }
}
pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) { pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) {
let active_panes: Vec<(ClientId, PaneId)> = self let active_panes: Vec<(ClientId, PaneId)> = self
.active_panes .active_panes
@ -1565,17 +1581,10 @@ impl TiledPanes {
self.panes_to_hide.contains(&pane_id) self.panes_to_hide.contains(&pane_id)
} }
pub fn fullscreen_is_active(&self) -> bool { pub fn fullscreen_is_active(&self) -> bool {
self.fullscreen_is_active self.fullscreen_is_active.is_some()
} }
pub fn unset_fullscreen(&mut self) { pub fn unset_fullscreen(&mut self) {
if self.fullscreen_is_active { if let Some(fullscreen_pane_id) = self.fullscreen_is_active {
let first_client_id = {
let connected_clients = self.connected_clients.borrow();
connected_clients.iter().next().copied()
};
if let Some(active_pane_id) =
first_client_id.and_then(|first_client_id| self.get_active_pane_id(first_client_id))
{
let panes_to_hide: Vec<_> = self.panes_to_hide.iter().copied().collect(); let panes_to_hide: Vec<_> = self.panes_to_hide.iter().copied().collect();
for pane_id in panes_to_hide { for pane_id in panes_to_hide {
let pane = self.get_pane_mut(pane_id).unwrap(); let pane = self.get_pane_mut(pane_id).unwrap();
@ -1596,22 +1605,26 @@ impl TiledPanes {
viewport_pane.reset_size_and_position_override(); viewport_pane.reset_size_and_position_override();
} }
self.panes_to_hide.clear(); self.panes_to_hide.clear();
let active_terminal = self.get_pane_mut(active_pane_id).unwrap(); let fullscreen_pane = self.get_pane_mut(fullscreen_pane_id).unwrap();
active_terminal.reset_size_and_position_override(); fullscreen_pane.reset_size_and_position_override();
self.set_force_render(); self.set_force_render();
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
self.resize(display_area); self.resize(display_area);
self.fullscreen_is_active = false; self.fullscreen_is_active = None;
}
} }
} }
pub fn toggle_active_pane_fullscreen(&mut self, client_id: ClientId) { pub fn toggle_active_pane_fullscreen(&mut self, client_id: ClientId) {
if let Some(active_pane_id) = self.get_active_pane_id(client_id) { if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
if self.fullscreen_is_active { self.toggle_pane_fullscreen(active_pane_id);
}
}
pub fn toggle_pane_fullscreen(&mut self, pane_id: PaneId) {
if self.fullscreen_is_active.is_some() {
self.unset_fullscreen(); self.unset_fullscreen();
} else { } else {
let pane_ids_to_hide = self.panes.iter().filter_map(|(&id, _pane)| { let pane_ids_to_hide = self.panes.iter().filter_map(|(&id, _pane)| {
if id != active_pane_id if id != pane_id
&& is_inside_viewport(&*self.viewport.borrow(), self.get_pane(id).unwrap()) && is_inside_viewport(&*self.viewport.borrow(), self.get_pane(id).unwrap())
{ {
Some(id) Some(id)
@ -1633,18 +1646,16 @@ impl TiledPanes {
.copied() .copied()
.into_iter() .into_iter()
.filter(|id| { .filter(|id| {
!is_inside_viewport( !is_inside_viewport(&*self.viewport.borrow(), self.get_pane(*id).unwrap())
&*self.viewport.borrow(),
self.get_pane(*id).unwrap(),
)
}) })
.collect(); .collect();
for pid in viewport_pane_ids { for pid in viewport_pane_ids {
let viewport_pane = self.get_pane_mut(pid).unwrap(); if let Some(viewport_pane) = self.get_pane_mut(pid) {
viewport_pane.set_geom_override(viewport_pane.position_and_size()); viewport_pane.set_geom_override(viewport_pane.position_and_size());
} }
}
let viewport = { *self.viewport.borrow() }; let viewport = { *self.viewport.borrow() };
let active_pane = self.get_pane_mut(active_pane_id).unwrap(); if let Some(active_pane) = self.get_pane_mut(pane_id) {
let full_screen_geom = PaneGeom { let full_screen_geom = PaneGeom {
x: viewport.x, x: viewport.x,
y: viewport.y, y: viewport.y,
@ -1652,16 +1663,16 @@ impl TiledPanes {
}; };
active_pane.set_geom_override(full_screen_geom); active_pane.set_geom_override(full_screen_geom);
} }
}
let connected_client_list: Vec<ClientId> = let connected_client_list: Vec<ClientId> =
{ self.connected_clients.borrow().iter().copied().collect() }; { self.connected_clients.borrow().iter().copied().collect() };
for client_id in connected_client_list { for client_id in connected_client_list {
self.focus_pane(active_pane_id, client_id); self.focus_pane(pane_id, client_id);
} }
self.set_force_render(); self.set_force_render();
let display_area = *self.display_area.borrow(); let display_area = *self.display_area.borrow();
self.resize(display_area); self.resize(display_area);
self.fullscreen_is_active = true; self.fullscreen_is_active = Some(pane_id);
}
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7482
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
ClearScreenForPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,10 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 8121
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
CloseTabWithIndex(
2,
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7127
expression: "format!(\"{:#?}\", rerun_command_pane_event)"
---
Some(
EditScrollbackForPaneWithId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,13 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7411
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
MovePaneWithPaneIdInDirection(
Terminal(
2,
),
Left,
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7340
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
MovePaneWithPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7908
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
PageScrollDownInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7837
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
PageScrollUpInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,19 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7056
expression: "format!(\"{:#?}\", rerun_command_pane_event)"
---
Some(
ResizePaneWithId(
ResizeStrategy {
resize: Increase,
direction: Some(
Left,
),
invert_on_boundaries: false,
},
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7624
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
ScrollDownInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7766
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
ScrollToBottomInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7695
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
ScrollToTopInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7553
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
ScrollUpInPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 8050
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
TogglePaneEmbedOrEjectForPaneId(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,12 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7979
expression: "format!(\"{:#?}\", screen_instruction)"
---
Some(
TogglePaneIdFullscreen(
Terminal(
2,
),
),
)

View file

@ -0,0 +1,18 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7269
expression: "format!(\"{:#?}\", rerun_command_pane_event)"
---
Some(
WriteToPaneId(
[
102,
111,
111,
10,
],
Terminal(
2,
),
),
)

View file

@ -0,0 +1,17 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 7198
expression: "format!(\"{:#?}\", rerun_command_pane_event)"
---
Some(
WriteToPaneId(
[
102,
111,
111,
],
Terminal(
2,
),
),
)

View file

@ -272,6 +272,54 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
PluginCommand::RerunCommandPane(terminal_pane_id) => { PluginCommand::RerunCommandPane(terminal_pane_id) => {
rerun_command_pane(env, terminal_pane_id) rerun_command_pane(env, terminal_pane_id)
}, },
PluginCommand::ResizePaneIdWithDirection(resize, pane_id) => {
resize_pane_with_id(env, resize, pane_id.into())
},
PluginCommand::EditScrollbackForPaneWithId(pane_id) => {
edit_scrollback_for_pane_with_id(env, pane_id.into())
},
PluginCommand::WriteToPaneId(bytes, pane_id) => {
write_to_pane_id(env, bytes, pane_id.into())
},
PluginCommand::WriteCharsToPaneId(chars, pane_id) => {
write_chars_to_pane_id(env, chars, pane_id.into())
},
PluginCommand::MovePaneWithPaneId(pane_id) => {
move_pane_with_pane_id(env, pane_id.into())
},
PluginCommand::MovePaneWithPaneIdInDirection(pane_id, direction) => {
move_pane_with_pane_id_in_direction(env, pane_id.into(), direction)
},
PluginCommand::ClearScreenForPaneId(pane_id) => {
clear_screen_for_pane_id(env, pane_id.into())
},
PluginCommand::ScrollUpInPaneId(pane_id) => {
scroll_up_in_pane_id(env, pane_id.into())
},
PluginCommand::ScrollDownInPaneId(pane_id) => {
scroll_down_in_pane_id(env, pane_id.into())
},
PluginCommand::ScrollToTopInPaneId(pane_id) => {
scroll_to_top_in_pane_id(env, pane_id.into())
},
PluginCommand::ScrollToBottomInPaneId(pane_id) => {
scroll_to_bottom_in_pane_id(env, pane_id.into())
},
PluginCommand::PageScrollUpInPaneId(pane_id) => {
page_scroll_up_in_pane_id(env, pane_id.into())
},
PluginCommand::PageScrollDownInPaneId(pane_id) => {
page_scroll_down_in_pane_id(env, pane_id.into())
},
PluginCommand::TogglePaneIdFullscreen(pane_id) => {
toggle_pane_id_fullscreen(env, pane_id.into())
},
PluginCommand::TogglePaneEmbedOrEjectForPaneId(pane_id) => {
toggle_pane_embed_or_eject_for_pane_id(env, pane_id.into())
},
PluginCommand::CloseTabWithIndex(tab_index) => {
close_tab_with_index(env, tab_index)
},
}, },
(PermissionStatus::Denied, permission) => { (PermissionStatus::Denied, permission) => {
log::error!( log::error!(
@ -1442,6 +1490,105 @@ fn scan_host_folder(env: &PluginEnv, folder_to_scan: PathBuf) {
} }
} }
fn resize_pane_with_id(env: &PluginEnv, resize: ResizeStrategy, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ResizePaneWithId(resize, pane_id));
}
fn edit_scrollback_for_pane_with_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::EditScrollbackForPaneWithId(pane_id));
}
fn write_to_pane_id(env: &PluginEnv, bytes: Vec<u8>, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::WriteToPaneId(bytes, pane_id));
}
fn write_chars_to_pane_id(env: &PluginEnv, chars: String, pane_id: PaneId) {
let bytes = chars.into_bytes();
let _ = env
.senders
.send_to_screen(ScreenInstruction::WriteToPaneId(bytes, pane_id));
}
fn move_pane_with_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::MovePaneWithPaneId(pane_id));
}
fn move_pane_with_pane_id_in_direction(env: &PluginEnv, pane_id: PaneId, direction: Direction) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::MovePaneWithPaneIdInDirection(
pane_id, direction,
));
}
fn clear_screen_for_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ClearScreenForPaneId(pane_id));
}
fn scroll_up_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ScrollUpInPaneId(pane_id));
}
fn scroll_down_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ScrollDownInPaneId(pane_id));
}
fn scroll_to_top_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ScrollToTopInPaneId(pane_id));
}
fn scroll_to_bottom_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::ScrollToBottomInPaneId(pane_id));
}
fn page_scroll_up_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::PageScrollUpInPaneId(pane_id));
}
fn page_scroll_down_in_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::PageScrollDownInPaneId(pane_id));
}
fn toggle_pane_id_fullscreen(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::TogglePaneIdFullscreen(pane_id));
}
fn toggle_pane_embed_or_eject_for_pane_id(env: &PluginEnv, pane_id: PaneId) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::TogglePaneEmbedOrEjectForPaneId(pane_id));
}
fn close_tab_with_index(env: &PluginEnv, tab_index: usize) {
let _ = env
.senders
.send_to_screen(ScreenInstruction::CloseTabWithIndex(tab_index));
}
// Custom panic handler for plugins. // Custom panic handler for plugins.
// //
// This is called when a panic occurs in a plugin. Since most panics will likely originate in the // This is called when a panic occurs in a plugin. Since most panics will likely originate in the
@ -1516,7 +1663,10 @@ fn check_command_permission(
| PluginCommand::RunCommand(..) | PluginCommand::RunCommand(..)
| PluginCommand::ExecCmd(..) => PermissionType::RunCommands, | PluginCommand::ExecCmd(..) => PermissionType::RunCommands,
PluginCommand::WebRequest(..) => PermissionType::WebAccess, PluginCommand::WebRequest(..) => PermissionType::WebAccess,
PluginCommand::Write(..) | PluginCommand::WriteChars(..) => PermissionType::WriteToStdin, PluginCommand::Write(..)
| PluginCommand::WriteChars(..)
| PluginCommand::WriteToPaneId(..)
| PluginCommand::WriteCharsToPaneId(..) => PermissionType::WriteToStdin,
PluginCommand::SwitchTabTo(..) PluginCommand::SwitchTabTo(..)
| PluginCommand::SwitchToMode(..) | PluginCommand::SwitchToMode(..)
| PluginCommand::NewTabsWithLayout(..) | PluginCommand::NewTabsWithLayout(..)
@ -1531,19 +1681,31 @@ fn check_command_permission(
| PluginCommand::MoveFocusOrTab(..) | PluginCommand::MoveFocusOrTab(..)
| PluginCommand::Detach | PluginCommand::Detach
| PluginCommand::EditScrollback | PluginCommand::EditScrollback
| PluginCommand::EditScrollbackForPaneWithId(..)
| PluginCommand::ToggleTab | PluginCommand::ToggleTab
| PluginCommand::MovePane | PluginCommand::MovePane
| PluginCommand::MovePaneWithDirection(..) | PluginCommand::MovePaneWithDirection(..)
| PluginCommand::MovePaneWithPaneId(..)
| PluginCommand::MovePaneWithPaneIdInDirection(..)
| PluginCommand::ClearScreen | PluginCommand::ClearScreen
| PluginCommand::ClearScreenForPaneId(..)
| PluginCommand::ScrollUp | PluginCommand::ScrollUp
| PluginCommand::ScrollUpInPaneId(..)
| PluginCommand::ScrollDown | PluginCommand::ScrollDown
| PluginCommand::ScrollDownInPaneId(..)
| PluginCommand::ScrollToTop | PluginCommand::ScrollToTop
| PluginCommand::ScrollToTopInPaneId(..)
| PluginCommand::ScrollToBottom | PluginCommand::ScrollToBottom
| PluginCommand::ScrollToBottomInPaneId(..)
| PluginCommand::PageScrollUp | PluginCommand::PageScrollUp
| PluginCommand::PageScrollUpInPaneId(..)
| PluginCommand::PageScrollDown | PluginCommand::PageScrollDown
| PluginCommand::PageScrollDownInPaneId(..)
| PluginCommand::ToggleFocusFullscreen | PluginCommand::ToggleFocusFullscreen
| PluginCommand::TogglePaneIdFullscreen(..)
| PluginCommand::TogglePaneFrames | PluginCommand::TogglePaneFrames
| PluginCommand::TogglePaneEmbedOrEject | PluginCommand::TogglePaneEmbedOrEject
| PluginCommand::TogglePaneEmbedOrEjectForPaneId(..)
| PluginCommand::UndoRenamePane | PluginCommand::UndoRenamePane
| PluginCommand::CloseFocus | PluginCommand::CloseFocus
| PluginCommand::ToggleActiveTabSync | PluginCommand::ToggleActiveTabSync
@ -1570,6 +1732,8 @@ fn check_command_permission(
| PluginCommand::ShowPaneWithId(..) | PluginCommand::ShowPaneWithId(..)
| PluginCommand::HidePaneWithId(..) | PluginCommand::HidePaneWithId(..)
| PluginCommand::RerunCommandPane(..) | PluginCommand::RerunCommandPane(..)
| PluginCommand::ResizePaneIdWithDirection(..)
| PluginCommand::CloseTabWithIndex(..)
| PluginCommand::KillSessions(..) => PermissionType::ChangeApplicationState, | PluginCommand::KillSessions(..) => PermissionType::ChangeApplicationState,
PluginCommand::UnblockCliPipeInput(..) PluginCommand::UnblockCliPipeInput(..)
| PluginCommand::BlockCliPipeInput(..) | PluginCommand::BlockCliPipeInput(..)

View file

@ -10,11 +10,7 @@ use crate::{
}; };
use async_std::task::{self, JoinHandle}; use async_std::task::{self, JoinHandle};
use std::sync::Arc; use std::sync::Arc;
use std::{ use std::{collections::HashMap, os::unix::io::RawFd, path::PathBuf};
collections::{BTreeMap, HashMap},
os::unix::io::RawFd,
path::PathBuf,
};
use zellij_utils::nix::unistd::Pid; use zellij_utils::nix::unistd::Pid;
use zellij_utils::{ use zellij_utils::{
async_std, async_std,
@ -32,7 +28,7 @@ use zellij_utils::{
pub type VteBytes = Vec<u8>; pub type VteBytes = Vec<u8>;
pub type TabIndex = u32; pub type TabIndex = u32;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClientTabIndexOrPaneId { pub enum ClientTabIndexOrPaneId {
ClientId(ClientId), ClientId(ClientId),
TabIndex(usize), TabIndex(usize),
@ -51,7 +47,7 @@ pub enum PtyInstruction {
ClientTabIndexOrPaneId, ClientTabIndexOrPaneId,
), // bool (if Some) is ), // bool (if Some) is
// should_float, String is an optional pane name // should_float, String is an optional pane name
OpenInPlaceEditor(PathBuf, Option<usize>, ClientId), // Option<usize> is the optional line number OpenInPlaceEditor(PathBuf, Option<usize>, ClientTabIndexOrPaneId), // Option<usize> is the optional line number
SpawnTerminalVertically(Option<TerminalAction>, Option<String>, ClientId), // String is an SpawnTerminalVertically(Option<TerminalAction>, Option<String>, ClientId), // String is an
// optional pane // optional pane
// name // name
@ -357,9 +353,12 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
}, },
} }
}, },
PtyInstruction::OpenInPlaceEditor(temp_file, line_number, client_id) => { PtyInstruction::OpenInPlaceEditor(
let err_context = temp_file,
|| format!("failed to open in-place editor for client {}", client_id); line_number,
client_tab_index_or_pane_id,
) => {
let err_context = || format!("failed to open in-place editor for client");
match pty.spawn_terminal( match pty.spawn_terminal(
Some(TerminalAction::OpenFile(OpenFilePayload::new( Some(TerminalAction::OpenFile(OpenFilePayload::new(
@ -367,14 +366,14 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
line_number, line_number,
None, None,
))), ))),
ClientTabIndexOrPaneId::ClientId(client_id), client_tab_index_or_pane_id,
) { ) {
Ok((pid, _starts_held)) => { Ok((pid, _starts_held)) => {
pty.bus pty.bus
.senders .senders
.send_to_screen(ScreenInstruction::OpenInPlaceEditor( .send_to_screen(ScreenInstruction::OpenInPlaceEditor(
PaneId::Terminal(pid), PaneId::Terminal(pid),
client_id, client_tab_index_or_pane_id,
)) ))
.with_context(err_context)?; .with_context(err_context)?;
}, },

View file

@ -156,7 +156,7 @@ pub enum ScreenInstruction {
bool, // start suppressed bool, // start suppressed
ClientTabIndexOrPaneId, ClientTabIndexOrPaneId,
), ),
OpenInPlaceEditor(PaneId, ClientId), OpenInPlaceEditor(PaneId, ClientTabIndexOrPaneId),
TogglePaneEmbedOrFloating(ClientId), TogglePaneEmbedOrFloating(ClientId),
ToggleFloatingPanes(ClientId, Option<TerminalAction>), ToggleFloatingPanes(ClientId, Option<TerminalAction>),
HorizontalSplit(PaneId, Option<InitialTitle>, HoldForCommand, ClientId), HorizontalSplit(PaneId, Option<InitialTitle>, HoldForCommand, ClientId),
@ -380,6 +380,21 @@ pub enum ScreenInstruction {
hide_session_name: bool, hide_session_name: bool,
}, },
RerunCommandPane(u32), // u32 - terminal pane id RerunCommandPane(u32), // u32 - terminal pane id
ResizePaneWithId(ResizeStrategy, PaneId),
EditScrollbackForPaneWithId(PaneId),
WriteToPaneId(Vec<u8>, PaneId),
MovePaneWithPaneId(PaneId),
MovePaneWithPaneIdInDirection(PaneId, Direction),
ClearScreenForPaneId(PaneId),
ScrollUpInPaneId(PaneId),
ScrollDownInPaneId(PaneId),
ScrollToTopInPaneId(PaneId),
ScrollToBottomInPaneId(PaneId),
PageScrollUpInPaneId(PaneId),
PageScrollDownInPaneId(PaneId),
TogglePaneIdFullscreen(PaneId),
TogglePaneEmbedOrEjectForPaneId(PaneId),
CloseTabWithIndex(usize),
} }
impl From<&ScreenInstruction> for ScreenContext { impl From<&ScreenInstruction> for ScreenContext {
@ -566,6 +581,27 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::ListClientsMetadata(..) => ScreenContext::ListClientsMetadata, ScreenInstruction::ListClientsMetadata(..) => ScreenContext::ListClientsMetadata,
ScreenInstruction::Reconfigure { .. } => ScreenContext::Reconfigure, ScreenInstruction::Reconfigure { .. } => ScreenContext::Reconfigure,
ScreenInstruction::RerunCommandPane { .. } => ScreenContext::RerunCommandPane, ScreenInstruction::RerunCommandPane { .. } => ScreenContext::RerunCommandPane,
ScreenInstruction::ResizePaneWithId(..) => ScreenContext::ResizePaneWithId,
ScreenInstruction::EditScrollbackForPaneWithId(..) => {
ScreenContext::EditScrollbackForPaneWithId
},
ScreenInstruction::WriteToPaneId(..) => ScreenContext::WriteToPaneId,
ScreenInstruction::MovePaneWithPaneId(..) => ScreenContext::MovePaneWithPaneId,
ScreenInstruction::MovePaneWithPaneIdInDirection(..) => {
ScreenContext::MovePaneWithPaneIdInDirection
},
ScreenInstruction::ClearScreenForPaneId(..) => ScreenContext::ClearScreenForPaneId,
ScreenInstruction::ScrollUpInPaneId(..) => ScreenContext::ScrollUpInPaneId,
ScreenInstruction::ScrollDownInPaneId(..) => ScreenContext::ScrollDownInPaneId,
ScreenInstruction::ScrollToTopInPaneId(..) => ScreenContext::ScrollToTopInPaneId,
ScreenInstruction::ScrollToBottomInPaneId(..) => ScreenContext::ScrollToBottomInPaneId,
ScreenInstruction::PageScrollUpInPaneId(..) => ScreenContext::PageScrollUpInPaneId,
ScreenInstruction::PageScrollDownInPaneId(..) => ScreenContext::PageScrollDownInPaneId,
ScreenInstruction::TogglePaneIdFullscreen(..) => ScreenContext::TogglePaneIdFullscreen,
ScreenInstruction::TogglePaneEmbedOrEjectForPaneId(..) => {
ScreenContext::TogglePaneEmbedOrEjectForPaneId
},
ScreenInstruction::CloseTabWithIndex(..) => ScreenContext::CloseTabWithIndex,
} }
} }
} }
@ -2010,6 +2046,19 @@ impl Screen {
); );
} }
} }
pub fn resize_pane_with_id(&mut self, resize: ResizeStrategy, pane_id: PaneId) {
let mut found = false;
for tab in self.tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.resize_pane_with_id(resize, pane_id);
found = true;
break;
}
}
if !found {
log::error!("Failed to find pane with id: {:?} to resize", pane_id);
}
}
pub fn break_pane( pub fn break_pane(
&mut self, &mut self,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
@ -2586,11 +2635,35 @@ pub(crate) fn screen_thread_main(
screen.render(None)?; screen.render(None)?;
}, },
ScreenInstruction::OpenInPlaceEditor(pid, client_id) => { ScreenInstruction::OpenInPlaceEditor(pid, client_tab_index_or_pane_id) => {
match client_tab_index_or_pane_id {
ClientTabIndexOrPaneId::ClientId(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab active_tab!(screen, client_id, |tab: &mut Tab| tab
.replace_active_pane_with_editor_pane(pid, client_id), ?); .replace_active_pane_with_editor_pane(pid, client_id), ?);
screen.unblock_input()?; screen.unblock_input()?;
screen.log_and_report_session_state()?; screen.log_and_report_session_state()?;
},
ClientTabIndexOrPaneId::TabIndex(tab_index) => {
log::error!("Cannot OpenInPlaceEditor with a TabIndex");
},
ClientTabIndexOrPaneId::PaneId(pane_id_to_replace) => {
let mut found = false;
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id_to_replace) {
tab.replace_pane_with_editor_pane(pid, pane_id_to_replace);
found = true;
break;
}
}
if !found {
log::error!(
"Could not find pane with id {:?} to replace",
pane_id_to_replace
);
}
},
}
screen.render(None)?; screen.render(None)?;
}, },
@ -4165,6 +4238,195 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::RerunCommandPane(terminal_pane_id) => { ScreenInstruction::RerunCommandPane(terminal_pane_id) => {
screen.rerun_command_pane_with_id(terminal_pane_id) screen.rerun_command_pane_with_id(terminal_pane_id)
}, },
ScreenInstruction::ResizePaneWithId(resize, pane_id) => {
screen.resize_pane_with_id(resize, pane_id)
},
ScreenInstruction::EditScrollbackForPaneWithId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.edit_scrollback_for_pane_with_id(pane_id).non_fatal();
break;
}
}
screen.render(None)?;
},
ScreenInstruction::WriteToPaneId(bytes, pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.write_to_pane_id(&None, bytes, false, pane_id, None)
.non_fatal();
break;
}
}
screen.render(None)?;
},
ScreenInstruction::MovePaneWithPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.move_pane(pane_id);
break;
}
}
screen.render(None)?;
},
ScreenInstruction::MovePaneWithPaneIdInDirection(pane_id, direction) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
match direction {
Direction::Down => tab.move_pane_down(pane_id),
Direction::Up => tab.move_pane_up(pane_id),
Direction::Left => tab.move_pane_left(pane_id),
Direction::Right => tab.move_pane_right(pane_id),
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::ClearScreenForPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.clear_screen_for_pane_id(pane_id);
break;
}
}
screen.render(None)?;
},
ScreenInstruction::ScrollUpInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_up(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!(
"Currently only terminal panes are supported for scrolling up"
);
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::ScrollDownInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_down(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!(
"Currently only terminal panes are supported for scrolling down"
);
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::ScrollToTopInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_to_top(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!(
"Currently only terminal panes are supported for scrolling to top"
);
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::ScrollToBottomInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_to_bottom(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!("Currently only terminal panes are supported for scrolling to bottom");
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::PageScrollUpInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_page_up(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!(
"Currently only terminal panes are supported for scrolling"
);
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::PageScrollDownInPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
if let PaneId::Terminal(terminal_pane_id) = pane_id {
tab.scroll_terminal_page_down(terminal_pane_id);
} else {
// this is because to do this with plugins, we need the client_id -
// which we do not have (yet?) in this context...
log::error!(
"Currently only terminal panes are supported for scrolling"
);
}
break;
}
}
screen.render(None)?;
},
ScreenInstruction::TogglePaneIdFullscreen(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.toggle_pane_fullscreen(pane_id);
break;
}
}
screen.render(None)?;
},
ScreenInstruction::TogglePaneEmbedOrEjectForPaneId(pane_id) => {
let all_tabs = screen.get_tabs_mut();
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
tab.toggle_pane_embed_or_floating_for_pane_id(pane_id)
.non_fatal();
break;
}
}
screen.render(None)?;
},
ScreenInstruction::CloseTabWithIndex(tab_index) => {
screen.close_tab_at_index(tab_index).non_fatal()
},
} }
} }
Ok(()) Ok(())

View file

@ -265,7 +265,7 @@ pub trait Pane {
fn pull_left(&mut self, count: usize); fn pull_left(&mut self, count: usize);
fn pull_up(&mut self, count: usize); fn pull_up(&mut self, count: usize);
fn clear_screen(&mut self); fn clear_screen(&mut self);
fn dump_screen(&mut self, _client_id: ClientId, _full: bool) -> String { fn dump_screen(&self, _full: bool) -> String {
"".to_owned() "".to_owned()
} }
fn scroll_up(&mut self, count: usize, client_id: ClientId); fn scroll_up(&mut self, count: usize, client_id: ClientId);
@ -1024,6 +1024,38 @@ impl Tab {
} }
Ok(()) Ok(())
} }
pub fn toggle_pane_embed_or_floating_for_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
let err_context = || {
format!(
"failed to toggle embedded/floating pane for pane_id {:?}",
pane_id
)
};
if self.tiled_panes.fullscreen_is_active() {
self.tiled_panes.unset_fullscreen();
}
if self.floating_panes.panes_contain(&pane_id) {
if self.tiled_panes.has_room_for_new_pane() {
let floating_pane_to_embed = self
.extract_pane(pane_id, true, None)
.with_context(|| {
format!("failed to find floating pane (ID: {pane_id:?}) to embed",)
})
.with_context(err_context)?;
self.add_tiled_pane(floating_pane_to_embed, pane_id, None)?;
}
} else if self.tiled_panes.panes_contain(&pane_id) {
if self.get_selectable_tiled_panes().count() <= 1 {
log::error!("Cannot float the last tiled pane...");
// don't close the only pane on screen...
return Ok(());
}
if let Some(embedded_pane_to_float) = self.extract_pane(pane_id, true, None) {
self.add_floating_pane(embedded_pane_to_float, pane_id, None, None)?;
}
}
Ok(())
}
pub fn toggle_floating_panes( pub fn toggle_floating_panes(
&mut self, &mut self,
client_id: Option<ClientId>, client_id: Option<ClientId>,
@ -1181,28 +1213,7 @@ impl Tab {
match pid { match pid {
PaneId::Terminal(pid) => { PaneId::Terminal(pid) => {
let next_terminal_position = self.get_next_terminal_position(); // TODO: this is not accurate in this case let new_pane = self.new_scrollback_editor_pane(pid);
let mut 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.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
None,
None,
self.debug,
self.arrow_fonts,
self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol,
);
new_pane.update_name("EDITING SCROLLBACK"); // we do this here and not in the
// constructor so it won't be overrided
// by the editor
let replaced_pane = if self.floating_panes.panes_are_visible() { let replaced_pane = if self.floating_panes.panes_are_visible() {
self.floating_panes self.floating_panes
.replace_active_pane(Box::new(new_pane), client_id) .replace_active_pane(Box::new(new_pane), client_id)
@ -1213,9 +1224,7 @@ impl Tab {
}; };
match replaced_pane { match replaced_pane {
Some(replaced_pane) => { Some(replaced_pane) => {
let is_scrollback_editor = true; self.insert_scrollback_editor_replaced_pane(replaced_pane, pid);
self.suppressed_panes
.insert(PaneId::Terminal(pid), (is_scrollback_editor, replaced_pane));
self.get_active_pane(client_id) self.get_active_pane(client_id)
.with_context(|| format!("no active pane found for client {client_id}")) .with_context(|| format!("no active pane found for client {client_id}"))
.and_then(|current_active_pane| { .and_then(|current_active_pane| {
@ -1243,6 +1252,60 @@ impl Tab {
} }
Ok(()) Ok(())
} }
pub fn replace_pane_with_editor_pane(
&mut self,
pid: PaneId,
pane_id_to_replace: PaneId,
) -> Result<()> {
// this method creates a new pane from pid and replaces it with the pane iwth the given pane_id_to_replace
// the pane with the given pane_id_to_replace is then suppressed (hidden and not rendered) until the current
// created pane is closed, in which case it will be replaced back by it
let err_context = || format!("failed to suppress pane");
match pid {
PaneId::Terminal(pid) => {
let new_pane = self.new_scrollback_editor_pane(pid);
let replaced_pane = if self.floating_panes.panes_contain(&pane_id_to_replace) {
self.floating_panes
.replace_pane(pane_id_to_replace, Box::new(new_pane))
.ok()
} else if self.tiled_panes.panes_contain(&pane_id_to_replace) {
self.tiled_panes
.replace_pane(pane_id_to_replace, Box::new(new_pane))
} else if self
.suppressed_panes
.values()
.any(|s_p| s_p.1.pid() == pane_id_to_replace)
{
log::error!("Cannot replace suppressed pane");
None
} else {
// not a thing
None
};
match replaced_pane {
Some(replaced_pane) => {
resize_pty!(
replaced_pane,
self.os_api,
self.senders,
self.character_cell_size
);
self.insert_scrollback_editor_replaced_pane(replaced_pane, pid);
},
None => {
Err::<(), _>(anyhow!("Could not find editor pane to replace"))
.with_context(err_context)
.non_fatal();
},
}
},
PaneId::Plugin(_pid) => {
// TBD, currently unsupported
},
}
Ok(())
}
pub fn suppress_pane_and_replace_with_pid( pub fn suppress_pane_and_replace_with_pid(
&mut self, &mut self,
old_pane_id: PaneId, old_pane_id: PaneId,
@ -1493,6 +1556,23 @@ impl Tab {
} }
}) })
} }
pub fn get_pane_with_id(&self, pane_id: PaneId) -> Option<&dyn Pane> {
self.floating_panes
.get_pane(pane_id)
.map(Box::as_ref)
.or_else(|| self.tiled_panes.get_pane(pane_id).map(Box::as_ref))
.or_else(|| self.suppressed_panes.get(&pane_id).map(|p| p.1.as_ref()))
}
pub fn get_pane_with_id_mut(&mut self, pane_id: PaneId) -> Option<&mut Box<dyn Pane>> {
self.floating_panes
.get_pane_mut(pane_id)
.or_else(|| self.tiled_panes.get_pane_mut(pane_id))
.or_else(|| {
self.suppressed_panes
.get_mut(&pane_id)
.map(|(_, pane)| pane)
})
}
pub fn get_active_pane_mut(&mut self, client_id: ClientId) -> Option<&mut Box<dyn Pane>> { pub fn get_active_pane_mut(&mut self, client_id: ClientId) -> Option<&mut Box<dyn Pane>> {
self.get_active_pane_id(client_id).and_then(|ap| { self.get_active_pane_id(client_id).and_then(|ap| {
if self.floating_panes.panes_are_visible() { if self.floating_panes.panes_are_visible() {
@ -1948,6 +2028,13 @@ impl Tab {
} }
self.tiled_panes.toggle_active_pane_fullscreen(client_id); self.tiled_panes.toggle_active_pane_fullscreen(client_id);
} }
pub fn toggle_pane_fullscreen(&mut self, pane_id: PaneId) {
if self.tiled_panes.panes_contain(&pane_id) {
self.tiled_panes.toggle_pane_fullscreen(pane_id);
} else {
log::error!("No tiled pane with id: {:?} found", pane_id);
}
}
pub fn is_fullscreen_active(&self) -> bool { pub fn is_fullscreen_active(&self) -> bool {
self.tiled_panes.fullscreen_is_active() self.tiled_panes.fullscreen_is_active()
} }
@ -2391,6 +2478,20 @@ impl Tab {
.move_active_pane(search_backwards, client_id); .move_active_pane(search_backwards, client_id);
} }
} }
pub fn move_pane(&mut self, pane_id: PaneId) {
if !self.has_selectable_panes() {
return;
}
if self.tiled_panes.fullscreen_is_active() {
return;
}
let search_backwards = false;
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_pane(search_backwards, pane_id);
} else {
self.tiled_panes.move_pane(search_backwards, pane_id);
}
}
pub fn move_active_pane_backwards(&mut self, client_id: ClientId) { pub fn move_active_pane_backwards(&mut self, client_id: ClientId) {
if !self.has_selectable_panes() { if !self.has_selectable_panes() {
return; return;
@ -2422,6 +2523,21 @@ impl Tab {
self.tiled_panes.move_active_pane_down(client_id); self.tiled_panes.move_active_pane_down(client_id);
} }
} }
pub fn move_pane_down(&mut self, pane_id: PaneId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_pane_down(pane_id);
self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
return;
}
if self.tiled_panes.fullscreen_is_active() {
return;
}
self.tiled_panes.move_pane_down(pane_id);
}
}
pub fn move_active_pane_up(&mut self, client_id: ClientId) { pub fn move_active_pane_up(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() { if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_up(client_id); self.floating_panes.move_active_pane_up(client_id);
@ -2437,6 +2553,21 @@ impl Tab {
self.tiled_panes.move_active_pane_up(client_id); self.tiled_panes.move_active_pane_up(client_id);
} }
} }
pub fn move_pane_up(&mut self, pane_id: PaneId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_pane_up(pane_id);
self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
return;
}
if self.tiled_panes.fullscreen_is_active() {
return;
}
self.tiled_panes.move_pane_up(pane_id);
}
}
pub fn move_active_pane_right(&mut self, client_id: ClientId) { pub fn move_active_pane_right(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() { if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_right(client_id); self.floating_panes.move_active_pane_right(client_id);
@ -2452,6 +2583,21 @@ impl Tab {
self.tiled_panes.move_active_pane_right(client_id); self.tiled_panes.move_active_pane_right(client_id);
} }
} }
pub fn move_pane_right(&mut self, pane_id: PaneId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_pane_right(pane_id);
self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
return;
}
if self.tiled_panes.fullscreen_is_active() {
return;
}
self.tiled_panes.move_pane_right(pane_id);
}
}
pub fn move_active_pane_left(&mut self, client_id: ClientId) { pub fn move_active_pane_left(&mut self, client_id: ClientId) {
if self.floating_panes.panes_are_visible() { if self.floating_panes.panes_are_visible() {
self.floating_panes.move_active_pane_left(client_id); self.floating_panes.move_active_pane_left(client_id);
@ -2467,6 +2613,21 @@ impl Tab {
self.tiled_panes.move_active_pane_left(client_id); self.tiled_panes.move_active_pane_left(client_id);
} }
} }
pub fn move_pane_left(&mut self, pane_id: PaneId) {
if self.floating_panes.panes_are_visible() {
self.floating_panes.move_pane_left(pane_id);
self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" behind
} else {
if !self.has_selectable_panes() {
return;
}
if self.tiled_panes.fullscreen_is_active() {
return;
}
self.tiled_panes.move_pane_left(pane_id);
}
}
fn close_down_to_max_terminals(&mut self) -> Result<()> { fn close_down_to_max_terminals(&mut self) -> Result<()> {
if let Some(max_panes) = self.max_panes { if let Some(max_panes) = self.max_panes {
let terminals = self.get_tiled_pane_ids(); let terminals = self.get_tiled_pane_ids();
@ -2744,6 +2905,11 @@ impl Tab {
} }
Ok(()) Ok(())
} }
pub fn clear_screen_for_pane_id(&mut self, pane_id: PaneId) {
if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
pane.clear_screen();
}
}
pub fn dump_active_terminal_screen( pub fn dump_active_terminal_screen(
&mut self, &mut self,
file: Option<String>, file: Option<String>,
@ -2754,13 +2920,25 @@ impl Tab {
|| format!("failed to dump active terminal screen for client {client_id}"); || format!("failed to dump active terminal screen for client {client_id}");
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) { if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
let dump = active_pane.dump_screen(client_id, full); let dump = active_pane.dump_screen(full);
self.os_api self.os_api
.write_to_file(dump, file) .write_to_file(dump, file)
.with_context(err_context)?; .with_context(err_context)?;
} }
Ok(()) Ok(())
} }
pub fn dump_terminal_screen(
&mut self,
file: Option<String>,
pane_id: PaneId,
full: bool,
) -> Result<()> {
if let Some(pane) = self.get_pane_with_id(pane_id) {
let dump = pane.dump_screen(full);
self.os_api.write_to_file(dump, file).non_fatal()
}
Ok(())
}
pub fn edit_scrollback(&mut self, client_id: ClientId) -> Result<()> { pub fn edit_scrollback(&mut self, client_id: ClientId) -> Result<()> {
let err_context = || format!("failed to edit scrollback for client {client_id}"); let err_context = || format!("failed to edit scrollback for client {client_id}");
@ -2779,16 +2957,44 @@ impl Tab {
.send_to_pty(PtyInstruction::OpenInPlaceEditor( .send_to_pty(PtyInstruction::OpenInPlaceEditor(
file, file,
line_number, line_number,
client_id, ClientTabIndexOrPaneId::ClientId(client_id),
)) ))
.with_context(err_context) .with_context(err_context)
} }
pub fn edit_scrollback_for_pane_with_id(&mut self, pane_id: PaneId) -> Result<()> {
if let PaneId::Terminal(_terminal_pane_id) = pane_id {
let mut file = temp_dir();
file.push(format!("{}.dump", Uuid::new_v4()));
self.dump_terminal_screen(Some(String::from(file.to_string_lossy())), pane_id, true)
.non_fatal();
let line_number = self
.get_pane_with_id(pane_id)
.and_then(|a_t| a_t.get_line_number());
self.senders.send_to_pty(PtyInstruction::OpenInPlaceEditor(
file,
line_number,
ClientTabIndexOrPaneId::PaneId(pane_id),
))
} else {
log::error!("Editing plugin pane scrollback is currently unsupported.");
Ok(())
}
}
pub fn scroll_active_terminal_up(&mut self, client_id: ClientId) { 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) { if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
active_pane.scroll_up(1, client_id); active_pane.scroll_up(1, client_id);
} }
} }
pub fn scroll_terminal_up(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
terminal_pane.scroll_up(1, fictitious_client_id);
}
}
pub fn scroll_active_terminal_down(&mut self, client_id: ClientId) -> Result<()> { pub fn scroll_active_terminal_down(&mut self, client_id: ClientId) -> Result<()> {
let err_context = || format!("failed to scroll down active pane for client {client_id}"); let err_context = || format!("failed to scroll down active pane for client {client_id}");
@ -2804,14 +3010,34 @@ impl Tab {
Ok(()) Ok(())
} }
pub fn scroll_terminal_down(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
terminal_pane.scroll_down(1, fictitious_client_id);
}
}
pub fn scroll_active_terminal_up_page(&mut self, client_id: ClientId) { pub fn scroll_active_terminal_up_page(&mut self, client_id: ClientId) {
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) { if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
// prevent overflow when row == 0 // prevent overflow when row == 0
let scroll_rows = active_pane.rows().max(1) - 1; let scroll_rows = active_pane.rows().max(1).saturating_sub(1);
active_pane.scroll_up(scroll_rows, client_id); active_pane.scroll_up(scroll_rows, client_id);
} }
} }
pub fn scroll_terminal_page_up(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
// prevent overflow when row == 0
let scroll_rows = terminal_pane.rows().max(1).saturating_sub(1);
terminal_pane.scroll_up(scroll_rows, fictitious_client_id);
}
}
pub fn scroll_active_terminal_down_page(&mut self, client_id: ClientId) -> Result<()> { pub fn scroll_active_terminal_down_page(&mut self, client_id: ClientId) -> Result<()> {
let err_context = let err_context =
|| format!("failed to scroll down one page in active pane for client {client_id}"); || format!("failed to scroll down one page in active pane for client {client_id}");
@ -2829,14 +3055,40 @@ impl Tab {
Ok(()) Ok(())
} }
pub fn scroll_terminal_page_down(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
let scroll_rows = terminal_pane.get_content_rows();
terminal_pane.scroll_down(scroll_rows, fictitious_client_id);
if !terminal_pane.is_scrolled() {
if let PaneId::Terminal(raw_fd) = terminal_pane.pid() {
self.process_pending_vte_events(raw_fd).non_fatal()
}
}
}
}
pub fn scroll_active_terminal_up_half_page(&mut self, client_id: ClientId) { pub fn scroll_active_terminal_up_half_page(&mut self, client_id: ClientId) {
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) { if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
// prevent overflow when row == 0 // prevent overflow when row == 0
let scroll_rows = (active_pane.rows().max(1) - 1) / 2; let scroll_rows = (active_pane.rows().max(1).saturating_sub(1)) / 2;
active_pane.scroll_up(scroll_rows, client_id); active_pane.scroll_up(scroll_rows, client_id);
} }
} }
pub fn scroll_terminal_half_page_up(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
// prevent overflow when row == 0
let scroll_rows = (terminal_pane.rows().max(1).saturating_sub(1)) / 2;
terminal_pane.scroll_down(scroll_rows, fictitious_client_id);
}
}
pub fn scroll_active_terminal_down_half_page(&mut self, client_id: ClientId) -> Result<()> { pub fn scroll_active_terminal_down_half_page(&mut self, client_id: ClientId) -> Result<()> {
let err_context = let err_context =
|| format!("failed to scroll down half a page in active pane for client {client_id}"); || format!("failed to scroll down half a page in active pane for client {client_id}");
@ -2854,6 +3106,21 @@ impl Tab {
Ok(()) Ok(())
} }
pub fn scroll_terminal_half_page_down(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
let scroll_rows = (terminal_pane.rows().max(1) - 1) / 2;
terminal_pane.scroll_down(scroll_rows, fictitious_client_id);
if !terminal_pane.is_scrolled() {
if let PaneId::Terminal(raw_fd) = terminal_pane.pid() {
self.process_pending_vte_events(raw_fd).non_fatal();
}
}
}
}
pub fn scroll_active_terminal_to_bottom(&mut self, client_id: ClientId) -> Result<()> { pub fn scroll_active_terminal_to_bottom(&mut self, client_id: ClientId) -> Result<()> {
let err_context = let err_context =
|| format!("failed to scroll to bottom in active pane for client {client_id}"); || format!("failed to scroll to bottom in active pane for client {client_id}");
@ -2870,6 +3137,17 @@ impl Tab {
Ok(()) Ok(())
} }
pub fn scroll_terminal_to_bottom(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
terminal_pane.clear_scroll();
if !terminal_pane.is_scrolled() {
if let PaneId::Terminal(raw_fd) = terminal_pane.pid() {
self.process_pending_vte_events(raw_fd).non_fatal();
}
}
}
}
pub fn scroll_active_terminal_to_top(&mut self, client_id: ClientId) -> Result<()> { pub fn scroll_active_terminal_to_top(&mut self, client_id: ClientId) -> Result<()> {
if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) { if let Some(active_pane) = self.get_active_pane_or_floating_pane_mut(client_id) {
active_pane.clear_scroll(); active_pane.clear_scroll();
@ -2880,6 +3158,18 @@ impl Tab {
Ok(()) Ok(())
} }
pub fn scroll_terminal_to_top(&mut self, terminal_pane_id: u32) {
if let Some(terminal_pane) = self.get_pane_with_id_mut(PaneId::Terminal(terminal_pane_id)) {
terminal_pane.clear_scroll();
if let Some(size) = terminal_pane.get_line_number() {
let fictitious_client_id = 1; // this is not checked for terminal panes and we
// don't have an actual client id here
// TODO: traits were a mistake
terminal_pane.scroll_up(size, fictitious_client_id);
}
}
}
pub fn clear_active_terminal_scroll(&mut self, client_id: ClientId) -> Result<()> { pub fn clear_active_terminal_scroll(&mut self, client_id: ClientId) -> Result<()> {
// TODO: is this a thing? // TODO: is this a thing?
let err_context = let err_context =
@ -3954,6 +4244,50 @@ impl Tab {
}, },
} }
} }
pub fn resize_pane_with_id(&mut self, strategy: ResizeStrategy, pane_id: PaneId) -> Result<()> {
let err_context = || format!("unable to resize pane");
if self.floating_panes.panes_contain(&pane_id) {
let successfully_resized = self
.floating_panes
.resize_pane_with_id(strategy, pane_id)
.with_context(err_context)?;
if successfully_resized {
self.swap_layouts.set_is_floating_damaged();
self.swap_layouts.set_is_tiled_damaged();
self.set_force_render(); // we force render here to make sure the panes under the floating pane render and don't leave "garbage" in case of a decrease
}
} else if self.tiled_panes.panes_contain(&pane_id) {
match self.tiled_panes.resize_pane_with_id(strategy, pane_id) {
Ok(_) => {},
Err(err) => match err.downcast_ref::<ZellijError>() {
Some(ZellijError::CantResizeFixedPanes { pane_ids }) => {
let mut pane_ids_to_error = vec![];
for (id, is_terminal) in pane_ids {
if *is_terminal {
pane_ids_to_error.push(PaneId::Terminal(*id));
} else {
pane_ids_to_error.push(PaneId::Plugin(*id));
};
}
self.senders
.send_to_background_jobs(BackgroundJob::DisplayPaneError(
pane_ids_to_error,
"FIXED!".into(),
))
.with_context(err_context)?;
},
_ => Err::<(), _>(err).fatal(),
},
}
} else if self
.suppressed_panes
.values()
.any(|s_p| s_p.1.pid() == pane_id)
{
log::error!("Cannot resize suppressed panes");
}
Ok(())
}
pub fn update_theme(&mut self, theme: Palette) { pub fn update_theme(&mut self, theme: Palette) {
self.style.colors = theme; self.style.colors = theme;
self.floating_panes.update_pane_themes(theme); self.floating_panes.update_pane_themes(theme);
@ -3995,6 +4329,42 @@ impl Tab {
pub fn update_auto_layout(&mut self, auto_layout: bool) { pub fn update_auto_layout(&mut self, auto_layout: bool) {
self.auto_layout = auto_layout; self.auto_layout = auto_layout;
} }
fn new_scrollback_editor_pane(&self, pid: u32) -> TerminalPane {
let next_terminal_position = self.get_next_terminal_position();
let mut 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.sixel_image_store.clone(),
self.terminal_emulator_colors.clone(),
self.terminal_emulator_color_codes.clone(),
None,
None,
self.debug,
self.arrow_fonts,
self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol,
);
new_pane.update_name("EDITING SCROLLBACK"); // we do this here and not in the
// constructor so it won't be overrided
// by the editor
new_pane
}
fn insert_scrollback_editor_replaced_pane(
&mut self,
replaced_pane: Box<dyn Pane>,
terminal_pane_id: u32,
) {
let is_scrollback_editor = true;
self.suppressed_panes.insert(
PaneId::Terminal(terminal_pane_id),
(is_scrollback_editor, replaced_pane),
);
}
} }
pub fn pane_info_for_pane(pane_id: &PaneId, pane: &Box<dyn Pane>) -> PaneInfo { pub fn pane_info_for_pane(pane_id: &PaneId, pane: &Box<dyn Pane>) -> PaneInfo {

View file

@ -29,7 +29,10 @@ use std::env::set_var;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::{plugins::PluginInstruction, pty::PtyInstruction}; use crate::{
plugins::PluginInstruction,
pty::{ClientTabIndexOrPaneId, PtyInstruction},
};
use zellij_utils::ipc::PixelDimensions; use zellij_utils::ipc::PixelDimensions;
use zellij_utils::{ use zellij_utils::{
@ -1699,7 +1702,7 @@ pub fn send_cli_edit_scrollback_action() {
{ {
assert_eq!(scrollback_contents_file, &PathBuf::from(&dumped_file_name)); assert_eq!(scrollback_contents_file, &PathBuf::from(&dumped_file_name));
assert_eq!(terminal_id, &Some(1)); assert_eq!(terminal_id, &Some(1));
assert_eq!(client_id, &1); assert_eq!(client_id, &ClientTabIndexOrPaneId::ClientId(1));
found_instruction = true; found_instruction = true;
} }
} }

View file

@ -857,6 +857,179 @@ pub fn rerun_command_pane(terminal_pane_id: u32) {
unsafe { host_run_plugin_command() }; unsafe { host_run_plugin_command() };
} }
/// Sugar for close_terminal_pane and close_plugin_pane
pub fn close_pane_with_id(pane_id: PaneId) {
let plugin_command = match pane_id {
PaneId::Terminal(terminal_pane_id) => PluginCommand::CloseTerminalPane(terminal_pane_id),
PaneId::Plugin(plugin_pane_id) => PluginCommand::ClosePluginPane(plugin_pane_id),
};
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Resize the specified pane (increase/decrease) with an optional direction (left/right/up/down)
pub fn resize_pane_with_id(resize_strategy: ResizeStrategy, pane_id: PaneId) {
let plugin_command = PluginCommand::ResizePaneIdWithDirection(resize_strategy, pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Changes the focus to the pane with the specified id, unsuppressing it if it was suppressed and switching to its tab and layer (eg. floating/tiled).
pub fn focus_pane_with_id(pane_id: PaneId, should_float_if_hidden: bool) {
let plugin_command = match pane_id {
PaneId::Terminal(terminal_pane_id) => {
PluginCommand::FocusTerminalPane(terminal_pane_id, should_float_if_hidden)
},
PaneId::Plugin(plugin_pane_id) => {
PluginCommand::FocusPluginPane(plugin_pane_id, should_float_if_hidden)
},
};
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Edit the scrollback of the specified pane in the user's default `$EDITOR` (currently only works
/// for terminal panes)
pub fn edit_scrollback_for_pane_with_id(pane_id: PaneId) {
let plugin_command = PluginCommand::EditScrollbackForPaneWithId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Write bytes to the `STDIN` of the specified pane
pub fn write_to_pane_id(bytes: Vec<u8>, pane_id: PaneId) {
let plugin_command = PluginCommand::WriteToPaneId(bytes, pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Write characters to the `STDIN` of the specified pane
pub fn write_chars_to_pane_id(chars: &str, pane_id: PaneId) {
let plugin_command = PluginCommand::WriteCharsToPaneId(chars.to_owned(), pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Switch the position of the pane with this id with a different pane
pub fn move_pane_with_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::MovePaneWithPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Switch the position of the pane with this id with a different pane in the specified direction (eg. `Down`, `Up`, `Left`, `Right`).
pub fn move_pane_with_pane_id_in_direction(pane_id: PaneId, direction: Direction) {
let plugin_command = PluginCommand::MovePaneWithPaneIdInDirection(pane_id, direction);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Clear the scroll buffer of the specified pane
pub fn clear_screen_for_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::ClearScreenForPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane up 1 line
pub fn scroll_up_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::ScrollUpInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane down 1 line
pub fn scroll_down_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::ScrollDownInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane all the way to the top of the scrollbuffer
pub fn scroll_to_top_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::ScrollToTopInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane all the way to the bottom of the scrollbuffer
pub fn scroll_to_bottom_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::ScrollToBottomInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane up one page
pub fn page_scroll_up_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::PageScrollUpInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Scroll the specified pane down one page
pub fn page_scroll_down_in_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::PageScrollDownInPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Toggle the specified pane to be fullscreen or normal sized
pub fn toggle_pane_id_fullscreen(pane_id: PaneId) {
let plugin_command = PluginCommand::TogglePaneIdFullscreen(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Embed the specified pane (make it stop floating) or turn it to a float pane if it is not
pub fn toggle_pane_embed_or_eject_for_pane_id(pane_id: PaneId) {
let plugin_command = PluginCommand::TogglePaneEmbedOrEjectForPaneId(pane_id);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Close the focused tab
pub fn close_tab_with_index(tab_index: usize) {
let plugin_command = PluginCommand::CloseTabWithIndex(tab_index);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Rename the specified pane
pub fn rename_pane_with_id<S: AsRef<str>>(pane_id: PaneId, new_name: S)
where
S: ToString,
{
let plugin_command = match pane_id {
PaneId::Terminal(terminal_pane_id) => {
PluginCommand::RenameTerminalPane(terminal_pane_id, new_name.to_string())
},
PaneId::Plugin(plugin_pane_id) => {
PluginCommand::RenamePluginPane(plugin_pane_id, new_name.to_string())
},
};
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 // Utility Functions
#[allow(unused)] #[allow(unused)]

View file

@ -5,7 +5,7 @@ pub struct PluginCommand {
pub name: i32, pub name: i32,
#[prost( #[prost(
oneof = "plugin_command::Payload", oneof = "plugin_command::Payload",
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67" tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83"
)] )]
pub payload: ::core::option::Option<plugin_command::Payload>, pub payload: ::core::option::Option<plugin_command::Payload>,
} }
@ -128,10 +128,150 @@ pub mod plugin_command {
OpenCommandPaneBackgroundPayload(super::OpenCommandPanePayload), OpenCommandPaneBackgroundPayload(super::OpenCommandPanePayload),
#[prost(message, tag = "67")] #[prost(message, tag = "67")]
RerunCommandPanePayload(super::RerunCommandPanePayload), RerunCommandPanePayload(super::RerunCommandPanePayload),
#[prost(message, tag = "68")]
ResizePaneIdWithDirectionPayload(super::ResizePaneIdWithDirectionPayload),
#[prost(message, tag = "69")]
EditScrollbackForPaneWithIdPayload(super::EditScrollbackForPaneWithIdPayload),
#[prost(message, tag = "70")]
WriteToPaneIdPayload(super::WriteToPaneIdPayload),
#[prost(message, tag = "71")]
WriteCharsToPaneIdPayload(super::WriteCharsToPaneIdPayload),
#[prost(message, tag = "72")]
MovePaneWithPaneIdPayload(super::MovePaneWithPaneIdPayload),
#[prost(message, tag = "73")]
MovePaneWithPaneIdInDirectionPayload(
super::MovePaneWithPaneIdInDirectionPayload,
),
#[prost(message, tag = "74")]
ClearScreenForPaneIdPayload(super::ClearScreenForPaneIdPayload),
#[prost(message, tag = "75")]
ScrollUpInPaneIdPayload(super::ScrollUpInPaneIdPayload),
#[prost(message, tag = "76")]
ScrollDownInPaneIdPayload(super::ScrollDownInPaneIdPayload),
#[prost(message, tag = "77")]
ScrollToTopInPaneIdPayload(super::ScrollToTopInPaneIdPayload),
#[prost(message, tag = "78")]
ScrollToBottomInPaneIdPayload(super::ScrollToBottomInPaneIdPayload),
#[prost(message, tag = "79")]
PageScrollUpInPaneIdPayload(super::PageScrollUpInPaneIdPayload),
#[prost(message, tag = "80")]
PageScrollDownInPaneIdPayload(super::PageScrollDownInPaneIdPayload),
#[prost(message, tag = "81")]
TogglePaneIdFullscreenPayload(super::TogglePaneIdFullscreenPayload),
#[prost(message, tag = "82")]
TogglePaneEmbedOrEjectForPaneIdPayload(
super::TogglePaneEmbedOrEjectForPaneIdPayload,
),
#[prost(message, tag = "83")]
CloseTabWithIndexPayload(super::CloseTabWithIndexPayload),
} }
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct MovePaneWithPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct MovePaneWithPaneIdInDirectionPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
#[prost(message, optional, tag = "2")]
pub direction: ::core::option::Option<super::resize::MoveDirection>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ClearScreenForPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScrollUpInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScrollDownInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScrollToTopInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ScrollToBottomInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PageScrollUpInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PageScrollDownInPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TogglePaneIdFullscreenPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TogglePaneEmbedOrEjectForPaneIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CloseTabWithIndexPayload {
#[prost(uint32, tag = "1")]
pub tab_index: u32,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WriteCharsToPaneIdPayload {
#[prost(string, tag = "1")]
pub chars_to_write: ::prost::alloc::string::String,
#[prost(message, optional, tag = "2")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WriteToPaneIdPayload {
#[prost(bytes = "vec", tag = "1")]
pub bytes_to_write: ::prost::alloc::vec::Vec<u8>,
#[prost(message, optional, tag = "2")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EditScrollbackForPaneWithIdPayload {
#[prost(message, optional, tag = "1")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ResizePaneIdWithDirectionPayload {
#[prost(message, optional, tag = "1")]
pub resize: ::core::option::Option<super::resize::Resize>,
#[prost(message, optional, tag = "2")]
pub pane_id: ::core::option::Option<PaneId>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ReconfigurePayload { pub struct ReconfigurePayload {
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub config: ::prost::alloc::string::String, pub config: ::prost::alloc::string::String,
@ -478,6 +618,22 @@ pub enum CommandName {
ShowPaneWithId = 89, ShowPaneWithId = 89,
OpenCommandPaneBackground = 90, OpenCommandPaneBackground = 90,
RerunCommandPane = 91, RerunCommandPane = 91,
ResizePaneIdWithDirection = 92,
EditScrollbackForPaneWithId = 93,
WriteToPaneId = 94,
WriteCharsToPaneId = 95,
MovePaneWithPaneId = 96,
MovePaneWithPaneIdInDirection = 97,
ClearScreenForPaneId = 98,
ScrollUpInPaneId = 99,
ScrollDownInPaneId = 100,
ScrollToTopInPaneId = 101,
ScrollToBottomInPaneId = 102,
PageScrollUpInPaneId = 103,
PageScrollDownInPaneId = 104,
TogglePaneIdFullscreen = 105,
TogglePaneEmbedOrEjectForPaneId = 106,
CloseTabWithIndex = 107,
} }
impl CommandName { impl CommandName {
/// String value of the enum field names used in the ProtoBuf definition. /// String value of the enum field names used in the ProtoBuf definition.
@ -578,6 +734,24 @@ impl CommandName {
CommandName::ShowPaneWithId => "ShowPaneWithId", CommandName::ShowPaneWithId => "ShowPaneWithId",
CommandName::OpenCommandPaneBackground => "OpenCommandPaneBackground", CommandName::OpenCommandPaneBackground => "OpenCommandPaneBackground",
CommandName::RerunCommandPane => "RerunCommandPane", CommandName::RerunCommandPane => "RerunCommandPane",
CommandName::ResizePaneIdWithDirection => "ResizePaneIdWithDirection",
CommandName::EditScrollbackForPaneWithId => "EditScrollbackForPaneWithId",
CommandName::WriteToPaneId => "WriteToPaneId",
CommandName::WriteCharsToPaneId => "WriteCharsToPaneId",
CommandName::MovePaneWithPaneId => "MovePaneWithPaneId",
CommandName::MovePaneWithPaneIdInDirection => "MovePaneWithPaneIdInDirection",
CommandName::ClearScreenForPaneId => "ClearScreenForPaneId",
CommandName::ScrollUpInPaneId => "ScrollUpInPaneId",
CommandName::ScrollDownInPaneId => "ScrollDownInPaneId",
CommandName::ScrollToTopInPaneId => "ScrollToTopInPaneId",
CommandName::ScrollToBottomInPaneId => "ScrollToBottomInPaneId",
CommandName::PageScrollUpInPaneId => "PageScrollUpInPaneId",
CommandName::PageScrollDownInPaneId => "PageScrollDownInPaneId",
CommandName::TogglePaneIdFullscreen => "TogglePaneIdFullscreen",
CommandName::TogglePaneEmbedOrEjectForPaneId => {
"TogglePaneEmbedOrEjectForPaneId"
}
CommandName::CloseTabWithIndex => "CloseTabWithIndex",
} }
} }
/// Creates an enum from field names used in the ProtoBuf definition. /// Creates an enum from field names used in the ProtoBuf definition.
@ -675,6 +849,24 @@ impl CommandName {
"ShowPaneWithId" => Some(Self::ShowPaneWithId), "ShowPaneWithId" => Some(Self::ShowPaneWithId),
"OpenCommandPaneBackground" => Some(Self::OpenCommandPaneBackground), "OpenCommandPaneBackground" => Some(Self::OpenCommandPaneBackground),
"RerunCommandPane" => Some(Self::RerunCommandPane), "RerunCommandPane" => Some(Self::RerunCommandPane),
"ResizePaneIdWithDirection" => Some(Self::ResizePaneIdWithDirection),
"EditScrollbackForPaneWithId" => Some(Self::EditScrollbackForPaneWithId),
"WriteToPaneId" => Some(Self::WriteToPaneId),
"WriteCharsToPaneId" => Some(Self::WriteCharsToPaneId),
"MovePaneWithPaneId" => Some(Self::MovePaneWithPaneId),
"MovePaneWithPaneIdInDirection" => Some(Self::MovePaneWithPaneIdInDirection),
"ClearScreenForPaneId" => Some(Self::ClearScreenForPaneId),
"ScrollUpInPaneId" => Some(Self::ScrollUpInPaneId),
"ScrollDownInPaneId" => Some(Self::ScrollDownInPaneId),
"ScrollToTopInPaneId" => Some(Self::ScrollToTopInPaneId),
"ScrollToBottomInPaneId" => Some(Self::ScrollToBottomInPaneId),
"PageScrollUpInPaneId" => Some(Self::PageScrollUpInPaneId),
"PageScrollDownInPaneId" => Some(Self::PageScrollDownInPaneId),
"TogglePaneIdFullscreen" => Some(Self::TogglePaneIdFullscreen),
"TogglePaneEmbedOrEjectForPaneId" => {
Some(Self::TogglePaneEmbedOrEjectForPaneId)
}
"CloseTabWithIndex" => Some(Self::CloseTabWithIndex),
_ => None, _ => None,
} }
} }

View file

@ -1820,4 +1820,20 @@ pub enum PluginCommand {
ShowPaneWithId(PaneId, bool), // bool -> should_float_if_hidden ShowPaneWithId(PaneId, bool), // bool -> should_float_if_hidden
OpenCommandPaneBackground(CommandToRun, Context), OpenCommandPaneBackground(CommandToRun, Context),
RerunCommandPane(u32), // u32 - terminal pane id RerunCommandPane(u32), // u32 - terminal pane id
ResizePaneIdWithDirection(ResizeStrategy, PaneId),
EditScrollbackForPaneWithId(PaneId),
WriteToPaneId(Vec<u8>, PaneId),
WriteCharsToPaneId(String, PaneId),
MovePaneWithPaneId(PaneId),
MovePaneWithPaneIdInDirection(PaneId, Direction),
ClearScreenForPaneId(PaneId),
ScrollUpInPaneId(PaneId),
ScrollDownInPaneId(PaneId),
ScrollToTopInPaneId(PaneId),
ScrollToBottomInPaneId(PaneId),
PageScrollUpInPaneId(PaneId),
PageScrollDownInPaneId(PaneId),
TogglePaneIdFullscreen(PaneId),
TogglePaneEmbedOrEjectForPaneId(PaneId),
CloseTabWithIndex(usize), // usize - tab_index
} }

View file

@ -355,6 +355,21 @@ pub enum ScreenContext {
ListClientsMetadata, ListClientsMetadata,
Reconfigure, Reconfigure,
RerunCommandPane, RerunCommandPane,
ResizePaneWithId,
EditScrollbackForPaneWithId,
WriteToPaneId,
MovePaneWithPaneId,
MovePaneWithPaneIdInDirection,
ClearScreenForPaneId,
ScrollUpInPaneId,
ScrollDownInPaneId,
ScrollToTopInPaneId,
ScrollToBottomInPaneId,
PageScrollUpInPaneId,
PageScrollDownInPaneId,
TogglePaneIdFullscreen,
TogglePaneEmbedOrEjectForPaneId,
CloseTabWithIndex,
} }
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s. /// Stack call representations corresponding to the different types of [`PtyInstruction`]s.

View file

@ -103,6 +103,22 @@ enum CommandName {
ShowPaneWithId = 89; ShowPaneWithId = 89;
OpenCommandPaneBackground = 90; OpenCommandPaneBackground = 90;
RerunCommandPane = 91; RerunCommandPane = 91;
ResizePaneIdWithDirection = 92;
EditScrollbackForPaneWithId = 93;
WriteToPaneId = 94;
WriteCharsToPaneId = 95;
MovePaneWithPaneId = 96;
MovePaneWithPaneIdInDirection = 97;
ClearScreenForPaneId = 98;
ScrollUpInPaneId = 99;
ScrollDownInPaneId = 100;
ScrollToTopInPaneId = 101;
ScrollToBottomInPaneId = 102;
PageScrollUpInPaneId = 103;
PageScrollDownInPaneId = 104;
TogglePaneIdFullscreen = 105;
TogglePaneEmbedOrEjectForPaneId = 106;
CloseTabWithIndex = 107;
} }
message PluginCommand { message PluginCommand {
@ -165,9 +181,93 @@ message PluginCommand {
ShowPaneWithIdPayload show_pane_with_id_payload = 65; ShowPaneWithIdPayload show_pane_with_id_payload = 65;
OpenCommandPanePayload open_command_pane_background_payload = 66; OpenCommandPanePayload open_command_pane_background_payload = 66;
RerunCommandPanePayload rerun_command_pane_payload = 67; RerunCommandPanePayload rerun_command_pane_payload = 67;
ResizePaneIdWithDirectionPayload resize_pane_id_with_direction_payload = 68;
EditScrollbackForPaneWithIdPayload edit_scrollback_for_pane_with_id_payload = 69;
WriteToPaneIdPayload write_to_pane_id_payload = 70;
WriteCharsToPaneIdPayload write_chars_to_pane_id_payload = 71;
MovePaneWithPaneIdPayload move_pane_with_pane_id_payload = 72;
MovePaneWithPaneIdInDirectionPayload move_pane_with_pane_id_in_direction_payload = 73;
ClearScreenForPaneIdPayload clear_screen_for_pane_id_payload = 74;
ScrollUpInPaneIdPayload scroll_up_in_pane_id_payload = 75;
ScrollDownInPaneIdPayload scroll_down_in_pane_id_payload = 76;
ScrollToTopInPaneIdPayload scroll_to_top_in_pane_id_payload = 77;
ScrollToBottomInPaneIdPayload scroll_to_bottom_in_pane_id_payload = 78;
PageScrollUpInPaneIdPayload page_scroll_up_in_pane_id_payload = 79;
PageScrollDownInPaneIdPayload page_scroll_down_in_pane_id_payload = 80;
TogglePaneIdFullscreenPayload toggle_pane_id_fullscreen_payload = 81;
TogglePaneEmbedOrEjectForPaneIdPayload toggle_pane_embed_or_eject_for_pane_id_payload = 82;
CloseTabWithIndexPayload close_tab_with_index_payload = 83;
} }
} }
message MovePaneWithPaneIdPayload {
PaneId pane_id = 1;
}
message MovePaneWithPaneIdInDirectionPayload {
PaneId pane_id = 1;
resize.MoveDirection direction = 2;
}
message ClearScreenForPaneIdPayload {
PaneId pane_id = 1;
}
message ScrollUpInPaneIdPayload {
PaneId pane_id = 1;
}
message ScrollDownInPaneIdPayload {
PaneId pane_id = 1;
}
message ScrollToTopInPaneIdPayload {
PaneId pane_id = 1;
}
message ScrollToBottomInPaneIdPayload {
PaneId pane_id = 1;
}
message PageScrollUpInPaneIdPayload {
PaneId pane_id = 1;
}
message PageScrollDownInPaneIdPayload {
PaneId pane_id = 1;
}
message TogglePaneIdFullscreenPayload {
PaneId pane_id = 1;
}
message TogglePaneEmbedOrEjectForPaneIdPayload {
PaneId pane_id = 1;
}
message CloseTabWithIndexPayload {
uint32 tab_index = 1;
}
message WriteCharsToPaneIdPayload {
string chars_to_write = 1;
PaneId pane_id = 2;
}
message WriteToPaneIdPayload {
bytes bytes_to_write = 1;
PaneId pane_id = 2;
}
message EditScrollbackForPaneWithIdPayload {
PaneId pane_id = 1;
}
message ResizePaneIdWithDirectionPayload {
resize.Resize resize = 1;
PaneId pane_id = 2;
}
message ReconfigurePayload { message ReconfigurePayload {
string config = 1; string config = 1;
bool write_to_disk = 2; bool write_to_disk = 2;

View file

@ -3,17 +3,23 @@ pub use super::generated_api::api::{
event::{EventNameList as ProtobufEventNameList, Header}, event::{EventNameList as ProtobufEventNameList, Header},
input_mode::InputMode as ProtobufInputMode, input_mode::InputMode as ProtobufInputMode,
plugin_command::{ plugin_command::{
plugin_command::Payload, CliPipeOutputPayload, CommandName, ContextItem, EnvVariable, plugin_command::Payload, ClearScreenForPaneIdPayload, CliPipeOutputPayload,
ExecCmdPayload, FixedOrPercent as ProtobufFixedOrPercent, CloseTabWithIndexPayload, CommandName, ContextItem, EditScrollbackForPaneWithIdPayload,
EnvVariable, ExecCmdPayload, FixedOrPercent as ProtobufFixedOrPercent,
FixedOrPercentValue as ProtobufFixedOrPercentValue, FixedOrPercentValue as ProtobufFixedOrPercentValue,
FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload, FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload,
HttpVerb as ProtobufHttpVerb, IdAndNewName, KillSessionsPayload, MessageToPluginPayload, HttpVerb as ProtobufHttpVerb, IdAndNewName, KillSessionsPayload, MessageToPluginPayload,
MovePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload, MovePaneWithPaneIdInDirectionPayload, MovePaneWithPaneIdPayload, MovePayload,
OpenCommandPanePayload, OpenFilePayload, PaneId as ProtobufPaneId, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload,
PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload, OpenCommandPanePayload, OpenFilePayload, PageScrollDownInPaneIdPayload,
ReconfigurePayload, RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePayload, PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId, PaneType as ProtobufPaneType,
RunCommandPayload, SetTimeoutPayload, ShowPaneWithIdPayload, SubscribePayload, PluginCommand as ProtobufPluginCommand, PluginMessagePayload, ReconfigurePayload,
SwitchSessionPayload, SwitchTabToPayload, UnsubscribePayload, WebRequestPayload, RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePaneIdWithDirectionPayload,
ResizePayload, RunCommandPayload, ScrollDownInPaneIdPayload, ScrollToBottomInPaneIdPayload,
ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload, SetTimeoutPayload,
ShowPaneWithIdPayload, SubscribePayload, SwitchSessionPayload, SwitchTabToPayload,
TogglePaneEmbedOrEjectForPaneIdPayload, TogglePaneIdFullscreenPayload, UnsubscribePayload,
WebRequestPayload, WriteCharsToPaneIdPayload, WriteToPaneIdPayload,
}, },
plugin_permission::PermissionType as ProtobufPermissionType, plugin_permission::PermissionType as ProtobufPermissionType,
resize::ResizeAction as ProtobufResizeAction, resize::ResizeAction as ProtobufResizeAction,
@ -991,6 +997,183 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
), ),
_ => Err("Mismatched payload for RerunCommandPane"), _ => Err("Mismatched payload for RerunCommandPane"),
}, },
Some(CommandName::ResizePaneIdWithDirection) => match protobuf_plugin_command.payload {
Some(Payload::ResizePaneIdWithDirectionPayload(resize_with_direction_payload)) => {
match (
resize_with_direction_payload.resize,
resize_with_direction_payload.pane_id,
) {
(Some(resize), Some(pane_id)) => {
Ok(PluginCommand::ResizePaneIdWithDirection(
resize.try_into()?,
pane_id.try_into()?,
))
},
_ => Err("Malformed resize_pane_with_id payload"),
}
},
_ => Err("Mismatched payload for Resize"),
},
Some(CommandName::EditScrollbackForPaneWithId) => match protobuf_plugin_command.payload
{
Some(Payload::EditScrollbackForPaneWithIdPayload(
edit_scrollback_for_pane_with_id_payload,
)) => match edit_scrollback_for_pane_with_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::EditScrollbackForPaneWithId(
pane_id.try_into()?,
)),
_ => Err("Malformed edit_scrollback_for_pane_with_id payload"),
},
_ => Err("Mismatched payload for EditScrollback"),
},
Some(CommandName::WriteToPaneId) => match protobuf_plugin_command.payload {
Some(Payload::WriteToPaneIdPayload(write_to_pane_id_payload)) => {
match write_to_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::WriteToPaneId(
write_to_pane_id_payload.bytes_to_write,
pane_id.try_into()?,
)),
_ => Err("Malformed write_to_pane_id payload"),
}
},
_ => Err("Mismatched payload for WriteToPaneId"),
},
Some(CommandName::WriteCharsToPaneId) => match protobuf_plugin_command.payload {
Some(Payload::WriteCharsToPaneIdPayload(write_chars_to_pane_id_payload)) => {
match write_chars_to_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::WriteCharsToPaneId(
write_chars_to_pane_id_payload.chars_to_write,
pane_id.try_into()?,
)),
_ => Err("Malformed write_chars_to_pane_id payload"),
}
},
_ => Err("Mismatched payload for WriteCharsCharsToPaneId"),
},
Some(CommandName::MovePaneWithPaneId) => match protobuf_plugin_command.payload {
Some(Payload::MovePaneWithPaneIdPayload(move_pane_with_pane_id_payload)) => {
match move_pane_with_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::MovePaneWithPaneId(pane_id.try_into()?)),
_ => Err("Malformed move_pane_with_pane_id payload"),
}
},
_ => Err("Mismatched payload for MovePaneWithPaneId"),
},
Some(CommandName::MovePaneWithPaneIdInDirection) => {
match protobuf_plugin_command.payload {
Some(Payload::MovePaneWithPaneIdInDirectionPayload(move_payload)) => {
match (move_payload.direction, move_payload.pane_id) {
(Some(direction), Some(pane_id)) => {
Ok(PluginCommand::MovePaneWithPaneIdInDirection(
pane_id.try_into()?,
direction.try_into()?,
))
},
_ => Err("Malformed MovePaneWithPaneIdInDirection payload"),
}
},
_ => Err("Mismatched payload for MovePaneWithDirection"),
}
},
Some(CommandName::ClearScreenForPaneId) => match protobuf_plugin_command.payload {
Some(Payload::ClearScreenForPaneIdPayload(clear_screen_for_pane_id_payload)) => {
match clear_screen_for_pane_id_payload.pane_id {
Some(pane_id) => {
Ok(PluginCommand::ClearScreenForPaneId(pane_id.try_into()?))
},
_ => Err("Malformed clear_screen_for_pane_id_payload payload"),
}
},
_ => Err("Mismatched payload for ClearScreenForPaneId"),
},
Some(CommandName::ScrollUpInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::ScrollUpInPaneIdPayload(scroll_up_in_pane_id_payload)) => {
match scroll_up_in_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::ScrollUpInPaneId(pane_id.try_into()?)),
_ => Err("Malformed scroll_up_in_pane_id_payload payload"),
}
},
_ => Err("Mismatched payload for ScrollUpInPaneId"),
},
Some(CommandName::ScrollDownInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::ScrollDownInPaneIdPayload(scroll_down_in_pane_id_payload)) => {
match scroll_down_in_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::ScrollDownInPaneId(pane_id.try_into()?)),
_ => Err("Malformed scroll_down_in_pane_id_payload payload"),
}
},
_ => Err("Mismatched payload for ScrollDownInPaneId"),
},
Some(CommandName::ScrollToTopInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::ScrollToTopInPaneIdPayload(scroll_to_top_in_pane_id_payload)) => {
match scroll_to_top_in_pane_id_payload.pane_id {
Some(pane_id) => {
Ok(PluginCommand::ScrollToTopInPaneId(pane_id.try_into()?))
},
_ => Err("Malformed scroll_to_top_in_pane_id_payload payload"),
}
},
_ => Err("Mismatched payload for ScrollToTopInPaneId"),
},
Some(CommandName::ScrollToBottomInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::ScrollToBottomInPaneIdPayload(
scroll_to_bottom_in_pane_id_payload,
)) => match scroll_to_bottom_in_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::ScrollToBottomInPaneId(pane_id.try_into()?)),
_ => Err("Malformed scroll_to_bottom_in_pane_id_payload payload"),
},
_ => Err("Mismatched payload for ScrollToBottomInPaneId"),
},
Some(CommandName::PageScrollUpInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::PageScrollUpInPaneIdPayload(page_scroll_up_in_pane_id_payload)) => {
match page_scroll_up_in_pane_id_payload.pane_id {
Some(pane_id) => {
Ok(PluginCommand::PageScrollUpInPaneId(pane_id.try_into()?))
},
_ => Err("Malformed page_scroll_up_in_pane_id_payload payload"),
}
},
_ => Err("Mismatched payload for PageScrollUpInPaneId"),
},
Some(CommandName::PageScrollDownInPaneId) => match protobuf_plugin_command.payload {
Some(Payload::PageScrollDownInPaneIdPayload(
page_scroll_down_in_pane_id_payload,
)) => match page_scroll_down_in_pane_id_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::PageScrollDownInPaneId(pane_id.try_into()?)),
_ => Err("Malformed page_scroll_down_in_pane_id_payload payload"),
},
_ => Err("Mismatched payload for PageScrollDownInPaneId"),
},
Some(CommandName::TogglePaneIdFullscreen) => match protobuf_plugin_command.payload {
Some(Payload::TogglePaneIdFullscreenPayload(toggle_pane_id_fullscreen_payload)) => {
match toggle_pane_id_fullscreen_payload.pane_id {
Some(pane_id) => {
Ok(PluginCommand::TogglePaneIdFullscreen(pane_id.try_into()?))
},
_ => Err("Malformed toggle_pane_id_fullscreen_payload payload"),
}
},
_ => Err("Mismatched payload for TogglePaneIdFullscreen"),
},
Some(CommandName::TogglePaneEmbedOrEjectForPaneId) => {
match protobuf_plugin_command.payload {
Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
toggle_pane_embed_or_eject_payload,
)) => match toggle_pane_embed_or_eject_payload.pane_id {
Some(pane_id) => Ok(PluginCommand::TogglePaneEmbedOrEjectForPaneId(
pane_id.try_into()?,
)),
_ => Err("Malformed toggle_pane_embed_or_eject_payload payload"),
},
_ => Err("Mismatched payload for TogglePaneEmbedOrEjectForPaneId"),
}
},
Some(CommandName::CloseTabWithIndex) => match protobuf_plugin_command.payload {
Some(Payload::CloseTabWithIndexPayload(close_tab_index_payload)) => Ok(
PluginCommand::CloseTabWithIndex(close_tab_index_payload.tab_index as usize),
),
_ => Err("Mismatched payload for CloseTabWithIndex"),
},
None => Err("Unrecognized plugin command"), None => Err("Unrecognized plugin command"),
} }
} }
@ -1605,6 +1788,140 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
terminal_pane_id, terminal_pane_id,
})), })),
}), }),
PluginCommand::ResizePaneIdWithDirection(resize, pane_id) => {
Ok(ProtobufPluginCommand {
name: CommandName::ResizePaneIdWithDirection as i32,
payload: Some(Payload::ResizePaneIdWithDirectionPayload(
ResizePaneIdWithDirectionPayload {
resize: Some(resize.try_into()?),
pane_id: Some(pane_id.try_into()?),
},
)),
})
},
PluginCommand::EditScrollbackForPaneWithId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::EditScrollbackForPaneWithId as i32,
payload: Some(Payload::EditScrollbackForPaneWithIdPayload(
EditScrollbackForPaneWithIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::WriteToPaneId(bytes_to_write, pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::WriteToPaneId as i32,
payload: Some(Payload::WriteToPaneIdPayload(WriteToPaneIdPayload {
bytes_to_write,
pane_id: Some(pane_id.try_into()?),
})),
}),
PluginCommand::WriteCharsToPaneId(chars_to_write, pane_id) => {
Ok(ProtobufPluginCommand {
name: CommandName::WriteCharsToPaneId as i32,
payload: Some(Payload::WriteCharsToPaneIdPayload(
WriteCharsToPaneIdPayload {
chars_to_write,
pane_id: Some(pane_id.try_into()?),
},
)),
})
},
PluginCommand::MovePaneWithPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::MovePaneWithPaneId as i32,
payload: Some(Payload::MovePaneWithPaneIdPayload(
MovePaneWithPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::MovePaneWithPaneIdInDirection(pane_id, direction) => {
Ok(ProtobufPluginCommand {
name: CommandName::MovePaneWithPaneIdInDirection as i32,
payload: Some(Payload::MovePaneWithPaneIdInDirectionPayload(
MovePaneWithPaneIdInDirectionPayload {
pane_id: Some(pane_id.try_into()?),
direction: Some(direction.try_into()?),
},
)),
})
},
PluginCommand::ClearScreenForPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::ClearScreenForPaneId as i32,
payload: Some(Payload::ClearScreenForPaneIdPayload(
ClearScreenForPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::ScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::ScrollUpInPaneId as i32,
payload: Some(Payload::ScrollUpInPaneIdPayload(ScrollUpInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
})),
}),
PluginCommand::ScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::ScrollDownInPaneId as i32,
payload: Some(Payload::ScrollDownInPaneIdPayload(
ScrollDownInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::ScrollToTopInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::ScrollToTopInPaneId as i32,
payload: Some(Payload::ScrollToTopInPaneIdPayload(
ScrollToTopInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::ScrollToBottomInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::ScrollToBottomInPaneId as i32,
payload: Some(Payload::ScrollToBottomInPaneIdPayload(
ScrollToBottomInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::PageScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::PageScrollUpInPaneId as i32,
payload: Some(Payload::PageScrollUpInPaneIdPayload(
PageScrollUpInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::PageScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::PageScrollDownInPaneId as i32,
payload: Some(Payload::PageScrollDownInPaneIdPayload(
PageScrollDownInPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::TogglePaneIdFullscreen(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::TogglePaneIdFullscreen as i32,
payload: Some(Payload::TogglePaneIdFullscreenPayload(
TogglePaneIdFullscreenPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::TogglePaneEmbedOrEjectForPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::TogglePaneEmbedOrEjectForPaneId as i32,
payload: Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
TogglePaneEmbedOrEjectForPaneIdPayload {
pane_id: Some(pane_id.try_into()?),
},
)),
}),
PluginCommand::CloseTabWithIndex(tab_index) => Ok(ProtobufPluginCommand {
name: CommandName::CloseTabWithIndex as i32,
payload: Some(Payload::CloseTabWithIndexPayload(
CloseTabWithIndexPayload {
tab_index: tab_index as u32,
},
)),
}),
} }
} }
} }