summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2024-02-29 16:26:25 +0100
committerGitHub <noreply@github.com>2024-02-29 16:26:25 +0100
commit896b09aa6f9190b4dc838314b028b63e0f2461b7 (patch)
tree80aeda55e00e51dfc3d0fd8b6b4f6e6bbf493efd
parentd5bedd0e83dfa531e922f89f9792d20384eb2dc3 (diff)
feat(plugins): allow specifying the cwd when switching sessions (#3172)
* feat(plugins): allow specifying the cwd when switching sessions * style(fmt): rustfmt
-rw-r--r--default-plugins/fixture-plugin-for-tests/src/main.rs8
-rw-r--r--default-plugins/session-manager/src/new_session_info.rs2
-rw-r--r--src/commands.rs3
-rw-r--r--zellij-server/src/plugins/unit/plugin_tests.rs81
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap3
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap25
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap3
-rw-r--r--zellij-server/src/plugins/zellij_exports.rs3
-rw-r--r--zellij-tile/src/shim.rs3
-rw-r--r--zellij-utils/assets/prost/api.plugin_command.rs2
-rw-r--r--zellij-utils/src/data.rs1
-rw-r--r--zellij-utils/src/input/layout.rs28
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto1
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs2
14 files changed, 160 insertions, 5 deletions
diff --git a/default-plugins/fixture-plugin-for-tests/src/main.rs b/default-plugins/fixture-plugin-for-tests/src/main.rs
index 0da45a2f4..cd4fb45a1 100644
--- a/default-plugins/fixture-plugin-for-tests/src/main.rs
+++ b/default-plugins/fixture-plugin-for-tests/src/main.rs
@@ -299,12 +299,20 @@ impl ZellijPlugin for State {
switch_session_with_layout(
Some("my_other_new_session"),
LayoutInfo::BuiltIn("compact".to_owned()),
+ None,
);
},
Key::Ctrl('8') => {
let mut file = std::fs::File::create("/host/hi-from-plugin.txt").unwrap();
file.write_all(b"Hi there!").unwrap();
},
+ Key::Ctrl('9') => {
+ switch_session_with_layout(
+ Some("my_other_new_session_with_cwd"),
+ LayoutInfo::BuiltIn("compact".to_owned()),
+ Some(std::path::PathBuf::from("/tmp")),
+ );
+ },
_ => {},
},
Event::CustomMessage(message, payload) => {
diff --git a/default-plugins/session-manager/src/new_session_info.rs b/default-plugins/session-manager/src/new_session_info.rs
index 6a2456f11..294f4fbc8 100644
--- a/default-plugins/session-manager/src/new_session_info.rs
+++ b/default-plugins/session-manager/src/new_session_info.rs
@@ -104,7 +104,7 @@ impl NewSessionInfo {
if new_session_name != current_session_name.as_ref().map(|s| s.as_str()) {
match new_session_layout {
Some(new_session_layout) => {
- switch_session_with_layout(new_session_name, new_session_layout)
+ switch_session_with_layout(new_session_name, new_session_layout, None)
},
None => {
switch_session(new_session_name);
diff --git a/src/commands.rs b/src/commands.rs
index 52dff211b..cde96b127 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -450,6 +450,9 @@ pub(crate) fn start_client(opts: CliArgs) {
// not want it to mix with the config of this session
let (new_layout, new_layout_config) = new_session_layout;
layout = new_layout;
+ if let Some(cwd) = reconnect_to_session.cwd.as_ref() {
+ layout.add_cwd_to_layout(cwd);
+ }
let mut new_config = config_without_layout.clone();
let _ = new_config.merge(new_layout_config.clone());
config = new_config;
diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs
index 8fa262474..65a3799ea 100644
--- a/zellij-server/src/plugins/unit/plugin_tests.rs
+++ b/zellij-server/src/plugins/unit/plugin_tests.rs
@@ -6319,6 +6319,87 @@ pub fn switch_session_with_layout_plugin_command() {
#[test]
#[ignore]
+pub fn switch_session_with_layout_and_cwd_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 cache_path = plugin_host_folder.join("permissions_test.kdl");
+ let (plugin_thread_sender, server_receiver, screen_receiver, teardown) =
+ create_plugin_thread_with_server_receiver(Some(plugin_host_folder));
+ let plugin_should_float = Some(false);
+ let plugin_title = Some("test_plugin".to_owned());
+ let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
+ configuration: Default::default(),
+ ..Default::default()
+ });
+ 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 = grant_permissions_and_log_actions_in_thread_naked_variant!(
+ received_screen_instructions,
+ ScreenInstruction::Exit,
+ screen_receiver,
+ 1,
+ &PermissionType::ChangeApplicationState,
+ cache_path,
+ plugin_thread_sender,
+ client_id
+ );
+ let received_server_instruction = Arc::new(Mutex::new(vec![]));
+ let server_thread = log_actions_in_thread!(
+ received_server_instruction,
+ ServerInstruction::SwitchSession,
+ server_receiver,
+ 1
+ );
+
+ let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
+ let _ = plugin_thread_sender.send(PluginInstruction::Load(
+ plugin_should_float,
+ false,
+ plugin_title,
+ run_plugin,
+ tab_index,
+ None,
+ client_id,
+ size,
+ None,
+ false,
+ ));
+ std::thread::sleep(std::time::Duration::from_millis(500));
+
+ let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
+ None,
+ Some(client_id),
+ Event::Key(Key::Ctrl('9')), // this triggers the enent in the fixture plugin
+ )]));
+ std::thread::sleep(std::time::Duration::from_millis(500));
+ teardown();
+ server_thread.join().unwrap(); // this might take a while if the cache is cold
+ let switch_session_event = received_server_instruction
+ .lock()
+ .unwrap()
+ .iter()
+ .rev()
+ .find_map(|i| {
+ if let ServerInstruction::SwitchSession(..) = i {
+ Some(i.clone())
+ } else {
+ None
+ }
+ })
+ .clone();
+ assert_snapshot!(format!("{:#?}", switch_session_event));
+}
+
+#[test]
+#[ignore]
pub fn disconnect_other_clients_plugins_command() {
let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
// destructor removes the directory
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
index f254f0398..db02121d7 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
-assertion_line: 6051
+assertion_line: 6236
expression: "format!(\"{:#?}\", switch_session_event)"
---
Some(
@@ -12,6 +12,7 @@ Some(
tab_position: None,
pane_id: None,
layout: None,
+ cwd: None,
},
1,
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap
new file mode 100644
index 000000000..16c19ce57
--- /dev/null
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap
@@ -0,0 +1,25 @@
+---
+source: zellij-server/src/plugins/./unit/plugin_tests.rs
+assertion_line: 6398
+expression: "format!(\"{:#?}\", switch_session_event)"
+---
+Some(
+ SwitchSession(
+ ConnectToSession {
+ name: Some(
+ "my_other_new_session_with_cwd",
+ ),
+ tab_position: None,
+ pane_id: None,
+ layout: Some(
+ BuiltIn(
+ "compact",
+ ),
+ ),
+ cwd: Some(
+ "/tmp",
+ ),
+ },
+ 1,
+ ),
+)
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
index 46f6819a5..1f2ff843f 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
@@ -1,6 +1,6 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
-assertion_line: 6131
+assertion_line: 6317
expression: "format!(\"{:#?}\", switch_session_event)"
---
Some(
@@ -16,6 +16,7 @@ Some(
"compact",
),
),
+ cwd: None,
},
1,
),
diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs
index 533d85f2f..2c95de42f 100644
--- a/zellij-server/src/plugins/zellij_exports.rs
+++ b/zellij-server/src/plugins/zellij_exports.rs
@@ -229,6 +229,7 @@ fn host_run_plugin_command(env: FunctionEnvMut<ForeignFunctionEnv>) {
connect_to_session.tab_position,
connect_to_session.pane_id,
connect_to_session.layout,
+ connect_to_session.cwd,
)?,
PluginCommand::DeleteDeadSession(session_name) => {
delete_dead_session(session_name)?
@@ -926,6 +927,7 @@ fn switch_session(
tab_position: Option<usize>,
pane_id: Option<(u32, bool)>,
layout: Option<LayoutInfo>,
+ cwd: Option<PathBuf>,
) -> Result<()> {
// pane_id is (id, is_plugin)
let err_context = || format!("Failed to switch session");
@@ -936,6 +938,7 @@ fn switch_session(
tab_position,
pane_id,
layout,
+ cwd,
};
env.plugin_env
.senders
diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs
index db3e84e39..064a53d85 100644
--- a/zellij-tile/src/shim.rs
+++ b/zellij-tile/src/shim.rs
@@ -660,10 +660,11 @@ pub fn switch_session(name: Option<&str>) {
}
/// Switch to a session with the given name, create one if no name is given
-pub fn switch_session_with_layout(name: Option<&str>, layout: LayoutInfo) {
+pub fn switch_session_with_layout(name: Option<&str>, layout: LayoutInfo, cwd: Option<PathBuf>) {
let plugin_command = PluginCommand::SwitchSession(ConnectToSession {
name: name.map(|n| n.to_string()),
layout: Some(layout),
+ cwd,
..Default::default()
});
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs
index 1ed8b3d32..44110ac83 100644
--- a/zellij-utils/assets/prost/api.plugin_command.rs
+++ b/zellij-utils/assets/prost/api.plugin_command.rs
@@ -183,6 +183,8 @@ pub struct SwitchSessionPayload {
pub pane_id_is_plugin: ::core::option::Option<bool>,
#[prost(message, optional, tag = "5")]
pub layout: ::core::option::Option<super::event::LayoutInfo>,
+ #[prost(string, optional, tag = "6")]
+ pub cwd: ::core::option::Option<::prost::alloc::string::String>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs
index 6e0dce94f..63ccccced 100644
--- a/zellij-utils/src/data.rs
+++ b/zellij-utils/src/data.rs
@@ -1095,6 +1095,7 @@ pub struct ConnectToSession {
pub tab_position: Option<usize>,
pub pane_id: Option<(u32, bool)>, // (id, is_plugin)
pub layout: Option<LayoutInfo>,
+ pub cwd: Option<PathBuf>,
}
impl ConnectToSession {
diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs
index 82da8cbf0..74242cff8 100644
--- a/zellij-utils/src/input/layout.rs
+++ b/zellij-utils/src/input/layout.rs
@@ -211,6 +211,16 @@ impl RunPluginOrAlias {
}
self
}
+ pub fn add_initial_cwd(&mut self, initial_cwd: &PathBuf) {
+ match self {
+ RunPluginOrAlias::RunPlugin(ref mut run_plugin) => {
+ run_plugin.initial_cwd = Some(initial_cwd.clone());
+ },
+ RunPluginOrAlias::Alias(ref mut alias) => {
+ alias.initial_cwd = Some(initial_cwd.clone());
+ },
+ }
+ }
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
@@ -305,7 +315,9 @@ impl Run {
Run::Cwd(path) => {
*path = cwd.join(&path);
},
- _ => {}, // plugins aren't yet supported
+ Run::Plugin(run_plugin_or_alias) => {
+ run_plugin_or_alias.add_initial_cwd(&cwd);
+ },
}
}
pub fn add_args(&mut self, args: Option<Vec<String>>) {
@@ -1365,6 +1377,20 @@ impl Layout {
}
}
}
+ pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
+ for (_, tiled_pane_layout, floating_panes) in self.tabs.iter_mut() {
+ tiled_pane_layout.add_cwd_to_layout(&cwd);
+ for floating_pane in floating_panes {
+ floating_pane.add_cwd_to_layout(&cwd);
+ }
+ }
+ if let Some((tiled_pane_layout, floating_panes)) = self.template.as_mut() {
+ tiled_pane_layout.add_cwd_to_layout(&cwd);
+ for floating_pane in floating_panes {
+ floating_pane.add_cwd_to_layout(&cwd);
+ }
+ }
+ }
}
fn split_space(
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
index d85afeed6..eecae43b8 100644
--- a/zellij-utils/src/plugin_api/plugin_command.proto
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -194,6 +194,7 @@ message SwitchSessionPayload {
optional uint32 pane_id = 3;
optional bool pane_id_is_plugin = 4;
optional event.LayoutInfo layout = 5;
+ optional string cwd = 6;
}
message RequestPluginPermissionPayload {
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
index 6ce7422e6..ab9d52940 100644
--- a/zellij-utils/src/plugin_api/plugin_command.rs
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -689,6 +689,7 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
tab_position: payload.tab_position.map(|p| p as usize),
pane_id,
layout: payload.layout.and_then(|l| l.try_into().ok()),
+ cwd: payload.cwd.map(|c| PathBuf::from(c)),
}))
},
_ => Err("Mismatched payload for SwitchSession"),
@@ -1222,6 +1223,7 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
pane_id: switch_to_session.pane_id.map(|p| p.0),
pane_id_is_plugin: switch_to_session.pane_id.map(|p| p.1),
layout: switch_to_session.layout.and_then(|l| l.try_into().ok()),
+ cwd: switch_to_session.cwd.map(|c| c.display().to_string()),
})),
}),
PluginCommand::OpenTerminalInPlace(cwd) => Ok(ProtobufPluginCommand {