From e392a66833046a2958dfcc0e1147257e59454c41 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Mon, 18 Sep 2023 16:28:06 +0200 Subject: feat(panes): in place run (#2795) * prototype * fix tests * add to all the things except plugins * add in-place to plugin commands * fix launch-or-focus should_float and in place behavior * various cleanups * style(fmt): rustfmt --- zellij-utils/src/cli.rs | 50 ++++++++++++++++++++ zellij-utils/src/data.rs | 3 ++ zellij-utils/src/errors.rs | 3 ++ zellij-utils/src/input/actions.rs | 20 +++++++- zellij-utils/src/ipc.rs | 2 +- zellij-utils/src/kdl/mod.rs | 9 ++++ zellij-utils/src/plugin_api/action.proto | 1 + zellij-utils/src/plugin_api/action.rs | 23 ++++++++- zellij-utils/src/plugin_api/plugin_command.proto | 6 +++ zellij-utils/src/plugin_api/plugin_command.rs | 55 +++++++++++++++++++++- ...test__default_config_with_no_cli_arguments.snap | 1 + ...__layout_env_vars_override_config_env_vars.snap | 1 + ...st__layout_plugins_override_config_plugins.snap | 1 + ...test__layout_themes_override_config_themes.snap | 1 + ...ayout_ui_config_overrides_config_ui_config.snap | 1 + 15 files changed, 171 insertions(+), 6 deletions(-) (limited to 'zellij-utils/src') diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 323834b37..d09625450 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -158,6 +158,18 @@ 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, @@ -183,6 +195,18 @@ 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, @@ -292,6 +316,18 @@ 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, @@ -335,6 +371,18 @@ 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, @@ -409,6 +457,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/data.rs b/zellij-utils/src/data.rs index fc09538cb..3702dace4 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/errors.rs b/zellij-utils/src/errors.rs index 677cbc420..a06980400 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -343,6 +343,8 @@ pub enum ScreenContext { BreakPaneRight, BreakPaneLeft, UpdateSessionInfos, + ReplacePane, + NewInPlacePluginPane, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. @@ -358,6 +360,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 054273a0a..766764c89 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 @@ -204,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), @@ -232,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), @@ -293,6 +298,7 @@ impl Action { plugin, cwd, floating, + in_place, name, close_on_exit, start_suspended, @@ -313,6 +319,8 @@ impl Action { }; if floating { Ok(vec![Action::NewFloatingPluginPane(plugin, name)]) + } else if in_place { + Ok(vec![Action::NewInPlacePluginPane(plugin, name)]) } else { // it is intentional that a new tiled plugin pane cannot include a // direction @@ -342,6 +350,8 @@ 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 +362,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 +374,7 @@ impl Action { file, line_number, floating, + in_place, cwd, } => { let mut file = file; @@ -380,6 +393,7 @@ impl Action { cwd, direction, floating, + in_place, )]) }, CliAction::SwitchMode { input_mode } => { @@ -501,6 +515,7 @@ impl Action { CliAction::LaunchOrFocusPlugin { url, floating, + in_place, move_to_focused_tab, configuration, } => { @@ -516,6 +531,7 @@ impl Action { run_plugin, floating, move_to_focused_tab, + in_place, )]) }, } diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index 0f3415209..a60ecc615 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/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index a7573af55..db72b80d2 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 7e40bde24..1545b9bf4 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 0d70af692..bba6e821c 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; Ok(Action::EditFile( file_to_edit, line_number, cwd, direction, should_float, + should_be_in_place, )) }, _ => Err("Wrong payload for Action::NewPane"), @@ -400,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"), @@ -814,7 +818,14 @@ 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 @@ -959,7 +970,12 @@ 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, @@ -968,6 +984,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()?), }, )), @@ -1149,6 +1166,8 @@ impl TryFrom for ProtobufAction { }), Action::NoOp | Action::Confirm + | Action::NewInPlacePane(..) + | Action::NewInPlacePluginPane(..) | Action::Deny | Action::Copy | Action::SkipConfirm(..) => Err("Unsupported action"), diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index fed8ec54d..17b153810 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 25773ba3a..3d34f10fc 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 2f0a54b9d..971547415 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 7ceedc681..589de2328 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 9c8dda671..ab867fa70 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 d9ead2b96..6de213ed7 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 7f05ec5c4..e44e52f25 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, -- cgit v1.2.3