aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2024-12-01 11:06:44 +0100
committerGitHub <noreply@github.com>2024-12-01 11:06:44 +0100
commit0c21eae6646d511944a85121433b9443a96c73aa (patch)
treea5a091a4df73920dfbb03e2abfb1cb770ffbf44b
parentdocs(changelog): ui component padding (diff)
downloadsl0ppij-0c21eae6646d511944a85121433b9443a96c73aa.tar.gz
sl0ppij-0c21eae6646d511944a85121433b9443a96c73aa.tar.xz
sl0ppij-0c21eae6646d511944a85121433b9443a96c73aa.zip
feat(plugins): allow changing the plugin's `/host` folder (under a new permission) (#3827)
* working without notifying plugins * permissions and events * cleanups and formatting * style(fmt): rustfmt
-rw-r--r--zellij-server/src/plugins/mod.rs7
-rw-r--r--zellij-server/src/plugins/plugin_loader.rs85
-rw-r--r--zellij-server/src/plugins/wasm_bridge.rs104
-rw-r--r--zellij-server/src/plugins/zellij_exports.rs14
-rw-r--r--zellij-tile/src/shim.rs7
-rw-r--r--zellij-utils/assets/prost/api.event.rs24
-rw-r--r--zellij-utils/assets/prost/api.plugin_command.rs13
-rw-r--r--zellij-utils/assets/prost/api.plugin_permission.rs3
-rw-r--r--zellij-utils/src/data.rs5
-rw-r--r--zellij-utils/src/errors.rs1
-rw-r--r--zellij-utils/src/plugin_api/event.proto12
-rw-r--r--zellij-utils/src/plugin_api/event.rs34
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto6
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs20
-rw-r--r--zellij-utils/src/plugin_api/plugin_permission.proto1
-rw-r--r--zellij-utils/src/plugin_api/plugin_permission.rs2
16 files changed, 301 insertions, 37 deletions
diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs
index de6ae028..fa1fabce 100644
--- a/zellij-server/src/plugins/mod.rs
+++ b/zellij-server/src/plugins/mod.rs
@@ -158,6 +158,7 @@ pub enum PluginInstruction {
},
WatchFilesystem,
ListClientsToPlugin(SessionLayoutMetadata, PluginId, ClientId),
+ ChangePluginHostDir(PathBuf, PluginId, ClientId),
Exit,
}
@@ -204,6 +205,7 @@ impl From<&PluginInstruction> for PluginContext {
PluginContext::FailedToWriteConfigToDisk
},
PluginInstruction::ListClientsToPlugin(..) => PluginContext::ListClientsToPlugin,
+ PluginInstruction::ChangePluginHostDir(..) => PluginContext::ChangePluginHostDir,
}
}
}
@@ -886,6 +888,11 @@ pub(crate) fn plugin_thread_main(
PluginInstruction::WatchFilesystem => {
wasm_bridge.start_fs_watcher_if_not_started();
},
+ PluginInstruction::ChangePluginHostDir(new_host_folder, plugin_id, client_id) => {
+ wasm_bridge
+ .change_plugin_host_dir(new_host_folder, plugin_id, client_id)
+ .non_fatal();
+ },
PluginInstruction::Exit => {
break;
},
diff --git a/zellij-server/src/plugins/plugin_loader.rs b/zellij-server/src/plugins/plugin_loader.rs
index 760824d7..56ae6786 100644
--- a/zellij-server/src/plugins/plugin_loader.rs
+++ b/zellij-server/src/plugins/plugin_loader.rs
@@ -14,7 +14,7 @@ use std::{
};
use url::Url;
use wasmtime::{Engine, Instance, Linker, Module, Store};
-use wasmtime_wasi::{DirPerms, FilePerms, WasiCtxBuilder};
+use wasmtime_wasi::{preview1::WasiP1Ctx, DirPerms, FilePerms, WasiCtxBuilder};
use zellij_utils::consts::ZELLIJ_PLUGIN_ARTIFACT_DIR;
use zellij_utils::prost::Message;
@@ -64,7 +64,7 @@ pub struct PluginLoader<'a> {
size: Size,
wasm_blob_on_hd: Option<(Vec<u8>, PathBuf)>,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -85,7 +85,7 @@ impl<'a> PluginLoader<'a> {
connected_clients: Arc<Mutex<Vec<ClientId>>>,
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -110,7 +110,7 @@ impl<'a> PluginLoader<'a> {
engine,
&plugin_dir,
path_to_default_shell,
- Some(zellij_cwd),
+ Some(plugin_cwd),
capabilities,
client_attributes,
default_shell,
@@ -145,7 +145,7 @@ impl<'a> PluginLoader<'a> {
connected_clients: Arc<Mutex<Vec<ClientId>>>,
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -168,7 +168,7 @@ impl<'a> PluginLoader<'a> {
tab_index,
size,
path_to_default_shell,
- zellij_cwd,
+ plugin_cwd,
capabilities,
client_attributes,
default_shell,
@@ -222,7 +222,7 @@ impl<'a> PluginLoader<'a> {
connected_clients: Arc<Mutex<Vec<ClientId>>>,
loading_indication: &mut LoadingIndication,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -246,7 +246,7 @@ impl<'a> PluginLoader<'a> {
engine.clone(),
&plugin_dir,
path_to_default_shell.clone(),
- zellij_cwd.clone(),
+ plugin_cwd.clone(),
capabilities.clone(),
client_attributes.clone(),
default_shell.clone(),
@@ -333,7 +333,7 @@ impl<'a> PluginLoader<'a> {
tab_index: Option<usize>,
size: Size,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -366,7 +366,7 @@ impl<'a> PluginLoader<'a> {
size,
wasm_blob_on_hd: None,
path_to_default_shell,
- zellij_cwd,
+ plugin_cwd,
capabilities,
client_attributes,
default_shell,
@@ -412,7 +412,7 @@ impl<'a> PluginLoader<'a> {
// prefer the explicitly given cwd, otherwise copy it from the running plugin
// (when reloading a plugin, we want to copy it, when starting a new plugin instance from
// meomory, we want to reset it)
- let zellij_cwd = cwd.unwrap_or_else(|| running_plugin.store.data().plugin_cwd.clone());
+ let plugin_cwd = cwd.unwrap_or_else(|| running_plugin.store.data().plugin_cwd.clone());
loading_indication.set_name(running_plugin.store.data().name());
PluginLoader::new(
plugin_cache,
@@ -426,7 +426,7 @@ impl<'a> PluginLoader<'a> {
tab_index,
size,
path_to_default_shell,
- zellij_cwd,
+ plugin_cwd,
capabilities,
client_attributes,
default_shell,
@@ -446,7 +446,7 @@ impl<'a> PluginLoader<'a> {
engine: Engine,
plugin_dir: &'a PathBuf,
path_to_default_shell: PathBuf,
- zellij_cwd: PathBuf,
+ plugin_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>,
@@ -483,7 +483,7 @@ impl<'a> PluginLoader<'a> {
tab_index,
size,
path_to_default_shell,
- zellij_cwd,
+ plugin_cwd,
capabilities,
client_attributes,
default_shell,
@@ -736,7 +736,7 @@ impl<'a> PluginLoader<'a> {
self.engine.clone(),
&self.plugin_dir,
self.path_to_default_shell.clone(),
- self.zellij_cwd.clone(),
+ self.plugin_cwd.clone(),
self.capabilities.clone(),
self.client_attributes.clone(),
self.default_shell.clone(),
@@ -784,18 +784,22 @@ impl<'a> PluginLoader<'a> {
},
}
}
- fn create_plugin_instance_env(&self, module: &Module) -> Result<(Store<PluginEnv>, Instance)> {
- let err_context = || {
- format!(
- "Failed to create instance, plugin env and subscriptions for plugin {}",
- self.plugin_id
- )
- };
+ pub fn create_wasi_ctx(
+ host_dir: &PathBuf,
+ data_dir: &PathBuf,
+ cache_dir: &PathBuf,
+ tmp_dir: &PathBuf,
+ plugin_url: &String,
+ plugin_id: PluginId,
+ stdin_pipe: Arc<Mutex<VecDeque<u8>>>,
+ stdout_pipe: Arc<Mutex<VecDeque<u8>>>,
+ ) -> Result<WasiP1Ctx> {
+ let err_context = || format!("Failed to create wasi_ctx");
let dirs = vec![
- ("/host".to_owned(), self.zellij_cwd.clone()),
- ("/data".to_owned(), self.plugin_own_data_dir.clone()),
- ("/cache".to_owned(), self.plugin_own_cache_dir.clone()),
- ("/tmp".to_owned(), ZELLIJ_TMP_DIR.clone()),
+ ("/host".to_owned(), host_dir.clone()),
+ ("/data".to_owned(), data_dir.clone()),
+ ("/cache".to_owned(), cache_dir.clone()),
+ ("/tmp".to_owned(), tmp_dir.clone()),
];
let dirs = dirs.into_iter().filter(|(_dir_name, dir)| {
// note that this does not protect against TOCTOU errors
@@ -812,16 +816,35 @@ impl<'a> PluginLoader<'a> {
.preopened_dir(host_path, guest_path, DirPerms::all(), FilePerms::all())
.with_context(err_context)?;
}
- let stdin_pipe = Arc::new(Mutex::new(VecDeque::new()));
- let stdout_pipe = Arc::new(Mutex::new(VecDeque::new()));
wasi_ctx_builder
.stdin(VecDequeInputStream(stdin_pipe.clone()))
.stdout(WriteOutputStream(stdout_pipe.clone()))
.stderr(WriteOutputStream(Arc::new(Mutex::new(LoggingPipe::new(
- &self.plugin.location.to_string(),
- self.plugin_id,
+ plugin_url, plugin_id,
)))));
let wasi_ctx = wasi_ctx_builder.build_p1();
+ Ok(wasi_ctx)
+ }
+ fn create_plugin_instance_env(&self, module: &Module) -> Result<(Store<PluginEnv>, Instance)> {
+ let err_context = || {
+ format!(
+ "Failed to create instance, plugin env and subscriptions for plugin {}",
+ self.plugin_id
+ )
+ };
+ let stdin_pipe = Arc::new(Mutex::new(VecDeque::new()));
+ let stdout_pipe = Arc::new(Mutex::new(VecDeque::new()));
+
+ let wasi_ctx = PluginLoader::create_wasi_ctx(
+ &self.plugin_cwd,
+ &self.plugin_own_data_dir,
+ &self.plugin_own_cache_dir,
+ &ZELLIJ_TMP_DIR,
+ &self.plugin.location.to_string(),
+ self.plugin_id,
+ stdin_pipe.clone(),
+ stdout_pipe.clone(),
+ )?;
let plugin = self.plugin.clone();
let plugin_env = PluginEnv {
plugin_id: self.plugin_id,
@@ -838,7 +861,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: self.client_attributes.clone(),
default_shell: self.default_shell.clone(),
default_layout: self.default_layout.clone(),
- plugin_cwd: self.zellij_cwd.clone(),
+ plugin_cwd: self.plugin_cwd.clone(),
input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())),
input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())),
layout_dir: self.layout_dir.clone(),
diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs
index eceed202..6096cbd6 100644
--- a/zellij-server/src/plugins/wasm_bridge.rs
+++ b/zellij-server/src/plugins/wasm_bridge.rs
@@ -4,6 +4,7 @@ use crate::plugins::pipes::{
};
use crate::plugins::plugin_loader::PluginLoader;
use crate::plugins::plugin_map::{AtomicEvent, PluginEnv, PluginMap, RunningPlugin, Subscriptions};
+
use crate::plugins::plugin_worker::MessageToWorker;
use crate::plugins::watch_filesystem::watch_filesystem;
use crate::plugins::zellij_exports::{wasi_read_string, wasi_write_object};
@@ -18,7 +19,7 @@ use std::{
use wasmtime::{Engine, Module};
use zellij_utils::async_channel::Sender;
use zellij_utils::async_std::task::{self, JoinHandle};
-use zellij_utils::consts::ZELLIJ_CACHE_DIR;
+use zellij_utils::consts::{ZELLIJ_CACHE_DIR, ZELLIJ_TMP_DIR};
use zellij_utils::data::{InputMode, PermissionStatus, PermissionType, PipeMessage, PipeSource};
use zellij_utils::downloader::Downloader;
use zellij_utils::input::keybinds::Keybinds;
@@ -736,6 +737,107 @@ impl WasmBridge {
}
Ok(())
}
+ pub fn change_plugin_host_dir(
+ &mut self,
+ new_host_dir: PathBuf,
+ plugin_id_to_update: PluginId,
+ client_id_to_update: ClientId,
+ ) -> Result<()> {
+ let plugins_to_change: Vec<(
+ PluginId,
+ ClientId,
+ Arc<Mutex<RunningPlugin>>,
+ Arc<Mutex<Subscriptions>>,
+ )> = self
+ .plugin_map
+ .lock()
+ .unwrap()
+ .running_plugins_and_subscriptions()
+ .iter()
+ .cloned()
+ .filter(|(plugin_id, _client_id, _running_plugin, _subscriptions)| {
+ // TODO: cache this somehow in this case...
+ !&self
+ .cached_events_for_pending_plugins
+ .contains_key(&plugin_id)
+ })
+ .collect();
+ task::spawn({
+ let senders = self.senders.clone();
+ async move {
+ match new_host_dir.try_exists() {
+ Ok(false) => {
+ log::error!(
+ "Failed to change folder to {},: folder does not exist",
+ new_host_dir.display()
+ );
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
+ Some(plugin_id_to_update),
+ Some(client_id_to_update),
+ Event::FailedToChangeHostFolder(Some(format!(
+ "Folder {} does not exist",
+ new_host_dir.display()
+ ))),
+ )]));
+ return;
+ },
+ Err(e) => {
+ log::error!(
+ "Failed to change folder to {},: {}",
+ new_host_dir.display(),
+ e
+ );
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
+ Some(plugin_id_to_update),
+ Some(client_id_to_update),
+ Event::FailedToChangeHostFolder(Some(e.to_string())),
+ )]));
+ return;
+ },
+ _ => {},
+ }
+ for (plugin_id, client_id, running_plugin, _subscriptions) in &plugins_to_change {
+ if plugin_id == &plugin_id_to_update && client_id == &client_id_to_update {
+ let mut running_plugin = running_plugin.lock().unwrap();
+ let plugin_env = running_plugin.store.data_mut();
+ let stdin_pipe = plugin_env.stdin_pipe.clone();
+ let stdout_pipe = plugin_env.stdout_pipe.clone();
+ let wasi_ctx = PluginLoader::create_wasi_ctx(
+ &new_host_dir,
+ &plugin_env.plugin_own_data_dir,
+ &plugin_env.plugin_own_cache_dir,
+ &ZELLIJ_TMP_DIR,
+ &plugin_env.plugin.location.to_string(),
+ plugin_env.plugin_id,
+ stdin_pipe.clone(),
+ stdout_pipe.clone(),
+ );
+ match wasi_ctx {
+ Ok(wasi_ctx) => {
+ drop(std::mem::replace(&mut plugin_env.wasi_ctx, wasi_ctx));
+ plugin_env.plugin_cwd = new_host_dir.clone();
+
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
+ Some(*plugin_id),
+ Some(*client_id),
+ Event::HostFolderChanged(new_host_dir.clone()),
+ )]));
+ },
+ Err(e) => {
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
+ Some(*plugin_id),
+ Some(*client_id),
+ Event::FailedToChangeHostFolder(Some(e.to_string())),
+ )]));
+ log::error!("Failed to create wasi ctx: {}", e);
+ },
+ }
+ }
+ }
+ }
+ });
+ Ok(())
+ }
pub fn pipe_messages(
&mut self,
mut messages: Vec<(Option<PluginId>, Option<ClientId>, PipeMessage)>,
diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs
index d308689b..aadf2827 100644
--- a/zellij-server/src/plugins/zellij_exports.rs
+++ b/zellij-server/src/plugins/zellij_exports.rs
@@ -352,6 +352,9 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
write_config_to_disk,
} => rebind_keys(env, keys_to_rebind, keys_to_unbind, write_config_to_disk)?,
PluginCommand::ListClients => list_clients(env),
+ PluginCommand::ChangeHostFolder(new_host_folder) => {
+ change_host_folder(env, new_host_folder)
+ },
},
(PermissionStatus::Denied, permission) => {
log::error!(
@@ -1484,6 +1487,16 @@ fn list_clients(env: &PluginEnv) {
});
}
+fn change_host_folder(env: &PluginEnv, new_host_folder: PathBuf) {
+ let _ = env.senders.to_plugin.as_ref().map(|sender| {
+ sender.send(PluginInstruction::ChangePluginHostDir(
+ new_host_folder,
+ env.plugin_id,
+ env.client_id,
+ ))
+ });
+}
+
fn scan_host_folder(env: &PluginEnv, folder_to_scan: PathBuf) {
if !folder_to_scan.starts_with("/host") {
log::error!(
@@ -1913,6 +1926,7 @@ fn check_command_permission(
PluginCommand::RebindKeys { .. } | PluginCommand::Reconfigure(..) => {
PermissionType::Reconfigure
},
+ PluginCommand::ChangeHostFolder(..) => PermissionType::FullHdAccess,
_ => return (PermissionStatus::Granted, None),
};
diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs
index bc1b4844..1e116f13 100644
--- a/zellij-tile/src/shim.rs
+++ b/zellij-tile/src/shim.rs
@@ -1128,6 +1128,13 @@ pub fn rebind_keys(
unsafe { host_run_plugin_command() };
}
+pub fn change_host_folder(new_host_folder: PathBuf) {
+ let plugin_command = PluginCommand::ChangeHostFolder(new_host_folder);
+ let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
+ object_to_stdout(&protobuf_plugin_command.encode_to_vec());
+ unsafe { host_run_plugin_command() };
+}
+
// Utility Functions
#[allow(unused)]
diff --git a/zellij-utils/assets/prost/api.event.rs b/zellij-utils/assets/prost/api.event.rs
index 02d709e6..b6572a41 100644
--- a/zellij-utils/assets/prost/api.event.rs
+++ b/zellij-utils/assets/prost/api.event.rs
@@ -11,7 +11,7 @@ pub struct Event {
pub name: i32,
#[prost(
oneof = "event::Payload",
- tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23"
+ tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25"
)]
pub payload: ::core::option::Option<event::Payload>,
}
@@ -64,10 +64,26 @@ pub mod event {
FailedToWriteConfigToDiskPayload(super::FailedToWriteConfigToDiskPayload),
#[prost(message, tag = "23")]
ListClientsPayload(super::ListClientsPayload),
+ #[prost(message, tag = "24")]
+ HostFolderChangedPayload(super::HostFolderChangedPayload),
+ #[prost(message, tag = "25")]
+ FailedToChangeHostFolderPayload(super::FailedToChangeHostFolderPayload),
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FailedToChangeHostFolderPayload {
+ #[prost(string, optional, tag = "1")]
+ pub error_message: ::core::option::Option<::prost::alloc::string::String>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct HostFolderChangedPayload {
+ #[prost(string, tag = "1")]
+ pub new_host_folder_path: ::prost::alloc::string::String,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListClientsPayload {
#[prost(message, repeated, tag = "1")]
pub client_info: ::prost::alloc::vec::Vec<ClientInfo>,
@@ -468,6 +484,8 @@ pub enum EventType {
CommandPaneReRun = 24,
FailedToWriteConfigToDisk = 25,
ListClients = 26,
+ HostFolderChanged = 27,
+ FailedToChangeHostFolder = 28,
}
impl EventType {
/// String value of the enum field names used in the ProtoBuf definition.
@@ -503,6 +521,8 @@ impl EventType {
EventType::CommandPaneReRun => "CommandPaneReRun",
EventType::FailedToWriteConfigToDisk => "FailedToWriteConfigToDisk",
EventType::ListClients => "ListClients",
+ EventType::HostFolderChanged => "HostFolderChanged",
+ EventType::FailedToChangeHostFolder => "FailedToChangeHostFolder",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
@@ -535,6 +555,8 @@ impl EventType {
"CommandPaneReRun" => Some(Self::CommandPaneReRun),
"FailedToWriteConfigToDisk" => Some(Self::FailedToWriteConfigToDisk),
"ListClients" => Some(Self::ListClients),
+ "HostFolderChanged" => Some(Self::HostFolderChanged),
+ "FailedToChangeHostFolder" => Some(Self::FailedToChangeHostFolder),
_ => None,
}
}
diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs
index 8b3b6752..d4604c98 100644
--- a/zellij-utils/assets/prost/api.plugin_command.rs
+++ b/zellij-utils/assets/prost/api.plugin_command.rs
@@ -5,7 +5,7 @@ pub struct PluginCommand {
pub name: i32,
#[prost(
oneof = "plugin_command::Payload",
- tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88"
+ tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89"
)]
pub payload: ::core::option::Option<plugin_command::Payload>,
}
@@ -174,10 +174,18 @@ pub mod plugin_command {
LoadNewPluginPayload(super::LoadNewPluginPayload),
#[prost(message, tag = "88")]
RebindKeysPayload(super::RebindKeysPayload),
+ #[prost(message, tag = "89")]
+ ChangeHostFolderPayload(super::ChangeHostFolderPayload),
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ChangeHostFolderPayload {
+ #[prost(string, tag = "1")]
+ pub new_host_folder: ::prost::alloc::string::String,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RebindKeysPayload {
#[prost(message, repeated, tag = "1")]
pub keys_to_rebind: ::prost::alloc::vec::Vec<KeyToRebind>,
@@ -716,6 +724,7 @@ pub enum CommandName {
LoadNewPlugin = 111,
RebindKeys = 112,
ListClients = 113,
+ ChangeHostFolder = 114,
}
impl CommandName {
/// String value of the enum field names used in the ProtoBuf definition.
@@ -840,6 +849,7 @@ impl CommandName {
CommandName::LoadNewPlugin => "LoadNewPlugin",
CommandName::RebindKeys => "RebindKeys",
CommandName::ListClients => "ListClients",
+ CommandName::ChangeHostFolder => "ChangeHostFolder",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
@@ -961,6 +971,7 @@ impl CommandName {
"LoadNewPlugin" => Some(Self::LoadNewPlugin),
"RebindKeys" => Some(Self::RebindKeys),
"ListClients" => Some(Self::ListClients),
+ "ChangeHostFolder" => Some(Self::ChangeHostFolder),
_ => None,
}
}
diff --git a/zellij-utils/assets/prost/api.plugin_permission.rs b/zellij-utils/assets/prost/api.plugin_permission.rs
index 013732d9..54b7de32 100644
--- a/zellij-utils/assets/prost/api.plugin_permission.rs
+++ b/zellij-utils/assets/prost/api.plugin_permission.rs
@@ -11,6 +11,7 @@ pub enum PermissionType {
ReadCliPipes = 7,
MessageAndLaunchOtherPlugins = 8,
Reconfigure = 9,
+ FullHdAccess = 10,
}
impl PermissionType {
/// String value of the enum field names used in the ProtoBuf definition.
@@ -31,6 +32,7 @@ impl PermissionType {
"MessageAndLaunchOtherPlugins"
}
PermissionType::Reconfigure => "Reconfigure",
+ PermissionType::FullHdAccess => "FullHdAccess",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
@@ -46,6 +48,7 @@ impl PermissionType {
"ReadCliPipes" => Some(Self::ReadCliPipes),
"MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins),
"Reconfigure" => Some(Self::Reconfigure),
+ "FullHdAccess" => Some(Self::FullHdAccess),
_ => None,
}
}
diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs
index 94b74c4d..1d0da685 100644
--- a/zellij-utils/src/data.rs
+++ b/zellij-utils/src/data.rs
@@ -912,6 +912,8 @@ pub enum Event {
CommandPaneReRun(u32, Context), // u32 - terminal_pane_id, Option<i32> -
FailedToWriteConfigToDisk(Option<String>), // String -> the file path we failed to write
ListClients(Vec<ClientInfo>),
+ HostFolderChanged(PathBuf), // PathBuf -> new host folder
+ FailedToChangeHostFolder(Option<String>), // String -> the error we got when changing
}
#[derive(
@@ -942,6 +944,7 @@ pub enum Permission {
ReadCliPipes,
MessageAndLaunchOtherPlugins,
Reconfigure,
+ FullHdAccess,
}
impl PermissionType {
@@ -963,6 +966,7 @@ impl PermissionType {
"Send messages to and launch other plugins".to_owned()
},
PermissionType::Reconfigure => "Change Zellij runtime configuration".to_owned(),
+ PermissionType::FullHdAccess => "Full access to the hard-drive".to_owned(),
}
}
}
@@ -1893,4 +1897,5 @@ pub enum PluginCommand {
write_config_to_disk: bool,
},
ListClients,
+ ChangeHostFolder(PathBuf),
}
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index 43deff3b..ffabec26 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -435,6 +435,7 @@ pub enum PluginContext {
Reconfigure,
FailedToWriteConfigToDisk,
ListClientsToPlugin,
+ ChangePluginHostDir,
}
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto
index 607ba448..be09507e 100644
--- a/zellij-utils/src/plugin_api/event.proto
+++ b/zellij-utils/src/plugin_api/event.proto
@@ -50,6 +50,8 @@ enum EventType {
CommandPaneReRun = 24;
FailedToWriteConfigToDisk = 25;
ListClients = 26;
+ HostFolderChanged = 27;
+ FailedToChangeHostFolder = 28;
}
message EventNameList {
@@ -81,9 +83,19 @@ message Event {
CommandPaneReRunPayload command_pane_rerun_payload = 21;
FailedToWriteConfigToDiskPayload failed_to_write_config_to_disk_payload = 22;
ListClientsPayload list_clients_payload = 23;
+ HostFolderChangedPayload host_folder_changed_payload = 24;
+ FailedToChangeHostFolderPayload failed_to_change_host_folder_payload = 25;
}
}
+message FailedToChangeHostFolderPayload {
+ optional string error_message = 1;
+}
+
+message HostFolderChangedPayload {
+ string new_host_folder_path = 1;
+}
+
message ListClientsPayload {
repeated ClientInfo client_info = 1;
}
diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs
index d78f5567..b1ab0e8e 100644
--- a/zellij-utils/src/plugin_api/event.rs
+++ b/zellij-utils/src/plugin_api/event.rs
@@ -333,6 +333,22 @@ impl TryFrom<ProtobufEvent> for Event {
},
_ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
},
+ Some(ProtobufEventType::HostFolderChanged) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::HostFolderChangedPayload(
+ host_folder_changed_payload,
+ )) => Ok(Event::HostFolderChanged(PathBuf::from(
+ host_folder_changed_payload.new_host_folder_path,
+ ))),
+ _ => Err("Malformed payload for the HostFolderChanged Event"),
+ },
+ Some(ProtobufEventType::FailedToChangeHostFolder) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::FailedToChangeHostFolderPayload(
+ failed_to_change_host_folder_payload,
+ )) => Ok(Event::FailedToChangeHostFolder(
+ failed_to_change_host_folder_payload.error_message,
+ )),
+ _ => Err("Malformed payload for the FailedToChangeHostFolder Event"),
+ },
None => Err("Unknown Protobuf Event"),
}
}
@@ -683,6 +699,20 @@ impl TryFrom<Event> for ProtobufEvent {
.collect(),
})),
}),
+ Event::HostFolderChanged(new_host_folder_path) => Ok(ProtobufEvent {
+ name: ProtobufEventType::HostFolderChanged as i32,
+ payload: Some(event::Payload::HostFolderChangedPayload(
+ HostFolderChangedPayload {
+ new_host_folder_path: new_host_folder_path.display().to_string(),
+ },
+ )),
+ }),
+ Event::FailedToChangeHostFolder(error_message) => Ok(ProtobufEvent {
+ name: ProtobufEventType::FailedToChangeHostFolder as i32,
+ payload: Some(event::Payload::FailedToChangeHostFolderPayload(
+ FailedToChangeHostFolderPayload { error_message },
+ )),
+ }),
}
}
}
@@ -1228,6 +1258,8 @@ impl TryFrom<ProtobufEventType> for EventType {
ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk,
ProtobufEventType::ListClients => EventType::ListClients,
+ ProtobufEventType::HostFolderChanged => EventType::HostFolderChanged,
+ ProtobufEventType::FailedToChangeHostFolder => EventType::FailedToChangeHostFolder,
})
}
}
@@ -1263,6 +1295,8 @@ impl TryFrom<EventType> for ProtobufEventType {
EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk,
EventType::ListClients => ProtobufEventType::ListClients,
+ EventType::HostFolderChanged => ProtobufEventType::HostFolderChanged,
+ EventType::FailedToChangeHostFolder => ProtobufEventType::FailedToChangeHostFolder,
})
}
}
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
index 5b58de14..4cc5c10c 100644
--- a/zellij-utils/src/plugin_api/plugin_command.proto
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -127,6 +127,7 @@ enum CommandName {
LoadNewPlugin = 111;
RebindKeys = 112;
ListClients = 113;
+ ChangeHostFolder = 114;
}
message PluginCommand {
@@ -210,9 +211,14 @@ message PluginCommand {
ReloadPluginPayload reload_plugin_payload = 86;
LoadNewPluginPayload load_new_plugin_payload = 87;
RebindKeysPayload rebind_keys_payload = 88;
+ ChangeHostFolderPayload change_host_folder_payload = 89;
}
}
+message ChangeHostFolderPayload {
+ string new_host_folder = 1;
+}
+
message RebindKeysPayload {
repeated KeyToRebind keys_to_rebind = 1;
repeated KeyToUnbind keys_to_unbind = 2;
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
index 06687971..4317a02e 100644
--- a/zellij-utils/src/plugin_api/plugin_command.rs
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -4,9 +4,9 @@ pub use super::generated_api::api::{
input_mode::InputMode as ProtobufInputMode,
plugin_command::{
plugin_command::Payload, BreakPanesToNewTabPayload, BreakPanesToTabWithIndexPayload,
- ClearScreenForPaneIdPayload, CliPipeOutputPayload, CloseTabWithIndexPayload, CommandName,
- ContextItem, EditScrollbackForPaneWithIdPayload, EnvVariable, ExecCmdPayload,
- FixedOrPercent as ProtobufFixedOrPercent,
+ ChangeHostFolderPayload, ClearScreenForPaneIdPayload, CliPipeOutputPayload,
+ CloseTabWithIndexPayload, CommandName, ContextItem, EditScrollbackForPaneWithIdPayload,
+ EnvVariable, ExecCmdPayload, FixedOrPercent as ProtobufFixedOrPercent,
FixedOrPercentValue as ProtobufFixedOrPercentValue,
FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload,
HttpVerb as ProtobufHttpVerb, IdAndNewName, KeyToRebind, KeyToUnbind, KillSessionsPayload,
@@ -1303,6 +1303,14 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
Some(_) => Err("ListClients should have no payload, found a payload"),
None => Ok(PluginCommand::ListClients),
},
+ Some(CommandName::ChangeHostFolder) => match protobuf_plugin_command.payload {
+ Some(Payload::ChangeHostFolderPayload(change_host_folder_payload)) => {
+ Ok(PluginCommand::ChangeHostFolder(PathBuf::from(
+ change_host_folder_payload.new_host_folder,
+ )))
+ },
+ _ => Err("Mismatched payload for ChangeHostFolder"),
+ },
None => Err("Unrecognized plugin command"),
}
}
@@ -2130,6 +2138,12 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
name: CommandName::ListClients as i32,
payload: None,
}),
+ PluginCommand::ChangeHostFolder(new_host_folder) => Ok(ProtobufPluginCommand {
+ name: CommandName::ChangeHostFolder as i32,
+ payload: Some(Payload::ChangeHostFolderPayload(ChangeHostFolderPayload {
+ new_host_folder: new_host_folder.display().to_string(), // TODO: not accurate?
+ })),
+ }),
}
}
}
diff --git a/zellij-utils/src/plugin_api/plugin_permission.proto b/zellij-utils/src/plugin_api/plugin_permission.proto
index 399ebba5..4f1f90f9 100644
--- a/zellij-utils/src/plugin_api/plugin_permission.proto
+++ b/zellij-utils/src/plugin_api/plugin_permission.proto
@@ -13,4 +13,5 @@ enum PermissionType {
ReadCliPipes = 7;
MessageAndLaunchOtherPlugins = 8;
Reconfigure = 9;
+ FullHdAccess = 10;
}
diff --git a/zellij-utils/src/plugin_api/plugin_permission.rs b/zellij-utils/src/plugin_api/plugin_permission.rs
index 5ea70157..5b6a831f 100644
--- a/zellij-utils/src/plugin_api/plugin_permission.rs
+++ b/zellij-utils/src/plugin_api/plugin_permission.rs
@@ -25,6 +25,7 @@ impl TryFrom<ProtobufPermissionType> for PermissionType {
Ok(PermissionType::MessageAndLaunchOtherPlugins)
},
ProtobufPermissionType::Reconfigure => Ok(PermissionType::Reconfigure),
+ ProtobufPermissionType::FullHdAccess => Ok(PermissionType::FullHdAccess),
}
}
}
@@ -51,6 +52,7 @@ impl TryFrom<PermissionType> for ProtobufPermissionType {
Ok(ProtobufPermissionType::MessageAndLaunchOtherPlugins)
},
PermissionType::Reconfigure => Ok(ProtobufPermissionType::Reconfigure),
+ PermissionType::FullHdAccess => Ok(ProtobufPermissionType::FullHdAccess),
}
}
}