summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-06-17 14:41:49 +0200
committerGitHub <noreply@github.com>2023-06-17 14:41:49 +0200
commit63e3a1eae2e727a808084d9fe9ff6eca7816ef7e (patch)
tree445840cba9b3193eca8d5fc73e9cffa610f510ca
parent044519f53740d02b6feabe379bc618a1ce5c4ec2 (diff)
feat(plugins): more plugin api methods (#2550)
* feat(plugins): close, focus, rename pane, rename tab and show_self api methods * style(fmt): rustfmt
-rw-r--r--default-plugins/fixture-plugin-for-tests/src/main.rs27
-rw-r--r--zellij-server/src/panes/plugin_pane.rs4
-rw-r--r--zellij-server/src/panes/terminal_pane.rs4
-rw-r--r--zellij-server/src/plugins/unit/plugin_tests.rs480
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap13
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap13
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap14
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap14
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap34
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap24
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap36
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap14
-rw-r--r--zellij-server/src/plugins/zellij_exports.rs97
-rw-r--r--zellij-server/src/route.rs61
-rw-r--r--zellij-server/src/screen.rs65
-rw-r--r--zellij-server/src/tab/mod.rs19
-rw-r--r--zellij-tile/src/shim.rs66
-rw-r--r--zellij-utils/src/errors.rs3
-rw-r--r--zellij-utils/src/input/actions.rs7
19 files changed, 994 insertions, 1 deletions
diff --git a/default-plugins/fixture-plugin-for-tests/src/main.rs b/default-plugins/fixture-plugin-for-tests/src/main.rs
index 2107137d1..9ce45f8af 100644
--- a/default-plugins/fixture-plugin-for-tests/src/main.rs
+++ b/default-plugins/fixture-plugin-for-tests/src/main.rs
@@ -183,6 +183,33 @@ impl ZellijPlugin for State {
Key::Ctrl('p') => {
hide_self();
},
+ Key::Ctrl('q') => {
+ let should_float_if_hidden = false;
+ show_self(should_float_if_hidden);
+ },
+ Key::Ctrl('r') => {
+ close_terminal_pane(1);
+ },
+ Key::Ctrl('s') => {
+ close_plugin_pane(1);
+ },
+ Key::Ctrl('t') => {
+ let should_float_if_hidden = false;
+ focus_terminal_pane(1, should_float_if_hidden);
+ },
+ Key::Ctrl('u') => {
+ let should_float_if_hidden = false;
+ focus_plugin_pane(1, should_float_if_hidden);
+ },
+ Key::Ctrl('v') => {
+ rename_terminal_pane(1, "new terminal_pane_name");
+ },
+ Key::Ctrl('w') => {
+ rename_plugin_pane(1, "new plugin_pane_name");
+ },
+ Key::Ctrl('x') => {
+ rename_tab(1, "new tab name");
+ },
_ => {},
},
Event::CustomMessage(message, payload) => {
diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs
index 557769f02..465529609 100644
--- a/zellij-server/src/panes/plugin_pane.rs
+++ b/zellij-server/src/panes/plugin_pane.rs
@@ -571,6 +571,10 @@ impl Pane for PluginPane {
self.pane_name.to_owned()
}
}
+ fn rename(&mut self, buf: Vec<u8>) {
+ self.pane_name = String::from_utf8_lossy(&buf).to_string();
+ self.set_should_render(true);
+ }
}
impl PluginPane {
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index df74afd69..a01d815b5 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -745,6 +745,10 @@ impl Pane for TerminalPane {
None => false,
}
}
+ fn rename(&mut self, buf: Vec<u8>) {
+ self.pane_name = String::from_utf8_lossy(&buf).to_string();
+ self.set_should_render(true);
+ }
}
impl TerminalPane {
diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs
index 6084c9fe9..3ec8485b0 100644
--- a/zellij-server/src/plugins/unit/plugin_tests.rs
+++ b/zellij-server/src/plugins/unit/plugin_tests.rs
@@ -3608,3 +3608,483 @@ pub fn hide_self_plugin_command() {
.clone();
assert_snapshot!(format!("{:#?}", new_tab_event));
}
+
+#[test]
+#[ignore]
+pub fn show_self_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::FocusPaneWithId,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('q')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::FocusPaneWithId(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn close_terminal_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::ClosePane,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('r')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::ClosePane(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn close_plugin_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::ClosePane,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('s')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::ClosePane(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn focus_terminal_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::FocusPaneWithId,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('t')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::FocusPaneWithId(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn focus_plugin_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::FocusPaneWithId,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('u')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::FocusPaneWithId(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn rename_terminal_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::RenamePane,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('v')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::RenamePane(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn rename_plugin_pane_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::RenamePane,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('w')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::RenamePane(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
+
+#[test]
+#[ignore]
+pub fn rename_tab_plugin_command() {
+ let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
+ // destructor removes the directory
+ let plugin_host_folder = PathBuf::from(temp_folder.path());
+ let (plugin_thread_sender, screen_receiver, mut teardown) =
+ create_plugin_thread(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ };
+ let tab_index = 1;
+ let client_id = 1;
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let received_screen_instructions = Arc::new(Mutex::new(vec![]));
+ let screen_thread = log_actions_in_thread!(
+ received_screen_instructions,
+ ScreenInstruction::RenameTab,
+ screen_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ client_id,
+ size,
+ ));
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('x')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ screen_thread.join().unwrap(); // this might take a while if the cache is cold
+ teardown();
+ let new_tab_event = received_screen_instructions
+ .lock()
+ .unwrap()
+ .iter()
+ .find_map(|i| {
+ if let ScreenInstruction::RenameTab(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", new_tab_event));
+}
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap
new file mode 100644
index 000000000..269986f12
--- /dev/null
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap
@@ -0,0 +1,13 @@
+---
+source: zellij-server/src/plugins/./unit/plugin_tests.rs
+assertion_line: 3789
+expression: "format!(\"{:#?}\", new_tab_event)"
+---
+Some(
+ ClosePane(
+ Plugin(
+ 1,
+ ),
+ None,
+ ),
+)
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap
new file mode 100644
index 000000000..778d07b9b
--- /dev/null
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap
@@ -0,0 +1,13 @@
+---
+source: zellij-server/src/plugins/./unit/plugin_tests.rs
+assertion_line: 3729
+expression: "format!(\"{:#?}\", new_tab_event)"
+---
+Some(
+ ClosePane(
+ Terminal(
+ 1,
+ ),
+ None,
+ ),
+)
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap
new file mode 100644
index 000000000..d830391ef
--- /dev/null
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap
@@ -0,0 +1,14 @@
+---
+source: zellij-server/src/plugins/./unit/plugin_tests.rs
+assertion_line: 3909
+expression: "format!(\"{:#?}\", new_tab_event)"
+---
+Some(
+ FocusPaneWithId(
+ Plugin(
+ 1,
+ ),
+