zellij_utils/plugin_api/
plugin_command.rs

1pub use super::generated_api::api::{
2    action::{PaneIdAndShouldFloat, SwitchToModePayload},
3    event::{EventNameList as ProtobufEventNameList, Header},
4    input_mode::InputMode as ProtobufInputMode,
5    plugin_command::{
6        plugin_command::Payload, BreakPanesToNewTabPayload, BreakPanesToTabWithIndexPayload,
7        ClearScreenForPaneIdPayload, CliPipeOutputPayload, CloseTabWithIndexPayload, CommandName,
8        ContextItem, EditScrollbackForPaneWithIdPayload, EnvVariable, ExecCmdPayload,
9        FixedOrPercent as ProtobufFixedOrPercent,
10        FixedOrPercentValue as ProtobufFixedOrPercentValue,
11        FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload,
12        HttpVerb as ProtobufHttpVerb, IdAndNewName, KeyToRebind, KeyToUnbind, KillSessionsPayload,
13        LoadNewPluginPayload, MessageToPluginPayload, MovePaneWithPaneIdInDirectionPayload,
14        MovePaneWithPaneIdPayload, MovePayload, NewPluginArgs as ProtobufNewPluginArgs,
15        NewTabsWithLayoutInfoPayload, OpenCommandPanePayload, OpenFilePayload,
16        PageScrollDownInPaneIdPayload, PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId,
17        PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload,
18        RebindKeysPayload, ReconfigurePayload, ReloadPluginPayload, RequestPluginPermissionPayload,
19        RerunCommandPanePayload, ResizePaneIdWithDirectionPayload, ResizePayload,
20        RunCommandPayload, ScrollDownInPaneIdPayload, ScrollToBottomInPaneIdPayload,
21        ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload, SetTimeoutPayload,
22        ShowPaneWithIdPayload, SubscribePayload, SwitchSessionPayload, SwitchTabToPayload,
23        TogglePaneEmbedOrEjectForPaneIdPayload, TogglePaneIdFullscreenPayload, UnsubscribePayload,
24        WebRequestPayload, WriteCharsToPaneIdPayload, WriteToPaneIdPayload,
25    },
26    plugin_permission::PermissionType as ProtobufPermissionType,
27    resize::ResizeAction as ProtobufResizeAction,
28};
29
30use crate::data::{
31    ConnectToSession, FloatingPaneCoordinates, HttpVerb, InputMode, KeyWithModifier,
32    MessageToPlugin, NewPluginArgs, PaneId, PermissionType, PluginCommand,
33};
34use crate::input::actions::Action;
35use crate::input::layout::SplitSize;
36
37use std::collections::BTreeMap;
38use std::convert::TryFrom;
39use std::path::PathBuf;
40
41impl Into<FloatingPaneCoordinates> for ProtobufFloatingPaneCoordinates {
42    fn into(self) -> FloatingPaneCoordinates {
43        FloatingPaneCoordinates {
44            x: self
45                .x
46                .and_then(|x| match ProtobufFixedOrPercent::from_i32(x.r#type) {
47                    Some(ProtobufFixedOrPercent::Percent) => {
48                        Some(SplitSize::Percent(x.value as usize))
49                    },
50                    Some(ProtobufFixedOrPercent::Fixed) => Some(SplitSize::Fixed(x.value as usize)),
51                    None => None,
52                }),
53            y: self
54                .y
55                .and_then(|y| match ProtobufFixedOrPercent::from_i32(y.r#type) {
56                    Some(ProtobufFixedOrPercent::Percent) => {
57                        Some(SplitSize::Percent(y.value as usize))
58                    },
59                    Some(ProtobufFixedOrPercent::Fixed) => Some(SplitSize::Fixed(y.value as usize)),
60                    None => None,
61                }),
62            width: self.width.and_then(|width| {
63                match ProtobufFixedOrPercent::from_i32(width.r#type) {
64                    Some(ProtobufFixedOrPercent::Percent) => {
65                        Some(SplitSize::Percent(width.value as usize))
66                    },
67                    Some(ProtobufFixedOrPercent::Fixed) => {
68                        Some(SplitSize::Fixed(width.value as usize))
69                    },
70                    None => None,
71                }
72            }),
73            height: self.height.and_then(|height| {
74                match ProtobufFixedOrPercent::from_i32(height.r#type) {
75                    Some(ProtobufFixedOrPercent::Percent) => {
76                        Some(SplitSize::Percent(height.value as usize))
77                    },
78                    Some(ProtobufFixedOrPercent::Fixed) => {
79                        Some(SplitSize::Fixed(height.value as usize))
80                    },
81                    None => None,
82                }
83            }),
84        }
85    }
86}
87
88impl Into<ProtobufFloatingPaneCoordinates> for FloatingPaneCoordinates {
89    fn into(self) -> ProtobufFloatingPaneCoordinates {
90        ProtobufFloatingPaneCoordinates {
91            x: match self.x {
92                Some(SplitSize::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
93                    r#type: ProtobufFixedOrPercent::Percent as i32,
94                    value: percent as u32,
95                }),
96                Some(SplitSize::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
97                    r#type: ProtobufFixedOrPercent::Fixed as i32,
98                    value: fixed as u32,
99                }),
100                None => None,
101            },
102            y: match self.y {
103                Some(SplitSize::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
104                    r#type: ProtobufFixedOrPercent::Percent as i32,
105                    value: percent as u32,
106                }),
107                Some(SplitSize::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
108                    r#type: ProtobufFixedOrPercent::Fixed as i32,
109                    value: fixed as u32,
110                }),
111                None => None,
112            },
113            width: match self.width {
114                Some(SplitSize::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
115                    r#type: ProtobufFixedOrPercent::Percent as i32,
116                    value: percent as u32,
117                }),
118                Some(SplitSize::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
119                    r#type: ProtobufFixedOrPercent::Fixed as i32,
120                    value: fixed as u32,
121                }),
122                None => None,
123            },
124            height: match self.height {
125                Some(SplitSize::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
126                    r#type: ProtobufFixedOrPercent::Percent as i32,
127                    value: percent as u32,
128                }),
129                Some(SplitSize::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
130                    r#type: ProtobufFixedOrPercent::Fixed as i32,
131                    value: fixed as u32,
132                }),
133                None => None,
134            },
135        }
136    }
137}
138
139impl Into<HttpVerb> for ProtobufHttpVerb {
140    fn into(self) -> HttpVerb {
141        match self {
142            ProtobufHttpVerb::Get => HttpVerb::Get,
143            ProtobufHttpVerb::Post => HttpVerb::Post,
144            ProtobufHttpVerb::Put => HttpVerb::Put,
145            ProtobufHttpVerb::Delete => HttpVerb::Delete,
146        }
147    }
148}
149
150impl Into<ProtobufHttpVerb> for HttpVerb {
151    fn into(self) -> ProtobufHttpVerb {
152        match self {
153            HttpVerb::Get => ProtobufHttpVerb::Get,
154            HttpVerb::Post => ProtobufHttpVerb::Post,
155            HttpVerb::Put => ProtobufHttpVerb::Put,
156            HttpVerb::Delete => ProtobufHttpVerb::Delete,
157        }
158    }
159}
160
161impl TryFrom<ProtobufPaneId> for PaneId {
162    type Error = &'static str;
163    fn try_from(protobuf_pane_id: ProtobufPaneId) -> Result<Self, &'static str> {
164        match ProtobufPaneType::from_i32(protobuf_pane_id.pane_type) {
165            Some(ProtobufPaneType::Terminal) => Ok(PaneId::Terminal(protobuf_pane_id.id)),
166            Some(ProtobufPaneType::Plugin) => Ok(PaneId::Plugin(protobuf_pane_id.id)),
167            None => Err("Failed to convert PaneId"),
168        }
169    }
170}
171
172impl TryFrom<PaneId> for ProtobufPaneId {
173    type Error = &'static str;
174    fn try_from(pane_id: PaneId) -> Result<Self, &'static str> {
175        match pane_id {
176            PaneId::Terminal(id) => Ok(ProtobufPaneId {
177                pane_type: ProtobufPaneType::Terminal as i32,
178                id,
179            }),
180            PaneId::Plugin(id) => Ok(ProtobufPaneId {
181                pane_type: ProtobufPaneType::Plugin as i32,
182                id,
183            }),
184        }
185    }
186}
187
188impl TryFrom<(InputMode, KeyWithModifier, Vec<Action>)> for KeyToRebind {
189    type Error = &'static str;
190    fn try_from(
191        key_to_rebind: (InputMode, KeyWithModifier, Vec<Action>),
192    ) -> Result<Self, &'static str> {
193        Ok(KeyToRebind {
194            input_mode: key_to_rebind.0 as i32,
195            key: Some(key_to_rebind.1.try_into()?),
196            actions: key_to_rebind
197                .2
198                .into_iter()
199                .filter_map(|a| a.try_into().ok())
200                .collect(),
201        })
202    }
203}
204
205impl TryFrom<(InputMode, KeyWithModifier)> for KeyToUnbind {
206    type Error = &'static str;
207    fn try_from(key_to_unbind: (InputMode, KeyWithModifier)) -> Result<Self, &'static str> {
208        Ok(KeyToUnbind {
209            input_mode: key_to_unbind.0 as i32,
210            key: Some(key_to_unbind.1.try_into()?),
211        })
212    }
213}
214
215fn key_to_rebind_to_plugin_command_assets(
216    key_to_rebind: KeyToRebind,
217) -> Option<(InputMode, KeyWithModifier, Vec<Action>)> {
218    Some((
219        ProtobufInputMode::from_i32(key_to_rebind.input_mode)?
220            .try_into()
221            .ok()?,
222        key_to_rebind.key?.try_into().ok()?,
223        key_to_rebind
224            .actions
225            .into_iter()
226            .filter_map(|a| a.try_into().ok())
227            .collect(),
228    ))
229}
230
231fn key_to_unbind_to_plugin_command_assets(
232    key_to_unbind: KeyToUnbind,
233) -> Option<(InputMode, KeyWithModifier)> {
234    Some((
235        ProtobufInputMode::from_i32(key_to_unbind.input_mode)?
236            .try_into()
237            .ok()?,
238        key_to_unbind.key?.try_into().ok()?,
239    ))
240}
241
242impl TryFrom<ProtobufPluginCommand> for PluginCommand {
243    type Error = &'static str;
244    fn try_from(protobuf_plugin_command: ProtobufPluginCommand) -> Result<Self, &'static str> {
245        match CommandName::from_i32(protobuf_plugin_command.name) {
246            Some(CommandName::Subscribe) => match protobuf_plugin_command.payload {
247                Some(Payload::SubscribePayload(subscribe_payload)) => {
248                    let protobuf_event_list = subscribe_payload.subscriptions;
249                    match protobuf_event_list {
250                        Some(protobuf_event_list) => {
251                            Ok(PluginCommand::Subscribe(protobuf_event_list.try_into()?))
252                        },
253                        None => Err("malformed subscription event"),
254                    }
255                },
256                _ => Err("Mismatched payload for Subscribe"),
257            },
258            Some(CommandName::Unsubscribe) => match protobuf_plugin_command.payload {
259                Some(Payload::UnsubscribePayload(unsubscribe_payload)) => {
260                    let protobuf_event_list = unsubscribe_payload.subscriptions;
261                    match protobuf_event_list {
262                        Some(protobuf_event_list) => {
263                            Ok(PluginCommand::Unsubscribe(protobuf_event_list.try_into()?))
264                        },
265                        None => Err("malformed unsubscription event"),
266                    }
267                },
268                _ => Err("Mismatched payload for Unsubscribe"),
269            },
270            Some(CommandName::SetSelectable) => match protobuf_plugin_command.payload {
271                Some(Payload::SetSelectablePayload(should_be_selectable)) => {
272                    Ok(PluginCommand::SetSelectable(should_be_selectable))
273                },
274                _ => Err("Mismatched payload for SetSelectable"),
275            },
276            Some(CommandName::GetPluginIds) => {
277                if protobuf_plugin_command.payload.is_some() {
278                    Err("GetPluginIds should not have a payload")
279                } else {
280                    Ok(PluginCommand::GetPluginIds)
281                }
282            },
283            Some(CommandName::GetZellijVersion) => {
284                if protobuf_plugin_command.payload.is_some() {
285                    Err("GetZellijVersion should not have a payload")
286                } else {
287                    Ok(PluginCommand::GetZellijVersion)
288                }
289            },
290            Some(CommandName::OpenFile) => match protobuf_plugin_command.payload {
291                Some(Payload::OpenFilePayload(file_to_open_payload)) => {
292                    match file_to_open_payload.file_to_open {
293                        Some(file_to_open) => {
294                            let context: BTreeMap<String, String> = file_to_open_payload
295                                .context
296                                .into_iter()
297                                .map(|e| (e.name, e.value))
298                                .collect();
299                            Ok(PluginCommand::OpenFile(file_to_open.try_into()?, context))
300                        },
301                        None => Err("Malformed open file payload"),
302                    }
303                },
304                _ => Err("Mismatched payload for OpenFile"),
305            },
306            Some(CommandName::OpenFileFloating) => match protobuf_plugin_command.payload {
307                Some(Payload::OpenFileFloatingPayload(file_to_open_payload)) => {
308                    let floating_pane_coordinates = file_to_open_payload
309                        .floating_pane_coordinates
310                        .map(|f| f.into());
311                    let context: BTreeMap<String, String> = file_to_open_payload
312                        .context
313                        .into_iter()
314                        .map(|e| (e.name, e.value))
315                        .collect();
316                    match file_to_open_payload.file_to_open {
317                        Some(file_to_open) => Ok(PluginCommand::OpenFileFloating(
318                            file_to_open.try_into()?,
319                            floating_pane_coordinates,
320                            context,
321                        )),
322                        None => Err("Malformed open file payload"),
323                    }
324                },
325                _ => Err("Mismatched payload for OpenFileFloating"),
326            },
327            Some(CommandName::OpenTerminal) => match protobuf_plugin_command.payload {
328                Some(Payload::OpenTerminalPayload(file_to_open_payload)) => {
329                    match file_to_open_payload.file_to_open {
330                        Some(file_to_open) => {
331                            Ok(PluginCommand::OpenTerminal(file_to_open.try_into()?))
332                        },
333                        None => Err("Malformed open terminal payload"),
334                    }
335                },
336                _ => Err("Mismatched payload for OpenTerminal"),
337            },
338            Some(CommandName::OpenTerminalFloating) => match protobuf_plugin_command.payload {
339                Some(Payload::OpenTerminalFloatingPayload(file_to_open_payload)) => {
340                    let floating_pane_coordinates = file_to_open_payload
341                        .floating_pane_coordinates
342                        .map(|f| f.into());
343                    match file_to_open_payload.file_to_open {
344                        Some(file_to_open) => Ok(PluginCommand::OpenTerminalFloating(
345                            file_to_open.try_into()?,
346                            floating_pane_coordinates,
347                        )),
348                        None => Err("Malformed open terminal floating payload"),
349                    }
350                },
351                _ => Err("Mismatched payload for OpenTerminalFloating"),
352            },
353            Some(CommandName::OpenCommandPane) => match protobuf_plugin_command.payload {
354                Some(Payload::OpenCommandPanePayload(command_to_run_payload)) => {
355                    match command_to_run_payload.command_to_run {
356                        Some(command_to_run) => {
357                            let context: BTreeMap<String, String> = command_to_run_payload
358                                .context
359                                .into_iter()
360                                .map(|e| (e.name, e.value))
361                                .collect();
362                            Ok(PluginCommand::OpenCommandPane(
363                                command_to_run.try_into()?,
364                                context,
365                            ))
366                        },
367                        None => Err("Malformed open open command pane payload"),
368                    }
369                },
370                _ => Err("Mismatched payload for OpenCommandPane"),
371            },
372            Some(CommandName::OpenCommandPaneFloating) => match protobuf_plugin_command.payload {
373                Some(Payload::OpenCommandPaneFloatingPayload(command_to_run_payload)) => {
374                    let floating_pane_coordinates = command_to_run_payload
375                        .floating_pane_coordinates
376                        .map(|f| f.into());
377                    match command_to_run_payload.command_to_run {
378                        Some(command_to_run) => {
379                            let context: BTreeMap<String, String> = command_to_run_payload
380                                .context
381                                .into_iter()
382                                .map(|e| (e.name, e.value))
383                                .collect();
384                            Ok(PluginCommand::OpenCommandPaneFloating(
385                                command_to_run.try_into()?,
386                                floating_pane_coordinates,
387                                context,
388                            ))
389                        },
390                        None => Err("Malformed open command pane floating payload"),
391                    }
392                },
393                _ => Err("Mismatched payload for OpenCommandPaneFloating"),
394            },
395            Some(CommandName::SwitchTabTo) => match protobuf_plugin_command.payload {
396                Some(Payload::SwitchTabToPayload(switch_to_tab_payload)) => Ok(
397                    PluginCommand::SwitchTabTo(switch_to_tab_payload.tab_index as u32),
398                ),
399                _ => Err("Mismatched payload for SwitchToTab"),
400            },
401            Some(CommandName::SetTimeout) => match protobuf_plugin_command.payload {
402                Some(Payload::SetTimeoutPayload(set_timeout_payload)) => {
403                    Ok(PluginCommand::SetTimeout(set_timeout_payload.seconds))
404                },
405                _ => Err("Mismatched payload for SetTimeout"),
406            },
407            Some(CommandName::ExecCmd) => match protobuf_plugin_command.payload {
408                Some(Payload::ExecCmdPayload(exec_cmd_payload)) => {
409                    Ok(PluginCommand::ExecCmd(exec_cmd_payload.command_line))
410                },
411                _ => Err("Mismatched payload for ExecCmd"),
412            },
413            Some(CommandName::PostMessageTo) => match protobuf_plugin_command.payload {
414                Some(Payload::PostMessageToPayload(post_message_to_payload)) => {
415                    match post_message_to_payload.message {
416                        Some(message) => Ok(PluginCommand::PostMessageTo(message.try_into()?)),
417                        None => Err("Malformed post message to payload"),
418                    }
419                },
420                _ => Err("Mismatched payload for PostMessageTo"),
421            },
422            Some(CommandName::PostMessageToPlugin) => match protobuf_plugin_command.payload {
423                Some(Payload::PostMessageToPluginPayload(post_message_to_payload)) => {
424                    match post_message_to_payload.message {
425                        Some(message) => {
426                            Ok(PluginCommand::PostMessageToPlugin(message.try_into()?))
427                        },
428                        None => Err("Malformed post message to plugin payload"),
429                    }
430                },
431                _ => Err("Mismatched payload for PostMessageToPlugin"),
432            },
433            Some(CommandName::HideSelf) => {
434                if protobuf_plugin_command.payload.is_some() {
435                    return Err("HideSelf should not have a payload");
436                }
437                Ok(PluginCommand::HideSelf)
438            },
439            Some(CommandName::ShowSelf) => match protobuf_plugin_command.payload {
440                Some(Payload::ShowSelfPayload(should_float_if_hidden)) => {
441                    Ok(PluginCommand::ShowSelf(should_float_if_hidden))
442                },
443                _ => Err("Mismatched payload for ShowSelf"),
444            },
445            Some(CommandName::SwitchToMode) => match protobuf_plugin_command.payload {
446                Some(Payload::SwitchToModePayload(switch_to_mode_payload)) => {
447                    match ProtobufInputMode::from_i32(switch_to_mode_payload.input_mode) {
448                        Some(protobuf_input_mode) => {
449                            Ok(PluginCommand::SwitchToMode(protobuf_input_mode.try_into()?))
450                        },
451                        None => Err("Malformed switch to mode payload"),
452                    }
453                },
454                _ => Err("Mismatched payload for SwitchToMode"),
455            },
456            Some(CommandName::NewTabsWithLayout) => match protobuf_plugin_command.payload {
457                Some(Payload::NewTabsWithLayoutPayload(raw_layout)) => {
458                    Ok(PluginCommand::NewTabsWithLayout(raw_layout))
459                },
460                _ => Err("Mismatched payload for NewTabsWithLayout"),
461            },
462            Some(CommandName::NewTab) => {
463                if protobuf_plugin_command.payload.is_some() {
464                    return Err("NewTab should not have a payload");
465                }
466                Ok(PluginCommand::NewTab)
467            },
468            Some(CommandName::GoToNextTab) => {
469                if protobuf_plugin_command.payload.is_some() {
470                    return Err("GoToNextTab should not have a payload");
471                }
472                Ok(PluginCommand::GoToNextTab)
473            },
474            Some(CommandName::GoToPreviousTab) => {
475                if protobuf_plugin_command.payload.is_some() {
476                    return Err("GoToPreviousTab should not have a payload");
477                }
478                Ok(PluginCommand::GoToPreviousTab)
479            },
480            Some(CommandName::Resize) => match protobuf_plugin_command.payload {
481                Some(Payload::ResizePayload(resize_payload)) => match resize_payload.resize {
482                    Some(resize) => Ok(PluginCommand::Resize(resize.try_into()?)),
483                    None => Err("Malformed switch resize payload"),
484                },
485                _ => Err("Mismatched payload for Resize"),
486            },
487            Some(CommandName::ResizeWithDirection) => match protobuf_plugin_command.payload {
488                Some(Payload::ResizeWithDirectionPayload(resize_with_direction_payload)) => {
489                    match resize_with_direction_payload.resize {
490                        Some(resize) => Ok(PluginCommand::ResizeWithDirection(resize.try_into()?)),
491                        None => Err("Malformed switch resize payload"),
492                    }
493                },
494                _ => Err("Mismatched payload for Resize"),
495            },
496            Some(CommandName::FocusNextPane) => {
497                if protobuf_plugin_command.payload.is_some() {
498                    return Err("FocusNextPane should not have a payload");
499                }
500                Ok(PluginCommand::FocusNextPane)
501            },
502            Some(CommandName::FocusPreviousPane) => {
503                if protobuf_plugin_command.payload.is_some() {
504                    return Err("FocusPreviousPane should not have a payload");
505                }
506                Ok(PluginCommand::FocusPreviousPane)
507            },
508            Some(CommandName::MoveFocus) => match protobuf_plugin_command.payload {
509                Some(Payload::MoveFocusPayload(move_payload)) => match move_payload.direction {
510                    Some(direction) => Ok(PluginCommand::MoveFocus(direction.try_into()?)),
511                    None => Err("Malformed move focus payload"),
512                },
513                _ => Err("Mismatched payload for MoveFocus"),
514            },
515            Some(CommandName::MoveFocusOrTab) => match protobuf_plugin_command.payload {
516                Some(Payload::MoveFocusOrTabPayload(move_payload)) => {
517                    match move_payload.direction {
518                        Some(direction) => Ok(PluginCommand::MoveFocusOrTab(direction.try_into()?)),
519                        None => Err("Malformed move focus or tab payload"),
520                    }
521                },
522                _ => Err("Mismatched payload for MoveFocusOrTab"),
523            },
524            Some(CommandName::Detach) => {
525                if protobuf_plugin_command.payload.is_some() {
526                    return Err("Detach should not have a payload");
527                }
528                Ok(PluginCommand::Detach)
529            },
530            Some(CommandName::EditScrollback) => {
531                if protobuf_plugin_command.payload.is_some() {
532                    return Err("EditScrollback should not have a payload");
533                }
534                Ok(PluginCommand::EditScrollback)
535            },
536            Some(CommandName::Write) => match protobuf_plugin_command.payload {
537                Some(Payload::WritePayload(bytes)) => Ok(PluginCommand::Write(bytes)),
538                _ => Err("Mismatched payload for Write"),
539            },
540            Some(CommandName::WriteChars) => match protobuf_plugin_command.payload {
541                Some(Payload::WriteCharsPayload(chars)) => Ok(PluginCommand::WriteChars(chars)),
542                _ => Err("Mismatched payload for WriteChars"),
543            },
544            Some(CommandName::ToggleTab) => {
545                if protobuf_plugin_command.payload.is_some() {
546                    return Err("ToggleTab should not have a payload");
547                }
548                Ok(PluginCommand::ToggleTab)
549            },
550            Some(CommandName::MovePane) => {
551                if protobuf_plugin_command.payload.is_some() {
552                    return Err("MovePane should not have a payload");
553                }
554                Ok(PluginCommand::MovePane)
555            },
556            Some(CommandName::MovePaneWithDirection) => match protobuf_plugin_command.payload {
557                Some(Payload::MovePaneWithDirectionPayload(move_payload)) => {
558                    match move_payload.direction {
559                        Some(direction) => {
560                            Ok(PluginCommand::MovePaneWithDirection(direction.try_into()?))
561                        },
562                        None => Err("Malformed MovePaneWithDirection payload"),
563                    }
564                },
565                _ => Err("Mismatched payload for MovePaneWithDirection"),
566            },
567            Some(CommandName::ClearScreen) => {
568                if protobuf_plugin_command.payload.is_some() {
569                    return Err("ClearScreen should not have a payload");
570                }
571                Ok(PluginCommand::ClearScreen)
572            },
573            Some(CommandName::ScrollUp) => {
574                if protobuf_plugin_command.payload.is_some() {
575                    return Err("ScrollUp should not have a payload");
576                }
577                Ok(PluginCommand::ScrollUp)
578            },
579            Some(CommandName::ScrollDown) => {
580                if protobuf_plugin_command.payload.is_some() {
581                    return Err("ScrollDown should not have a payload");
582                }
583                Ok(PluginCommand::ScrollDown)
584            },
585            Some(CommandName::ScrollToTop) => {
586                if protobuf_plugin_command.payload.is_some() {
587                    return Err("ScrollToTop should not have a payload");
588                }
589                Ok(PluginCommand::ScrollToTop)
590            },
591            Some(CommandName::ScrollToBottom) => {
592                if protobuf_plugin_command.payload.is_some() {
593                    return Err("ScrollToBottom should not have a payload");
594                }
595                Ok(PluginCommand::ScrollToBottom)
596            },
597            Some(CommandName::PageScrollUp) => {
598                if protobuf_plugin_command.payload.is_some() {
599                    return Err("PageScrollUp should not have a payload");
600                }
601                Ok(PluginCommand::PageScrollUp)
602            },
603            Some(CommandName::PageScrollDown) => {
604                if protobuf_plugin_command.payload.is_some() {
605                    return Err("PageScrollDown should not have a payload");
606                }
607                Ok(PluginCommand::PageScrollDown)
608            },
609            Some(CommandName::ToggleFocusFullscreen) => {
610                if protobuf_plugin_command.payload.is_some() {
611                    return Err("ToggleFocusFullscreen should not have a payload");
612                }
613                Ok(PluginCommand::ToggleFocusFullscreen)
614            },
615            Some(CommandName::TogglePaneFrames) => {
616                if protobuf_plugin_command.payload.is_some() {
617                    return Err("TogglePaneFrames should not have a payload");
618                }
619                Ok(PluginCommand::TogglePaneFrames)
620            },
621            Some(CommandName::TogglePaneEmbedOrEject) => {
622                if protobuf_plugin_command.payload.is_some() {
623                    return Err("TogglePaneEmbedOrEject should not have a payload");
624                }
625                Ok(PluginCommand::TogglePaneEmbedOrEject)
626            },
627            Some(CommandName::UndoRenamePane) => {
628                if protobuf_plugin_command.payload.is_some() {
629                    return Err("UndoRenamePane should not have a payload");
630                }
631                Ok(PluginCommand::UndoRenamePane)
632            },
633            Some(CommandName::CloseFocus) => {
634                if protobuf_plugin_command.payload.is_some() {
635                    return Err("CloseFocus should not have a payload");
636                }
637                Ok(PluginCommand::CloseFocus)
638            },
639            Some(CommandName::ToggleActiveTabSync) => {
640                if protobuf_plugin_command.payload.is_some() {
641                    return Err("ToggleActiveTabSync should not have a payload");
642                }
643                Ok(PluginCommand::ToggleActiveTabSync)
644            },
645            Some(CommandName::CloseFocusedTab) => {
646                if protobuf_plugin_command.payload.is_some() {
647                    return Err("CloseFocusedTab should not have a payload");
648                }
649                Ok(PluginCommand::CloseFocusedTab)
650            },
651            Some(CommandName::UndoRenameTab) => {
652                if protobuf_plugin_command.payload.is_some() {
653                    return Err("UndoRenameTab should not have a payload");
654                }
655                Ok(PluginCommand::UndoRenameTab)
656            },
657            Some(CommandName::QuitZellij) => {
658                if protobuf_plugin_command.payload.is_some() {
659                    return Err("QuitZellij should not have a payload");
660                }
661                Ok(PluginCommand::QuitZellij)
662            },
663            Some(CommandName::PreviousSwapLayout) => {
664                if protobuf_plugin_command.payload.is_some() {
665                    return Err("PreviousSwapLayout should not have a payload");
666                }
667                Ok(PluginCommand::PreviousSwapLayout)
668            },
669            Some(CommandName::NextSwapLayout) => {
670                if protobuf_plugin_command.payload.is_some() {
671                    return Err("NextSwapLayout should not have a payload");
672                }
673                Ok(PluginCommand::NextSwapLayout)
674            },
675            Some(CommandName::GoToTabName) => match protobuf_plugin_command.payload {
676                Some(Payload::GoToTabNamePayload(tab_name)) => {
677                    Ok(PluginCommand::GoToTabName(tab_name))
678                },
679                _ => Err("Mismatched payload for GoToTabName"),
680            },
681            Some(CommandName::FocusOrCreateTab) => match protobuf_plugin_command.payload {
682                Some(Payload::FocusOrCreateTabPayload(tab_name)) => {
683                    Ok(PluginCommand::FocusOrCreateTab(tab_name))
684                },
685                _ => Err("Mismatched payload for FocusOrCreateTab"),
686            },
687            Some(CommandName::GoToTab) => match protobuf_plugin_command.payload {
688                Some(Payload::GoToTabPayload(tab_index)) => {
689                    Ok(PluginCommand::GoToTab(tab_index as u32))
690                },
691                _ => Err("Mismatched payload for GoToTab"),
692            },
693            Some(CommandName::StartOrReloadPlugin) => match protobuf_plugin_command.payload {
694                Some(Payload::StartOrReloadPluginPayload(url)) => {
695                    Ok(PluginCommand::StartOrReloadPlugin(url))
696                },
697                _ => Err("Mismatched payload for StartOrReloadPlugin"),
698            },
699            Some(CommandName::CloseTerminalPane) => match protobuf_plugin_command.payload {
700                Some(Payload::CloseTerminalPanePayload(pane_id)) => {
701                    Ok(PluginCommand::CloseTerminalPane(pane_id as u32))
702                },
703                _ => Err("Mismatched payload for CloseTerminalPane"),
704            },
705            Some(CommandName::ClosePluginPane) => match protobuf_plugin_command.payload {
706                Some(Payload::ClosePluginPanePayload(pane_id)) => {
707                    Ok(PluginCommand::ClosePluginPane(pane_id as u32))
708                },
709                _ => Err("Mismatched payload for ClosePluginPane"),
710            },
711            Some(CommandName::FocusTerminalPane) => match protobuf_plugin_command.payload {
712                Some(Payload::FocusTerminalPanePayload(payload)) => {
713                    let pane_id = payload.pane_id as u32;
714                    let should_float = payload.should_float;
715                    Ok(PluginCommand::FocusTerminalPane(pane_id, should_float))
716                },
717                _ => Err("Mismatched payload for ClosePluginPane"),
718            },
719            Some(CommandName::FocusPluginPane) => match protobuf_plugin_command.payload {
720                Some(Payload::FocusPluginPanePayload(payload)) => {
721                    let pane_id = payload.pane_id as u32;
722                    let should_float = payload.should_float;
723                    Ok(PluginCommand::FocusPluginPane(pane_id, should_float))
724                },
725                _ => Err("Mismatched payload for ClosePluginPane"),
726            },
727            Some(CommandName::RenameTerminalPane) => match protobuf_plugin_command.payload {
728                Some(Payload::RenameTerminalPanePayload(payload)) => {
729                    let pane_id = payload.id as u32;
730                    let new_name = payload.new_name;
731                    Ok(PluginCommand::RenameTerminalPane(pane_id, new_name))
732                },
733                _ => Err("Mismatched payload for RenameTerminalPane"),
734            },
735            Some(CommandName::RenamePluginPane) => match protobuf_plugin_command.payload {
736                Some(Payload::RenamePluginPanePayload(payload)) => {
737                    let pane_id = payload.id as u32;
738                    let new_name = payload.new_name;
739                    Ok(PluginCommand::RenamePluginPane(pane_id, new_name))
740                },
741                _ => Err("Mismatched payload for RenamePluginPane"),
742            },
743            Some(CommandName::RenameTab) => match protobuf_plugin_command.payload {
744                Some(Payload::RenameTabPayload(payload)) => {
745                    let tab_index = payload.id as u32;
746                    let name = payload.new_name;
747                    Ok(PluginCommand::RenameTab(tab_index, name))
748                },
749                _ => Err("Mismatched payload for RenameTab"),
750            },
751            Some(CommandName::ReportCrash) => match protobuf_plugin_command.payload {
752                Some(Payload::ReportCrashPayload(payload)) => {
753                    Ok(PluginCommand::ReportPanic(payload))
754                },
755                _ => Err("Mismatched payload for ReportCrash"),
756            },
757            Some(CommandName::RequestPluginPermissions) => match protobuf_plugin_command.payload {
758                Some(Payload::RequestPluginPermissionPayload(payload)) => {
759                    Ok(PluginCommand::RequestPluginPermissions(
760                        payload
761                            .permissions
762                            .iter()
763                            .filter_map(|p| ProtobufPermissionType::from_i32(*p))
764                            .filter_map(|p| PermissionType::try_from(p).ok())
765                            .collect(),
766                    ))
767                },
768                _ => Err("Mismatched payload for RequestPluginPermission"),
769            },
770            Some(CommandName::SwitchSession) => match protobuf_plugin_command.payload {
771                Some(Payload::SwitchSessionPayload(payload)) => {
772                    let pane_id = match (payload.pane_id, payload.pane_id_is_plugin) {
773                        (Some(pane_id), Some(is_plugin)) => Some((pane_id, is_plugin)),
774                        (None, None) => None,
775                        _ => {
776                            return Err("Malformed payload for SwitchSession, 'pane_id' and 'is_plugin' must be included together or not at all")
777                        }
778                    };
779                    Ok(PluginCommand::SwitchSession(ConnectToSession {
780                        name: payload.name,
781                        tab_position: payload.tab_position.map(|p| p as usize),
782                        pane_id,
783                        layout: payload.layout.and_then(|l| l.try_into().ok()),
784                        cwd: payload.cwd.map(|c| PathBuf::from(c)),
785                    }))
786                },
787                _ => Err("Mismatched payload for SwitchSession"),
788            },
789            Some(CommandName::OpenTerminalInPlace) => match protobuf_plugin_command.payload {
790                Some(Payload::OpenTerminalInPlacePayload(file_to_open_payload)) => {
791                    match file_to_open_payload.file_to_open {
792                        Some(file_to_open) => {
793                            Ok(PluginCommand::OpenTerminalInPlace(file_to_open.try_into()?))
794                        },
795                        None => Err("Malformed open terminal in-place payload"),
796                    }
797                },
798                _ => Err("Mismatched payload for OpenTerminalInPlace"),
799            },
800            Some(CommandName::OpenFileInPlace) => match protobuf_plugin_command.payload {
801                Some(Payload::OpenFileInPlacePayload(file_to_open_payload)) => {
802                    match file_to_open_payload.file_to_open {
803                        Some(file_to_open) => {
804                            let context: BTreeMap<String, String> = file_to_open_payload
805                                .context
806                                .into_iter()
807                                .map(|e| (e.name, e.value))
808                                .collect();
809                            Ok(PluginCommand::OpenFileInPlace(
810                                file_to_open.try_into()?,
811                                context,
812                            ))
813                        },
814                        None => Err("Malformed open file in place payload"),
815                    }
816                },
817                _ => Err("Mismatched payload for OpenFileInPlace"),
818            },
819            Some(CommandName::OpenCommandInPlace) => match protobuf_plugin_command.payload {
820                Some(Payload::OpenCommandPaneInPlacePayload(command_to_run_payload)) => {
821                    match command_to_run_payload.command_to_run {
822                        Some(command_to_run) => {
823                            let context: BTreeMap<String, String> = command_to_run_payload
824                                .context
825                                .into_iter()
826                                .map(|e| (e.name, e.value))
827                                .collect();
828                            Ok(PluginCommand::OpenCommandPaneInPlace(
829                                command_to_run.try_into()?,
830                                context,
831                            ))
832                        },
833                        None => Err("Malformed open command pane in-place payload"),
834                    }
835                },
836                _ => Err("Mismatched payload for OpenCommandPaneInPlace"),
837            },
838            Some(CommandName::RunCommand) => match protobuf_plugin_command.payload {
839                Some(Payload::RunCommandPayload(run_command_payload)) => {
840                    let env_variables: BTreeMap<String, String> = run_command_payload
841                        .env_variables
842                        .into_iter()
843                        .map(|e| (e.name, e.value))
844                        .collect();
845                    let context: BTreeMap<String, String> = run_command_payload
846                        .context
847                        .into_iter()
848                        .map(|e| (e.name, e.value))
849                        .collect();
850                    Ok(PluginCommand::RunCommand(
851                        run_command_payload.command_line,
852                        env_variables,
853                        PathBuf::from(run_command_payload.cwd),
854                        context,
855                    ))
856                },
857                _ => Err("Mismatched payload for RunCommand"),
858            },
859            Some(CommandName::WebRequest) => match protobuf_plugin_command.payload {
860                Some(Payload::WebRequestPayload(web_request_payload)) => {
861                    let context: BTreeMap<String, String> = web_request_payload
862                        .context
863                        .into_iter()
864                        .map(|e| (e.name, e.value))
865                        .collect();
866                    let headers: BTreeMap<String, String> = web_request_payload
867                        .headers
868                        .into_iter()
869                        .map(|e| (e.name, e.value))
870                        .collect();
871                    let verb = match ProtobufHttpVerb::from_i32(web_request_payload.verb) {
872                        Some(verb) => verb.into(),
873                        None => {
874                            return Err("Unrecognized http verb");
875                        },
876                    };
877                    Ok(PluginCommand::WebRequest(
878                        web_request_payload.url,
879                        verb,
880                        headers,
881                        web_request_payload.body,
882                        context,
883                    ))
884                },
885                _ => Err("Mismatched payload for WebRequest"),
886            },
887            Some(CommandName::DeleteDeadSession) => match protobuf_plugin_command.payload {
888                Some(Payload::DeleteDeadSessionPayload(dead_session_name)) => {
889                    Ok(PluginCommand::DeleteDeadSession(dead_session_name))
890                },
891                _ => Err("Mismatched payload for DeleteDeadSession"),
892            },
893            Some(CommandName::DeleteAllDeadSessions) => Ok(PluginCommand::DeleteAllDeadSessions),
894            Some(CommandName::RenameSession) => match protobuf_plugin_command.payload {
895                Some(Payload::RenameSessionPayload(new_session_name)) => {
896                    Ok(PluginCommand::RenameSession(new_session_name))
897                },
898                _ => Err("Mismatched payload for RenameSession"),
899            },
900            Some(CommandName::UnblockCliPipeInput) => match protobuf_plugin_command.payload {
901                Some(Payload::UnblockCliPipeInputPayload(pipe_name)) => {
902                    Ok(PluginCommand::UnblockCliPipeInput(pipe_name))
903                },
904                _ => Err("Mismatched payload for UnblockPipeInput"),
905            },
906            Some(CommandName::BlockCliPipeInput) => match protobuf_plugin_command.payload {
907                Some(Payload::BlockCliPipeInputPayload(pipe_name)) => {
908                    Ok(PluginCommand::BlockCliPipeInput(pipe_name))
909                },
910                _ => Err("Mismatched payload for BlockPipeInput"),
911            },
912            Some(CommandName::CliPipeOutput) => match protobuf_plugin_command.payload {
913                Some(Payload::CliPipeOutputPayload(CliPipeOutputPayload { pipe_name, output })) => {
914                    Ok(PluginCommand::CliPipeOutput(pipe_name, output))
915                },
916                _ => Err("Mismatched payload for PipeOutput"),
917            },
918            Some(CommandName::MessageToPlugin) => match protobuf_plugin_command.payload {
919                Some(Payload::MessageToPluginPayload(MessageToPluginPayload {
920                    plugin_url,
921                    plugin_config,
922                    message_name,
923                    message_payload,
924                    message_args,
925                    new_plugin_args,
926                    destination_plugin_id,
927                })) => {
928                    let plugin_config: BTreeMap<String, String> = plugin_config
929                        .into_iter()
930                        .map(|e| (e.name, e.value))
931                        .collect();
932                    let message_args: BTreeMap<String, String> = message_args
933                        .into_iter()
934                        .map(|e| (e.name, e.value))
935                        .collect();
936                    Ok(PluginCommand::MessageToPlugin(MessageToPlugin {
937                        plugin_url,
938                        plugin_config,
939                        message_name,
940                        message_payload,
941                        message_args,
942                        new_plugin_args: new_plugin_args.and_then(|protobuf_new_plugin_args| {
943                            Some(NewPluginArgs {
944                                should_float: protobuf_new_plugin_args.should_float,
945                                pane_id_to_replace: protobuf_new_plugin_args
946                                    .pane_id_to_replace
947                                    .and_then(|p_id| PaneId::try_from(p_id).ok()),
948                                pane_title: protobuf_new_plugin_args.pane_title,
949                                cwd: protobuf_new_plugin_args.cwd.map(|cwd| PathBuf::from(cwd)),
950                                skip_cache: protobuf_new_plugin_args.skip_cache,
951                            })
952                        }),
953                        destination_plugin_id,
954                    }))
955                },
956                _ => Err("Mismatched payload for MessageToPlugin"),
957            },
958            Some(CommandName::DisconnectOtherClients) => match protobuf_plugin_command.payload {
959                None => Ok(PluginCommand::DisconnectOtherClients),
960                _ => Err("Mismatched payload for DisconnectOtherClients"),
961            },
962            Some(CommandName::KillSessions) => match protobuf_plugin_command.payload {
963                Some(Payload::KillSessionsPayload(KillSessionsPayload { session_names })) => {
964                    Ok(PluginCommand::KillSessions(session_names))
965                },
966                _ => Err("Mismatched payload for KillSessions"),
967            },
968            Some(CommandName::ScanHostFolder) => match protobuf_plugin_command.payload {
969                Some(Payload::ScanHostFolderPayload(folder_to_scan)) => {
970                    Ok(PluginCommand::ScanHostFolder(PathBuf::from(folder_to_scan)))
971                },
972                _ => Err("Mismatched payload for ScanHostFolder"),
973            },
974            Some(CommandName::WatchFilesystem) => match protobuf_plugin_command.payload {
975                Some(_) => Err("WatchFilesystem should have no payload, found a payload"),
976                None => Ok(PluginCommand::WatchFilesystem),
977            },
978            Some(CommandName::DumpSessionLayout) => match protobuf_plugin_command.payload {
979                Some(_) => Err("DumpSessionLayout should have no payload, found a payload"),
980                None => Ok(PluginCommand::DumpSessionLayout),
981            },
982            Some(CommandName::CloseSelf) => match protobuf_plugin_command.payload {
983                Some(_) => Err("CloseSelf should have no payload, found a payload"),
984                None => Ok(PluginCommand::CloseSelf),
985            },
986            Some(CommandName::NewTabsWithLayoutInfo) => match protobuf_plugin_command.payload {
987                Some(Payload::NewTabsWithLayoutInfoPayload(new_tabs_with_layout_info_payload)) => {
988                    new_tabs_with_layout_info_payload
989                        .layout_info
990                        .and_then(|layout_info| {
991                            Some(PluginCommand::NewTabsWithLayoutInfo(
992                                layout_info.try_into().ok()?,
993                            ))
994                        })
995                        .ok_or("Failed to parse NewTabsWithLayoutInfo command")
996                },
997                _ => Err("Mismatched payload for NewTabsWithLayoutInfo"),
998            },
999            Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
1000                Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
1001                    Ok(PluginCommand::Reconfigure(
1002                        reconfigure_payload.config,
1003                        reconfigure_payload.write_to_disk,
1004                    ))
1005                },
1006                _ => Err("Mismatched payload for Reconfigure"),
1007            },
1008            Some(CommandName::HidePaneWithId) => match protobuf_plugin_command.payload {
1009                Some(Payload::HidePaneWithIdPayload(hide_pane_with_id_payload)) => {
1010                    let pane_id = hide_pane_with_id_payload
1011                        .pane_id
1012                        .and_then(|p_id| PaneId::try_from(p_id).ok())
1013                        .ok_or("Failed to parse HidePaneWithId command")?;
1014                    Ok(PluginCommand::HidePaneWithId(pane_id))
1015                },
1016                _ => Err("Mismatched payload for HidePaneWithId"),
1017            },
1018            Some(CommandName::ShowPaneWithId) => match protobuf_plugin_command.payload {
1019                Some(Payload::ShowPaneWithIdPayload(show_pane_with_id_payload)) => {
1020                    let pane_id = show_pane_with_id_payload
1021                        .pane_id
1022                        .and_then(|p_id| PaneId::try_from(p_id).ok())
1023                        .ok_or("Failed to parse ShowPaneWithId command")?;
1024                    let should_float_if_hidden = show_pane_with_id_payload.should_float_if_hidden;
1025                    Ok(PluginCommand::ShowPaneWithId(
1026                        pane_id,
1027                        should_float_if_hidden,
1028                    ))
1029                },
1030                _ => Err("Mismatched payload for ShowPaneWithId"),
1031            },
1032            Some(CommandName::OpenCommandPaneBackground) => match protobuf_plugin_command.payload {
1033                Some(Payload::OpenCommandPaneBackgroundPayload(command_to_run_payload)) => {
1034                    match command_to_run_payload.command_to_run {
1035                        Some(command_to_run) => {
1036                            let context: BTreeMap<String, String> = command_to_run_payload
1037                                .context
1038                                .into_iter()
1039                                .map(|e| (e.name, e.value))
1040                                .collect();
1041                            Ok(PluginCommand::OpenCommandPaneBackground(
1042                                command_to_run.try_into()?,
1043                                context,
1044                            ))
1045                        },
1046                        None => Err("Malformed open command pane background payload"),
1047                    }
1048                },
1049                _ => Err("Mismatched payload for OpenCommandPaneBackground"),
1050            },
1051            Some(CommandName::RerunCommandPane) => match protobuf_plugin_command.payload {
1052                Some(Payload::RerunCommandPanePayload(rerun_command_pane_payload)) => Ok(
1053                    PluginCommand::RerunCommandPane(rerun_command_pane_payload.terminal_pane_id),
1054                ),
1055                _ => Err("Mismatched payload for RerunCommandPane"),
1056            },
1057            Some(CommandName::ResizePaneIdWithDirection) => match protobuf_plugin_command.payload {
1058                Some(Payload::ResizePaneIdWithDirectionPayload(resize_with_direction_payload)) => {
1059                    match (
1060                        resize_with_direction_payload.resize,
1061                        resize_with_direction_payload.pane_id,
1062                    ) {
1063                        (Some(resize), Some(pane_id)) => {
1064                            Ok(PluginCommand::ResizePaneIdWithDirection(
1065                                resize.try_into()?,
1066                                pane_id.try_into()?,
1067                            ))
1068                        },
1069                        _ => Err("Malformed resize_pane_with_id payload"),
1070                    }
1071                },
1072                _ => Err("Mismatched payload for Resize"),
1073            },
1074            Some(CommandName::EditScrollbackForPaneWithId) => match protobuf_plugin_command.payload
1075            {
1076                Some(Payload::EditScrollbackForPaneWithIdPayload(
1077                    edit_scrollback_for_pane_with_id_payload,
1078                )) => match edit_scrollback_for_pane_with_id_payload.pane_id {
1079                    Some(pane_id) => Ok(PluginCommand::EditScrollbackForPaneWithId(
1080                        pane_id.try_into()?,
1081                    )),
1082                    _ => Err("Malformed edit_scrollback_for_pane_with_id payload"),
1083                },
1084                _ => Err("Mismatched payload for EditScrollback"),
1085            },
1086            Some(CommandName::WriteToPaneId) => match protobuf_plugin_command.payload {
1087                Some(Payload::WriteToPaneIdPayload(write_to_pane_id_payload)) => {
1088                    match write_to_pane_id_payload.pane_id {
1089                        Some(pane_id) => Ok(PluginCommand::WriteToPaneId(
1090                            write_to_pane_id_payload.bytes_to_write,
1091                            pane_id.try_into()?,
1092                        )),
1093                        _ => Err("Malformed write_to_pane_id payload"),
1094                    }
1095                },
1096                _ => Err("Mismatched payload for WriteToPaneId"),
1097            },
1098            Some(CommandName::WriteCharsToPaneId) => match protobuf_plugin_command.payload {
1099                Some(Payload::WriteCharsToPaneIdPayload(write_chars_to_pane_id_payload)) => {
1100                    match write_chars_to_pane_id_payload.pane_id {
1101                        Some(pane_id) => Ok(PluginCommand::WriteCharsToPaneId(
1102                            write_chars_to_pane_id_payload.chars_to_write,
1103                            pane_id.try_into()?,
1104                        )),
1105                        _ => Err("Malformed write_chars_to_pane_id payload"),
1106                    }
1107                },
1108                _ => Err("Mismatched payload for WriteCharsCharsToPaneId"),
1109            },
1110            Some(CommandName::MovePaneWithPaneId) => match protobuf_plugin_command.payload {
1111                Some(Payload::MovePaneWithPaneIdPayload(move_pane_with_pane_id_payload)) => {
1112                    match move_pane_with_pane_id_payload.pane_id {
1113                        Some(pane_id) => Ok(PluginCommand::MovePaneWithPaneId(pane_id.try_into()?)),
1114                        _ => Err("Malformed move_pane_with_pane_id payload"),
1115                    }
1116                },
1117                _ => Err("Mismatched payload for MovePaneWithPaneId"),
1118            },
1119            Some(CommandName::MovePaneWithPaneIdInDirection) => {
1120                match protobuf_plugin_command.payload {
1121                    Some(Payload::MovePaneWithPaneIdInDirectionPayload(move_payload)) => {
1122                        match (move_payload.direction, move_payload.pane_id) {
1123                            (Some(direction), Some(pane_id)) => {
1124                                Ok(PluginCommand::MovePaneWithPaneIdInDirection(
1125                                    pane_id.try_into()?,
1126                                    direction.try_into()?,
1127                                ))
1128                            },
1129                            _ => Err("Malformed MovePaneWithPaneIdInDirection payload"),
1130                        }
1131                    },
1132                    _ => Err("Mismatched payload for MovePaneWithDirection"),
1133                }
1134            },
1135            Some(CommandName::ClearScreenForPaneId) => match protobuf_plugin_command.payload {
1136                Some(Payload::ClearScreenForPaneIdPayload(clear_screen_for_pane_id_payload)) => {
1137                    match clear_screen_for_pane_id_payload.pane_id {
1138                        Some(pane_id) => {
1139                            Ok(PluginCommand::ClearScreenForPaneId(pane_id.try_into()?))
1140                        },
1141                        _ => Err("Malformed clear_screen_for_pane_id_payload payload"),
1142                    }
1143                },
1144                _ => Err("Mismatched payload for ClearScreenForPaneId"),
1145            },
1146            Some(CommandName::ScrollUpInPaneId) => match protobuf_plugin_command.payload {
1147                Some(Payload::ScrollUpInPaneIdPayload(scroll_up_in_pane_id_payload)) => {
1148                    match scroll_up_in_pane_id_payload.pane_id {
1149                        Some(pane_id) => Ok(PluginCommand::ScrollUpInPaneId(pane_id.try_into()?)),
1150                        _ => Err("Malformed scroll_up_in_pane_id_payload payload"),
1151                    }
1152                },
1153                _ => Err("Mismatched payload for ScrollUpInPaneId"),
1154            },
1155            Some(CommandName::ScrollDownInPaneId) => match protobuf_plugin_command.payload {
1156                Some(Payload::ScrollDownInPaneIdPayload(scroll_down_in_pane_id_payload)) => {
1157                    match scroll_down_in_pane_id_payload.pane_id {
1158                        Some(pane_id) => Ok(PluginCommand::ScrollDownInPaneId(pane_id.try_into()?)),
1159                        _ => Err("Malformed scroll_down_in_pane_id_payload payload"),
1160                    }
1161                },
1162                _ => Err("Mismatched payload for ScrollDownInPaneId"),
1163            },
1164            Some(CommandName::ScrollToTopInPaneId) => match protobuf_plugin_command.payload {
1165                Some(Payload::ScrollToTopInPaneIdPayload(scroll_to_top_in_pane_id_payload)) => {
1166                    match scroll_to_top_in_pane_id_payload.pane_id {
1167                        Some(pane_id) => {
1168                            Ok(PluginCommand::ScrollToTopInPaneId(pane_id.try_into()?))
1169                        },
1170                        _ => Err("Malformed scroll_to_top_in_pane_id_payload payload"),
1171                    }
1172                },
1173                _ => Err("Mismatched payload for ScrollToTopInPaneId"),
1174            },
1175            Some(CommandName::ScrollToBottomInPaneId) => match protobuf_plugin_command.payload {
1176                Some(Payload::ScrollToBottomInPaneIdPayload(
1177                    scroll_to_bottom_in_pane_id_payload,
1178                )) => match scroll_to_bottom_in_pane_id_payload.pane_id {
1179                    Some(pane_id) => Ok(PluginCommand::ScrollToBottomInPaneId(pane_id.try_into()?)),
1180                    _ => Err("Malformed scroll_to_bottom_in_pane_id_payload payload"),
1181                },
1182                _ => Err("Mismatched payload for ScrollToBottomInPaneId"),
1183            },
1184            Some(CommandName::PageScrollUpInPaneId) => match protobuf_plugin_command.payload {
1185                Some(Payload::PageScrollUpInPaneIdPayload(page_scroll_up_in_pane_id_payload)) => {
1186                    match page_scroll_up_in_pane_id_payload.pane_id {
1187                        Some(pane_id) => {
1188                            Ok(PluginCommand::PageScrollUpInPaneId(pane_id.try_into()?))
1189                        },
1190                        _ => Err("Malformed page_scroll_up_in_pane_id_payload payload"),
1191                    }
1192                },
1193                _ => Err("Mismatched payload for PageScrollUpInPaneId"),
1194            },
1195            Some(CommandName::PageScrollDownInPaneId) => match protobuf_plugin_command.payload {
1196                Some(Payload::PageScrollDownInPaneIdPayload(
1197                    page_scroll_down_in_pane_id_payload,
1198                )) => match page_scroll_down_in_pane_id_payload.pane_id {
1199                    Some(pane_id) => Ok(PluginCommand::PageScrollDownInPaneId(pane_id.try_into()?)),
1200                    _ => Err("Malformed page_scroll_down_in_pane_id_payload payload"),
1201                },
1202                _ => Err("Mismatched payload for PageScrollDownInPaneId"),
1203            },
1204            Some(CommandName::TogglePaneIdFullscreen) => match protobuf_plugin_command.payload {
1205                Some(Payload::TogglePaneIdFullscreenPayload(toggle_pane_id_fullscreen_payload)) => {
1206                    match toggle_pane_id_fullscreen_payload.pane_id {
1207                        Some(pane_id) => {
1208                            Ok(PluginCommand::TogglePaneIdFullscreen(pane_id.try_into()?))
1209                        },
1210                        _ => Err("Malformed toggle_pane_id_fullscreen_payload payload"),
1211                    }
1212                },
1213                _ => Err("Mismatched payload for TogglePaneIdFullscreen"),
1214            },
1215            Some(CommandName::TogglePaneEmbedOrEjectForPaneId) => {
1216                match protobuf_plugin_command.payload {
1217                    Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
1218                        toggle_pane_embed_or_eject_payload,
1219                    )) => match toggle_pane_embed_or_eject_payload.pane_id {
1220                        Some(pane_id) => Ok(PluginCommand::TogglePaneEmbedOrEjectForPaneId(
1221                            pane_id.try_into()?,
1222                        )),
1223                        _ => Err("Malformed toggle_pane_embed_or_eject_payload payload"),
1224                    },
1225                    _ => Err("Mismatched payload for TogglePaneEmbedOrEjectForPaneId"),
1226                }
1227            },
1228            Some(CommandName::CloseTabWithIndex) => match protobuf_plugin_command.payload {
1229                Some(Payload::CloseTabWithIndexPayload(close_tab_index_payload)) => Ok(
1230                    PluginCommand::CloseTabWithIndex(close_tab_index_payload.tab_index as usize),
1231                ),
1232                _ => Err("Mismatched payload for CloseTabWithIndex"),
1233            },
1234            Some(CommandName::BreakPanesToNewTab) => match protobuf_plugin_command.payload {
1235                Some(Payload::BreakPanesToNewTabPayload(break_panes_to_new_tab_payload)) => {
1236                    Ok(PluginCommand::BreakPanesToNewTab(
1237                        break_panes_to_new_tab_payload
1238                            .pane_ids
1239                            .into_iter()
1240                            .filter_map(|p_id| p_id.try_into().ok())
1241                            .collect(),
1242                        break_panes_to_new_tab_payload.new_tab_name,
1243                        break_panes_to_new_tab_payload.should_change_focus_to_new_tab,
1244                    ))
1245                },
1246                _ => Err("Mismatched payload for BreakPanesToNewTab"),
1247            },
1248            Some(CommandName::BreakPanesToTabWithIndex) => match protobuf_plugin_command.payload {
1249                Some(Payload::BreakPanesToTabWithIndexPayload(
1250                    break_panes_to_tab_with_index_payload,
1251                )) => Ok(PluginCommand::BreakPanesToTabWithIndex(
1252                    break_panes_to_tab_with_index_payload
1253                        .pane_ids
1254                        .into_iter()
1255                        .filter_map(|p_id| p_id.try_into().ok())
1256                        .collect(),
1257                    break_panes_to_tab_with_index_payload.tab_index as usize,
1258                    break_panes_to_tab_with_index_payload.should_change_focus_to_target_tab,
1259                )),
1260                _ => Err("Mismatched payload for BreakPanesToTabWithIndex"),
1261            },
1262            Some(CommandName::ReloadPlugin) => match protobuf_plugin_command.payload {
1263                Some(Payload::ReloadPluginPayload(reload_plugin_payload)) => {
1264                    Ok(PluginCommand::ReloadPlugin(reload_plugin_payload.plugin_id))
1265                },
1266                _ => Err("Mismatched payload for ReloadPlugin"),
1267            },
1268            Some(CommandName::LoadNewPlugin) => match protobuf_plugin_command.payload {
1269                Some(Payload::LoadNewPluginPayload(load_new_plugin_payload)) => {
1270                    Ok(PluginCommand::LoadNewPlugin {
1271                        url: load_new_plugin_payload.plugin_url,
1272                        config: load_new_plugin_payload
1273                            .plugin_config
1274                            .into_iter()
1275                            .map(|e| (e.name, e.value))
1276                            .collect(),
1277                        load_in_background: load_new_plugin_payload
1278                            .should_load_plugin_in_background,
1279                        skip_plugin_cache: load_new_plugin_payload.should_skip_plugin_cache,
1280                    })
1281                },
1282                _ => Err("Mismatched payload for LoadNewPlugin"),
1283            },
1284            Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload {
1285                Some(Payload::RebindKeysPayload(rebind_keys_payload)) => {
1286                    Ok(PluginCommand::RebindKeys {
1287                        keys_to_rebind: rebind_keys_payload
1288                            .keys_to_rebind
1289                            .into_iter()
1290                            .filter_map(|k| key_to_rebind_to_plugin_command_assets(k))
1291                            .collect(),
1292                        keys_to_unbind: rebind_keys_payload
1293                            .keys_to_unbind
1294                            .into_iter()
1295                            .filter_map(|k| key_to_unbind_to_plugin_command_assets(k))
1296                            .collect(),
1297                        write_config_to_disk: rebind_keys_payload.write_config_to_disk,
1298                    })
1299                },
1300                _ => Err("Mismatched payload for RebindKeys"),
1301            },
1302            Some(CommandName::ListClients) => match protobuf_plugin_command.payload {
1303                Some(_) => Err("ListClients should have no payload, found a payload"),
1304                None => Ok(PluginCommand::ListClients),
1305            },
1306            None => Err("Unrecognized plugin command"),
1307        }
1308    }
1309}
1310
1311impl TryFrom<PluginCommand> for ProtobufPluginCommand {
1312    type Error = &'static str;
1313    fn try_from(plugin_command: PluginCommand) -> Result<Self, &'static str> {
1314        match plugin_command {
1315            PluginCommand::Subscribe(subscriptions) => {
1316                let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
1317                Ok(ProtobufPluginCommand {
1318                    name: CommandName::Subscribe as i32,
1319                    payload: Some(Payload::SubscribePayload(SubscribePayload {
1320                        subscriptions: Some(subscriptions),
1321                    })),
1322                })
1323            },
1324            PluginCommand::Unsubscribe(subscriptions) => {
1325                let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
1326                Ok(ProtobufPluginCommand {
1327                    name: CommandName::Unsubscribe as i32,
1328                    payload: Some(Payload::UnsubscribePayload(UnsubscribePayload {
1329                        subscriptions: Some(subscriptions),
1330                    })),
1331                })
1332            },
1333            PluginCommand::SetSelectable(should_be_selectable) => Ok(ProtobufPluginCommand {
1334                name: CommandName::SetSelectable as i32,
1335                payload: Some(Payload::SetSelectablePayload(should_be_selectable)),
1336            }),
1337            PluginCommand::GetPluginIds => Ok(ProtobufPluginCommand {
1338                name: CommandName::GetPluginIds as i32,
1339                payload: None,
1340            }),
1341            PluginCommand::GetZellijVersion => Ok(ProtobufPluginCommand {
1342                name: CommandName::GetZellijVersion as i32,
1343                payload: None,
1344            }),
1345            PluginCommand::OpenFile(file_to_open, context) => Ok(ProtobufPluginCommand {
1346                name: CommandName::OpenFile as i32,
1347                payload: Some(Payload::OpenFilePayload(OpenFilePayload {
1348                    file_to_open: Some(file_to_open.try_into()?),
1349                    floating_pane_coordinates: None,
1350                    context: context
1351                        .into_iter()
1352                        .map(|(name, value)| ContextItem { name, value })
1353                        .collect(),
1354                })),
1355            }),
1356            PluginCommand::OpenFileFloating(file_to_open, floating_pane_coordinates, context) => {
1357                Ok(ProtobufPluginCommand {
1358                    name: CommandName::OpenFileFloating as i32,
1359                    payload: Some(Payload::OpenFileFloatingPayload(OpenFilePayload {
1360                        file_to_open: Some(file_to_open.try_into()?),
1361                        floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
1362                        context: context
1363                            .into_iter()
1364                            .map(|(name, value)| ContextItem { name, value })
1365                            .collect(),
1366                    })),
1367                })
1368            },
1369            PluginCommand::OpenTerminal(cwd) => Ok(ProtobufPluginCommand {
1370                name: CommandName::OpenTerminal as i32,
1371                payload: Some(Payload::OpenTerminalPayload(OpenFilePayload {
1372                    file_to_open: Some(cwd.try_into()?),
1373                    floating_pane_coordinates: None,
1374                    context: vec![], // will be added in the future
1375                })),
1376            }),
1377            PluginCommand::OpenTerminalFloating(cwd, floating_pane_coordinates) => {
1378                Ok(ProtobufPluginCommand {
1379                    name: CommandName::OpenTerminalFloating as i32,
1380                    payload: Some(Payload::OpenTerminalFloatingPayload(OpenFilePayload {
1381                        file_to_open: Some(cwd.try_into()?),
1382                        floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
1383                        context: vec![], // will be added in the future
1384                    })),
1385                })
1386            },
1387            PluginCommand::OpenCommandPane(command_to_run, context) => {
1388                let context: Vec<_> = context
1389                    .into_iter()
1390                    .map(|(name, value)| ContextItem { name, value })
1391                    .collect();
1392                Ok(ProtobufPluginCommand {
1393                    name: CommandName::OpenCommandPane as i32,
1394                    payload: Some(Payload::OpenCommandPanePayload(OpenCommandPanePayload {
1395                        command_to_run: Some(command_to_run.try_into()?),
1396                        floating_pane_coordinates: None,
1397                        context,
1398                    })),
1399                })
1400            },
1401            PluginCommand::OpenCommandPaneFloating(
1402                command_to_run,
1403                floating_pane_coordinates,
1404                context,
1405            ) => {
1406                let context: Vec<_> = context
1407                    .into_iter()
1408                    .map(|(name, value)| ContextItem { name, value })
1409                    .collect();
1410                Ok(ProtobufPluginCommand {
1411                    name: CommandName::OpenCommandPaneFloating as i32,
1412                    payload: Some(Payload::OpenCommandPaneFloatingPayload(
1413                        OpenCommandPanePayload {
1414                            command_to_run: Some(command_to_run.try_into()?),
1415                            floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
1416                            context,
1417                        },
1418                    )),
1419                })
1420            },
1421            PluginCommand::SwitchTabTo(tab_index) => Ok(ProtobufPluginCommand {
1422                name: CommandName::SwitchTabTo as i32,
1423                payload: Some(Payload::SwitchTabToPayload(SwitchTabToPayload {
1424                    tab_index: tab_index,
1425                })),
1426            }),
1427            PluginCommand::SetTimeout(seconds) => Ok(ProtobufPluginCommand {
1428                name: CommandName::SetTimeout as i32,
1429                payload: Some(Payload::SetTimeoutPayload(SetTimeoutPayload { seconds })),
1430            }),
1431            PluginCommand::ExecCmd(command_line) => Ok(ProtobufPluginCommand {
1432                name: CommandName::ExecCmd as i32,
1433                payload: Some(Payload::ExecCmdPayload(ExecCmdPayload { command_line })),
1434            }),
1435            PluginCommand::PostMessageTo(plugin_message) => Ok(ProtobufPluginCommand {
1436                name: CommandName::PostMessageTo as i32,
1437                payload: Some(Payload::PostMessageToPayload(PluginMessagePayload {
1438                    message: Some(plugin_message.try_into()?),
1439                })),
1440            }),
1441            PluginCommand::PostMessageToPlugin(plugin_message) => Ok(ProtobufPluginCommand {
1442                name: CommandName::PostMessageToPlugin as i32,
1443                payload: Some(Payload::PostMessageToPluginPayload(PluginMessagePayload {
1444                    message: Some(plugin_message.try_into()?),
1445                })),
1446            }),
1447            PluginCommand::HideSelf => Ok(ProtobufPluginCommand {
1448                name: CommandName::HideSelf as i32,
1449                payload: None,
1450            }),
1451            PluginCommand::ShowSelf(should_float_if_hidden) => Ok(ProtobufPluginCommand {
1452                name: CommandName::ShowSelf as i32,
1453                payload: Some(Payload::ShowSelfPayload(should_float_if_hidden)),
1454            }),
1455            PluginCommand::SwitchToMode(input_mode) => Ok(ProtobufPluginCommand {
1456                name: CommandName::SwitchToMode as i32,
1457                payload: Some(Payload::SwitchToModePayload(SwitchToModePayload {
1458                    input_mode: ProtobufInputMode::try_from(input_mode)? as i32,
1459                })),
1460            }),
1461            PluginCommand::NewTabsWithLayout(raw_layout) => Ok(ProtobufPluginCommand {
1462                name: CommandName::NewTabsWithLayout as i32,
1463                payload: Some(Payload::NewTabsWithLayoutPayload(raw_layout)),
1464            }),
1465            PluginCommand::NewTab => Ok(ProtobufPluginCommand {
1466                name: CommandName::NewTab as i32,
1467                payload: None,
1468            }),
1469            PluginCommand::GoToNextTab => Ok(ProtobufPluginCommand {
1470                name: CommandName::GoToNextTab as i32,
1471                payload: None,
1472            }),
1473            PluginCommand::GoToPreviousTab => Ok(ProtobufPluginCommand {
1474                name: CommandName::GoToPreviousTab as i32,
1475                payload: None,
1476            }),
1477            PluginCommand::Resize(resize) => Ok(ProtobufPluginCommand {
1478                name: CommandName::Resize as i32,
1479                payload: Some(Payload::ResizePayload(ResizePayload {
1480                    resize: Some(resize.try_into()?),
1481                })),
1482            }),
1483            PluginCommand::ResizeWithDirection(resize) => Ok(ProtobufPluginCommand {
1484                name: CommandName::ResizeWithDirection as i32,
1485                payload: Some(Payload::ResizeWithDirectionPayload(ResizePayload {
1486                    resize: Some(resize.try_into()?),
1487                })),
1488            }),
1489            PluginCommand::FocusNextPane => Ok(ProtobufPluginCommand {
1490                name: CommandName::FocusNextPane as i32,
1491                payload: None,
1492            }),
1493            PluginCommand::FocusPreviousPane => Ok(ProtobufPluginCommand {
1494                name: CommandName::FocusPreviousPane as i32,
1495                payload: None,
1496            }),
1497            PluginCommand::MoveFocus(direction) => Ok(ProtobufPluginCommand {
1498                name: CommandName::MoveFocus as i32,
1499                payload: Some(Payload::MoveFocusPayload(MovePayload {
1500                    direction: Some(direction.try_into()?),
1501                })),
1502            }),
1503            PluginCommand::MoveFocusOrTab(direction) => Ok(ProtobufPluginCommand {
1504                name: CommandName::MoveFocusOrTab as i32,
1505                payload: Some(Payload::MoveFocusOrTabPayload(MovePayload {
1506                    direction: Some(direction.try_into()?),
1507                })),
1508            }),
1509            PluginCommand::Detach => Ok(ProtobufPluginCommand {
1510                name: CommandName::Detach as i32,
1511                payload: None,
1512            }),
1513            PluginCommand::EditScrollback => Ok(ProtobufPluginCommand {
1514                name: CommandName::EditScrollback as i32,
1515                payload: None,
1516            }),
1517            PluginCommand::Write(bytes) => Ok(ProtobufPluginCommand {
1518                name: CommandName::Write as i32,
1519                payload: Some(Payload::WritePayload(bytes)),
1520            }),
1521            PluginCommand::WriteChars(chars) => Ok(ProtobufPluginCommand {
1522                name: CommandName::WriteChars as i32,
1523                payload: Some(Payload::WriteCharsPayload(chars)),
1524            }),
1525            PluginCommand::ToggleTab => Ok(ProtobufPluginCommand {
1526                name: CommandName::ToggleTab as i32,
1527                payload: None,
1528            }),
1529            PluginCommand::MovePane => Ok(ProtobufPluginCommand {
1530                name: CommandName::MovePane as i32,
1531                payload: None,
1532            }),
1533            PluginCommand::MovePaneWithDirection(direction) => Ok(ProtobufPluginCommand {
1534                name: CommandName::MovePaneWithDirection as i32,
1535                payload: Some(Payload::MovePaneWithDirectionPayload(MovePayload {
1536                    direction: Some(direction.try_into()?),
1537                })),
1538            }),
1539            PluginCommand::ClearScreen => Ok(ProtobufPluginCommand {
1540                name: CommandName::ClearScreen as i32,
1541                payload: None,
1542            }),
1543            PluginCommand::ScrollUp => Ok(ProtobufPluginCommand {
1544                name: CommandName::ScrollUp as i32,
1545                payload: None,
1546            }),
1547            PluginCommand::ScrollDown => Ok(ProtobufPluginCommand {
1548                name: CommandName::ScrollDown as i32,
1549                payload: None,
1550            }),
1551            PluginCommand::ScrollToTop => Ok(ProtobufPluginCommand {
1552                name: CommandName::ScrollToTop as i32,
1553                payload: None,
1554            }),
1555            PluginCommand::ScrollToBottom => Ok(ProtobufPluginCommand {
1556                name: CommandName::ScrollToBottom as i32,
1557                payload: None,
1558            }),
1559            PluginCommand::PageScrollUp => Ok(ProtobufPluginCommand {
1560                name: CommandName::PageScrollUp as i32,
1561                payload: None,
1562            }),
1563            PluginCommand::PageScrollDown => Ok(ProtobufPluginCommand {
1564                name: CommandName::PageScrollDown as i32,
1565                payload: None,
1566            }),
1567            PluginCommand::ToggleFocusFullscreen => Ok(ProtobufPluginCommand {
1568                name: CommandName::ToggleFocusFullscreen as i32,
1569                payload: None,
1570            }),
1571            PluginCommand::TogglePaneFrames => Ok(ProtobufPluginCommand {
1572                name: CommandName::TogglePaneFrames as i32,
1573                payload: None,
1574            }),
1575            PluginCommand::TogglePaneEmbedOrEject => Ok(ProtobufPluginCommand {
1576                name: CommandName::TogglePaneEmbedOrEject as i32,
1577                payload: None,
1578            }),
1579            PluginCommand::UndoRenamePane => Ok(ProtobufPluginCommand {
1580                name: CommandName::UndoRenamePane as i32,
1581                payload: None,
1582            }),
1583            PluginCommand::CloseFocus => Ok(ProtobufPluginCommand {
1584                name: CommandName::CloseFocus as i32,
1585                payload: None,
1586            }),
1587            PluginCommand::ToggleActiveTabSync => Ok(ProtobufPluginCommand {
1588                name: CommandName::ToggleActiveTabSync as i32,
1589                payload: None,
1590            }),
1591            PluginCommand::CloseFocusedTab => Ok(ProtobufPluginCommand {
1592                name: CommandName::CloseFocusedTab as i32,
1593                payload: None,
1594            }),
1595            PluginCommand::UndoRenameTab => Ok(ProtobufPluginCommand {
1596                name: CommandName::UndoRenameTab as i32,
1597                payload: None,
1598            }),
1599            PluginCommand::QuitZellij => Ok(ProtobufPluginCommand {
1600                name: CommandName::QuitZellij as i32,
1601                payload: None,
1602            }),
1603            PluginCommand::PreviousSwapLayout => Ok(ProtobufPluginCommand {
1604                name: CommandName::PreviousSwapLayout as i32,
1605                payload: None,
1606            }),
1607            PluginCommand::NextSwapLayout => Ok(ProtobufPluginCommand {
1608                name: CommandName::NextSwapLayout as i32,
1609                payload: None,
1610            }),
1611            PluginCommand::GoToTabName(tab_name) => Ok(ProtobufPluginCommand {
1612                name: CommandName::GoToTabName as i32,
1613                payload: Some(Payload::GoToTabNamePayload(tab_name)),
1614            }),
1615            PluginCommand::FocusOrCreateTab(tab_name) => Ok(ProtobufPluginCommand {
1616                name: CommandName::FocusOrCreateTab as i32,
1617                payload: Some(Payload::FocusOrCreateTabPayload(tab_name)),
1618            }),
1619            PluginCommand::GoToTab(tab_index) => Ok(ProtobufPluginCommand {
1620                name: CommandName::GoToTab as i32,
1621                payload: Some(Payload::GoToTabPayload(tab_index)),
1622            }),
1623            PluginCommand::StartOrReloadPlugin(url) => Ok(ProtobufPluginCommand {
1624                name: CommandName::StartOrReloadPlugin as i32,
1625                payload: Some(Payload::StartOrReloadPluginPayload(url)),
1626            }),
1627            PluginCommand::CloseTerminalPane(pane_id) => Ok(ProtobufPluginCommand {
1628                name: CommandName::CloseTerminalPane as i32,
1629                payload: Some(Payload::CloseTerminalPanePayload(pane_id)),
1630            }),
1631            PluginCommand::ClosePluginPane(pane_id) => Ok(ProtobufPluginCommand {
1632                name: CommandName::ClosePluginPane as i32,
1633                payload: Some(Payload::ClosePluginPanePayload(pane_id)),
1634            }),
1635            PluginCommand::FocusTerminalPane(pane_id, should_float_if_hidden) => {
1636                Ok(ProtobufPluginCommand {
1637                    name: CommandName::FocusTerminalPane as i32,
1638                    payload: Some(Payload::FocusTerminalPanePayload(PaneIdAndShouldFloat {
1639                        pane_id: pane_id,
1640                        should_float: should_float_if_hidden,
1641                    })),
1642                })
1643            },
1644            PluginCommand::FocusPluginPane(pane_id, should_float_if_hidden) => {
1645                Ok(ProtobufPluginCommand {
1646                    name: CommandName::FocusPluginPane as i32,
1647                    payload: Some(Payload::FocusPluginPanePayload(PaneIdAndShouldFloat {
1648                        pane_id: pane_id,
1649                        should_float: should_float_if_hidden,
1650                    })),
1651                })
1652            },
1653            PluginCommand::RenameTerminalPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
1654                name: CommandName::RenameTerminalPane as i32,
1655                payload: Some(Payload::RenameTerminalPanePayload(IdAndNewName {
1656                    id: pane_id,
1657                    new_name,
1658                })),
1659            }),
1660            PluginCommand::RenamePluginPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
1661                name: CommandName::RenamePluginPane as i32,
1662                payload: Some(Payload::RenamePluginPanePayload(IdAndNewName {
1663                    id: pane_id,
1664                    new_name,
1665                })),
1666            }),
1667            PluginCommand::RenameTab(tab_index, new_name) => Ok(ProtobufPluginCommand {
1668                name: CommandName::RenameTab as i32,
1669                payload: Some(Payload::RenameTabPayload(IdAndNewName {
1670                    id: tab_index,
1671                    new_name,
1672                })),
1673            }),
1674            PluginCommand::ReportPanic(payload) => Ok(ProtobufPluginCommand {
1675                name: CommandName::ReportCrash as i32,
1676                payload: Some(Payload::ReportCrashPayload(payload)),
1677            }),
1678            PluginCommand::RequestPluginPermissions(permissions) => Ok(ProtobufPluginCommand {
1679                name: CommandName::RequestPluginPermissions as i32,
1680                payload: Some(Payload::RequestPluginPermissionPayload(
1681                    RequestPluginPermissionPayload {
1682                        permissions: permissions
1683                            .iter()
1684                            .filter_map(|p| ProtobufPermissionType::try_from(*p).ok())
1685                            .map(|p| p as i32)
1686                            .collect(),
1687                    },
1688                )),
1689            }),
1690            PluginCommand::SwitchSession(switch_to_session) => Ok(ProtobufPluginCommand {
1691                name: CommandName::SwitchSession as i32,
1692                payload: Some(Payload::SwitchSessionPayload(SwitchSessionPayload {
1693                    name: switch_to_session.name,
1694                    tab_position: switch_to_session.tab_position.map(|t| t as u32),
1695                    pane_id: switch_to_session.pane_id.map(|p| p.0),
1696                    pane_id_is_plugin: switch_to_session.pane_id.map(|p| p.1),
1697                    layout: switch_to_session.layout.and_then(|l| l.try_into().ok()),
1698                    cwd: switch_to_session.cwd.map(|c| c.display().to_string()),
1699                })),
1700            }),
1701            PluginCommand::OpenTerminalInPlace(cwd) => Ok(ProtobufPluginCommand {
1702                name: CommandName::OpenTerminalInPlace as i32,
1703                payload: Some(Payload::OpenTerminalInPlacePayload(OpenFilePayload {
1704                    file_to_open: Some(cwd.try_into()?),
1705                    floating_pane_coordinates: None,
1706                    context: vec![], // will be added in the future
1707                })),
1708            }),
1709            PluginCommand::OpenFileInPlace(file_to_open, context) => Ok(ProtobufPluginCommand {
1710                name: CommandName::OpenFileInPlace as i32,
1711                payload: Some(Payload::OpenFileInPlacePayload(OpenFilePayload {
1712                    file_to_open: Some(file_to_open.try_into()?),
1713                    floating_pane_coordinates: None,
1714                    context: context
1715                        .into_iter()
1716                        .map(|(name, value)| ContextItem { name, value })
1717                        .collect(),
1718                })),
1719            }),
1720            PluginCommand::OpenCommandPaneInPlace(command_to_run, context) => {
1721                let context: Vec<_> = context
1722                    .into_iter()
1723                    .map(|(name, value)| ContextItem { name, value })
1724                    .collect();
1725                Ok(ProtobufPluginCommand {
1726                    name: CommandName::OpenCommandInPlace as i32,
1727                    payload: Some(Payload::OpenCommandPaneInPlacePayload(
1728                        OpenCommandPanePayload {
1729                            command_to_run: Some(command_to_run.try_into()?),
1730                            floating_pane_coordinates: None,
1731                            context,
1732                        },
1733                    )),
1734                })
1735            },
1736            PluginCommand::RunCommand(command_line, env_variables, cwd, context) => {
1737                let env_variables: Vec<_> = env_variables
1738                    .into_iter()
1739                    .map(|(name, value)| EnvVariable { name, value })
1740                    .collect();
1741                let context: Vec<_> = context
1742                    .into_iter()
1743                    .map(|(name, value)| ContextItem { name, value })
1744                    .collect();
1745                let cwd = cwd.display().to_string();
1746                Ok(ProtobufPluginCommand {
1747                    name: CommandName::RunCommand as i32,
1748                    payload: Some(Payload::RunCommandPayload(RunCommandPayload {
1749                        command_line,
1750                        env_variables,
1751                        cwd,
1752                        context,
1753                    })),
1754                })
1755            },
1756            PluginCommand::WebRequest(url, verb, headers, body, context) => {
1757                let context: Vec<_> = context
1758                    .into_iter()
1759                    .map(|(name, value)| ContextItem { name, value })
1760                    .collect();
1761                let headers: Vec<_> = headers
1762                    .into_iter()
1763                    .map(|(name, value)| Header { name, value })
1764                    .collect();
1765                let verb: ProtobufHttpVerb = verb.into();
1766                Ok(ProtobufPluginCommand {
1767                    name: CommandName::WebRequest as i32,
1768                    payload: Some(Payload::WebRequestPayload(WebRequestPayload {
1769                        url,
1770                        verb: verb as i32,
1771                        body,
1772                        headers,
1773                        context,
1774                    })),
1775                })
1776            },
1777            PluginCommand::DeleteDeadSession(dead_session_name) => Ok(ProtobufPluginCommand {
1778                name: CommandName::DeleteDeadSession as i32,
1779                payload: Some(Payload::DeleteDeadSessionPayload(dead_session_name)),
1780            }),
1781            PluginCommand::DeleteAllDeadSessions => Ok(ProtobufPluginCommand {
1782                name: CommandName::DeleteAllDeadSessions as i32,
1783                payload: None,
1784            }),
1785            PluginCommand::RenameSession(new_session_name) => Ok(ProtobufPluginCommand {
1786                name: CommandName::RenameSession as i32,
1787                payload: Some(Payload::RenameSessionPayload(new_session_name)),
1788            }),
1789            PluginCommand::UnblockCliPipeInput(pipe_name) => Ok(ProtobufPluginCommand {
1790                name: CommandName::UnblockCliPipeInput as i32,
1791                payload: Some(Payload::UnblockCliPipeInputPayload(pipe_name)),
1792            }),
1793            PluginCommand::BlockCliPipeInput(pipe_name) => Ok(ProtobufPluginCommand {
1794                name: CommandName::BlockCliPipeInput as i32,
1795                payload: Some(Payload::BlockCliPipeInputPayload(pipe_name)),
1796            }),
1797            PluginCommand::CliPipeOutput(pipe_name, output) => Ok(ProtobufPluginCommand {
1798                name: CommandName::CliPipeOutput as i32,
1799                payload: Some(Payload::CliPipeOutputPayload(CliPipeOutputPayload {
1800                    pipe_name,
1801                    output,
1802                })),
1803            }),
1804            PluginCommand::MessageToPlugin(message_to_plugin) => {
1805                let plugin_config: Vec<_> = message_to_plugin
1806                    .plugin_config
1807                    .into_iter()
1808                    .map(|(name, value)| ContextItem { name, value })
1809                    .collect();
1810                let message_args: Vec<_> = message_to_plugin
1811                    .message_args
1812                    .into_iter()
1813                    .map(|(name, value)| ContextItem { name, value })
1814                    .collect();
1815                Ok(ProtobufPluginCommand {
1816                    name: CommandName::MessageToPlugin as i32,
1817                    payload: Some(Payload::MessageToPluginPayload(MessageToPluginPayload {
1818                        plugin_url: message_to_plugin.plugin_url,
1819                        plugin_config,
1820                        message_name: message_to_plugin.message_name,
1821                        message_payload: message_to_plugin.message_payload,
1822                        message_args,
1823                        new_plugin_args: message_to_plugin.new_plugin_args.map(|m_t_p| {
1824                            ProtobufNewPluginArgs {
1825                                should_float: m_t_p.should_float,
1826                                pane_id_to_replace: m_t_p
1827                                    .pane_id_to_replace
1828                                    .and_then(|p_id| ProtobufPaneId::try_from(p_id).ok()),
1829                                pane_title: m_t_p.pane_title,
1830                                cwd: m_t_p.cwd.map(|cwd| cwd.display().to_string()),
1831                                skip_cache: m_t_p.skip_cache,
1832                            }
1833                        }),
1834                        destination_plugin_id: message_to_plugin.destination_plugin_id,
1835                    })),
1836                })
1837            },
1838            PluginCommand::DisconnectOtherClients => Ok(ProtobufPluginCommand {
1839                name: CommandName::DisconnectOtherClients as i32,
1840                payload: None,
1841            }),
1842            PluginCommand::KillSessions(session_names) => Ok(ProtobufPluginCommand {
1843                name: CommandName::KillSessions as i32,
1844                payload: Some(Payload::KillSessionsPayload(KillSessionsPayload {
1845                    session_names,
1846                })),
1847            }),
1848            PluginCommand::ScanHostFolder(folder_to_scan) => Ok(ProtobufPluginCommand {
1849                name: CommandName::ScanHostFolder as i32,
1850                payload: Some(Payload::ScanHostFolderPayload(
1851                    folder_to_scan.display().to_string(),
1852                )),
1853            }),
1854            PluginCommand::WatchFilesystem => Ok(ProtobufPluginCommand {
1855                name: CommandName::WatchFilesystem as i32,
1856                payload: None,
1857            }),
1858            PluginCommand::DumpSessionLayout => Ok(ProtobufPluginCommand {
1859                name: CommandName::DumpSessionLayout as i32,
1860                payload: None,
1861            }),
1862            PluginCommand::CloseSelf => Ok(ProtobufPluginCommand {
1863                name: CommandName::CloseSelf as i32,
1864                payload: None,
1865            }),
1866            PluginCommand::NewTabsWithLayoutInfo(new_tabs_with_layout_info_payload) => {
1867                Ok(ProtobufPluginCommand {
1868                    name: CommandName::NewTabsWithLayoutInfo as i32,
1869                    payload: Some(Payload::NewTabsWithLayoutInfoPayload(
1870                        NewTabsWithLayoutInfoPayload {
1871                            layout_info: new_tabs_with_layout_info_payload.try_into().ok(),
1872                        },
1873                    )),
1874                })
1875            },
1876            PluginCommand::Reconfigure(config, write_to_disk) => Ok(ProtobufPluginCommand {
1877                name: CommandName::Reconfigure as i32,
1878                payload: Some(Payload::ReconfigurePayload(ReconfigurePayload {
1879                    config,
1880                    write_to_disk,
1881                })),
1882            }),
1883            PluginCommand::HidePaneWithId(pane_id_to_hide) => Ok(ProtobufPluginCommand {
1884                name: CommandName::HidePaneWithId as i32,
1885                payload: Some(Payload::HidePaneWithIdPayload(HidePaneWithIdPayload {
1886                    pane_id: ProtobufPaneId::try_from(pane_id_to_hide).ok(),
1887                })),
1888            }),
1889            PluginCommand::ShowPaneWithId(pane_id_to_show, should_float_if_hidden) => {
1890                Ok(ProtobufPluginCommand {
1891                    name: CommandName::ShowPaneWithId as i32,
1892                    payload: Some(Payload::ShowPaneWithIdPayload(ShowPaneWithIdPayload {
1893                        pane_id: ProtobufPaneId::try_from(pane_id_to_show).ok(),
1894                        should_float_if_hidden,
1895                    })),
1896                })
1897            },
1898            PluginCommand::OpenCommandPaneBackground(command_to_run, context) => {
1899                let context: Vec<_> = context
1900                    .into_iter()
1901                    .map(|(name, value)| ContextItem { name, value })
1902                    .collect();
1903                Ok(ProtobufPluginCommand {
1904                    name: CommandName::OpenCommandPaneBackground as i32,
1905                    payload: Some(Payload::OpenCommandPaneBackgroundPayload(
1906                        OpenCommandPanePayload {
1907                            command_to_run: Some(command_to_run.try_into()?),
1908                            floating_pane_coordinates: None,
1909                            context,
1910                        },
1911                    )),
1912                })
1913            },
1914            PluginCommand::RerunCommandPane(terminal_pane_id) => Ok(ProtobufPluginCommand {
1915                name: CommandName::RerunCommandPane as i32,
1916                payload: Some(Payload::RerunCommandPanePayload(RerunCommandPanePayload {
1917                    terminal_pane_id,
1918                })),
1919            }),
1920            PluginCommand::ResizePaneIdWithDirection(resize, pane_id) => {
1921                Ok(ProtobufPluginCommand {
1922                    name: CommandName::ResizePaneIdWithDirection as i32,
1923                    payload: Some(Payload::ResizePaneIdWithDirectionPayload(
1924                        ResizePaneIdWithDirectionPayload {
1925                            resize: Some(resize.try_into()?),
1926                            pane_id: Some(pane_id.try_into()?),
1927                        },
1928                    )),
1929                })
1930            },
1931            PluginCommand::EditScrollbackForPaneWithId(pane_id) => Ok(ProtobufPluginCommand {
1932                name: CommandName::EditScrollbackForPaneWithId as i32,
1933                payload: Some(Payload::EditScrollbackForPaneWithIdPayload(
1934                    EditScrollbackForPaneWithIdPayload {
1935                        pane_id: Some(pane_id.try_into()?),
1936                    },
1937                )),
1938            }),
1939            PluginCommand::WriteToPaneId(bytes_to_write, pane_id) => Ok(ProtobufPluginCommand {
1940                name: CommandName::WriteToPaneId as i32,
1941                payload: Some(Payload::WriteToPaneIdPayload(WriteToPaneIdPayload {
1942                    bytes_to_write,
1943                    pane_id: Some(pane_id.try_into()?),
1944                })),
1945            }),
1946            PluginCommand::WriteCharsToPaneId(chars_to_write, pane_id) => {
1947                Ok(ProtobufPluginCommand {
1948                    name: CommandName::WriteCharsToPaneId as i32,
1949                    payload: Some(Payload::WriteCharsToPaneIdPayload(
1950                        WriteCharsToPaneIdPayload {
1951                            chars_to_write,
1952                            pane_id: Some(pane_id.try_into()?),
1953                        },
1954                    )),
1955                })
1956            },
1957            PluginCommand::MovePaneWithPaneId(pane_id) => Ok(ProtobufPluginCommand {
1958                name: CommandName::MovePaneWithPaneId as i32,
1959                payload: Some(Payload::MovePaneWithPaneIdPayload(
1960                    MovePaneWithPaneIdPayload {
1961                        pane_id: Some(pane_id.try_into()?),
1962                    },
1963                )),
1964            }),
1965            PluginCommand::MovePaneWithPaneIdInDirection(pane_id, direction) => {
1966                Ok(ProtobufPluginCommand {
1967                    name: CommandName::MovePaneWithPaneIdInDirection as i32,
1968                    payload: Some(Payload::MovePaneWithPaneIdInDirectionPayload(
1969                        MovePaneWithPaneIdInDirectionPayload {
1970                            pane_id: Some(pane_id.try_into()?),
1971                            direction: Some(direction.try_into()?),
1972                        },
1973                    )),
1974                })
1975            },
1976            PluginCommand::ClearScreenForPaneId(pane_id) => Ok(ProtobufPluginCommand {
1977                name: CommandName::ClearScreenForPaneId as i32,
1978                payload: Some(Payload::ClearScreenForPaneIdPayload(
1979                    ClearScreenForPaneIdPayload {
1980                        pane_id: Some(pane_id.try_into()?),
1981                    },
1982                )),
1983            }),
1984            PluginCommand::ScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
1985                name: CommandName::ScrollUpInPaneId as i32,
1986                payload: Some(Payload::ScrollUpInPaneIdPayload(ScrollUpInPaneIdPayload {
1987                    pane_id: Some(pane_id.try_into()?),
1988                })),
1989            }),
1990            PluginCommand::ScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
1991                name: CommandName::ScrollDownInPaneId as i32,
1992                payload: Some(Payload::ScrollDownInPaneIdPayload(
1993                    ScrollDownInPaneIdPayload {
1994                        pane_id: Some(pane_id.try_into()?),
1995                    },
1996                )),
1997            }),
1998            PluginCommand::ScrollToTopInPaneId(pane_id) => Ok(ProtobufPluginCommand {
1999                name: CommandName::ScrollToTopInPaneId as i32,
2000                payload: Some(Payload::ScrollToTopInPaneIdPayload(
2001                    ScrollToTopInPaneIdPayload {
2002                        pane_id: Some(pane_id.try_into()?),
2003                    },
2004                )),
2005            }),
2006            PluginCommand::ScrollToBottomInPaneId(pane_id) => Ok(ProtobufPluginCommand {
2007                name: CommandName::ScrollToBottomInPaneId as i32,
2008                payload: Some(Payload::ScrollToBottomInPaneIdPayload(
2009                    ScrollToBottomInPaneIdPayload {
2010                        pane_id: Some(pane_id.try_into()?),
2011                    },
2012                )),
2013            }),
2014            PluginCommand::PageScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
2015                name: CommandName::PageScrollUpInPaneId as i32,
2016                payload: Some(Payload::PageScrollUpInPaneIdPayload(
2017                    PageScrollUpInPaneIdPayload {
2018                        pane_id: Some(pane_id.try_into()?),
2019                    },
2020                )),
2021            }),
2022            PluginCommand::PageScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
2023                name: CommandName::PageScrollDownInPaneId as i32,
2024                payload: Some(Payload::PageScrollDownInPaneIdPayload(
2025                    PageScrollDownInPaneIdPayload {
2026                        pane_id: Some(pane_id.try_into()?),
2027                    },
2028                )),
2029            }),
2030            PluginCommand::TogglePaneIdFullscreen(pane_id) => Ok(ProtobufPluginCommand {
2031                name: CommandName::TogglePaneIdFullscreen as i32,
2032                payload: Some(Payload::TogglePaneIdFullscreenPayload(
2033                    TogglePaneIdFullscreenPayload {
2034                        pane_id: Some(pane_id.try_into()?),
2035                    },
2036                )),
2037            }),
2038            PluginCommand::TogglePaneEmbedOrEjectForPaneId(pane_id) => Ok(ProtobufPluginCommand {
2039                name: CommandName::TogglePaneEmbedOrEjectForPaneId as i32,
2040                payload: Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
2041                    TogglePaneEmbedOrEjectForPaneIdPayload {
2042                        pane_id: Some(pane_id.try_into()?),
2043                    },
2044                )),
2045            }),
2046            PluginCommand::CloseTabWithIndex(tab_index) => Ok(ProtobufPluginCommand {
2047                name: CommandName::CloseTabWithIndex as i32,
2048                payload: Some(Payload::CloseTabWithIndexPayload(
2049                    CloseTabWithIndexPayload {
2050                        tab_index: tab_index as u32,
2051                    },
2052                )),
2053            }),
2054            PluginCommand::BreakPanesToNewTab(
2055                pane_ids,
2056                new_tab_name,
2057                should_change_focus_to_new_tab,
2058            ) => Ok(ProtobufPluginCommand {
2059                name: CommandName::BreakPanesToNewTab as i32,
2060                payload: Some(Payload::BreakPanesToNewTabPayload(
2061                    BreakPanesToNewTabPayload {
2062                        pane_ids: pane_ids
2063                            .into_iter()
2064                            .filter_map(|p_id| p_id.try_into().ok())
2065                            .collect(),
2066                        should_change_focus_to_new_tab,
2067                        new_tab_name,
2068                    },
2069                )),
2070            }),
2071            PluginCommand::BreakPanesToTabWithIndex(
2072                pane_ids,
2073                tab_index,
2074                should_change_focus_to_target_tab,
2075            ) => Ok(ProtobufPluginCommand {
2076                name: CommandName::BreakPanesToTabWithIndex as i32,
2077                payload: Some(Payload::BreakPanesToTabWithIndexPayload(
2078                    BreakPanesToTabWithIndexPayload {
2079                        pane_ids: pane_ids
2080                            .into_iter()
2081                            .filter_map(|p_id| p_id.try_into().ok())
2082                            .collect(),
2083                        tab_index: tab_index as u32,
2084                        should_change_focus_to_target_tab,
2085                    },
2086                )),
2087            }),
2088            PluginCommand::ReloadPlugin(plugin_id) => Ok(ProtobufPluginCommand {
2089                name: CommandName::ReloadPlugin as i32,
2090                payload: Some(Payload::ReloadPluginPayload(ReloadPluginPayload {
2091                    plugin_id,
2092                })),
2093            }),
2094            PluginCommand::LoadNewPlugin {
2095                url,
2096                config,
2097                load_in_background,
2098                skip_plugin_cache,
2099            } => Ok(ProtobufPluginCommand {
2100                name: CommandName::LoadNewPlugin as i32,
2101                payload: Some(Payload::LoadNewPluginPayload(LoadNewPluginPayload {
2102                    plugin_url: url,
2103                    plugin_config: config
2104                        .into_iter()
2105                        .map(|(name, value)| ContextItem { name, value })
2106                        .collect(),
2107                    should_skip_plugin_cache: skip_plugin_cache,
2108                    should_load_plugin_in_background: load_in_background,
2109                })),
2110            }),
2111            PluginCommand::RebindKeys {
2112                keys_to_rebind,
2113                keys_to_unbind,
2114                write_config_to_disk,
2115            } => Ok(ProtobufPluginCommand {
2116                name: CommandName::RebindKeys as i32,
2117                payload: Some(Payload::RebindKeysPayload(RebindKeysPayload {
2118                    keys_to_rebind: keys_to_rebind
2119                        .into_iter()
2120                        .filter_map(|k| k.try_into().ok())
2121                        .collect(),
2122                    keys_to_unbind: keys_to_unbind
2123                        .into_iter()
2124                        .filter_map(|k| k.try_into().ok())
2125                        .collect(),
2126                    write_config_to_disk,
2127                })),
2128            }),
2129            PluginCommand::ListClients => Ok(ProtobufPluginCommand {
2130                name: CommandName::ListClients as i32,
2131                payload: None,
2132            }),
2133        }
2134    }
2135}