aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-07-09 16:52:50 +0200
committerGitHub <noreply@github.com>2026-07-09 16:52:50 +0200
commit4bfda976b110b5d3182fca004ee7031f6322253e (patch)
treeff16cdbec15673861ee0907181a25f709565b4fd
parentfix: focus last pane correctness issues (#5344) (diff)
downloadsl0ppij-4bfda976b110b5d3182fca004ee7031f6322253e.tar.gz
sl0ppij-4bfda976b110b5d3182fca004ee7031f6322253e.tar.xz
sl0ppij-4bfda976b110b5d3182fca004ee7031f6322253e.zip
Allow creating panes/tabs from the CLI without changing focus to them (#5346)
* feat: allow opening panes and tabs from the cli without focusing them * rustfmt * fix flake * rustfmt * add pr
-rw-r--r--CHANGELOG.md1
-rw-r--r--default-plugins/status-bar/src/one_line_ui.rs2
-rw-r--r--src/main.rs7
-rw-r--r--zellij-integration-tests/src/runner.rs1
-rw-r--r--zellij-integration-tests/tests/no_focus.rs155
-rw-r--r--zellij-integration-tests/tests/plugins.rs9
-rw-r--r--zellij-integration-tests/tests/single_pane_tab_title.rs1
-rw-r--r--zellij-integration-tests/tests/snapshots/plugins__load_plugins_in_background_on_startup.snap1
-rw-r--r--zellij-server/src/panes/tiled_panes/mod.rs110
-rw-r--r--zellij-server/src/plugins/zellij_exports.rs13
-rw-r--r--zellij-server/src/pty.rs7
-rw-r--r--zellij-server/src/route.rs113
-rw-r--r--zellij-server/src/screen.rs97
-rw-r--r--zellij-server/src/tab/mod.rs187
-rw-r--r--zellij-server/src/unit/screen_tests.rs18
-rw-r--r--zellij-utils/assets/prost_ipc/client_server_contract.rs22
-rw-r--r--zellij-utils/src/cli.rs36
-rw-r--r--zellij-utils/src/client_server_contract/common_types.proto11
-rw-r--r--zellij-utils/src/input/actions.rs56
-rw-r--r--zellij-utils/src/ipc/protobuf_conversion.rs33
-rw-r--r--zellij-utils/src/ipc/tests/roundtrip_tests.rs34
-rw-r--r--zellij-utils/src/kdl/mod.rs6
-rw-r--r--zellij-utils/src/plugin_api/action.rs14
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap1
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap1
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap1
-rw-r--r--zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap1
27 files changed, 797 insertions, 141 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a568431..e21895f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix(windows): route Windows Terminal through the VT input path (https://github.com/zellij-org/zellij/pull/5335)
* fix(windows): backslashes dropped when quoting arguments passed to spawned processes (https://github.com/zellij-org/zellij/pull/5336)
* fix: occasional high resource utilization and sluggishness on machines with tens of thousands of concurent processes (https://github.com/zellij-org/zellij/pull/5324)
+* feat: allow opening panes/tabs from the CLI without changing focus (https://github.com/zellij-org/zellij/pull/5346)
## [0.44.3] - 2026-05-13
* fix(windows): bump windows-sys to 0.59 to align manifest with code, fixing source builds via `cargo install`/`cargo binstall` (https://github.com/zellij-org/zellij/pull/5139)
diff --git a/default-plugins/status-bar/src/one_line_ui.rs b/default-plugins/status-bar/src/one_line_ui.rs
index 6d00a6bf..ae57a223 100644
--- a/default-plugins/status-bar/src/one_line_ui.rs
+++ b/default-plugins/status-bar/src/one_line_ui.rs
@@ -1613,7 +1613,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
(s("Toggle Embed"), s("Embed"), single_action_key(&km, &[A::TogglePaneEmbedOrFloating, TO_NORMAL])),
(s("Split Right"), s("Right"), single_action_key(&km, &[A::NewPane{direction: Some(Direction::Right), pane_name: None, start_suppressed: false}, TO_NORMAL])),
(s("Split Down"), s("Down"), single_action_key(&km, &[A::NewPane{direction: Some(Direction::Down), pane_name: None, start_suppressed: false}, TO_NORMAL])),
- (s("Stack"), s("Stack"), single_action_key(&km, &[A::NewStackedPane{command: None, pane_name: None, near_current_pane: false, tab_id: None}, TO_NORMAL])),
+ (s("Stack"), s("Stack"), single_action_key(&km, &[A::NewStackedPane{command: None, pane_name: None, near_current_pane: false, no_focus: false, tab_id: None}, TO_NORMAL])),
(s("Select pane"), s("Select"), to_basemode_key),
]} else if mi.mode == IM::Tab {
// With the default bindings, "Move focus" for tabs is tricky: It binds all the arrow keys
diff --git a/src/main.rs b/src/main.rs
index a5faf7d3..30c9a00e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -50,6 +50,7 @@ fn main() {
block_until_exit_failure,
block_until_exit,
near_current_pane,
+ no_focus,
borderless,
tab_id,
})) = opts.command
@@ -94,6 +95,7 @@ fn main() {
block_until_exit: false,
unblock_condition,
near_current_pane,
+ no_focus,
borderless,
tab_id,
};
@@ -112,6 +114,7 @@ fn main() {
width,
height,
pinned,
+ no_focus,
borderless,
tab_id,
})) = opts.command
@@ -146,6 +149,7 @@ fn main() {
block_until_exit: false,
unblock_condition,
near_current_pane: false,
+ no_focus,
borderless,
tab_id,
};
@@ -166,6 +170,7 @@ fn main() {
height,
pinned,
near_current_pane,
+ no_focus,
borderless,
tab_id,
})) = opts.command
@@ -191,6 +196,7 @@ fn main() {
height,
pinned,
near_current_pane,
+ no_focus,
borderless,
tab_id,
};
@@ -286,6 +292,7 @@ fn main() {
block_until_exit_success: false,
block_until_exit_failure: false,
block_until_exit: false,
+ no_focus: false,
};
commands::send_action_to_session(new_layout_cli_action, Some(session_name), config);
} else {
diff --git a/zellij-integration-tests/src/runner.rs b/zellij-integration-tests/src/runner.rs
index 76544ecd..cee765a9 100644
--- a/zellij-integration-tests/src/runner.rs
+++ b/zellij-integration-tests/src/runner.rs
@@ -145,6 +145,7 @@ fn new_pane_cli_action(
block_until_exit,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
}
diff --git a/zellij-integration-tests/tests/no_focus.rs b/zellij-integration-tests/tests/no_focus.rs
new file mode 100644
index 00000000..5722a019
--- /dev/null
+++ b/zellij-integration-tests/tests/no_focus.rs
@@ -0,0 +1,155 @@
+#![cfg(unix)]
+
+use std::time::Instant;
+use zellij_integration_tests::{
+ claim_first_terminal_and_wait_for_prompt, default_timeout, start_zellij, FakePtyHandle, PROMPT,
+};
+use zellij_utils::cli::CliAction;
+
+fn no_focus_new_pane_action(command: &[&str]) -> CliAction {
+ CliAction::NewPane {
+ direction: None,
+ command: command.iter().map(|part| part.to_string()).collect(),
+ plugin: None,
+ cwd: None,
+ floating: false,
+ in_place: false,
+ close_replaced_pane: false,
+ pane_id: None,
+ name: None,
+ close_on_exit: false,
+ start_suspended: false,
+ configuration: None,
+ skip_plugin_cache: false,
+ x: None,
+ y: None,
+ width: None,
+ height: None,
+ pinned: None,
+ stacked: false,
+ blocking: false,
+ block_until_exit_success: false,
+ block_until_exit_failure: false,
+ block_until_exit: false,
+ unblock_condition: None,
+ near_current_pane: false,
+ no_focus: true,
+ borderless: None,
+ tab_id: None,
+ }
+}
+
+fn no_focus_new_tab_action() -> CliAction {
+ CliAction::NewTab {
+ name: None,
+ layout: None,
+ layout_string: None,
+ layout_dir: None,
+ cwd: None,
+ initial_command: vec![],
+ initial_plugin: None,
+ close_on_exit: false,
+ start_suspended: false,
+ block_until_exit_success: false,
+ block_until_exit_failure: false,
+ block_until_exit: false,
+ no_focus: true,
+ }
+}
+
+fn wait_until_stdin_contains(handle: &FakePtyHandle, needle: &[u8]) {
+ let deadline = Instant::now() + default_timeout();
+ loop {
+ let bytes = handle.stdin_bytes();
+ if bytes.windows(needle.len()).any(|window| window == needle) {
+ return;
+ }
+ if Instant::now() >= deadline {
+ panic!(
+ "timed out waiting for pane to receive {:?}, received {:?}",
+ String::from_utf8_lossy(needle),
+ String::from_utf8_lossy(&bytes),
+ );
+ }
+ std::thread::sleep(std::time::Duration::from_millis(10));
+ }
+}
+
+fn stdin_contains(handle: &FakePtyHandle, needle: &[u8]) -> bool {
+ handle
+ .stdin_bytes()
+ .windows(needle.len())
+ .any(|window| window == needle)
+}
+
+#[test]
+fn new_pane_no_focus_leaves_input_on_the_original_pane() {
+ let mut zellij = start_zellij();
+ let original_pane = claim_first_terminal_and_wait_for_prompt(&zellij);
+
+ zellij.run_cli_action(no_focus_new_pane_action(&["unfocused-command"]));
+ let unfocused_pane = zellij.expect_pty_spawn();
+ unfocused_pane.output(PROMPT);
+ zellij.wait_until(
+ "second pane appeared alongside the first",
+ |grid_snapshot| grid_snapshot.text.matches("$").count() >= 2,
+ );
+
+ let probe = b"nofocusprobe";
+ zellij.send_stdin(probe);
+ wait_until_stdin_contains(&original_pane, probe);
+ assert!(
+ !stdin_contains(&unfocused_pane, probe),
+ "input leaked into the pane that was opened with --no-focus"
+ );
+ zellij.quit();
+}
+
+#[test]
+fn new_pane_without_no_focus_moves_input_to_the_new_pane() {
+ let mut zellij = start_zellij();
+ let original_pane = claim_first_terminal_and_wait_for_prompt(&zellij);
+
+ let mut focusing_action = no_focus_new_pane_action(&["focused-command"]);
+ if let CliAction::NewPane { no_focus, .. } = &mut focusing_action {
+ *no_focus = false;
+ }
+ zellij.run_cli_action(focusing_action);
+ let focused_pane = zellij.expect_pty_spawn();
+ focused_pane.output(PROMPT);
+ zellij.wait_until(
+ "second pane appeared alongside the first",
+ |grid_snapshot| grid_snapshot.text.matches("$").count() >= 2,
+ );
+
+ let probe = b"focusprobe";
+ zellij.send_stdin(probe);
+ wait_until_stdin_contains(&focused_pane, probe);
+ assert!(
+ !stdin_contains(&original_pane, probe),
+ "input reached the original pane even though the new pane should have taken focus"
+ );
+ zellij.quit();
+}
+
+#[test]
+fn new_tab_no_focus_leaves_focus_on_the_original_tab() {
+ let mut zellij = start_zellij();
+ let original_pane = claim_first_terminal_and_wait_for_prompt(&zellij);
+
+ zellij.run_cli_action(no_focus_new_tab_action());
+ let new_tab_pane = zellij.expect_pty_spawn();
+ new_tab_pane.output(PROMPT);
+ zellij.wait_until("a second tab exists in the tab bar", |grid_snapshot| {
+ grid_snapshot.text.contains("Tab #2")
+ });
+
+ let probe = b"nofocusprobe";
+ zellij.send_stdin(probe);
+ wait_until_stdin_contains(&original_pane, probe);
+ assert!(
+ !stdin_contains(&new_tab_pane, probe),
+ "input leaked into the tab that was created with --no-focus"
+ );
+ zellij.quit();
+}
diff --git a/zellij-integration-tests/tests/plugins.rs b/zellij-integration-tests/tests/plugins.rs
index 5b14c633..21990a94 100644
--- a/zellij-integration-tests/tests/plugins.rs
+++ b/zellij-integration-tests/tests/plugins.rs
@@ -22,9 +22,12 @@ fn load_plugins_in_background_on_startup() {
let terminal = zellij.expect_pty_spawn();
terminal.output(b"$ ");
- let grid_snapshot = zellij
- .wait_until("background plugin requests permissions", |grid_snapshot| {
- grid_snapshot.contains("Allow? (y/n)") && grid_snapshot.tab_bar_appears()
+ let grid_snapshot =
+ zellij.wait_until("background plugin requests permissions", |grid_snapshot| {
+ grid_snapshot.contains("Allow? (y/n)")
+ && grid_snapshot.tab_bar_appears()
+ && grid_snapshot.status_bar_appears()
+ && grid_snapshot.contains("STAGGERED")
});
assert_snapshot!(normalized(&grid_snapshot));
zellij.send_stdin(b"y");
diff --git a/zellij-integration-tests/tests/single_pane_tab_title.rs b/zellij-integration-tests/tests/single_pane_tab_title.rs
index 1fd1a553..cc70a163 100644
--- a/zellij-integration-tests/tests/single_pane_tab_title.rs
+++ b/zellij-integration-tests/tests/single_pane_tab_title.rs
@@ -37,6 +37,7 @@ fn replace_pane_in_place_with_held_command(
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
});
diff --git a/zellij-integration-tests/tests/snapshots/plugins__load_plugins_in_background_on_startup.snap b/zellij-integration-tests/tests/snapshots/plugins__load_plugins_in_background_on_startup.snap
index 034a2c02..a77d1dd9 100644
--- a/zellij-integration-tests/tests/snapshots/plugins__load_plugins_in_background_on_startup.snap
+++ b/zellij-integration-tests/tests/snapshots/plugins__load_plugins_in_background_on_startup.snap
@@ -16,3 +16,4 @@ $
│ │
│ │
└──────────────────────────────────────────────────────────┘
+ Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  ...
diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs
index d9448641..ba0ba51c 100644
--- a/zellij-server/src/panes/tiled_panes/mod.rs
+++ b/zellij-server/src/panes/tiled_panes/mod.rs
@@ -649,64 +649,80 @@ impl TiledPanes {
self.reset_boundaries();
}
pub fn can_split_pane_horizontally(&mut self, client_id: ClientId) -> bool {
- if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
- if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
- let mut full_pane_size = active_pane.position_and_size();
-
- if full_pane_size.is_stacked() {
- let Some(position_and_size_of_stack) =
- StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
- .position_and_size_of_stack(&active_pane_id)
- else {
- log::error!("Failed to find position and size of stack");
- return false;
- };
- full_pane_size = position_and_size_of_stack;
- }
+ match self.active_panes.get(&client_id).copied() {
+ Some(active_pane_id) => self.can_split_pane_id_horizontally(active_pane_id),
+ None => false,
+ }
+ }
+ pub fn can_split_pane_id_horizontally(&mut self, active_pane_id: PaneId) -> bool {
+ if let Some(active_pane) = self.panes.get_mut(&active_pane_id) {
+ let mut full_pane_size = active_pane.position_and_size();
- if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 {
+ if full_pane_size.is_stacked() {
+ let Some(position_and_size_of_stack) =
+ StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .position_and_size_of_stack(&active_pane_id)
+ else {
+ log::error!("Failed to find position and size of stack");
return false;
- } else {
- return split(SplitDirection::Horizontal, &full_pane_size).is_some();
- }
+ };
+ full_pane_size = position_and_size_of_stack;
+ }
+
+ if full_pane_size.rows.as_usize() < MIN_TERMINAL_HEIGHT * 2 {
+ return false;
+ } else {
+ return split(SplitDirection::Horizontal, &full_pane_size).is_some();
}
}
false
}
pub fn can_split_pane_vertically(&mut self, client_id: ClientId) -> bool {
- if let Some(active_pane_id) = &self.active_panes.get(&client_id) {
- if let Some(active_pane) = self.panes.get_mut(active_pane_id) {
- let mut full_pane_size = active_pane.position_and_size();
-
- if full_pane_size.is_stacked() {
- let Some(position_and_size_of_stack) =
- StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
- .position_and_size_of_stack(&active_pane_id)
- else {
- log::error!("Failed to find position and size of stack");
- return false;
- };
- full_pane_size = position_and_size_of_stack;
- }
+ match self.active_panes.get(&client_id).copied() {
+ Some(active_pane_id) => self.can_split_pane_id_vertically(active_pane_id),
+ None => false,
+ }
+ }
+ pub fn can_split_pane_id_vertically(&mut self, active_pane_id: PaneId) -> bool {
+ if let Some(active_pane) = self.panes.get_mut(&active_pane_id) {
+ let mut full_pane_size = active_pane.position_and_size();
- if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 {
+ if full_pane_size.is_stacked() {
+ let Some(position_and_size_of_stack) =
+ StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
+ .position_and_size_of_stack(&active_pane_id)
+ else {
+ log::error!("Failed to find position and size of stack");
return false;
- }
- return split(SplitDirection::Vertical, &full_pane_size).is_some();
+ };
+ full_pane_size = position_and_size_of_stack;
}
+
+ if full_pane_size.cols.as_usize() < MIN_TERMINAL_WIDTH * 2 {
+ return false;
+ }
+ return split(SplitDirection::Vertical, &full_pane_size).is_some();
}
false
}
pub fn split_pane_horizontally(
&mut self,
pid: PaneId,
- mut new_pane: Box<dyn Pane>,
+ new_pane: Box<dyn Pane>,
client_id: ClientId,
) {
- let active_pane_id = &self.active_panes.get(&client_id).unwrap();
+ let active_pane_id = *self.active_panes.get(&client_id).unwrap();
+ self.split_pane_id_horizontally(pid, new_pane, active_pane_id);
+ }
+ pub fn split_pane_id_horizontally(
+ &mut self,
+ pid: PaneId,
+ mut new_pane: Box<dyn Pane>,
+ active_pane_id: PaneId,
+ ) {
let mut full_pane_size = self
.panes
- .get(active_pane_id)
+ .get(&active_pane_id)
.map(|p| p.position_and_size())
.unwrap();
if full_pane_size.is_stacked() {
@@ -721,7 +737,7 @@ impl TiledPanes {
},
}
}
- let active_pane = self.panes.get_mut(active_pane_id).unwrap();
+ let active_pane = self.panes.get_mut(&active_pane_id).unwrap();
if let Some((top_winsize, bottom_winsize)) =
split(SplitDirection::Horizontal, &full_pane_size)
{
@@ -745,13 +761,21 @@ impl TiledPanes {
pub fn split_pane_vertically(
&mut self,
pid: PaneId,
- mut new_pane: Box<dyn Pane>,
+ new_pane: Box<dyn Pane>,
client_id: ClientId,
) {
- let active_pane_id = &self.active_panes.get(&client_id).unwrap();
+ let active_pane_id = *self.active_panes.get(&client_id).unwrap();
+ self.split_pane_id_vertically(pid, new_pane, active_pane_id);
+ }
+ pub fn split_pane_id_vertically(
+ &mut self,
+ pid: PaneId,
+ mut new_pane: Box<dyn Pane>,
+ active_pane_id: PaneId,
+ ) {
let mut full_pane_size = self
.panes
- .get(active_pane_id)
+ .get(&active_pane_id)
.map(|p| p.position_and_size())
.unwrap();
if full_pane_size.is_stacked() {
@@ -766,7 +790,7 @@ impl TiledPanes {
},
}
}
- let active_pane = self.panes.get_mut(active_pane_id).unwrap();
+ let active_pane = self.panes.get_mut(&active_pane_id).unwrap();
if let Some((left_winsize, right_winsize)) =
split(SplitDirection::Vertical, &full_pane_size)
{
diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs
index 4dd559ed..d850145c 100644
--- a/zellij-server/src/plugins/zellij_exports.rs
+++ b/zellij-server/src/plugins/zellij_exports.rs
@@ -1197,6 +1197,7 @@ fn open_plugin_pane_floating(
skip_cache: false,
cwd: Some(env.plugin_cwd.clone()),
coordinates: floating_pane_coordinates,
+ no_focus: false,
tab_id: None,
};
let error_msg = || format!("Failed to open floating plugin pane");
@@ -1437,6 +1438,7 @@ fn open_file(env: &PluginEnv, file_to_open: FileToOpen, context: BTreeMap<String
start_suppressed,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
let result = apply_action!(action, error_msg, env);
@@ -1532,6 +1534,7 @@ fn open_file_floating(
start_suppressed,
coordinates: floating_pane_coordinates,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
let result = apply_action!(action, error_msg, env);
@@ -1573,6 +1576,7 @@ fn open_file_in_place(
start_suppressed,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
let result = apply_action!(action, error_msg, env);
@@ -1733,6 +1737,7 @@ fn open_terminal(env: &PluginEnv, cwd: PathBuf) {
command: run_command_action,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -1810,6 +1815,7 @@ fn open_terminal_floating(
pane_name: None,
coordinates: floating_pane_coordinates,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
let result = apply_action!(action, error_msg, env);
@@ -1884,6 +1890,7 @@ fn open_terminal_in_place(env: &PluginEnv, cwd: PathBuf) {
command: run_command_action,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane: false,
tab_id: None,
@@ -2170,6 +2177,7 @@ fn open_command_pane(
command: Some(run_command_action),
pane_name: name,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -2279,6 +2287,7 @@ fn open_command_pane_floating(
pane_name: name,
coordinates: floating_pane_coordinates,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
let result = apply_action!(action, error_msg, env);
@@ -2388,6 +2397,7 @@ fn open_command_pane_in_place(
command: Some(run_command_action),
pane_name: name,
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane: false,
tab_id: None,
@@ -2872,6 +2882,7 @@ fn new_tiled_pane_in_tab(env: &PluginEnv, tab_position: usize) {
command: run_command_action,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(tab_position),
};
@@ -4730,9 +4741,9 @@ fn try_edit_layout(
start_suppressed: false,
coordinates: None,
near_current_pane: true,
+ no_focus: false,
tab_id: None,
};
-
// Route the action - this is fallible
route_action(
action,
diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs
index 13b06b57..68a2371b 100644
--- a/zellij-server/src/pty.rs
+++ b/zellij-server/src/pty.rs
@@ -39,7 +39,9 @@ pub type TabIndex = u32;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClientTabIndexOrPaneId {
ClientId(ClientId),
+ ClientIdNoFocus(ClientId),
TabIndex(usize),
+ TabIndexNoFocus(usize),
PaneId(PaneId),
}
@@ -1025,13 +1027,14 @@ impl Pty {
// returns the terminal id
let terminal_action = match client_or_tab_index {
- ClientTabIndexOrPaneId::ClientId(client_id) => {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ | ClientTabIndexOrPaneId::ClientIdNoFocus(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
},
- ClientTabIndexOrPaneId::TabIndex(_) => {
+ ClientTabIndexOrPaneId::TabIndex(_) | ClientTabIndexOrPaneId::TabIndexNoFocus(_) => {
terminal_action.unwrap_or_else(|| self.get_default_terminal(None, None))
},
ClientTabIndexOrPaneId::PaneId(pane_id) => {
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index 529a93b9..08200abb 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -193,6 +193,28 @@ impl Drop for NotificationEnd {
// otherwise blocking-CLI actions
// (`wait_forever=true`) park this function while still holding the guard,
// deadlocking concurrent `session_data.write()`s.
+fn new_pane_routing(
+ no_focus: bool,
+ near_current_pane: bool,
+ tab_id: Option<usize>,
+ pane_id: Option<PaneId>,
+ client_id: ClientId,
+) -> ClientTabIndexOrPaneId {
+ if let Some(tab_id) = tab_id {
+ if no_focus {
+ ClientTabIndexOrPaneId::TabIndexNoFocus(tab_id)
+ } else {
+ ClientTabIndexOrPaneId::TabIndex(tab_id)
+ }
+ } else if (no_focus || near_current_pane) && pane_id.is_some() {
+ ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
+ } else if no_focus {
+ ClientTabIndexOrPaneId::ClientIdNoFocus(client_id)
+ } else {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ }
+}
+
pub(crate) fn route_action(
action: Action,
client_id: ClientId,
@@ -635,6 +657,7 @@ pub(crate) fn route_action(
command,
unblock_condition,
near_current_pane,
+ no_focus,
tab_id,
} => {
let command = command
@@ -667,13 +690,8 @@ pub(crate) fn route_action(
_ => pane_id,
};
- let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else if near_current_pane && pane_id.is_some() {
- ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, tab_id, pane_id, client_id);
senders
.send_to_pty(PtyInstruction::SpawnTerminal(
command,
@@ -696,18 +714,14 @@ pub(crate) fn route_action(
start_suppressed,
coordinates: floating_pane_coordinates,
near_current_pane,
+ no_focus,
tab_id,
} => {
let title = format!("Editing: {}", open_file_payload.path.display());
let open_file = TerminalAction::OpenFile(open_file_payload);
let pty_instr = if should_open_in_place {
- let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else if near_current_pane && pane_id.is_some() {
- ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, tab_id, pane_id, client_id);
PtyInstruction::SpawnInPlaceTerminal(
Some(open_file),
Some(title),
@@ -716,11 +730,8 @@ pub(crate) fn route_action(
Some(NotificationEnd::new(completion_tx)),
)
} else {
- let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, tab_id, pane_id, client_id);
PtyInstruction::SpawnTerminal(
Some(open_file),
Some(title),
@@ -760,18 +771,14 @@ pub(crate) fn route_action(
pane_name: name,
coordinates: floating_pane_coordinates,
near_current_pane,
+ no_focus,
tab_id,
} => {
let run_cmd = run_command
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
.or_else(|| default_shell.clone());
- let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else if near_current_pane && pane_id.is_some() {
- ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, tab_id, pane_id, client_id);
senders
.send_to_pty(PtyInstruction::SpawnTerminal(
run_cmd,
@@ -788,6 +795,7 @@ pub(crate) fn route_action(
command: run_command,
pane_name: name,
near_current_pane,
+ no_focus,
pane_id_to_replace,
close_replaced_pane,
tab_id,
@@ -799,11 +807,17 @@ pub(crate) fn route_action(
.and_then(|pane_id_to_replace| pane_id_to_replace.try_into().ok());
let pane_id = explicit_pane_id_to_replace.or(pane_id);
let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else if let Some(pane_id) =
- pane_id.filter(|_| explicit_pane_id_to_replace.is_some() || near_current_pane)
+ if no_focus {
+ ClientTabIndexOrPaneId::TabIndexNoFocus(tab_id)
+ } else {
+ ClientTabIndexOrPaneId::TabIndex(tab_id)
+ }
+ } else if let Some(pane_id) = pane_id
+ .filter(|_| explicit_pane_id_to_replace.is_some() || near_current_pane || no_focus)
{
ClientTabIndexOrPaneId::PaneId(pane_id)
+ } else if no_focus {
+ ClientTabIndexOrPaneId::ClientIdNoFocus(client_id)
} else {
ClientTabIndexOrPaneId::ClientId(client_id)
};
@@ -821,6 +835,7 @@ pub(crate) fn route_action(
command: run_command,
pane_name: name,
near_current_pane,
+ no_focus,
tab_id,
} => {
let run_cmd = run_command
@@ -833,9 +848,13 @@ pub(crate) fn route_action(
pane_id_to_stack_under: None,
borderless: None,
},
- ClientTabIndexOrPaneId::TabIndex(tab_id),
+ if no_focus {
+ ClientTabIndexOrPaneId::TabIndexNoFocus(tab_id)
+ } else {
+ ClientTabIndexOrPaneId::TabIndex(tab_id)
+ },
)
- } else if near_current_pane && pane_id.is_some() {
+ } else if (no_focus || near_current_pane) && pane_id.is_some() {
let pane_id = pane_id.unwrap();
(
NewPanePlacement::Stacked {
@@ -850,7 +869,11 @@ pub(crate) fn route_action(
pane_id_to_stack_under: None,
borderless: None,
},
- ClientTabIndexOrPaneId::ClientId(client_id),
+ if no_focus {
+ ClientTabIndexOrPaneId::ClientIdNoFocus(client_id)
+ } else {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ },
)
};
senders
@@ -870,19 +893,15 @@ pub(crate) fn route_action(
command: run_command,
pane_name: name,
near_current_pane,
+ no_focus,
borderless,
tab_id,
} => {
let run_cmd = run_command
.map(|cmd| TerminalAction::RunCommand(cmd.into()))
.or_else(|| default_shell.clone());
- let client_tab_index_or_paneid = if let Some(tab_id) = tab_id {
- ClientTabIndexOrPaneId::TabIndex(tab_id)
- } else if near_current_pane && pane_id.is_some() {
- ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, tab_id, pane_id, client_id);
senders
.send_to_pty(PtyInstruction::SpawnTerminal(
run_cmd,
@@ -935,13 +954,11 @@ pub(crate) fn route_action(
Action::Run {
command,
near_current_pane,
+ no_focus,
} => {
let run_cmd = Some(TerminalAction::RunCommand(command.clone().into()));
- let client_tab_index_or_paneid = if near_current_pane && pane_id.is_some() {
- ClientTabIndexOrPaneId::PaneId(pane_id.unwrap())
- } else {
- ClientTabIndexOrPaneId::ClientId(client_id)
- };
+ let client_tab_index_or_paneid =
+ new_pane_routing(no_focus, near_current_pane, None, pane_id, client_id);
senders
.send_to_pty(PtyInstruction::SpawnTerminal(
run_cmd,
@@ -1321,6 +1338,7 @@ pub(crate) fn route_action(
pane_name: name,
skip_cache,
cwd,
+ no_focus,
tab_id,
} => {
senders
@@ -1332,6 +1350,7 @@ pub(crate) fn route_action(
client_id,
Some(NotificationEnd::new(completion_tx)),
tab_id,
+ no_focus,
))
.with_context(err_context)?;
},
@@ -1341,6 +1360,7 @@ pub(crate) fn route_action(
skip_cache,
cwd,
coordinates: floating_pane_coordinates,
+ no_focus,
tab_id,
} => {
senders
@@ -1353,6 +1373,7 @@ pub(crate) fn route_action(
client_id,
Some(NotificationEnd::new(completion_tx)),
tab_id,
+ no_focus,
))
.with_context(err_context)?;
},
@@ -1361,6 +1382,7 @@ pub(crate) fn route_action(
pane_name: name,
skip_cache,
close_replaced_pane,
+ no_focus,
tab_id,
} => {
if let Some(pane_id) = pane_id {
@@ -1374,6 +1396,7 @@ pub(crate) fn route_action(
client_id,
Some(NotificationEnd::new(completion_tx)),
tab_id,
+ no_focus,
))
.with_context(err_context)?;
} else {
@@ -1420,6 +1443,7 @@ pub(crate) fn route_action(
close_replaced_pane,
skip_cache,
cwd,
+ no_focus,
tab_id,
} => {
senders
@@ -1434,6 +1458,7 @@ pub(crate) fn route_action(
client_id,
Some(NotificationEnd::new(completion_tx)),
tab_id,
+ no_focus,
))
.with_context(err_context)?;
},
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 34c9ced5..773e390b 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -609,6 +609,7 @@ pub enum ScreenInstruction {
ClientId,
Option<NotificationEnd>,
Option<usize>, // tab_id
+ bool,
), // Option<String> is
// optional pane title, bool is skip cache, Option<PathBuf> is an optional cwd
NewFloatingPluginPane(
@@ -620,6 +621,7 @@ pub enum ScreenInstruction {
ClientId,
Option<NotificationEnd>,
Option<usize>, // tab_id
+ bool,
), // Option<String> is an
// optional pane title, bool
// is skip cache, Option<PathBuf> is an optional cwd
@@ -632,6 +634,7 @@ pub enum ScreenInstruction {
ClientId,
Option<NotificationEnd>,
Option<usize>, // tab_id
+ bool,
), // Option<String> is an
// optional pane title, first bool is skip cache, second bool is close_replaced_pane
StartOrReloadPluginPane(RunPluginOrAlias, Option<String>, Option<NotificationEnd>),
@@ -678,6 +681,7 @@ pub enum ScreenInstruction {
ClientId,
Option<NotificationEnd>,
Option<usize>, // tab_id
+ bool,
), // bools are: should_float, should_open_in_place, close_replaced_pane, Option<PaneId> is the pane id to replace, Option<PathBuf> is an optional cwd, bool after is skip_cache
SuppressPane(PaneId, ClientId),
UnsuppressPane(PaneId, bool), // bool -> should float if hidden
@@ -4917,7 +4921,8 @@ impl Screen {
}
};
match client_id_tab_index_or_pane_id {
- ClientTabIndexOrPaneId::ClientId(client_id) => {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ | ClientTabIndexOrPaneId::ClientIdNoFocus(client_id) => {
active_tab!(self, client_id, |tab: &mut Tab| {
match tab.get_active_pane_id(client_id) {
Some(pane_id) => {
@@ -4951,7 +4956,8 @@ impl Screen {
},
};
},
- ClientTabIndexOrPaneId::TabIndex(_tab_index) => {
+ ClientTabIndexOrPaneId::TabIndex(_tab_index)
+ | ClientTabIndexOrPaneId::TabIndexNoFocus(_tab_index) => {
log::error!("Cannot replace pane with tab index");
},
}
@@ -6384,13 +6390,16 @@ pub(crate) fn screen_thread_main(
let blocking_notification = if set_blocking { completion_tx } else { None };
match client_or_tab_index {
- ClientTabIndexOrPaneId::ClientId(client_id) => {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ | ClientTabIndexOrPaneId::ClientIdNoFocus(client_id) => {
+ let should_focus_pane =
+ matches!(client_or_tab_index, ClientTabIndexOrPaneId::ClientId(_));
active_tab_and_connected_client_id_with_first_tab_fallback!(screen, client_id, |tab: &mut Tab, client_id: Option<ClientId>| {
tab.new_pane(pid,
initial_pane_title,
invoked_with,
start_suppressed,
- true,
+ should_focus_pane,
new_pane_placement,
client_id,
blocking_notification
@@ -6410,7 +6419,10 @@ pub(crate) fn screen_thread_main(
)
}
},
- ClientTabIndexOrPaneId::TabIndex(tab_index) => {
+ ClientTabIndexOrPaneId::TabIndex(tab_index)
+ | ClientTabIndexOrPaneId::TabIndexNoFocus(tab_index) => {
+ let should_focus_pane =
+ matches!(client_or_tab_index, ClientTabIndexOrPaneId::TabIndex(_));
// Some placements (directional split, stacked without a
// target pane) need a client_id to know which pane to
// split relative to. Only resolve one when required.
@@ -6440,7 +6452,7 @@ pub(crate) fn screen_thread_main(
initial_pane_title,
invoked_with,
start_suppressed,
- true,
+ should_focus_pane,
new_pane_placement,
client_id,
blocking_notification,
@@ -6459,16 +6471,46 @@ pub(crate) fn screen_thread_main(
let should_focus_pane = false;
for tab in all_tabs.values_mut() {
if tab.has_pane_with_pid(&pane_id) {
- tab.new_pane(
- pid,
- initial_pane_title,
- invoked_with,
- start_suppressed,
- should_focus_pane,
- new_pane_placement,
- None,
- blocking_notification, // TODO: is this correct?
- )?;
+ match new_pane_placement {
+ NewPanePlacement::Tiled {
+ direction: Some(direction),
+ borderless,
+ } => {
+ if direction == Direction::Left
+ || direction == Direction::Right
+ {
+ tab.vertical_split_of_pane_id(
+ pid,
+ initial_pane_title,
+ invoked_with,
+ pane_id,
+ blocking_notification,
+ borderless,
+ )?;
+ } else {
+ tab.horizontal_split_of_pane_id(
+ pid,
+ initial_pane_title,
+ invoked_with,
+ pane_id,
+ blocking_notification,
+ borderless,
+ )?;
+ }
+ },
+ _ => {
+ tab.new_pane(
+ pid,
+ initial_pane_title,
+ invoked_with,
+ start_suppressed,
+ should_focus_pane,
+ new_pane_placement,
+ None,
+ blocking_notification,
+ )?;
+ },
+ }
if let Some(hold_for_command) = hold_for_command {
let is_first_run = true;
tab.hold_pane(pid, None, is_first_run, hold_for_command);
@@ -6496,12 +6538,14 @@ pub(crate) fn screen_thread_main(
},
ScreenInstruction::OpenInPlaceEditor(pid, client_tab_index_or_pane_id) => {
match client_tab_index_or_pane_id {
- ClientTabIndexOrPaneId::ClientId(client_id) => {
+ ClientTabIndexOrPaneId::ClientId(client_id)
+ | ClientTabIndexOrPaneId::ClientIdNoFocus(client_id) => {
active_tab!(screen, client_id, |tab: &mut Tab| tab
.replace_active_pane_with_editor_pane(pid, client_id), ?);
screen.log_and_report_session_state()?;
},
- ClientTabIndexOrPaneId::TabIndex(_tab_index) => {
+ ClientTabIndexOrPaneId::TabIndex(_tab_index)
+ | ClientTabIndexOrPaneId::TabIndexNoFocus(_tab_index) => {
log::error!("Cannot OpenInPlaceEditor with a TabIndex");
},
ClientTabIndexOrPaneId::PaneId(pane_id_to_replace) => {
@@ -8478,12 +8522,14 @@ pub(crate) fn screen_thread_main(
client_id,
completion_tx,
explicit_tab_id,
+ no_focus,
) => {
let tab_index = explicit_tab_id
.unwrap_or_else(|| *screen.active_tab_ids.values().next().unwrap_or(&1));
let size = Size::default();
let should_float = Some(false);
let should_be_opened_in_place = false;
+ let should_focus_plugin = if no_focus { Some(false) } else { None };
screen
.bus
.senders
@@ -8499,7 +8545,7 @@ pub(crate) fn screen_thread_main(
size,
skip_cache,
cwd,
- None,
+ should_focus_plugin,
None,
completion_tx,
))?;
@@ -8513,6 +8559,7 @@ pub(crate) fn screen_thread_main(
client_id,
completion_tx,
explicit_tab_id,
+ no_focus,
) => {
let resolved_tab_index =
explicit_tab_id.or_else(|| screen.active_tab_ids.values().next().copied());
@@ -8521,6 +8568,7 @@ pub(crate) fn screen_thread_main(
let size = Size::default();
let should_float = Some(true);
let should_be_opened_in_place = false;
+ let should_focus_plugin = if no_focus { Some(false) } else { None };
screen
.bus
.senders
@@ -8536,7 +8584,7 @@ pub(crate) fn screen_thread_main(
size,
skip_cache,
cwd,
- None,
+ should_focus_plugin,
floating_pane_coordinates,
completion_tx,
))?;
@@ -8557,6 +8605,7 @@ pub(crate) fn screen_thread_main(
client_id,
completion_tx,
explicit_tab_id,
+ no_focus,
) => {
let resolved_tab_index =
explicit_tab_id.or_else(|| screen.active_tab_ids.values().next().copied());
@@ -8565,6 +8614,7 @@ pub(crate) fn screen_thread_main(
let size = Size::default();
let should_float = None;
let should_be_in_place = true;
+ let should_focus_plugin = if no_focus { Some(false) } else { None };
screen
.bus
.senders
@@ -8580,7 +8630,7 @@ pub(crate) fn screen_thread_main(
size,
skip_cache,
None,
- None,
+ should_focus_plugin,
None,
completion_tx,
))?;
@@ -8891,6 +8941,7 @@ pub(crate) fn screen_thread_main(
client_id,
completion_tx,
explicit_tab_id,
+ no_focus,
) => match pane_id_to_replace {
Some(pane_id_to_replace) => {
let resolved_tab_index =
@@ -8913,7 +8964,7 @@ pub(crate) fn screen_thread_main(
size,
skip_cache,
cwd,
- None,
+ if no_focus { Some(false) } else { None },
None,
completion_tx,
))?;
@@ -8957,7 +9008,7 @@ pub(crate) fn screen_thread_main(
Size::default(),
skip_cache,
cwd,
- None,
+ if no_focus { Some(false) } else { None },
None,
completion_tx,
))?;
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index d3bc154f..3189e69a 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -68,8 +68,8 @@ use zellij_utils::{
input::{
command::TerminalAction,
layout::{
- FloatingPaneLayout, Run, RunPluginOrAlias, SwapFloatingLayout, SwapTiledLayout,
- TiledPaneLayout,
+ FloatingPaneLayout, Run, RunPluginOrAlias, SplitDirection, SwapFloatingLayout,
+ SwapTiledLayout, TiledPaneLayout,
},
options::PaneFrameStyle,
parse_keys,
@@ -2393,20 +2393,45 @@ impl Tab {
direction: Some(direction),
borderless,
} => {
- if let Some(client_id) = client_id {
- if direction == Direction::Left || direction == Direction::Right {
- self.vertical_split(
+ let is_vertical = direction == Direction::Left || direction == Direction::Right;
+ if should_focus_pane {
+ if let Some(client_id) = client_id {
+ if is_vertical {
+ self.vertical_split(
+ pid,
+ initial_pane_title,
+ client_id,
+ blocking_notification,
+ borderless,
+ )?;
+ } else {
+ self.horizontal_split(
+ pid,
+ initial_pane_title,
+ client_id,
+ blocking_notification,
+ borderless,
+ )?;
+ }
+ }
+ } else if let Some(target_pane_id) =
+ client_id.and_then(|client_id| self.tiled_panes.get_active_pane_id(client_id))
+ {
+ if is_vertical {
+ self.vertical_split_of_pane_id(
pid,
initial_pane_title,
- client_id,
+ invoked_with,
+ target_pane_id,
blocking_notification,
borderless,
)?;
} else {
- self.horizontal_split(
+ self.horizontal_split_of_pane_id(
pid,
initial_pane_title,
- client_id,
+ invoked_with,
+ target_pane_id,
blocking_notification,
borderless,
)?;
@@ -2559,7 +2584,7 @@ impl Tab {
if self.floating_panes.panes_are_visible() {
self.add_floating_pane(new_pane, pid, None, false, client_id)
} else {
- self.add_tiled_pane(new_pane, pid, false, client_id)
+ self.add_tiled_pane(new_pane, pid, false, None)
}
}
}
@@ -2663,7 +2688,8 @@ impl Tab {
.insert(pid, (is_scrollback_editor, new_pane));
Ok(())
} else {
- self.add_tiled_pane(new_pane, pid, false, client_id)
+ let focus_client_id = if should_focus_pane { client_id } else { None };
+ self.add_tiled_pane(new_pane, pid, false, focus_client_id)
}
}
pub fn new_floating_pane(
@@ -2918,11 +2944,14 @@ impl Tab {
Ok(())
} else {
if let Some(pane_id_to_stack_under) = pane_id_to_stack_under {
- // TODO: also focus pane if should_focus_pane? in cases where we did this from the CLI in an unfocused
- // pane...
- self.add_stacked_pane_to_pane_id(new_pane, pid, pane_id_to_stack_under)
+ self.add_stacked_pane_to_pane_id(
+ new_pane,
+ pid,
+ pane_id_to_stack_under,
+ should_focus_pane,
+ )
} else if let Some(client_id) = client_id {
- self.add_stacked_pane_to_active_pane(new_pane, pid, client_id)
+ self.add_stacked_pane_to_active_pane(new_pane, pid, client_id, should_focus_pane)
} else {
log::error!("Must have client id or pane id to stack pane");
return Ok(());
@@ -3393,6 +3422,125 @@ impl Tab {
Ok(())
}
+ pub fn horizontal_split_of_pane_id(
+ &mut self,
+ pid: PaneId,
+ initial_pane_title: Option<String>,
+ invoked_with: Option<Run>,
+ target_pane_id: PaneId,
+ completion_tx: Option<NotificationEnd>,
+ borderless: Option<bool>,
+ ) -> Result<()> {
+ self.split_of_pane_id(
+ pid,
+ initial_pane_title,
+ invoked_with,
+ target_pane_id,
+ SplitDirection::Horizontal,
+ completion_tx,
+ borderless,
+ )
+ }
+ pub fn vertical_split_of_pane_id(
+ &mut self,
+ pid: PaneId,
+ initial_pane_title: Option<String>,
+ invoked_with: Option<Run>,
+ target_pane_id: PaneId,
+ completion_tx: Option<NotificationEnd>,
+ borderless: Option<bool>,
+ ) -> Result<()> {
+ self.split_of_pane_id(
+ pid,
+ initial_pane_title,
+ invoked_with,
+ target_pane_id,
+ SplitDirection::Vertical,
+ completion_tx,
+ borderless,
+ )
+ }
+ fn split_of_pane_id(
+ &mut self,
+ pid: PaneId,
+ initial_pane_title: Option<String>,
+ invoked_with: Option<Run>,
+ target_pane_id: PaneId,
+ split_direction: SplitDirection,
+ completion_tx: Option<NotificationEnd>,
+ borderless: Option<bool>,
+ ) -> Result<()> {
+ let err_context =
+ || format!("failed to split pane {target_pane_id:?} without changing focus");
+ if self.floating_panes.panes_are_visible() {
+ return Ok(());
+ }
+ if !self.tiled_panes.panes_contain(&target_pane_id) {
+ return Ok(());
+ }
+ self.close_down_to_max_terminals()
+ .with_context(err_context)?;
+ if self.tiled_panes.fullscreen_is_active() {
+ self.tiled_panes.unset_fullscreen();
+ }
+ self.dissolve_stack_lists_for_classic_mutation();
+ let can_split = match split_direction {
+ SplitDirection::Horizontal => self
+ .tiled_panes
+ .can_split_pane_id_horizontally(target_pane_id),
+ SplitDirection::Vertical => self
+ .tiled_panes
+ .can_split_pane_id_vertically(target_pane_id),
+ };
+ if !can_split {
+ self.senders
+ .send_to_pty(PtyInstruction::ClosePane(pid, completion_tx))
+ .with_context(err_context)?;
+ return Ok(());
+ }
+ if let PaneId::Terminal(term_pid) = pid {
+ let next_terminal_position = self.get_next_terminal_position();
+ let mut new_terminal = TerminalPane::new(
+ term_pid,
+ PaneGeom::default(),
+ 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(),
+ initial_pane_title,
+ invoked_with,
+ self.debug,
+ self.arrow_fonts,
+ self.styled_underlines,
+ self.osc8_hyperlinks,
+ self.explicitly_disable_kitty_keyboard_protocol,
+ completion_tx,
+ );
+ if let Some(borderless) = borderless {
+ new_terminal.set_borderless(borderless);
+ }
+ match split_direction {
+ SplitDirection::Horizontal => self.tiled_panes.split_pane_id_horizontally(
+ pid,
+ Box::new(new_terminal),
+ target_pane_id,
+ ),
+ SplitDirection::Vertical => self.tiled_panes.split_pane_id_vertically(
+ pid,
+ Box::new(new_terminal),
+ target_pane_id,
+ ),
+ }
+ self.set_should_clear_display_before_rendering();
+ self.swap_layouts.set_is_tiled_damaged();
+ }
+ Ok(())
+ }
+
pub fn get_active_pane(&self, client_id: ClientId) -> Option<&dyn Pane> {
self.get_active_pane_id(client_id).and_then(|ap| {
if self.floating_panes.panes_are_visible() {
@@ -6654,6 +6802,7 @@ impl Tab {
pane: Box<dyn Pane>,
pane_id: PaneId,
root_pane_id: PaneId,
+ should_focus: bool,
) -> Result<()> {
if self.tiled_panes.fullscreen_is_active() {
self.tiled_panes.unset_fullscreen();
@@ -6662,8 +6811,9 @@ impl Tab {
self.tiled_panes
.add_pane_to_stack_of_pane_id(pane_id, pane, root_pane_id);
self.set_should_clear_display_before_rendering();
- self.tiled_panes.expand_pane_in_stack(pane_id); // so that it will get focused by all
- // clients
+ if should_focus {
+ self.tiled_panes.expand_pane_in_stack(pane_id);
+ }
self.swap_layouts.set_is_tiled_damaged();
Ok(())
}
@@ -6672,6 +6822,7 @@ impl Tab {
pane: Box<dyn Pane>,
pane_id: PaneId,
client_id: ClientId,
+ should_focus: bool,
) -> Result<()> {
if self.tiled_panes.fullscreen_is_active() {
self.tiled_panes.unset_fullscreen();
@@ -6679,7 +6830,9 @@ impl Tab {
self.dissolve_stack_lists_for_classic_mutation();
self.tiled_panes
.add_pane_to_stack_of_active_pane(pane_id, pane, client_id);
- self.tiled_panes.focus_pane(pane_id, client_id);
+ if should_focus {
+ self.tiled_panes.focus_pane(pane_id, client_id);
+ }
self.swap_layouts.set_is_tiled_damaged();
Ok(())
}
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs
index a45ec812..17c9ac36 100644
--- a/zellij-server/src/unit/screen_tests.rs
+++ b/zellij-server/src/unit/screen_tests.rs
@@ -3252,6 +3252,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: None,
};
@@ -3307,6 +3308,7 @@ pub fn send_cli_new_pane_action_with_split_direction() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: None,
};
@@ -3362,6 +3364,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: None,
};
@@ -3428,6 +3431,7 @@ pub fn send_cli_new_pane_action_with_floating_pane_and_coordinates() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: None,
};
@@ -3472,6 +3476,7 @@ pub fn send_cli_edit_action_with_default_parameters() {
pinned: None,
borderless: Some(false),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
@@ -3515,6 +3520,7 @@ pub fn send_cli_edit_action_with_line_number() {
pinned: None,
borderless: Some(false),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
@@ -3558,6 +3564,7 @@ pub fn send_cli_edit_action_with_split_direction() {
pinned: None,
borderless: Some(false),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
};
send_cli_action_to_server(&session_metadata, cli_edit_action, client_id);
@@ -3759,6 +3766,7 @@ pub fn send_cli_new_tab_action_default_params() {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -3807,6 +3815,7 @@ pub fn send_cli_new_tab_action_with_name_and_layout() {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -5250,6 +5259,7 @@ pub fn send_cli_new_pane_in_place_with_close_replaced_pane() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -5301,6 +5311,7 @@ pub fn send_cli_edit_in_place_with_close_replaced_pane() {
height: None,
pinned: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -7853,6 +7864,7 @@ pub fn send_cli_new_tab_action_with_layout_string() {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -7907,6 +7919,7 @@ pub fn send_cli_new_tab_action_with_layout_string_and_name() {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
send_cli_action_to_server(&session_metadata, new_tab_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -7977,6 +7990,7 @@ pub fn send_cli_new_pane_action_with_tab_id() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: Some(0),
};
@@ -8039,6 +8053,7 @@ pub fn send_cli_new_floating_pane_action_with_tab_id() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(0),
};
@@ -8088,6 +8103,7 @@ pub fn send_cli_edit_action_with_tab_id() {
height: None,
pinned: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(0),
};
@@ -8149,6 +8165,7 @@ pub fn send_cli_new_pane_action_with_tab_id_and_direction() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: Some(false),
tab_id: Some(0),
};
@@ -8210,6 +8227,7 @@ pub fn send_cli_new_pane_action_with_tab_id_and_stacked() {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(0),
};
diff --git a/zellij-utils/assets/prost_ipc/client_server_contract.rs b/zellij-utils/assets/prost_ipc/client_server_contract.rs
index 6b01f7fc..79b0b95a 100644
--- a/zellij-utils/assets/prost_ipc/client_server_contract.rs
+++ b/zellij-utils/assets/prost_ipc/client_server_contract.rs
@@ -848,6 +848,8 @@ pub struct EditFileAction {
pub close_replaced_pane: bool,
#[prost(uint32, optional, tag="9")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="10")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -862,6 +864,8 @@ pub struct NewFloatingPaneAction {
pub near_current_pane: bool,
#[prost(uint32, optional, tag="8")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="9")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -878,6 +882,8 @@ pub struct NewTiledPaneAction {
pub borderless: ::core::option::Option<bool>,
#[prost(uint32, optional, tag="9")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="10")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -894,6 +900,8 @@ pub struct NewInPlacePaneAction {
pub close_replaced_pane: bool,
#[prost(uint32, optional, tag="6")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="7")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -906,6 +914,8 @@ pub struct NewStackedPaneAction {
pub near_current_pane: bool,
#[prost(uint32, optional, tag="4")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="5")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -922,6 +932,8 @@ pub struct NewBlockingPaneAction {
pub near_current_pane: bool,
#[prost(uint32, optional, tag="6")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="7")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -984,6 +996,8 @@ pub struct RunAction {
pub command: ::core::option::Option<RunCommandAction>,
#[prost(bool, tag="2")]
pub near_current_pane: bool,
+ #[prost(bool, tag="3")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -1020,6 +1034,8 @@ pub struct LaunchPluginAction {
pub close_replaced_pane: bool,
#[prost(uint32, optional, tag="7")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="8")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -1064,6 +1080,8 @@ pub struct NewTiledPluginPaneAction {
pub cwd: ::core::option::Option<::prost::alloc::string::String>,
#[prost(uint32, optional, tag="5")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="6")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -1080,6 +1098,8 @@ pub struct NewFloatingPluginPaneAction {
pub coordinates: ::core::option::Option<FloatingPaneCoordinates>,
#[prost(uint32, optional, tag="6")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="7")]
+ pub no_focus: bool,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@@ -1094,6 +1114,8 @@ pub struct NewInPlacePluginPaneAction {
pub close_replaced_pane: bool,
#[prost(uint32, optional, tag="5")]
pub tab_id: ::core::option::Option<u32>,
+ #[prost(bool, tag="6")]
+ pub no_focus: 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 ee2b6da1..e09755e0 100644
--- a/zellij-utils/src/cli.rs
+++ b/zellij-utils/src/cli.rs
@@ -520,6 +520,11 @@ pub enum Sessions {
/// if set, will open the pane near the current one rather than following the user's focus
#[clap(long)]
near_current_pane: bool,
+ #[clap(
+ long,
+ help = "if set, will open the pane without changing the focus of any client, placing it relative to the pane the command was issued from"
+ )]
+ no_focus: bool,
/// start this pane without a border (warning: will make it impossible to move with the
/// mouse)
#[clap(short, long, value_parser)]
@@ -588,6 +593,11 @@ pub enum Sessions {
/// Whether to pin a floating pane so that it is always on top
#[clap(long, requires("floating"))]
pinned: Option<bool>,
+ #[clap(
+ long,
+ help = "if set, will open the plugin pane without changing the focus of any client, placing it relative to the pane the command was issued from"
+ )]
+ no_focus: bool,
/// start this pane without a border (warning: will make it impossible to move with the
/// mouse)
#[clap(short, long, value_parser)]
@@ -657,6 +667,11 @@ pub enum Sessions {
/// if set, will open the pane near the current one rather than following the user's focus
#[clap(long)]
near_current_pane: bool,
+ #[clap(
+ long,
+ help = "if set, will open the pane without changing the focus of any client, placing it relative to the pane the command was issued from"
+ )]
+ no_focus: bool,
/// start this pane without a border (warning: will make it impossible to move with the
/// mouse)
#[clap(short, long, value_parser)]
@@ -1050,6 +1065,11 @@ pub enum CliAction {
/// if set, will open the pane near the current one rather than following the user's focus
#[clap(long)]
near_current_pane: bool,
+ #[clap(
+ long,
+ help = "if set, will open the pane without changing the focus of any client, placing it relative to the pane the command was issued from"
+ )]
+ no_focus: bool,
/// start this pane without a border (warning: will make it impossible to move with the
/// mouse)
#[clap(long, value_parser)]
@@ -1123,6 +1143,11 @@ pub enum CliAction {
/// if set, will open the pane near the current one rather than following the user's focus
#[clap(long)]
near_current_pane: bool,
+ #[clap(
+ long,
+ help = "if set, will open the pane without changing the focus of any client, placing it relative to the pane the command was issued from"
+ )]
+ no_focus: bool,
/// start this pane without a border (warning: will make it impossible to move with the
/// mouse)
#[clap(short, long, value_parser)]
@@ -1335,6 +1360,12 @@ pub enum CliAction {
conflicts_with("block-until-exit-failure")
)]
block_until_exit: bool,
+
+ #[clap(
+ long,
+ help = "if set, will create the tab without changing the focus of any client"
+ )]
+ no_focus: bool,
},
/// Move the focused tab in the specified direction. [right|left]
MoveTab {
@@ -1437,6 +1468,11 @@ pub enum CliAction {
configuration: Option<PluginUserConfiguration>,
#[clap(short, long, value_parser)]
skip_plugin_cache: bool,
+ #[clap(
+ long,
+ help = "if set, will open the plugin pane without changing the focus of any client"
+ )]
+ no_focus: bool,
/// Target a specific tab by ID
#[clap(long, value_parser, conflicts_with("in-place"))]
tab_id: Option<usize>,
diff --git a/zellij-utils/src/client_server_contract/common_types.proto b/zellij-utils/src/client_server_contract/common_types.proto
index 14f8eda0..4c2f8395 100644
--- a/zellij-utils/src/client_server_contract/common_types.proto
+++ b/zellij-utils/src/client_server_contract/common_types.proto
@@ -469,6 +469,7 @@ message EditFileAction {
bool near_current_pane = 7;
bool close_replaced_pane = 8;
optional uint32 tab_id = 9;
+ bool no_focus = 10;
}
message NewFloatingPaneAction {
@@ -477,6 +478,7 @@ message NewFloatingPaneAction {
optional FloatingPaneCoordinates coordinates = 3;
bool near_current_pane = 7;
optional uint32 tab_id = 8;
+ bool no_focus = 9;
}
message NewTiledPaneAction {
@@ -486,6 +488,7 @@ message NewTiledPaneAction {
bool near_current_pane = 7;
optional bool borderless = 8;
optional uint32 tab_id = 9;
+ bool no_focus = 10;
}
message NewInPlacePaneAction {
@@ -495,6 +498,7 @@ message NewInPlacePaneAction {
optional PaneId pane_id_to_replace = 4;
bool close_replaced_pane = 5;
optional uint32 tab_id = 6;
+ bool no_focus = 7;
}
message NewStackedPaneAction {
@@ -502,6 +506,7 @@ message NewStackedPaneAction {
optional string pane_name = 2;
bool near_current_pane = 3;
optional uint32 tab_id = 4;
+ bool no_focus = 5;
}
message NewBlockingPaneAction {
@@ -511,6 +516,7 @@ message NewBlockingPaneAction {
optional UnblockCondition unblock_condition = 4;
bool near_current_pane = 5;
optional uint32 tab_id = 6;
+ bool no_focus = 7;
}
message PaneNameInputAction {
@@ -549,6 +555,7 @@ message MoveTabAction {
message RunAction {
RunCommandAction command = 1;
bool near_current_pane = 2;
+ bool no_focus = 3;
}
message LaunchOrFocusPluginAction {
@@ -569,6 +576,7 @@ message LaunchPluginAction {
optional string cwd = 5;
bool close_replaced_pane = 6;
optional uint32 tab_id = 7;
+ bool no_focus = 8;
}
message MouseEventAction {
@@ -597,6 +605,7 @@ message NewTiledPluginPaneAction {
bool skip_cache = 3;
optional string cwd = 4;
optional uint32 tab_id = 5;
+ bool no_focus = 6;
}
message NewFloatingPluginPaneAction {
@@ -606,6 +615,7 @@ message NewFloatingPluginPaneAction {
optional string cwd = 4;
optional FloatingPaneCoordinates coordinates = 5;
optional uint32 tab_id = 6;
+ bool no_focus = 7;
}
message NewInPlacePluginPaneAction {
@@ -614,6 +624,7 @@ message NewInPlacePluginPaneAction {
bool skip_cache = 3;
bool close_replaced_pane = 4;
optional uint32 tab_id = 5;
+ bool no_focus = 6;
}
message StartOrReloadPluginAction {
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index 757e99e4..c0e953b6 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -235,6 +235,7 @@ pub enum Action {
command: Option<RunCommandAction>,
unblock_condition: Option<UnblockCondition>,
near_current_pane: bool,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Open the file in a new pane using the default editor
@@ -248,6 +249,7 @@ pub enum Action {
start_suppressed: bool,
coordinates: Option<FloatingPaneCoordinates>,
near_current_pane: bool,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Open a new floating pane
@@ -257,6 +259,7 @@ pub enum Action {
pane_name: Option<String>,
coordinates: Option<FloatingPaneCoordinates>,
near_current_pane: bool,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Open a new tiled (embedded, non-floating) pane
@@ -266,6 +269,7 @@ pub enum Action {
command: Option<RunCommandAction>,
pane_name: Option<String>,
near_current_pane: bool,
+ no_focus: bool,
borderless: Option<bool>,
tab_id: Option<usize>,
},
@@ -275,6 +279,7 @@ pub enum Action {
command: Option<RunCommandAction>,
pane_name: Option<String>,
near_current_pane: bool,
+ no_focus: bool,
pane_id_to_replace: Option<PaneId>,
close_replaced_pane: bool,
tab_id: Option<usize>,
@@ -284,6 +289,7 @@ pub enum Action {
command: Option<RunCommandAction>,
pane_name: Option<String>,
near_current_pane: bool,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Embed focused pane in tab if floating or float focused pane if embedded
@@ -347,6 +353,7 @@ pub enum Action {
Run {
command: RunCommandAction,
near_current_pane: bool,
+ no_focus: bool,
},
/// Set pane default foreground/background color
SetPaneColor {
@@ -388,6 +395,7 @@ pub enum Action {
close_replaced_pane: bool,
skip_cache: bool,
cwd: Option<PathBuf>,
+ no_focus: bool,
tab_id: Option<usize>,
},
MouseEvent {
@@ -434,6 +442,7 @@ pub enum Action {
pane_name: Option<String>,
skip_cache: bool,
cwd: Option<PathBuf>,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Returns: Created pane ID (format: plugin_<id>)
@@ -443,6 +452,7 @@ pub enum Action {
skip_cache: bool,
cwd: Option<PathBuf>,
coordinates: Option<FloatingPaneCoordinates>,
+ no_focus: bool,
tab_id: Option<usize>,
},
/// Returns: Created pane ID (format: plugin_<id>)
@@ -451,6 +461,7 @@ pub enum Action {
pane_name: Option<String>,
skip_cache: bool,
close_replaced_pane: bool,
+ no_focus: bool,
tab_id: Option<usize>,
},
StartOrReloadPlugin {
@@ -1039,6 +1050,7 @@ impl Action {
block_until_exit,
unblock_condition,
near_current_pane,
+ no_focus,
borderless,
tab_id,
} => {
@@ -1124,6 +1136,7 @@ impl Action {
command,
unblock_condition,
near_current_pane,
+ no_focus,
tab_id,
}])
} else if let Some(plugin) = plugin {
@@ -1156,6 +1169,7 @@ impl Action {
coordinates: FloatingPaneCoordinates::new(
x, y, width, height, pinned, borderless,
),
+ no_focus,
tab_id,
}])
} else if in_place {
@@ -1164,6 +1178,7 @@ impl Action {
pane_name: name,
skip_cache: skip_plugin_cache,
close_replaced_pane,
+ no_focus,
tab_id,
}])
} else {
@@ -1180,6 +1195,7 @@ impl Action {
pane_name: name,
skip_cache: skip_plugin_cache,
cwd,
+ no_focus,
tab_id,
}])
}
@@ -1205,6 +1221,7 @@ impl Action {
x, y, width, height, pinned, borderless,
),
near_current_pane,
+ no_focus,
tab_id,
}])
} else if in_place {
@@ -1212,6 +1229,7 @@ impl Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane,
+ no_focus,
pane_id_to_replace,
close_replaced_pane,
tab_id,
@@ -1221,6 +1239,7 @@ impl Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane,
+ no_focus,
tab_id,
}])
} else {
@@ -1229,6 +1248,7 @@ impl Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane,
+ no_focus,
borderless,
tab_id,
}])
@@ -1242,6 +1262,7 @@ impl Action {
x, y, width, height, pinned, borderless,
),
near_current_pane,
+ no_focus,
tab_id,
}])
} else if in_place {
@@ -1249,6 +1270,7 @@ impl Action {
command: None,
pane_name: name,
near_current_pane,
+ no_focus,
pane_id_to_replace,
close_replaced_pane,
tab_id,
@@ -1258,6 +1280,7 @@ impl Action {
command: None,
pane_name: name,
near_current_pane,
+ no_focus,
tab_id,
}])
} else {
@@ -1266,6 +1289,7 @@ impl Action {
command: None,
pane_name: name,
near_current_pane,
+ no_focus,
borderless,
tab_id,
}])
@@ -1286,6 +1310,7 @@ impl Action {
height,
pinned,
near_current_pane,
+ no_focus,
borderless,
tab_id,
} => {
@@ -1311,6 +1336,7 @@ impl Action {
x, y, width, height, pinned, borderless,
),
near_current_pane,
+ no_focus,
tab_id,
}])
},
@@ -1414,6 +1440,7 @@ impl Action {
block_until_exit_success,
block_until_exit_failure,
block_until_exit,
+ no_focus,
} => {
let current_dir = get_current_dir();
let cwd = cwd
@@ -1520,8 +1547,8 @@ impl Action {
.any(|(_, layout, _)| layout.focus.unwrap_or(false));
for (tab_name, layout, floating_panes_layout) in tabs.drain(..) {
let name = tab_name.or_else(|| name.clone());
- let should_change_focus_to_new_tab =
- layout.focus.unwrap_or_else(|| {
+ let should_change_focus_to_new_tab = !no_focus
+ && layout.focus.unwrap_or_else(|| {
if !has_focused_tab {
has_focused_tab = true;
true
@@ -1546,7 +1573,7 @@ impl Action {
let swap_tiled_layouts = Some(layout.swap_tiled_layouts.clone());
let swap_floating_layouts = Some(layout.swap_floating_layouts.clone());
let (layout, floating_panes_layout) = layout.new_tab();
- let should_change_focus_to_new_tab = true;
+ let should_change_focus_to_new_tab = !no_focus;
Ok(vec![Action::NewTab {
tiled_layout: Some(layout),
floating_layouts: floating_panes_layout,
@@ -1636,8 +1663,8 @@ impl Action {
.any(|(_, layout, _)| layout.focus.unwrap_or(false));
for (tab_name, layout, floating_panes_layout) in tabs.drain(..) {
let name = tab_name.or_else(|| name.clone());
- let should_change_focus_to_new_tab =
- layout.focus.unwrap_or_else(|| {
+ let should_change_focus_to_new_tab = !no_focus
+ && layout.focus.unwrap_or_else(|| {
if !has_focused_tab {
has_focused_tab = true;
true
@@ -1662,7 +1689,7 @@ impl Action {
let swap_tiled_layouts = Some(layout.swap_tiled_layouts.clone());
let swap_floating_layouts = Some(layout.swap_floating_layouts.clone());
let (layout, floating_panes_layout) = layout.new_tab();
- let should_change_focus_to_new_tab = true;
+ let should_change_focus_to_new_tab = !no_focus;
Ok(vec![Action::NewTab {
tiled_layout: Some(layout),
floating_layouts: floating_panes_layout,
@@ -1676,7 +1703,7 @@ impl Action {
}])
}
} else {
- let should_change_focus_to_new_tab = true;
+ let should_change_focus_to_new_tab = !no_focus;
Ok(vec![Action::NewTab {
tiled_layout: None,
floating_layouts: vec![],
@@ -1854,6 +1881,7 @@ impl Action {
close_replaced_pane,
configuration,
skip_plugin_cache,
+ no_focus,
tab_id,
} => {
let current_dir = get_current_dir();
@@ -1870,6 +1898,7 @@ impl Action {
close_replaced_pane,
skip_cache: skip_plugin_cache,
cwd: Some(current_dir),
+ no_focus,
tab_id,
}])
},
@@ -3474,6 +3503,7 @@ mod tests {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
assert!(result.is_ok());
@@ -3510,6 +3540,7 @@ mod tests {
block_until_exit: false,
block_until_exit_success: false,
block_until_exit_failure: false,
+ no_focus: false,
};
let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
assert!(result.is_err());
@@ -3608,6 +3639,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(3),
};
@@ -3651,6 +3683,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -3694,6 +3727,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -3739,6 +3773,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -3775,6 +3810,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(5),
};
@@ -3818,6 +3854,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(1),
};
@@ -3861,6 +3898,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(2),
};
@@ -3892,6 +3930,7 @@ mod tests {
height: None,
pinned: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(4),
};
@@ -3923,6 +3962,7 @@ mod tests {
height: None,
pinned: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
};
@@ -3966,6 +4006,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(2),
};
@@ -4009,6 +4050,7 @@ mod tests {
block_until_exit: false,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(1),
};
diff --git a/zellij-utils/src/ipc/protobuf_conversion.rs b/zellij-utils/src/ipc/protobuf_conversion.rs
index 1f625ddd..ebaae103 100644
--- a/zellij-utils/src/ipc/protobuf_conversion.rs
+++ b/zellij-utils/src/ipc/protobuf_conversion.rs
@@ -1225,6 +1225,7 @@ impl From<crate::input::actions::Action>
start_suppressed,
coordinates,
near_current_pane,
+ no_focus,
tab_id,
..
} => ActionType::EditFile(EditFileAction {
@@ -1237,12 +1238,14 @@ impl From<crate::input::actions::Action>
coordinates: coordinates.map(|c| c.into()),
near_current_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewFloatingPane {
command,
pane_name,
coordinates,
near_current_pane,
+ no_focus,
tab_id,
..
} => ActionType::NewFloatingPane(NewFloatingPaneAction {
@@ -1251,12 +1254,14 @@ impl From<crate::input::actions::Action>
coordinates: coordinates.map(|c| c.into()),
near_current_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewTiledPane {
direction,
command,
pane_name,
near_current_pane,
+ no_focus,
borderless,
tab_id,
..
@@ -1267,11 +1272,13 @@ impl From<crate::input::actions::Action>
near_current_pane,
borderless,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewInPlacePane {
command,
pane_name,
near_current_pane,
+ no_focus,
pane_id_to_replace,
close_replaced_pane,
tab_id,
@@ -1283,11 +1290,13 @@ impl From<crate::input::actions::Action>
pane_id_to_replace: pane_id_to_replace.and_then(|p| p.try_into().ok()),
close_replaced_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewStackedPane {
command,
pane_name,
near_current_pane,
+ no_focus,
tab_id,
..
} => ActionType::NewStackedPane(NewStackedPaneAction {
@@ -1295,6 +1304,7 @@ impl From<crate::input::actions::Action>
pane_name,
near_current_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewBlockingPane {
placement,
@@ -1302,6 +1312,7 @@ impl From<crate::input::actions::Action>
command,
unblock_condition,
near_current_pane,
+ no_focus,
tab_id,
..
} => ActionType::NewBlockingPane(NewBlockingPaneAction {
@@ -1311,6 +1322,7 @@ impl From<crate::input::actions::Action>
unblock_condition: unblock_condition.map(|c| unblock_condition_to_proto_i32(c)),
near_current_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::TogglePaneEmbedOrFloating => {
ActionType::TogglePaneEmbedOrFloating(TogglePaneEmbedOrFloatingAction {})
@@ -1403,9 +1415,11 @@ impl From<crate::input::actions::Action>
crate::input::actions::Action::Run {
command,
near_current_pane,
+ no_focus,
} => ActionType::Run(RunAction {
command: Some(command.into()),
near_current_pane,
+ no_focus,
}),
crate::input::actions::Action::Detach => ActionType::Detach(DetachAction {}),
crate::input::actions::Action::SetDarkTheme => {
@@ -1458,6 +1472,7 @@ impl From<crate::input::actions::Action>
close_replaced_pane,
skip_cache,
cwd,
+ no_focus,
tab_id,
..
} => ActionType::LaunchPlugin(LaunchPluginAction {
@@ -1468,6 +1483,7 @@ impl From<crate::input::actions::Action>
skip_cache,
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::MouseEvent { event } => {
ActionType::MouseEvent(MouseEventAction {
@@ -1528,6 +1544,7 @@ impl From<crate::input::actions::Action>
pane_name,
skip_cache,
cwd,
+ no_focus,
tab_id,
..
} => ActionType::NewTiledPluginPane(NewTiledPluginPaneAction {
@@ -1536,6 +1553,7 @@ impl From<crate::input::actions::Action>
skip_cache,
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewFloatingPluginPane {
plugin,
@@ -1543,6 +1561,7 @@ impl From<crate::input::actions::Action>
skip_cache,
cwd,
coordinates,
+ no_focus,
tab_id,
..
} => ActionType::NewFloatingPluginPane(NewFloatingPluginPaneAction {
@@ -1552,12 +1571,14 @@ impl From<crate::input::actions::Action>
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
coordinates: coordinates.map(|c| c.into()),
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::NewInPlacePluginPane {
plugin,
pane_name,
skip_cache,
close_replaced_pane,
+ no_focus,
tab_id,
..
} => ActionType::NewInPlacePluginPane(NewInPlacePluginPaneAction {
@@ -1566,6 +1587,7 @@ impl From<crate::input::actions::Action>
skip_cache,
close_replaced_pane,
tab_id: tab_id.map(|t| t as u32),
+ no_focus,
}),
crate::input::actions::Action::StartOrReloadPlugin { plugin } => {
ActionType::StartOrReloadPlugin(StartOrReloadPluginAction {
@@ -2099,6 +2121,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.map(|c| c.try_into())
.transpose()?,
near_current_pane: edit_file_action.near_current_pane,
+ no_focus: edit_file_action.no_focus,
tab_id: edit_file_action.tab_id.map(|t| t as usize),
}),
ActionType::NewFloatingPane(new_floating_action) => {
@@ -2113,6 +2136,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.map(|c| c.try_into())
.transpose()?,
near_current_pane: new_floating_action.near_current_pane,
+ no_focus: new_floating_action.no_focus,
tab_id: new_floating_action.tab_id.map(|t| t as usize),
})
},
@@ -2125,6 +2149,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
command: new_tiled_action.command.map(|c| c.try_into()).transpose()?,
pane_name: new_tiled_action.pane_name,
near_current_pane: new_tiled_action.near_current_pane,
+ no_focus: new_tiled_action.no_focus,
borderless: new_tiled_action.borderless,
tab_id: new_tiled_action.tab_id.map(|t| t as usize),
})
@@ -2137,6 +2162,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.transpose()?,
pane_name: new_in_place_action.pane_name,
near_current_pane: new_in_place_action.near_current_pane,
+ no_focus: new_in_place_action.no_focus,
pane_id_to_replace: new_in_place_action
.pane_id_to_replace
.and_then(|p| p.try_into().ok()),
@@ -2152,6 +2178,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.transpose()?,
pane_name: new_stacked_action.pane_name,
near_current_pane: new_stacked_action.near_current_pane,
+ no_focus: new_stacked_action.no_focus,
tab_id: new_stacked_action.tab_id.map(|t| t as usize),
})
},
@@ -2171,6 +2198,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.map(|c| proto_i32_to_unblock_condition(c))
.transpose()?,
near_current_pane: new_blocking_action.near_current_pane,
+ no_focus: new_blocking_action.no_focus,
tab_id: new_blocking_action.tab_id.map(|t| t as usize),
})
},
@@ -2287,6 +2315,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.ok_or_else(|| anyhow!("Run missing command"))?
.try_into()?,
near_current_pane: run_action.near_current_pane,
+ no_focus: run_action.no_focus,
}),
ActionType::Detach(_) => Ok(crate::input::actions::Action::Detach),
ActionType::SetDarkTheme(_) => Ok(crate::input::actions::Action::SetDarkTheme),
@@ -2332,6 +2361,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
close_replaced_pane: launch_plugin_action.close_replaced_pane,
skip_cache: launch_plugin_action.skip_cache,
cwd: launch_plugin_action.cwd.map(PathBuf::from),
+ no_focus: launch_plugin_action.no_focus,
tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
})
},
@@ -2405,6 +2435,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
pane_name: new_tiled_plugin_action.pane_name,
skip_cache: new_tiled_plugin_action.skip_cache,
cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),
+ no_focus: new_tiled_plugin_action.no_focus,
tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),
})
},
@@ -2421,6 +2452,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
.coordinates
.map(|c| c.try_into())
.transpose()?,
+ no_focus: new_floating_plugin_action.no_focus,
tab_id: new_floating_plugin_action.tab_id.map(|t| t as usize),
})
},
@@ -2433,6 +2465,7 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
pane_name: new_in_place_plugin_action.pane_name,
skip_cache: new_in_place_plugin_action.skip_cache,
close_replaced_pane: new_in_place_plugin_action.close_replaced_pane,
+ no_focus: new_in_place_plugin_action.no_focus,
tab_id: new_in_place_plugin_action.tab_id.map(|t| t as usize),
})
},
diff --git a/zellij-utils/src/ipc/tests/roundtrip_tests.rs b/zellij-utils/src/ipc/tests/roundtrip_tests.rs
index 4f9d57ac..db0b8fc1 100644
--- a/zellij-utils/src/ipc/tests/roundtrip_tests.rs
+++ b/zellij-utils/src/ipc/tests/roundtrip_tests.rs
@@ -1059,6 +1059,7 @@ fn test_client_messages() {
start_suppressed: false,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1084,6 +1085,7 @@ fn test_client_messages() {
start_suppressed: false,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1109,6 +1111,7 @@ fn test_client_messages() {
start_suppressed: false,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1134,6 +1137,7 @@ fn test_client_messages() {
start_suppressed: true,
coordinates: FloatingPaneCoordinates::new(None, None, None, None, None, Some(false)),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1166,6 +1170,7 @@ fn test_client_messages() {
Some(false),
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1198,6 +1203,7 @@ fn test_client_messages() {
Some(false),
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1230,6 +1236,7 @@ fn test_client_messages() {
Some(false),
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1262,6 +1269,7 @@ fn test_client_messages() {
Some(false)
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1274,6 +1282,7 @@ fn test_client_messages() {
pane_name: None,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1302,6 +1311,7 @@ fn test_client_messages() {
Some(false),
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1334,6 +1344,7 @@ fn test_client_messages() {
Some(false),
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1346,6 +1357,7 @@ fn test_client_messages() {
direction: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
},
@@ -1372,6 +1384,7 @@ fn test_client_messages() {
direction: Some(Direction::Right),
pane_name: Some("my_pane_name".to_owned()),
near_current_pane: false,
+ no_focus: false,
borderless: Some(true),
tab_id: None,
},
@@ -1397,6 +1410,7 @@ fn test_client_messages() {
}),
pane_name: Some("my_pane_name".to_owned()),
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane: false,
tab_id: None,
@@ -1410,6 +1424,7 @@ fn test_client_messages() {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane: false,
tab_id: None,
@@ -1436,6 +1451,7 @@ fn test_client_messages() {
}),
pane_name: Some("my_pane_name".to_owned()),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -1447,6 +1463,7 @@ fn test_client_messages() {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2249,6 +2266,7 @@ fn test_client_messages() {
use_terminal_title: false,
},
near_current_pane: false,
+ no_focus: false,
},
terminal_id: Some(1),
client_id: Some(100),
@@ -2296,6 +2314,7 @@ fn test_client_messages() {
close_replaced_pane: false,
skip_cache: true,
cwd: None,
+ no_focus: true,
tab_id: None,
},
terminal_id: Some(1),
@@ -2310,6 +2329,7 @@ fn test_client_messages() {
close_replaced_pane: false,
skip_cache: false,
cwd: Some(PathBuf::from("/path/to/cwd")),
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2483,6 +2503,7 @@ fn test_client_messages() {
pane_name: Some("my_pane_name".to_owned()),
skip_cache: false,
cwd: Some(PathBuf::from("relative/path/to/cwd")),
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2496,6 +2517,7 @@ fn test_client_messages() {
skip_cache: true,
cwd: Some(PathBuf::from("relative/path/to/cwd")),
coordinates: None,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2516,6 +2538,7 @@ fn test_client_messages() {
Some(true),
Some(false),
),
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2528,6 +2551,7 @@ fn test_client_messages() {
pane_name: Some("my_pane_name".to_owned()),
skip_cache: true,
close_replaced_pane: false,
+ no_focus: false,
tab_id: None,
},
terminal_id: Some(1),
@@ -2540,6 +2564,7 @@ fn test_client_messages() {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: Some(3),
},
@@ -2553,6 +2578,7 @@ fn test_client_messages() {
pane_name: None,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: Some(5),
},
terminal_id: Some(1),
@@ -2564,6 +2590,7 @@ fn test_client_messages() {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: Some(2),
},
terminal_id: Some(1),
@@ -2580,6 +2607,7 @@ fn test_client_messages() {
command: None,
unblock_condition: None,
near_current_pane: false,
+ no_focus: false,
tab_id: Some(1),
},
terminal_id: Some(1),
@@ -2601,6 +2629,7 @@ fn test_client_messages() {
start_suppressed: false,
coordinates: None,
near_current_pane: false,
+ no_focus: false,
tab_id: Some(4),
},
terminal_id: Some(1),
@@ -2612,6 +2641,7 @@ fn test_client_messages() {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane: false,
tab_id: Some(7),
@@ -2642,6 +2672,7 @@ fn test_client_messages() {
close_replaced_pane: false,
skip_cache: false,
cwd: None,
+ no_focus: false,
tab_id: Some(6),
},
terminal_id: Some(1),
@@ -2654,6 +2685,7 @@ fn test_client_messages() {
pane_name: None,
skip_cache: false,
cwd: None,
+ no_focus: false,
tab_id: Some(1),
},
terminal_id: Some(1),
@@ -2667,6 +2699,7 @@ fn test_client_messages() {
skip_cache: false,
cwd: None,
coordinates: None,
+ no_focus: false,
tab_id: Some(3),
},
terminal_id: Some(1),
@@ -2679,6 +2712,7 @@ fn test_client_messages() {
pane_name: None,
skip_cache: false,
close_replaced_pane: false,
+ no_focus: false,
tab_id: Some(2),
},
terminal_id: Some(1),
diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs
index 30495d5f..94848e63 100644
--- a/zellij-utils/src/kdl/mod.rs
+++ b/zellij-utils/src/kdl/mod.rs
@@ -573,6 +573,7 @@ impl Action {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
});
} else {
@@ -2038,6 +2039,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
x, y, width, height, pinned, borderless,
),
near_current_pane: false,
+ no_focus: false,
tab_id: None,
})
} else if in_place {
@@ -2045,6 +2047,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane: false,
+ no_focus: false,
pane_id_to_replace: None,
close_replaced_pane,
tab_id: None,
@@ -2054,6 +2057,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
})
} else {
@@ -2062,6 +2066,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
command: Some(run_command_action),
pane_name: name,
near_current_pane: false,
+ no_focus: false,
borderless: None,
tab_id: None,
})
@@ -2171,6 +2176,7 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
skip_cache: skip_plugin_cache,
cwd: None, // we explicitly do not send the current dir here so that it will be
// filled from the active pane == better UX
+ no_focus: false,
tab_id: None,
})
},
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
index 209bff3f..f1d71222 100644
--- a/zellij-utils/src/plugin_api/action.rs
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -355,6 +355,7 @@ impl TryFrom<ProtobufAction> for Action {
start_suppressed: false,
coordinates: None,
near_current_pane,
+ no_focus: false,
tab_id: None,
})
},
@@ -371,6 +372,7 @@ impl TryFrom<ProtobufAction> for Action {
pane_name,
coordinates: None,
near_current_pane,
+ no_focus: false,
tab_id: None,
})
} else {
@@ -379,6 +381,7 @@ impl TryFrom<ProtobufAction> for Action {
pane_name: None,
coordinates: None,
near_current_pane,
+ no_focus: false,
tab_id: None,
})
}
@@ -401,6 +404,7 @@ impl TryFrom<ProtobufAction> for Action {
command: Some(run_command_action),
pane_name,
near_current_pane,
+ no_focus: false,
borderless,
tab_id: None,
})
@@ -410,6 +414,7 @@ impl TryFrom<ProtobufAction> for Action {
command: None,
pane_name: None,
near_current_pane,
+ no_focus: false,
borderless,
tab_id: None,
})
@@ -620,6 +625,7 @@ impl TryFrom<ProtobufAction> for Action {
Ok(Action::Run {
command: run_command_action,
near_current_pane: false,
+ no_focus: false,
})
},
_ => Err("Wrong payload for Action::Run"),
@@ -723,6 +729,7 @@ impl TryFrom<ProtobufAction> for Action {
close_replaced_pane: false,
skip_cache: skip_plugin_cache,
cwd: None,
+ no_focus: false,
tab_id: None,
})
},
@@ -843,6 +850,7 @@ impl TryFrom<ProtobufAction> for Action {
pane_name,
skip_cache: skip_plugin_cache,
cwd: None,
+ no_focus: false,
tab_id: None,
})
},
@@ -869,6 +877,7 @@ impl TryFrom<ProtobufAction> for Action {
skip_cache: skip_plugin_cache,
cwd: None,
coordinates: None,
+ no_focus: false,
tab_id: None,
})
},
@@ -1022,6 +1031,7 @@ impl TryFrom<ProtobufAction> for Action {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
}),
},
@@ -1044,6 +1054,7 @@ impl TryFrom<ProtobufAction> for Action {
command,
unblock_condition,
near_current_pane,
+ no_focus: false,
tab_id: None,
})
},
@@ -1062,6 +1073,7 @@ impl TryFrom<ProtobufAction> for Action {
command: Some(run_command_action),
pane_name,
near_current_pane,
+ no_focus: false,
pane_id_to_replace,
close_replaced_pane,
tab_id: None,
@@ -1071,6 +1083,7 @@ impl TryFrom<ProtobufAction> for Action {
command: None,
pane_name: payload.pane_name,
near_current_pane,
+ no_focus: false,
pane_id_to_replace,
close_replaced_pane,
tab_id: None,
@@ -1598,6 +1611,7 @@ impl TryFrom<Action> for ProtobufAction {
Action::Run {
command: run_command_action,
near_current_pane: _,
+ no_focus: _,
} => {
let run_command_action: ProtobufRunCommandAction = run_command_action.try_into()?;
Ok(ProtobufAction {
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 5a35fe4e..9b6ac7fe 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
@@ -1349,6 +1349,7 @@ Config {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
SwitchToMode {
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 83046edf..6c210eeb 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
@@ -1349,6 +1349,7 @@ Config {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
SwitchToMode {
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 7ae735ab..7f1625d3 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
@@ -1349,6 +1349,7 @@ Config {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
SwitchToMode {
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 f0391d92..c7db95cd 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
@@ -1349,6 +1349,7 @@ Config {
command: None,
pane_name: None,
near_current_pane: false,
+ no_focus: false,
tab_id: None,
},
SwitchToMode {