feat(plugins): add API to list clients, their focused panes and running commands/plugins (#3687)
* fix(list-clients): properly show client info after a tab was closed * feat(plugins): add API to list clients, their focused panes and running commands/plugins * style(fmt): rustfmt
This commit is contained in:
parent
912c9f599f
commit
d671ab650e
17 changed files with 339 additions and 16 deletions
|
|
@ -525,6 +525,9 @@ impl ZellijPlugin for State {
|
|||
];
|
||||
rebind_keys(keys_to_unbind, keys_to_rebind, write_to_disk);
|
||||
},
|
||||
BareKey::Char('z') if key.has_modifiers(&[KeyModifier::Alt]) => {
|
||||
list_clients();
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
Event::CustomMessage(message, payload) => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use wasm_bridge::WasmBridge;
|
|||
use zellij_utils::{
|
||||
async_std::{channel, future::timeout, task},
|
||||
data::{
|
||||
Event, EventType, InputMode, MessageToPlugin, PermissionStatus, PermissionType,
|
||||
ClientInfo, Event, EventType, InputMode, MessageToPlugin, PermissionStatus, PermissionType,
|
||||
PipeMessage, PipeSource, PluginCapabilities,
|
||||
},
|
||||
errors::{prelude::*, ContextType, PluginContext},
|
||||
|
|
@ -158,6 +158,7 @@ pub enum PluginInstruction {
|
|||
file_path: Option<PathBuf>,
|
||||
},
|
||||
WatchFilesystem,
|
||||
ListClientsToPlugin(SessionLayoutMetadata, PluginId, ClientId),
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
@ -203,6 +204,7 @@ impl From<&PluginInstruction> for PluginContext {
|
|||
PluginInstruction::FailedToWriteConfigToDisk { .. } => {
|
||||
PluginContext::FailedToWriteConfigToDisk
|
||||
},
|
||||
PluginInstruction::ListClientsToPlugin(..) => PluginContext::ListClientsToPlugin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -607,6 +609,35 @@ pub(crate) fn plugin_thread_main(
|
|||
},
|
||||
}
|
||||
},
|
||||
PluginInstruction::ListClientsToPlugin(
|
||||
mut session_layout_metadata,
|
||||
plugin_id,
|
||||
client_id,
|
||||
) => {
|
||||
populate_session_layout_metadata(
|
||||
&mut session_layout_metadata,
|
||||
&wasm_bridge,
|
||||
&plugin_aliases,
|
||||
);
|
||||
let mut clients_metadata = session_layout_metadata.all_clients_metadata();
|
||||
let mut client_list_for_plugin = vec![];
|
||||
let default_editor = session_layout_metadata.default_editor.clone();
|
||||
for (client_metadata_id, client_metadata) in clients_metadata.iter_mut() {
|
||||
let is_current_client = client_metadata_id == &client_id;
|
||||
client_list_for_plugin.push(ClientInfo::new(
|
||||
*client_metadata_id,
|
||||
client_metadata.get_pane_id().into(),
|
||||
client_metadata.stringify_command(&default_editor),
|
||||
is_current_client,
|
||||
));
|
||||
}
|
||||
let updates = vec![(
|
||||
Some(plugin_id),
|
||||
Some(client_id),
|
||||
Event::ListClients(client_list_for_plugin),
|
||||
)];
|
||||
wasm_bridge.update_plugins(updates, shutdown_send.clone())?;
|
||||
},
|
||||
PluginInstruction::LogLayoutToHd(mut session_layout_metadata) => {
|
||||
populate_session_layout_metadata(
|
||||
&mut session_layout_metadata,
|
||||
|
|
|
|||
|
|
@ -8551,3 +8551,74 @@ pub fn rebind_keys_plugin_command() {
|
|||
.clone();
|
||||
assert_snapshot!(format!("{:#?}", rebind_event));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn list_clients_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, screen_receiver, 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 = 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!(
|
||||
received_screen_instructions,
|
||||
ScreenInstruction::ListClientsToPlugin,
|
||||
screen_receiver,
|
||||
1,
|
||||
&PermissionType::ChangeApplicationState,
|
||||
cache_path,
|
||||
plugin_thread_sender,
|
||||
client_id
|
||||
);
|
||||
|
||||
let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
|
||||
let _ = plugin_thread_sender.send(PluginInstruction::Load(
|
||||
plugin_should_float,
|
||||
false,
|
||||
plugin_title,
|
||||
run_plugin,
|
||||
Some(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(KeyWithModifier::new(BareKey::Char('z')).with_alt_modifier()), // this triggers the enent in the fixture plugin
|
||||
)]));
|
||||
screen_thread.join().unwrap(); // this might take a while if the cache is cold
|
||||
teardown();
|
||||
let list_clients_instruction = received_screen_instructions
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find_map(|i| {
|
||||
if let ScreenInstruction::ListClientsToPlugin(..) = i {
|
||||
Some(i.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
assert_snapshot!(format!("{:#?}", list_clients_instruction));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||
assertion_line: 8623
|
||||
expression: "format!(\"{:#?}\", list_clients_instruction)"
|
||||
---
|
||||
ListClientsToPlugin(
|
||||
0,
|
||||
1,
|
||||
)
|
||||
|
|
@ -351,6 +351,7 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
|
|||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
} => rebind_keys(env, keys_to_rebind, keys_to_unbind, write_config_to_disk)?,
|
||||
PluginCommand::ListClients => list_clients(env),
|
||||
},
|
||||
(PermissionStatus::Denied, permission) => {
|
||||
log::error!(
|
||||
|
|
@ -1474,6 +1475,15 @@ fn dump_session_layout(env: &PluginEnv) {
|
|||
.map(|sender| sender.send(ScreenInstruction::DumpLayoutToPlugin(env.plugin_id)));
|
||||
}
|
||||
|
||||
fn list_clients(env: &PluginEnv) {
|
||||
let _ = env.senders.to_screen.as_ref().map(|sender| {
|
||||
sender.send(ScreenInstruction::ListClientsToPlugin(
|
||||
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!(
|
||||
|
|
@ -1897,7 +1907,9 @@ fn check_command_permission(
|
|||
| PluginCommand::BlockCliPipeInput(..)
|
||||
| PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes,
|
||||
PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins,
|
||||
PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState,
|
||||
PluginCommand::ListClients | PluginCommand::DumpSessionLayout => {
|
||||
PermissionType::ReadApplicationState
|
||||
},
|
||||
PluginCommand::RebindKeys { .. } | PluginCommand::Reconfigure(..) => {
|
||||
PermissionType::Reconfigure
|
||||
},
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ pub enum PtyInstruction {
|
|||
client_id: ClientId,
|
||||
default_editor: Option<PathBuf>,
|
||||
},
|
||||
ListClientsToPlugin(SessionLayoutMetadata, PluginId, ClientId),
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +126,7 @@ impl From<&PtyInstruction> for PtyContext {
|
|||
PtyInstruction::FillPluginCwd(..) => PtyContext::FillPluginCwd,
|
||||
PtyInstruction::ListClientsMetadata(..) => PtyContext::ListClientsMetadata,
|
||||
PtyInstruction::Reconfigure { .. } => PtyContext::Reconfigure,
|
||||
PtyInstruction::ListClientsToPlugin(..) => PtyContext::ListClientsToPlugin,
|
||||
PtyInstruction::Exit => PtyContext::Exit,
|
||||
}
|
||||
}
|
||||
|
|
@ -724,6 +726,23 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
|
|||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
},
|
||||
PtyInstruction::ListClientsToPlugin(
|
||||
mut session_layout_metadata,
|
||||
plugin_id,
|
||||
client_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::ListClientsToPlugin(
|
||||
session_layout_metadata,
|
||||
plugin_id,
|
||||
client_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);
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ pub enum ScreenInstruction {
|
|||
should_change_focus_to_new_tab: bool,
|
||||
client_id: ClientId,
|
||||
},
|
||||
ListClientsToPlugin(PluginId, ClientId),
|
||||
}
|
||||
|
||||
impl From<&ScreenInstruction> for ScreenContext {
|
||||
|
|
@ -621,6 +622,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
|||
ScreenInstruction::BreakPanesToTabWithIndex { .. } => {
|
||||
ScreenContext::BreakPanesToTabWithIndex
|
||||
},
|
||||
ScreenInstruction::ListClientsToPlugin(..) => ScreenContext::ListClientsToPlugin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2506,7 +2508,7 @@ impl Screen {
|
|||
let active_tab_index =
|
||||
first_client_id.and_then(|client_id| self.active_tab_indices.get(&client_id));
|
||||
|
||||
for (tab_index, tab) in self.tabs.values().enumerate() {
|
||||
for (tab_index, tab) in self.tabs.iter() {
|
||||
let tab_is_focused = active_tab_index == Some(&tab_index);
|
||||
let hide_floating_panes = !tab.are_floating_panes_visible();
|
||||
let mut suppressed_panes = HashMap::new();
|
||||
|
|
@ -3110,6 +3112,21 @@ pub(crate) fn screen_thread_main(
|
|||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
},
|
||||
ScreenInstruction::ListClientsToPlugin(plugin_id, client_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::ListClientsToPlugin(
|
||||
session_layout_metadata,
|
||||
plugin_id,
|
||||
client_id,
|
||||
))
|
||||
.with_context(err_context)
|
||||
.non_fatal();
|
||||
},
|
||||
ScreenInstruction::EditScrollback(client_id) => {
|
||||
active_tab_and_connected_client_id!(
|
||||
screen,
|
||||
|
|
|
|||
|
|
@ -82,6 +82,28 @@ impl SessionLayoutMetadata {
|
|||
|
||||
ClientMetadata::render_many(clients_metadata, &self.default_editor)
|
||||
}
|
||||
pub fn all_clients_metadata(&self) -> BTreeMap<ClientId, ClientMetadata> {
|
||||
let mut clients_metadata: BTreeMap<ClientId, ClientMetadata> = BTreeMap::new();
|
||||
for tab in &self.tabs {
|
||||
let panes = if tab.hide_floating_panes {
|
||||
&tab.tiled_panes
|
||||
} else {
|
||||
&tab.floating_panes
|
||||
};
|
||||
for pane in panes {
|
||||
for focused_client in &pane.focused_clients {
|
||||
clients_metadata.insert(
|
||||
*focused_client,
|
||||
ClientMetadata {
|
||||
pane_id: pane.id.clone(),
|
||||
command: pane.run.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
clients_metadata
|
||||
}
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
// here we check to see if the serialized layout would be different than the base one, and
|
||||
// thus is "dirty". A layout is considered dirty if one of the following is true:
|
||||
|
|
@ -372,7 +394,7 @@ impl PaneLayoutMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
struct ClientMetadata {
|
||||
pub struct ClientMetadata {
|
||||
pane_id: PaneId,
|
||||
command: Option<Run>,
|
||||
}
|
||||
|
|
@ -404,6 +426,9 @@ impl ClientMetadata {
|
|||
};
|
||||
stringified.unwrap_or("N/A".to_owned())
|
||||
}
|
||||
pub fn get_pane_id(&self) -> PaneId {
|
||||
self.pane_id
|
||||
}
|
||||
pub fn render_many(
|
||||
clients_metadata: BTreeMap<ClientId, ClientMetadata>,
|
||||
default_editor: &Option<PathBuf>,
|
||||
|
|
|
|||
|
|
@ -854,6 +854,15 @@ pub fn dump_session_layout() {
|
|||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
/// Get a list of clients, their focused pane and running command or focused plugin back as an
|
||||
/// Event::ListClients (note: this event must be subscribed to)
|
||||
pub fn list_clients() {
|
||||
let plugin_command = PluginCommand::ListClients;
|
||||
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
|
||||
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
|
||||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
/// Change configuration for the current user
|
||||
pub fn reconfigure(new_config: String, save_configuration_file: bool) {
|
||||
let plugin_command = PluginCommand::Reconfigure(new_config, save_configuration_file);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23"
|
||||
)]
|
||||
pub payload: ::core::option::Option<event::Payload>,
|
||||
}
|
||||
|
|
@ -62,10 +62,30 @@ pub mod event {
|
|||
CommandPaneRerunPayload(super::CommandPaneReRunPayload),
|
||||
#[prost(message, tag = "22")]
|
||||
FailedToWriteConfigToDiskPayload(super::FailedToWriteConfigToDiskPayload),
|
||||
#[prost(message, tag = "23")]
|
||||
ListClientsPayload(super::ListClientsPayload),
|
||||
}
|
||||
}
|
||||
#[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>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ClientInfo {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub client_id: u32,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub pane_id: ::core::option::Option<PaneId>,
|
||||
#[prost(string, tag = "3")]
|
||||
pub running_command: ::prost::alloc::string::String,
|
||||
#[prost(bool, tag = "4")]
|
||||
pub is_current_client: bool,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FailedToWriteConfigToDiskPayload {
|
||||
#[prost(string, optional, tag = "1")]
|
||||
pub file_path: ::core::option::Option<::prost::alloc::string::String>,
|
||||
|
|
@ -447,6 +467,7 @@ pub enum EventType {
|
|||
EditPaneExited = 23,
|
||||
CommandPaneReRun = 24,
|
||||
FailedToWriteConfigToDisk = 25,
|
||||
ListClients = 26,
|
||||
}
|
||||
impl EventType {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
|
|
@ -481,6 +502,7 @@ impl EventType {
|
|||
EventType::EditPaneExited => "EditPaneExited",
|
||||
EventType::CommandPaneReRun => "CommandPaneReRun",
|
||||
EventType::FailedToWriteConfigToDisk => "FailedToWriteConfigToDisk",
|
||||
EventType::ListClients => "ListClients",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
|
|
@ -512,6 +534,7 @@ impl EventType {
|
|||
"EditPaneExited" => Some(Self::EditPaneExited),
|
||||
"CommandPaneReRun" => Some(Self::CommandPaneReRun),
|
||||
"FailedToWriteConfigToDisk" => Some(Self::FailedToWriteConfigToDisk),
|
||||
"ListClients" => Some(Self::ListClients),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -715,6 +715,7 @@ pub enum CommandName {
|
|||
ReloadPlugin = 110,
|
||||
LoadNewPlugin = 111,
|
||||
RebindKeys = 112,
|
||||
ListClients = 113,
|
||||
}
|
||||
impl CommandName {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
|
|
@ -838,6 +839,7 @@ impl CommandName {
|
|||
CommandName::ReloadPlugin => "ReloadPlugin",
|
||||
CommandName::LoadNewPlugin => "LoadNewPlugin",
|
||||
CommandName::RebindKeys => "RebindKeys",
|
||||
CommandName::ListClients => "ListClients",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
|
|
@ -958,6 +960,7 @@ impl CommandName {
|
|||
"ReloadPlugin" => Some(Self::ReloadPlugin),
|
||||
"LoadNewPlugin" => Some(Self::LoadNewPlugin),
|
||||
"RebindKeys" => Some(Self::RebindKeys),
|
||||
"ListClients" => Some(Self::ListClients),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -921,6 +921,7 @@ pub enum Event {
|
|||
EditPaneExited(u32, Option<i32>, Context), // u32 - terminal_pane_id, Option<i32> - exit code
|
||||
CommandPaneReRun(u32, Context), // u32 - terminal_pane_id, Option<i32> -
|
||||
FailedToWriteConfigToDisk(Option<String>), // String -> the file path we failed to write
|
||||
ListClients(Vec<ClientInfo>),
|
||||
}
|
||||
|
||||
#[derive(
|
||||
|
|
@ -1365,6 +1366,29 @@ pub struct PaneInfo {
|
|||
/// (eg. the default `status-bar` or `tab-bar`).
|
||||
pub is_selectable: bool,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct ClientInfo {
|
||||
pub client_id: ClientId,
|
||||
pub pane_id: PaneId,
|
||||
pub running_command: String,
|
||||
pub is_current_client: bool,
|
||||
}
|
||||
|
||||
impl ClientInfo {
|
||||
pub fn new(
|
||||
client_id: ClientId,
|
||||
pane_id: PaneId,
|
||||
running_command: String,
|
||||
is_current_client: bool,
|
||||
) -> Self {
|
||||
ClientInfo {
|
||||
client_id,
|
||||
pane_id,
|
||||
running_command,
|
||||
is_current_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub struct PluginIds {
|
||||
|
|
@ -1878,4 +1902,5 @@ pub enum PluginCommand {
|
|||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
write_config_to_disk: bool,
|
||||
},
|
||||
ListClients,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ pub enum ScreenContext {
|
|||
CloseTabWithIndex,
|
||||
BreakPanesToNewTab,
|
||||
BreakPanesToTabWithIndex,
|
||||
ListClientsToPlugin,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
|
||||
|
|
@ -395,6 +396,7 @@ pub enum PtyContext {
|
|||
DumpLayoutToPlugin,
|
||||
ListClientsMetadata,
|
||||
Reconfigure,
|
||||
ListClientsToPlugin,
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
@ -432,6 +434,7 @@ pub enum PluginContext {
|
|||
ListClientsMetadata,
|
||||
Reconfigure,
|
||||
FailedToWriteConfigToDisk,
|
||||
ListClientsToPlugin,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ enum EventType {
|
|||
EditPaneExited = 23;
|
||||
CommandPaneReRun = 24;
|
||||
FailedToWriteConfigToDisk = 25;
|
||||
ListClients = 26;
|
||||
}
|
||||
|
||||
message EventNameList {
|
||||
|
|
@ -79,9 +80,21 @@ message Event {
|
|||
EditPaneExitedPayload edit_pane_exited_payload = 20;
|
||||
CommandPaneReRunPayload command_pane_rerun_payload = 21;
|
||||
FailedToWriteConfigToDiskPayload failed_to_write_config_to_disk_payload = 22;
|
||||
ListClientsPayload list_clients_payload = 23;
|
||||
}
|
||||
}
|
||||
|
||||
message ListClientsPayload {
|
||||
repeated ClientInfo client_info = 1;
|
||||
}
|
||||
|
||||
message ClientInfo {
|
||||
uint32 client_id = 1;
|
||||
PaneId pane_id = 2;
|
||||
string running_command = 3;
|
||||
bool is_current_client = 4;
|
||||
}
|
||||
|
||||
message FailedToWriteConfigToDiskPayload {
|
||||
optional string file_path = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
pub use super::generated_api::api::{
|
||||
action::{Action as ProtobufAction, Position as ProtobufPosition},
|
||||
event::{
|
||||
event::Payload as ProtobufEventPayload, CopyDestination as ProtobufCopyDestination,
|
||||
Event as ProtobufEvent, EventNameList as ProtobufEventNameList,
|
||||
EventType as ProtobufEventType, FileMetadata as ProtobufFileMetadata,
|
||||
InputModeKeybinds as ProtobufInputModeKeybinds, KeyBind as ProtobufKeyBind,
|
||||
LayoutInfo as ProtobufLayoutInfo, ModeUpdatePayload as ProtobufModeUpdatePayload,
|
||||
PaneId as ProtobufPaneId, PaneInfo as ProtobufPaneInfo,
|
||||
PaneManifest as ProtobufPaneManifest, PaneType as ProtobufPaneType,
|
||||
PluginInfo as ProtobufPluginInfo, ResurrectableSession as ProtobufResurrectableSession,
|
||||
event::Payload as ProtobufEventPayload, ClientInfo as ProtobufClientInfo,
|
||||
CopyDestination as ProtobufCopyDestination, Event as ProtobufEvent,
|
||||
EventNameList as ProtobufEventNameList, EventType as ProtobufEventType,
|
||||
FileMetadata as ProtobufFileMetadata, InputModeKeybinds as ProtobufInputModeKeybinds,
|
||||
KeyBind as ProtobufKeyBind, LayoutInfo as ProtobufLayoutInfo,
|
||||
ModeUpdatePayload as ProtobufModeUpdatePayload, PaneId as ProtobufPaneId,
|
||||
PaneInfo as ProtobufPaneInfo, PaneManifest as ProtobufPaneManifest,
|
||||
PaneType as ProtobufPaneType, PluginInfo as ProtobufPluginInfo,
|
||||
ResurrectableSession as ProtobufResurrectableSession,
|
||||
SessionManifest as ProtobufSessionManifest, TabInfo as ProtobufTabInfo, *,
|
||||
},
|
||||
input_mode::InputMode as ProtobufInputMode,
|
||||
|
|
@ -17,9 +18,9 @@ pub use super::generated_api::api::{
|
|||
};
|
||||
#[allow(hidden_glob_reexports)]
|
||||
use crate::data::{
|
||||
CopyDestination, Event, EventType, FileMetadata, InputMode, KeyWithModifier, LayoutInfo,
|
||||
ModeInfo, Mouse, PaneId, PaneInfo, PaneManifest, PermissionStatus, PluginCapabilities,
|
||||
PluginInfo, SessionInfo, Style, TabInfo,
|
||||
ClientInfo, CopyDestination, Event, EventType, FileMetadata, InputMode, KeyWithModifier,
|
||||
LayoutInfo, ModeInfo, Mouse, PaneId, PaneInfo, PaneManifest, PermissionStatus,
|
||||
PluginCapabilities, PluginInfo, SessionInfo, Style, TabInfo,
|
||||
};
|
||||
|
||||
use crate::errors::prelude::*;
|
||||
|
|
@ -320,11 +321,50 @@ impl TryFrom<ProtobufEvent> for Event {
|
|||
)),
|
||||
_ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
|
||||
},
|
||||
Some(ProtobufEventType::ListClients) => match protobuf_event.payload {
|
||||
Some(ProtobufEventPayload::ListClientsPayload(mut list_clients_payload)) => {
|
||||
Ok(Event::ListClients(
|
||||
list_clients_payload
|
||||
.client_info
|
||||
.drain(..)
|
||||
.filter_map(|c| c.try_into().ok())
|
||||
.collect(),
|
||||
))
|
||||
},
|
||||
_ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
|
||||
},
|
||||
None => Err("Unknown Protobuf Event"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ProtobufClientInfo> for ClientInfo {
|
||||
type Error = &'static str;
|
||||
fn try_from(protobuf_client_info: ProtobufClientInfo) -> Result<Self, &'static str> {
|
||||
Ok(ClientInfo::new(
|
||||
protobuf_client_info.client_id as u16,
|
||||
protobuf_client_info
|
||||
.pane_id
|
||||
.ok_or("No pane id found")?
|
||||
.try_into()?,
|
||||
protobuf_client_info.running_command,
|
||||
protobuf_client_info.is_current_client,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ClientInfo> for ProtobufClientInfo {
|
||||
type Error = &'static str;
|
||||
fn try_from(client_info: ClientInfo) -> Result<Self, &'static str> {
|
||||
Ok(ProtobufClientInfo {
|
||||
client_id: client_info.client_id as u32,
|
||||
pane_id: Some(client_info.pane_id.try_into()?),
|
||||
running_command: client_info.running_command,
|
||||
is_current_client: client_info.is_current_client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Event> for ProtobufEvent {
|
||||
type Error = &'static str;
|
||||
fn try_from(event: Event) -> Result<Self, &'static str> {
|
||||
|
|
@ -634,6 +674,15 @@ impl TryFrom<Event> for ProtobufEvent {
|
|||
FailedToWriteConfigToDiskPayload { file_path },
|
||||
)),
|
||||
}),
|
||||
Event::ListClients(mut client_info_list) => Ok(ProtobufEvent {
|
||||
name: ProtobufEventType::ListClients as i32,
|
||||
payload: Some(event::Payload::ListClientsPayload(ListClientsPayload {
|
||||
client_info: client_info_list
|
||||
.drain(..)
|
||||
.filter_map(|c| c.try_into().ok())
|
||||
.collect(),
|
||||
})),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1178,6 +1227,7 @@ impl TryFrom<ProtobufEventType> for EventType {
|
|||
ProtobufEventType::EditPaneExited => EventType::EditPaneExited,
|
||||
ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
|
||||
ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk,
|
||||
ProtobufEventType::ListClients => EventType::ListClients,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1212,6 +1262,7 @@ impl TryFrom<EventType> for ProtobufEventType {
|
|||
EventType::EditPaneExited => ProtobufEventType::EditPaneExited,
|
||||
EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
|
||||
EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk,
|
||||
EventType::ListClients => ProtobufEventType::ListClients,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ enum CommandName {
|
|||
ReloadPlugin = 110;
|
||||
LoadNewPlugin = 111;
|
||||
RebindKeys = 112;
|
||||
ListClients = 113;
|
||||
}
|
||||
|
||||
message PluginCommand {
|
||||
|
|
|
|||
|
|
@ -1299,6 +1299,10 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
|
|||
},
|
||||
_ => Err("Mismatched payload for RebindKeys"),
|
||||
},
|
||||
Some(CommandName::ListClients) => match protobuf_plugin_command.payload {
|
||||
Some(_) => Err("ListClients should have no payload, found a payload"),
|
||||
None => Ok(PluginCommand::ListClients),
|
||||
},
|
||||
None => Err("Unrecognized plugin command"),
|
||||
}
|
||||
}
|
||||
|
|
@ -2122,6 +2126,10 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
|
|||
write_config_to_disk,
|
||||
})),
|
||||
}),
|
||||
PluginCommand::ListClients => Ok(ProtobufPluginCommand {
|
||||
name: CommandName::ListClients as i32,
|
||||
payload: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue