feat(plugins): add api to dump the current session layout to a plugin (#3227)
This commit is contained in:
parent
b24dd87b80
commit
2eaa50cc44
10 changed files with 95 additions and 2 deletions
|
|
@ -37,6 +37,7 @@ use zellij_utils::{
|
|||
},
|
||||
ipc::ClientAttributes,
|
||||
pane_size::Size,
|
||||
session_serialization,
|
||||
};
|
||||
|
||||
pub type PluginId = u32;
|
||||
|
|
@ -104,6 +105,7 @@ pub enum PluginInstruction {
|
|||
Option<PathBuf>,
|
||||
),
|
||||
DumpLayout(SessionLayoutMetadata, ClientId),
|
||||
DumpLayoutToPlugin(SessionLayoutMetadata, PluginId),
|
||||
LogLayoutToHd(SessionLayoutMetadata),
|
||||
CliPipe {
|
||||
pipe_id: String,
|
||||
|
|
@ -178,6 +180,7 @@ impl From<&PluginInstruction> for PluginContext {
|
|||
PluginInstruction::UnblockCliPipes { .. } => PluginContext::UnblockCliPipes,
|
||||
PluginInstruction::WatchFilesystem => PluginContext::WatchFilesystem,
|
||||
PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe,
|
||||
PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -484,6 +487,32 @@ pub(crate) fn plugin_thread_main(
|
|||
client_id,
|
||||
)));
|
||||
},
|
||||
PluginInstruction::DumpLayoutToPlugin(mut session_layout_metadata, plugin_id) => {
|
||||
populate_session_layout_metadata(&mut session_layout_metadata, &wasm_bridge);
|
||||
match session_serialization::serialize_session_layout(
|
||||
session_layout_metadata.into(),
|
||||
) {
|
||||
Ok((layout, _pane_contents)) => {
|
||||
let updates = vec![(
|
||||
Some(plugin_id),
|
||||
None,
|
||||
Event::CustomMessage("session_layout".to_owned(), layout),
|
||||
)];
|
||||
wasm_bridge.update_plugins(updates, shutdown_send.clone())?;
|
||||
},
|
||||
Err(e) => {
|
||||
let updates = vec![(
|
||||
Some(plugin_id),
|
||||
None,
|
||||
Event::CustomMessage(
|
||||
"session_layout_error".to_owned(),
|
||||
format!("{}", e),
|
||||
),
|
||||
)];
|
||||
wasm_bridge.update_plugins(updates, shutdown_send.clone())?;
|
||||
},
|
||||
}
|
||||
},
|
||||
PluginInstruction::LogLayoutToHd(mut session_layout_metadata) => {
|
||||
populate_session_layout_metadata(&mut session_layout_metadata, &wasm_bridge);
|
||||
drop(
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ fn host_run_plugin_command(env: FunctionEnvMut<ForeignFunctionEnv>) {
|
|||
scan_host_folder(env, folder_to_scan)
|
||||
},
|
||||
PluginCommand::WatchFilesystem => watch_filesystem(env),
|
||||
PluginCommand::DumpSessionLayout => dump_session_layout(env),
|
||||
},
|
||||
(PermissionStatus::Denied, permission) => {
|
||||
log::error!(
|
||||
|
|
@ -1340,6 +1341,14 @@ fn watch_filesystem(env: &ForeignFunctionEnv) {
|
|||
.map(|sender| sender.send(PluginInstruction::WatchFilesystem));
|
||||
}
|
||||
|
||||
fn dump_session_layout(env: &ForeignFunctionEnv) {
|
||||
let _ = env.plugin_env.senders.to_screen.as_ref().map(|sender| {
|
||||
sender.send(ScreenInstruction::DumpLayoutToPlugin(
|
||||
env.plugin_env.plugin_id,
|
||||
))
|
||||
});
|
||||
}
|
||||
|
||||
fn scan_host_folder(env: &ForeignFunctionEnv, folder_to_scan: PathBuf) {
|
||||
if !folder_to_scan.starts_with("/host") {
|
||||
log::error!(
|
||||
|
|
@ -1542,6 +1551,7 @@ fn check_command_permission(
|
|||
| PluginCommand::BlockCliPipeInput(..)
|
||||
| PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes,
|
||||
PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins,
|
||||
PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState,
|
||||
_ => return (PermissionStatus::Granted, None),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::background_jobs::BackgroundJob;
|
|||
use crate::terminal_bytes::TerminalBytes;
|
||||
use crate::{
|
||||
panes::PaneId,
|
||||
plugins::PluginInstruction,
|
||||
plugins::{PluginId, PluginInstruction},
|
||||
screen::ScreenInstruction,
|
||||
session_layout_metadata::SessionLayoutMetadata,
|
||||
thread_bus::{Bus, ThreadSenders},
|
||||
|
|
@ -77,6 +77,7 @@ pub enum PtyInstruction {
|
|||
ClientTabIndexOrPaneId,
|
||||
), // String is an optional pane name
|
||||
DumpLayout(SessionLayoutMetadata, ClientId),
|
||||
DumpLayoutToPlugin(SessionLayoutMetadata, PluginId),
|
||||
LogLayoutToHd(SessionLayoutMetadata),
|
||||
FillPluginCwd(
|
||||
Option<bool>, // should float
|
||||
|
|
@ -110,6 +111,7 @@ impl From<&PtyInstruction> for PtyContext {
|
|||
PtyInstruction::DropToShellInPane { .. } => PtyContext::DropToShellInPane,
|
||||
PtyInstruction::SpawnInPlaceTerminal(..) => PtyContext::SpawnInPlaceTerminal,
|
||||
PtyInstruction::DumpLayout(..) => PtyContext::DumpLayout,
|
||||
PtyInstruction::DumpLayoutToPlugin(..) => PtyContext::DumpLayoutToPlugin,
|
||||
PtyInstruction::LogLayoutToHd(..) => PtyContext::LogLayoutToHd,
|
||||
PtyInstruction::FillPluginCwd(..) => PtyContext::FillPluginCwd,
|
||||
PtyInstruction::Exit => PtyContext::Exit,
|
||||
|
|
@ -630,6 +632,18 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
|||
},
|
||||
}
|
||||
},
|
||||
PtyInstruction::DumpLayoutToPlugin(mut session_layout_metadata, plugin_id) => {
|
||||
let err_context = || format!("Failed to dump layout");
|
||||
pty.populate_session_layout_metadata(&mut session_layout_metadata);
|
||||
pty.bus
|
||||
.senders
|
||||
.send_to_plugin(PluginInstruction::DumpLayoutToPlugin(
|
||||
session_layout_metadata,
|
||||
plugin_id,
|
||||
))
|
||||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
},
|
||||
PtyInstruction::LogLayoutToHd(mut session_layout_metadata) => {
|
||||
let err_context = || format!("Failed to dump layout");
|
||||
pty.populate_session_layout_metadata(&mut session_layout_metadata);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use crate::{
|
|||
output::Output,
|
||||
panes::sixel::SixelImageStore,
|
||||
panes::PaneId,
|
||||
plugins::{PluginInstruction, PluginRenderAsset},
|
||||
plugins::{PluginId, PluginInstruction, PluginRenderAsset},
|
||||
pty::{ClientTabIndexOrPaneId, PtyInstruction, VteBytes},
|
||||
tab::Tab,
|
||||
thread_bus::Bus,
|
||||
|
|
@ -180,6 +180,7 @@ pub enum ScreenInstruction {
|
|||
DumpScreen(String, ClientId, bool),
|
||||
DumpLayout(Option<PathBuf>, ClientId), // PathBuf is the default configured
|
||||
// shell
|
||||
DumpLayoutToPlugin(PluginId),
|
||||
EditScrollback(ClientId),
|
||||
ScrollUp(ClientId),
|
||||
ScrollUpAt(Position, ClientId),
|
||||
|
|
@ -421,6 +422,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
|||
ScreenInstruction::ClearScreen(..) => ScreenContext::ClearScreen,
|
||||
ScreenInstruction::DumpScreen(..) => ScreenContext::DumpScreen,
|
||||
ScreenInstruction::DumpLayout(..) => ScreenContext::DumpLayout,
|
||||
ScreenInstruction::DumpLayoutToPlugin(..) => ScreenContext::DumpLayoutToPlugin,
|
||||
ScreenInstruction::EditScrollback(..) => ScreenContext::EditScrollback,
|
||||
ScreenInstruction::ScrollUp(..) => ScreenContext::ScrollUp,
|
||||
ScreenInstruction::ScrollDown(..) => ScreenContext::ScrollDown,
|
||||
|
|
@ -2630,6 +2632,20 @@ pub(crate) fn screen_thread_main(
|
|||
))
|
||||
.with_context(err_context)?;
|
||||
},
|
||||
ScreenInstruction::DumpLayoutToPlugin(plugin_id) => {
|
||||
let err_context = || format!("Failed to dump layout");
|
||||
let session_layout_metadata =
|
||||
screen.get_layout_metadata(screen.default_shell.clone());
|
||||
screen
|
||||
.bus
|
||||
.senders
|
||||
.send_to_pty(PtyInstruction::DumpLayoutToPlugin(
|
||||
session_layout_metadata,
|
||||
plugin_id,
|
||||
))
|
||||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
},
|
||||
ScreenInstruction::EditScrollback(client_id) => {
|
||||
active_tab_and_connected_client_id!(
|
||||
screen,
|
||||
|
|
|
|||
|
|
@ -784,6 +784,14 @@ pub fn watch_filesystem() {
|
|||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
/// Get the serialized session layout in KDL format as a CustomMessage Event
|
||||
pub fn dump_session_layout() {
|
||||
let plugin_command = PluginCommand::DumpSessionLayout;
|
||||
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)]
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ pub enum CommandName {
|
|||
KillSessions = 81,
|
||||
ScanHostFolder = 82,
|
||||
WatchFilesystem = 83,
|
||||
DumpSessionLayout = 84,
|
||||
}
|
||||
impl CommandName {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
|
|
@ -512,6 +513,7 @@ impl CommandName {
|
|||
CommandName::KillSessions => "KillSessions",
|
||||
CommandName::ScanHostFolder => "ScanHostFolder",
|
||||
CommandName::WatchFilesystem => "WatchFilesystem",
|
||||
CommandName::DumpSessionLayout => "DumpSessionLayout",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
|
|
@ -601,6 +603,7 @@ impl CommandName {
|
|||
"KillSessions" => Some(Self::KillSessions),
|
||||
"ScanHostFolder" => Some(Self::ScanHostFolder),
|
||||
"WatchFilesystem" => Some(Self::WatchFilesystem),
|
||||
"DumpSessionLayout" => Some(Self::DumpSessionLayout),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1378,4 +1378,5 @@ pub enum PluginCommand {
|
|||
KillSessions(Vec<String>), // one or more session names
|
||||
ScanHostFolder(PathBuf), // TODO: rename to ScanHostFolder
|
||||
WatchFilesystem,
|
||||
DumpSessionLayout,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ pub enum ScreenContext {
|
|||
NewInPlacePluginPane,
|
||||
DumpLayoutToHd,
|
||||
RenameSession,
|
||||
DumpLayoutToPlugin,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
|
||||
|
|
@ -371,6 +372,7 @@ pub enum PtyContext {
|
|||
DumpLayout,
|
||||
LogLayoutToHd,
|
||||
FillPluginCwd,
|
||||
DumpLayoutToPlugin,
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
@ -402,6 +404,7 @@ pub enum PluginContext {
|
|||
UnblockCliPipes,
|
||||
WatchFilesystem,
|
||||
KeybindPipe,
|
||||
DumpLayoutToPlugin,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ enum CommandName {
|
|||
KillSessions = 81;
|
||||
ScanHostFolder = 82;
|
||||
WatchFilesystem = 83;
|
||||
DumpSessionLayout = 84;
|
||||
}
|
||||
|
||||
message PluginCommand {
|
||||
|
|
|
|||
|
|
@ -867,6 +867,10 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
|
|||
Some(_) => Err("WatchFilesystem should have no payload, found a payload"),
|
||||
None => Ok(PluginCommand::WatchFilesystem),
|
||||
},
|
||||
Some(CommandName::DumpSessionLayout) => match protobuf_plugin_command.payload {
|
||||
Some(_) => Err("DumpSessionLayout should have no payload, found a payload"),
|
||||
None => Ok(PluginCommand::DumpSessionLayout),
|
||||
},
|
||||
None => Err("Unrecognized plugin command"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1381,6 +1385,10 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
|
|||
name: CommandName::WatchFilesystem as i32,
|
||||
payload: None,
|
||||
}),
|
||||
PluginCommand::DumpSessionLayout => Ok(ProtobufPluginCommand {
|
||||
name: CommandName::DumpSessionLayout as i32,
|
||||
payload: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue