From 89b8c2ade0d7d7e93e3c903ab763daa2ca106fa4 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Sat, 2 Sep 2023 12:27:14 +0200 Subject: [PATCH 1/7] prototype --- src/main.rs | 4 + zellij-client/src/cli_client.rs | 3 +- zellij-client/src/input_handler.rs | 10 +- zellij-client/src/lib.rs | 1 + zellij-client/src/os_input_output.rs | 5 + zellij-server/src/os_input_output.rs | 1 + zellij-server/src/plugins/zellij_exports.rs | 5 + zellij-server/src/pty.rs | 108 ++++++++++++++++++-- zellij-server/src/route.rs | 46 +++++++-- zellij-server/src/screen.rs | 90 ++++++++++++++-- zellij-server/src/tab/mod.rs | 70 ++++++++++++- zellij-utils/src/cli.rs | 16 +++ zellij-utils/src/errors.rs | 2 + zellij-utils/src/input/actions.rs | 18 +++- zellij-utils/src/ipc.rs | 2 +- zellij-utils/src/plugin_api/action.rs | 5 +- 16 files changed, 351 insertions(+), 35 deletions(-) diff --git a/src/main.rs b/src/main.rs index f32d76cd85..da059b7fb5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ fn main() { direction, cwd, floating, + in_place, name, close_on_exit, start_suspended, @@ -36,6 +37,7 @@ fn main() { direction, cwd, floating, + in_place, name, close_on_exit, start_suspended, @@ -49,6 +51,7 @@ fn main() { direction, line_number, floating, + in_place, cwd, })) = opts.command { @@ -64,6 +67,7 @@ fn main() { direction, line_number, floating, + in_place, cwd, }; commands::send_action_to_session(command_cli_action, opts.session, config); diff --git a/zellij-client/src/cli_client.rs b/zellij-client/src/cli_client.rs index 197efa141e..2a2543adf1 100644 --- a/zellij-client/src/cli_client.rs +++ b/zellij-client/src/cli_client.rs @@ -18,8 +18,9 @@ pub fn start_cli_client(os_input: Box, session_name: &str, acti sock_dir }; os_input.connect_to_server(&*zellij_ipc_pipe); + let pane_id = os_input.env_variable("ZELLIJ_PANE_ID").and_then(|e| e.trim().parse().ok()); for action in actions { - let msg = ClientToServerMsg::Action(action, None); + let msg = ClientToServerMsg::Action(action, pane_id, None); os_input.send_to_server(msg); } loop { diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index 2781d3afb2..cf5b3d3260 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -283,13 +283,13 @@ impl InputHandler { Action::NoOp => {}, Action::Quit => { self.os_input - .send_to_server(ClientToServerMsg::Action(action, client_id)); + .send_to_server(ClientToServerMsg::Action(action, None, client_id)); self.exit(ExitReason::Normal); should_break = true; }, Action::Detach => { self.os_input - .send_to_server(ClientToServerMsg::Action(action, client_id)); + .send_to_server(ClientToServerMsg::Action(action, None, client_id)); self.exit(ExitReason::NormalDetached); should_break = true; }, @@ -298,7 +298,7 @@ impl InputHandler { // server later that atomically changes the mode as well self.mode = mode; self.os_input - .send_to_server(ClientToServerMsg::Action(action, None)); + .send_to_server(ClientToServerMsg::Action(action, None, None)); }, Action::CloseFocus | Action::ClearScreen @@ -318,7 +318,7 @@ impl InputHandler { | Action::MoveFocusOrTab(_) => { self.command_is_executing.blocking_input_thread(); self.os_input - .send_to_server(ClientToServerMsg::Action(action, client_id)); + .send_to_server(ClientToServerMsg::Action(action, None, client_id)); self.command_is_executing .wait_until_input_thread_is_unblocked(); }, @@ -333,7 +333,7 @@ impl InputHandler { }, _ => self .os_input - .send_to_server(ClientToServerMsg::Action(action, client_id)), + .send_to_server(ClientToServerMsg::Action(action, None, client_id)), } should_break diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 6aeb22e5ab..a472cd1dc9 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -316,6 +316,7 @@ pub fn start_client( os_api.send_to_server(ClientToServerMsg::Action( on_force_close.into(), None, + None, )); } }), diff --git a/zellij-client/src/os_input_output.rs b/zellij-client/src/os_input_output.rs index 212ed2f7d2..bfc8cc0769 100644 --- a/zellij-client/src/os_input_output.rs +++ b/zellij-client/src/os_input_output.rs @@ -114,6 +114,7 @@ pub trait ClientOsApi: Send + Sync { fn disable_mouse(&self) -> Result<()>; // Repeatedly send action, until stdin is readable again fn stdin_poller(&self) -> StdinPoller; + fn env_variable(&self, _name: &str) -> Option { None } } impl ClientOsApi for ClientOsInputOutput { @@ -282,6 +283,10 @@ impl ClientOsApi for ClientOsInputOutput { fn stdin_poller(&self) -> StdinPoller { StdinPoller::default() } + + fn env_variable(&self, name: &str) -> Option { + std::env::var(name).ok() + } } impl Clone for Box { diff --git a/zellij-server/src/os_input_output.rs b/zellij-server/src/os_input_output.rs index f4cbf9b4a3..28cb124c81 100644 --- a/zellij-server/src/os_input_output.rs +++ b/zellij-server/src/os_input_output.rs @@ -183,6 +183,7 @@ fn handle_openpty( } command .args(&cmd.args) + .env("ZELLIJ_PANE_ID", &format!("{}", terminal_id)) .pre_exec(move || -> std::io::Result<()> { if libc::login_tty(pid_secondary) != 0 { panic!("failed to set controlling terminal"); diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index 6ec50c3a5a..908bfeb086 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -51,6 +51,7 @@ macro_rules! apply_action { if let Err(e) = route_action( $action, $env.plugin_env.client_id, + Some(PaneId::Plugin($env.plugin_env.plugin_id)), $env.plugin_env.senders.clone(), $env.plugin_env.capabilities.clone(), $env.plugin_env.client_attributes.clone(), @@ -347,12 +348,14 @@ fn get_zellij_version(env: &ForeignFunctionEnv) { fn open_file(env: &ForeignFunctionEnv, file_to_open: FileToOpen) { let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); let floating = false; + let in_place = false; let action = Action::EditFile( file_to_open.path, file_to_open.line_number, file_to_open.cwd, None, floating, + in_place, ); apply_action!(action, error_msg, env); } @@ -360,12 +363,14 @@ fn open_file(env: &ForeignFunctionEnv, file_to_open: FileToOpen) { fn open_file_floating(env: &ForeignFunctionEnv, file_to_open: FileToOpen) { let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); let floating = true; + let in_place = false; let action = Action::EditFile( file_to_open.path, file_to_open.line_number, file_to_open.cwd, None, floating, + in_place, ); apply_action!(action, error_msg, env); } diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index a785f536db..be363a63fa 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -26,9 +26,10 @@ pub type VteBytes = Vec; pub type TabIndex = u32; #[derive(Clone, Copy, Debug)] -pub enum ClientOrTabIndex { +pub enum ClientTabIndexOrPaneId { ClientId(ClientId), TabIndex(usize), + PaneId(PaneId), } /// Instructions related to PTYs (pseudoterminals). @@ -38,7 +39,7 @@ pub enum PtyInstruction { Option, Option, Option, - ClientOrTabIndex, + ClientTabIndexOrPaneId, ), // bool (if Some) is // should_float, String is an optional pane name OpenInPlaceEditor(PathBuf, Option, ClientId), // Option is the optional line number @@ -62,6 +63,11 @@ pub enum PtyInstruction { ClosePane(PaneId), CloseTab(Vec), ReRunCommandInPane(PaneId, RunCommand), + SpawnInPlaceTerminal( + Option, + Option, + ClientTabIndexOrPaneId, + ), // String is an optional pane name Exit, } @@ -78,6 +84,7 @@ impl From<&PtyInstruction> for PtyContext { PtyInstruction::CloseTab(_) => PtyContext::CloseTab, PtyInstruction::NewTab(..) => PtyContext::NewTab, PtyInstruction::ReRunCommandInPane(..) => PtyContext::ReRunCommandInPane, + PtyInstruction::SpawnInPlaceTerminal(..) => PtyContext::SpawnInPlaceTerminal, PtyInstruction::Exit => PtyContext::Exit, } } @@ -164,13 +171,76 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { }, } }, + PtyInstruction::SpawnInPlaceTerminal( + terminal_action, + name, + client_id_tab_index_or_pane_id, + ) => { + let err_context = + || format!("failed to spawn terminal for {:?}", client_id_tab_index_or_pane_id); + let (hold_on_close, run_command, pane_title) = match &terminal_action { + Some(TerminalAction::RunCommand(run_command)) => ( + run_command.hold_on_close, + Some(run_command.clone()), + Some(name.unwrap_or_else(|| run_command.to_string())), + ), + _ => (false, None, name), + }; + match pty + .spawn_terminal(terminal_action, client_id_tab_index_or_pane_id) + .with_context(err_context) + { + Ok((pid, starts_held)) => { + let hold_for_command = if starts_held { run_command } else { None }; + pty.bus + .senders + .send_to_screen(ScreenInstruction::ReplacePane( + PaneId::Terminal(pid), + hold_for_command, + pane_title, + client_id_tab_index_or_pane_id, + )) + .with_context(err_context)?; + }, + Err(err) => match err.downcast_ref::() { + Some(ZellijError::CommandNotFound { terminal_id, .. }) => { + if hold_on_close { + let hold_for_command = None; // we do not hold an "error" pane + pty.bus + .senders + .send_to_screen(ScreenInstruction::ReplacePane( + PaneId::Terminal(*terminal_id), + hold_for_command, + pane_title, + client_id_tab_index_or_pane_id, + )) + .with_context(err_context)?; + if let Some(run_command) = run_command { + send_command_not_found_to_screen( + pty.bus.senders.clone(), + *terminal_id, + run_command.clone(), + None, + ) + .with_context(err_context)?; + } + } else { + log::error!("Failed to spawn terminal: {:?}", err); + pty.close_pane(PaneId::Terminal(*terminal_id)) + .with_context(err_context)?; + } + }, + _ => Err::<(), _>(err).non_fatal(), + }, + } + }, PtyInstruction::OpenInPlaceEditor(temp_file, line_number, client_id) => { let err_context = || format!("failed to open in-place editor for client {}", client_id); match pty.spawn_terminal( Some(TerminalAction::OpenFile(temp_file, line_number, None)), - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), ) { Ok((pid, _starts_held)) => { pty.bus @@ -199,7 +269,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { _ => (false, None, name), }; match pty - .spawn_terminal(terminal_action, ClientOrTabIndex::ClientId(client_id)) + .spawn_terminal(terminal_action, ClientTabIndexOrPaneId::ClientId(client_id)) .with_context(err_context) { Ok((pid, starts_held)) => { @@ -270,7 +340,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { _ => (false, None, name), }; match pty - .spawn_terminal(terminal_action, ClientOrTabIndex::ClientId(client_id)) + .spawn_terminal(terminal_action, ClientTabIndexOrPaneId::ClientId(client_id)) .with_context(err_context) { Ok((pid, starts_held)) => { @@ -501,25 +571,47 @@ impl Pty { }; }; } + fn fill_cwd_from_pane_id(&self, terminal_action: &mut TerminalAction, pane_id: &u32) { + if let TerminalAction::RunCommand(run_command) = terminal_action { + if run_command.cwd.is_none() { + run_command.cwd = self + .id_to_child_pid.get(pane_id) + .and_then(|&id| { + self.bus + .os_input + .as_ref() + .and_then(|input| input.get_cwd(Pid::from_raw(id))) + }); + }; + }; + } pub fn spawn_terminal( &mut self, terminal_action: Option, - client_or_tab_index: ClientOrTabIndex, + client_or_tab_index: ClientTabIndexOrPaneId, ) -> Result<(u32, bool)> { // bool is starts_held let err_context = || format!("failed to spawn terminal for {:?}", client_or_tab_index); // returns the terminal id let terminal_action = match client_or_tab_index { - ClientOrTabIndex::ClientId(client_id) => { + ClientTabIndexOrPaneId::ClientId(client_id) => { let mut terminal_action = terminal_action.unwrap_or_else(|| self.get_default_terminal(None, None)); self.fill_cwd(&mut terminal_action, client_id); terminal_action }, - ClientOrTabIndex::TabIndex(_) => { + ClientTabIndexOrPaneId::TabIndex(_) => { terminal_action.unwrap_or_else(|| self.get_default_terminal(None, None)) }, + ClientTabIndexOrPaneId::PaneId(pane_id) => { + let mut terminal_action = + terminal_action.unwrap_or_else(|| self.get_default_terminal(None, None)); + if let PaneId::Terminal(terminal_pane_id) = pane_id { + self.fill_cwd_from_pane_id(&mut terminal_action, &terminal_pane_id); + } + terminal_action + } }; let (hold_on_start, hold_on_close) = match &terminal_action { TerminalAction::RunCommand(run_command) => { diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index b29dd934fa..54489584de 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -6,7 +6,7 @@ use crate::{ os_input_output::ServerOsApi, panes::PaneId, plugins::PluginInstruction, - pty::{ClientOrTabIndex, PtyInstruction}, + pty::{ClientTabIndexOrPaneId, PtyInstruction}, screen::ScreenInstruction, ServerInstruction, SessionMetaData, SessionState, }; @@ -30,6 +30,7 @@ use crate::ClientId; pub(crate) fn route_action( action: Action, client_id: ClientId, + pane_id: Option, senders: ThreadSenders, capabilities: PluginCapabilities, client_attributes: ClientAttributes, @@ -257,12 +258,12 @@ pub(crate) fn route_action( shell, None, name, - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), ), }; senders.send_to_pty(pty_instr).with_context(err_context)?; }, - Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float) => { + Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float, should_open_in_place) => { let title = format!("Editing: {}", path_to_file.display()); let open_file = TerminalAction::OpenFile(path_to_file, line_number, cwd); let pty_instr = match (split_direction, should_float) { @@ -287,7 +288,7 @@ pub(crate) fn route_action( Some(open_file), Some(should_float), Some(title), - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), ), }; senders.send_to_pty(pty_instr).with_context(err_context)?; @@ -319,10 +320,38 @@ pub(crate) fn route_action( run_cmd, Some(should_float), name, - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), )) .with_context(err_context)?; }, + Action::NewInPlacePane(run_command, name) => { + let run_cmd = run_command + .map(|cmd| TerminalAction::RunCommand(cmd.into())) + .or_else(|| default_shell.clone()); + match pane_id { + Some(pane_id) => { + senders + .send_to_pty(PtyInstruction::SpawnInPlaceTerminal( + run_cmd, + name, + ClientTabIndexOrPaneId::PaneId(pane_id), + )) + .with_context(err_context)?; + }, + None => { + senders + .send_to_pty(PtyInstruction::SpawnInPlaceTerminal( + run_cmd, + name, + ClientTabIndexOrPaneId::ClientId(client_id) + )) + .with_context(err_context)?; + }, + _ => { + log::error!("To open an in place editor, we must have either a pane id or a client id") + } + } + }, Action::NewTiledPane(direction, run_command, name) => { let should_float = false; let run_cmd = run_command @@ -346,7 +375,7 @@ pub(crate) fn route_action( run_cmd, Some(should_float), name, - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), ), }; senders.send_to_pty(pty_instr).with_context(err_context)?; @@ -394,7 +423,7 @@ pub(crate) fn route_action( run_cmd, None, None, - ClientOrTabIndex::ClientId(client_id), + ClientTabIndexOrPaneId::ClientId(client_id), ), }; senders.send_to_pty(pty_instr).with_context(err_context)?; @@ -752,7 +781,7 @@ pub(crate) fn route_thread_main( -> Result { let mut should_break = false; match instruction { - ClientToServerMsg::Action(action, maybe_client_id) => { + ClientToServerMsg::Action(action, maybe_pane_id, maybe_client_id) => { let client_id = maybe_client_id.unwrap_or(client_id); if let Some(rlocked_sessions) = rlocked_sessions.as_ref() { if let Action::SwitchToMode(input_mode) = action { @@ -769,6 +798,7 @@ pub(crate) fn route_thread_main( if route_action( action, client_id, + maybe_pane_id.map(|p| PaneId::Terminal(p)), rlocked_sessions.senders.clone(), rlocked_sessions.capabilities.clone(), rlocked_sessions.client_attributes.clone(), diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index efa9110b88..b4832541f6 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -32,7 +32,7 @@ use crate::{ panes::sixel::SixelImageStore, panes::PaneId, plugins::PluginInstruction, - pty::{ClientOrTabIndex, PtyInstruction, VteBytes}, + pty::{ClientTabIndexOrPaneId, PtyInstruction, VteBytes}, tab::Tab, thread_bus::Bus, ui::{ @@ -141,7 +141,7 @@ pub enum ScreenInstruction { Option, Option, HoldForCommand, - ClientOrTabIndex, + ClientTabIndexOrPaneId, ), OpenInPlaceEditor(PaneId, ClientId), TogglePaneEmbedOrFloating(ClientId), @@ -294,6 +294,12 @@ pub enum ScreenInstruction { BreakPaneRight(ClientId), BreakPaneLeft(ClientId), UpdateSessionInfos(BTreeMap), // String is the session name + ReplacePane( + PaneId, + HoldForCommand, + Option, + ClientTabIndexOrPaneId + ), } impl From<&ScreenInstruction> for ScreenContext { @@ -468,6 +474,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::BreakPaneRight(..) => ScreenContext::BreakPaneRight, ScreenInstruction::BreakPaneLeft(..) => ScreenContext::BreakPaneLeft, ScreenInstruction::UpdateSessionInfos(..) => ScreenContext::UpdateSessionInfos, + ScreenInstruction::ReplacePane(..) => ScreenContext::ReplacePane, } } } @@ -1822,7 +1829,66 @@ impl Screen { self.render()?; Ok(()) } - + pub fn replace_pane( + &mut self, + new_pane_id: PaneId, + hold_for_command: HoldForCommand, + pane_title: Option, + client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId + ) -> Result<()> { + let err_context = || format!("failed to replace pane"); + let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| { + tab.suppress_pane_and_replace_with_pid(pane_id, new_pane_id); + if let Some(pane_title) = pane_title { + tab.rename_pane(pane_title.as_bytes().to_vec(), new_pane_id); + } + if let Some(hold_for_command) = hold_for_command { + let is_first_run = true; + tab.hold_pane( + new_pane_id, + None, + is_first_run, + hold_for_command + ) + } + }; + match client_id_tab_index_or_pane_id { + ClientTabIndexOrPaneId::ClientId(client_id) => { + active_tab!(self, client_id, |tab: &mut Tab| { + match tab.get_active_pane_id(client_id) { + Some(pane_id) => { + suppress_pane(tab, pane_id, new_pane_id); + }, + None => { + log::error!("Failed to find active pane for client id: {:?}", client_id); + } + } + }) + } + ClientTabIndexOrPaneId::PaneId(pane_id) => { + let tab_index = self + .tabs + .iter() + .find(|(_tab_index, tab)| tab.has_pane_with_pid(&pane_id)) + .map(|(tab_index, _tab)| *tab_index); + match tab_index { + Some(tab_index) => { + let tab = self.tabs + .get_mut(&tab_index) + .with_context(err_context)?; + suppress_pane(tab, pane_id, new_pane_id); + }, + None => { + log::error!("Could not find pane with id: {:?}", pane_id); + }, + }; + } + ClientTabIndexOrPaneId::TabIndex(tab_index) => { + log::error!("Cannot replace pane with tab index"); + } + } + Ok(()) + } fn unblock_input(&self) -> Result<()> { self.bus .senders @@ -1919,7 +1985,7 @@ pub(crate) fn screen_thread_main( client_or_tab_index, ) => { match client_or_tab_index { - ClientOrTabIndex::ClientId(client_id) => { + ClientTabIndexOrPaneId::ClientId(client_id) => { active_tab_and_connected_client_id!(screen, client_id, |tab: &mut Tab, client_id: ClientId| { tab.new_pane(pid, initial_pane_title, @@ -1942,7 +2008,7 @@ pub(crate) fn screen_thread_main( ) } }, - ClientOrTabIndex::TabIndex(tab_index) => { + ClientTabIndexOrPaneId::TabIndex(tab_index) => { if let Some(active_tab) = screen.tabs.get_mut(&tab_index) { active_tab.new_pane( pid, @@ -1959,6 +2025,9 @@ pub(crate) fn screen_thread_main( log::error!("Tab index not found: {:?}", tab_index); } }, + ClientTabIndexOrPaneId::PaneId(pane_id) => { + log::error!("cannot open a pane with a pane id??"); + } }; screen.unblock_input()?; screen.log_and_report_session_state()?; @@ -1967,7 +2036,7 @@ pub(crate) fn screen_thread_main( }, ScreenInstruction::OpenInPlaceEditor(pid, client_id) => { active_tab!(screen, client_id, |tab: &mut Tab| tab - .suppress_active_pane(pid, client_id), ?); + .replace_active_pane_with_editor_pane(pid, client_id), ?); screen.unblock_input()?; screen.log_and_report_session_state()?; @@ -3109,6 +3178,15 @@ pub(crate) fn screen_thread_main( ScreenInstruction::UpdateSessionInfos(new_session_infos) => { screen.update_session_infos(new_session_infos)?; }, + ScreenInstruction::ReplacePane(new_pane_id, hold_for_command, pane_title, client_id_tab_index_or_pane_id) => { + let err_context = || format!("Failed to replace pane"); + screen.replace_pane(new_pane_id, hold_for_command, pane_title, client_id_tab_index_or_pane_id)?; + + screen.unblock_input()?; + screen.log_and_report_session_state()?; + + screen.render()?; + }, } } Ok(()) diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 9483a94bf5..7a8f4849d8 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -32,7 +32,7 @@ use crate::{ panes::{FloatingPanes, TiledPanes}, panes::{LinkHandler, PaneId, PluginPane, TerminalPane}, plugins::PluginInstruction, - pty::{ClientOrTabIndex, PtyInstruction, VteBytes}, + pty::{ClientTabIndexOrPaneId, PtyInstruction, VteBytes}, thread_bus::ThreadSenders, ClientId, ServerInstruction, }; @@ -991,8 +991,8 @@ impl Tab { let name = None; let should_float = true; let client_id_or_tab_index = match client_id { - Some(client_id) => ClientOrTabIndex::ClientId(client_id), - None => ClientOrTabIndex::TabIndex(self.index), + Some(client_id) => ClientTabIndexOrPaneId::ClientId(client_id), + None => ClientTabIndexOrPaneId::TabIndex(self.index), }; let instruction = PtyInstruction::SpawnTerminal( default_shell, @@ -1074,7 +1074,7 @@ impl Tab { self.add_tiled_pane(new_pane, pid, client_id) } } - pub fn suppress_active_pane(&mut self, pid: PaneId, client_id: ClientId) -> Result<()> { + pub fn replace_active_pane_with_editor_pane(&mut self, pid: PaneId, client_id: ClientId) -> Result<()> { // this method creates a new pane from pid and replaces it with the active pane // the active pane is then suppressed (hidden and not rendered) until the current // created pane is closed, in which case it will be replaced back by it @@ -1140,6 +1140,64 @@ impl Tab { } Ok(()) } + pub fn suppress_pane_and_replace_with_pid(&mut self, old_pane_id: PaneId, new_pane_id: PaneId) -> Result<()> { + // this method creates a new pane from pid and replaces it with the active pane + // the active pane is then suppressed (hidden and not rendered) until the current + // created pane is closed, in which case it will be replaced back by it + let err_context = || format!("failed to suppress active pane"); + + match new_pane_id { + PaneId::Terminal(new_pane_id) => { + let next_terminal_position = self.get_next_terminal_position(); // TODO: this is not accurate in this case + let mut new_pane = TerminalPane::new( + new_pane_id, + 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, + ); + let replaced_pane = if self.floating_panes.panes_contain(&old_pane_id) { + self.floating_panes + .replace_pane(old_pane_id, Box::new(new_pane)) + .ok() + } else { + self.tiled_panes + .replace_pane(old_pane_id, Box::new(new_pane)) + }; + match replaced_pane { + Some(replaced_pane) => { + resize_pty!( + replaced_pane, + self.os_api, + self.senders, + self.character_cell_size + ); + self.suppressed_panes + .insert(PaneId::Terminal(new_pane_id), replaced_pane); + }, + None => { + Err::<(), _>(anyhow!( + "Could not find editor pane to replace - is no pane focused?" + )) + .with_context(err_context) + .non_fatal(); + }, + } + }, + PaneId::Plugin(_pid) => { + // TBD, currently unsupported + }, + } + Ok(()) + } pub fn horizontal_split( &mut self, pid: PaneId, @@ -3427,6 +3485,10 @@ impl Tab { }) } pub fn suppress_pane(&mut self, pane_id: PaneId, client_id: ClientId) { + // this method places a pane in the suppressed pane with its own ID - this means we'll + // not take it out of there when another pane is closed (eg. like happens with the + // scrollback editor), but it has to take itself out on its own (eg. a plugin using the + // show_self() method) if let Some(pane) = self.close_pane(pane_id, true, Some(client_id)) { self.suppressed_panes.insert(pane_id, pane); } diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index f8c59f5430..36e738bd27 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -134,6 +134,10 @@ pub enum Sessions { #[clap(short, long, value_parser, default_value("false"), takes_value(false))] floating: bool, + /// Open the new pane in place of the current pane, temporarily suspending it + #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + in_place: bool, + /// Name of the new pane #[clap(short, long, value_parser)] name: Option, @@ -159,6 +163,10 @@ pub enum Sessions { #[clap(short, long, value_parser, conflicts_with("floating"))] direction: Option, + /// Open the new pane in place of the current pane, temporarily suspending it + #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + in_place: bool, + /// Open the new pane in floating mode #[clap(short, long, value_parser, default_value("false"), takes_value(false))] floating: bool, @@ -268,6 +276,10 @@ pub enum CliAction { #[clap(short, long, value_parser, default_value("false"), takes_value(false))] floating: bool, + /// Open the new pane in place of the current pane, temporarily suspending it + #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + in_place: bool, + /// Name of the new pane #[clap(short, long, value_parser)] name: Option, @@ -311,6 +323,10 @@ pub enum CliAction { #[clap(short, long, value_parser, default_value("false"), takes_value(false))] floating: bool, + /// Open the new pane in place of the current pane, temporarily suspending it + #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + in_place: bool, + /// Change the working directory of the editor #[clap(long, value_parser)] cwd: Option, diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 677cbc420e..215966790e 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -343,6 +343,7 @@ pub enum ScreenContext { BreakPaneRight, BreakPaneLeft, UpdateSessionInfos, + ReplacePane, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. @@ -358,6 +359,7 @@ pub enum PtyContext { ClosePane, CloseTab, ReRunCommandInPane, + SpawnInPlaceTerminal, Exit, } diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 054273a0a3..d03f4fbb84 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -161,11 +161,14 @@ pub enum Action { Option, Option, bool, - ), // usize is an optional line number, Option is an optional cwd, bool is floating true/false + bool, + ), // usize is an optional line number, Option is an optional cwd, bool is floating true/false, second bool is in_place /// Open a new floating pane NewFloatingPane(Option, Option), // String is an optional pane name /// Open a new tiled (embedded, non-floating) pane NewTiledPane(Option, Option, Option), // String is an + /// Open a new pane in place of the focused one, suppressing it instead + NewInPlacePane(Option, Option), // String is an // optional pane // name /// Embed focused pane in tab if floating or float focused pane if embedded @@ -293,6 +296,7 @@ impl Action { plugin, cwd, floating, + in_place, name, close_on_exit, start_suspended, @@ -313,6 +317,9 @@ impl Action { }; if floating { Ok(vec![Action::NewFloatingPluginPane(plugin, name)]) + } else if in_place { + // TODO: implement this + unimplemented!() } else { // it is intentional that a new tiled plugin pane cannot include a // direction @@ -342,6 +349,11 @@ impl Action { Some(run_command_action), name, )]) + } else if in_place { + Ok(vec![Action::NewInPlacePane( + Some(run_command_action), + name, + )]) } else { Ok(vec![Action::NewTiledPane( direction, @@ -352,6 +364,8 @@ impl Action { } else { if floating { Ok(vec![Action::NewFloatingPane(None, name)]) + } else if in_place { + Ok(vec![Action::NewInPlacePane(None, name)]) } else { Ok(vec![Action::NewTiledPane(direction, None, name)]) } @@ -362,6 +376,7 @@ impl Action { file, line_number, floating, + in_place, cwd, } => { let mut file = file; @@ -380,6 +395,7 @@ impl Action { cwd, direction, floating, + in_place, )]) }, CliAction::SwitchMode { input_mode } => { diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index 0f3415209f..a60ecc6154 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -84,7 +84,7 @@ pub enum ClientToServerMsg { Option, // tab position to focus Option<(u32, bool)>, // (pane_id, is_plugin) => pane id to focus ), - Action(Action, Option), + Action(Action, Option, Option), // u32 is the terminal id ClientExited, KillSession, ConnStatus, diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 0d70af6920..d4ecf02e08 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -232,12 +232,14 @@ impl TryFrom for Action { .and_then(|d| ProtobufResizeDirection::from_i32(d)) .and_then(|d| d.try_into().ok()); let should_float = payload.should_float; + let should_be_in_place = false; // TODO: implement this Ok(Action::EditFile( file_to_edit, line_number, cwd, direction, should_float, + should_be_in_place )) }, _ => Err("Wrong payload for Action::NewPane"), @@ -814,7 +816,7 @@ impl TryFrom for ProtobufAction { })), }) }, - Action::EditFile(path_to_file, line_number, cwd, direction, should_float) => { + Action::EditFile(path_to_file, line_number, cwd, direction, should_float, should_be_in_place) => { let file_to_edit = path_to_file.display().to_string(); let cwd = cwd.map(|cwd| cwd.display().to_string()); let direction: Option = direction @@ -1149,6 +1151,7 @@ impl TryFrom for ProtobufAction { }), Action::NoOp | Action::Confirm + | Action::NewInPlacePane(..) // TODO: implement this | Action::Deny | Action::Copy | Action::SkipConfirm(..) => Err("Unsupported action"), From a8b5fa07f6d682606ad6b45014b58b9952a9b72d Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Sat, 2 Sep 2023 13:50:59 +0200 Subject: [PATCH 2/7] fix tests --- zellij-client/src/unit/stdin_tests.rs | 2 +- .../src/tab/unit/tab_integration_tests.rs | 16 ++++++++-------- zellij-server/src/tab/unit/tab_tests.rs | 2 +- zellij-server/src/unit/screen_tests.rs | 7 +++++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/zellij-client/src/unit/stdin_tests.rs b/zellij-client/src/unit/stdin_tests.rs index 31c7fe0750..3091af50dc 100644 --- a/zellij-client/src/unit/stdin_tests.rs +++ b/zellij-client/src/unit/stdin_tests.rs @@ -199,7 +199,7 @@ fn extract_actions_sent_to_server( ) -> Vec { let events_sent_to_server = events_sent_to_server.lock().unwrap(); events_sent_to_server.iter().fold(vec![], |mut acc, event| { - if let ClientToServerMsg::Action(action, None) = event { + if let ClientToServerMsg::Action(action, None, None) = event { acc.push(action.clone()); } acc diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 56dff4d72b..b941817b0b 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -2094,7 +2094,7 @@ fn suppress_tiled_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.suppress_active_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.render(&mut output).unwrap(); @@ -2122,7 +2122,7 @@ fn suppress_floating_pane() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.suppress_active_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.render(&mut output).unwrap(); @@ -2145,7 +2145,7 @@ fn close_suppressing_tiled_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.suppress_active_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2176,7 +2176,7 @@ fn close_suppressing_floating_pane() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.suppress_active_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2202,7 +2202,7 @@ fn suppress_tiled_pane_float_it_and_close() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.suppress_active_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2234,7 +2234,7 @@ fn suppress_floating_pane_embed_it_and_close_it() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.suppress_active_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2261,7 +2261,7 @@ fn resize_whole_tab_while_tiled_pane_is_suppressed() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.suppress_active_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.resize_whole_tab(Size { @@ -2294,7 +2294,7 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.suppress_active_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.resize_whole_tab(Size { diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 195dbb8831..44cde75eb2 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -330,7 +330,7 @@ fn write_to_suppressed_pane() { tab.vertical_split(PaneId::Terminal(2), None, 1).unwrap(); // Suppress pane 2 and remove it from active panes - tab.suppress_active_pane(PaneId::Terminal(2), 1).unwrap(); + tab.replace_active_pane_with_editor_pane(PaneId::Terminal(2), 1).unwrap(); tab.tiled_panes.remove_pane(PaneId::Terminal(2)); // Make sure it's suppressed now diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index beaa19cda5..f84e4b81c4 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -114,6 +114,7 @@ fn send_cli_action_to_server( route_action( action, client_id, + None, senders.clone(), capabilities, client_attributes.clone(), @@ -1866,6 +1867,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() { plugin: None, cwd: None, floating: false, + in_place: false, name: None, close_on_exit: false, start_suspended: false, @@ -1903,6 +1905,7 @@ pub fn send_cli_new_pane_action_with_split_direction() { plugin: None, cwd: None, floating: false, + in_place: false, name: None, close_on_exit: false, start_suspended: false, @@ -1940,6 +1943,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() { plugin: None, cwd: Some("/some/folder".into()), floating: false, + in_place: false, name: None, close_on_exit: false, start_suspended: false, @@ -1976,6 +1980,7 @@ pub fn send_cli_edit_action_with_default_parameters() { direction: None, line_number: None, floating: false, + in_place: false, cwd: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); @@ -2009,6 +2014,7 @@ pub fn send_cli_edit_action_with_line_number() { direction: None, line_number: Some(100), floating: false, + in_place: false, cwd: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); @@ -2042,6 +2048,7 @@ pub fn send_cli_edit_action_with_split_direction() { direction: Some(Direction::Down), line_number: None, floating: false, + in_place: false, cwd: None, }; send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); From d1f0f2a5f14b07175b73fd759e434c3a5de25750 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Fri, 15 Sep 2023 15:12:59 +0200 Subject: [PATCH 3/7] add to all the things except plugins --- default-plugins/status-bar/src/second_line.rs | 2 +- zellij-server/src/plugins/mod.rs | 12 +- zellij-server/src/route.rs | 52 ++++-- zellij-server/src/screen.rs | 152 ++++++++++++++---- zellij-server/src/tab/mod.rs | 51 +++++- zellij-utils/assets/prost/api.action.rs | 2 + zellij-utils/src/cli.rs | 2 + zellij-utils/src/errors.rs | 1 + zellij-utils/src/input/actions.rs | 38 ++++- zellij-utils/src/kdl/mod.rs | 9 ++ zellij-utils/src/plugin_api/action.proto | 1 + zellij-utils/src/plugin_api/action.rs | 6 +- 12 files changed, 274 insertions(+), 54 deletions(-) diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index d31218fd3c..d33ddad8ce 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -245,7 +245,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { action_key(&km, &[A::SearchToggleOption(SOpt::WholeWord)])), ]} else if mi.mode == IM::Session { vec![ (s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])), - (s("Session Manager"), s("Manager"), action_key(&km, &[A::LaunchOrFocusPlugin(Default::default(), true, true), TO_NORMAL])), // not entirely accurate + (s("Session Manager"), s("Manager"), action_key(&km, &[A::LaunchOrFocusPlugin(Default::default(), true, true, false), TO_NORMAL])), // not entirely accurate (s("Select pane"), s("Select"), to_normal_key), ]} else if mi.mode == IM::Tmux { vec![ (s("Move focus"), s("Move"), action_key_group(&km, &[ diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index c72356699d..36bfae8def 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -14,6 +14,7 @@ use wasmer::Store; use crate::screen::ScreenInstruction; use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId, ServerInstruction}; +use crate::panes::PaneId; use wasm_bridge::WasmBridge; @@ -38,9 +39,11 @@ pub type PluginId = u32; pub enum PluginInstruction { Load( Option, // should float + bool, // should be opened in place Option, // pane title RunPlugin, usize, // tab index + Option, // pane id to replace if this is to be opened "in-place" ClientId, Size, ), @@ -156,15 +159,18 @@ pub(crate) fn plugin_thread_main( let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Plugin((&event).into())); match event { - PluginInstruction::Load(should_float, pane_title, run, tab_index, client_id, size) => { + PluginInstruction::Load(should_float, should_be_open_in_place, pane_title, run, tab_index, pane_id_to_replace, client_id, size) => { match wasm_bridge.load_plugin(&run, tab_index, size, Some(client_id)) { Ok(plugin_id) => { drop(bus.senders.send_to_screen(ScreenInstruction::AddPlugin( should_float, + should_be_open_in_place, run, pane_title, tab_index, plugin_id, + pane_id_to_replace, + Some(client_id), ))); }, Err(e) => { @@ -192,12 +198,16 @@ pub(crate) fn plugin_thread_main( // the cli who spawned the command and is not an existing client_id match wasm_bridge.load_plugin(&run, tab_index, size, None) { Ok(plugin_id) => { + let should_be_open_in_place = false; drop(bus.senders.send_to_screen(ScreenInstruction::AddPlugin( should_float, + should_be_open_in_place, run, pane_title, tab_index, plugin_id, + None, + None, ))); }, Err(e) => { diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 54489584de..d7efea9703 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -266,25 +266,45 @@ pub(crate) fn route_action( Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float, should_open_in_place) => { let title = format!("Editing: {}", path_to_file.display()); let open_file = TerminalAction::OpenFile(path_to_file, line_number, cwd); - let pty_instr = match (split_direction, should_float) { - (Some(Direction::Left), false) => { + let pty_instr = match (split_direction, should_float, should_open_in_place) { + (Some(Direction::Left), false, false) => { PtyInstruction::SpawnTerminalVertically(Some(open_file), Some(title), client_id) }, - (Some(Direction::Right), false) => { + (Some(Direction::Right), false, false) => { PtyInstruction::SpawnTerminalVertically(Some(open_file), Some(title), client_id) }, - (Some(Direction::Up), false) => PtyInstruction::SpawnTerminalHorizontally( + (Some(Direction::Up), false, false) => PtyInstruction::SpawnTerminalHorizontally( Some(open_file), Some(title), client_id, ), - (Some(Direction::Down), false) => PtyInstruction::SpawnTerminalHorizontally( + (Some(Direction::Down), false, false) => PtyInstruction::SpawnTerminalHorizontally( Some(open_file), Some(title), client_id, ), - // No direction specified or should float - defer placement to screen - (None, _) | (_, true) => PtyInstruction::SpawnTerminal( + // open terminal in place + (_, _, true) => { + match pane_id { + Some(pane_id) => { + PtyInstruction::SpawnInPlaceTerminal( + Some(open_file), + Some(title), + ClientTabIndexOrPaneId::PaneId(pane_id), + ) + }, + None => { + PtyInstruction::SpawnInPlaceTerminal( + Some(open_file), + Some(title), + ClientTabIndexOrPaneId::ClientId(client_id) + ) + }, + } + } + // Open either floating terminal if we were asked with should_float or defer + // placement to screen + (None, _, _) | (_, true, _) => PtyInstruction::SpawnTerminal( Some(open_file), Some(should_float), Some(title), @@ -347,9 +367,6 @@ pub(crate) fn route_action( )) .with_context(err_context)?; }, - _ => { - log::error!("To open an in place editor, we must have either a pane id or a client id") - } } }, Action::NewTiledPane(direction, run_command, name) => { @@ -645,17 +662,30 @@ pub(crate) fn route_action( )) .with_context(err_context)?; }, + Action::NewInPlacePluginPane(run_plugin, name) => { + if let Some(pane_id) = pane_id { + senders + .send_to_screen(ScreenInstruction::NewInPlacePluginPane( + run_plugin, name, pane_id, client_id, + )) + .with_context(err_context)?; + } else { + log::error!("Must have pane_id in order to open in place pane"); + } + }, Action::StartOrReloadPlugin(run_plugin) => { senders .send_to_screen(ScreenInstruction::StartOrReloadPluginPane(run_plugin, None)) .with_context(err_context)?; }, - Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab) => { + Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab, should_open_in_place) => { senders .send_to_screen(ScreenInstruction::LaunchOrFocusPlugin( run_plugin, should_float, move_to_focused_tab, + should_open_in_place, + pane_id, client_id, )) .with_context(err_context)?; diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index b4832541f6..e66dbc0000 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -268,20 +268,24 @@ pub enum ScreenInstruction { NewTiledPluginPane(RunPlugin, Option, ClientId), // Option is // optional pane title NewFloatingPluginPane(RunPlugin, Option, ClientId), // Option is an + NewInPlacePluginPane(RunPlugin, Option, PaneId, ClientId), // Option is an // optional pane title StartOrReloadPluginPane(RunPlugin, Option), AddPlugin( Option, // should_float + bool, // should be opened in place RunPlugin, Option, // pane title usize, // tab index u32, // plugin id + Option, + Option, ), UpdatePluginLoadingStage(u32, LoadingIndication), // u32 - plugin_id StartPluginLoadingIndication(u32, LoadingIndication), // u32 - plugin_id ProgressPluginLoadingOffset(u32), // u32 - plugin id RequestStateUpdateForPlugins, - LaunchOrFocusPlugin(RunPlugin, bool, bool, ClientId), // bools are: should_float, move_to_focused_tab + LaunchOrFocusPlugin(RunPlugin, bool, bool, bool, Option, ClientId), // bools are: should_float, move_to_focused_tab, should_open_in_place Option is the pane id to replace SuppressPane(PaneId, ClientId), // bool is should_float FocusPaneWithId(PaneId, bool, ClientId), // bool is should_float RenamePane(PaneId, Vec), @@ -475,6 +479,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::BreakPaneLeft(..) => ScreenContext::BreakPaneLeft, ScreenInstruction::UpdateSessionInfos(..) => ScreenContext::UpdateSessionInfos, ScreenInstruction::ReplacePane(..) => ScreenContext::ReplacePane, + ScreenInstruction::NewInPlacePluginPane(..) => ScreenContext::NewInPlacePluginPane, } } } @@ -1833,12 +1838,13 @@ impl Screen { &mut self, new_pane_id: PaneId, hold_for_command: HoldForCommand, + run_plugin: Option, pane_title: Option, client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId ) -> Result<()> { let err_context = || format!("failed to replace pane"); let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| { - tab.suppress_pane_and_replace_with_pid(pane_id, new_pane_id); + tab.suppress_pane_and_replace_with_pid(pane_id, new_pane_id, run_plugin); if let Some(pane_title) = pane_title { tab.rename_pane(pane_title.as_bytes().to_vec(), new_pane_id); } @@ -2961,11 +2967,14 @@ pub(crate) fn screen_thread_main( let tab_index = screen.active_tab_indices.values().next().unwrap_or(&1); let size = Size::default(); let should_float = Some(false); + let should_be_opened_in_place = false; screen.bus.senders.send_to_plugin(PluginInstruction::Load( should_float, + should_be_opened_in_place, pane_title, run_plugin, *tab_index, + None, // pane it to replace client_id, size, ))?; @@ -2975,11 +2984,38 @@ pub(crate) fn screen_thread_main( Some(tab_index) => { let size = Size::default(); let should_float = Some(true); + let should_be_opened_in_place = false; + screen.bus.senders.send_to_plugin(PluginInstruction::Load( + should_float, + should_be_opened_in_place, + pane_title, + run_plugin, + *tab_index, + None, // pane id to replace + client_id, + size, + ))?; + }, + None => { + log::error!( + "Could not find an active tab - is there at least 1 connected user?" + ); + }, + } + }, + ScreenInstruction::NewInPlacePluginPane(run_plugin, pane_title, pane_id_to_replace, client_id) => { + match screen.active_tab_indices.values().next() { + Some(tab_index) => { + let size = Size::default(); + let should_float = None; + let should_be_in_place = true; screen.bus.senders.send_to_plugin(PluginInstruction::Load( should_float, + should_be_in_place, pane_title, run_plugin, *tab_index, + Some(pane_id_to_replace), client_id, size, ))?; @@ -3008,15 +3044,29 @@ pub(crate) fn screen_thread_main( }, ScreenInstruction::AddPlugin( should_float, + should_be_in_place, run_plugin_location, pane_title, tab_index, plugin_id, + pane_id_to_replace, + client_id, ) => { let pane_title = pane_title.unwrap_or_else(|| run_plugin_location.location.to_string()); let run_plugin = Run::Plugin(run_plugin_location); - if let Some(active_tab) = screen.tabs.get_mut(&tab_index) { + + if should_be_in_place { + if let Some(pane_id_to_replace) = pane_id_to_replace { + let client_tab_index_or_pane_id = ClientTabIndexOrPaneId::PaneId(pane_id_to_replace); + screen.replace_pane(PaneId::Plugin(plugin_id), None, Some(run_plugin), Some(pane_title), client_tab_index_or_pane_id)?; + } else if let Some(client_id) = client_id { + let client_tab_index_or_pane_id = ClientTabIndexOrPaneId::ClientId(client_id); + screen.replace_pane(PaneId::Plugin(plugin_id), None, Some(run_plugin), Some(pane_title), client_tab_index_or_pane_id)?; + } else { + log::error!("Must have pane id to replace or connected client_id if replacing a pane"); + } + } else if let Some(active_tab) = screen.tabs.get_mut(&tab_index) { active_tab.new_pane( PaneId::Plugin(plugin_id), Some(pane_title), @@ -3072,41 +3122,73 @@ pub(crate) fn screen_thread_main( run_plugin, should_float, move_to_focused_tab, + should_open_in_place, + pane_id_to_replace, client_id, ) => { - let client_id = if screen.active_tab_indices.contains_key(&client_id) { - Some(client_id) - } else { - screen.get_first_client_id() - }; - let client_id_and_focused_tab = client_id.and_then(|client_id| { - screen - .active_tab_indices - .get(&client_id) - .map(|tab_index| (*tab_index, client_id)) - }); - match client_id_and_focused_tab { - Some((tab_index, client_id)) => { - if screen.focus_plugin_pane( - &run_plugin, - should_float, - move_to_focused_tab, - client_id, - )? { - screen.render()?; - screen.log_and_report_session_state()?; - } else { - screen.bus.senders.send_to_plugin(PluginInstruction::Load( - Some(should_float), - None, - run_plugin, - tab_index, - client_id, - Size::default(), - ))?; + match pane_id_to_replace { + Some(pane_id_to_replace) => { + match screen.active_tab_indices.values().next() { + Some(tab_index) => { + let size = Size::default(); + let should_float = None; + let should_be_in_place = true; + screen.bus.senders.send_to_plugin(PluginInstruction::Load( + should_float, + should_be_in_place, + None, + run_plugin, + *tab_index, + Some(pane_id_to_replace), + client_id, + size, + ))?; + }, + None => { + log::error!( + "Could not find an active tab - is there at least 1 connected user?" + ); + }, } }, - None => log::error!("No connected clients found - cannot load or focus plugin"), + None => { + let client_id = if screen.active_tab_indices.contains_key(&client_id) { + Some(client_id) + } else { + screen.get_first_client_id() + }; + let client_id_and_focused_tab = client_id.and_then(|client_id| { + screen + .active_tab_indices + .get(&client_id) + .map(|tab_index| (*tab_index, client_id)) + }); + match client_id_and_focused_tab { + Some((tab_index, client_id)) => { + if screen.focus_plugin_pane( + &run_plugin, + should_float, + move_to_focused_tab, + client_id, + )? { + screen.render()?; + screen.log_and_report_session_state()?; + } else { + screen.bus.senders.send_to_plugin(PluginInstruction::Load( + Some(should_float), + should_open_in_place, + None, + run_plugin, + tab_index, + None, // pane id to replace + client_id, + Size::default(), + ))?; + } + }, + None => log::error!("No connected clients found - cannot load or focus plugin"), + } + } } }, ScreenInstruction::SuppressPane(pane_id, client_id) => { @@ -3180,7 +3262,7 @@ pub(crate) fn screen_thread_main( }, ScreenInstruction::ReplacePane(new_pane_id, hold_for_command, pane_title, client_id_tab_index_or_pane_id) => { let err_context = || format!("Failed to replace pane"); - screen.replace_pane(new_pane_id, hold_for_command, pane_title, client_id_tab_index_or_pane_id)?; + screen.replace_pane(new_pane_id, hold_for_command, None, pane_title, client_id_tab_index_or_pane_id)?; screen.unblock_input()?; screen.log_and_report_session_state()?; diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 7a8f4849d8..67ddb4c605 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -1140,7 +1140,7 @@ impl Tab { } Ok(()) } - pub fn suppress_pane_and_replace_with_pid(&mut self, old_pane_id: PaneId, new_pane_id: PaneId) -> Result<()> { + pub fn suppress_pane_and_replace_with_pid(&mut self, old_pane_id: PaneId, new_pane_id: PaneId, run_plugin: Option) -> Result<()> { // this method creates a new pane from pid and replaces it with the active pane // the active pane is then suppressed (hidden and not rendered) until the current // created pane is closed, in which case it will be replaced back by it @@ -1192,8 +1192,55 @@ impl Tab { }, } }, - PaneId::Plugin(_pid) => { + PaneId::Plugin(plugin_pid) => { // TBD, currently unsupported + let mut new_pane = PluginPane::new( + plugin_pid, + PaneGeom::default(), // this will be filled out later + self.senders + .to_plugin + .as_ref() + .with_context(err_context)? + .clone(), + String::new(), + String::new(), + self.sixel_image_store.clone(), + self.terminal_emulator_colors.clone(), + self.terminal_emulator_color_codes.clone(), + self.link_handler.clone(), + self.character_cell_size.clone(), + self.connected_clients.borrow().iter().copied().collect(), + self.style, + run_plugin, + self.debug, + ); + let replaced_pane = if self.floating_panes.panes_contain(&old_pane_id) { + self.floating_panes + .replace_pane(old_pane_id, Box::new(new_pane)) + .ok() + } else { + self.tiled_panes + .replace_pane(old_pane_id, Box::new(new_pane)) + }; + match replaced_pane { + Some(replaced_pane) => { + resize_pty!( + replaced_pane, + self.os_api, + self.senders, + self.character_cell_size + ); + self.suppressed_panes + .insert(PaneId::Plugin(plugin_pid), replaced_pane); + }, + None => { + Err::<(), _>(anyhow!( + "Could not find editor pane to replace - is no pane focused?" + )) + .with_context(err_context) + .non_fatal(); + }, + } }, } Ok(()) diff --git a/zellij-utils/assets/prost/api.action.rs b/zellij-utils/assets/prost/api.action.rs index 9099b6ef53..97976393b6 100644 --- a/zellij-utils/assets/prost/api.action.rs +++ b/zellij-utils/assets/prost/api.action.rs @@ -137,6 +137,8 @@ pub struct LaunchOrFocusPluginPayload { pub plugin_configuration: ::core::option::Option, #[prost(bool, tag = "4")] pub move_to_focused_tab: bool, + #[prost(bool, tag = "5")] + pub should_open_in_place: bool, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 36e738bd27..e79d87214c 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -401,6 +401,8 @@ pub enum CliAction { #[clap(short, long, value_parser)] floating: bool, #[clap(short, long, value_parser)] + in_place: bool, + #[clap(short, long, value_parser)] move_to_focused_tab: bool, url: Url, #[clap(short, long, value_parser)] diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 215966790e..a069804001 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -344,6 +344,7 @@ pub enum ScreenContext { BreakPaneLeft, UpdateSessionInfos, ReplacePane, + NewInPlacePluginPane, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index d03f4fbb84..6a7d22e4c8 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -207,7 +207,8 @@ pub enum Action { LeftClick(Position), RightClick(Position), MiddleClick(Position), - LaunchOrFocusPlugin(RunPlugin, bool, bool), // bools => should float, move_to_focused_tab + LaunchOrFocusPlugin(RunPlugin, bool, bool, bool), // bools => should float, + // move_to_focused_tab, should_open_in_place LeftMouseRelease(Position), RightMouseRelease(Position), MiddleMouseRelease(Position), @@ -235,6 +236,7 @@ pub enum Action { /// Open a new tiled (embedded, non-floating) plugin pane NewTiledPluginPane(RunPlugin, Option), // String is an optional name NewFloatingPluginPane(RunPlugin, Option), // String is an optional name + NewInPlacePluginPane(RunPlugin, Option), // String is an optional name StartOrReloadPlugin(RunPlugin), CloseTerminalPane(u32), ClosePluginPane(u32), @@ -318,8 +320,10 @@ impl Action { if floating { Ok(vec![Action::NewFloatingPluginPane(plugin, name)]) } else if in_place { - // TODO: implement this - unimplemented!() + Ok(vec![Action::NewInPlacePluginPane( + plugin, + name, + )]) } else { // it is intentional that a new tiled plugin pane cannot include a // direction @@ -517,9 +521,36 @@ impl Action { CliAction::LaunchOrFocusPlugin { url, floating, + in_place, move_to_focused_tab, configuration, } => { + // TODO: CONTINUE HERE (before vacation) - add an in_place flag and make it work + // - we already did this with the NewPane action above, to test: + // * cargo x run --singlepass + // * target/dev-opt/zellij action new-pane --in-place --plugin zellij:session-manager + // * this also already works with zellij run with the --in-place flag + // * we need to make it work with everything, then also make it work with plugins + // - make it work with LaunchOrFocusPlugin - DONE + // - make it work with the edit action - DONE + // - test with keybinding + // * run - DONE + // * launch_or_focus_plugin - DONE (has some issues, might want to test again + // with properly fixed monocle) + // - add to plugins (open_terminal_in_place, open_command_pane_in_place, + // open_file_in_place) <== CONTINUE HERE + // - test these with/without flag + // * zellij run + // * zellij action new-pane (command and plugin) + // * zellij action launch-or-focus-plugin + // * zellij action edit + // * zellij edit + // * keybinding + // - run + // - launch_or_focus_plugin + // * plugins (show_self/hide_self, open_file_in_place(n), + // open_terminal_in_place(n), open_command_pane_in_place(n)) + let current_dir = get_current_dir(); let run_plugin_location = RunPluginLocation::parse(url.as_str(), Some(current_dir)) .map_err(|e| format!("Failed to parse plugin location: {}", e))?; @@ -532,6 +563,7 @@ impl Action { run_plugin, floating, move_to_focused_tab, + in_place, )]) }, } diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index a7573af55a..db72b80d22 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -886,6 +886,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action { let floating = command_metadata .and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "floating")) .unwrap_or(false); + let in_place = command_metadata + .and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "in_place")) + .unwrap_or(false); let run_command_action = RunCommandAction { command: PathBuf::from(command), args, @@ -896,6 +899,8 @@ impl TryFrom<(&KdlNode, &Options)> for Action { }; if floating { Ok(Action::NewFloatingPane(Some(run_command_action), name)) + } else if in_place { + Ok(Action::NewInPlacePane(Some(run_command_action), name)) } else { Ok(Action::NewTiledPane( direction, @@ -923,6 +928,9 @@ impl TryFrom<(&KdlNode, &Options)> for Action { let move_to_focused_tab = command_metadata .and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "move_to_focused_tab")) .unwrap_or(false); + let should_open_in_place = command_metadata + .and_then(|c_m| kdl_child_bool_value_for_entry(c_m, "in_place")) + .unwrap_or(false); let current_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); let location = RunPluginLocation::parse(&plugin_path, Some(current_dir))?; let configuration = KdlLayoutParser::parse_plugin_user_configuration(&kdl_action)?; @@ -935,6 +943,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action { run_plugin, should_float, move_to_focused_tab, + should_open_in_place, )) }, "PreviousSwapLayout" => Ok(Action::PreviousSwapLayout), diff --git a/zellij-utils/src/plugin_api/action.proto b/zellij-utils/src/plugin_api/action.proto index 7e40bde24c..1545b9bf44 100644 --- a/zellij-utils/src/plugin_api/action.proto +++ b/zellij-utils/src/plugin_api/action.proto @@ -85,6 +85,7 @@ message LaunchOrFocusPluginPayload { bool should_float = 2; optional PluginConfiguration plugin_configuration = 3; bool move_to_focused_tab = 4; + bool should_open_in_place = 5; } message GoToTabNamePayload { diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index d4ecf02e08..70278d461a 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -402,10 +402,12 @@ impl TryFrom for Action { }; let should_float = payload.should_float; let move_to_focused_tab = payload.move_to_focused_tab; + let should_open_in_place = payload.should_open_in_place; Ok(Action::LaunchOrFocusPlugin( run_plugin, should_float, move_to_focused_tab, + should_open_in_place, )) }, _ => Err("Wrong payload for Action::LaunchOrFocusPlugin"), @@ -961,7 +963,7 @@ impl TryFrom for ProtobufAction { optional_payload: Some(OptionalPayload::MiddleClickPayload(position)), }) }, - Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab) => { + Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab, should_open_in_place) => { let url: Url = Url::from(&run_plugin.location); Ok(ProtobufAction { name: ProtobufActionName::LaunchOrFocusPlugin as i32, @@ -970,6 +972,7 @@ impl TryFrom for ProtobufAction { plugin_url: url.into(), should_float, move_to_focused_tab, + should_open_in_place, plugin_configuration: Some(run_plugin.configuration.try_into()?), }, )), @@ -1152,6 +1155,7 @@ impl TryFrom for ProtobufAction { Action::NoOp | Action::Confirm | Action::NewInPlacePane(..) // TODO: implement this + | Action::NewInPlacePluginPane(..) // TODO: implement this | Action::Deny | Action::Copy | Action::SkipConfirm(..) => Err("Unsupported action"), From ffde90e04c3fbd19a3f1363f06dbc1b2924fa174 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 18 Sep 2023 14:02:18 +0200 Subject: [PATCH 4/7] add in-place to plugin commands --- zellij-server/src/panes/floating_panes/mod.rs | 5 +- zellij-server/src/panes/tiled_panes/mod.rs | 1 + .../src/plugins/unit/plugin_tests.rs | 134 ++++++++++++++++++ zellij-server/src/plugins/zellij_exports.rs | 67 ++++++++- zellij-server/src/unit/screen_tests.rs | 2 + ...end_cli_launch_or_focus_plugin_action.snap | 4 +- zellij-tile/src/shim.rs | 27 +++- .../assets/prost/api.plugin_command.rs | 17 ++- zellij-utils/src/data.rs | 3 + zellij-utils/src/plugin_api/action.rs | 2 +- .../src/plugin_api/plugin_command.proto | 6 + zellij-utils/src/plugin_api/plugin_command.rs | 55 ++++++- ..._default_config_with_no_cli_arguments.snap | 1 + ...out_env_vars_override_config_env_vars.snap | 1 + ...ayout_plugins_override_config_plugins.snap | 1 + ..._layout_themes_override_config_themes.snap | 1 + ..._ui_config_overrides_config_ui_config.snap | 1 + 17 files changed, 318 insertions(+), 10 deletions(-) diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs index ed21b010a3..61205668e6 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -157,6 +157,7 @@ impl FloatingPanes { // move clients from the previously active pane to the new pane we just inserted self.move_clients_between_panes(pane_id, with_pane_id); + self.set_pane_frames(); removed_pane } pub fn remove_pane(&mut self, pane_id: PaneId) -> Option> { @@ -295,7 +296,7 @@ impl FloatingPanes { pane.render_full_viewport(); } } - pub fn set_pane_frames(&mut self, _os_api: &mut Box) -> Result<()> { + pub fn set_pane_frames(&mut self) -> Result<()> { let err_context = |pane_id: &PaneId| format!("failed to activate frame on pane {pane_id:?}"); @@ -640,7 +641,7 @@ impl FloatingPanes { current_position.set_geom_override(geom); } current_position.set_should_render(true); - let _ = self.set_pane_frames(os_api); + let _ = self.set_pane_frames(); } } pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) { diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 71a53a330a..6477a8af00 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -159,6 +159,7 @@ impl TiledPanes { // move clients from the previously active pane to the new pane we just inserted self.move_clients_between_panes(pane_id, with_pane_id); + self.reapply_pane_frames(); removed_pane } pub fn insert_pane(&mut self, pane_id: PaneId, pane: Box) { diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index 222b14c659..5c0600cacb 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -533,9 +533,11 @@ pub fn load_new_plugin_from_hd() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -601,9 +603,11 @@ pub fn plugin_workers() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -672,9 +676,11 @@ pub fn plugin_workers_persist_state() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -747,9 +753,11 @@ pub fn can_subscribe_to_hd_events() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -817,9 +825,11 @@ pub fn switch_to_mode_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -885,9 +895,11 @@ pub fn switch_to_mode_plugin_command_permission_denied() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -953,9 +965,11 @@ pub fn new_tabs_with_layout_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1035,9 +1049,11 @@ pub fn new_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1103,9 +1119,11 @@ pub fn go_to_next_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1170,9 +1188,11 @@ pub fn go_to_previous_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1237,9 +1257,11 @@ pub fn resize_focused_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1304,9 +1326,11 @@ pub fn resize_focused_pane_with_direction_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1371,9 +1395,11 @@ pub fn focus_next_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1438,9 +1464,11 @@ pub fn focus_previous_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1505,9 +1533,11 @@ pub fn move_focus_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1572,9 +1602,11 @@ pub fn move_focus_or_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1639,9 +1671,11 @@ pub fn edit_scrollback_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1706,9 +1740,11 @@ pub fn write_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1773,9 +1809,11 @@ pub fn write_chars_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1840,9 +1878,11 @@ pub fn toggle_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1907,9 +1947,11 @@ pub fn move_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -1974,9 +2016,11 @@ pub fn move_pane_with_direction_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2042,9 +2086,11 @@ pub fn clear_screen_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2110,9 +2156,11 @@ pub fn scroll_up_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2177,9 +2225,11 @@ pub fn scroll_down_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2244,9 +2294,11 @@ pub fn scroll_to_top_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2311,9 +2363,11 @@ pub fn scroll_to_bottom_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2378,9 +2432,11 @@ pub fn page_scroll_up_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2445,9 +2501,11 @@ pub fn page_scroll_down_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2512,9 +2570,11 @@ pub fn toggle_focus_fullscreen_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2579,9 +2639,11 @@ pub fn toggle_pane_frames_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2646,9 +2708,11 @@ pub fn toggle_pane_embed_or_eject_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2713,9 +2777,11 @@ pub fn undo_rename_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2780,9 +2846,11 @@ pub fn close_focus_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2847,9 +2915,11 @@ pub fn toggle_active_tab_sync_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2914,9 +2984,11 @@ pub fn close_focused_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -2981,9 +3053,11 @@ pub fn undo_rename_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3048,9 +3122,11 @@ pub fn previous_swap_layout_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3115,9 +3191,11 @@ pub fn next_swap_layout_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3182,9 +3260,11 @@ pub fn go_to_tab_name_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3249,9 +3329,11 @@ pub fn focus_or_create_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3316,9 +3398,11 @@ pub fn go_to_tab() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3383,9 +3467,11 @@ pub fn start_or_reload_plugin() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3457,9 +3543,11 @@ pub fn quit_zellij_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3531,9 +3619,11 @@ pub fn detach_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3605,9 +3695,11 @@ pub fn open_file_floating_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3679,9 +3771,11 @@ pub fn open_file_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3754,9 +3848,11 @@ pub fn open_file_with_line_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3828,9 +3924,11 @@ pub fn open_file_with_line_floating_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3902,9 +4000,11 @@ pub fn open_terminal_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -3976,9 +4076,11 @@ pub fn open_terminal_floating_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4050,9 +4152,11 @@ pub fn open_command_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4124,9 +4228,11 @@ pub fn open_command_pane_floating_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4191,9 +4297,11 @@ pub fn switch_to_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4253,9 +4361,11 @@ pub fn hide_self_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4315,9 +4425,11 @@ pub fn show_self_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4382,9 +4494,11 @@ pub fn close_terminal_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4449,9 +4563,11 @@ pub fn close_plugin_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4516,9 +4632,11 @@ pub fn focus_terminal_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4583,9 +4701,11 @@ pub fn focus_plugin_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4650,9 +4770,11 @@ pub fn rename_terminal_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4717,9 +4839,11 @@ pub fn rename_plugin_pane_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4784,9 +4908,11 @@ pub fn rename_tab_plugin_command() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4860,9 +4986,11 @@ pub fn send_configuration_to_plugins() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -4924,9 +5052,11 @@ pub fn request_plugin_permissions() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin, tab_index, + None, client_id, size, )); @@ -5012,9 +5142,11 @@ pub fn granted_permission_request_result() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin.clone(), tab_index, + None, client_id, size, )); @@ -5098,9 +5230,11 @@ pub fn denied_permission_request_result() { let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); let _ = plugin_thread_sender.send(PluginInstruction::Load( plugin_should_float, + false, plugin_title, run_plugin.clone(), tab_index, + None, client_id, size, )); diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index 908bfeb086..d256d4c24f 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -215,6 +215,15 @@ fn host_run_plugin_command(env: &ForeignFunctionEnv) { connect_to_session.tab_position, connect_to_session.pane_id, )?, + PluginCommand::OpenFileInPlace(file_to_open) => { + open_file_in_place(env, file_to_open) + }, + PluginCommand::OpenTerminalInPlace(cwd) => { + open_terminal_in_place(env, cwd.path.try_into()?) + }, + PluginCommand::OpenCommandPaneInPlace(command_to_run) => { + open_command_pane_in_place(env, command_to_run) + }, }, (PermissionStatus::Denied, permission) => { log::error!( @@ -375,6 +384,21 @@ fn open_file_floating(env: &ForeignFunctionEnv, file_to_open: FileToOpen) { apply_action!(action, error_msg, env); } +fn open_file_in_place(env: &ForeignFunctionEnv, file_to_open: FileToOpen) { + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let floating = false; + let in_place = true; + let action = Action::EditFile( + file_to_open.path, + file_to_open.line_number, + file_to_open.cwd, + None, + floating, + in_place, + ); + apply_action!(action, error_msg, env); +} + fn open_terminal(env: &ForeignFunctionEnv, cwd: PathBuf) { let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); let mut default_shell = env @@ -407,6 +431,22 @@ fn open_terminal_floating(env: &ForeignFunctionEnv, cwd: PathBuf) { apply_action!(action, error_msg, env); } +fn open_terminal_in_place(env: &ForeignFunctionEnv, cwd: PathBuf) { + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let mut default_shell = env + .plugin_env + .default_shell + .clone() + .unwrap_or_else(|| TerminalAction::RunCommand(RunCommand::default())); + default_shell.change_cwd(cwd); + let run_command_action: Option = match default_shell { + TerminalAction::RunCommand(run_command) => Some(run_command.into()), + _ => None, + }; + let action = Action::NewInPlacePane(run_command_action, None); + apply_action!(action, error_msg, env); +} + fn open_command_pane(env: &ForeignFunctionEnv, command_to_run: CommandToRun) { let error_msg = || format!("failed to open command in plugin {}", env.plugin_env.name()); let command = command_to_run.path; @@ -449,6 +489,27 @@ fn open_command_pane_floating(env: &ForeignFunctionEnv, command_to_run: CommandT apply_action!(action, error_msg, env); } +fn open_command_pane_in_place(env: &ForeignFunctionEnv, command_to_run: CommandToRun) { + let error_msg = || format!("failed to open command in plugin {}", env.plugin_env.name()); + let command = command_to_run.path; + let cwd = command_to_run.cwd; + let args = command_to_run.args; + let direction = None; + let hold_on_close = true; + let hold_on_start = false; + let name = None; + let run_command_action = RunCommandAction { + command, + args, + cwd, + direction, + hold_on_close, + hold_on_start, + }; + let action = Action::NewInPlacePane(Some(run_command_action), name); + apply_action!(action, error_msg, env); +} + fn switch_tab_to(env: &ForeignFunctionEnv, tab_idx: u32) { env.plugin_env .senders @@ -1095,14 +1156,16 @@ fn check_command_permission( return (PermissionStatus::Granted, None); } let permission = match command { - PluginCommand::OpenFile(..) | PluginCommand::OpenFileFloating(..) => { + PluginCommand::OpenFile(..) | PluginCommand::OpenFileFloating(..) | PluginCommand::OpenFileInPlace(..) => { PermissionType::OpenFiles }, PluginCommand::OpenTerminal(..) | PluginCommand::StartOrReloadPlugin(..) - | PluginCommand::OpenTerminalFloating(..) => PermissionType::OpenTerminalsOrPlugins, + | PluginCommand::OpenTerminalFloating(..) + | PluginCommand::OpenTerminalInPlace(..) => PermissionType::OpenTerminalsOrPlugins, PluginCommand::OpenCommandPane(..) | PluginCommand::OpenCommandPaneFloating(..) + | PluginCommand::OpenCommandPaneInPlace(..) | PluginCommand::ExecCmd(..) => PermissionType::RunCommands, PluginCommand::Write(..) | PluginCommand::WriteChars(..) => PermissionType::WriteToStdin, PluginCommand::SwitchTabTo(..) diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index f84e4b81c4..5e38352ec7 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -2574,6 +2574,7 @@ pub fn send_cli_launch_or_focus_plugin_action() { ); let cli_action = CliAction::LaunchOrFocusPlugin { floating: true, + in_place: false, move_to_focused_tab: true, url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), configuration: Default::default(), @@ -2632,6 +2633,7 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded() { ); let cli_action = CliAction::LaunchOrFocusPlugin { floating: true, + in_place: false, move_to_focused_tab: true, url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), configuration: Default::default(), diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap index d6420c3fcf..08a13a19eb 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2572 +assertion_line: 2596 expression: "format!(\"{:#?}\", plugin_load_instruction)" --- Some( @@ -8,6 +8,7 @@ Some( Some( true, ), + false, None, RunPlugin { _allow_exec_host_cmd: false, @@ -19,6 +20,7 @@ Some( ), }, 0, + None, 1, Size { rows: 0, diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index 591a0ca8e4..31445620fb 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -87,6 +87,14 @@ pub fn open_file_floating(file_to_open: FileToOpen) { unsafe { host_run_plugin_command() }; } +/// Open a file in the user's default `$EDITOR` in a new floating pane +pub fn open_file_in_place(file_to_open: FileToOpen) { + let plugin_command = PluginCommand::OpenFileInPlace(file_to_open); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + /// Open a new terminal pane to the specified location on the host filesystem pub fn open_terminal>(path: P) { let file_to_open = FileToOpen::new(path.as_ref().to_path_buf()); @@ -105,8 +113,16 @@ pub fn open_terminal_floating>(path: P) { unsafe { host_run_plugin_command() }; } +/// Open a new floating terminal pane to the specified location on the host filesystem +pub fn open_terminal_in_place>(path: P) { + let file_to_open = FileToOpen::new(path.as_ref().to_path_buf()); + let plugin_command = PluginCommand::OpenTerminalInPlace(file_to_open); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + /// Open a new command pane with the specified command and args (this sort of pane allows the user to control the command, re-run it and see its exit status through the Zellij UI). -// pub fn open_command_pane, A: AsRef>(path: P, args: Vec) { pub fn open_command_pane(command_to_run: CommandToRun) { let plugin_command = PluginCommand::OpenCommandPane(command_to_run); let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); @@ -115,7 +131,6 @@ pub fn open_command_pane(command_to_run: CommandToRun) { } /// Open a new floating command pane with the specified command and args (this sort of pane allows the user to control the command, re-run it and see its exit status through the Zellij UI). -// pub fn open_command_pane_floating, A: AsRef>(path: P, args: Vec) { pub fn open_command_pane_floating(command_to_run: CommandToRun) { let plugin_command = PluginCommand::OpenCommandPaneFloating(command_to_run); let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); @@ -123,6 +138,14 @@ pub fn open_command_pane_floating(command_to_run: CommandToRun) { unsafe { host_run_plugin_command() }; } +/// Open a new floating command pane with the specified command and args (this sort of pane allows the user to control the command, re-run it and see its exit status through the Zellij UI). +pub fn open_command_pane_in_place(command_to_run: CommandToRun) { + let plugin_command = PluginCommand::OpenCommandPaneInPlace(command_to_run); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + /// Change the focused tab to the specified index (corresponding with the default tab names, to starting at `1`, `0` will be considered as `1`). pub fn switch_tab_to(tab_idx: u32) { let plugin_command = PluginCommand::SwitchTabTo(tab_idx); diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs index da13196c00..b86f954912 100644 --- a/zellij-utils/assets/prost/api.plugin_command.rs +++ b/zellij-utils/assets/prost/api.plugin_command.rs @@ -5,7 +5,7 @@ pub struct PluginCommand { pub name: i32, #[prost( 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" + 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" )] pub payload: ::core::option::Option, } @@ -90,6 +90,12 @@ pub mod plugin_command { RequestPluginPermissionPayload(super::RequestPluginPermissionPayload), #[prost(message, tag = "39")] SwitchSessionPayload(super::SwitchSessionPayload), + #[prost(message, tag = "40")] + OpenFileInPlacePayload(super::OpenFilePayload), + #[prost(message, tag = "41")] + OpenTerminalInPlacePayload(super::OpenFilePayload), + #[prost(message, tag = "42")] + OpenCommandPaneInPlacePayload(super::OpenCommandPanePayload), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -254,6 +260,9 @@ pub enum CommandName { ReportCrash = 65, RequestPluginPermissions = 66, SwitchSession = 67, + OpenTerminalInPlace = 68, + OpenCommandInPlace = 69, + OpenFileInPlace = 70, } impl CommandName { /// String value of the enum field names used in the ProtoBuf definition. @@ -330,6 +339,9 @@ impl CommandName { CommandName::ReportCrash => "ReportCrash", CommandName::RequestPluginPermissions => "RequestPluginPermissions", CommandName::SwitchSession => "SwitchSession", + CommandName::OpenTerminalInPlace => "OpenTerminalInPlace", + CommandName::OpenCommandInPlace => "OpenCommandInPlace", + CommandName::OpenFileInPlace => "OpenFileInPlace", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -403,6 +415,9 @@ impl CommandName { "ReportCrash" => Some(Self::ReportCrash), "RequestPluginPermissions" => Some(Self::RequestPluginPermissions), "SwitchSession" => Some(Self::SwitchSession), + "OpenTerminalInPlace" => Some(Self::OpenTerminalInPlace), + "OpenCommandInPlace" => Some(Self::OpenCommandInPlace), + "OpenFileInPlace" => Some(Self::OpenFileInPlace), _ => None, } } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index fc09538cba..3702dace4c 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -1061,4 +1061,7 @@ pub enum PluginCommand { ReportPanic(String), // stringified panic RequestPluginPermissions(Vec), SwitchSession(ConnectToSession), + OpenTerminalInPlace(FileToOpen), // only used for the path as cwd + OpenFileInPlace(FileToOpen), + OpenCommandPaneInPlace(CommandToRun), } diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 70278d461a..93e05e1261 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -818,7 +818,7 @@ impl TryFrom for ProtobufAction { })), }) }, - Action::EditFile(path_to_file, line_number, cwd, direction, should_float, should_be_in_place) => { + Action::EditFile(path_to_file, line_number, cwd, direction, should_float, _should_be_in_place) => { let file_to_edit = path_to_file.display().to_string(); let cwd = cwd.map(|cwd| cwd.display().to_string()); let direction: Option = direction diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index fed8ec54d5..17b153810d 100644 --- a/zellij-utils/src/plugin_api/plugin_command.proto +++ b/zellij-utils/src/plugin_api/plugin_command.proto @@ -79,6 +79,9 @@ enum CommandName { ReportCrash = 65; RequestPluginPermissions = 66; SwitchSession = 67; + OpenTerminalInPlace = 68; + OpenCommandInPlace = 69; + OpenFileInPlace = 70; } message PluginCommand { @@ -122,6 +125,9 @@ message PluginCommand { string report_crash_payload = 37; RequestPluginPermissionPayload request_plugin_permission_payload = 38; SwitchSessionPayload switch_session_payload = 39; + OpenFilePayload open_file_in_place_payload = 40; + OpenFilePayload open_terminal_in_place_payload = 41; + OpenCommandPanePayload open_command_pane_in_place_payload = 42; } } diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 25773ba3ab..1f125989dc 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -82,7 +82,7 @@ impl TryFrom for PluginCommand { None => Err("Malformed open file payload"), } }, - _ => Err("Mismatched payload for OpenFile"), + _ => Err("Mismatched payload for OpenFileFloating"), }, Some(CommandName::OpenTerminal) => match protobuf_plugin_command.payload { Some(Payload::OpenTerminalPayload(file_to_open_payload)) => { @@ -520,6 +520,39 @@ impl TryFrom for PluginCommand { }, _ => Err("Mismatched payload for SwitchSession"), }, + Some(CommandName::OpenTerminalInPlace) => match protobuf_plugin_command.payload { + Some(Payload::OpenTerminalInPlacePayload(file_to_open_payload)) => { + match file_to_open_payload.file_to_open { + Some(file_to_open) => Ok(PluginCommand::OpenTerminalInPlace( + file_to_open.try_into()?, + )), + None => Err("Malformed open terminal in-place payload"), + } + }, + _ => Err("Mismatched payload for OpenTerminalInPlace"), + }, + Some(CommandName::OpenFileInPlace) => match protobuf_plugin_command.payload { + Some(Payload::OpenFileInPlacePayload(file_to_open_payload)) => { + match file_to_open_payload.file_to_open { + Some(file_to_open) => { + Ok(PluginCommand::OpenFileInPlace(file_to_open.try_into()?)) + }, + None => Err("Malformed open file in place payload"), + } + }, + _ => Err("Mismatched payload for OpenFileInPlace"), + }, + Some(CommandName::OpenCommandInPlace) => match protobuf_plugin_command.payload { + Some(Payload::OpenCommandPaneInPlacePayload(command_to_run_payload)) => { + match command_to_run_payload.command_to_run { + Some(command_to_run) => Ok(PluginCommand::OpenCommandPaneInPlace( + command_to_run.try_into()?, + )), + None => Err("Malformed open command pane in-place payload"), + } + }, + _ => Err("Mismatched payload for OpenCommandPaneInPlace"), + }, None => Err("Unrecognized plugin command"), } } @@ -875,6 +908,26 @@ impl TryFrom for ProtobufPluginCommand { pane_id_is_plugin: switch_to_session.pane_id.map(|p| p.1), })), }), + PluginCommand::OpenTerminalInPlace(cwd) => Ok(ProtobufPluginCommand { + name: CommandName::OpenTerminalInPlace as i32, + payload: Some(Payload::OpenTerminalInPlacePayload(OpenFilePayload { + file_to_open: Some(cwd.try_into()?), + })), + }), + PluginCommand::OpenFileInPlace(file_to_open) => Ok(ProtobufPluginCommand { + name: CommandName::OpenFileInPlace as i32, + payload: Some(Payload::OpenFileInPlacePayload(OpenFilePayload { + file_to_open: Some(file_to_open.try_into()?), + })), + }), + PluginCommand::OpenCommandPaneInPlace(command_to_run) => Ok(ProtobufPluginCommand { + name: CommandName::OpenCommandInPlace as i32, + payload: Some(Payload::OpenCommandPaneInPlacePayload( + OpenCommandPanePayload { + command_to_run: Some(command_to_run.try_into()?), + }, + )), + }), } } } diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap index 2f0a54b9d5..9715474152 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap @@ -2506,6 +2506,7 @@ Config { }, true, true, + false, ), SwitchToMode( Normal, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap index 7ceedc6810..589de23284 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap @@ -2506,6 +2506,7 @@ Config { }, true, true, + false, ), SwitchToMode( Normal, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap index 9c8dda6719..ab867fa707 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_plugins_override_config_plugins.snap @@ -2506,6 +2506,7 @@ Config { }, true, true, + false, ), SwitchToMode( Normal, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap index d9ead2b96b..6de213ed77 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap @@ -2506,6 +2506,7 @@ Config { }, true, true, + false, ), SwitchToMode( Normal, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap index 7f05ec5c4d..e44e52f256 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap @@ -2506,6 +2506,7 @@ Config { }, true, true, + false, ), SwitchToMode( Normal, From 1dc23142fb90f63c9a495914f0b9d545b2def528 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 18 Sep 2023 15:18:00 +0200 Subject: [PATCH 5/7] fix launch-or-focus should_float and in place behavior --- zellij-server/src/screen.rs | 6 ++---- zellij-utils/src/input/actions.rs | 26 -------------------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index e66dbc0000..fbf0788418 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -3131,11 +3131,9 @@ pub(crate) fn screen_thread_main( match screen.active_tab_indices.values().next() { Some(tab_index) => { let size = Size::default(); - let should_float = None; - let should_be_in_place = true; screen.bus.senders.send_to_plugin(PluginInstruction::Load( - should_float, - should_be_in_place, + Some(should_float), + should_open_in_place, None, run_plugin, *tab_index, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 6a7d22e4c8..9e77bb607a 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -525,32 +525,6 @@ impl Action { move_to_focused_tab, configuration, } => { - // TODO: CONTINUE HERE (before vacation) - add an in_place flag and make it work - // - we already did this with the NewPane action above, to test: - // * cargo x run --singlepass - // * target/dev-opt/zellij action new-pane --in-place --plugin zellij:session-manager - // * this also already works with zellij run with the --in-place flag - // * we need to make it work with everything, then also make it work with plugins - // - make it work with LaunchOrFocusPlugin - DONE - // - make it work with the edit action - DONE - // - test with keybinding - // * run - DONE - // * launch_or_focus_plugin - DONE (has some issues, might want to test again - // with properly fixed monocle) - // - add to plugins (open_terminal_in_place, open_command_pane_in_place, - // open_file_in_place) <== CONTINUE HERE - // - test these with/without flag - // * zellij run - // * zellij action new-pane (command and plugin) - // * zellij action launch-or-focus-plugin - // * zellij action edit - // * zellij edit - // * keybinding - // - run - // - launch_or_focus_plugin - // * plugins (show_self/hide_self, open_file_in_place(n), - // open_terminal_in_place(n), open_command_pane_in_place(n)) - let current_dir = get_current_dir(); let run_plugin_location = RunPluginLocation::parse(url.as_str(), Some(current_dir)) .map_err(|e| format!("Failed to parse plugin location: {}", e))?; From e9cbfe4268fe8dd6d6bb458083c8ac07ff63e873 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 18 Sep 2023 15:39:31 +0200 Subject: [PATCH 6/7] various cleanups --- zellij-utils/src/plugin_api/action.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 93e05e1261..98c8e7ec7e 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -232,7 +232,7 @@ impl TryFrom for Action { .and_then(|d| ProtobufResizeDirection::from_i32(d)) .and_then(|d| d.try_into().ok()); let should_float = payload.should_float; - let should_be_in_place = false; // TODO: implement this + let should_be_in_place = false; Ok(Action::EditFile( file_to_edit, line_number, @@ -1154,8 +1154,8 @@ impl TryFrom for ProtobufAction { }), Action::NoOp | Action::Confirm - | Action::NewInPlacePane(..) // TODO: implement this - | Action::NewInPlacePluginPane(..) // TODO: implement this + | Action::NewInPlacePane(..) + | Action::NewInPlacePluginPane(..) | Action::Deny | Action::Copy | Action::SkipConfirm(..) => Err("Unsupported action"), From d00e4f99be1ec0639a61e90904421153f1d58373 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 18 Sep 2023 15:39:49 +0200 Subject: [PATCH 7/7] style(fmt): rustfmt --- zellij-client/src/cli_client.rs | 4 +- zellij-client/src/os_input_output.rs | 4 +- zellij-server/src/plugins/mod.rs | 49 +++--- zellij-server/src/plugins/zellij_exports.rs | 6 +- zellij-server/src/pty.rs | 24 +-- zellij-server/src/route.rs | 48 ++--- zellij-server/src/screen.rs | 164 ++++++++++-------- zellij-server/src/tab/mod.rs | 13 +- .../src/tab/unit/tab_integration_tests.rs | 24 ++- zellij-server/src/tab/unit/tab_tests.rs | 3 +- zellij-utils/src/cli.rs | 40 ++++- zellij-utils/src/input/actions.rs | 14 +- zellij-utils/src/plugin_api/action.rs | 18 +- zellij-utils/src/plugin_api/plugin_command.rs | 6 +- 14 files changed, 258 insertions(+), 159 deletions(-) diff --git a/zellij-client/src/cli_client.rs b/zellij-client/src/cli_client.rs index 2a2543adf1..6ebc10aebb 100644 --- a/zellij-client/src/cli_client.rs +++ b/zellij-client/src/cli_client.rs @@ -18,7 +18,9 @@ pub fn start_cli_client(os_input: Box, session_name: &str, acti sock_dir }; os_input.connect_to_server(&*zellij_ipc_pipe); - let pane_id = os_input.env_variable("ZELLIJ_PANE_ID").and_then(|e| e.trim().parse().ok()); + let pane_id = os_input + .env_variable("ZELLIJ_PANE_ID") + .and_then(|e| e.trim().parse().ok()); for action in actions { let msg = ClientToServerMsg::Action(action, pane_id, None); os_input.send_to_server(msg); diff --git a/zellij-client/src/os_input_output.rs b/zellij-client/src/os_input_output.rs index bfc8cc0769..d6fb3b30a5 100644 --- a/zellij-client/src/os_input_output.rs +++ b/zellij-client/src/os_input_output.rs @@ -114,7 +114,9 @@ pub trait ClientOsApi: Send + Sync { fn disable_mouse(&self) -> Result<()>; // Repeatedly send action, until stdin is readable again fn stdin_poller(&self) -> StdinPoller; - fn env_variable(&self, _name: &str) -> Option { None } + fn env_variable(&self, _name: &str) -> Option { + None + } } impl ClientOsApi for ClientOsInputOutput { diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index 36bfae8def..deb368c18f 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -12,9 +12,9 @@ use std::{ }; use wasmer::Store; +use crate::panes::PaneId; use crate::screen::ScreenInstruction; use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId, ServerInstruction}; -use crate::panes::PaneId; use wasm_bridge::WasmBridge; @@ -39,10 +39,10 @@ pub type PluginId = u32; pub enum PluginInstruction { Load( Option, // should float - bool, // should be opened in place + bool, // should be opened in place Option, // pane title RunPlugin, - usize, // tab index + usize, // tab index Option, // pane id to replace if this is to be opened "in-place" ClientId, Size, @@ -159,24 +159,31 @@ pub(crate) fn plugin_thread_main( let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel"); err_ctx.add_call(ContextType::Plugin((&event).into())); match event { - PluginInstruction::Load(should_float, should_be_open_in_place, pane_title, run, tab_index, pane_id_to_replace, client_id, size) => { - match wasm_bridge.load_plugin(&run, tab_index, size, Some(client_id)) { - Ok(plugin_id) => { - drop(bus.senders.send_to_screen(ScreenInstruction::AddPlugin( - should_float, - should_be_open_in_place, - run, - pane_title, - tab_index, - plugin_id, - pane_id_to_replace, - Some(client_id), - ))); - }, - Err(e) => { - log::error!("Failed to load plugin: {e}"); - }, - } + PluginInstruction::Load( + should_float, + should_be_open_in_place, + pane_title, + run, + tab_index, + pane_id_to_replace, + client_id, + size, + ) => match wasm_bridge.load_plugin(&run, tab_index, size, Some(client_id)) { + Ok(plugin_id) => { + drop(bus.senders.send_to_screen(ScreenInstruction::AddPlugin( + should_float, + should_be_open_in_place, + run, + pane_title, + tab_index, + plugin_id, + pane_id_to_replace, + Some(client_id), + ))); + }, + Err(e) => { + log::error!("Failed to load plugin: {e}"); + }, }, PluginInstruction::Update(updates) => { wasm_bridge.update_plugins(updates)?; diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index d256d4c24f..901f66b276 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -1156,9 +1156,9 @@ fn check_command_permission( return (PermissionStatus::Granted, None); } let permission = match command { - PluginCommand::OpenFile(..) | PluginCommand::OpenFileFloating(..) | PluginCommand::OpenFileInPlace(..) => { - PermissionType::OpenFiles - }, + PluginCommand::OpenFile(..) + | PluginCommand::OpenFileFloating(..) + | PluginCommand::OpenFileInPlace(..) => PermissionType::OpenFiles, PluginCommand::OpenTerminal(..) | PluginCommand::StartOrReloadPlugin(..) | PluginCommand::OpenTerminalFloating(..) diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index be363a63fa..40a98326cf 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -176,8 +176,12 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { name, client_id_tab_index_or_pane_id, ) => { - let err_context = - || format!("failed to spawn terminal for {:?}", client_id_tab_index_or_pane_id); + let err_context = || { + format!( + "failed to spawn terminal for {:?}", + client_id_tab_index_or_pane_id + ) + }; let (hold_on_close, run_command, pane_title) = match &terminal_action { Some(TerminalAction::RunCommand(run_command)) => ( run_command.hold_on_close, @@ -574,14 +578,12 @@ impl Pty { fn fill_cwd_from_pane_id(&self, terminal_action: &mut TerminalAction, pane_id: &u32) { if let TerminalAction::RunCommand(run_command) = terminal_action { if run_command.cwd.is_none() { - run_command.cwd = self - .id_to_child_pid.get(pane_id) - .and_then(|&id| { - self.bus - .os_input - .as_ref() - .and_then(|input| input.get_cwd(Pid::from_raw(id))) - }); + run_command.cwd = self.id_to_child_pid.get(pane_id).and_then(|&id| { + self.bus + .os_input + .as_ref() + .and_then(|input| input.get_cwd(Pid::from_raw(id))) + }); }; }; } @@ -611,7 +613,7 @@ impl Pty { self.fill_cwd_from_pane_id(&mut terminal_action, &terminal_pane_id); } terminal_action - } + }, }; let (hold_on_start, hold_on_close) = match &terminal_action { TerminalAction::RunCommand(run_command) => { diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index d7efea9703..ab6dd26194 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -263,7 +263,14 @@ pub(crate) fn route_action( }; senders.send_to_pty(pty_instr).with_context(err_context)?; }, - Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float, should_open_in_place) => { + Action::EditFile( + path_to_file, + line_number, + cwd, + split_direction, + should_float, + should_open_in_place, + ) => { let title = format!("Editing: {}", path_to_file.display()); let open_file = TerminalAction::OpenFile(path_to_file, line_number, cwd); let pty_instr = match (split_direction, should_float, should_open_in_place) { @@ -284,24 +291,18 @@ pub(crate) fn route_action( client_id, ), // open terminal in place - (_, _, true) => { - match pane_id { - Some(pane_id) => { - PtyInstruction::SpawnInPlaceTerminal( - Some(open_file), - Some(title), - ClientTabIndexOrPaneId::PaneId(pane_id), - ) - }, - None => { - PtyInstruction::SpawnInPlaceTerminal( - Some(open_file), - Some(title), - ClientTabIndexOrPaneId::ClientId(client_id) - ) - }, - } - } + (_, _, true) => match pane_id { + Some(pane_id) => PtyInstruction::SpawnInPlaceTerminal( + Some(open_file), + Some(title), + ClientTabIndexOrPaneId::PaneId(pane_id), + ), + None => PtyInstruction::SpawnInPlaceTerminal( + Some(open_file), + Some(title), + ClientTabIndexOrPaneId::ClientId(client_id), + ), + }, // Open either floating terminal if we were asked with should_float or defer // placement to screen (None, _, _) | (_, true, _) => PtyInstruction::SpawnTerminal( @@ -363,7 +364,7 @@ pub(crate) fn route_action( .send_to_pty(PtyInstruction::SpawnInPlaceTerminal( run_cmd, name, - ClientTabIndexOrPaneId::ClientId(client_id) + ClientTabIndexOrPaneId::ClientId(client_id), )) .with_context(err_context)?; }, @@ -678,7 +679,12 @@ pub(crate) fn route_action( .send_to_screen(ScreenInstruction::StartOrReloadPluginPane(run_plugin, None)) .with_context(err_context)?; }, - Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab, should_open_in_place) => { + Action::LaunchOrFocusPlugin( + run_plugin, + should_float, + move_to_focused_tab, + should_open_in_place, + ) => { senders .send_to_screen(ScreenInstruction::LaunchOrFocusPlugin( run_plugin, diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index fbf0788418..cb7e519d12 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -273,7 +273,7 @@ pub enum ScreenInstruction { StartOrReloadPluginPane(RunPlugin, Option), AddPlugin( Option, // should_float - bool, // should be opened in place + bool, // should be opened in place RunPlugin, Option, // pane title usize, // tab index @@ -286,8 +286,8 @@ pub enum ScreenInstruction { ProgressPluginLoadingOffset(u32), // u32 - plugin id RequestStateUpdateForPlugins, LaunchOrFocusPlugin(RunPlugin, bool, bool, bool, Option, ClientId), // bools are: should_float, move_to_focused_tab, should_open_in_place Option is the pane id to replace - SuppressPane(PaneId, ClientId), // bool is should_float - FocusPaneWithId(PaneId, bool, ClientId), // bool is should_float + SuppressPane(PaneId, ClientId), // bool is should_float + FocusPaneWithId(PaneId, bool, ClientId), // bool is should_float RenamePane(PaneId, Vec), RenameTab(usize, Vec), RequestPluginPermissions( @@ -302,7 +302,7 @@ pub enum ScreenInstruction { PaneId, HoldForCommand, Option, - ClientTabIndexOrPaneId + ClientTabIndexOrPaneId, ), } @@ -1840,7 +1840,7 @@ impl Screen { hold_for_command: HoldForCommand, run_plugin: Option, pane_title: Option, - client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId + client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId, ) -> Result<()> { let err_context = || format!("failed to replace pane"); let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| { @@ -1850,12 +1850,7 @@ impl Screen { } if let Some(hold_for_command) = hold_for_command { let is_first_run = true; - tab.hold_pane( - new_pane_id, - None, - is_first_run, - hold_for_command - ) + tab.hold_pane(new_pane_id, None, is_first_run, hold_for_command) } }; match client_id_tab_index_or_pane_id { @@ -1866,11 +1861,14 @@ impl Screen { suppress_pane(tab, pane_id, new_pane_id); }, None => { - log::error!("Failed to find active pane for client id: {:?}", client_id); - } + log::error!( + "Failed to find active pane for client id: {:?}", + client_id + ); + }, } }) - } + }, ClientTabIndexOrPaneId::PaneId(pane_id) => { let tab_index = self .tabs @@ -1879,19 +1877,17 @@ impl Screen { .map(|(tab_index, _tab)| *tab_index); match tab_index { Some(tab_index) => { - let tab = self.tabs - .get_mut(&tab_index) - .with_context(err_context)?; + let tab = self.tabs.get_mut(&tab_index).with_context(err_context)?; suppress_pane(tab, pane_id, new_pane_id); }, None => { log::error!("Could not find pane with id: {:?}", pane_id); }, }; - } + }, ClientTabIndexOrPaneId::TabIndex(tab_index) => { log::error!("Cannot replace pane with tab index"); - } + }, } Ok(()) } @@ -2033,7 +2029,7 @@ pub(crate) fn screen_thread_main( }, ClientTabIndexOrPaneId::PaneId(pane_id) => { log::error!("cannot open a pane with a pane id??"); - } + }, }; screen.unblock_input()?; screen.log_and_report_session_state()?; @@ -3003,29 +2999,32 @@ pub(crate) fn screen_thread_main( }, } }, - ScreenInstruction::NewInPlacePluginPane(run_plugin, pane_title, pane_id_to_replace, client_id) => { - match screen.active_tab_indices.values().next() { - Some(tab_index) => { - let size = Size::default(); - let should_float = None; - let should_be_in_place = true; - screen.bus.senders.send_to_plugin(PluginInstruction::Load( - should_float, - should_be_in_place, - pane_title, - run_plugin, - *tab_index, - Some(pane_id_to_replace), - client_id, - size, - ))?; - }, - None => { - log::error!( - "Could not find an active tab - is there at least 1 connected user?" - ); - }, - } + ScreenInstruction::NewInPlacePluginPane( + run_plugin, + pane_title, + pane_id_to_replace, + client_id, + ) => match screen.active_tab_indices.values().next() { + Some(tab_index) => { + let size = Size::default(); + let should_float = None; + let should_be_in_place = true; + screen.bus.senders.send_to_plugin(PluginInstruction::Load( + should_float, + should_be_in_place, + pane_title, + run_plugin, + *tab_index, + Some(pane_id_to_replace), + client_id, + size, + ))?; + }, + None => { + log::error!( + "Could not find an active tab - is there at least 1 connected user?" + ); + }, }, ScreenInstruction::StartOrReloadPluginPane(run_plugin, pane_title) => { let tab_index = screen.active_tab_indices.values().next().unwrap_or(&1); @@ -3058,11 +3057,25 @@ pub(crate) fn screen_thread_main( if should_be_in_place { if let Some(pane_id_to_replace) = pane_id_to_replace { - let client_tab_index_or_pane_id = ClientTabIndexOrPaneId::PaneId(pane_id_to_replace); - screen.replace_pane(PaneId::Plugin(plugin_id), None, Some(run_plugin), Some(pane_title), client_tab_index_or_pane_id)?; + let client_tab_index_or_pane_id = + ClientTabIndexOrPaneId::PaneId(pane_id_to_replace); + screen.replace_pane( + PaneId::Plugin(plugin_id), + None, + Some(run_plugin), + Some(pane_title), + client_tab_index_or_pane_id, + )?; } else if let Some(client_id) = client_id { - let client_tab_index_or_pane_id = ClientTabIndexOrPaneId::ClientId(client_id); - screen.replace_pane(PaneId::Plugin(plugin_id), None, Some(run_plugin), Some(pane_title), client_tab_index_or_pane_id)?; + let client_tab_index_or_pane_id = + ClientTabIndexOrPaneId::ClientId(client_id); + screen.replace_pane( + PaneId::Plugin(plugin_id), + None, + Some(run_plugin), + Some(pane_title), + client_tab_index_or_pane_id, + )?; } else { log::error!("Must have pane id to replace or connected client_id if replacing a pane"); } @@ -3127,27 +3140,25 @@ pub(crate) fn screen_thread_main( client_id, ) => { match pane_id_to_replace { - Some(pane_id_to_replace) => { - match screen.active_tab_indices.values().next() { - Some(tab_index) => { - let size = Size::default(); - screen.bus.senders.send_to_plugin(PluginInstruction::Load( - Some(should_float), - should_open_in_place, - None, - run_plugin, - *tab_index, - Some(pane_id_to_replace), - client_id, - size, - ))?; - }, - None => { - log::error!( + Some(pane_id_to_replace) => match screen.active_tab_indices.values().next() { + Some(tab_index) => { + let size = Size::default(); + screen.bus.senders.send_to_plugin(PluginInstruction::Load( + Some(should_float), + should_open_in_place, + None, + run_plugin, + *tab_index, + Some(pane_id_to_replace), + client_id, + size, + ))?; + }, + None => { + log::error!( "Could not find an active tab - is there at least 1 connected user?" ); - }, - } + }, }, None => { let client_id = if screen.active_tab_indices.contains_key(&client_id) { @@ -3184,9 +3195,11 @@ pub(crate) fn screen_thread_main( ))?; } }, - None => log::error!("No connected clients found - cannot load or focus plugin"), + None => log::error!( + "No connected clients found - cannot load or focus plugin" + ), } - } + }, } }, ScreenInstruction::SuppressPane(pane_id, client_id) => { @@ -3258,9 +3271,20 @@ pub(crate) fn screen_thread_main( ScreenInstruction::UpdateSessionInfos(new_session_infos) => { screen.update_session_infos(new_session_infos)?; }, - ScreenInstruction::ReplacePane(new_pane_id, hold_for_command, pane_title, client_id_tab_index_or_pane_id) => { + ScreenInstruction::ReplacePane( + new_pane_id, + hold_for_command, + pane_title, + client_id_tab_index_or_pane_id, + ) => { let err_context = || format!("Failed to replace pane"); - screen.replace_pane(new_pane_id, hold_for_command, None, pane_title, client_id_tab_index_or_pane_id)?; + screen.replace_pane( + new_pane_id, + hold_for_command, + None, + pane_title, + client_id_tab_index_or_pane_id, + )?; screen.unblock_input()?; screen.log_and_report_session_state()?; diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 67ddb4c605..1d671d0733 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -1074,7 +1074,11 @@ impl Tab { self.add_tiled_pane(new_pane, pid, client_id) } } - pub fn replace_active_pane_with_editor_pane(&mut self, pid: PaneId, client_id: ClientId) -> Result<()> { + pub fn replace_active_pane_with_editor_pane( + &mut self, + pid: PaneId, + client_id: ClientId, + ) -> Result<()> { // this method creates a new pane from pid and replaces it with the active pane // the active pane is then suppressed (hidden and not rendered) until the current // created pane is closed, in which case it will be replaced back by it @@ -1140,7 +1144,12 @@ impl Tab { } Ok(()) } - pub fn suppress_pane_and_replace_with_pid(&mut self, old_pane_id: PaneId, new_pane_id: PaneId, run_plugin: Option) -> Result<()> { + pub fn suppress_pane_and_replace_with_pid( + &mut self, + old_pane_id: PaneId, + new_pane_id: PaneId, + run_plugin: Option, + ) -> Result<()> { // this method creates a new pane from pid and replaces it with the active pane // the active pane is then suppressed (hidden and not rendered) until the current // created pane is closed, in which case it will be replaced back by it diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index b941817b0b..7409bbc46c 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -2094,7 +2094,8 @@ fn suppress_tiled_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.render(&mut output).unwrap(); @@ -2122,7 +2123,8 @@ fn suppress_floating_pane() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.render(&mut output).unwrap(); @@ -2145,7 +2147,8 @@ fn close_suppressing_tiled_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2176,7 +2179,8 @@ fn close_suppressing_floating_pane() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2202,7 +2206,8 @@ fn suppress_tiled_pane_float_it_and_close() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(1, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2234,7 +2239,8 @@ fn suppress_floating_pane_embed_it_and_close_it() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am the original pane".as_bytes())) @@ -2261,7 +2267,8 @@ fn resize_whole_tab_while_tiled_pane_is_suppressed() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.replace_active_pane_with_editor_pane(new_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(new_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.resize_whole_tab(Size { @@ -2294,7 +2301,8 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() { tab.toggle_floating_panes(Some(client_id), None).unwrap(); tab.new_pane(new_pane_id, None, None, None, Some(client_id)) .unwrap(); - tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id).unwrap(); + tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) + .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) .unwrap(); tab.resize_whole_tab(Size { diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 44cde75eb2..8ba9596782 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -330,7 +330,8 @@ fn write_to_suppressed_pane() { tab.vertical_split(PaneId::Terminal(2), None, 1).unwrap(); // Suppress pane 2 and remove it from active panes - tab.replace_active_pane_with_editor_pane(PaneId::Terminal(2), 1).unwrap(); + tab.replace_active_pane_with_editor_pane(PaneId::Terminal(2), 1) + .unwrap(); tab.tiled_panes.remove_pane(PaneId::Terminal(2)); // Make sure it's suppressed now diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index e79d87214c..54c09c0d7c 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -135,7 +135,15 @@ pub enum Sessions { floating: bool, /// Open the new pane in place of the current pane, temporarily suspending it - #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + #[clap( + short, + long, + value_parser, + default_value("false"), + takes_value(false), + conflicts_with("floating"), + conflicts_with("direction") + )] in_place: bool, /// Name of the new pane @@ -164,7 +172,15 @@ pub enum Sessions { direction: Option, /// Open the new pane in place of the current pane, temporarily suspending it - #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + #[clap( + short, + long, + value_parser, + default_value("false"), + takes_value(false), + conflicts_with("floating"), + conflicts_with("direction") + )] in_place: bool, /// Open the new pane in floating mode @@ -277,7 +293,15 @@ pub enum CliAction { floating: bool, /// Open the new pane in place of the current pane, temporarily suspending it - #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + #[clap( + short, + long, + value_parser, + default_value("false"), + takes_value(false), + conflicts_with("floating"), + conflicts_with("direction") + )] in_place: bool, /// Name of the new pane @@ -324,7 +348,15 @@ pub enum CliAction { floating: bool, /// Open the new pane in place of the current pane, temporarily suspending it - #[clap(short, long, value_parser, default_value("false"), takes_value(false), conflicts_with("floating"), conflicts_with("direction"))] + #[clap( + short, + long, + value_parser, + default_value("false"), + takes_value(false), + conflicts_with("floating"), + conflicts_with("direction") + )] in_place: bool, /// Change the working directory of the editor diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 9e77bb607a..766764c89f 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -208,7 +208,7 @@ pub enum Action { RightClick(Position), MiddleClick(Position), LaunchOrFocusPlugin(RunPlugin, bool, bool, bool), // bools => should float, - // move_to_focused_tab, should_open_in_place + // move_to_focused_tab, should_open_in_place LeftMouseRelease(Position), RightMouseRelease(Position), MiddleMouseRelease(Position), @@ -236,7 +236,7 @@ pub enum Action { /// Open a new tiled (embedded, non-floating) plugin pane NewTiledPluginPane(RunPlugin, Option), // String is an optional name NewFloatingPluginPane(RunPlugin, Option), // String is an optional name - NewInPlacePluginPane(RunPlugin, Option), // String is an optional name + NewInPlacePluginPane(RunPlugin, Option), // String is an optional name StartOrReloadPlugin(RunPlugin), CloseTerminalPane(u32), ClosePluginPane(u32), @@ -320,10 +320,7 @@ impl Action { if floating { Ok(vec![Action::NewFloatingPluginPane(plugin, name)]) } else if in_place { - Ok(vec![Action::NewInPlacePluginPane( - plugin, - name, - )]) + Ok(vec![Action::NewInPlacePluginPane(plugin, name)]) } else { // it is intentional that a new tiled plugin pane cannot include a // direction @@ -354,10 +351,7 @@ impl Action { name, )]) } else if in_place { - Ok(vec![Action::NewInPlacePane( - Some(run_command_action), - name, - )]) + Ok(vec![Action::NewInPlacePane(Some(run_command_action), name)]) } else { Ok(vec![Action::NewTiledPane( direction, diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index 98c8e7ec7e..bba6e821c1 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -239,7 +239,7 @@ impl TryFrom for Action { cwd, direction, should_float, - should_be_in_place + should_be_in_place, )) }, _ => Err("Wrong payload for Action::NewPane"), @@ -818,7 +818,14 @@ impl TryFrom for ProtobufAction { })), }) }, - Action::EditFile(path_to_file, line_number, cwd, direction, should_float, _should_be_in_place) => { + Action::EditFile( + path_to_file, + line_number, + cwd, + direction, + should_float, + _should_be_in_place, + ) => { let file_to_edit = path_to_file.display().to_string(); let cwd = cwd.map(|cwd| cwd.display().to_string()); let direction: Option = direction @@ -963,7 +970,12 @@ impl TryFrom for ProtobufAction { optional_payload: Some(OptionalPayload::MiddleClickPayload(position)), }) }, - Action::LaunchOrFocusPlugin(run_plugin, should_float, move_to_focused_tab, should_open_in_place) => { + Action::LaunchOrFocusPlugin( + run_plugin, + should_float, + move_to_focused_tab, + should_open_in_place, + ) => { let url: Url = Url::from(&run_plugin.location); Ok(ProtobufAction { name: ProtobufActionName::LaunchOrFocusPlugin as i32, diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 1f125989dc..3d34f10fcd 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -523,9 +523,9 @@ impl TryFrom for PluginCommand { Some(CommandName::OpenTerminalInPlace) => match protobuf_plugin_command.payload { Some(Payload::OpenTerminalInPlacePayload(file_to_open_payload)) => { match file_to_open_payload.file_to_open { - Some(file_to_open) => Ok(PluginCommand::OpenTerminalInPlace( - file_to_open.try_into()?, - )), + Some(file_to_open) => { + Ok(PluginCommand::OpenTerminalInPlace(file_to_open.try_into()?)) + }, None => Err("Malformed open terminal in-place payload"), } },