From af120de6dba440bd901f3ce940415aa61dbccdf8 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Fri, 31 Jan 2025 16:49:24 +0100 Subject: [PATCH] feat(plugins): add `PastedText` Event (#3962) * working with text paste * handle utf8 conversion error * feat(plugins): add PastedText Event --- zellij-server/src/panes/plugin_pane.rs | 32 ++++++++++++++++++++---- zellij-server/src/panes/terminal_pane.rs | 1 + zellij-server/src/tab/mod.rs | 3 +++ zellij-utils/assets/prost/api.event.rs | 13 +++++++++- zellij-utils/src/data.rs | 1 + zellij-utils/src/plugin_api/event.proto | 6 +++++ zellij-utils/src/plugin_api/event.rs | 14 +++++++++++ 7 files changed, 64 insertions(+), 6 deletions(-) diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs index c879cfef..9605437b 100644 --- a/zellij-server/src/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -100,6 +100,7 @@ pub(crate) struct PluginPane { arrow_fonts: bool, styled_underlines: bool, should_be_suppressed: bool, + text_being_pasted: Option>, } impl PluginPane { @@ -154,6 +155,7 @@ impl PluginPane { arrow_fonts, styled_underlines, should_be_suppressed: false, + text_being_pasted: None, }; for client_id in currently_connected_clients { plugin.handle_plugin_bytes(client_id, initial_loading_message.as_bytes().to_vec()); @@ -248,8 +250,9 @@ impl Pane for PluginPane { fn adjust_input_to_terminal( &mut self, key_with_modifier: &Option, - raw_input_bytes: Vec, + mut raw_input_bytes: Vec, _raw_input_bytes_are_kitty: bool, + client_id: Option, ) -> Option { if let Some(requesting_permissions) = &self.requesting_permissions { let permissions = requesting_permissions.permissions.clone(); @@ -286,10 +289,29 @@ impl Pane for PluginPane { } } else if let Some(key_with_modifier) = key_with_modifier { Some(AdjustedInput::WriteKeyToPlugin(key_with_modifier.clone())) - } else if raw_input_bytes.as_slice() == BRACKETED_PASTE_BEGIN - || raw_input_bytes.as_slice() == BRACKETED_PASTE_END - { - // plugins do not need bracketed paste + } else if raw_input_bytes.as_slice() == BRACKETED_PASTE_BEGIN { + self.text_being_pasted = Some(vec![]); + None + } else if raw_input_bytes.as_slice() == BRACKETED_PASTE_END { + if let Some(text_being_pasted) = self.text_being_pasted.take() { + match String::from_utf8(text_being_pasted) { + Ok(pasted_text) => { + let _ = self + .send_plugin_instructions + .send(PluginInstruction::Update(vec![( + Some(self.pid), + client_id, + Event::PastedText(pasted_text), + )])); + }, + Err(e) => { + log::error!("Failed to convert pasted bytes as utf8 {:?}", e); + }, + } + } + None + } else if let Some(pasted_text) = self.text_being_pasted.as_mut() { + pasted_text.append(&mut raw_input_bytes); None } else { Some(AdjustedInput::WriteBytesToTerminal(raw_input_bytes)) diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 61587d5e..7c10db12 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -213,6 +213,7 @@ impl Pane for TerminalPane { key_with_modifier: &Option, raw_input_bytes: Vec, raw_input_bytes_are_kitty: bool, + _client_id: Option, ) -> Option { // there are some cases in which the terminal state means that input sent to it // needs to be adjusted. diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index e402dfae..eec00568 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -229,6 +229,7 @@ pub trait Pane { _key_with_modifier: &Option, _raw_input_bytes: Vec, _raw_input_bytes_are_kitty: bool, + _client_id: Option, ) -> Option { None } @@ -1874,6 +1875,7 @@ impl Tab { key_with_modifier, raw_input_bytes, raw_input_bytes_are_kitty, + client_id, ) { Some(AdjustedInput::WriteBytesToTerminal(adjusted_input)) => { self.senders @@ -1916,6 +1918,7 @@ impl Tab { key_with_modifier, raw_input_bytes, raw_input_bytes_are_kitty, + client_id, ) { Some(AdjustedInput::WriteKeyToPlugin(key_with_modifier)) => { self.senders diff --git a/zellij-utils/assets/prost/api.event.rs b/zellij-utils/assets/prost/api.event.rs index 46cbfa9e..20abfc38 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, 24, 25" + 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" )] pub payload: ::core::option::Option, } @@ -68,10 +68,18 @@ pub mod event { HostFolderChangedPayload(super::HostFolderChangedPayload), #[prost(message, tag = "25")] FailedToChangeHostFolderPayload(super::FailedToChangeHostFolderPayload), + #[prost(message, tag = "26")] + PastedTextPayload(super::PastedTextPayload), } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct PastedTextPayload { + #[prost(string, tag = "1")] + pub pasted_text: ::prost::alloc::string::String, +} +#[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>, @@ -494,6 +502,7 @@ pub enum EventType { ListClients = 26, HostFolderChanged = 27, FailedToChangeHostFolder = 28, + PastedText = 29, } impl EventType { /// String value of the enum field names used in the ProtoBuf definition. @@ -531,6 +540,7 @@ impl EventType { EventType::ListClients => "ListClients", EventType::HostFolderChanged => "HostFolderChanged", EventType::FailedToChangeHostFolder => "FailedToChangeHostFolder", + EventType::PastedText => "PastedText", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -565,6 +575,7 @@ impl EventType { "ListClients" => Some(Self::ListClients), "HostFolderChanged" => Some(Self::HostFolderChanged), "FailedToChangeHostFolder" => Some(Self::FailedToChangeHostFolder), + "PastedText" => Some(Self::PastedText), _ => None, } } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index a9efb3d7..0deeeb19 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -914,6 +914,7 @@ pub enum Event { ListClients(Vec), HostFolderChanged(PathBuf), // PathBuf -> new host folder FailedToChangeHostFolder(Option), // String -> the error we got when changing + PastedText(String), } #[derive( diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto index d39edb23..86f74bdf 100644 --- a/zellij-utils/src/plugin_api/event.proto +++ b/zellij-utils/src/plugin_api/event.proto @@ -52,6 +52,7 @@ enum EventType { ListClients = 26; HostFolderChanged = 27; FailedToChangeHostFolder = 28; + PastedText = 29; } message EventNameList { @@ -85,9 +86,14 @@ message Event { ListClientsPayload list_clients_payload = 23; HostFolderChangedPayload host_folder_changed_payload = 24; FailedToChangeHostFolderPayload failed_to_change_host_folder_payload = 25; + PastedTextPayload pasted_text_payload = 26; } } +message PastedTextPayload { + string pasted_text = 1; +} + message FailedToChangeHostFolderPayload { optional string error_message = 1; } diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs index b525c76c..9a6829d6 100644 --- a/zellij-utils/src/plugin_api/event.rs +++ b/zellij-utils/src/plugin_api/event.rs @@ -349,6 +349,12 @@ impl TryFrom for Event { )), _ => Err("Malformed payload for the FailedToChangeHostFolder Event"), }, + Some(ProtobufEventType::PastedText) => match protobuf_event.payload { + Some(ProtobufEventPayload::PastedTextPayload(pasted_text_payload)) => { + Ok(Event::PastedText(pasted_text_payload.pasted_text)) + }, + _ => Err("Malformed payload for the PastedText Event"), + }, None => Err("Unknown Protobuf Event"), } } @@ -713,6 +719,12 @@ impl TryFrom for ProtobufEvent { FailedToChangeHostFolderPayload { error_message }, )), }), + Event::PastedText(pasted_text) => Ok(ProtobufEvent { + name: ProtobufEventType::PastedText as i32, + payload: Some(event::Payload::PastedTextPayload(PastedTextPayload { + pasted_text, + })), + }), } } } @@ -1268,6 +1280,7 @@ impl TryFrom for EventType { ProtobufEventType::ListClients => EventType::ListClients, ProtobufEventType::HostFolderChanged => EventType::HostFolderChanged, ProtobufEventType::FailedToChangeHostFolder => EventType::FailedToChangeHostFolder, + ProtobufEventType::PastedText => EventType::PastedText, }) } } @@ -1305,6 +1318,7 @@ impl TryFrom for ProtobufEventType { EventType::ListClients => ProtobufEventType::ListClients, EventType::HostFolderChanged => ProtobufEventType::HostFolderChanged, EventType::FailedToChangeHostFolder => ProtobufEventType::FailedToChangeHostFolder, + EventType::PastedText => ProtobufEventType::PastedText, }) } }