Skip to main content

zellij_utils/plugin_api/
plugin_command.rs

1pub use super::generated_api::api::{
2    action::{Action as ProtobufAction, PaneIdAndShouldFloat, SwitchToModePayload},
3    event::{
4        EventNameList as ProtobufEventNameList, Header,
5        ResurrectableSession as ProtobufResurrectableSession,
6        SessionManifest as ProtobufSessionManifest,
7    },
8    input_mode::InputMode as ProtobufInputMode,
9    pane_frame_style::PaneFrameStyle as ProtobufPaneFrameStyle,
10    plugin_command::{
11        break_panes_to_new_tab_response, break_panes_to_tab_with_id_response,
12        break_panes_to_tab_with_index_response, delete_layout_response, dump_layout_response,
13        dump_session_layout_response, edit_layout_response, focus_or_create_tab_response,
14        get_focused_pane_info_response, get_pane_cwd_response, get_pane_pid_response,
15        get_pane_running_command_response, get_session_list_response, hide_floating_panes_response,
16        highlight_style::Style as ProtobufHighlightStyleVariant, new_tab_response,
17        new_tab_unfocused_response, parse_layout_response, plugin_command::Payload,
18        rename_layout_response, save_layout_response, save_session_response,
19        show_floating_panes_response, BreakPanesToNewTabPayload,
20        BreakPanesToNewTabResponse as ProtobufBreakPanesToNewTabResponse,
21        BreakPanesToTabWithIdPayload,
22        BreakPanesToTabWithIdResponse as ProtobufBreakPanesToTabWithIdResponse,
23        BreakPanesToTabWithIndexPayload,
24        BreakPanesToTabWithIndexResponse as ProtobufBreakPanesToTabWithIndexResponse,
25        ChangeFloatingPanesCoordinatesPayload, ChangeHostFolderPayload, ClearPaneHighlightsPayload,
26        ClearScreenForPaneIdPayload, CliPipeOutputPayload, CloseMultiplePanesPayload,
27        CloseTabWithIdPayload, CloseTabWithIndexPayload, CommandName, ContextItem,
28        CopyToClipboardPayload, CreateTokenResponse as ProtobufCreateTokenResponse,
29        CreateTokenResponse, CurrentSessionLastSavedTimePayload,
30        CurrentSessionLastSavedTimeResponse as ProtobufCurrentSessionLastSavedTimeResponse,
31        CursorPosition, CustomIndexHighlight as ProtobufCustomIndexHighlight,
32        CustomRgbHighlight as ProtobufCustomRgbHighlight,
33        DeleteAllDeadSessionsResponse as ProtobufDeleteAllDeadSessionsResponse,
34        DeleteDeadSessionResponse as ProtobufDeleteDeadSessionResponse, DeleteLayoutPayload,
35        DeleteLayoutResponse as ProtobufDeleteLayoutResponse, DumpLayoutPayload,
36        DumpLayoutResponse as ProtobufDumpLayoutResponse, DumpSessionLayoutPayload,
37        DumpSessionLayoutResponse as ProtobufDumpSessionLayoutResponse, EditLayoutPayload,
38        EditLayoutResponse as ProtobufEditLayoutResponse, EditScrollbackForPaneWithIdPayload,
39        EmbedMultiplePanesPayload, EnvVariable, ExecCmdPayload,
40        FixedOrPercent as ProtobufFixedOrPercent,
41        FixedOrPercentValue as ProtobufFixedOrPercentValue, FloatMultiplePanesPayload,
42        FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates,
43        FocusOrCreateTabResponse as ProtobufFocusOrCreateTabResponse, FocusedPaneInfo,
44        GenerateRandomNamePayload,
45        GenerateRandomNameResponse as ProtobufGenerateRandomNameResponse,
46        GenerateWebLoginTokenPayload, GetFocusedPaneInfoPayload,
47        GetFocusedPaneInfoResponse as ProtobufGetFocusedPaneInfoResponse, GetLayoutDirPayload,
48        GetLayoutDirResponse as ProtobufGetLayoutDirResponse,
49        GetPaneCwdPayload as ProtobufGetPaneCwdPayload,
50        GetPaneCwdResponse as ProtobufGetPaneCwdResponse, GetPaneInfoPayload,
51        GetPaneInfoResponse as ProtobufGetPaneInfoResponse, GetPanePidPayload,
52        GetPanePidResponse as ProtobufGetPanePidResponse,
53        GetPaneRunningCommandPayload as ProtobufGetPaneRunningCommandPayload,
54        GetPaneRunningCommandResponse as ProtobufGetPaneRunningCommandResponse,
55        GetPaneScrollbackPayload,
56        GetSessionEnvironmentVariablesPayload as ProtobufGetSessionEnvironmentVariablesPayload,
57        GetSessionEnvironmentVariablesResponse as ProtobufGetSessionEnvironmentVariablesResponse,
58        GetSessionListPayload as ProtobufGetSessionListPayload,
59        GetSessionListResponse as ProtobufGetSessionListResponse, GetTabInfoPayload,
60        GetTabInfoResponse as ProtobufGetTabInfoResponse, GoToTabWithIdPayload,
61        GroupAndUngroupPanesPayload, HideFloatingPanesPayload as ProtobufHideFloatingPanesPayload,
62        HideFloatingPanesResponse as ProtobufHideFloatingPanesResponse, HidePaneWithIdPayload,
63        HighlightAndUnhighlightPanesPayload, HighlightLayer as ProtobufHighlightLayer,
64        HighlightStyle as ProtobufHighlightStyle, HttpVerb as ProtobufHttpVerb, IdAndNewName,
65        KeyToRebind, KeyToUnbind, KillSessionsPayload,
66        KillSessionsResponse as ProtobufKillSessionsResponse, ListTokensResponse,
67        LoadNewPluginPayload, MessageToPluginPayload, MovePaneWithPaneIdInDirectionPayload,
68        MovePaneWithPaneIdPayload, MovePayload, NewPluginArgs as ProtobufNewPluginArgs,
69        NewTabPayload, NewTabResponse as ProtobufNewTabResponse, NewTabUnfocusedPayload,
70        NewTabUnfocusedResponse as ProtobufNewTabUnfocusedResponse,
71        NewTabsResponse as ProtobufNewTabsResponse, NewTabsWithLayoutInfoPayload,
72        NewTiledPaneInTabPayload, NewTiledPaneInTabResponse as ProtobufNewTiledPaneInTabResponse,
73        OpenCommandPaneBackgroundResponse as ProtobufOpenCommandPaneBackgroundResponse,
74        OpenCommandPaneFloatingNearPluginPayload,
75        OpenCommandPaneFloatingNearPluginResponse as ProtobufOpenCommandPaneFloatingNearPluginResponse,
76        OpenCommandPaneFloatingResponse as ProtobufOpenCommandPaneFloatingResponse,
77        OpenCommandPaneInPlaceOfPaneIdPayload,
78        OpenCommandPaneInPlaceOfPaneIdResponse as ProtobufOpenCommandPaneInPlaceOfPaneIdResponse,
79        OpenCommandPaneInPlaceOfPluginPayload,
80        OpenCommandPaneInPlaceOfPluginResponse as ProtobufOpenCommandPaneInPlaceOfPluginResponse,
81        OpenCommandPaneInPlaceResponse as ProtobufOpenCommandPaneInPlaceResponse,
82        OpenCommandPaneNearPluginPayload,
83        OpenCommandPaneNearPluginResponse as ProtobufOpenCommandPaneNearPluginResponse,
84        OpenCommandPanePayload, OpenCommandPaneResponse as ProtobufOpenCommandPaneResponse,
85        OpenEditPaneInPlaceOfPaneIdPayload,
86        OpenEditPaneInPlaceOfPaneIdResponse as ProtobufOpenEditPaneInPlaceOfPaneIdResponse,
87        OpenFileFloatingNearPluginPayload,
88        OpenFileFloatingNearPluginResponse as ProtobufOpenFileFloatingNearPluginResponse,
89        OpenFileFloatingResponse as ProtobufOpenFileFloatingResponse,
90        OpenFileInPlaceOfPluginPayload,
91        OpenFileInPlaceOfPluginResponse as ProtobufOpenFileInPlaceOfPluginResponse,
92        OpenFileInPlaceResponse as ProtobufOpenFileInPlaceResponse, OpenFileNearPluginPayload,
93        OpenFileNearPluginResponse as ProtobufOpenFileNearPluginResponse, OpenFilePayload,
94        OpenFileResponse as ProtobufOpenFileResponse,
95        OpenPaneInNewTabResponse as ProtobufOpenPaneInNewTabResponse,
96        OpenPluginPaneFloatingPayload,
97        OpenPluginPaneFloatingResponse as ProtobufOpenPluginPaneFloatingResponse,
98        OpenPluginPaneInNewTabPayload as ProtobufOpenPluginPaneInNewTabPayload,
99        OpenTerminalFloatingNearPluginPayload,
100        OpenTerminalFloatingNearPluginResponse as ProtobufOpenTerminalFloatingNearPluginResponse,
101        OpenTerminalFloatingResponse as ProtobufOpenTerminalFloatingResponse,
102        OpenTerminalInPlaceOfPluginPayload,
103        OpenTerminalInPlaceOfPluginResponse as ProtobufOpenTerminalInPlaceOfPluginResponse,
104        OpenTerminalInPlaceResponse as ProtobufOpenTerminalInPlaceResponse,
105        OpenTerminalNearPluginPayload,
106        OpenTerminalNearPluginResponse as ProtobufOpenTerminalNearPluginResponse,
107        OpenTerminalPaneInPlaceOfPaneIdPayload,
108        OpenTerminalPaneInPlaceOfPaneIdResponse as ProtobufOpenTerminalPaneInPlaceOfPaneIdResponse,
109        OpenTerminalResponse as ProtobufOpenTerminalResponse, OverrideLayoutPayload,
110        PageScrollDownInPaneIdPayload, PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId,
111        PaneIdAndFloatingPaneCoordinates, PaneType as ProtobufPaneType, ParseLayoutPayload,
112        ParseLayoutResponse as ProtobufParseLayoutResponse, PluginCommand as ProtobufPluginCommand,
113        PluginMessagePayload, RebindKeysPayload, ReconfigurePayload,
114        RegexHighlight as ProtobufRegexHighlight, ReloadPluginPayload, RenameLayoutPayload,
115        RenameLayoutResponse as ProtobufRenameLayoutResponse, RenameTabWithIdPayload,
116        RenameWebLoginTokenPayload, RenameWebTokenResponse, ReplacePaneWithExistingPanePayload,
117        RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePaneIdWithDirectionPayload,
118        ResizePayload, RevokeAllWebTokensResponse, RevokeTokenResponse, RevokeWebLoginTokenPayload,
119        RunActionPayload, RunCommandPayload, RunningCommand as ProtobufRunningCommand,
120        SaveLayoutPayload, SaveLayoutResponse as ProtobufSaveLayoutResponse, SaveSessionPayload,
121        SaveSessionResponse as ProtobufSaveSessionResponse, ScrollDownInPaneIdPayload,
122        ScrollToBottomInPaneIdPayload, ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload,
123        SessionListSnapshot as ProtobufSessionListSnapshot, SetFloatingPanePinnedPayload,
124        SetPaneBorderlessPayload, SetPaneColorPayload,
125        SetPaneFrameStylePayload as ProtobufSetPaneFrameStylePayload,
126        SetPaneRegexHighlightsPayload, SetSelfMouseSelectionSupportPayload,
127        SetSoftKeyboardPayload as ProtobufSetSoftKeyboardPayload, SetTimeoutPayload,
128        ShowCursorPayload, ShowFloatingPanesPayload as ProtobufShowFloatingPanesPayload,
129        ShowFloatingPanesResponse as ProtobufShowFloatingPanesResponse, ShowPaneWithIdPayload,
130        StackPanesPayload, SubscribePayload, SwitchSessionPayload, SwitchTabToIdPayload,
131        SwitchTabToPayload, ToggleFloatingPanesPayload, TogglePaneBorderlessPayload,
132        TogglePaneEmbedOrEjectForPaneIdPayload, TogglePaneIdFullscreenPayload, UnsubscribePayload,
133        WebRequestPayload, WriteCharsToPaneIdPayload, WriteToPaneIdPayload,
134    },
135    plugin_permission::PermissionType as ProtobufPermissionType,
136    resize::ResizeAction as ProtobufResizeAction,
137};
138
139use crate::data::{
140    ConnectToSession, DeleteAllDeadSessionsResponse, DeleteDeadSessionResponse,
141    DeleteLayoutResponse, EditLayoutResponse, FloatingPaneCoordinates, GetFocusedPaneInfoResponse,
142    GetPaneCwdResponse, GetPanePidResponse, GetPaneRunningCommandResponse, GetSessionListResponse,
143    HighlightLayer, HighlightStyle, HttpVerb, InputMode, KeyWithModifier, KillSessionsResponse,
144    MessageToPlugin, NewPluginArgs, PaneId, PermissionType, PluginCommand, RegexHighlight,
145    RenameLayoutResponse, SaveLayoutResponse, SessionInfo, SessionListSnapshot,
146};
147use crate::input::actions::Action;
148use crate::input::layout::PercentOrFixed;
149
150use std::collections::BTreeMap;
151use std::convert::TryFrom;
152use std::path::PathBuf;
153
154impl Into<FloatingPaneCoordinates> for ProtobufFloatingPaneCoordinates {
155    fn into(self) -> FloatingPaneCoordinates {
156        FloatingPaneCoordinates {
157            x: self
158                .x
159                .and_then(|x| match ProtobufFixedOrPercent::try_from(x.r#type).ok() {
160                    Some(ProtobufFixedOrPercent::Percent) => {
161                        Some(PercentOrFixed::Percent(x.value as usize))
162                    },
163                    Some(ProtobufFixedOrPercent::Fixed) => {
164                        Some(PercentOrFixed::Fixed(x.value as usize))
165                    },
166                    None => None,
167                }),
168            y: self
169                .y
170                .and_then(|y| match ProtobufFixedOrPercent::try_from(y.r#type).ok() {
171                    Some(ProtobufFixedOrPercent::Percent) => {
172                        Some(PercentOrFixed::Percent(y.value as usize))
173                    },
174                    Some(ProtobufFixedOrPercent::Fixed) => {
175                        Some(PercentOrFixed::Fixed(y.value as usize))
176                    },
177                    None => None,
178                }),
179            width: self.width.and_then(|width| {
180                match ProtobufFixedOrPercent::try_from(width.r#type).ok() {
181                    Some(ProtobufFixedOrPercent::Percent) => {
182                        Some(PercentOrFixed::Percent(width.value as usize))
183                    },
184                    Some(ProtobufFixedOrPercent::Fixed) => {
185                        Some(PercentOrFixed::Fixed(width.value as usize))
186                    },
187                    None => None,
188                }
189            }),
190            height: self.height.and_then(|height| {
191                match ProtobufFixedOrPercent::try_from(height.r#type).ok() {
192                    Some(ProtobufFixedOrPercent::Percent) => {
193                        Some(PercentOrFixed::Percent(height.value as usize))
194                    },
195                    Some(ProtobufFixedOrPercent::Fixed) => {
196                        Some(PercentOrFixed::Fixed(height.value as usize))
197                    },
198                    None => None,
199                }
200            }),
201            pinned: self.pinned,
202            borderless: self.borderless,
203        }
204    }
205}
206
207impl Into<ProtobufFloatingPaneCoordinates> for FloatingPaneCoordinates {
208    fn into(self) -> ProtobufFloatingPaneCoordinates {
209        ProtobufFloatingPaneCoordinates {
210            x: match self.x {
211                Some(PercentOrFixed::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
212                    r#type: ProtobufFixedOrPercent::Percent as i32,
213                    value: percent as u32,
214                }),
215                Some(PercentOrFixed::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
216                    r#type: ProtobufFixedOrPercent::Fixed as i32,
217                    value: fixed as u32,
218                }),
219                None => None,
220            },
221            y: match self.y {
222                Some(PercentOrFixed::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
223                    r#type: ProtobufFixedOrPercent::Percent as i32,
224                    value: percent as u32,
225                }),
226                Some(PercentOrFixed::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
227                    r#type: ProtobufFixedOrPercent::Fixed as i32,
228                    value: fixed as u32,
229                }),
230                None => None,
231            },
232            width: match self.width {
233                Some(PercentOrFixed::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
234                    r#type: ProtobufFixedOrPercent::Percent as i32,
235                    value: percent as u32,
236                }),
237                Some(PercentOrFixed::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
238                    r#type: ProtobufFixedOrPercent::Fixed as i32,
239                    value: fixed as u32,
240                }),
241                None => None,
242            },
243            height: match self.height {
244                Some(PercentOrFixed::Percent(percent)) => Some(ProtobufFixedOrPercentValue {
245                    r#type: ProtobufFixedOrPercent::Percent as i32,
246                    value: percent as u32,
247                }),
248                Some(PercentOrFixed::Fixed(fixed)) => Some(ProtobufFixedOrPercentValue {
249                    r#type: ProtobufFixedOrPercent::Fixed as i32,
250                    value: fixed as u32,
251                }),
252                None => None,
253            },
254            pinned: self.pinned,
255            borderless: self.borderless,
256        }
257    }
258}
259
260impl Into<HttpVerb> for ProtobufHttpVerb {
261    fn into(self) -> HttpVerb {
262        match self {
263            ProtobufHttpVerb::Get => HttpVerb::Get,
264            ProtobufHttpVerb::Post => HttpVerb::Post,
265            ProtobufHttpVerb::Put => HttpVerb::Put,
266            ProtobufHttpVerb::Delete => HttpVerb::Delete,
267        }
268    }
269}
270
271impl Into<ProtobufHttpVerb> for HttpVerb {
272    fn into(self) -> ProtobufHttpVerb {
273        match self {
274            HttpVerb::Get => ProtobufHttpVerb::Get,
275            HttpVerb::Post => ProtobufHttpVerb::Post,
276            HttpVerb::Put => ProtobufHttpVerb::Put,
277            HttpVerb::Delete => ProtobufHttpVerb::Delete,
278        }
279    }
280}
281
282impl TryFrom<ProtobufPaneId> for PaneId {
283    type Error = &'static str;
284    fn try_from(protobuf_pane_id: ProtobufPaneId) -> Result<Self, &'static str> {
285        match ProtobufPaneType::try_from(protobuf_pane_id.pane_type).ok() {
286            Some(ProtobufPaneType::Terminal) => Ok(PaneId::Terminal(protobuf_pane_id.id)),
287            Some(ProtobufPaneType::Plugin) => Ok(PaneId::Plugin(protobuf_pane_id.id)),
288            None => Err("Failed to convert PaneId"),
289        }
290    }
291}
292
293impl TryFrom<PaneId> for ProtobufPaneId {
294    type Error = &'static str;
295    fn try_from(pane_id: PaneId) -> Result<Self, &'static str> {
296        match pane_id {
297            PaneId::Terminal(id) => Ok(ProtobufPaneId {
298                pane_type: ProtobufPaneType::Terminal as i32,
299                id,
300            }),
301            PaneId::Plugin(id) => Ok(ProtobufPaneId {
302                pane_type: ProtobufPaneType::Plugin as i32,
303                id,
304            }),
305        }
306    }
307}
308
309impl TryFrom<ProtobufGetPanePidResponse> for GetPanePidResponse {
310    type Error = &'static str;
311    fn try_from(protobuf_response: ProtobufGetPanePidResponse) -> Result<Self, &'static str> {
312        match protobuf_response.result {
313            Some(get_pane_pid_response::Result::Pid(pid)) => Ok(GetPanePidResponse::Ok(pid)),
314            Some(get_pane_pid_response::Result::Error(error)) => Ok(GetPanePidResponse::Err(error)),
315            None => Err("Empty GetPanePidResponse"),
316        }
317    }
318}
319
320impl From<GetPanePidResponse> for ProtobufGetPanePidResponse {
321    fn from(response: GetPanePidResponse) -> Self {
322        match response {
323            GetPanePidResponse::Ok(pid) => ProtobufGetPanePidResponse {
324                result: Some(get_pane_pid_response::Result::Pid(pid)),
325            },
326            GetPanePidResponse::Err(error) => ProtobufGetPanePidResponse {
327                result: Some(get_pane_pid_response::Result::Error(error)),
328            },
329        }
330    }
331}
332
333impl From<GetPaneRunningCommandResponse> for ProtobufGetPaneRunningCommandResponse {
334    fn from(response: GetPaneRunningCommandResponse) -> Self {
335        match response {
336            GetPaneRunningCommandResponse::Ok(args) => ProtobufGetPaneRunningCommandResponse {
337                result: Some(get_pane_running_command_response::Result::Command(
338                    ProtobufRunningCommand { args },
339                )),
340            },
341            GetPaneRunningCommandResponse::Err(err) => ProtobufGetPaneRunningCommandResponse {
342                result: Some(get_pane_running_command_response::Result::Error(err)),
343            },
344        }
345    }
346}
347
348impl From<GetSessionListResponse> for ProtobufGetSessionListResponse {
349    fn from(response: GetSessionListResponse) -> Self {
350        match response {
351            GetSessionListResponse::Ok(snapshot) => {
352                let live_sessions = snapshot
353                    .live_sessions
354                    .into_iter()
355                    .filter_map(|si| ProtobufSessionManifest::try_from(si).ok())
356                    .collect();
357                let resurrectable_sessions = snapshot
358                    .resurrectable_sessions
359                    .into_iter()
360                    .map(|entry| ProtobufResurrectableSession::from(entry))
361                    .collect();
362                ProtobufGetSessionListResponse {
363                    result: Some(get_session_list_response::Result::Snapshot(
364                        ProtobufSessionListSnapshot {
365                            live_sessions,
366                            resurrectable_sessions,
367                        },
368                    )),
369                }
370            },
371            GetSessionListResponse::Err(err) => ProtobufGetSessionListResponse {
372                result: Some(get_session_list_response::Result::Error(err)),
373            },
374        }
375    }
376}
377
378impl TryFrom<ProtobufGetSessionListResponse> for GetSessionListResponse {
379    type Error = &'static str;
380    fn try_from(protobuf_response: ProtobufGetSessionListResponse) -> Result<Self, &'static str> {
381        match protobuf_response.result {
382            Some(get_session_list_response::Result::Snapshot(snapshot)) => {
383                let mut live_sessions: Vec<SessionInfo> = Vec::new();
384                for manifest in snapshot.live_sessions {
385                    live_sessions.push(SessionInfo::try_from(manifest)?);
386                }
387                let resurrectable_sessions = snapshot
388                    .resurrectable_sessions
389                    .into_iter()
390                    .map(<(String, std::time::Duration)>::from)
391                    .collect();
392                Ok(GetSessionListResponse::Ok(SessionListSnapshot {
393                    live_sessions,
394                    resurrectable_sessions,
395                }))
396            },
397            Some(get_session_list_response::Result::Error(err)) => {
398                Ok(GetSessionListResponse::Err(err))
399            },
400            None => Err("Empty GetSessionListResponse"),
401        }
402    }
403}
404
405impl From<KillSessionsResponse> for ProtobufKillSessionsResponse {
406    fn from(response: KillSessionsResponse) -> Self {
407        match response {
408            KillSessionsResponse::Ok => ProtobufKillSessionsResponse { error: None },
409            KillSessionsResponse::Err(err) => ProtobufKillSessionsResponse { error: Some(err) },
410        }
411    }
412}
413
414impl From<ProtobufKillSessionsResponse> for KillSessionsResponse {
415    fn from(protobuf_response: ProtobufKillSessionsResponse) -> Self {
416        match protobuf_response.error {
417            Some(err) => KillSessionsResponse::Err(err),
418            None => KillSessionsResponse::Ok,
419        }
420    }
421}
422
423impl From<DeleteDeadSessionResponse> for ProtobufDeleteDeadSessionResponse {
424    fn from(response: DeleteDeadSessionResponse) -> Self {
425        match response {
426            DeleteDeadSessionResponse::Ok => ProtobufDeleteDeadSessionResponse { error: None },
427            DeleteDeadSessionResponse::Err(err) => {
428                ProtobufDeleteDeadSessionResponse { error: Some(err) }
429            },
430        }
431    }
432}
433
434impl From<ProtobufDeleteDeadSessionResponse> for DeleteDeadSessionResponse {
435    fn from(protobuf_response: ProtobufDeleteDeadSessionResponse) -> Self {
436        match protobuf_response.error {
437            Some(err) => DeleteDeadSessionResponse::Err(err),
438            None => DeleteDeadSessionResponse::Ok,
439        }
440    }
441}
442
443impl From<DeleteAllDeadSessionsResponse> for ProtobufDeleteAllDeadSessionsResponse {
444    fn from(response: DeleteAllDeadSessionsResponse) -> Self {
445        match response {
446            DeleteAllDeadSessionsResponse::Ok => {
447                ProtobufDeleteAllDeadSessionsResponse { error: None }
448            },
449            DeleteAllDeadSessionsResponse::Err(err) => {
450                ProtobufDeleteAllDeadSessionsResponse { error: Some(err) }
451            },
452        }
453    }
454}
455
456impl From<ProtobufDeleteAllDeadSessionsResponse> for DeleteAllDeadSessionsResponse {
457    fn from(protobuf_response: ProtobufDeleteAllDeadSessionsResponse) -> Self {
458        match protobuf_response.error {
459            Some(err) => DeleteAllDeadSessionsResponse::Err(err),
460            None => DeleteAllDeadSessionsResponse::Ok,
461        }
462    }
463}
464
465impl From<GetPaneCwdResponse> for ProtobufGetPaneCwdResponse {
466    fn from(response: GetPaneCwdResponse) -> Self {
467        match response {
468            GetPaneCwdResponse::Ok(path) => {
469                let cwd_string = path
470                    .to_str()
471                    .map(|s| s.to_string())
472                    .unwrap_or_else(|| String::from(""));
473                ProtobufGetPaneCwdResponse {
474                    result: Some(get_pane_cwd_response::Result::Cwd(cwd_string)),
475                }
476            },
477            GetPaneCwdResponse::Err(err) => ProtobufGetPaneCwdResponse {
478                result: Some(get_pane_cwd_response::Result::Error(err)),
479            },
480        }
481    }
482}
483
484impl From<GetFocusedPaneInfoResponse> for ProtobufGetFocusedPaneInfoResponse {
485    fn from(response: GetFocusedPaneInfoResponse) -> Self {
486        match response {
487            GetFocusedPaneInfoResponse::Ok { tab_index, pane_id } => {
488                let protobuf_pane_id = ProtobufPaneId {
489                    pane_type: match pane_id {
490                        PaneId::Terminal(_) => ProtobufPaneType::Terminal as i32,
491                        PaneId::Plugin(_) => ProtobufPaneType::Plugin as i32,
492                    },
493                    id: match pane_id {
494                        PaneId::Terminal(id) | PaneId::Plugin(id) => id,
495                    },
496                };
497                ProtobufGetFocusedPaneInfoResponse {
498                    result: Some(get_focused_pane_info_response::Result::FocusedPaneInfo(
499                        FocusedPaneInfo {
500                            focused_tab_index: tab_index as u32,
501                            focused_pane_id: Some(protobuf_pane_id),
502                        },
503                    )),
504                }
505            },
506            GetFocusedPaneInfoResponse::Err(err) => ProtobufGetFocusedPaneInfoResponse {
507                result: Some(get_focused_pane_info_response::Result::Error(err)),
508            },
509        }
510    }
511}
512
513impl TryFrom<ProtobufSaveLayoutResponse> for SaveLayoutResponse {
514    type Error = &'static str;
515    fn try_from(protobuf_response: ProtobufSaveLayoutResponse) -> Result<Self, &'static str> {
516        match protobuf_response.result {
517            Some(save_layout_response::Result::Success(_)) => Ok(SaveLayoutResponse::Ok(())),
518            Some(save_layout_response::Result::Error(error)) => Ok(SaveLayoutResponse::Err(error)),
519            None => Err("Empty SaveLayoutResponse"),
520        }
521    }
522}
523
524impl From<SaveLayoutResponse> for ProtobufSaveLayoutResponse {
525    fn from(response: SaveLayoutResponse) -> Self {
526        match response {
527            SaveLayoutResponse::Ok(_) => ProtobufSaveLayoutResponse {
528                result: Some(save_layout_response::Result::Success(true)),
529            },
530            SaveLayoutResponse::Err(error) => ProtobufSaveLayoutResponse {
531                result: Some(save_layout_response::Result::Error(error)),
532            },
533        }
534    }
535}
536
537impl TryFrom<ProtobufDeleteLayoutResponse> for DeleteLayoutResponse {
538    type Error = &'static str;
539    fn try_from(protobuf_response: ProtobufDeleteLayoutResponse) -> Result<Self, &'static str> {
540        match protobuf_response.result {
541            Some(delete_layout_response::Result::Success(_)) => Ok(DeleteLayoutResponse::Ok(())),
542            Some(delete_layout_response::Result::Error(error)) => {
543                Ok(DeleteLayoutResponse::Err(error))
544            },
545            None => Err("Empty DeleteLayoutResponse"),
546        }
547    }
548}
549
550impl From<DeleteLayoutResponse> for ProtobufDeleteLayoutResponse {
551    fn from(response: DeleteLayoutResponse) -> Self {
552        match response {
553            DeleteLayoutResponse::Ok(_) => ProtobufDeleteLayoutResponse {
554                result: Some(delete_layout_response::Result::Success(true)),
555            },
556            DeleteLayoutResponse::Err(error) => ProtobufDeleteLayoutResponse {
557                result: Some(delete_layout_response::Result::Error(error)),
558            },
559        }
560    }
561}
562
563impl TryFrom<ProtobufRenameLayoutResponse> for RenameLayoutResponse {
564    type Error = &'static str;
565    fn try_from(protobuf_response: ProtobufRenameLayoutResponse) -> Result<Self, &'static str> {
566        match protobuf_response.result {
567            Some(rename_layout_response::Result::Success(_)) => Ok(RenameLayoutResponse::Ok(())),
568            Some(rename_layout_response::Result::Error(error)) => {
569                Ok(RenameLayoutResponse::Err(error))
570            },
571            None => Err("Empty RenameLayoutResponse"),
572        }
573    }
574}
575
576impl From<RenameLayoutResponse> for ProtobufRenameLayoutResponse {
577    fn from(response: RenameLayoutResponse) -> Self {
578        match response {
579            RenameLayoutResponse::Ok(_) => ProtobufRenameLayoutResponse {
580                result: Some(rename_layout_response::Result::Success(true)),
581            },
582            RenameLayoutResponse::Err(error) => ProtobufRenameLayoutResponse {
583                result: Some(rename_layout_response::Result::Error(error)),
584            },
585        }
586    }
587}
588
589impl TryFrom<ProtobufEditLayoutResponse> for EditLayoutResponse {
590    type Error = &'static str;
591    fn try_from(protobuf_response: ProtobufEditLayoutResponse) -> Result<Self, &'static str> {
592        match protobuf_response.result {
593            Some(edit_layout_response::Result::Success(_)) => Ok(EditLayoutResponse::Ok(())),
594            Some(edit_layout_response::Result::Error(error)) => Ok(EditLayoutResponse::Err(error)),
595            None => Err("Empty EditLayoutResponse"),
596        }
597    }
598}
599
600impl From<EditLayoutResponse> for ProtobufEditLayoutResponse {
601    fn from(response: EditLayoutResponse) -> Self {
602        match response {
603            EditLayoutResponse::Ok(_) => ProtobufEditLayoutResponse {
604                result: Some(edit_layout_response::Result::Success(true)),
605            },
606            EditLayoutResponse::Err(error) => ProtobufEditLayoutResponse {
607                result: Some(edit_layout_response::Result::Error(error)),
608            },
609        }
610    }
611}
612
613impl TryFrom<(InputMode, KeyWithModifier, Vec<Action>)> for KeyToRebind {
614    type Error = &'static str;
615    fn try_from(
616        key_to_rebind: (InputMode, KeyWithModifier, Vec<Action>),
617    ) -> Result<Self, &'static str> {
618        Ok(KeyToRebind {
619            input_mode: key_to_rebind.0 as i32,
620            key: Some(key_to_rebind.1.try_into()?),
621            actions: key_to_rebind
622                .2
623                .into_iter()
624                .filter_map(|a| a.try_into().ok())
625                .collect(),
626        })
627    }
628}
629
630impl TryFrom<(InputMode, KeyWithModifier)> for KeyToUnbind {
631    type Error = &'static str;
632    fn try_from(key_to_unbind: (InputMode, KeyWithModifier)) -> Result<Self, &'static str> {
633        Ok(KeyToUnbind {
634            input_mode: key_to_unbind.0 as i32,
635            key: Some(key_to_unbind.1.try_into()?),
636        })
637    }
638}
639
640fn key_to_rebind_to_plugin_command_assets(
641    key_to_rebind: KeyToRebind,
642) -> Option<(InputMode, KeyWithModifier, Vec<Action>)> {
643    Some((
644        ProtobufInputMode::try_from(key_to_rebind.input_mode)
645            .ok()?
646            .try_into()
647            .ok()?,
648        key_to_rebind.key?.try_into().ok()?,
649        key_to_rebind
650            .actions
651            .into_iter()
652            .filter_map(|a| a.try_into().ok())
653            .collect(),
654    ))
655}
656
657fn key_to_unbind_to_plugin_command_assets(
658    key_to_unbind: KeyToUnbind,
659) -> Option<(InputMode, KeyWithModifier)> {
660    Some((
661        ProtobufInputMode::try_from(key_to_unbind.input_mode)
662            .ok()?
663            .try_into()
664            .ok()?,
665        key_to_unbind.key?.try_into().ok()?,
666    ))
667}
668
669impl TryFrom<ProtobufPluginCommand> for PluginCommand {
670    type Error = &'static str;
671    fn try_from(protobuf_plugin_command: ProtobufPluginCommand) -> Result<Self, &'static str> {
672        match CommandName::try_from(protobuf_plugin_command.name).ok() {
673            Some(CommandName::Subscribe) => match protobuf_plugin_command.payload {
674                Some(Payload::SubscribePayload(subscribe_payload)) => {
675                    let protobuf_event_list = subscribe_payload.subscriptions;
676                    match protobuf_event_list {
677                        Some(protobuf_event_list) => {
678                            Ok(PluginCommand::Subscribe(protobuf_event_list.try_into()?))
679                        },
680                        None => Err("malformed subscription event"),
681                    }
682                },
683                _ => Err("Mismatched payload for Subscribe"),
684            },
685            Some(CommandName::Unsubscribe) => match protobuf_plugin_command.payload {
686                Some(Payload::UnsubscribePayload(unsubscribe_payload)) => {
687                    let protobuf_event_list = unsubscribe_payload.subscriptions;
688                    match protobuf_event_list {
689                        Some(protobuf_event_list) => {
690                            Ok(PluginCommand::Unsubscribe(protobuf_event_list.try_into()?))
691                        },
692                        None => Err("malformed unsubscription event"),
693                    }
694                },
695                _ => Err("Mismatched payload for Unsubscribe"),
696            },
697            Some(CommandName::SetSelectable) => match protobuf_plugin_command.payload {
698                Some(Payload::SetSelectablePayload(should_be_selectable)) => {
699                    Ok(PluginCommand::SetSelectable(should_be_selectable))
700                },
701                _ => Err("Mismatched payload for SetSelectable"),
702            },
703            Some(CommandName::ShowCursor) => match protobuf_plugin_command.payload {
704                Some(Payload::ShowCursorPayload(payload)) => {
705                    let cursor_position =
706                        payload.position.map(|pos| (pos.x as usize, pos.y as usize));
707                    Ok(PluginCommand::ShowCursor(cursor_position))
708                },
709                _ => Err("Mismatched payload for ShowCursor"),
710            },
711            Some(CommandName::GetPluginIds) => {
712                if protobuf_plugin_command.payload.is_some() {
713                    Err("GetPluginIds should not have a payload")
714                } else {
715                    Ok(PluginCommand::GetPluginIds)
716                }
717            },
718            Some(CommandName::GetZellijVersion) => {
719                if protobuf_plugin_command.payload.is_some() {
720                    Err("GetZellijVersion should not have a payload")
721                } else {
722                    Ok(PluginCommand::GetZellijVersion)
723                }
724            },
725            Some(CommandName::OpenFile) => match protobuf_plugin_command.payload {
726                Some(Payload::OpenFilePayload(file_to_open_payload)) => {
727                    match file_to_open_payload.file_to_open {
728                        Some(file_to_open) => {
729                            let context: BTreeMap<String, String> = file_to_open_payload
730                                .context
731                                .into_iter()
732                                .map(|e| (e.name, e.value))
733                                .collect();
734                            Ok(PluginCommand::OpenFile(file_to_open.try_into()?, context))
735                        },
736                        None => Err("Malformed open file payload"),
737                    }
738                },
739                _ => Err("Mismatched payload for OpenFile"),
740            },
741            Some(CommandName::OpenFileFloating) => match protobuf_plugin_command.payload {
742                Some(Payload::OpenFileFloatingPayload(file_to_open_payload)) => {
743                    let floating_pane_coordinates = file_to_open_payload
744                        .floating_pane_coordinates
745                        .map(|f| f.into());
746                    let context: BTreeMap<String, String> = file_to_open_payload
747                        .context
748                        .into_iter()
749                        .map(|e| (e.name, e.value))
750                        .collect();
751                    match file_to_open_payload.file_to_open {
752                        Some(file_to_open) => Ok(PluginCommand::OpenFileFloating(
753                            file_to_open.try_into()?,
754                            floating_pane_coordinates,
755                            context,
756                        )),
757                        None => Err("Malformed open file payload"),
758                    }
759                },
760                _ => Err("Mismatched payload for OpenFileFloating"),
761            },
762            Some(CommandName::OpenTerminal) => match protobuf_plugin_command.payload {
763                Some(Payload::OpenTerminalPayload(file_to_open_payload)) => {
764                    match file_to_open_payload.file_to_open {
765                        Some(file_to_open) => {
766                            Ok(PluginCommand::OpenTerminal(file_to_open.try_into()?))
767                        },
768                        None => Err("Malformed open terminal payload"),
769                    }
770                },
771                _ => Err("Mismatched payload for OpenTerminal"),
772            },
773            Some(CommandName::OpenTerminalFloating) => match protobuf_plugin_command.payload {
774                Some(Payload::OpenTerminalFloatingPayload(file_to_open_payload)) => {
775                    let floating_pane_coordinates = file_to_open_payload
776                        .floating_pane_coordinates
777                        .map(|f| f.into());
778                    match file_to_open_payload.file_to_open {
779                        Some(file_to_open) => Ok(PluginCommand::OpenTerminalFloating(
780                            file_to_open.try_into()?,
781                            floating_pane_coordinates,
782                        )),
783                        None => Err("Malformed open terminal floating payload"),
784                    }
785                },
786                _ => Err("Mismatched payload for OpenTerminalFloating"),
787            },
788            Some(CommandName::OpenCommandPane) => match protobuf_plugin_command.payload {
789                Some(Payload::OpenCommandPanePayload(command_to_run_payload)) => {
790                    match command_to_run_payload.command_to_run {
791                        Some(command_to_run) => {
792                            let context: BTreeMap<String, String> = command_to_run_payload
793                                .context
794                                .into_iter()
795                                .map(|e| (e.name, e.value))
796                                .collect();
797                            Ok(PluginCommand::OpenCommandPane(
798                                command_to_run.try_into()?,
799                                context,
800                            ))
801                        },
802                        None => Err("Malformed open open command pane payload"),
803                    }
804                },
805                _ => Err("Mismatched payload for OpenCommandPane"),
806            },
807            Some(CommandName::OpenCommandPaneFloating) => match protobuf_plugin_command.payload {
808                Some(Payload::OpenCommandPaneFloatingPayload(command_to_run_payload)) => {
809                    let floating_pane_coordinates = command_to_run_payload
810                        .floating_pane_coordinates
811                        .map(|f| f.into());
812                    match command_to_run_payload.command_to_run {
813                        Some(command_to_run) => {
814                            let context: BTreeMap<String, String> = command_to_run_payload
815                                .context
816                                .into_iter()
817                                .map(|e| (e.name, e.value))
818                                .collect();
819                            Ok(PluginCommand::OpenCommandPaneFloating(
820                                command_to_run.try_into()?,
821                                floating_pane_coordinates,
822                                context,
823                            ))
824                        },
825                        None => Err("Malformed open command pane floating payload"),
826                    }
827                },
828                _ => Err("Mismatched payload for OpenCommandPaneFloating"),
829            },
830            Some(CommandName::SwitchTabTo) => match protobuf_plugin_command.payload {
831                Some(Payload::SwitchTabToPayload(switch_to_tab_payload)) => Ok(
832                    PluginCommand::SwitchTabTo(switch_to_tab_payload.tab_index as u32),
833                ),
834                _ => Err("Mismatched payload for SwitchToTab"),
835            },
836            Some(CommandName::SetTimeout) => match protobuf_plugin_command.payload {
837                Some(Payload::SetTimeoutPayload(set_timeout_payload)) => {
838                    Ok(PluginCommand::SetTimeout(set_timeout_payload.seconds))
839                },
840                _ => Err("Mismatched payload for SetTimeout"),
841            },
842            Some(CommandName::ExecCmd) => match protobuf_plugin_command.payload {
843                Some(Payload::ExecCmdPayload(exec_cmd_payload)) => {
844                    Ok(PluginCommand::ExecCmd(exec_cmd_payload.command_line))
845                },
846                _ => Err("Mismatched payload for ExecCmd"),
847            },
848            Some(CommandName::PostMessageTo) => match protobuf_plugin_command.payload {
849                Some(Payload::PostMessageToPayload(post_message_to_payload)) => {
850                    match post_message_to_payload.message {
851                        Some(message) => Ok(PluginCommand::PostMessageTo(message.try_into()?)),
852                        None => Err("Malformed post message to payload"),
853                    }
854                },
855                _ => Err("Mismatched payload for PostMessageTo"),
856            },
857            Some(CommandName::PostMessageToPlugin) => match protobuf_plugin_command.payload {
858                Some(Payload::PostMessageToPluginPayload(post_message_to_payload)) => {
859                    match post_message_to_payload.message {
860                        Some(message) => {
861                            Ok(PluginCommand::PostMessageToPlugin(message.try_into()?))
862                        },
863                        None => Err("Malformed post message to plugin payload"),
864                    }
865                },
866                _ => Err("Mismatched payload for PostMessageToPlugin"),
867            },
868            Some(CommandName::HideSelf) => {
869                if protobuf_plugin_command.payload.is_some() {
870                    return Err("HideSelf should not have a payload");
871                }
872                Ok(PluginCommand::HideSelf)
873            },
874            Some(CommandName::ShowSelf) => match protobuf_plugin_command.payload {
875                Some(Payload::ShowSelfPayload(should_float_if_hidden)) => {
876                    Ok(PluginCommand::ShowSelf(should_float_if_hidden))
877                },
878                _ => Err("Mismatched payload for ShowSelf"),
879            },
880            Some(CommandName::SwitchToMode) => match protobuf_plugin_command.payload {
881                Some(Payload::SwitchToModePayload(switch_to_mode_payload)) => {
882                    match ProtobufInputMode::try_from(switch_to_mode_payload.input_mode).ok() {
883                        Some(protobuf_input_mode) => {
884                            Ok(PluginCommand::SwitchToMode(protobuf_input_mode.try_into()?))
885                        },
886                        None => Err("Malformed switch to mode payload"),
887                    }
888                },
889                _ => Err("Mismatched payload for SwitchToMode"),
890            },
891            Some(CommandName::NewTabsWithLayout) => match protobuf_plugin_command.payload {
892                Some(Payload::NewTabsWithLayoutPayload(raw_layout)) => {
893                    Ok(PluginCommand::NewTabsWithLayout(raw_layout))
894                },
895                _ => Err("Mismatched payload for NewTabsWithLayout"),
896            },
897            Some(CommandName::NewTab) => match protobuf_plugin_command.payload {
898                Some(Payload::NewTabPayload(protobuf_new_tab_payload)) => {
899                    Ok(PluginCommand::NewTab {
900                        name: protobuf_new_tab_payload.name,
901                        cwd: protobuf_new_tab_payload.cwd,
902                    })
903                },
904                None => Ok(PluginCommand::NewTab {
905                    name: None,
906                    cwd: None,
907                }),
908                _ => Err("Mismatched payload for NewTab"),
909            },
910            Some(CommandName::NewTabUnfocused) => match protobuf_plugin_command.payload {
911                Some(Payload::NewTabUnfocusedPayload(payload)) => {
912                    Ok(PluginCommand::NewTabUnfocused {
913                        name: payload.name,
914                        cwd: payload.cwd,
915                    })
916                },
917                None => Ok(PluginCommand::NewTabUnfocused {
918                    name: None,
919                    cwd: None,
920                }),
921                _ => Err("Mismatched payload for NewTabUnfocused"),
922            },
923            Some(CommandName::NewTiledPaneInTab) => match protobuf_plugin_command.payload {
924                Some(Payload::NewTiledPaneInTabPayload(payload)) => {
925                    Ok(PluginCommand::NewTiledPaneInTab {
926                        tab_position: payload.tab_position as usize,
927                    })
928                },
929                _ => Err("Mismatched payload for NewTiledPaneInTab"),
930            },
931            Some(CommandName::ToggleFloatingPanes) => match protobuf_plugin_command.payload {
932                Some(Payload::ToggleFloatingPanesPayload(payload)) => {
933                    Ok(PluginCommand::ToggleFloatingPanes {
934                        tab_id: payload.tab_id,
935                    })
936                },
937                _ => Ok(PluginCommand::ToggleFloatingPanes { tab_id: None }),
938            },
939            Some(CommandName::NewPane) => {
940                if protobuf_plugin_command.payload.is_some() {
941                    return Err("NewPane should not have a payload");
942                }
943                Ok(PluginCommand::NewPane)
944            },
945            Some(CommandName::GoToNextTab) => {
946                if protobuf_plugin_command.payload.is_some() {
947                    return Err("GoToNextTab should not have a payload");
948                }
949                Ok(PluginCommand::GoToNextTab)
950            },
951            Some(CommandName::GoToPreviousTab) => {
952                if protobuf_plugin_command.payload.is_some() {
953                    return Err("GoToPreviousTab should not have a payload");
954                }
955                Ok(PluginCommand::GoToPreviousTab)
956            },
957            Some(CommandName::Resize) => match protobuf_plugin_command.payload {
958                Some(Payload::ResizePayload(resize_payload)) => match resize_payload.resize {
959                    Some(resize) => Ok(PluginCommand::Resize(resize.try_into()?)),
960                    None => Err("Malformed switch resize payload"),
961                },
962                _ => Err("Mismatched payload for Resize"),
963            },
964            Some(CommandName::ResizeWithDirection) => match protobuf_plugin_command.payload {
965                Some(Payload::ResizeWithDirectionPayload(resize_with_direction_payload)) => {
966                    match resize_with_direction_payload.resize {
967                        Some(resize) => Ok(PluginCommand::ResizeWithDirection(resize.try_into()?)),
968                        None => Err("Malformed switch resize payload"),
969                    }
970                },
971                _ => Err("Mismatched payload for Resize"),
972            },
973            Some(CommandName::FocusNextPane) => {
974                if protobuf_plugin_command.payload.is_some() {
975                    return Err("FocusNextPane should not have a payload");
976                }
977                Ok(PluginCommand::FocusNextPane)
978            },
979            Some(CommandName::FocusPreviousPane) => {
980                if protobuf_plugin_command.payload.is_some() {
981                    return Err("FocusPreviousPane should not have a payload");
982                }
983                Ok(PluginCommand::FocusPreviousPane)
984            },
985            Some(CommandName::FocusLastPane) => {
986                if protobuf_plugin_command.payload.is_some() {
987                    return Err("FocusLastPane should not have a payload");
988                }
989                Ok(PluginCommand::FocusLastPane)
990            },
991            Some(CommandName::MoveFocus) => match protobuf_plugin_command.payload {
992                Some(Payload::MoveFocusPayload(move_payload)) => match move_payload.direction {
993                    Some(direction) => Ok(PluginCommand::MoveFocus(direction.try_into()?)),
994                    None => Err("Malformed move focus payload"),
995                },
996                _ => Err("Mismatched payload for MoveFocus"),
997            },
998            Some(CommandName::MoveFocusOrTab) => match protobuf_plugin_command.payload {
999                Some(Payload::MoveFocusOrTabPayload(move_payload)) => {
1000                    match move_payload.direction {
1001                        Some(direction) => Ok(PluginCommand::MoveFocusOrTab(direction.try_into()?)),
1002                        None => Err("Malformed move focus or tab payload"),
1003                    }
1004                },
1005                _ => Err("Mismatched payload for MoveFocusOrTab"),
1006            },
1007            Some(CommandName::Detach) => {
1008                if protobuf_plugin_command.payload.is_some() {
1009                    return Err("Detach should not have a payload");
1010                }
1011                Ok(PluginCommand::Detach)
1012            },
1013            Some(CommandName::EditScrollback) => {
1014                if protobuf_plugin_command.payload.is_some() {
1015                    return Err("EditScrollback should not have a payload");
1016                }
1017                Ok(PluginCommand::EditScrollback)
1018            },
1019            Some(CommandName::Write) => match protobuf_plugin_command.payload {
1020                Some(Payload::WritePayload(bytes)) => Ok(PluginCommand::Write(bytes)),
1021                _ => Err("Mismatched payload for Write"),
1022            },
1023            Some(CommandName::WriteChars) => match protobuf_plugin_command.payload {
1024                Some(Payload::WriteCharsPayload(chars)) => Ok(PluginCommand::WriteChars(chars)),
1025                _ => Err("Mismatched payload for WriteChars"),
1026            },
1027            Some(CommandName::ToggleTab) => {
1028                if protobuf_plugin_command.payload.is_some() {
1029                    return Err("ToggleTab should not have a payload");
1030                }
1031                Ok(PluginCommand::ToggleTab)
1032            },
1033            Some(CommandName::MovePane) => {
1034                if protobuf_plugin_command.payload.is_some() {
1035                    return Err("MovePane should not have a payload");
1036                }
1037                Ok(PluginCommand::MovePane)
1038            },
1039            Some(CommandName::MovePaneWithDirection) => match protobuf_plugin_command.payload {
1040                Some(Payload::MovePaneWithDirectionPayload(move_payload)) => {
1041                    match move_payload.direction {
1042                        Some(direction) => {
1043                            Ok(PluginCommand::MovePaneWithDirection(direction.try_into()?))
1044                        },
1045                        None => Err("Malformed MovePaneWithDirection payload"),
1046                    }
1047                },
1048                _ => Err("Mismatched payload for MovePaneWithDirection"),
1049            },
1050            Some(CommandName::ClearScreen) => {
1051                if protobuf_plugin_command.payload.is_some() {
1052                    return Err("ClearScreen should not have a payload");
1053                }
1054                Ok(PluginCommand::ClearScreen)
1055            },
1056            Some(CommandName::ScrollUp) => {
1057                if protobuf_plugin_command.payload.is_some() {
1058                    return Err("ScrollUp should not have a payload");
1059                }
1060                Ok(PluginCommand::ScrollUp)
1061            },
1062            Some(CommandName::ScrollDown) => {
1063                if protobuf_plugin_command.payload.is_some() {
1064                    return Err("ScrollDown should not have a payload");
1065                }
1066                Ok(PluginCommand::ScrollDown)
1067            },
1068            Some(CommandName::ScrollToTop) => {
1069                if protobuf_plugin_command.payload.is_some() {
1070                    return Err("ScrollToTop should not have a payload");
1071                }
1072                Ok(PluginCommand::ScrollToTop)
1073            },
1074            Some(CommandName::ScrollToBottom) => {
1075                if protobuf_plugin_command.payload.is_some() {
1076                    return Err("ScrollToBottom should not have a payload");
1077                }
1078                Ok(PluginCommand::ScrollToBottom)
1079            },
1080            Some(CommandName::PageScrollUp) => {
1081                if protobuf_plugin_command.payload.is_some() {
1082                    return Err("PageScrollUp should not have a payload");
1083                }
1084                Ok(PluginCommand::PageScrollUp)
1085            },
1086            Some(CommandName::PageScrollDown) => {
1087                if protobuf_plugin_command.payload.is_some() {
1088                    return Err("PageScrollDown should not have a payload");
1089                }
1090                Ok(PluginCommand::PageScrollDown)
1091            },
1092            Some(CommandName::ToggleFocusFullscreen) => {
1093                if protobuf_plugin_command.payload.is_some() {
1094                    return Err("ToggleFocusFullscreen should not have a payload");
1095                }
1096                Ok(PluginCommand::ToggleFocusFullscreen)
1097            },
1098            Some(CommandName::ToggleFocusNoUiFullscreen) => {
1099                if protobuf_plugin_command.payload.is_some() {
1100                    return Err("ToggleFocusNoUiFullscreen should not have a payload");
1101                }
1102                Ok(PluginCommand::ToggleFocusNoUiFullscreen)
1103            },
1104            Some(CommandName::FocusHostSession) => {
1105                if protobuf_plugin_command.payload.is_some() {
1106                    return Err("FocusHostSession should not have a payload");
1107                }
1108                Ok(PluginCommand::FocusHostSession)
1109            },
1110            Some(CommandName::TogglePaneFrames) => {
1111                if protobuf_plugin_command.payload.is_some() {
1112                    return Err("TogglePaneFrames should not have a payload");
1113                }
1114                Ok(PluginCommand::TogglePaneFrames)
1115            },
1116            Some(CommandName::SetPaneFrameStyle) => match protobuf_plugin_command.payload {
1117                Some(Payload::SetPaneFrameStylePayload(payload)) => {
1118                    match ProtobufPaneFrameStyle::try_from(payload.pane_frame_style).ok() {
1119                        Some(protobuf_pane_frame_style) => Ok(PluginCommand::SetPaneFrameStyle(
1120                            protobuf_pane_frame_style.try_into()?,
1121                        )),
1122                        None => Err("Malformed SetPaneFrameStyle payload"),
1123                    }
1124                },
1125                _ => Err("Mismatched payload for SetPaneFrameStyle"),
1126            },
1127            Some(CommandName::TogglePaneEmbedOrEject) => {
1128                if protobuf_plugin_command.payload.is_some() {
1129                    return Err("TogglePaneEmbedOrEject should not have a payload");
1130                }
1131                Ok(PluginCommand::TogglePaneEmbedOrEject)
1132            },
1133            Some(CommandName::UndoRenamePane) => {
1134                if protobuf_plugin_command.payload.is_some() {
1135                    return Err("UndoRenamePane should not have a payload");
1136                }
1137                Ok(PluginCommand::UndoRenamePane)
1138            },
1139            Some(CommandName::CloseFocus) => {
1140                if protobuf_plugin_command.payload.is_some() {
1141                    return Err("CloseFocus should not have a payload");
1142                }
1143                Ok(PluginCommand::CloseFocus)
1144            },
1145            Some(CommandName::ToggleActiveTabSync) => {
1146                if protobuf_plugin_command.payload.is_some() {
1147                    return Err("ToggleActiveTabSync should not have a payload");
1148                }
1149                Ok(PluginCommand::ToggleActiveTabSync)
1150            },
1151            Some(CommandName::CloseFocusedTab) => {
1152                if protobuf_plugin_command.payload.is_some() {
1153                    return Err("CloseFocusedTab should not have a payload");
1154                }
1155                Ok(PluginCommand::CloseFocusedTab)
1156            },
1157            Some(CommandName::UndoRenameTab) => {
1158                if protobuf_plugin_command.payload.is_some() {
1159                    return Err("UndoRenameTab should not have a payload");
1160                }
1161                Ok(PluginCommand::UndoRenameTab)
1162            },
1163            Some(CommandName::QuitZellij) => {
1164                if protobuf_plugin_command.payload.is_some() {
1165                    return Err("QuitZellij should not have a payload");
1166                }
1167                Ok(PluginCommand::QuitZellij)
1168            },
1169            Some(CommandName::PreviousSwapLayout) => {
1170                if protobuf_plugin_command.payload.is_some() {
1171                    return Err("PreviousSwapLayout should not have a payload");
1172                }
1173                Ok(PluginCommand::PreviousSwapLayout)
1174            },
1175            Some(CommandName::NextSwapLayout) => {
1176                if protobuf_plugin_command.payload.is_some() {
1177                    return Err("NextSwapLayout should not have a payload");
1178                }
1179                Ok(PluginCommand::NextSwapLayout)
1180            },
1181            Some(CommandName::GoToTabName) => match protobuf_plugin_command.payload {
1182                Some(Payload::GoToTabNamePayload(tab_name)) => {
1183                    Ok(PluginCommand::GoToTabName(tab_name))
1184                },
1185                _ => Err("Mismatched payload for GoToTabName"),
1186            },
1187            Some(CommandName::FocusOrCreateTab) => match protobuf_plugin_command.payload {
1188                Some(Payload::FocusOrCreateTabPayload(tab_name)) => {
1189                    Ok(PluginCommand::FocusOrCreateTab(tab_name))
1190                },
1191                _ => Err("Mismatched payload for FocusOrCreateTab"),
1192            },
1193            Some(CommandName::GoToTab) => match protobuf_plugin_command.payload {
1194                Some(Payload::GoToTabPayload(tab_index)) => {
1195                    Ok(PluginCommand::GoToTab(tab_index as u32))
1196                },
1197                _ => Err("Mismatched payload for GoToTab"),
1198            },
1199            Some(CommandName::StartOrReloadPlugin) => match protobuf_plugin_command.payload {
1200                Some(Payload::StartOrReloadPluginPayload(url)) => {
1201                    Ok(PluginCommand::StartOrReloadPlugin(url))
1202                },
1203                _ => Err("Mismatched payload for StartOrReloadPlugin"),
1204            },
1205            Some(CommandName::CloseTerminalPane) => match protobuf_plugin_command.payload {
1206                Some(Payload::CloseTerminalPanePayload(pane_id)) => {
1207                    Ok(PluginCommand::CloseTerminalPane(pane_id as u32))
1208                },
1209                _ => Err("Mismatched payload for CloseTerminalPane"),
1210            },
1211            Some(CommandName::ClosePluginPane) => match protobuf_plugin_command.payload {
1212                Some(Payload::ClosePluginPanePayload(pane_id)) => {
1213                    Ok(PluginCommand::ClosePluginPane(pane_id as u32))
1214                },
1215                _ => Err("Mismatched payload for ClosePluginPane"),
1216            },
1217            Some(CommandName::FocusTerminalPane) => match protobuf_plugin_command.payload {
1218                Some(Payload::FocusTerminalPanePayload(payload)) => {
1219                    let pane_id = payload.pane_id as u32;
1220                    let should_float = payload.should_float;
1221                    let should_be_in_place = payload.should_be_in_place;
1222                    Ok(PluginCommand::FocusTerminalPane(
1223                        pane_id,
1224                        should_float,
1225                        should_be_in_place,
1226                    ))
1227                },
1228                _ => Err("Mismatched payload for ClosePluginPane"),
1229            },
1230            Some(CommandName::FocusPluginPane) => match protobuf_plugin_command.payload {
1231                Some(Payload::FocusPluginPanePayload(payload)) => {
1232                    let pane_id = payload.pane_id as u32;
1233                    let should_float = payload.should_float;
1234                    let should_be_in_place = payload.should_be_in_place;
1235                    Ok(PluginCommand::FocusPluginPane(
1236                        pane_id,
1237                        should_float,
1238                        should_be_in_place,
1239                    ))
1240                },
1241                _ => Err("Mismatched payload for ClosePluginPane"),
1242            },
1243            Some(CommandName::RenameTerminalPane) => match protobuf_plugin_command.payload {
1244                Some(Payload::RenameTerminalPanePayload(payload)) => {
1245                    let pane_id = payload.id as u32;
1246                    let new_name = payload.new_name;
1247                    Ok(PluginCommand::RenameTerminalPane(pane_id, new_name))
1248                },
1249                _ => Err("Mismatched payload for RenameTerminalPane"),
1250            },
1251            Some(CommandName::RenamePluginPane) => match protobuf_plugin_command.payload {
1252                Some(Payload::RenamePluginPanePayload(payload)) => {
1253                    let pane_id = payload.id as u32;
1254                    let new_name = payload.new_name;
1255                    Ok(PluginCommand::RenamePluginPane(pane_id, new_name))
1256                },
1257                _ => Err("Mismatched payload for RenamePluginPane"),
1258            },
1259            Some(CommandName::RenameTab) => match protobuf_plugin_command.payload {
1260                Some(Payload::RenameTabPayload(payload)) => {
1261                    let tab_index = payload.id as u32;
1262                    let name = payload.new_name;
1263                    Ok(PluginCommand::RenameTab(tab_index, name))
1264                },
1265                _ => Err("Mismatched payload for RenameTab"),
1266            },
1267            Some(CommandName::ReportCrash) => match protobuf_plugin_command.payload {
1268                Some(Payload::ReportCrashPayload(payload)) => {
1269                    Ok(PluginCommand::ReportPanic(payload))
1270                },
1271                _ => Err("Mismatched payload for ReportCrash"),
1272            },
1273            Some(CommandName::RequestPluginPermissions) => match protobuf_plugin_command.payload {
1274                Some(Payload::RequestPluginPermissionPayload(payload)) => {
1275                    Ok(PluginCommand::RequestPluginPermissions(
1276                        payload
1277                            .permissions
1278                            .iter()
1279                            .filter_map(|p| ProtobufPermissionType::try_from(*p).ok())
1280                            .filter_map(|p| PermissionType::try_from(p).ok())
1281                            .collect(),
1282                    ))
1283                },
1284                _ => Err("Mismatched payload for RequestPluginPermission"),
1285            },
1286            Some(CommandName::SwitchSession) => match protobuf_plugin_command.payload {
1287                Some(Payload::SwitchSessionPayload(payload)) => {
1288                    let pane_id = match (payload.pane_id, payload.pane_id_is_plugin) {
1289                        (Some(pane_id), Some(is_plugin)) => Some((pane_id, is_plugin)),
1290                        (None, None) => None,
1291                        _ => {
1292                            return Err("Malformed payload for SwitchSession, 'pane_id' and 'is_plugin' must be included together or not at all")
1293                        }
1294                    };
1295                    Ok(PluginCommand::SwitchSession(ConnectToSession {
1296                        name: payload.name,
1297                        tab_position: payload.tab_position.map(|p| p as usize),
1298                        pane_id,
1299                        layout: payload.layout.and_then(|l| l.try_into().ok()),
1300                        cwd: payload.cwd.map(|c| PathBuf::from(c)),
1301                    }))
1302                },
1303                _ => Err("Mismatched payload for SwitchSession"),
1304            },
1305            Some(CommandName::OpenTerminalInPlace) => match protobuf_plugin_command.payload {
1306                Some(Payload::OpenTerminalInPlacePayload(file_to_open_payload)) => {
1307                    match file_to_open_payload.file_to_open {
1308                        Some(file_to_open) => {
1309                            Ok(PluginCommand::OpenTerminalInPlace(file_to_open.try_into()?))
1310                        },
1311                        None => Err("Malformed open terminal in-place payload"),
1312                    }
1313                },
1314                _ => Err("Mismatched payload for OpenTerminalInPlace"),
1315            },
1316            Some(CommandName::OpenFileInPlace) => match protobuf_plugin_command.payload {
1317                Some(Payload::OpenFileInPlacePayload(file_to_open_payload)) => {
1318                    match file_to_open_payload.file_to_open {
1319                        Some(file_to_open) => {
1320                            let context: BTreeMap<String, String> = file_to_open_payload
1321                                .context
1322                                .into_iter()
1323                                .map(|e| (e.name, e.value))
1324                                .collect();
1325                            Ok(PluginCommand::OpenFileInPlace(
1326                                file_to_open.try_into()?,
1327                                context,
1328                            ))
1329                        },
1330                        None => Err("Malformed open file in place payload"),
1331                    }
1332                },
1333                _ => Err("Mismatched payload for OpenFileInPlace"),
1334            },
1335            Some(CommandName::OpenCommandInPlace) => match protobuf_plugin_command.payload {
1336                Some(Payload::OpenCommandPaneInPlacePayload(command_to_run_payload)) => {
1337                    match command_to_run_payload.command_to_run {
1338                        Some(command_to_run) => {
1339                            let context: BTreeMap<String, String> = command_to_run_payload
1340                                .context
1341                                .into_iter()
1342                                .map(|e| (e.name, e.value))
1343                                .collect();
1344                            Ok(PluginCommand::OpenCommandPaneInPlace(
1345                                command_to_run.try_into()?,
1346                                context,
1347                            ))
1348                        },
1349                        None => Err("Malformed open command pane in-place payload"),
1350                    }
1351                },
1352                _ => Err("Mismatched payload for OpenCommandPaneInPlace"),
1353            },
1354            Some(CommandName::RunCommand) => match protobuf_plugin_command.payload {
1355                Some(Payload::RunCommandPayload(run_command_payload)) => {
1356                    let env_variables: BTreeMap<String, String> = run_command_payload
1357                        .env_variables
1358                        .into_iter()
1359                        .map(|e| (e.name, e.value))
1360                        .collect();
1361                    let context: BTreeMap<String, String> = run_command_payload
1362                        .context
1363                        .into_iter()
1364                        .map(|e| (e.name, e.value))
1365                        .collect();
1366                    Ok(PluginCommand::RunCommand(
1367                        run_command_payload.command_line,
1368                        env_variables,
1369                        PathBuf::from(run_command_payload.cwd),
1370                        context,
1371                    ))
1372                },
1373                _ => Err("Mismatched payload for RunCommand"),
1374            },
1375            Some(CommandName::WebRequest) => match protobuf_plugin_command.payload {
1376                Some(Payload::WebRequestPayload(web_request_payload)) => {
1377                    let context: BTreeMap<String, String> = web_request_payload
1378                        .context
1379                        .into_iter()
1380                        .map(|e| (e.name, e.value))
1381                        .collect();
1382                    let headers: BTreeMap<String, String> = web_request_payload
1383                        .headers
1384                        .into_iter()
1385                        .map(|e| (e.name, e.value))
1386                        .collect();
1387                    let verb = match ProtobufHttpVerb::try_from(web_request_payload.verb).ok() {
1388                        Some(verb) => verb.into(),
1389                        None => {
1390                            return Err("Unrecognized http verb");
1391                        },
1392                    };
1393                    Ok(PluginCommand::WebRequest(
1394                        web_request_payload.url,
1395                        verb,
1396                        headers,
1397                        web_request_payload.body,
1398                        context,
1399                    ))
1400                },
1401                _ => Err("Mismatched payload for WebRequest"),
1402            },
1403            Some(CommandName::DeleteDeadSession) => match protobuf_plugin_command.payload {
1404                Some(Payload::DeleteDeadSessionPayload(dead_session_name)) => {
1405                    Ok(PluginCommand::DeleteDeadSession(dead_session_name))
1406                },
1407                _ => Err("Mismatched payload for DeleteDeadSession"),
1408            },
1409            Some(CommandName::DeleteAllDeadSessions) => Ok(PluginCommand::DeleteAllDeadSessions),
1410            Some(CommandName::RenameSession) => match protobuf_plugin_command.payload {
1411                Some(Payload::RenameSessionPayload(new_session_name)) => {
1412                    Ok(PluginCommand::RenameSession(new_session_name))
1413                },
1414                _ => Err("Mismatched payload for RenameSession"),
1415            },
1416            Some(CommandName::UnblockCliPipeInput) => match protobuf_plugin_command.payload {
1417                Some(Payload::UnblockCliPipeInputPayload(pipe_name)) => {
1418                    Ok(PluginCommand::UnblockCliPipeInput(pipe_name))
1419                },
1420                _ => Err("Mismatched payload for UnblockPipeInput"),
1421            },
1422            Some(CommandName::BlockCliPipeInput) => match protobuf_plugin_command.payload {
1423                Some(Payload::BlockCliPipeInputPayload(pipe_name)) => {
1424                    Ok(PluginCommand::BlockCliPipeInput(pipe_name))
1425                },
1426                _ => Err("Mismatched payload for BlockPipeInput"),
1427            },
1428            Some(CommandName::CliPipeOutput) => match protobuf_plugin_command.payload {
1429                Some(Payload::CliPipeOutputPayload(CliPipeOutputPayload { pipe_name, output })) => {
1430                    Ok(PluginCommand::CliPipeOutput(pipe_name, output))
1431                },
1432                _ => Err("Mismatched payload for PipeOutput"),
1433            },
1434            Some(CommandName::MessageToPlugin) => match protobuf_plugin_command.payload {
1435                Some(Payload::MessageToPluginPayload(MessageToPluginPayload {
1436                    plugin_url,
1437                    plugin_config,
1438                    message_name,
1439                    message_payload,
1440                    message_args,
1441                    new_plugin_args,
1442                    destination_plugin_id,
1443                    floating_pane_coordinates,
1444                })) => {
1445                    let plugin_config: BTreeMap<String, String> = plugin_config
1446                        .into_iter()
1447                        .map(|e| (e.name, e.value))
1448                        .collect();
1449                    let message_args: BTreeMap<String, String> = message_args
1450                        .into_iter()
1451                        .map(|e| (e.name, e.value))
1452                        .collect();
1453                    Ok(PluginCommand::MessageToPlugin(MessageToPlugin {
1454                        plugin_url,
1455                        plugin_config,
1456                        message_name,
1457                        message_payload,
1458                        message_args,
1459                        new_plugin_args: new_plugin_args.and_then(|protobuf_new_plugin_args| {
1460                            Some(NewPluginArgs {
1461                                should_float: protobuf_new_plugin_args.should_float,
1462                                pane_id_to_replace: protobuf_new_plugin_args
1463                                    .pane_id_to_replace
1464                                    .and_then(|p_id| PaneId::try_from(p_id).ok()),
1465                                pane_title: protobuf_new_plugin_args.pane_title,
1466                                cwd: protobuf_new_plugin_args.cwd.map(|cwd| PathBuf::from(cwd)),
1467                                skip_cache: protobuf_new_plugin_args.skip_cache,
1468                                should_focus: protobuf_new_plugin_args.should_focus,
1469                            })
1470                        }),
1471                        destination_plugin_id,
1472                        floating_pane_coordinates: floating_pane_coordinates
1473                            .and_then(|f| f.try_into().ok()),
1474                    }))
1475                },
1476                _ => Err("Mismatched payload for MessageToPlugin"),
1477            },
1478            Some(CommandName::DisconnectOtherClients) => match protobuf_plugin_command.payload {
1479                None => Ok(PluginCommand::DisconnectOtherClients),
1480                _ => Err("Mismatched payload for DisconnectOtherClients"),
1481            },
1482            Some(CommandName::KillSessions) => match protobuf_plugin_command.payload {
1483                Some(Payload::KillSessionsPayload(KillSessionsPayload { session_names })) => {
1484                    Ok(PluginCommand::KillSessions(session_names))
1485                },
1486                _ => Err("Mismatched payload for KillSessions"),
1487            },
1488            Some(CommandName::ScanHostFolder) => match protobuf_plugin_command.payload {
1489                Some(Payload::ScanHostFolderPayload(folder_to_scan)) => {
1490                    Ok(PluginCommand::ScanHostFolder(PathBuf::from(folder_to_scan)))
1491                },
1492                _ => Err("Mismatched payload for ScanHostFolder"),
1493            },
1494            Some(CommandName::WatchFilesystem) => match protobuf_plugin_command.payload {
1495                Some(_) => Err("WatchFilesystem should have no payload, found a payload"),
1496                None => Ok(PluginCommand::WatchFilesystem),
1497            },
1498            Some(CommandName::ListWindowsVolumes) => match protobuf_plugin_command.payload {
1499                Some(_) => Err("ListWindowsVolumes should have no payload"),
1500                None => Ok(PluginCommand::ListWindowsVolumes),
1501            },
1502            Some(CommandName::GetSessionList) => match protobuf_plugin_command.payload {
1503                Some(Payload::GetSessionListPayload(_)) => Ok(PluginCommand::GetSessionList),
1504                None => Ok(PluginCommand::GetSessionList),
1505                _ => Err("Mismatched payload for GetSessionList"),
1506            },
1507            Some(CommandName::KillSessionsAndReply) => match protobuf_plugin_command.payload {
1508                Some(Payload::KillSessionsAndReplyPayload(KillSessionsPayload {
1509                    session_names,
1510                })) => Ok(PluginCommand::KillSessionsAndReply(session_names)),
1511                _ => Err("Mismatched payload for KillSessionsAndReply"),
1512            },
1513            Some(CommandName::DeleteDeadSessionAndReply) => match protobuf_plugin_command.payload {
1514                Some(Payload::DeleteDeadSessionAndReplyPayload(dead_session_name)) => {
1515                    Ok(PluginCommand::DeleteDeadSessionAndReply(dead_session_name))
1516                },
1517                _ => Err("Mismatched payload for DeleteDeadSessionAndReply"),
1518            },
1519            Some(CommandName::DeleteAllDeadSessionsAndReply) => {
1520                Ok(PluginCommand::DeleteAllDeadSessionsAndReply)
1521            },
1522            Some(CommandName::SetSoftKeyboard) => match protobuf_plugin_command.payload {
1523                Some(Payload::SetSoftKeyboardPayload(payload)) => {
1524                    Ok(PluginCommand::SetSoftKeyboard(payload.on))
1525                },
1526                _ => Err("Mismatched payload for SetSoftKeyboard"),
1527            },
1528            Some(CommandName::DumpSessionLayout) => match protobuf_plugin_command.payload {
1529                Some(Payload::DumpSessionLayoutPayload(payload)) => {
1530                    Ok(PluginCommand::DumpSessionLayout {
1531                        tab_index: payload.tab_index.map(|i| i as usize),
1532                    })
1533                },
1534                None => Ok(PluginCommand::DumpSessionLayout { tab_index: None }),
1535                _ => Err("Mismatched payload for DumpSessionLayout"),
1536            },
1537            Some(CommandName::CloseSelf) => match protobuf_plugin_command.payload {
1538                Some(_) => Err("CloseSelf should have no payload, found a payload"),
1539                None => Ok(PluginCommand::CloseSelf),
1540            },
1541            Some(CommandName::NewTabsWithLayoutInfo) => match protobuf_plugin_command.payload {
1542                Some(Payload::NewTabsWithLayoutInfoPayload(new_tabs_with_layout_info_payload)) => {
1543                    new_tabs_with_layout_info_payload
1544                        .layout_info
1545                        .and_then(|layout_info| {
1546                            Some(PluginCommand::NewTabsWithLayoutInfo(
1547                                layout_info.try_into().ok()?,
1548                            ))
1549                        })
1550                        .ok_or("Failed to parse NewTabsWithLayoutInfo command")
1551                },
1552                _ => Err("Mismatched payload for NewTabsWithLayoutInfo"),
1553            },
1554            Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
1555                Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
1556                    Ok(PluginCommand::Reconfigure(
1557                        reconfigure_payload.config,
1558                        reconfigure_payload.write_to_disk,
1559                    ))
1560                },
1561                _ => Err("Mismatched payload for Reconfigure"),
1562            },
1563            Some(CommandName::HidePaneWithId) => match protobuf_plugin_command.payload {
1564                Some(Payload::HidePaneWithIdPayload(hide_pane_with_id_payload)) => {
1565                    let pane_id = hide_pane_with_id_payload
1566                        .pane_id
1567                        .and_then(|p_id| PaneId::try_from(p_id).ok())
1568                        .ok_or("Failed to parse HidePaneWithId command")?;
1569                    Ok(PluginCommand::HidePaneWithId(pane_id))
1570                },
1571                _ => Err("Mismatched payload for HidePaneWithId"),
1572            },
1573            Some(CommandName::ShowPaneWithId) => match protobuf_plugin_command.payload {
1574                Some(Payload::ShowPaneWithIdPayload(show_pane_with_id_payload)) => {
1575                    let pane_id = show_pane_with_id_payload
1576                        .pane_id
1577                        .and_then(|p_id| PaneId::try_from(p_id).ok())
1578                        .ok_or("Failed to parse ShowPaneWithId command")?;
1579                    let should_float_if_hidden = show_pane_with_id_payload.should_float_if_hidden;
1580                    let should_focus_pane = show_pane_with_id_payload.should_focus_pane;
1581                    Ok(PluginCommand::ShowPaneWithId(
1582                        pane_id,
1583                        should_float_if_hidden,
1584                        should_focus_pane,
1585                    ))
1586                },
1587                _ => Err("Mismatched payload for ShowPaneWithId"),
1588            },
1589            Some(CommandName::OpenCommandPaneBackground) => match protobuf_plugin_command.payload {
1590                Some(Payload::OpenCommandPaneBackgroundPayload(command_to_run_payload)) => {
1591                    match command_to_run_payload.command_to_run {
1592                        Some(command_to_run) => {
1593                            let context: BTreeMap<String, String> = command_to_run_payload
1594                                .context
1595                                .into_iter()
1596                                .map(|e| (e.name, e.value))
1597                                .collect();
1598                            Ok(PluginCommand::OpenCommandPaneBackground(
1599                                command_to_run.try_into()?,
1600                                context,
1601                            ))
1602                        },
1603                        None => Err("Malformed open command pane background payload"),
1604                    }
1605                },
1606                _ => Err("Mismatched payload for OpenCommandPaneBackground"),
1607            },
1608            Some(CommandName::RerunCommandPane) => match protobuf_plugin_command.payload {
1609                Some(Payload::RerunCommandPanePayload(rerun_command_pane_payload)) => Ok(
1610                    PluginCommand::RerunCommandPane(rerun_command_pane_payload.terminal_pane_id),
1611                ),
1612                _ => Err("Mismatched payload for RerunCommandPane"),
1613            },
1614            Some(CommandName::ResizePaneIdWithDirection) => match protobuf_plugin_command.payload {
1615                Some(Payload::ResizePaneIdWithDirectionPayload(resize_with_direction_payload)) => {
1616                    match (
1617                        resize_with_direction_payload.resize,
1618                        resize_with_direction_payload.pane_id,
1619                    ) {
1620                        (Some(resize), Some(pane_id)) => {
1621                            Ok(PluginCommand::ResizePaneIdWithDirection(
1622                                resize.try_into()?,
1623                                pane_id.try_into()?,
1624                            ))
1625                        },
1626                        _ => Err("Malformed resize_pane_with_id payload"),
1627                    }
1628                },
1629                _ => Err("Mismatched payload for Resize"),
1630            },
1631            Some(CommandName::EditScrollbackForPaneWithId) => match protobuf_plugin_command.payload
1632            {
1633                Some(Payload::EditScrollbackForPaneWithIdPayload(
1634                    edit_scrollback_for_pane_with_id_payload,
1635                )) => match edit_scrollback_for_pane_with_id_payload.pane_id {
1636                    Some(pane_id) => Ok(PluginCommand::EditScrollbackForPaneWithId(
1637                        pane_id.try_into()?,
1638                    )),
1639                    _ => Err("Malformed edit_scrollback_for_pane_with_id payload"),
1640                },
1641                _ => Err("Mismatched payload for EditScrollback"),
1642            },
1643            Some(CommandName::GetPaneScrollback) => match protobuf_plugin_command.payload {
1644                Some(Payload::GetPaneScrollbackPayload(get_pane_scrollback_payload)) => {
1645                    match get_pane_scrollback_payload.pane_id {
1646                        Some(pane_id) => Ok(PluginCommand::GetPaneScrollback {
1647                            pane_id: pane_id.try_into()?,
1648                            get_full_scrollback: get_pane_scrollback_payload.get_full_scrollback,
1649                        }),
1650                        _ => Err("Malformed get_pane_scrollback_payload"),
1651                    }
1652                },
1653                _ => Err("Mismatched payload for GetPaneScrollback"),
1654            },
1655            Some(CommandName::WriteToPaneId) => match protobuf_plugin_command.payload {
1656                Some(Payload::WriteToPaneIdPayload(write_to_pane_id_payload)) => {
1657                    match write_to_pane_id_payload.pane_id {
1658                        Some(pane_id) => Ok(PluginCommand::WriteToPaneId(
1659                            write_to_pane_id_payload.bytes_to_write,
1660                            pane_id.try_into()?,
1661                        )),
1662                        _ => Err("Malformed write_to_pane_id payload"),
1663                    }
1664                },
1665                _ => Err("Mismatched payload for WriteToPaneId"),
1666            },
1667            Some(CommandName::WriteCharsToPaneId) => match protobuf_plugin_command.payload {
1668                Some(Payload::WriteCharsToPaneIdPayload(write_chars_to_pane_id_payload)) => {
1669                    match write_chars_to_pane_id_payload.pane_id {
1670                        Some(pane_id) => Ok(PluginCommand::WriteCharsToPaneId(
1671                            write_chars_to_pane_id_payload.chars_to_write,
1672                            pane_id.try_into()?,
1673                        )),
1674                        _ => Err("Malformed write_chars_to_pane_id payload"),
1675                    }
1676                },
1677                _ => Err("Mismatched payload for WriteCharsCharsToPaneId"),
1678            },
1679            Some(CommandName::SendSigintToPaneId) => match protobuf_plugin_command.payload {
1680                Some(Payload::SendSigintToPaneIdPayload(pane_id)) => {
1681                    Ok(PluginCommand::SendSigintToPaneId(pane_id.try_into()?))
1682                },
1683                _ => Err("Mismatched payload for SendSigintToPaneId"),
1684            },
1685            Some(CommandName::SendSigkillToPaneId) => match protobuf_plugin_command.payload {
1686                Some(Payload::SendSigkillToPaneIdPayload(pane_id)) => {
1687                    Ok(PluginCommand::SendSigkillToPaneId(pane_id.try_into()?))
1688                },
1689                _ => Err("Mismatched payload for SendSigkillToPaneId"),
1690            },
1691            Some(CommandName::GetPanePid) => match protobuf_plugin_command.payload {
1692                Some(Payload::GetPanePidPayload(get_pane_pid_payload)) => {
1693                    match get_pane_pid_payload.pane_id {
1694                        Some(pane_id) => Ok(PluginCommand::GetPanePid {
1695                            pane_id: pane_id.try_into()?,
1696                        }),
1697                        _ => Err("Malformed get_pane_pid payload"),
1698                    }
1699                },
1700                _ => Err("Mismatched payload for GetPanePid"),
1701            },
1702            Some(CommandName::GetPaneRunningCommand) => match protobuf_plugin_command.payload {
1703                Some(Payload::GetPaneRunningCommandPayload(payload)) => {
1704                    Ok(PluginCommand::GetPaneRunningCommand {
1705                        pane_id: payload
1706                            .pane_id
1707                            .ok_or("Malformed GetPaneRunningCommand: missing pane_id")?
1708                            .try_into()?,
1709                    })
1710                },
1711                _ => Err("Malformed GetPaneRunningCommand payload"),
1712            },
1713            Some(CommandName::GetPaneCwd) => match protobuf_plugin_command.payload {
1714                Some(Payload::GetPaneCwdPayload(payload)) => Ok(PluginCommand::GetPaneCwd {
1715                    pane_id: payload
1716                        .pane_id
1717                        .ok_or("Malformed GetPaneCwd: missing pane_id")?
1718                        .try_into()?,
1719                }),
1720                _ => Err("Malformed GetPaneCwd payload"),
1721            },
1722            Some(CommandName::OverrideLayout) => match protobuf_plugin_command.payload {
1723                Some(Payload::OverrideLayoutPayload(override_layout_payload)) => {
1724                    let layout_info = override_layout_payload
1725                        .layout_info
1726                        .ok_or("OverrideLayout missing layout_info")?
1727                        .try_into()
1728                        .map_err(|_| "Failed to parse LayoutInfo")?;
1729                    let context = override_layout_payload
1730                        .context
1731                        .into_iter()
1732                        .map(|c| (c.name, c.value))
1733                        .collect();
1734                    Ok(PluginCommand::OverrideLayout(
1735                        layout_info,
1736                        override_layout_payload.retain_existing_terminal_panes,
1737                        override_layout_payload.retain_existing_plugin_panes,
1738                        override_layout_payload.apply_only_to_active_tab,
1739                        context,
1740                    ))
1741                },
1742                _ => Err("Mismatched payload for OverrideLayout"),
1743            },
1744            Some(CommandName::SaveLayout) => match protobuf_plugin_command.payload {
1745                Some(Payload::SaveLayoutPayload(save_layout_payload)) => {
1746                    Ok(PluginCommand::SaveLayout {
1747                        layout_name: save_layout_payload.layout_name,
1748                        layout_kdl: save_layout_payload.layout_kdl,
1749                        overwrite: save_layout_payload.overwrite,
1750                    })
1751                },
1752                _ => Err("Mismatched payload for SaveLayout"),
1753            },
1754            Some(CommandName::DeleteLayout) => match protobuf_plugin_command.payload {
1755                Some(Payload::DeleteLayoutPayload(delete_layout_payload)) => {
1756                    Ok(PluginCommand::DeleteLayout {
1757                        layout_name: delete_layout_payload.layout_name,
1758                    })
1759                },
1760                _ => Err("Mismatched payload for DeleteLayout"),
1761            },
1762            Some(CommandName::RenameLayout) => match protobuf_plugin_command.payload {
1763                Some(Payload::RenameLayoutPayload(rename_layout_payload)) => {
1764                    Ok(PluginCommand::RenameLayout {
1765                        old_layout_name: rename_layout_payload.old_layout_name,
1766                        new_layout_name: rename_layout_payload.new_layout_name,
1767                    })
1768                },
1769                _ => Err("Mismatched payload for RenameLayout"),
1770            },
1771            Some(CommandName::EditLayout) => match protobuf_plugin_command.payload {
1772                Some(Payload::EditLayoutPayload(edit_layout_payload)) => {
1773                    let layout_name = edit_layout_payload.layout_name;
1774                    let context: BTreeMap<String, String> = edit_layout_payload
1775                        .context
1776                        .into_iter()
1777                        .map(|e| (e.name, e.value))
1778                        .collect();
1779                    Ok(PluginCommand::EditLayout {
1780                        layout_name,
1781                        context,
1782                    })
1783                },
1784                _ => Err("Mismatched payload for EditLayout"),
1785            },
1786            Some(CommandName::MovePaneWithPaneId) => match protobuf_plugin_command.payload {
1787                Some(Payload::MovePaneWithPaneIdPayload(move_pane_with_pane_id_payload)) => {
1788                    match move_pane_with_pane_id_payload.pane_id {
1789                        Some(pane_id) => Ok(PluginCommand::MovePaneWithPaneId(pane_id.try_into()?)),
1790                        _ => Err("Malformed move_pane_with_pane_id payload"),
1791                    }
1792                },
1793                _ => Err("Mismatched payload for MovePaneWithPaneId"),
1794            },
1795            Some(CommandName::MovePaneWithPaneIdInDirection) => {
1796                match protobuf_plugin_command.payload {
1797                    Some(Payload::MovePaneWithPaneIdInDirectionPayload(move_payload)) => {
1798                        match (move_payload.direction, move_payload.pane_id) {
1799                            (Some(direction), Some(pane_id)) => {
1800                                Ok(PluginCommand::MovePaneWithPaneIdInDirection(
1801                                    pane_id.try_into()?,
1802                                    direction.try_into()?,
1803                                ))
1804                            },
1805                            _ => Err("Malformed MovePaneWithPaneIdInDirection payload"),
1806                        }
1807                    },
1808                    _ => Err("Mismatched payload for MovePaneWithDirection"),
1809                }
1810            },
1811            Some(CommandName::ClearScreenForPaneId) => match protobuf_plugin_command.payload {
1812                Some(Payload::ClearScreenForPaneIdPayload(clear_screen_for_pane_id_payload)) => {
1813                    match clear_screen_for_pane_id_payload.pane_id {
1814                        Some(pane_id) => {
1815                            Ok(PluginCommand::ClearScreenForPaneId(pane_id.try_into()?))
1816                        },
1817                        _ => Err("Malformed clear_screen_for_pane_id_payload payload"),
1818                    }
1819                },
1820                _ => Err("Mismatched payload for ClearScreenForPaneId"),
1821            },
1822            Some(CommandName::ScrollUpInPaneId) => match protobuf_plugin_command.payload {
1823                Some(Payload::ScrollUpInPaneIdPayload(scroll_up_in_pane_id_payload)) => {
1824                    match scroll_up_in_pane_id_payload.pane_id {
1825                        Some(pane_id) => Ok(PluginCommand::ScrollUpInPaneId(pane_id.try_into()?)),
1826                        _ => Err("Malformed scroll_up_in_pane_id_payload payload"),
1827                    }
1828                },
1829                _ => Err("Mismatched payload for ScrollUpInPaneId"),
1830            },
1831            Some(CommandName::ScrollDownInPaneId) => match protobuf_plugin_command.payload {
1832                Some(Payload::ScrollDownInPaneIdPayload(scroll_down_in_pane_id_payload)) => {
1833                    match scroll_down_in_pane_id_payload.pane_id {
1834                        Some(pane_id) => Ok(PluginCommand::ScrollDownInPaneId(pane_id.try_into()?)),
1835                        _ => Err("Malformed scroll_down_in_pane_id_payload payload"),
1836                    }
1837                },
1838                _ => Err("Mismatched payload for ScrollDownInPaneId"),
1839            },
1840            Some(CommandName::ScrollToTopInPaneId) => match protobuf_plugin_command.payload {
1841                Some(Payload::ScrollToTopInPaneIdPayload(scroll_to_top_in_pane_id_payload)) => {
1842                    match scroll_to_top_in_pane_id_payload.pane_id {
1843                        Some(pane_id) => {
1844                            Ok(PluginCommand::ScrollToTopInPaneId(pane_id.try_into()?))
1845                        },
1846                        _ => Err("Malformed scroll_to_top_in_pane_id_payload payload"),
1847                    }
1848                },
1849                _ => Err("Mismatched payload for ScrollToTopInPaneId"),
1850            },
1851            Some(CommandName::ScrollToBottomInPaneId) => match protobuf_plugin_command.payload {
1852                Some(Payload::ScrollToBottomInPaneIdPayload(
1853                    scroll_to_bottom_in_pane_id_payload,
1854                )) => match scroll_to_bottom_in_pane_id_payload.pane_id {
1855                    Some(pane_id) => Ok(PluginCommand::ScrollToBottomInPaneId(pane_id.try_into()?)),
1856                    _ => Err("Malformed scroll_to_bottom_in_pane_id_payload payload"),
1857                },
1858                _ => Err("Mismatched payload for ScrollToBottomInPaneId"),
1859            },
1860            Some(CommandName::PageScrollUpInPaneId) => match protobuf_plugin_command.payload {
1861                Some(Payload::PageScrollUpInPaneIdPayload(page_scroll_up_in_pane_id_payload)) => {
1862                    match page_scroll_up_in_pane_id_payload.pane_id {
1863                        Some(pane_id) => {
1864                            Ok(PluginCommand::PageScrollUpInPaneId(pane_id.try_into()?))
1865                        },
1866                        _ => Err("Malformed page_scroll_up_in_pane_id_payload payload"),
1867                    }
1868                },
1869                _ => Err("Mismatched payload for PageScrollUpInPaneId"),
1870            },
1871            Some(CommandName::PageScrollDownInPaneId) => match protobuf_plugin_command.payload {
1872                Some(Payload::PageScrollDownInPaneIdPayload(
1873                    page_scroll_down_in_pane_id_payload,
1874                )) => match page_scroll_down_in_pane_id_payload.pane_id {
1875                    Some(pane_id) => Ok(PluginCommand::PageScrollDownInPaneId(pane_id.try_into()?)),
1876                    _ => Err("Malformed page_scroll_down_in_pane_id_payload payload"),
1877                },
1878                _ => Err("Mismatched payload for PageScrollDownInPaneId"),
1879            },
1880            Some(CommandName::TogglePaneIdFullscreen) => match protobuf_plugin_command.payload {
1881                Some(Payload::TogglePaneIdFullscreenPayload(toggle_pane_id_fullscreen_payload)) => {
1882                    match toggle_pane_id_fullscreen_payload.pane_id {
1883                        Some(pane_id) => {
1884                            Ok(PluginCommand::TogglePaneIdFullscreen(pane_id.try_into()?))
1885                        },
1886                        _ => Err("Malformed toggle_pane_id_fullscreen_payload payload"),
1887                    }
1888                },
1889                _ => Err("Mismatched payload for TogglePaneIdFullscreen"),
1890            },
1891            Some(CommandName::TogglePaneEmbedOrEjectForPaneId) => {
1892                match protobuf_plugin_command.payload {
1893                    Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
1894                        toggle_pane_embed_or_eject_payload,
1895                    )) => match toggle_pane_embed_or_eject_payload.pane_id {
1896                        Some(pane_id) => Ok(PluginCommand::TogglePaneEmbedOrEjectForPaneId(
1897                            pane_id.try_into()?,
1898                        )),
1899                        _ => Err("Malformed toggle_pane_embed_or_eject_payload payload"),
1900                    },
1901                    _ => Err("Mismatched payload for TogglePaneEmbedOrEjectForPaneId"),
1902                }
1903            },
1904            Some(CommandName::CloseTabWithIndex) => match protobuf_plugin_command.payload {
1905                Some(Payload::CloseTabWithIndexPayload(close_tab_index_payload)) => Ok(
1906                    PluginCommand::CloseTabWithIndex(close_tab_index_payload.tab_index as usize),
1907                ),
1908                _ => Err("Mismatched payload for CloseTabWithIndex"),
1909            },
1910            Some(CommandName::BreakPanesToNewTab) => match protobuf_plugin_command.payload {
1911                Some(Payload::BreakPanesToNewTabPayload(break_panes_to_new_tab_payload)) => {
1912                    Ok(PluginCommand::BreakPanesToNewTab(
1913                        break_panes_to_new_tab_payload
1914                            .pane_ids
1915                            .into_iter()
1916                            .filter_map(|p_id| p_id.try_into().ok())
1917                            .collect(),
1918                        break_panes_to_new_tab_payload.new_tab_name,
1919                        break_panes_to_new_tab_payload.should_change_focus_to_new_tab,
1920                    ))
1921                },
1922                _ => Err("Mismatched payload for BreakPanesToNewTab"),
1923            },
1924            Some(CommandName::BreakPanesToTabWithIndex) => match protobuf_plugin_command.payload {
1925                Some(Payload::BreakPanesToTabWithIndexPayload(
1926                    break_panes_to_tab_with_index_payload,
1927                )) => Ok(PluginCommand::BreakPanesToTabWithIndex(
1928                    break_panes_to_tab_with_index_payload
1929                        .pane_ids
1930                        .into_iter()
1931                        .filter_map(|p_id| p_id.try_into().ok())
1932                        .collect(),
1933                    break_panes_to_tab_with_index_payload.tab_index as usize,
1934                    break_panes_to_tab_with_index_payload.should_change_focus_to_target_tab,
1935                )),
1936                _ => Err("Mismatched payload for BreakPanesToTabWithIndex"),
1937            },
1938            Some(CommandName::SwitchTabToId) => match protobuf_plugin_command.payload {
1939                Some(Payload::SwitchTabToIdPayload(payload)) => {
1940                    Ok(PluginCommand::SwitchTabToId(payload.tab_id))
1941                },
1942                _ => Err("Mismatched payload for SwitchTabToId"),
1943            },
1944            Some(CommandName::GoToTabWithId) => match protobuf_plugin_command.payload {
1945                Some(Payload::GoToTabWithIdPayload(payload)) => {
1946                    Ok(PluginCommand::GoToTabWithId(payload.tab_id))
1947                },
1948                _ => Err("Mismatched payload for GoToTabWithId"),
1949            },
1950            Some(CommandName::CloseTabWithId) => match protobuf_plugin_command.payload {
1951                Some(Payload::CloseTabWithIdPayload(payload)) => {
1952                    Ok(PluginCommand::CloseTabWithId(payload.tab_id))
1953                },
1954                _ => Err("Mismatched payload for CloseTabWithId"),
1955            },
1956            Some(CommandName::RenameTabWithId) => match protobuf_plugin_command.payload {
1957                Some(Payload::RenameTabWithIdPayload(payload)) => Ok(
1958                    PluginCommand::RenameTabWithId(payload.tab_id, payload.new_name),
1959                ),
1960                _ => Err("Mismatched payload for RenameTabWithId"),
1961            },
1962            Some(CommandName::BreakPanesToTabWithId) => match protobuf_plugin_command.payload {
1963                Some(Payload::BreakPanesToTabWithIdPayload(payload)) => {
1964                    Ok(PluginCommand::BreakPanesToTabWithId(
1965                        payload
1966                            .pane_ids
1967                            .into_iter()
1968                            .filter_map(|p_id| p_id.try_into().ok())
1969                            .collect(),
1970                        payload.tab_id,
1971                        payload.should_change_focus_to_target_tab,
1972                    ))
1973                },
1974                _ => Err("Mismatched payload for BreakPanesToTabWithId"),
1975            },
1976            Some(CommandName::ReloadPlugin) => match protobuf_plugin_command.payload {
1977                Some(Payload::ReloadPluginPayload(reload_plugin_payload)) => {
1978                    Ok(PluginCommand::ReloadPlugin(reload_plugin_payload.plugin_id))
1979                },
1980                _ => Err("Mismatched payload for ReloadPlugin"),
1981            },
1982            Some(CommandName::LoadNewPlugin) => match protobuf_plugin_command.payload {
1983                Some(Payload::LoadNewPluginPayload(load_new_plugin_payload)) => {
1984                    Ok(PluginCommand::LoadNewPlugin {
1985                        url: load_new_plugin_payload.plugin_url,
1986                        config: load_new_plugin_payload
1987                            .plugin_config
1988                            .into_iter()
1989                            .map(|e| (e.name, e.value))
1990                            .collect(),
1991                        load_in_background: load_new_plugin_payload
1992                            .should_load_plugin_in_background,
1993                        skip_plugin_cache: load_new_plugin_payload.should_skip_plugin_cache,
1994                    })
1995                },
1996                _ => Err("Mismatched payload for LoadNewPlugin"),
1997            },
1998            Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload {
1999                Some(Payload::RebindKeysPayload(rebind_keys_payload)) => {
2000                    Ok(PluginCommand::RebindKeys {
2001                        keys_to_rebind: rebind_keys_payload
2002                            .keys_to_rebind
2003                            .into_iter()
2004                            .filter_map(|k| key_to_rebind_to_plugin_command_assets(k))
2005                            .collect(),
2006                        keys_to_unbind: rebind_keys_payload
2007                            .keys_to_unbind
2008                            .into_iter()
2009                            .filter_map(|k| key_to_unbind_to_plugin_command_assets(k))
2010                            .collect(),
2011                        write_config_to_disk: rebind_keys_payload.write_config_to_disk,
2012                    })
2013                },
2014                _ => Err("Mismatched payload for RebindKeys"),
2015            },
2016            Some(CommandName::ListClients) => match protobuf_plugin_command.payload {
2017                Some(_) => Err("ListClients should have no payload, found a payload"),
2018                None => Ok(PluginCommand::ListClients),
2019            },
2020            Some(CommandName::ChangeHostFolder) => match protobuf_plugin_command.payload {
2021                Some(Payload::ChangeHostFolderPayload(change_host_folder_payload)) => {
2022                    Ok(PluginCommand::ChangeHostFolder(PathBuf::from(
2023                        change_host_folder_payload.new_host_folder,
2024                    )))
2025                },
2026                _ => Err("Mismatched payload for ChangeHostFolder"),
2027            },
2028            Some(CommandName::SetFloatingPanePinned) => match protobuf_plugin_command.payload {
2029                Some(Payload::SetFloatingPanePinnedPayload(set_floating_pane_pinned_payload)) => {
2030                    match set_floating_pane_pinned_payload
2031                        .pane_id
2032                        .and_then(|p| p.try_into().ok())
2033                    {
2034                        Some(pane_id) => Ok(PluginCommand::SetFloatingPanePinned(
2035                            pane_id,
2036                            set_floating_pane_pinned_payload.should_be_pinned,
2037                        )),
2038                        None => Err("PaneId not found!"),
2039                    }
2040                },
2041                _ => Err("Mismatched payload for SetFloatingPanePinned"),
2042            },
2043            Some(CommandName::StackPanes) => match protobuf_plugin_command.payload {
2044                Some(Payload::StackPanesPayload(stack_panes_payload)) => {
2045                    Ok(PluginCommand::StackPanes(
2046                        stack_panes_payload
2047                            .pane_ids
2048                            .into_iter()
2049                            .filter_map(|p_id| p_id.try_into().ok())
2050                            .collect(),
2051                    ))
2052                },
2053                _ => Err("Mismatched payload for StackPanes"),
2054            },
2055            Some(CommandName::ChangeFloatingPanesCoordinates) => {
2056                match protobuf_plugin_command.payload {
2057                    Some(Payload::ChangeFloatingPanesCoordinatesPayload(
2058                        change_floating_panes_coordinates_payload,
2059                    )) => Ok(PluginCommand::ChangeFloatingPanesCoordinates(
2060                        change_floating_panes_coordinates_payload
2061                            .pane_ids_and_floating_panes_coordinates
2062                            .into_iter()
2063                            .filter_map(|p_id_a_fp| {
2064                                let pane_id: PaneId = p_id_a_fp.pane_id?.try_into().ok()?;
2065                                let floating_pane_coordinates: FloatingPaneCoordinates =
2066                                    p_id_a_fp.floating_pane_coordinates?.try_into().ok()?;
2067                                Some((pane_id, floating_pane_coordinates))
2068                            })
2069                            .collect(),
2070                    )),
2071                    _ => Err("Mismatched payload for ChangeFloatingPanesCoordinates"),
2072                }
2073            },
2074            Some(CommandName::TogglePaneBorderless) => match protobuf_plugin_command.payload {
2075                Some(Payload::TogglePaneBorderlessPayload(toggle_payload)) => {
2076                    match toggle_payload.pane_id {
2077                        Some(pane_id) => {
2078                            Ok(PluginCommand::TogglePaneBorderless(pane_id.try_into()?))
2079                        },
2080                        None => Err("Malformed TogglePaneBorderless payload"),
2081                    }
2082                },
2083                _ => Err("Mismatched payload for TogglePaneBorderless"),
2084            },
2085            Some(CommandName::SetPaneBorderless) => match protobuf_plugin_command.payload {
2086                Some(Payload::SetPaneBorderlessPayload(payload)) => {
2087                    match (payload.pane_id, payload.borderless) {
2088                        (Some(pane_id), borderless) => Ok(PluginCommand::SetPaneBorderless(
2089                            pane_id.try_into()?,
2090                            borderless,
2091                        )),
2092                        _ => Err("Malformed SetPaneBorderless payload"),
2093                    }
2094                },
2095                _ => Err("Mismatched payload for SetPaneBorderless"),
2096            },
2097            Some(CommandName::OpenCommandPaneNearPlugin) => match protobuf_plugin_command.payload {
2098                Some(Payload::OpenCommandPaneNearPluginPayload(command_to_run_payload)) => {
2099                    match command_to_run_payload.command_to_run {
2100                        Some(command_to_run) => {
2101                            let context: BTreeMap<String, String> = command_to_run_payload
2102                                .context
2103                                .into_iter()
2104                                .map(|e| (e.name, e.value))
2105                                .collect();
2106                            Ok(PluginCommand::OpenCommandPaneNearPlugin(
2107                                command_to_run.try_into()?,
2108                                context,
2109                            ))
2110                        },
2111                        None => Err("Malformed open command pane near plugin payload"),
2112                    }
2113                },
2114                _ => Err("Mismatched payload for OpenCommandPaneNearPlugin"),
2115            },
2116            Some(CommandName::OpenTerminalNearPlugin) => match protobuf_plugin_command.payload {
2117                Some(Payload::OpenTerminalNearPluginPayload(open_terminal_near_plugin_payload)) => {
2118                    match open_terminal_near_plugin_payload.file_to_open {
2119                        Some(file_to_open) => Ok(PluginCommand::OpenTerminalNearPlugin(
2120                            file_to_open.try_into()?,
2121                        )),
2122                        None => Err("Malformed open terminal near plugin payload"),
2123                    }
2124                },
2125                _ => Err("Mismatched payload for OpenTerminalNearPluginPayload"),
2126            },
2127            Some(CommandName::OpenTerminalFloatingNearPlugin) => match protobuf_plugin_command
2128                .payload
2129            {
2130                Some(Payload::OpenTerminalFloatingNearPluginPayload(
2131                    open_terminal_floating_near_plugin_payload,
2132                )) => {
2133                    let floating_pane_coordinates = open_terminal_floating_near_plugin_payload
2134                        .floating_pane_coordinates
2135                        .map(|f| f.into());
2136                    match open_terminal_floating_near_plugin_payload.file_to_open {
2137                        Some(file_to_open) => Ok(PluginCommand::OpenTerminalFloatingNearPlugin(
2138                            file_to_open.try_into()?,
2139                            floating_pane_coordinates,
2140                        )),
2141                        None => Err("Malformed open terminal floating near plugin payload"),
2142                    }
2143                },
2144                _ => Err("Mismatched payload for OpenTerminalFloatingNearPlugin"),
2145            },
2146            Some(CommandName::OpenTerminalInPlaceOfPlugin) => match protobuf_plugin_command.payload
2147            {
2148                Some(Payload::OpenTerminalInPlaceOfPluginPayload(
2149                    open_terminal_in_place_of_plugin_payload,
2150                )) => match open_terminal_in_place_of_plugin_payload.file_to_open {
2151                    Some(file_to_open) => Ok(PluginCommand::OpenTerminalInPlaceOfPlugin(
2152                        file_to_open.try_into()?,
2153                        open_terminal_in_place_of_plugin_payload.close_plugin_after_replace,
2154                    )),
2155                    None => Err("Malformed open terminal in place of plugin payload"),
2156                },
2157                _ => Err("Mismatched payload for OpenTerminalInPlaceOfPlugin"),
2158            },
2159            Some(CommandName::OpenCommandPaneFloatingNearPlugin) => {
2160                match protobuf_plugin_command.payload {
2161                    Some(Payload::OpenCommandPaneFloatingNearPluginPayload(
2162                        open_command_pane_floating_near_plugin,
2163                    )) => match open_command_pane_floating_near_plugin.command_to_run {
2164                        Some(command_to_run) => {
2165                            let context: BTreeMap<String, String> =
2166                                open_command_pane_floating_near_plugin
2167                                    .context
2168                                    .into_iter()
2169                                    .map(|e| (e.name, e.value))
2170                                    .collect();
2171                            let floating_pane_coordinates = open_command_pane_floating_near_plugin
2172                                .floating_pane_coordinates
2173                                .map(|f| f.into());
2174                            Ok(PluginCommand::OpenCommandPaneFloatingNearPlugin(
2175                                command_to_run.try_into()?,
2176                                floating_pane_coordinates,
2177                                context,
2178                            ))
2179                        },
2180                        None => Err("Malformed open command pane floating near plugin payload"),
2181                    },
2182                    _ => Err("Mismatched payload for OpenCommandPaneFloatingNearPlugin"),
2183                }
2184            },
2185            Some(CommandName::OpenCommandPaneInPlaceOfPlugin) => {
2186                match protobuf_plugin_command.payload {
2187                    Some(Payload::OpenCommandPaneInPlaceOfPluginPayload(
2188                        open_command_pane_in_place_of_plugin_payload,
2189                    )) => match open_command_pane_in_place_of_plugin_payload.command_to_run {
2190                        Some(command_to_run) => {
2191                            let context: BTreeMap<String, String> =
2192                                open_command_pane_in_place_of_plugin_payload
2193                                    .context
2194                                    .into_iter()
2195                                    .map(|e| (e.name, e.value))
2196                                    .collect();
2197                            Ok(PluginCommand::OpenCommandPaneInPlaceOfPlugin(
2198                                command_to_run.try_into()?,
2199                                open_command_pane_in_place_of_plugin_payload
2200                                    .close_plugin_after_replace,
2201                                context,
2202                            ))
2203                        },
2204                        None => Err("Malformed open command pane in place of plugin payload"),
2205                    },
2206                    _ => Err("Mismatched payload for OpenCommandPaneInPlaceOfPlugin"),
2207                }
2208            },
2209            Some(CommandName::OpenFileNearPlugin) => match protobuf_plugin_command.payload {
2210                Some(Payload::OpenFileNearPluginPayload(file_to_open_payload)) => {
2211                    match file_to_open_payload.file_to_open {
2212                        Some(file_to_open) => {
2213                            let context: BTreeMap<String, String> = file_to_open_payload
2214                                .context
2215                                .into_iter()
2216                                .map(|e| (e.name, e.value))
2217                                .collect();
2218                            Ok(PluginCommand::OpenFileNearPlugin(
2219                                file_to_open.try_into()?,
2220                                context,
2221                            ))
2222                        },
2223                        None => Err("Malformed open file payload"),
2224                    }
2225                },
2226                _ => Err("Mismatched payload for OpenFileNearPlugin"),
2227            },
2228            Some(CommandName::OpenFileFloatingNearPlugin) => {
2229                match protobuf_plugin_command.payload {
2230                    Some(Payload::OpenFileFloatingNearPluginPayload(file_to_open_payload)) => {
2231                        let floating_pane_coordinates = file_to_open_payload
2232                            .floating_pane_coordinates
2233                            .map(|f| f.into());
2234                        let context: BTreeMap<String, String> = file_to_open_payload
2235                            .context
2236                            .into_iter()
2237                            .map(|e| (e.name, e.value))
2238                            .collect();
2239                        match file_to_open_payload.file_to_open {
2240                            Some(file_to_open) => Ok(PluginCommand::OpenFileFloatingNearPlugin(
2241                                file_to_open.try_into()?,
2242                                floating_pane_coordinates,
2243                                context,
2244                            )),
2245                            None => Err("Malformed open file payload"),
2246                        }
2247                    },
2248                    _ => Err("Mismatched payload for OpenFileFloatingNearPlugin"),
2249                }
2250            },
2251            Some(CommandName::OpenFileInPlaceOfPlugin) => match protobuf_plugin_command.payload {
2252                Some(Payload::OpenFileInPlaceOfPluginPayload(file_to_open_payload)) => {
2253                    match file_to_open_payload.file_to_open {
2254                        Some(file_to_open) => {
2255                            let context: BTreeMap<String, String> = file_to_open_payload
2256                                .context
2257                                .into_iter()
2258                                .map(|e| (e.name, e.value))
2259                                .collect();
2260                            Ok(PluginCommand::OpenFileInPlaceOfPlugin(
2261                                file_to_open.try_into()?,
2262                                file_to_open_payload.close_plugin_after_replace,
2263                                context,
2264                            ))
2265                        },
2266                        None => Err("Malformed open file in place payload"),
2267                    }
2268                },
2269                _ => Err("Mismatched payload for OpenFileInPlaceOfPlugin"),
2270            },
2271            Some(CommandName::StartWebServer) => {
2272                if protobuf_plugin_command.payload.is_some() {
2273                    Err("StartWebServer should not have a payload")
2274                } else {
2275                    Ok(PluginCommand::StartWebServer)
2276                }
2277            },
2278            Some(CommandName::StopWebServer) => {
2279                if protobuf_plugin_command.payload.is_some() {
2280                    Err("StopWebServer should not have a payload")
2281                } else {
2282                    Ok(PluginCommand::StopWebServer)
2283                }
2284            },
2285            Some(CommandName::QueryWebServerStatus) => {
2286                if protobuf_plugin_command.payload.is_some() {
2287                    Err("QueryWebServerStatus should not have a payload")
2288                } else {
2289                    Ok(PluginCommand::QueryWebServerStatus)
2290                }
2291            },
2292            Some(CommandName::GroupAndUngroupPanes) => match protobuf_plugin_command.payload {
2293                Some(Payload::GroupAndUngroupPanesPayload(group_and_ungroup_panes_payload)) => {
2294                    Ok(PluginCommand::GroupAndUngroupPanes(
2295                        group_and_ungroup_panes_payload
2296                            .pane_ids_to_group
2297                            .into_iter()
2298                            .filter_map(|p| p.try_into().ok())
2299                            .collect(),
2300                        group_and_ungroup_panes_payload
2301                            .pane_ids_to_ungroup
2302                            .into_iter()
2303                            .filter_map(|p| p.try_into().ok())
2304                            .collect(),
2305                        group_and_ungroup_panes_payload.for_all_clients,
2306                    ))
2307                },
2308                _ => Err("Mismatched payload for GroupAndUngroupPanes"),
2309            },
2310            Some(CommandName::HighlightAndUnhighlightPanes) => {
2311                match protobuf_plugin_command.payload {
2312                    Some(Payload::HighlightAndUnhighlightPanesPayload(
2313                        highlight_and_unhighlight_panes_payload,
2314                    )) => Ok(PluginCommand::HighlightAndUnhighlightPanes(
2315                        highlight_and_unhighlight_panes_payload
2316                            .pane_ids_to_highlight
2317                            .into_iter()
2318                            .filter_map(|p| p.try_into().ok())
2319                            .collect(),
2320                        highlight_and_unhighlight_panes_payload
2321                            .pane_ids_to_unhighlight
2322                            .into_iter()
2323                            .filter_map(|p| p.try_into().ok())
2324                            .collect(),
2325                    )),
2326                    _ => Err("Mismatched payload for HighlightAndUnhighlightPanes"),
2327                }
2328            },
2329            Some(CommandName::CloseMultiplePanes) => match protobuf_plugin_command.payload {
2330                Some(Payload::CloseMultiplePanesPayload(close_multiple_panes_payload)) => {
2331                    Ok(PluginCommand::CloseMultiplePanes(
2332                        close_multiple_panes_payload
2333                            .pane_ids
2334                            .into_iter()
2335                            .filter_map(|p| p.try_into().ok())
2336                            .collect(),
2337                    ))
2338                },
2339                _ => Err("Mismatched payload for CloseMultiplePanes"),
2340            },
2341            Some(CommandName::FloatMultiplePanes) => match protobuf_plugin_command.payload {
2342                Some(Payload::FloatMultiplePanesPayload(float_multiple_panes_payload)) => {
2343                    Ok(PluginCommand::FloatMultiplePanes(
2344                        float_multiple_panes_payload
2345                            .pane_ids
2346                            .into_iter()
2347                            .filter_map(|p| p.try_into().ok())
2348                            .collect(),
2349                    ))
2350                },
2351                _ => Err("Mismatched payload for FloatMultiplePanes"),
2352            },
2353            Some(CommandName::EmbedMultiplePanes) => match protobuf_plugin_command.payload {
2354                Some(Payload::EmbedMultiplePanesPayload(embed_multiple_panes_payload)) => {
2355                    Ok(PluginCommand::EmbedMultiplePanes(
2356                        embed_multiple_panes_payload
2357                            .pane_ids
2358                            .into_iter()
2359                            .filter_map(|p| p.try_into().ok())
2360                            .collect(),
2361                    ))
2362                },
2363                _ => Err("Mismatched payload for EmbedMultiplePanes"),
2364            },
2365            Some(CommandName::ShareCurrentSession) => {
2366                if protobuf_plugin_command.payload.is_some() {
2367                    Err("ShareCurrentSession should not have a payload")
2368                } else {
2369                    Ok(PluginCommand::ShareCurrentSession)
2370                }
2371            },
2372            Some(CommandName::StopSharingCurrentSession) => {
2373                if protobuf_plugin_command.payload.is_some() {
2374                    Err("StopSharingCurrentSession should not have a payload")
2375                } else {
2376                    Ok(PluginCommand::StopSharingCurrentSession)
2377                }
2378            },
2379            Some(CommandName::SetSelfMouseSelectionSupport) => {
2380                match protobuf_plugin_command.payload {
2381                    Some(Payload::SetSelfMouseSelectionSupportPayload(
2382                        set_self_mouse_selection_support_payload,
2383                    )) => Ok(PluginCommand::SetSelfMouseSelectionSupport(
2384                        set_self_mouse_selection_support_payload.support_mouse_selection,
2385                    )),
2386                    _ => Err("SetSelfMouseSelectionSupport requires a payload"),
2387                }
2388            },
2389            Some(CommandName::GenerateWebLoginToken) => match protobuf_plugin_command.payload {
2390                Some(Payload::GenerateWebLoginTokenPayload(generate_web_login_token_payload)) => {
2391                    Ok(PluginCommand::GenerateWebLoginToken(
2392                        generate_web_login_token_payload.token_label,
2393                        generate_web_login_token_payload.read_only.unwrap_or(false),
2394                    ))
2395                },
2396                _ => Err("GenerateWebLoginToken requires a payload"),
2397            },
2398            Some(CommandName::RevokeWebLoginToken) => match protobuf_plugin_command.payload {
2399                Some(Payload::RevokeWebLoginTokenPayload(revoke_web_login_token_payload)) => Ok(
2400                    PluginCommand::RevokeWebLoginToken(revoke_web_login_token_payload.token_label),
2401                ),
2402                _ => Err("RevokeWebLoginToken requires a payload"),
2403            },
2404            Some(CommandName::ListWebLoginTokens) => {
2405                if protobuf_plugin_command.payload.is_some() {
2406                    Err("ListWebLoginTokens should not have a payload")
2407                } else {
2408                    Ok(PluginCommand::ListWebLoginTokens)
2409                }
2410            },
2411            Some(CommandName::RevokeAllWebLoginTokens) => {
2412                if protobuf_plugin_command.payload.is_some() {
2413                    Err("RevokeAllWebLoginTokens should not have a payload")
2414                } else {
2415                    Ok(PluginCommand::RevokeAllWebLoginTokens)
2416                }
2417            },
2418            Some(CommandName::RenameWebLoginToken) => match protobuf_plugin_command.payload {
2419                Some(Payload::RenameWebLoginTokenPayload(rename_web_login_token_payload)) => {
2420                    Ok(PluginCommand::RenameWebLoginToken(
2421                        rename_web_login_token_payload.old_name,
2422                        rename_web_login_token_payload.new_name,
2423                    ))
2424                },
2425                _ => Err("RenameWebLoginToken requires a payload"),
2426            },
2427            Some(CommandName::InterceptKeyPresses) => match protobuf_plugin_command.payload {
2428                Some(_) => Err("InterceptKeyPresses should have no payload, found a payload"),
2429                None => Ok(PluginCommand::InterceptKeyPresses),
2430            },
2431            Some(CommandName::ClearKeyPressesIntercepts) => match protobuf_plugin_command.payload {
2432                Some(_) => Err("ClearKeyPressesIntercepts should have no payload, found a payload"),
2433                None => Ok(PluginCommand::ClearKeyPressesIntercepts),
2434            },
2435            Some(CommandName::ReplacePaneWithExistingPane) => match protobuf_plugin_command.payload
2436            {
2437                Some(Payload::ReplacePaneWithExistingPanePayload(
2438                    replace_pane_with_other_pane_payload,
2439                )) => Ok(PluginCommand::ReplacePaneWithExistingPane(
2440                    replace_pane_with_other_pane_payload
2441                        .pane_id_to_replace
2442                        .and_then(|p_id| PaneId::try_from(p_id).ok())
2443                        .ok_or("Failed to parse ReplacePaneWithExistingPanePayload")?,
2444                    replace_pane_with_other_pane_payload
2445                        .existing_pane_id
2446                        .and_then(|p_id| PaneId::try_from(p_id).ok())
2447                        .ok_or("Failed to parse ReplacePaneWithExistingPanePayload")?,
2448                    replace_pane_with_other_pane_payload.suppress_replaced_pane,
2449                )),
2450                _ => Err("Mismatched payload for ReplacePaneWithExistingPane"),
2451            },
2452            Some(CommandName::RunAction) => match protobuf_plugin_command.payload {
2453                Some(Payload::RunActionPayload(protobuf_payload)) => {
2454                    let action = Action::try_from(
2455                        protobuf_payload
2456                            .action
2457                            .ok_or("Missing action in RunAction payload")?,
2458                    )
2459                    .map_err(|_| "Failed to convert protobuf action")?;
2460
2461                    let context: BTreeMap<String, String> = protobuf_payload
2462                        .context
2463                        .into_iter()
2464                        .map(|item| (item.name, item.value))
2465                        .collect();
2466
2467                    Ok(PluginCommand::RunAction(action, context))
2468                },
2469                _ => Err("Mismatched payload for RunAction"),
2470            },
2471            Some(CommandName::CopyToClipboard) => match protobuf_plugin_command.payload {
2472                Some(Payload::CopyToClipboardPayload(payload)) => {
2473                    Ok(PluginCommand::CopyToClipboard(payload.text))
2474                },
2475                _ => Err("Mismatched payload for CopyToClipboard"),
2476            },
2477            Some(CommandName::GenerateRandomName) => Ok(PluginCommand::GenerateRandomName),
2478            Some(CommandName::DumpLayout) => match protobuf_plugin_command.payload {
2479                Some(Payload::DumpLayoutPayload(payload)) => {
2480                    Ok(PluginCommand::DumpLayout(payload.layout_name))
2481                },
2482                _ => Err("Mismatched payload for DumpLayout"),
2483            },
2484            Some(CommandName::ParseLayout) => match protobuf_plugin_command.payload {
2485                Some(Payload::ParseLayoutPayload(payload)) => {
2486                    Ok(PluginCommand::ParseLayout(payload.layout_string))
2487                },
2488                _ => Err("Mismatched payload for ParseLayout"),
2489            },
2490            Some(CommandName::GetLayoutDir) => Ok(PluginCommand::GetLayoutDir),
2491            Some(CommandName::GetFocusedPaneInfo) => Ok(PluginCommand::GetFocusedPaneInfo),
2492            Some(CommandName::SaveSession) => Ok(PluginCommand::SaveSession),
2493            Some(CommandName::CurrentSessionLastSavedTime) => {
2494                Ok(PluginCommand::CurrentSessionLastSavedTime)
2495            },
2496            Some(CommandName::GetPaneInfo) => match protobuf_plugin_command.payload {
2497                Some(Payload::GetPaneInfoPayload(get_pane_info_payload)) => {
2498                    let pane_id = get_pane_info_payload
2499                        .pane_id
2500                        .ok_or("Malformed pane_id for GetPaneInfo")
2501                        .and_then(|p| p.try_into())?;
2502                    Ok(PluginCommand::GetPaneInfo(pane_id))
2503                },
2504                _ => Err("Malformed payload for GetPaneInfo"),
2505            },
2506            Some(CommandName::GetTabInfo) => match protobuf_plugin_command.payload {
2507                Some(Payload::GetTabInfoPayload(get_tab_info_payload)) => {
2508                    let tab_id = get_tab_info_payload.tab_id as usize;
2509                    Ok(PluginCommand::GetTabInfo(tab_id))
2510                },
2511                _ => Err("Malformed payload for GetTabInfo"),
2512            },
2513            Some(CommandName::GetSessionEnvironmentVariables) => {
2514                match protobuf_plugin_command.payload {
2515                    Some(Payload::GetSessionEnvironmentVariablesPayload(_)) => {
2516                        Ok(PluginCommand::GetSessionEnvironmentVariables)
2517                    },
2518                    _ => Err("Mismatched payload for GetSessionEnvironmentVariables"),
2519                }
2520            },
2521            Some(CommandName::OpenCommandPaneInNewTab) => match protobuf_plugin_command.payload {
2522                Some(Payload::OpenCommandPaneInNewTabPayload(payload)) => {
2523                    match payload.command_to_run {
2524                        Some(command_to_run) => {
2525                            let context: BTreeMap<String, String> = payload
2526                                .context
2527                                .into_iter()
2528                                .map(|e| (e.name, e.value))
2529                                .collect();
2530                            Ok(PluginCommand::OpenCommandPaneInNewTab(
2531                                command_to_run.try_into()?,
2532                                context,
2533                            ))
2534                        },
2535                        None => Err("Malformed open_command_pane_in_new_tab payload"),
2536                    }
2537                },
2538                _ => Err("Mismatched payload for OpenCommandPaneInNewTab"),
2539            },
2540            Some(CommandName::OpenPluginPaneInNewTab) => match protobuf_plugin_command.payload {
2541                Some(Payload::OpenPluginPaneInNewTabPayload(payload)) => {
2542                    let configuration: BTreeMap<String, String> =
2543                        payload.configuration.into_iter().collect();
2544                    let context: BTreeMap<String, String> = payload
2545                        .context
2546                        .into_iter()
2547                        .map(|e| (e.name, e.value))
2548                        .collect();
2549                    Ok(PluginCommand::OpenPluginPaneInNewTab {
2550                        plugin_url: payload.plugin_url,
2551                        configuration,
2552                        context,
2553                    })
2554                },
2555                _ => Err("Mismatched payload for OpenPluginPaneInNewTab"),
2556            },
2557            Some(CommandName::OpenEditorPaneInNewTab) => match protobuf_plugin_command.payload {
2558                Some(Payload::OpenEditorPaneInNewTabPayload(payload)) => {
2559                    match payload.file_to_open {
2560                        Some(file) => {
2561                            let context: BTreeMap<String, String> = payload
2562                                .context
2563                                .into_iter()
2564                                .map(|e| (e.name, e.value))
2565                                .collect();
2566                            Ok(PluginCommand::OpenEditorPaneInNewTab(
2567                                file.try_into()?,
2568                                context,
2569                            ))
2570                        },
2571                        None => Err("Malformed open_editor_pane_in_new_tab payload"),
2572                    }
2573                },
2574                _ => Err("Mismatched payload for OpenEditorPaneInNewTab"),
2575            },
2576            Some(CommandName::OpenCommandPaneInPlaceOfPaneId) => {
2577                match protobuf_plugin_command.payload {
2578                    Some(Payload::OpenCommandPaneInPlaceOfPaneIdPayload(payload)) => {
2579                        match (payload.pane_id_to_replace, payload.command_to_run) {
2580                            (Some(pane_id), Some(command_to_run)) => {
2581                                let context: BTreeMap<String, String> = payload
2582                                    .context
2583                                    .into_iter()
2584                                    .map(|e| (e.name, e.value))
2585                                    .collect();
2586                                Ok(PluginCommand::OpenCommandPaneInPlaceOfPaneId(
2587                                    pane_id.try_into()?,
2588                                    command_to_run.try_into()?,
2589                                    payload.close_replaced_pane,
2590                                    context,
2591                                ))
2592                            },
2593                            _ => Err("Malformed open_command_pane_in_place_of_pane_id payload"),
2594                        }
2595                    },
2596                    _ => Err("Mismatched payload for OpenCommandPaneInPlaceOfPaneId"),
2597                }
2598            },
2599            Some(CommandName::OpenTerminalPaneInPlaceOfPaneId) => {
2600                match protobuf_plugin_command.payload {
2601                    Some(Payload::OpenTerminalPaneInPlaceOfPaneIdPayload(payload)) => {
2602                        match payload.pane_id_to_replace {
2603                            Some(pane_id) => {
2604                                let cwd = payload.cwd.map(|f| f.try_into()).transpose()?;
2605                                let cwd = cwd.unwrap_or_else(|| crate::data::FileToOpen {
2606                                    path: std::path::PathBuf::from("."),
2607                                    ..Default::default()
2608                                });
2609                                Ok(PluginCommand::OpenTerminalPaneInPlaceOfPaneId(
2610                                    pane_id.try_into()?,
2611                                    cwd,
2612                                    payload.close_replaced_pane,
2613                                ))
2614                            },
2615                            None => Err("Malformed open_terminal_pane_in_place_of_pane_id payload"),
2616                        }
2617                    },
2618                    _ => Err("Mismatched payload for OpenTerminalPaneInPlaceOfPaneId"),
2619                }
2620            },
2621            Some(CommandName::OpenEditPaneInPlaceOfPaneId) => {
2622                match protobuf_plugin_command.payload {
2623                    Some(Payload::OpenEditPaneInPlaceOfPaneIdPayload(payload)) => {
2624                        match (payload.pane_id_to_replace, payload.file_to_open) {
2625                            (Some(pane_id), Some(file_to_open)) => {
2626                                let context: BTreeMap<String, String> = payload
2627                                    .context
2628                                    .into_iter()
2629                                    .map(|e| (e.name, e.value))
2630                                    .collect();
2631                                Ok(PluginCommand::OpenEditPaneInPlaceOfPaneId(
2632                                    pane_id.try_into()?,
2633                                    file_to_open.try_into()?,
2634                                    payload.close_replaced_pane,
2635                                    context,
2636                                ))
2637                            },
2638                            _ => Err("Malformed open_edit_pane_in_place_of_pane_id payload"),
2639                        }
2640                    },
2641                    _ => Err("Mismatched payload for OpenEditPaneInPlaceOfPaneId"),
2642                }
2643            },
2644            Some(CommandName::HideFloatingPanes) => match protobuf_plugin_command.payload {
2645                Some(Payload::HideFloatingPanesPayload(payload)) => {
2646                    Ok(PluginCommand::HideFloatingPanes {
2647                        tab_id: payload.tab_id.map(|id| id as usize),
2648                    })
2649                },
2650                None => Ok(PluginCommand::HideFloatingPanes { tab_id: None }),
2651                _ => Err("Mismatched payload for HideFloatingPanes"),
2652            },
2653            Some(CommandName::ShowFloatingPanes) => match protobuf_plugin_command.payload {
2654                Some(Payload::ShowFloatingPanesPayload(payload)) => {
2655                    Ok(PluginCommand::ShowFloatingPanes {
2656                        tab_id: payload.tab_id.map(|id| id as usize),
2657                    })
2658                },
2659                None => Ok(PluginCommand::ShowFloatingPanes { tab_id: None }),
2660                _ => Err("Mismatched payload for ShowFloatingPanes"),
2661            },
2662            Some(CommandName::SetPaneColor) => match protobuf_plugin_command.payload {
2663                Some(Payload::SetPaneColorPayload(payload)) => match payload.pane_id {
2664                    Some(pane_id) => Ok(PluginCommand::SetPaneColor(
2665                        pane_id.try_into()?,
2666                        payload.fg,
2667                        payload.bg,
2668                    )),
2669                    None => Err("Malformed SetPaneColor payload"),
2670                },
2671                _ => Err("Mismatched payload for SetPaneColor"),
2672            },
2673            Some(CommandName::SetPaneRegexHighlights) => {
2674                match protobuf_plugin_command.payload {
2675                    Some(Payload::SetPaneRegexHighlightsPayload(p)) => {
2676                        let pane_id: PaneId = p
2677                            .pane_id
2678                            .ok_or("Missing pane_id in SetPaneRegexHighlights")?
2679                            .try_into()?;
2680                        let highlights = p
2681                            .highlights
2682                            .into_iter()
2683                            .map(|h| {
2684                                let style = match h.style.and_then(|s| s.style) {
2685                                    Some(ProtobufHighlightStyleVariant::Emphasis0(_)) => {
2686                                        HighlightStyle::Emphasis0
2687                                    },
2688                                    Some(ProtobufHighlightStyleVariant::Emphasis1(_)) => {
2689                                        HighlightStyle::Emphasis1
2690                                    },
2691                                    Some(ProtobufHighlightStyleVariant::Emphasis2(_)) => {
2692                                        HighlightStyle::Emphasis2
2693                                    },
2694                                    Some(ProtobufHighlightStyleVariant::Emphasis3(_)) => {
2695                                        HighlightStyle::Emphasis3
2696                                    },
2697                                    Some(ProtobufHighlightStyleVariant::CustomRgb(c)) => {
2698                                        HighlightStyle::CustomRgb {
2699                                            fg: match (c.fg_r, c.fg_g, c.fg_b) {
2700                                                (Some(r), Some(g), Some(b)) => {
2701                                                    Some((r as u8, g as u8, b as u8))
2702                                                },
2703                                                _ => None,
2704                                            },
2705                                            bg: match (c.bg_r, c.bg_g, c.bg_b) {
2706                                                (Some(r), Some(g), Some(b)) => {
2707                                                    Some((r as u8, g as u8, b as u8))
2708                                                },
2709                                                _ => None,
2710                                            },
2711                                        }
2712                                    },
2713                                    Some(ProtobufHighlightStyleVariant::CustomIndex(c)) => {
2714                                        HighlightStyle::CustomIndex {
2715                                            fg: c.fg.map(|v| v as u8),
2716                                            bg: c.bg.map(|v| v as u8),
2717                                        }
2718                                    },
2719                                    Some(ProtobufHighlightStyleVariant::BackgroundEmphasis0(_)) => {
2720                                        HighlightStyle::BackgroundEmphasis0
2721                                    },
2722                                    Some(ProtobufHighlightStyleVariant::BackgroundEmphasis1(_)) => {
2723                                        HighlightStyle::BackgroundEmphasis1
2724                                    },
2725                                    Some(ProtobufHighlightStyleVariant::BackgroundEmphasis2(_)) => {
2726                                        HighlightStyle::BackgroundEmphasis2
2727                                    },
2728                                    Some(ProtobufHighlightStyleVariant::BackgroundEmphasis3(_)) => {
2729                                        HighlightStyle::BackgroundEmphasis3
2730                                    },
2731                                    Some(ProtobufHighlightStyleVariant::None(_)) => {
2732                                        HighlightStyle::None
2733                                    },
2734                                    None => HighlightStyle::Emphasis0, // fallback
2735                                };
2736                                let context = h
2737                                    .context
2738                                    .into_iter()
2739                                    .map(|item| (item.name, item.value))
2740                                    .collect();
2741                                RegexHighlight {
2742                                    pattern: h.pattern,
2743                                    style,
2744                                    layer: match h.layer {
2745                                        x if x == ProtobufHighlightLayer::Tool as i32 => {
2746                                            HighlightLayer::Tool
2747                                        },
2748                                        x if x == ProtobufHighlightLayer::ActionFeedback as i32 => {
2749                                            HighlightLayer::ActionFeedback
2750                                        },
2751                                        _ => HighlightLayer::Hint, // 0 or unknown => Hint
2752                                    },
2753                                    context,
2754                                    on_hover: h.on_hover,
2755                                    bold: h.bold,
2756                                    italic: h.italic,
2757                                    underline: h.underline,
2758                                    tooltip_text: h.tooltip_text,
2759                                }
2760                            })
2761                            .collect();
2762                        Ok(PluginCommand::SetPaneRegexHighlights(pane_id, highlights))
2763                    },
2764                    _ => Err("Mismatched payload for SetPaneRegexHighlights"),
2765                }
2766            },
2767            Some(CommandName::ClearPaneHighlights) => match protobuf_plugin_command.payload {
2768                Some(Payload::ClearPaneHighlightsPayload(p)) => {
2769                    let pane_id: PaneId = p
2770                        .pane_id
2771                        .ok_or("Missing pane_id in ClearPaneHighlights")?
2772                        .try_into()?;
2773                    Ok(PluginCommand::ClearPaneHighlights(pane_id))
2774                },
2775                _ => Err("Mismatched payload for ClearPaneHighlights"),
2776            },
2777            Some(CommandName::OpenPluginPaneFloating) => match protobuf_plugin_command.payload {
2778                Some(Payload::OpenPluginPaneFloatingPayload(payload)) => {
2779                    let configuration: BTreeMap<String, String> =
2780                        payload.configuration.into_iter().collect();
2781                    let floating_pane_coordinates =
2782                        payload.floating_pane_coordinates.map(|f| f.into());
2783                    let context: BTreeMap<String, String> = payload
2784                        .context
2785                        .into_iter()
2786                        .map(|e| (e.name, e.value))
2787                        .collect();
2788                    Ok(PluginCommand::OpenPluginPaneFloating {
2789                        plugin_url: payload.plugin_url,
2790                        configuration,
2791                        floating_pane_coordinates,
2792                        context,
2793                    })
2794                },
2795                _ => Err("Mismatched payload for OpenPluginPaneFloating"),
2796            },
2797            None => Err("Unrecognized plugin command"),
2798        }
2799    }
2800}
2801
2802impl TryFrom<PluginCommand> for ProtobufPluginCommand {
2803    type Error = &'static str;
2804    fn try_from(plugin_command: PluginCommand) -> Result<Self, &'static str> {
2805        match plugin_command {
2806            PluginCommand::Subscribe(subscriptions) => {
2807                let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
2808                Ok(ProtobufPluginCommand {
2809                    name: CommandName::Subscribe as i32,
2810                    payload: Some(Payload::SubscribePayload(SubscribePayload {
2811                        subscriptions: Some(subscriptions),
2812                    })),
2813                })
2814            },
2815            PluginCommand::Unsubscribe(subscriptions) => {
2816                let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
2817                Ok(ProtobufPluginCommand {
2818                    name: CommandName::Unsubscribe as i32,
2819                    payload: Some(Payload::UnsubscribePayload(UnsubscribePayload {
2820                        subscriptions: Some(subscriptions),
2821                    })),
2822                })
2823            },
2824            PluginCommand::SetSelectable(should_be_selectable) => Ok(ProtobufPluginCommand {
2825                name: CommandName::SetSelectable as i32,
2826                payload: Some(Payload::SetSelectablePayload(should_be_selectable)),
2827            }),
2828            PluginCommand::ShowCursor(cursor_position) => {
2829                let position = cursor_position.map(|(x, y)| CursorPosition {
2830                    x: x as u32,
2831                    y: y as u32,
2832                });
2833                Ok(ProtobufPluginCommand {
2834                    name: CommandName::ShowCursor as i32,
2835                    payload: Some(Payload::ShowCursorPayload(ShowCursorPayload { position })),
2836                })
2837            },
2838            PluginCommand::GetPluginIds => Ok(ProtobufPluginCommand {
2839                name: CommandName::GetPluginIds as i32,
2840                payload: None,
2841            }),
2842            PluginCommand::GetZellijVersion => Ok(ProtobufPluginCommand {
2843                name: CommandName::GetZellijVersion as i32,
2844                payload: None,
2845            }),
2846            PluginCommand::OpenFile(file_to_open, context) => Ok(ProtobufPluginCommand {
2847                name: CommandName::OpenFile as i32,
2848                payload: Some(Payload::OpenFilePayload(OpenFilePayload {
2849                    file_to_open: Some(file_to_open.try_into()?),
2850                    floating_pane_coordinates: None,
2851                    context: context
2852                        .into_iter()
2853                        .map(|(name, value)| ContextItem { name, value })
2854                        .collect(),
2855                })),
2856            }),
2857            PluginCommand::OpenFileFloating(file_to_open, floating_pane_coordinates, context) => {
2858                Ok(ProtobufPluginCommand {
2859                    name: CommandName::OpenFileFloating as i32,
2860                    payload: Some(Payload::OpenFileFloatingPayload(OpenFilePayload {
2861                        file_to_open: Some(file_to_open.try_into()?),
2862                        floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
2863                        context: context
2864                            .into_iter()
2865                            .map(|(name, value)| ContextItem { name, value })
2866                            .collect(),
2867                    })),
2868                })
2869            },
2870            PluginCommand::OpenTerminal(cwd) => Ok(ProtobufPluginCommand {
2871                name: CommandName::OpenTerminal as i32,
2872                payload: Some(Payload::OpenTerminalPayload(OpenFilePayload {
2873                    file_to_open: Some(cwd.try_into()?),
2874                    floating_pane_coordinates: None,
2875                    context: vec![], // will be added in the future
2876                })),
2877            }),
2878            PluginCommand::OpenTerminalFloating(cwd, floating_pane_coordinates) => {
2879                Ok(ProtobufPluginCommand {
2880                    name: CommandName::OpenTerminalFloating as i32,
2881                    payload: Some(Payload::OpenTerminalFloatingPayload(OpenFilePayload {
2882                        file_to_open: Some(cwd.try_into()?),
2883                        floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
2884                        context: vec![], // will be added in the future
2885                    })),
2886                })
2887            },
2888            PluginCommand::OpenCommandPane(command_to_run, context) => {
2889                let context: Vec<_> = context
2890                    .into_iter()
2891                    .map(|(name, value)| ContextItem { name, value })
2892                    .collect();
2893                Ok(ProtobufPluginCommand {
2894                    name: CommandName::OpenCommandPane as i32,
2895                    payload: Some(Payload::OpenCommandPanePayload(OpenCommandPanePayload {
2896                        command_to_run: Some(command_to_run.try_into()?),
2897                        floating_pane_coordinates: None,
2898                        context,
2899                    })),
2900                })
2901            },
2902            PluginCommand::OpenCommandPaneFloating(
2903                command_to_run,
2904                floating_pane_coordinates,
2905                context,
2906            ) => {
2907                let context: Vec<_> = context
2908                    .into_iter()
2909                    .map(|(name, value)| ContextItem { name, value })
2910                    .collect();
2911                Ok(ProtobufPluginCommand {
2912                    name: CommandName::OpenCommandPaneFloating as i32,
2913                    payload: Some(Payload::OpenCommandPaneFloatingPayload(
2914                        OpenCommandPanePayload {
2915                            command_to_run: Some(command_to_run.try_into()?),
2916                            floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
2917                            context,
2918                        },
2919                    )),
2920                })
2921            },
2922            PluginCommand::SwitchTabTo(tab_index) => Ok(ProtobufPluginCommand {
2923                name: CommandName::SwitchTabTo as i32,
2924                payload: Some(Payload::SwitchTabToPayload(SwitchTabToPayload {
2925                    tab_index: tab_index,
2926                })),
2927            }),
2928            PluginCommand::SetTimeout(seconds) => Ok(ProtobufPluginCommand {
2929                name: CommandName::SetTimeout as i32,
2930                payload: Some(Payload::SetTimeoutPayload(SetTimeoutPayload { seconds })),
2931            }),
2932            PluginCommand::ExecCmd(command_line) => Ok(ProtobufPluginCommand {
2933                name: CommandName::ExecCmd as i32,
2934                payload: Some(Payload::ExecCmdPayload(ExecCmdPayload { command_line })),
2935            }),
2936            PluginCommand::PostMessageTo(plugin_message) => Ok(ProtobufPluginCommand {
2937                name: CommandName::PostMessageTo as i32,
2938                payload: Some(Payload::PostMessageToPayload(PluginMessagePayload {
2939                    message: Some(plugin_message.try_into()?),
2940                })),
2941            }),
2942            PluginCommand::PostMessageToPlugin(plugin_message) => Ok(ProtobufPluginCommand {
2943                name: CommandName::PostMessageToPlugin as i32,
2944                payload: Some(Payload::PostMessageToPluginPayload(PluginMessagePayload {
2945                    message: Some(plugin_message.try_into()?),
2946                })),
2947            }),
2948            PluginCommand::HideSelf => Ok(ProtobufPluginCommand {
2949                name: CommandName::HideSelf as i32,
2950                payload: None,
2951            }),
2952            PluginCommand::ShowSelf(should_float_if_hidden) => Ok(ProtobufPluginCommand {
2953                name: CommandName::ShowSelf as i32,
2954                payload: Some(Payload::ShowSelfPayload(should_float_if_hidden)),
2955            }),
2956            PluginCommand::SwitchToMode(input_mode) => Ok(ProtobufPluginCommand {
2957                name: CommandName::SwitchToMode as i32,
2958                payload: Some(Payload::SwitchToModePayload(SwitchToModePayload {
2959                    input_mode: ProtobufInputMode::try_from(input_mode)? as i32,
2960                })),
2961            }),
2962            PluginCommand::NewTabsWithLayout(raw_layout) => Ok(ProtobufPluginCommand {
2963                name: CommandName::NewTabsWithLayout as i32,
2964                payload: Some(Payload::NewTabsWithLayoutPayload(raw_layout)),
2965            }),
2966            PluginCommand::NewTab { name, cwd } => Ok(ProtobufPluginCommand {
2967                name: CommandName::NewTab as i32,
2968                payload: Some(Payload::NewTabPayload(NewTabPayload { name, cwd })),
2969            }),
2970            PluginCommand::NewTabUnfocused { name, cwd } => Ok(ProtobufPluginCommand {
2971                name: CommandName::NewTabUnfocused as i32,
2972                payload: Some(Payload::NewTabUnfocusedPayload(NewTabUnfocusedPayload {
2973                    name,
2974                    cwd,
2975                })),
2976            }),
2977            PluginCommand::NewTiledPaneInTab { tab_position } => Ok(ProtobufPluginCommand {
2978                name: CommandName::NewTiledPaneInTab as i32,
2979                payload: Some(Payload::NewTiledPaneInTabPayload(
2980                    NewTiledPaneInTabPayload {
2981                        tab_position: tab_position as u32,
2982                    },
2983                )),
2984            }),
2985            PluginCommand::ToggleFloatingPanes { tab_id } => Ok(ProtobufPluginCommand {
2986                name: CommandName::ToggleFloatingPanes as i32,
2987                payload: Some(Payload::ToggleFloatingPanesPayload(
2988                    ToggleFloatingPanesPayload { tab_id },
2989                )),
2990            }),
2991            PluginCommand::NewPane => Ok(ProtobufPluginCommand {
2992                name: CommandName::NewPane as i32,
2993                payload: None,
2994            }),
2995            PluginCommand::GoToNextTab => Ok(ProtobufPluginCommand {
2996                name: CommandName::GoToNextTab as i32,
2997                payload: None,
2998            }),
2999            PluginCommand::GoToPreviousTab => Ok(ProtobufPluginCommand {
3000                name: CommandName::GoToPreviousTab as i32,
3001                payload: None,
3002            }),
3003            PluginCommand::Resize(resize) => Ok(ProtobufPluginCommand {
3004                name: CommandName::Resize as i32,
3005                payload: Some(Payload::ResizePayload(ResizePayload {
3006                    resize: Some(resize.try_into()?),
3007                })),
3008            }),
3009            PluginCommand::ResizeWithDirection(resize) => Ok(ProtobufPluginCommand {
3010                name: CommandName::ResizeWithDirection as i32,
3011                payload: Some(Payload::ResizeWithDirectionPayload(ResizePayload {
3012                    resize: Some(resize.try_into()?),
3013                })),
3014            }),
3015            PluginCommand::FocusNextPane => Ok(ProtobufPluginCommand {
3016                name: CommandName::FocusNextPane as i32,
3017                payload: None,
3018            }),
3019            PluginCommand::FocusPreviousPane => Ok(ProtobufPluginCommand {
3020                name: CommandName::FocusPreviousPane as i32,
3021                payload: None,
3022            }),
3023            PluginCommand::FocusLastPane => Ok(ProtobufPluginCommand {
3024                name: CommandName::FocusLastPane as i32,
3025                payload: None,
3026            }),
3027            PluginCommand::MoveFocus(direction) => Ok(ProtobufPluginCommand {
3028                name: CommandName::MoveFocus as i32,
3029                payload: Some(Payload::MoveFocusPayload(MovePayload {
3030                    direction: Some(direction.try_into()?),
3031                })),
3032            }),
3033            PluginCommand::MoveFocusOrTab(direction) => Ok(ProtobufPluginCommand {
3034                name: CommandName::MoveFocusOrTab as i32,
3035                payload: Some(Payload::MoveFocusOrTabPayload(MovePayload {
3036                    direction: Some(direction.try_into()?),
3037                })),
3038            }),
3039            PluginCommand::Detach => Ok(ProtobufPluginCommand {
3040                name: CommandName::Detach as i32,
3041                payload: None,
3042            }),
3043            PluginCommand::EditScrollback => Ok(ProtobufPluginCommand {
3044                name: CommandName::EditScrollback as i32,
3045                payload: None,
3046            }),
3047            PluginCommand::Write(bytes) => Ok(ProtobufPluginCommand {
3048                name: CommandName::Write as i32,
3049                payload: Some(Payload::WritePayload(bytes)),
3050            }),
3051            PluginCommand::WriteChars(chars) => Ok(ProtobufPluginCommand {
3052                name: CommandName::WriteChars as i32,
3053                payload: Some(Payload::WriteCharsPayload(chars)),
3054            }),
3055            PluginCommand::ToggleTab => Ok(ProtobufPluginCommand {
3056                name: CommandName::ToggleTab as i32,
3057                payload: None,
3058            }),
3059            PluginCommand::MovePane => Ok(ProtobufPluginCommand {
3060                name: CommandName::MovePane as i32,
3061                payload: None,
3062            }),
3063            PluginCommand::MovePaneWithDirection(direction) => Ok(ProtobufPluginCommand {
3064                name: CommandName::MovePaneWithDirection as i32,
3065                payload: Some(Payload::MovePaneWithDirectionPayload(MovePayload {
3066                    direction: Some(direction.try_into()?),
3067                })),
3068            }),
3069            PluginCommand::ClearScreen => Ok(ProtobufPluginCommand {
3070                name: CommandName::ClearScreen as i32,
3071                payload: None,
3072            }),
3073            PluginCommand::ScrollUp => Ok(ProtobufPluginCommand {
3074                name: CommandName::ScrollUp as i32,
3075                payload: None,
3076            }),
3077            PluginCommand::ScrollDown => Ok(ProtobufPluginCommand {
3078                name: CommandName::ScrollDown as i32,
3079                payload: None,
3080            }),
3081            PluginCommand::ScrollToTop => Ok(ProtobufPluginCommand {
3082                name: CommandName::ScrollToTop as i32,
3083                payload: None,
3084            }),
3085            PluginCommand::ScrollToBottom => Ok(ProtobufPluginCommand {
3086                name: CommandName::ScrollToBottom as i32,
3087                payload: None,
3088            }),
3089            PluginCommand::PageScrollUp => Ok(ProtobufPluginCommand {
3090                name: CommandName::PageScrollUp as i32,
3091                payload: None,
3092            }),
3093            PluginCommand::PageScrollDown => Ok(ProtobufPluginCommand {
3094                name: CommandName::PageScrollDown as i32,
3095                payload: None,
3096            }),
3097            PluginCommand::ToggleFocusFullscreen => Ok(ProtobufPluginCommand {
3098                name: CommandName::ToggleFocusFullscreen as i32,
3099                payload: None,
3100            }),
3101            PluginCommand::ToggleFocusNoUiFullscreen => Ok(ProtobufPluginCommand {
3102                name: CommandName::ToggleFocusNoUiFullscreen as i32,
3103                payload: None,
3104            }),
3105            PluginCommand::FocusHostSession => Ok(ProtobufPluginCommand {
3106                name: CommandName::FocusHostSession as i32,
3107                payload: None,
3108            }),
3109            PluginCommand::TogglePaneFrames => Ok(ProtobufPluginCommand {
3110                name: CommandName::TogglePaneFrames as i32,
3111                payload: None,
3112            }),
3113            PluginCommand::SetPaneFrameStyle(pane_frame_style) => Ok(ProtobufPluginCommand {
3114                name: CommandName::SetPaneFrameStyle as i32,
3115                payload: Some(Payload::SetPaneFrameStylePayload(
3116                    ProtobufSetPaneFrameStylePayload {
3117                        pane_frame_style: ProtobufPaneFrameStyle::try_from(pane_frame_style)?
3118                            as i32,
3119                    },
3120                )),
3121            }),
3122            PluginCommand::TogglePaneEmbedOrEject => Ok(ProtobufPluginCommand {
3123                name: CommandName::TogglePaneEmbedOrEject as i32,
3124                payload: None,
3125            }),
3126            PluginCommand::UndoRenamePane => Ok(ProtobufPluginCommand {
3127                name: CommandName::UndoRenamePane as i32,
3128                payload: None,
3129            }),
3130            PluginCommand::CloseFocus => Ok(ProtobufPluginCommand {
3131                name: CommandName::CloseFocus as i32,
3132                payload: None,
3133            }),
3134            PluginCommand::ToggleActiveTabSync => Ok(ProtobufPluginCommand {
3135                name: CommandName::ToggleActiveTabSync as i32,
3136                payload: None,
3137            }),
3138            PluginCommand::CloseFocusedTab => Ok(ProtobufPluginCommand {
3139                name: CommandName::CloseFocusedTab as i32,
3140                payload: None,
3141            }),
3142            PluginCommand::UndoRenameTab => Ok(ProtobufPluginCommand {
3143                name: CommandName::UndoRenameTab as i32,
3144                payload: None,
3145            }),
3146            PluginCommand::QuitZellij => Ok(ProtobufPluginCommand {
3147                name: CommandName::QuitZellij as i32,
3148                payload: None,
3149            }),
3150            PluginCommand::PreviousSwapLayout => Ok(ProtobufPluginCommand {
3151                name: CommandName::PreviousSwapLayout as i32,
3152                payload: None,
3153            }),
3154            PluginCommand::NextSwapLayout => Ok(ProtobufPluginCommand {
3155                name: CommandName::NextSwapLayout as i32,
3156                payload: None,
3157            }),
3158            PluginCommand::GoToTabName(tab_name) => Ok(ProtobufPluginCommand {
3159                name: CommandName::GoToTabName as i32,
3160                payload: Some(Payload::GoToTabNamePayload(tab_name)),
3161            }),
3162            PluginCommand::FocusOrCreateTab(tab_name) => Ok(ProtobufPluginCommand {
3163                name: CommandName::FocusOrCreateTab as i32,
3164                payload: Some(Payload::FocusOrCreateTabPayload(tab_name)),
3165            }),
3166            PluginCommand::GoToTab(tab_index) => Ok(ProtobufPluginCommand {
3167                name: CommandName::GoToTab as i32,
3168                payload: Some(Payload::GoToTabPayload(tab_index)),
3169            }),
3170            PluginCommand::StartOrReloadPlugin(url) => Ok(ProtobufPluginCommand {
3171                name: CommandName::StartOrReloadPlugin as i32,
3172                payload: Some(Payload::StartOrReloadPluginPayload(url)),
3173            }),
3174            PluginCommand::CloseTerminalPane(pane_id) => Ok(ProtobufPluginCommand {
3175                name: CommandName::CloseTerminalPane as i32,
3176                payload: Some(Payload::CloseTerminalPanePayload(pane_id)),
3177            }),
3178            PluginCommand::ClosePluginPane(pane_id) => Ok(ProtobufPluginCommand {
3179                name: CommandName::ClosePluginPane as i32,
3180                payload: Some(Payload::ClosePluginPanePayload(pane_id)),
3181            }),
3182            PluginCommand::FocusTerminalPane(
3183                pane_id,
3184                should_float_if_hidden,
3185                should_be_in_place_if_hidden,
3186            ) => Ok(ProtobufPluginCommand {
3187                name: CommandName::FocusTerminalPane as i32,
3188                payload: Some(Payload::FocusTerminalPanePayload(PaneIdAndShouldFloat {
3189                    pane_id: pane_id,
3190                    should_float: should_float_if_hidden,
3191                    should_be_in_place: should_be_in_place_if_hidden,
3192                })),
3193            }),
3194            PluginCommand::FocusPluginPane(
3195                pane_id,
3196                should_float_if_hidden,
3197                should_be_in_place_if_hidden,
3198            ) => Ok(ProtobufPluginCommand {
3199                name: CommandName::FocusPluginPane as i32,
3200                payload: Some(Payload::FocusPluginPanePayload(PaneIdAndShouldFloat {
3201                    pane_id: pane_id,
3202                    should_float: should_float_if_hidden,
3203                    should_be_in_place: should_be_in_place_if_hidden,
3204                })),
3205            }),
3206            PluginCommand::RenameTerminalPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
3207                name: CommandName::RenameTerminalPane as i32,
3208                payload: Some(Payload::RenameTerminalPanePayload(IdAndNewName {
3209                    id: pane_id,
3210                    new_name,
3211                })),
3212            }),
3213            PluginCommand::RenamePluginPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
3214                name: CommandName::RenamePluginPane as i32,
3215                payload: Some(Payload::RenamePluginPanePayload(IdAndNewName {
3216                    id: pane_id,
3217                    new_name,
3218                })),
3219            }),
3220            PluginCommand::RenameTab(tab_index, new_name) => Ok(ProtobufPluginCommand {
3221                name: CommandName::RenameTab as i32,
3222                payload: Some(Payload::RenameTabPayload(IdAndNewName {
3223                    id: tab_index,
3224                    new_name,
3225                })),
3226            }),
3227            PluginCommand::ReportPanic(payload) => Ok(ProtobufPluginCommand {
3228                name: CommandName::ReportCrash as i32,
3229                payload: Some(Payload::ReportCrashPayload(payload)),
3230            }),
3231            PluginCommand::RequestPluginPermissions(permissions) => Ok(ProtobufPluginCommand {
3232                name: CommandName::RequestPluginPermissions as i32,
3233                payload: Some(Payload::RequestPluginPermissionPayload(
3234                    RequestPluginPermissionPayload {
3235                        permissions: permissions
3236                            .iter()
3237                            .filter_map(|p| ProtobufPermissionType::try_from(*p).ok())
3238                            .map(|p| p as i32)
3239                            .collect(),
3240                    },
3241                )),
3242            }),
3243            PluginCommand::SwitchSession(switch_to_session) => Ok(ProtobufPluginCommand {
3244                name: CommandName::SwitchSession as i32,
3245                payload: Some(Payload::SwitchSessionPayload(SwitchSessionPayload {
3246                    name: switch_to_session.name,
3247                    tab_position: switch_to_session.tab_position.map(|t| t as u32),
3248                    pane_id: switch_to_session.pane_id.map(|p| p.0),
3249                    pane_id_is_plugin: switch_to_session.pane_id.map(|p| p.1),
3250                    layout: switch_to_session.layout.and_then(|l| l.try_into().ok()),
3251                    cwd: switch_to_session.cwd.map(|c| c.display().to_string()),
3252                })),
3253            }),
3254            PluginCommand::OpenTerminalInPlace(cwd) => Ok(ProtobufPluginCommand {
3255                name: CommandName::OpenTerminalInPlace as i32,
3256                payload: Some(Payload::OpenTerminalInPlacePayload(OpenFilePayload {
3257                    file_to_open: Some(cwd.try_into()?),
3258                    floating_pane_coordinates: None,
3259                    context: vec![], // will be added in the future
3260                })),
3261            }),
3262            PluginCommand::OpenFileInPlace(file_to_open, context) => Ok(ProtobufPluginCommand {
3263                name: CommandName::OpenFileInPlace as i32,
3264                payload: Some(Payload::OpenFileInPlacePayload(OpenFilePayload {
3265                    file_to_open: Some(file_to_open.try_into()?),
3266                    floating_pane_coordinates: None,
3267                    context: context
3268                        .into_iter()
3269                        .map(|(name, value)| ContextItem { name, value })
3270                        .collect(),
3271                })),
3272            }),
3273            PluginCommand::OpenCommandPaneInPlace(command_to_run, context) => {
3274                let context: Vec<_> = context
3275                    .into_iter()
3276                    .map(|(name, value)| ContextItem { name, value })
3277                    .collect();
3278                Ok(ProtobufPluginCommand {
3279                    name: CommandName::OpenCommandInPlace as i32,
3280                    payload: Some(Payload::OpenCommandPaneInPlacePayload(
3281                        OpenCommandPanePayload {
3282                            command_to_run: Some(command_to_run.try_into()?),
3283                            floating_pane_coordinates: None,
3284                            context,
3285                        },
3286                    )),
3287                })
3288            },
3289            PluginCommand::RunCommand(command_line, env_variables, cwd, context) => {
3290                let env_variables: Vec<_> = env_variables
3291                    .into_iter()
3292                    .map(|(name, value)| EnvVariable { name, value })
3293                    .collect();
3294                let context: Vec<_> = context
3295                    .into_iter()
3296                    .map(|(name, value)| ContextItem { name, value })
3297                    .collect();
3298                let cwd = cwd.display().to_string();
3299                Ok(ProtobufPluginCommand {
3300                    name: CommandName::RunCommand as i32,
3301                    payload: Some(Payload::RunCommandPayload(RunCommandPayload {
3302                        command_line,
3303                        env_variables,
3304                        cwd,
3305                        context,
3306                    })),
3307                })
3308            },
3309            PluginCommand::WebRequest(url, verb, headers, body, context) => {
3310                let context: Vec<_> = context
3311                    .into_iter()
3312                    .map(|(name, value)| ContextItem { name, value })
3313                    .collect();
3314                let headers: Vec<_> = headers
3315                    .into_iter()
3316                    .map(|(name, value)| Header { name, value })
3317                    .collect();
3318                let verb: ProtobufHttpVerb = verb.into();
3319                Ok(ProtobufPluginCommand {
3320                    name: CommandName::WebRequest as i32,
3321                    payload: Some(Payload::WebRequestPayload(WebRequestPayload {
3322                        url,
3323                        verb: verb as i32,
3324                        body,
3325                        headers,
3326                        context,
3327                    })),
3328                })
3329            },
3330            PluginCommand::DeleteDeadSession(dead_session_name) => Ok(ProtobufPluginCommand {
3331                name: CommandName::DeleteDeadSession as i32,
3332                payload: Some(Payload::DeleteDeadSessionPayload(dead_session_name)),
3333            }),
3334            PluginCommand::DeleteAllDeadSessions => Ok(ProtobufPluginCommand {
3335                name: CommandName::DeleteAllDeadSessions as i32,
3336                payload: None,
3337            }),
3338            PluginCommand::RenameSession(new_session_name) => Ok(ProtobufPluginCommand {
3339                name: CommandName::RenameSession as i32,
3340                payload: Some(Payload::RenameSessionPayload(new_session_name)),
3341            }),
3342            PluginCommand::UnblockCliPipeInput(pipe_name) => Ok(ProtobufPluginCommand {
3343                name: CommandName::UnblockCliPipeInput as i32,
3344                payload: Some(Payload::UnblockCliPipeInputPayload(pipe_name)),
3345            }),
3346            PluginCommand::BlockCliPipeInput(pipe_name) => Ok(ProtobufPluginCommand {
3347                name: CommandName::BlockCliPipeInput as i32,
3348                payload: Some(Payload::BlockCliPipeInputPayload(pipe_name)),
3349            }),
3350            PluginCommand::CliPipeOutput(pipe_name, output) => Ok(ProtobufPluginCommand {
3351                name: CommandName::CliPipeOutput as i32,
3352                payload: Some(Payload::CliPipeOutputPayload(CliPipeOutputPayload {
3353                    pipe_name,
3354                    output,
3355                })),
3356            }),
3357            PluginCommand::MessageToPlugin(message_to_plugin) => {
3358                let plugin_config: Vec<_> = message_to_plugin
3359                    .plugin_config
3360                    .into_iter()
3361                    .map(|(name, value)| ContextItem { name, value })
3362                    .collect();
3363                let message_args: Vec<_> = message_to_plugin
3364                    .message_args
3365                    .into_iter()
3366                    .map(|(name, value)| ContextItem { name, value })
3367                    .collect();
3368                Ok(ProtobufPluginCommand {
3369                    name: CommandName::MessageToPlugin as i32,
3370                    payload: Some(Payload::MessageToPluginPayload(MessageToPluginPayload {
3371                        plugin_url: message_to_plugin.plugin_url,
3372                        plugin_config,
3373                        message_name: message_to_plugin.message_name,
3374                        message_payload: message_to_plugin.message_payload,
3375                        message_args,
3376                        new_plugin_args: message_to_plugin.new_plugin_args.map(|m_t_p| {
3377                            ProtobufNewPluginArgs {
3378                                should_float: m_t_p.should_float,
3379                                pane_id_to_replace: m_t_p
3380                                    .pane_id_to_replace
3381                                    .and_then(|p_id| ProtobufPaneId::try_from(p_id).ok()),
3382                                pane_title: m_t_p.pane_title,
3383                                cwd: m_t_p.cwd.map(|cwd| cwd.display().to_string()),
3384                                skip_cache: m_t_p.skip_cache,
3385                                should_focus: m_t_p.should_focus,
3386                            }
3387                        }),
3388                        destination_plugin_id: message_to_plugin.destination_plugin_id,
3389                        floating_pane_coordinates: message_to_plugin
3390                            .floating_pane_coordinates
3391                            .and_then(|f| f.try_into().ok()),
3392                    })),
3393                })
3394            },
3395            PluginCommand::DisconnectOtherClients => Ok(ProtobufPluginCommand {
3396                name: CommandName::DisconnectOtherClients as i32,
3397                payload: None,
3398            }),
3399            PluginCommand::KillSessions(session_names) => Ok(ProtobufPluginCommand {
3400                name: CommandName::KillSessions as i32,
3401                payload: Some(Payload::KillSessionsPayload(KillSessionsPayload {
3402                    session_names,
3403                })),
3404            }),
3405            PluginCommand::ScanHostFolder(folder_to_scan) => Ok(ProtobufPluginCommand {
3406                name: CommandName::ScanHostFolder as i32,
3407                payload: Some(Payload::ScanHostFolderPayload(
3408                    folder_to_scan.display().to_string(),
3409                )),
3410            }),
3411            PluginCommand::WatchFilesystem => Ok(ProtobufPluginCommand {
3412                name: CommandName::WatchFilesystem as i32,
3413                payload: None,
3414            }),
3415            PluginCommand::ListWindowsVolumes => Ok(ProtobufPluginCommand {
3416                name: CommandName::ListWindowsVolumes as i32,
3417                payload: None,
3418            }),
3419            PluginCommand::GetSessionList => Ok(ProtobufPluginCommand {
3420                name: CommandName::GetSessionList as i32,
3421                payload: Some(Payload::GetSessionListPayload(
3422                    ProtobufGetSessionListPayload {},
3423                )),
3424            }),
3425            PluginCommand::KillSessionsAndReply(session_names) => Ok(ProtobufPluginCommand {
3426                name: CommandName::KillSessionsAndReply as i32,
3427                payload: Some(Payload::KillSessionsAndReplyPayload(KillSessionsPayload {
3428                    session_names,
3429                })),
3430            }),
3431            PluginCommand::DeleteDeadSessionAndReply(dead_session_name) => {
3432                Ok(ProtobufPluginCommand {
3433                    name: CommandName::DeleteDeadSessionAndReply as i32,
3434                    payload: Some(Payload::DeleteDeadSessionAndReplyPayload(dead_session_name)),
3435                })
3436            },
3437            PluginCommand::DeleteAllDeadSessionsAndReply => Ok(ProtobufPluginCommand {
3438                name: CommandName::DeleteAllDeadSessionsAndReply as i32,
3439                payload: None,
3440            }),
3441            PluginCommand::SetSoftKeyboard(on) => Ok(ProtobufPluginCommand {
3442                name: CommandName::SetSoftKeyboard as i32,
3443                payload: Some(Payload::SetSoftKeyboardPayload(
3444                    ProtobufSetSoftKeyboardPayload { on },
3445                )),
3446            }),
3447            PluginCommand::DumpSessionLayout { tab_index } => Ok(ProtobufPluginCommand {
3448                name: CommandName::DumpSessionLayout as i32,
3449                payload: tab_index.map(|idx| {
3450                    Payload::DumpSessionLayoutPayload(DumpSessionLayoutPayload {
3451                        tab_index: Some(idx as u32),
3452                    })
3453                }),
3454            }),
3455            PluginCommand::CloseSelf => Ok(ProtobufPluginCommand {
3456                name: CommandName::CloseSelf as i32,
3457                payload: None,
3458            }),
3459            PluginCommand::NewTabsWithLayoutInfo(new_tabs_with_layout_info_payload) => {
3460                Ok(ProtobufPluginCommand {
3461                    name: CommandName::NewTabsWithLayoutInfo as i32,
3462                    payload: Some(Payload::NewTabsWithLayoutInfoPayload(
3463                        NewTabsWithLayoutInfoPayload {
3464                            layout_info: new_tabs_with_layout_info_payload.try_into().ok(),
3465                        },
3466                    )),
3467                })
3468            },
3469            PluginCommand::Reconfigure(config, write_to_disk) => Ok(ProtobufPluginCommand {
3470                name: CommandName::Reconfigure as i32,
3471                payload: Some(Payload::ReconfigurePayload(ReconfigurePayload {
3472                    config,
3473                    write_to_disk,
3474                })),
3475            }),
3476            PluginCommand::HidePaneWithId(pane_id_to_hide) => Ok(ProtobufPluginCommand {
3477                name: CommandName::HidePaneWithId as i32,
3478                payload: Some(Payload::HidePaneWithIdPayload(HidePaneWithIdPayload {
3479                    pane_id: ProtobufPaneId::try_from(pane_id_to_hide).ok(),
3480                })),
3481            }),
3482            PluginCommand::ShowPaneWithId(
3483                pane_id_to_show,
3484                should_float_if_hidden,
3485                should_focus_pane,
3486            ) => Ok(ProtobufPluginCommand {
3487                name: CommandName::ShowPaneWithId as i32,
3488                payload: Some(Payload::ShowPaneWithIdPayload(ShowPaneWithIdPayload {
3489                    pane_id: ProtobufPaneId::try_from(pane_id_to_show).ok(),
3490                    should_float_if_hidden,
3491                    should_focus_pane,
3492                })),
3493            }),
3494            PluginCommand::OpenCommandPaneBackground(command_to_run, context) => {
3495                let context: Vec<_> = context
3496                    .into_iter()
3497                    .map(|(name, value)| ContextItem { name, value })
3498                    .collect();
3499                Ok(ProtobufPluginCommand {
3500                    name: CommandName::OpenCommandPaneBackground as i32,
3501                    payload: Some(Payload::OpenCommandPaneBackgroundPayload(
3502                        OpenCommandPanePayload {
3503                            command_to_run: Some(command_to_run.try_into()?),
3504                            floating_pane_coordinates: None,
3505                            context,
3506                        },
3507                    )),
3508                })
3509            },
3510            PluginCommand::RerunCommandPane(terminal_pane_id) => Ok(ProtobufPluginCommand {
3511                name: CommandName::RerunCommandPane as i32,
3512                payload: Some(Payload::RerunCommandPanePayload(RerunCommandPanePayload {
3513                    terminal_pane_id,
3514                })),
3515            }),
3516            PluginCommand::ResizePaneIdWithDirection(resize, pane_id) => {
3517                Ok(ProtobufPluginCommand {
3518                    name: CommandName::ResizePaneIdWithDirection as i32,
3519                    payload: Some(Payload::ResizePaneIdWithDirectionPayload(
3520                        ResizePaneIdWithDirectionPayload {
3521                            resize: Some(resize.try_into()?),
3522                            pane_id: Some(pane_id.try_into()?),
3523                        },
3524                    )),
3525                })
3526            },
3527            PluginCommand::EditScrollbackForPaneWithId(pane_id) => Ok(ProtobufPluginCommand {
3528                name: CommandName::EditScrollbackForPaneWithId as i32,
3529                payload: Some(Payload::EditScrollbackForPaneWithIdPayload(
3530                    EditScrollbackForPaneWithIdPayload {
3531                        pane_id: Some(pane_id.try_into()?),
3532                    },
3533                )),
3534            }),
3535            PluginCommand::GetPaneScrollback {
3536                pane_id,
3537                get_full_scrollback,
3538            } => Ok(ProtobufPluginCommand {
3539                name: CommandName::GetPaneScrollback as i32,
3540                payload: Some(Payload::GetPaneScrollbackPayload(
3541                    GetPaneScrollbackPayload {
3542                        pane_id: Some(pane_id.try_into()?),
3543                        get_full_scrollback,
3544                    },
3545                )),
3546            }),
3547            PluginCommand::WriteToPaneId(bytes_to_write, pane_id) => Ok(ProtobufPluginCommand {
3548                name: CommandName::WriteToPaneId as i32,
3549                payload: Some(Payload::WriteToPaneIdPayload(WriteToPaneIdPayload {
3550                    bytes_to_write,
3551                    pane_id: Some(pane_id.try_into()?),
3552                })),
3553            }),
3554            PluginCommand::WriteCharsToPaneId(chars_to_write, pane_id) => {
3555                Ok(ProtobufPluginCommand {
3556                    name: CommandName::WriteCharsToPaneId as i32,
3557                    payload: Some(Payload::WriteCharsToPaneIdPayload(
3558                        WriteCharsToPaneIdPayload {
3559                            chars_to_write,
3560                            pane_id: Some(pane_id.try_into()?),
3561                        },
3562                    )),
3563                })
3564            },
3565            PluginCommand::SendSigintToPaneId(pane_id) => Ok(ProtobufPluginCommand {
3566                name: CommandName::SendSigintToPaneId as i32,
3567                payload: Some(Payload::SendSigintToPaneIdPayload(pane_id.try_into()?)),
3568            }),
3569            PluginCommand::SendSigkillToPaneId(pane_id) => Ok(ProtobufPluginCommand {
3570                name: CommandName::SendSigkillToPaneId as i32,
3571                payload: Some(Payload::SendSigkillToPaneIdPayload(pane_id.try_into()?)),
3572            }),
3573            PluginCommand::GetPanePid { pane_id } => Ok(ProtobufPluginCommand {
3574                name: CommandName::GetPanePid as i32,
3575                payload: Some(Payload::GetPanePidPayload(GetPanePidPayload {
3576                    pane_id: Some(pane_id.try_into()?),
3577                })),
3578            }),
3579            PluginCommand::GetPaneRunningCommand { pane_id } => Ok(ProtobufPluginCommand {
3580                name: CommandName::GetPaneRunningCommand as i32,
3581                payload: Some(Payload::GetPaneRunningCommandPayload(
3582                    ProtobufGetPaneRunningCommandPayload {
3583                        pane_id: Some(pane_id.try_into()?),
3584                    },
3585                )),
3586            }),
3587            PluginCommand::GetPaneCwd { pane_id } => Ok(ProtobufPluginCommand {
3588                name: CommandName::GetPaneCwd as i32,
3589                payload: Some(Payload::GetPaneCwdPayload(ProtobufGetPaneCwdPayload {
3590                    pane_id: Some(pane_id.try_into()?),
3591                })),
3592            }),
3593            PluginCommand::OverrideLayout(
3594                layout_info,
3595                retain_existing_terminal_panes,
3596                retain_existing_plugin_panes,
3597                apply_only_to_active_tab,
3598                context,
3599            ) => Ok(ProtobufPluginCommand {
3600                name: CommandName::OverrideLayout as i32,
3601                payload: Some(Payload::OverrideLayoutPayload(OverrideLayoutPayload {
3602                    layout_info: layout_info.try_into().ok(),
3603                    context: context
3604                        .into_iter()
3605                        .map(|(name, value)| ContextItem { name, value })
3606                        .collect(),
3607                    retain_existing_terminal_panes,
3608                    retain_existing_plugin_panes,
3609                    apply_only_to_active_tab,
3610                })),
3611            }),
3612            PluginCommand::SaveLayout {
3613                layout_name,
3614                layout_kdl,
3615                overwrite,
3616            } => Ok(ProtobufPluginCommand {
3617                name: CommandName::SaveLayout as i32,
3618                payload: Some(Payload::SaveLayoutPayload(SaveLayoutPayload {
3619                    layout_name,
3620                    layout_kdl,
3621                    overwrite,
3622                })),
3623            }),
3624            PluginCommand::DeleteLayout { layout_name } => Ok(ProtobufPluginCommand {
3625                name: CommandName::DeleteLayout as i32,
3626                payload: Some(Payload::DeleteLayoutPayload(DeleteLayoutPayload {
3627                    layout_name,
3628                })),
3629            }),
3630            PluginCommand::RenameLayout {
3631                old_layout_name,
3632                new_layout_name,
3633            } => Ok(ProtobufPluginCommand {
3634                name: CommandName::RenameLayout as i32,
3635                payload: Some(Payload::RenameLayoutPayload(RenameLayoutPayload {
3636                    old_layout_name,
3637                    new_layout_name,
3638                })),
3639            }),
3640            PluginCommand::EditLayout {
3641                layout_name,
3642                context,
3643            } => {
3644                let context: Vec<_> = context
3645                    .into_iter()
3646                    .map(|(name, value)| ContextItem { name, value })
3647                    .collect();
3648                Ok(ProtobufPluginCommand {
3649                    name: CommandName::EditLayout as i32,
3650                    payload: Some(Payload::EditLayoutPayload(EditLayoutPayload {
3651                        layout_name,
3652                        context,
3653                    })),
3654                })
3655            },
3656            PluginCommand::MovePaneWithPaneId(pane_id) => Ok(ProtobufPluginCommand {
3657                name: CommandName::MovePaneWithPaneId as i32,
3658                payload: Some(Payload::MovePaneWithPaneIdPayload(
3659                    MovePaneWithPaneIdPayload {
3660                        pane_id: Some(pane_id.try_into()?),
3661                    },
3662                )),
3663            }),
3664            PluginCommand::MovePaneWithPaneIdInDirection(pane_id, direction) => {
3665                Ok(ProtobufPluginCommand {
3666                    name: CommandName::MovePaneWithPaneIdInDirection as i32,
3667                    payload: Some(Payload::MovePaneWithPaneIdInDirectionPayload(
3668                        MovePaneWithPaneIdInDirectionPayload {
3669                            pane_id: Some(pane_id.try_into()?),
3670                            direction: Some(direction.try_into()?),
3671                        },
3672                    )),
3673                })
3674            },
3675            PluginCommand::ClearScreenForPaneId(pane_id) => Ok(ProtobufPluginCommand {
3676                name: CommandName::ClearScreenForPaneId as i32,
3677                payload: Some(Payload::ClearScreenForPaneIdPayload(
3678                    ClearScreenForPaneIdPayload {
3679                        pane_id: Some(pane_id.try_into()?),
3680                    },
3681                )),
3682            }),
3683            PluginCommand::ScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3684                name: CommandName::ScrollUpInPaneId as i32,
3685                payload: Some(Payload::ScrollUpInPaneIdPayload(ScrollUpInPaneIdPayload {
3686                    pane_id: Some(pane_id.try_into()?),
3687                })),
3688            }),
3689            PluginCommand::ScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3690                name: CommandName::ScrollDownInPaneId as i32,
3691                payload: Some(Payload::ScrollDownInPaneIdPayload(
3692                    ScrollDownInPaneIdPayload {
3693                        pane_id: Some(pane_id.try_into()?),
3694                    },
3695                )),
3696            }),
3697            PluginCommand::ScrollToTopInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3698                name: CommandName::ScrollToTopInPaneId as i32,
3699                payload: Some(Payload::ScrollToTopInPaneIdPayload(
3700                    ScrollToTopInPaneIdPayload {
3701                        pane_id: Some(pane_id.try_into()?),
3702                    },
3703                )),
3704            }),
3705            PluginCommand::ScrollToBottomInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3706                name: CommandName::ScrollToBottomInPaneId as i32,
3707                payload: Some(Payload::ScrollToBottomInPaneIdPayload(
3708                    ScrollToBottomInPaneIdPayload {
3709                        pane_id: Some(pane_id.try_into()?),
3710                    },
3711                )),
3712            }),
3713            PluginCommand::PageScrollUpInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3714                name: CommandName::PageScrollUpInPaneId as i32,
3715                payload: Some(Payload::PageScrollUpInPaneIdPayload(
3716                    PageScrollUpInPaneIdPayload {
3717                        pane_id: Some(pane_id.try_into()?),
3718                    },
3719                )),
3720            }),
3721            PluginCommand::PageScrollDownInPaneId(pane_id) => Ok(ProtobufPluginCommand {
3722                name: CommandName::PageScrollDownInPaneId as i32,
3723                payload: Some(Payload::PageScrollDownInPaneIdPayload(
3724                    PageScrollDownInPaneIdPayload {
3725                        pane_id: Some(pane_id.try_into()?),
3726                    },
3727                )),
3728            }),
3729            PluginCommand::TogglePaneIdFullscreen(pane_id) => Ok(ProtobufPluginCommand {
3730                name: CommandName::TogglePaneIdFullscreen as i32,
3731                payload: Some(Payload::TogglePaneIdFullscreenPayload(
3732                    TogglePaneIdFullscreenPayload {
3733                        pane_id: Some(pane_id.try_into()?),
3734                    },
3735                )),
3736            }),
3737            PluginCommand::TogglePaneEmbedOrEjectForPaneId(pane_id) => Ok(ProtobufPluginCommand {
3738                name: CommandName::TogglePaneEmbedOrEjectForPaneId as i32,
3739                payload: Some(Payload::TogglePaneEmbedOrEjectForPaneIdPayload(
3740                    TogglePaneEmbedOrEjectForPaneIdPayload {
3741                        pane_id: Some(pane_id.try_into()?),
3742                    },
3743                )),
3744            }),
3745            PluginCommand::CloseTabWithIndex(tab_index) => Ok(ProtobufPluginCommand {
3746                name: CommandName::CloseTabWithIndex as i32,
3747                payload: Some(Payload::CloseTabWithIndexPayload(
3748                    CloseTabWithIndexPayload {
3749                        tab_index: tab_index as u32,
3750                    },
3751                )),
3752            }),
3753            PluginCommand::BreakPanesToNewTab(
3754                pane_ids,
3755                new_tab_name,
3756                should_change_focus_to_new_tab,
3757            ) => Ok(ProtobufPluginCommand {
3758                name: CommandName::BreakPanesToNewTab as i32,
3759                payload: Some(Payload::BreakPanesToNewTabPayload(
3760                    BreakPanesToNewTabPayload {
3761                        pane_ids: pane_ids
3762                            .into_iter()
3763                            .filter_map(|p_id| p_id.try_into().ok())
3764                            .collect(),
3765                        should_change_focus_to_new_tab,
3766                        new_tab_name,
3767                    },
3768                )),
3769            }),
3770            PluginCommand::BreakPanesToTabWithIndex(
3771                pane_ids,
3772                tab_index,
3773                should_change_focus_to_target_tab,
3774            ) => Ok(ProtobufPluginCommand {
3775                name: CommandName::BreakPanesToTabWithIndex as i32,
3776                payload: Some(Payload::BreakPanesToTabWithIndexPayload(
3777                    BreakPanesToTabWithIndexPayload {
3778                        pane_ids: pane_ids
3779                            .into_iter()
3780                            .filter_map(|p_id| p_id.try_into().ok())
3781                            .collect(),
3782                        tab_index: tab_index as u32,
3783                        should_change_focus_to_target_tab,
3784                    },
3785                )),
3786            }),
3787            PluginCommand::SwitchTabToId(tab_id) => Ok(ProtobufPluginCommand {
3788                name: CommandName::SwitchTabToId as i32,
3789                payload: Some(Payload::SwitchTabToIdPayload(SwitchTabToIdPayload {
3790                    tab_id,
3791                })),
3792            }),
3793            PluginCommand::GoToTabWithId(tab_id) => Ok(ProtobufPluginCommand {
3794                name: CommandName::GoToTabWithId as i32,
3795                payload: Some(Payload::GoToTabWithIdPayload(GoToTabWithIdPayload {
3796                    tab_id,
3797                })),
3798            }),
3799            PluginCommand::CloseTabWithId(tab_id) => Ok(ProtobufPluginCommand {
3800                name: CommandName::CloseTabWithId as i32,
3801                payload: Some(Payload::CloseTabWithIdPayload(CloseTabWithIdPayload {
3802                    tab_id,
3803                })),
3804            }),
3805            PluginCommand::RenameTabWithId(tab_id, new_name) => Ok(ProtobufPluginCommand {
3806                name: CommandName::RenameTabWithId as i32,
3807                payload: Some(Payload::RenameTabWithIdPayload(RenameTabWithIdPayload {
3808                    tab_id,
3809                    new_name,
3810                })),
3811            }),
3812            PluginCommand::BreakPanesToTabWithId(
3813                pane_ids,
3814                tab_id,
3815                should_change_focus_to_target_tab,
3816            ) => Ok(ProtobufPluginCommand {
3817                name: CommandName::BreakPanesToTabWithId as i32,
3818                payload: Some(Payload::BreakPanesToTabWithIdPayload(
3819                    BreakPanesToTabWithIdPayload {
3820                        pane_ids: pane_ids
3821                            .into_iter()
3822                            .filter_map(|p_id| p_id.try_into().ok())
3823                            .collect(),
3824                        tab_id,
3825                        should_change_focus_to_target_tab,
3826                    },
3827                )),
3828            }),
3829            PluginCommand::ReloadPlugin(plugin_id) => Ok(ProtobufPluginCommand {
3830                name: CommandName::ReloadPlugin as i32,
3831                payload: Some(Payload::ReloadPluginPayload(ReloadPluginPayload {
3832                    plugin_id,
3833                })),
3834            }),
3835            PluginCommand::LoadNewPlugin {
3836                url,
3837                config,
3838                load_in_background,
3839                skip_plugin_cache,
3840            } => Ok(ProtobufPluginCommand {
3841                name: CommandName::LoadNewPlugin as i32,
3842                payload: Some(Payload::LoadNewPluginPayload(LoadNewPluginPayload {
3843                    plugin_url: url,
3844                    plugin_config: config
3845                        .into_iter()
3846                        .map(|(name, value)| ContextItem { name, value })
3847                        .collect(),
3848                    should_skip_plugin_cache: skip_plugin_cache,
3849                    should_load_plugin_in_background: load_in_background,
3850                })),
3851            }),
3852            PluginCommand::RebindKeys {
3853                keys_to_rebind,
3854                keys_to_unbind,
3855                write_config_to_disk,
3856            } => Ok(ProtobufPluginCommand {
3857                name: CommandName::RebindKeys as i32,
3858                payload: Some(Payload::RebindKeysPayload(RebindKeysPayload {
3859                    keys_to_rebind: keys_to_rebind
3860                        .into_iter()
3861                        .filter_map(|k| k.try_into().ok())
3862                        .collect(),
3863                    keys_to_unbind: keys_to_unbind
3864                        .into_iter()
3865                        .filter_map(|k| k.try_into().ok())
3866                        .collect(),
3867                    write_config_to_disk,
3868                })),
3869            }),
3870            PluginCommand::ListClients => Ok(ProtobufPluginCommand {
3871                name: CommandName::ListClients as i32,
3872                payload: None,
3873            }),
3874            PluginCommand::ChangeHostFolder(new_host_folder) => Ok(ProtobufPluginCommand {
3875                name: CommandName::ChangeHostFolder as i32,
3876                payload: Some(Payload::ChangeHostFolderPayload(ChangeHostFolderPayload {
3877                    new_host_folder: new_host_folder.display().to_string(), // TODO: not accurate?
3878                })),
3879            }),
3880            PluginCommand::SetFloatingPanePinned(pane_id, should_be_pinned) => {
3881                Ok(ProtobufPluginCommand {
3882                    name: CommandName::SetFloatingPanePinned as i32,
3883                    payload: Some(Payload::SetFloatingPanePinnedPayload(
3884                        SetFloatingPanePinnedPayload {
3885                            pane_id: pane_id.try_into().ok(),
3886                            should_be_pinned,
3887                        },
3888                    )),
3889                })
3890            },
3891            PluginCommand::StackPanes(pane_ids) => Ok(ProtobufPluginCommand {
3892                name: CommandName::StackPanes as i32,
3893                payload: Some(Payload::StackPanesPayload(StackPanesPayload {
3894                    pane_ids: pane_ids
3895                        .into_iter()
3896                        .filter_map(|p_id| p_id.try_into().ok())
3897                        .collect(),
3898                })),
3899            }),
3900            PluginCommand::ChangeFloatingPanesCoordinates(
3901                pane_ids_and_floating_panes_coordinates,
3902            ) => Ok(ProtobufPluginCommand {
3903                name: CommandName::ChangeFloatingPanesCoordinates as i32,
3904                payload: Some(Payload::ChangeFloatingPanesCoordinatesPayload(
3905                    ChangeFloatingPanesCoordinatesPayload {
3906                        pane_ids_and_floating_panes_coordinates:
3907                            pane_ids_and_floating_panes_coordinates
3908                                .into_iter()
3909                                .filter_map(|(p_id, floating_pane_coordinates)| {
3910                                    Some(PaneIdAndFloatingPaneCoordinates {
3911                                        pane_id: Some(p_id.try_into().ok()?),
3912                                        floating_pane_coordinates: Some(
3913                                            floating_pane_coordinates.try_into().ok()?,
3914                                        ),
3915                                    })
3916                                })
3917                                .collect(),
3918                    },
3919                )),
3920            }),
3921            PluginCommand::TogglePaneBorderless(pane_id) => Ok(ProtobufPluginCommand {
3922                name: CommandName::TogglePaneBorderless as i32,
3923                payload: Some(Payload::TogglePaneBorderlessPayload(
3924                    TogglePaneBorderlessPayload {
3925                        pane_id: Some(pane_id.try_into()?),
3926                    },
3927                )),
3928            }),
3929            PluginCommand::SetPaneBorderless(pane_id, borderless) => Ok(ProtobufPluginCommand {
3930                name: CommandName::SetPaneBorderless as i32,
3931                payload: Some(Payload::SetPaneBorderlessPayload(
3932                    SetPaneBorderlessPayload {
3933                        pane_id: Some(pane_id.try_into()?),
3934                        borderless,
3935                    },
3936                )),
3937            }),
3938            PluginCommand::OpenCommandPaneNearPlugin(command_to_run, context) => {
3939                let context: Vec<_> = context
3940                    .into_iter()
3941                    .map(|(name, value)| ContextItem { name, value })
3942                    .collect();
3943                Ok(ProtobufPluginCommand {
3944                    name: CommandName::OpenCommandPaneNearPlugin as i32,
3945                    payload: Some(Payload::OpenCommandPaneNearPluginPayload(
3946                        OpenCommandPaneNearPluginPayload {
3947                            command_to_run: Some(command_to_run.try_into()?),
3948                            floating_pane_coordinates: None,
3949                            context,
3950                        },
3951                    )),
3952                })
3953            },
3954            PluginCommand::OpenCommandPaneFloatingNearPlugin(
3955                command_to_run,
3956                floating_pane_coordinates,
3957                context,
3958            ) => {
3959                let context: Vec<_> = context
3960                    .into_iter()
3961                    .map(|(name, value)| ContextItem { name, value })
3962                    .collect();
3963                Ok(ProtobufPluginCommand {
3964                    name: CommandName::OpenCommandPaneFloatingNearPlugin as i32,
3965                    payload: Some(Payload::OpenCommandPaneFloatingNearPluginPayload(
3966                        OpenCommandPaneFloatingNearPluginPayload {
3967                            command_to_run: Some(command_to_run.try_into()?),
3968                            floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
3969                            context,
3970                        },
3971                    )),
3972                })
3973            },
3974            PluginCommand::OpenTerminalNearPlugin(cwd) => Ok(ProtobufPluginCommand {
3975                name: CommandName::OpenTerminalNearPlugin as i32,
3976                payload: Some(Payload::OpenTerminalNearPluginPayload(
3977                    OpenTerminalNearPluginPayload {
3978                        file_to_open: Some(cwd.try_into()?),
3979                        context: vec![], // will be added in the future
3980                    },
3981                )),
3982            }),
3983            PluginCommand::OpenTerminalFloatingNearPlugin(cwd, floating_pane_coordinates) => {
3984                Ok(ProtobufPluginCommand {
3985                    name: CommandName::OpenTerminalFloatingNearPlugin as i32,
3986                    payload: Some(Payload::OpenTerminalFloatingNearPluginPayload(
3987                        OpenTerminalFloatingNearPluginPayload {
3988                            file_to_open: Some(cwd.try_into()?),
3989                            floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
3990                            context: vec![], // will be added in the future
3991                        },
3992                    )),
3993                })
3994            },
3995            PluginCommand::OpenTerminalInPlaceOfPlugin(cwd, close_plugin_after_replace) => {
3996                Ok(ProtobufPluginCommand {
3997                    name: CommandName::OpenTerminalInPlaceOfPlugin as i32,
3998                    payload: Some(Payload::OpenTerminalInPlaceOfPluginPayload(
3999                        OpenTerminalInPlaceOfPluginPayload {
4000                            file_to_open: Some(cwd.try_into()?),
4001                            close_plugin_after_replace,
4002                            context: vec![], // will be added in the future
4003                        },
4004                    )),
4005                })
4006            },
4007            PluginCommand::OpenCommandPaneInPlaceOfPlugin(
4008                command_to_run,
4009                close_plugin_after_replace,
4010                context,
4011            ) => {
4012                let context: Vec<_> = context
4013                    .into_iter()
4014                    .map(|(name, value)| ContextItem { name, value })
4015                    .collect();
4016                Ok(ProtobufPluginCommand {
4017                    name: CommandName::OpenCommandPaneInPlaceOfPlugin as i32,
4018                    payload: Some(Payload::OpenCommandPaneInPlaceOfPluginPayload(
4019                        OpenCommandPaneInPlaceOfPluginPayload {
4020                            command_to_run: Some(command_to_run.try_into()?),
4021                            close_plugin_after_replace,
4022                            context,
4023                        },
4024                    )),
4025                })
4026            },
4027            PluginCommand::OpenFileNearPlugin(file_to_open, context) => Ok(ProtobufPluginCommand {
4028                name: CommandName::OpenFileNearPlugin as i32,
4029                payload: Some(Payload::OpenFileNearPluginPayload(
4030                    OpenFileNearPluginPayload {
4031                        file_to_open: Some(file_to_open.try_into()?),
4032                        floating_pane_coordinates: None,
4033                        context: context
4034                            .into_iter()
4035                            .map(|(name, value)| ContextItem { name, value })
4036                            .collect(),
4037                    },
4038                )),
4039            }),
4040            PluginCommand::OpenFileFloatingNearPlugin(
4041                file_to_open,
4042                floating_pane_coordinates,
4043                context,
4044            ) => Ok(ProtobufPluginCommand {
4045                name: CommandName::OpenFileFloatingNearPlugin as i32,
4046                payload: Some(Payload::OpenFileFloatingNearPluginPayload(
4047                    OpenFileFloatingNearPluginPayload {
4048                        file_to_open: Some(file_to_open.try_into()?),
4049                        floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
4050                        context: context
4051                            .into_iter()
4052                            .map(|(name, value)| ContextItem { name, value })
4053                            .collect(),
4054                    },
4055                )),
4056            }),
4057            PluginCommand::OpenFileInPlaceOfPlugin(
4058                file_to_open,
4059                close_plugin_after_replace,
4060                context,
4061            ) => Ok(ProtobufPluginCommand {
4062                name: CommandName::OpenFileInPlaceOfPlugin as i32,
4063                payload: Some(Payload::OpenFileInPlaceOfPluginPayload(
4064                    OpenFileInPlaceOfPluginPayload {
4065                        file_to_open: Some(file_to_open.try_into()?),
4066                        floating_pane_coordinates: None,
4067                        close_plugin_after_replace,
4068                        context: context
4069                            .into_iter()
4070                            .map(|(name, value)| ContextItem { name, value })
4071                            .collect(),
4072                    },
4073                )),
4074            }),
4075            PluginCommand::GroupAndUngroupPanes(
4076                panes_to_group,
4077                panes_to_ungroup,
4078                for_all_clients,
4079            ) => Ok(ProtobufPluginCommand {
4080                name: CommandName::GroupAndUngroupPanes as i32,
4081                payload: Some(Payload::GroupAndUngroupPanesPayload(
4082                    GroupAndUngroupPanesPayload {
4083                        pane_ids_to_group: panes_to_group
4084                            .iter()
4085                            .filter_map(|&p| p.try_into().ok())
4086                            .collect(),
4087                        pane_ids_to_ungroup: panes_to_ungroup
4088                            .iter()
4089                            .filter_map(|&p| p.try_into().ok())
4090                            .collect(),
4091                        for_all_clients,
4092                    },
4093                )),
4094            }),
4095            PluginCommand::StartWebServer => Ok(ProtobufPluginCommand {
4096                name: CommandName::StartWebServer as i32,
4097                payload: None,
4098            }),
4099            PluginCommand::StopWebServer => Ok(ProtobufPluginCommand {
4100                name: CommandName::StopWebServer as i32,
4101                payload: None,
4102            }),
4103            PluginCommand::QueryWebServerStatus => Ok(ProtobufPluginCommand {
4104                name: CommandName::QueryWebServerStatus as i32,
4105                payload: None,
4106            }),
4107            PluginCommand::HighlightAndUnhighlightPanes(
4108                panes_to_highlight,
4109                panes_to_unhighlight,
4110            ) => Ok(ProtobufPluginCommand {
4111                name: CommandName::HighlightAndUnhighlightPanes as i32,
4112                payload: Some(Payload::HighlightAndUnhighlightPanesPayload(
4113                    HighlightAndUnhighlightPanesPayload {
4114                        pane_ids_to_highlight: panes_to_highlight
4115                            .iter()
4116                            .filter_map(|&p| p.try_into().ok())
4117                            .collect(),
4118                        pane_ids_to_unhighlight: panes_to_unhighlight
4119                            .iter()
4120                            .filter_map(|&p| p.try_into().ok())
4121                            .collect(),
4122                    },
4123                )),
4124            }),
4125            PluginCommand::CloseMultiplePanes(pane_ids) => Ok(ProtobufPluginCommand {
4126                name: CommandName::CloseMultiplePanes as i32,
4127                payload: Some(Payload::CloseMultiplePanesPayload(
4128                    CloseMultiplePanesPayload {
4129                        pane_ids: pane_ids.iter().filter_map(|&p| p.try_into().ok()).collect(),
4130                    },
4131                )),
4132            }),
4133            PluginCommand::FloatMultiplePanes(pane_ids) => Ok(ProtobufPluginCommand {
4134                name: CommandName::FloatMultiplePanes as i32,
4135                payload: Some(Payload::FloatMultiplePanesPayload(
4136                    FloatMultiplePanesPayload {
4137                        pane_ids: pane_ids.iter().filter_map(|&p| p.try_into().ok()).collect(),
4138                    },
4139                )),
4140            }),
4141            PluginCommand::EmbedMultiplePanes(pane_ids) => Ok(ProtobufPluginCommand {
4142                name: CommandName::EmbedMultiplePanes as i32,
4143                payload: Some(Payload::EmbedMultiplePanesPayload(
4144                    EmbedMultiplePanesPayload {
4145                        pane_ids: pane_ids.iter().filter_map(|&p| p.try_into().ok()).collect(),
4146                    },
4147                )),
4148            }),
4149            PluginCommand::ShareCurrentSession => Ok(ProtobufPluginCommand {
4150                name: CommandName::ShareCurrentSession as i32,
4151                payload: None,
4152            }),
4153            PluginCommand::StopSharingCurrentSession => Ok(ProtobufPluginCommand {
4154                name: CommandName::StopSharingCurrentSession as i32,
4155                payload: None,
4156            }),
4157            PluginCommand::SetSelfMouseSelectionSupport(support_mouse_selection) => {
4158                Ok(ProtobufPluginCommand {
4159                    name: CommandName::SetSelfMouseSelectionSupport as i32,
4160                    payload: Some(Payload::SetSelfMouseSelectionSupportPayload(
4161                        SetSelfMouseSelectionSupportPayload {
4162                            support_mouse_selection,
4163                        },
4164                    )),
4165                })
4166            },
4167            PluginCommand::GenerateWebLoginToken(token_label, read_only) => {
4168                Ok(ProtobufPluginCommand {
4169                    name: CommandName::GenerateWebLoginToken as i32,
4170                    payload: Some(Payload::GenerateWebLoginTokenPayload(
4171                        GenerateWebLoginTokenPayload {
4172                            token_label,
4173                            read_only: Some(read_only),
4174                        },
4175                    )),
4176                })
4177            },
4178            PluginCommand::RevokeWebLoginToken(token_label) => Ok(ProtobufPluginCommand {
4179                name: CommandName::RevokeWebLoginToken as i32,
4180                payload: Some(Payload::RevokeWebLoginTokenPayload(
4181                    RevokeWebLoginTokenPayload { token_label },
4182                )),
4183            }),
4184            PluginCommand::ListWebLoginTokens => Ok(ProtobufPluginCommand {
4185                name: CommandName::ListWebLoginTokens as i32,
4186                payload: None,
4187            }),
4188            PluginCommand::RevokeAllWebLoginTokens => Ok(ProtobufPluginCommand {
4189                name: CommandName::RevokeAllWebLoginTokens as i32,
4190                payload: None,
4191            }),
4192            PluginCommand::RenameWebLoginToken(old_name, new_name) => Ok(ProtobufPluginCommand {
4193                name: CommandName::RenameWebLoginToken as i32,
4194                payload: Some(Payload::RenameWebLoginTokenPayload(
4195                    RenameWebLoginTokenPayload { old_name, new_name },
4196                )),
4197            }),
4198            PluginCommand::InterceptKeyPresses => Ok(ProtobufPluginCommand {
4199                name: CommandName::InterceptKeyPresses as i32,
4200                payload: None,
4201            }),
4202            PluginCommand::ClearKeyPressesIntercepts => Ok(ProtobufPluginCommand {
4203                name: CommandName::ClearKeyPressesIntercepts as i32,
4204                payload: None,
4205            }),
4206            PluginCommand::ReplacePaneWithExistingPane(
4207                pane_id_to_replace,
4208                existing_pane_id,
4209                suppress_replaced_pane,
4210            ) => Ok(ProtobufPluginCommand {
4211                name: CommandName::ReplacePaneWithExistingPane as i32,
4212                payload: Some(Payload::ReplacePaneWithExistingPanePayload(
4213                    ReplacePaneWithExistingPanePayload {
4214                        pane_id_to_replace: ProtobufPaneId::try_from(pane_id_to_replace).ok(),
4215                        existing_pane_id: ProtobufPaneId::try_from(existing_pane_id).ok(),
4216                        suppress_replaced_pane,
4217                    },
4218                )),
4219            }),
4220            PluginCommand::RunAction(action, context) => {
4221                let protobuf_action = ProtobufAction::try_from(action)
4222                    .map_err(|_| "Failed to convert action to protobuf")?;
4223
4224                let context_items: Vec<ContextItem> = context
4225                    .into_iter()
4226                    .map(|(name, value)| ContextItem { name, value })
4227                    .collect();
4228
4229                Ok(ProtobufPluginCommand {
4230                    name: CommandName::RunAction as i32,
4231                    payload: Some(Payload::RunActionPayload(RunActionPayload {
4232                        action: Some(protobuf_action),
4233                        context: context_items,
4234                    })),
4235                })
4236            },
4237            PluginCommand::CopyToClipboard(text) => Ok(ProtobufPluginCommand {
4238                name: CommandName::CopyToClipboard as i32,
4239                payload: Some(Payload::CopyToClipboardPayload(CopyToClipboardPayload {
4240                    text,
4241                })),
4242            }),
4243            PluginCommand::GenerateRandomName => Ok(ProtobufPluginCommand {
4244                name: CommandName::GenerateRandomName as i32,
4245                payload: Some(Payload::GenerateRandomNamePayload(
4246                    GenerateRandomNamePayload {},
4247                )),
4248            }),
4249            PluginCommand::DumpLayout(layout_name) => Ok(ProtobufPluginCommand {
4250                name: CommandName::DumpLayout as i32,
4251                payload: Some(Payload::DumpLayoutPayload(DumpLayoutPayload {
4252                    layout_name,
4253                })),
4254            }),
4255            PluginCommand::ParseLayout(layout_string) => Ok(ProtobufPluginCommand {
4256                name: CommandName::ParseLayout as i32,
4257                payload: Some(Payload::ParseLayoutPayload(ParseLayoutPayload {
4258                    layout_string,
4259                })),
4260            }),
4261            PluginCommand::GetLayoutDir => Ok(ProtobufPluginCommand {
4262                name: CommandName::GetLayoutDir as i32,
4263                payload: Some(Payload::GetLayoutDirPayload(GetLayoutDirPayload {})),
4264            }),
4265            PluginCommand::GetFocusedPaneInfo => Ok(ProtobufPluginCommand {
4266                name: CommandName::GetFocusedPaneInfo as i32,
4267                payload: Some(Payload::GetFocusedPaneInfoPayload(
4268                    GetFocusedPaneInfoPayload {},
4269                )),
4270            }),
4271            PluginCommand::SaveSession => Ok(ProtobufPluginCommand {
4272                name: CommandName::SaveSession as i32,
4273                payload: Some(Payload::SaveSessionPayload(SaveSessionPayload {})),
4274            }),
4275            PluginCommand::CurrentSessionLastSavedTime => Ok(ProtobufPluginCommand {
4276                name: CommandName::CurrentSessionLastSavedTime as i32,
4277                payload: Some(Payload::CurrentSessionLastSavedTimePayload(
4278                    CurrentSessionLastSavedTimePayload {},
4279                )),
4280            }),
4281            PluginCommand::GetPaneInfo(pane_id) => {
4282                let protobuf_pane_id: ProtobufPaneId = pane_id.try_into()?;
4283                Ok(ProtobufPluginCommand {
4284                    name: CommandName::GetPaneInfo as i32,
4285                    payload: Some(Payload::GetPaneInfoPayload(GetPaneInfoPayload {
4286                        pane_id: Some(protobuf_pane_id),
4287                    })),
4288                })
4289            },
4290            PluginCommand::GetTabInfo(tab_id) => Ok(ProtobufPluginCommand {
4291                name: CommandName::GetTabInfo as i32,
4292                payload: Some(Payload::GetTabInfoPayload(GetTabInfoPayload {
4293                    tab_id: tab_id as u64,
4294                })),
4295            }),
4296            PluginCommand::GetSessionEnvironmentVariables => {
4297                let payload = ProtobufGetSessionEnvironmentVariablesPayload {};
4298                Ok(ProtobufPluginCommand {
4299                    name: CommandName::GetSessionEnvironmentVariables as i32,
4300                    payload: Some(Payload::GetSessionEnvironmentVariablesPayload(payload)),
4301                })
4302            },
4303            PluginCommand::OpenCommandPaneInNewTab(command_to_run, context) => {
4304                let context: Vec<_> = context
4305                    .into_iter()
4306                    .map(|(name, value)| ContextItem { name, value })
4307                    .collect();
4308                Ok(ProtobufPluginCommand {
4309                    name: CommandName::OpenCommandPaneInNewTab as i32,
4310                    payload: Some(Payload::OpenCommandPaneInNewTabPayload(
4311                        OpenCommandPanePayload {
4312                            command_to_run: Some(command_to_run.try_into()?),
4313                            floating_pane_coordinates: None,
4314                            context,
4315                        },
4316                    )),
4317                })
4318            },
4319            PluginCommand::OpenPluginPaneInNewTab {
4320                plugin_url,
4321                configuration,
4322                context,
4323            } => {
4324                let context: Vec<_> = context
4325                    .into_iter()
4326                    .map(|(name, value)| ContextItem { name, value })
4327                    .collect();
4328                let configuration: std::collections::HashMap<String, String> =
4329                    configuration.into_iter().collect();
4330                Ok(ProtobufPluginCommand {
4331                    name: CommandName::OpenPluginPaneInNewTab as i32,
4332                    payload: Some(Payload::OpenPluginPaneInNewTabPayload(
4333                        ProtobufOpenPluginPaneInNewTabPayload {
4334                            plugin_url,
4335                            configuration,
4336                            context,
4337                        },
4338                    )),
4339                })
4340            },
4341            PluginCommand::OpenEditorPaneInNewTab(file_to_open, context) => {
4342                let context: Vec<_> = context
4343                    .into_iter()
4344                    .map(|(name, value)| ContextItem { name, value })
4345                    .collect();
4346                Ok(ProtobufPluginCommand {
4347                    name: CommandName::OpenEditorPaneInNewTab as i32,
4348                    payload: Some(Payload::OpenEditorPaneInNewTabPayload(OpenFilePayload {
4349                        file_to_open: Some(file_to_open.try_into()?),
4350                        floating_pane_coordinates: None,
4351                        context,
4352                    })),
4353                })
4354            },
4355            PluginCommand::OpenCommandPaneInPlaceOfPaneId(
4356                pane_id,
4357                command_to_run,
4358                close_replaced_pane,
4359                context,
4360            ) => {
4361                let context: Vec<_> = context
4362                    .into_iter()
4363                    .map(|(name, value)| ContextItem { name, value })
4364                    .collect();
4365                Ok(ProtobufPluginCommand {
4366                    name: CommandName::OpenCommandPaneInPlaceOfPaneId as i32,
4367                    payload: Some(Payload::OpenCommandPaneInPlaceOfPaneIdPayload(
4368                        OpenCommandPaneInPlaceOfPaneIdPayload {
4369                            pane_id_to_replace: Some(pane_id.try_into()?),
4370                            command_to_run: Some(command_to_run.try_into()?),
4371                            close_replaced_pane,
4372                            context,
4373                        },
4374                    )),
4375                })
4376            },
4377            PluginCommand::OpenTerminalPaneInPlaceOfPaneId(pane_id, cwd, close_replaced_pane) => {
4378                Ok(ProtobufPluginCommand {
4379                    name: CommandName::OpenTerminalPaneInPlaceOfPaneId as i32,
4380                    payload: Some(Payload::OpenTerminalPaneInPlaceOfPaneIdPayload(
4381                        OpenTerminalPaneInPlaceOfPaneIdPayload {
4382                            pane_id_to_replace: Some(pane_id.try_into()?),
4383                            cwd: Some(cwd.try_into()?),
4384                            close_replaced_pane,
4385                        },
4386                    )),
4387                })
4388            },
4389            PluginCommand::OpenEditPaneInPlaceOfPaneId(
4390                pane_id,
4391                file_to_open,
4392                close_replaced_pane,
4393                context,
4394            ) => {
4395                let context: Vec<_> = context
4396                    .into_iter()
4397                    .map(|(name, value)| ContextItem { name, value })
4398                    .collect();
4399                Ok(ProtobufPluginCommand {
4400                    name: CommandName::OpenEditPaneInPlaceOfPaneId as i32,
4401                    payload: Some(Payload::OpenEditPaneInPlaceOfPaneIdPayload(
4402                        OpenEditPaneInPlaceOfPaneIdPayload {
4403                            pane_id_to_replace: Some(pane_id.try_into()?),
4404                            file_to_open: Some(file_to_open.try_into()?),
4405                            close_replaced_pane,
4406                            context,
4407                        },
4408                    )),
4409                })
4410            },
4411            PluginCommand::HideFloatingPanes { tab_id } => Ok(ProtobufPluginCommand {
4412                name: CommandName::HideFloatingPanes as i32,
4413                payload: Some(Payload::HideFloatingPanesPayload(
4414                    ProtobufHideFloatingPanesPayload {
4415                        tab_id: tab_id.map(|id| id as u32),
4416                    },
4417                )),
4418            }),
4419            PluginCommand::ShowFloatingPanes { tab_id } => Ok(ProtobufPluginCommand {
4420                name: CommandName::ShowFloatingPanes as i32,
4421                payload: Some(Payload::ShowFloatingPanesPayload(
4422                    ProtobufShowFloatingPanesPayload {
4423                        tab_id: tab_id.map(|id| id as u32),
4424                    },
4425                )),
4426            }),
4427            PluginCommand::SetPaneColor(pane_id, fg, bg) => Ok(ProtobufPluginCommand {
4428                name: CommandName::SetPaneColor as i32,
4429                payload: Some(Payload::SetPaneColorPayload(SetPaneColorPayload {
4430                    pane_id: Some(pane_id.try_into()?),
4431                    fg,
4432                    bg,
4433                })),
4434            }),
4435            PluginCommand::SetPaneRegexHighlights(pane_id, highlights) => {
4436                Ok(ProtobufPluginCommand {
4437                    name: CommandName::SetPaneRegexHighlights as i32,
4438                    payload: Some(Payload::SetPaneRegexHighlightsPayload(
4439                        SetPaneRegexHighlightsPayload {
4440                            pane_id: pane_id.try_into().ok(),
4441                            highlights: highlights
4442                                .into_iter()
4443                                .map(|h| {
4444                                    let style_variant = match h.style {
4445                                        HighlightStyle::Emphasis0 => {
4446                                            ProtobufHighlightStyleVariant::Emphasis0(true)
4447                                        },
4448                                        HighlightStyle::Emphasis1 => {
4449                                            ProtobufHighlightStyleVariant::Emphasis1(true)
4450                                        },
4451                                        HighlightStyle::Emphasis2 => {
4452                                            ProtobufHighlightStyleVariant::Emphasis2(true)
4453                                        },
4454                                        HighlightStyle::Emphasis3 => {
4455                                            ProtobufHighlightStyleVariant::Emphasis3(true)
4456                                        },
4457                                        HighlightStyle::CustomRgb { fg, bg } => {
4458                                            ProtobufHighlightStyleVariant::CustomRgb(
4459                                                ProtobufCustomRgbHighlight {
4460                                                    fg_r: fg.map(|(r, _, _)| r as u32),
4461                                                    fg_g: fg.map(|(_, g, _)| g as u32),
4462                                                    fg_b: fg.map(|(_, _, b)| b as u32),
4463                                                    bg_r: bg.map(|(r, _, _)| r as u32),
4464                                                    bg_g: bg.map(|(_, g, _)| g as u32),
4465                                                    bg_b: bg.map(|(_, _, b)| b as u32),
4466                                                },
4467                                            )
4468                                        },
4469                                        HighlightStyle::CustomIndex { fg, bg } => {
4470                                            ProtobufHighlightStyleVariant::CustomIndex(
4471                                                ProtobufCustomIndexHighlight {
4472                                                    fg: fg.map(|v| v as u32),
4473                                                    bg: bg.map(|v| v as u32),
4474                                                },
4475                                            )
4476                                        },
4477                                        HighlightStyle::BackgroundEmphasis0 => {
4478                                            ProtobufHighlightStyleVariant::BackgroundEmphasis0(true)
4479                                        },
4480                                        HighlightStyle::BackgroundEmphasis1 => {
4481                                            ProtobufHighlightStyleVariant::BackgroundEmphasis1(true)
4482                                        },
4483                                        HighlightStyle::BackgroundEmphasis2 => {
4484                                            ProtobufHighlightStyleVariant::BackgroundEmphasis2(true)
4485                                        },
4486                                        HighlightStyle::BackgroundEmphasis3 => {
4487                                            ProtobufHighlightStyleVariant::BackgroundEmphasis3(true)
4488                                        },
4489                                        HighlightStyle::None => {
4490                                            ProtobufHighlightStyleVariant::None(true)
4491                                        },
4492                                    };
4493                                    ProtobufRegexHighlight {
4494                                        pattern: h.pattern,
4495                                        style: Some(ProtobufHighlightStyle {
4496                                            style: Some(style_variant),
4497                                        }),
4498                                        context: h
4499                                            .context
4500                                            .into_iter()
4501                                            .map(|(name, value)| ContextItem { name, value })
4502                                            .collect(),
4503                                        on_hover: h.on_hover,
4504                                        bold: h.bold,
4505                                        italic: h.italic,
4506                                        underline: h.underline,
4507                                        tooltip_text: h.tooltip_text,
4508                                        layer: match h.layer {
4509                                            HighlightLayer::Hint => {
4510                                                ProtobufHighlightLayer::Hint as i32
4511                                            },
4512                                            HighlightLayer::Tool => {
4513                                                ProtobufHighlightLayer::Tool as i32
4514                                            },
4515                                            HighlightLayer::ActionFeedback => {
4516                                                ProtobufHighlightLayer::ActionFeedback as i32
4517                                            },
4518                                        },
4519                                    }
4520                                })
4521                                .collect(),
4522                        },
4523                    )),
4524                })
4525            },
4526            PluginCommand::ClearPaneHighlights(pane_id) => Ok(ProtobufPluginCommand {
4527                name: CommandName::ClearPaneHighlights as i32,
4528                payload: Some(Payload::ClearPaneHighlightsPayload(
4529                    ClearPaneHighlightsPayload {
4530                        pane_id: pane_id.try_into().ok(),
4531                    },
4532                )),
4533            }),
4534            PluginCommand::OpenPluginPaneFloating {
4535                plugin_url,
4536                configuration,
4537                floating_pane_coordinates,
4538                context,
4539            } => {
4540                let context: Vec<_> = context
4541                    .into_iter()
4542                    .map(|(name, value)| ContextItem { name, value })
4543                    .collect();
4544                let configuration: std::collections::HashMap<String, String> =
4545                    configuration.into_iter().collect();
4546                Ok(ProtobufPluginCommand {
4547                    name: CommandName::OpenPluginPaneFloating as i32,
4548                    payload: Some(Payload::OpenPluginPaneFloatingPayload(
4549                        OpenPluginPaneFloatingPayload {
4550                            plugin_url,
4551                            configuration,
4552                            floating_pane_coordinates: floating_pane_coordinates.map(|f| f.into()),
4553                            context,
4554                        },
4555                    )),
4556                })
4557            },
4558        }
4559    }
4560}
4561
4562// Conversion implementations for tab creation response types
4563use crate::data::{
4564    BreakPanesToNewTabResponse, BreakPanesToTabWithIdResponse, BreakPanesToTabWithIndexResponse,
4565    FocusOrCreateTabResponse, NewTabResponse, NewTabUnfocusedResponse, NewTabsResponse,
4566    NewTiledPaneInTabResponse, OpenCommandPaneBackgroundResponse,
4567    OpenCommandPaneFloatingNearPluginResponse, OpenCommandPaneFloatingResponse,
4568    OpenCommandPaneInPlaceOfPaneIdResponse, OpenCommandPaneInPlaceOfPluginResponse,
4569    OpenCommandPaneInPlaceResponse, OpenCommandPaneNearPluginResponse, OpenCommandPaneResponse,
4570    OpenEditPaneInPlaceOfPaneIdResponse, OpenFileFloatingNearPluginResponse,
4571    OpenFileFloatingResponse, OpenFileInPlaceOfPluginResponse, OpenFileInPlaceResponse,
4572    OpenFileNearPluginResponse, OpenFileResponse, OpenPaneInNewTabResponse,
4573    OpenPluginPaneFloatingResponse, OpenTerminalFloatingNearPluginResponse,
4574    OpenTerminalFloatingResponse, OpenTerminalInPlaceOfPluginResponse, OpenTerminalInPlaceResponse,
4575    OpenTerminalNearPluginResponse, OpenTerminalPaneInPlaceOfPaneIdResponse, OpenTerminalResponse,
4576};
4577
4578impl TryFrom<ProtobufNewTabResponse> for NewTabResponse {
4579    type Error = &'static str;
4580    fn try_from(protobuf: ProtobufNewTabResponse) -> Result<Self, Self::Error> {
4581        match protobuf.result {
4582            Some(new_tab_response::Result::TabId(id)) => Ok(Some(id as usize)),
4583            Some(new_tab_response::Result::None(_)) | None => Ok(None),
4584        }
4585    }
4586}
4587
4588impl From<NewTabResponse> for ProtobufNewTabResponse {
4589    fn from(response: NewTabResponse) -> Self {
4590        match response {
4591            Some(tab_id) => ProtobufNewTabResponse {
4592                result: Some(new_tab_response::Result::TabId(tab_id as u64)),
4593            },
4594            None => ProtobufNewTabResponse {
4595                result: Some(new_tab_response::Result::None(true)),
4596            },
4597        }
4598    }
4599}
4600
4601impl TryFrom<ProtobufNewTabUnfocusedResponse> for NewTabUnfocusedResponse {
4602    type Error = &'static str;
4603    fn try_from(protobuf: ProtobufNewTabUnfocusedResponse) -> Result<Self, Self::Error> {
4604        match protobuf.result {
4605            Some(new_tab_unfocused_response::Result::TabId(id)) => Ok(Some(id as usize)),
4606            Some(new_tab_unfocused_response::Result::None(_)) | None => Ok(None),
4607        }
4608    }
4609}
4610
4611impl From<NewTabUnfocusedResponse> for ProtobufNewTabUnfocusedResponse {
4612    fn from(response: NewTabUnfocusedResponse) -> Self {
4613        match response {
4614            Some(tab_id) => ProtobufNewTabUnfocusedResponse {
4615                result: Some(new_tab_unfocused_response::Result::TabId(tab_id as u64)),
4616            },
4617            None => ProtobufNewTabUnfocusedResponse {
4618                result: Some(new_tab_unfocused_response::Result::None(true)),
4619            },
4620        }
4621    }
4622}
4623
4624impl TryFrom<ProtobufNewTiledPaneInTabResponse> for NewTiledPaneInTabResponse {
4625    type Error = &'static str;
4626    fn try_from(protobuf: ProtobufNewTiledPaneInTabResponse) -> Result<Self, Self::Error> {
4627        match protobuf.pane_id {
4628            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4629            None => Ok(None),
4630        }
4631    }
4632}
4633
4634impl From<NewTiledPaneInTabResponse> for ProtobufNewTiledPaneInTabResponse {
4635    fn from(response: NewTiledPaneInTabResponse) -> Self {
4636        ProtobufNewTiledPaneInTabResponse {
4637            pane_id: response.map(|p| p.try_into().unwrap()),
4638        }
4639    }
4640}
4641
4642impl TryFrom<ProtobufNewTabsResponse> for NewTabsResponse {
4643    type Error = &'static str;
4644    fn try_from(protobuf: ProtobufNewTabsResponse) -> Result<Self, Self::Error> {
4645        Ok(protobuf.tab_ids.into_iter().map(|id| id as usize).collect())
4646    }
4647}
4648
4649impl From<NewTabsResponse> for ProtobufNewTabsResponse {
4650    fn from(response: NewTabsResponse) -> Self {
4651        ProtobufNewTabsResponse {
4652            tab_ids: response.into_iter().map(|id| id as u64).collect(),
4653        }
4654    }
4655}
4656
4657impl TryFrom<ProtobufFocusOrCreateTabResponse> for FocusOrCreateTabResponse {
4658    type Error = &'static str;
4659    fn try_from(protobuf: ProtobufFocusOrCreateTabResponse) -> Result<Self, Self::Error> {
4660        match protobuf.result {
4661            Some(focus_or_create_tab_response::Result::TabId(id)) => Ok(Some(id as usize)),
4662            Some(focus_or_create_tab_response::Result::None(_)) | None => Ok(None),
4663        }
4664    }
4665}
4666
4667impl From<FocusOrCreateTabResponse> for ProtobufFocusOrCreateTabResponse {
4668    fn from(response: FocusOrCreateTabResponse) -> Self {
4669        match response {
4670            Some(tab_id) => ProtobufFocusOrCreateTabResponse {
4671                result: Some(focus_or_create_tab_response::Result::TabId(tab_id as u64)),
4672            },
4673            None => ProtobufFocusOrCreateTabResponse {
4674                result: Some(focus_or_create_tab_response::Result::None(true)),
4675            },
4676        }
4677    }
4678}
4679
4680impl TryFrom<ProtobufBreakPanesToNewTabResponse> for BreakPanesToNewTabResponse {
4681    type Error = &'static str;
4682    fn try_from(protobuf: ProtobufBreakPanesToNewTabResponse) -> Result<Self, Self::Error> {
4683        match protobuf.result {
4684            Some(break_panes_to_new_tab_response::Result::TabId(id)) => Ok(Some(id as usize)),
4685            Some(break_panes_to_new_tab_response::Result::None(_)) | None => Ok(None),
4686        }
4687    }
4688}
4689
4690impl From<BreakPanesToNewTabResponse> for ProtobufBreakPanesToNewTabResponse {
4691    fn from(response: BreakPanesToNewTabResponse) -> Self {
4692        match response {
4693            Some(tab_id) => ProtobufBreakPanesToNewTabResponse {
4694                result: Some(break_panes_to_new_tab_response::Result::TabId(
4695                    tab_id as u64,
4696                )),
4697            },
4698            None => ProtobufBreakPanesToNewTabResponse {
4699                result: Some(break_panes_to_new_tab_response::Result::None(true)),
4700            },
4701        }
4702    }
4703}
4704
4705impl TryFrom<ProtobufBreakPanesToTabWithIndexResponse> for BreakPanesToTabWithIndexResponse {
4706    type Error = &'static str;
4707    fn try_from(protobuf: ProtobufBreakPanesToTabWithIndexResponse) -> Result<Self, Self::Error> {
4708        match protobuf.result {
4709            Some(break_panes_to_tab_with_index_response::Result::TabId(id)) => {
4710                Ok(Some(id as usize))
4711            },
4712            Some(break_panes_to_tab_with_index_response::Result::None(_)) | None => Ok(None),
4713        }
4714    }
4715}
4716
4717impl From<BreakPanesToTabWithIndexResponse> for ProtobufBreakPanesToTabWithIndexResponse {
4718    fn from(response: BreakPanesToTabWithIndexResponse) -> Self {
4719        match response {
4720            Some(tab_id) => ProtobufBreakPanesToTabWithIndexResponse {
4721                result: Some(break_panes_to_tab_with_index_response::Result::TabId(
4722                    tab_id as u64,
4723                )),
4724            },
4725            None => ProtobufBreakPanesToTabWithIndexResponse {
4726                result: Some(break_panes_to_tab_with_index_response::Result::None(true)),
4727            },
4728        }
4729    }
4730}
4731
4732impl TryFrom<ProtobufBreakPanesToTabWithIdResponse> for BreakPanesToTabWithIdResponse {
4733    type Error = &'static str;
4734    fn try_from(protobuf: ProtobufBreakPanesToTabWithIdResponse) -> Result<Self, Self::Error> {
4735        match protobuf.result {
4736            Some(break_panes_to_tab_with_id_response::Result::TabId(id)) => Ok(Some(id as usize)),
4737            Some(break_panes_to_tab_with_id_response::Result::None(_)) | None => Ok(None),
4738        }
4739    }
4740}
4741
4742impl From<BreakPanesToTabWithIdResponse> for ProtobufBreakPanesToTabWithIdResponse {
4743    fn from(response: BreakPanesToTabWithIdResponse) -> Self {
4744        match response {
4745            Some(tab_id) => ProtobufBreakPanesToTabWithIdResponse {
4746                result: Some(break_panes_to_tab_with_id_response::Result::TabId(
4747                    tab_id as u64,
4748                )),
4749            },
4750            None => ProtobufBreakPanesToTabWithIdResponse {
4751                result: Some(break_panes_to_tab_with_id_response::Result::None(true)),
4752            },
4753        }
4754    }
4755}
4756
4757// Pane-creating command response conversions
4758
4759impl TryFrom<ProtobufOpenFileResponse> for OpenFileResponse {
4760    type Error = &'static str;
4761    fn try_from(protobuf: ProtobufOpenFileResponse) -> Result<Self, Self::Error> {
4762        match protobuf.pane_id {
4763            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4764            None => Ok(None),
4765        }
4766    }
4767}
4768
4769impl From<OpenFileResponse> for ProtobufOpenFileResponse {
4770    fn from(response: OpenFileResponse) -> Self {
4771        ProtobufOpenFileResponse {
4772            pane_id: response.map(|p| p.try_into().unwrap()),
4773        }
4774    }
4775}
4776
4777impl TryFrom<ProtobufOpenFileFloatingResponse> for OpenFileFloatingResponse {
4778    type Error = &'static str;
4779    fn try_from(protobuf: ProtobufOpenFileFloatingResponse) -> Result<Self, Self::Error> {
4780        match protobuf.pane_id {
4781            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4782            None => Ok(None),
4783        }
4784    }
4785}
4786
4787impl From<OpenFileFloatingResponse> for ProtobufOpenFileFloatingResponse {
4788    fn from(response: OpenFileFloatingResponse) -> Self {
4789        ProtobufOpenFileFloatingResponse {
4790            pane_id: response.map(|p| p.try_into().unwrap()),
4791        }
4792    }
4793}
4794
4795impl TryFrom<ProtobufOpenFileInPlaceResponse> for OpenFileInPlaceResponse {
4796    type Error = &'static str;
4797    fn try_from(protobuf: ProtobufOpenFileInPlaceResponse) -> Result<Self, Self::Error> {
4798        match protobuf.pane_id {
4799            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4800            None => Ok(None),
4801        }
4802    }
4803}
4804
4805impl From<OpenFileInPlaceResponse> for ProtobufOpenFileInPlaceResponse {
4806    fn from(response: OpenFileInPlaceResponse) -> Self {
4807        ProtobufOpenFileInPlaceResponse {
4808            pane_id: response.map(|p| p.try_into().unwrap()),
4809        }
4810    }
4811}
4812
4813impl TryFrom<ProtobufOpenFileNearPluginResponse> for OpenFileNearPluginResponse {
4814    type Error = &'static str;
4815    fn try_from(protobuf: ProtobufOpenFileNearPluginResponse) -> Result<Self, Self::Error> {
4816        match protobuf.pane_id {
4817            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4818            None => Ok(None),
4819        }
4820    }
4821}
4822
4823impl From<OpenFileNearPluginResponse> for ProtobufOpenFileNearPluginResponse {
4824    fn from(response: OpenFileNearPluginResponse) -> Self {
4825        ProtobufOpenFileNearPluginResponse {
4826            pane_id: response.map(|p| p.try_into().unwrap()),
4827        }
4828    }
4829}
4830
4831impl TryFrom<ProtobufOpenFileFloatingNearPluginResponse> for OpenFileFloatingNearPluginResponse {
4832    type Error = &'static str;
4833    fn try_from(protobuf: ProtobufOpenFileFloatingNearPluginResponse) -> Result<Self, Self::Error> {
4834        match protobuf.pane_id {
4835            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4836            None => Ok(None),
4837        }
4838    }
4839}
4840
4841impl From<OpenFileFloatingNearPluginResponse> for ProtobufOpenFileFloatingNearPluginResponse {
4842    fn from(response: OpenFileFloatingNearPluginResponse) -> Self {
4843        ProtobufOpenFileFloatingNearPluginResponse {
4844            pane_id: response.map(|p| p.try_into().unwrap()),
4845        }
4846    }
4847}
4848
4849impl TryFrom<ProtobufOpenFileInPlaceOfPluginResponse> for OpenFileInPlaceOfPluginResponse {
4850    type Error = &'static str;
4851    fn try_from(protobuf: ProtobufOpenFileInPlaceOfPluginResponse) -> Result<Self, Self::Error> {
4852        match protobuf.pane_id {
4853            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4854            None => Ok(None),
4855        }
4856    }
4857}
4858
4859impl From<OpenFileInPlaceOfPluginResponse> for ProtobufOpenFileInPlaceOfPluginResponse {
4860    fn from(response: OpenFileInPlaceOfPluginResponse) -> Self {
4861        ProtobufOpenFileInPlaceOfPluginResponse {
4862            pane_id: response.map(|p| p.try_into().unwrap()),
4863        }
4864    }
4865}
4866
4867impl TryFrom<ProtobufOpenTerminalResponse> for OpenTerminalResponse {
4868    type Error = &'static str;
4869    fn try_from(protobuf: ProtobufOpenTerminalResponse) -> Result<Self, Self::Error> {
4870        match protobuf.pane_id {
4871            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4872            None => Ok(None),
4873        }
4874    }
4875}
4876
4877impl From<OpenTerminalResponse> for ProtobufOpenTerminalResponse {
4878    fn from(response: OpenTerminalResponse) -> Self {
4879        ProtobufOpenTerminalResponse {
4880            pane_id: response.map(|p| p.try_into().unwrap()),
4881        }
4882    }
4883}
4884
4885impl TryFrom<ProtobufOpenTerminalFloatingResponse> for OpenTerminalFloatingResponse {
4886    type Error = &'static str;
4887    fn try_from(protobuf: ProtobufOpenTerminalFloatingResponse) -> Result<Self, Self::Error> {
4888        match protobuf.pane_id {
4889            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4890            None => Ok(None),
4891        }
4892    }
4893}
4894
4895impl From<OpenTerminalFloatingResponse> for ProtobufOpenTerminalFloatingResponse {
4896    fn from(response: OpenTerminalFloatingResponse) -> Self {
4897        ProtobufOpenTerminalFloatingResponse {
4898            pane_id: response.map(|p| p.try_into().unwrap()),
4899        }
4900    }
4901}
4902
4903impl TryFrom<ProtobufOpenTerminalInPlaceResponse> for OpenTerminalInPlaceResponse {
4904    type Error = &'static str;
4905    fn try_from(protobuf: ProtobufOpenTerminalInPlaceResponse) -> Result<Self, Self::Error> {
4906        match protobuf.pane_id {
4907            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4908            None => Ok(None),
4909        }
4910    }
4911}
4912
4913impl From<OpenTerminalInPlaceResponse> for ProtobufOpenTerminalInPlaceResponse {
4914    fn from(response: OpenTerminalInPlaceResponse) -> Self {
4915        ProtobufOpenTerminalInPlaceResponse {
4916            pane_id: response.map(|p| p.try_into().unwrap()),
4917        }
4918    }
4919}
4920
4921impl TryFrom<ProtobufOpenTerminalNearPluginResponse> for OpenTerminalNearPluginResponse {
4922    type Error = &'static str;
4923    fn try_from(protobuf: ProtobufOpenTerminalNearPluginResponse) -> Result<Self, Self::Error> {
4924        match protobuf.pane_id {
4925            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4926            None => Ok(None),
4927        }
4928    }
4929}
4930
4931impl From<OpenTerminalNearPluginResponse> for ProtobufOpenTerminalNearPluginResponse {
4932    fn from(response: OpenTerminalNearPluginResponse) -> Self {
4933        ProtobufOpenTerminalNearPluginResponse {
4934            pane_id: response.map(|p| p.try_into().unwrap()),
4935        }
4936    }
4937}
4938
4939impl TryFrom<ProtobufOpenTerminalFloatingNearPluginResponse>
4940    for OpenTerminalFloatingNearPluginResponse
4941{
4942    type Error = &'static str;
4943    fn try_from(
4944        protobuf: ProtobufOpenTerminalFloatingNearPluginResponse,
4945    ) -> Result<Self, Self::Error> {
4946        match protobuf.pane_id {
4947            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4948            None => Ok(None),
4949        }
4950    }
4951}
4952
4953impl From<OpenTerminalFloatingNearPluginResponse>
4954    for ProtobufOpenTerminalFloatingNearPluginResponse
4955{
4956    fn from(response: OpenTerminalFloatingNearPluginResponse) -> Self {
4957        ProtobufOpenTerminalFloatingNearPluginResponse {
4958            pane_id: response.map(|p| p.try_into().unwrap()),
4959        }
4960    }
4961}
4962
4963impl TryFrom<ProtobufOpenTerminalInPlaceOfPluginResponse> for OpenTerminalInPlaceOfPluginResponse {
4964    type Error = &'static str;
4965    fn try_from(
4966        protobuf: ProtobufOpenTerminalInPlaceOfPluginResponse,
4967    ) -> Result<Self, Self::Error> {
4968        match protobuf.pane_id {
4969            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4970            None => Ok(None),
4971        }
4972    }
4973}
4974
4975impl From<OpenTerminalInPlaceOfPluginResponse> for ProtobufOpenTerminalInPlaceOfPluginResponse {
4976    fn from(response: OpenTerminalInPlaceOfPluginResponse) -> Self {
4977        ProtobufOpenTerminalInPlaceOfPluginResponse {
4978            pane_id: response.map(|p| p.try_into().unwrap()),
4979        }
4980    }
4981}
4982
4983impl TryFrom<ProtobufOpenCommandPaneResponse> for OpenCommandPaneResponse {
4984    type Error = &'static str;
4985    fn try_from(protobuf: ProtobufOpenCommandPaneResponse) -> Result<Self, Self::Error> {
4986        match protobuf.pane_id {
4987            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
4988            None => Ok(None),
4989        }
4990    }
4991}
4992
4993impl From<OpenCommandPaneResponse> for ProtobufOpenCommandPaneResponse {
4994    fn from(response: OpenCommandPaneResponse) -> Self {
4995        ProtobufOpenCommandPaneResponse {
4996            pane_id: response.map(|p| p.try_into().unwrap()),
4997        }
4998    }
4999}
5000
5001impl TryFrom<ProtobufOpenCommandPaneFloatingResponse> for OpenCommandPaneFloatingResponse {
5002    type Error = &'static str;
5003    fn try_from(protobuf: ProtobufOpenCommandPaneFloatingResponse) -> Result<Self, Self::Error> {
5004        match protobuf.pane_id {
5005            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5006            None => Ok(None),
5007        }
5008    }
5009}
5010
5011impl From<OpenCommandPaneFloatingResponse> for ProtobufOpenCommandPaneFloatingResponse {
5012    fn from(response: OpenCommandPaneFloatingResponse) -> Self {
5013        ProtobufOpenCommandPaneFloatingResponse {
5014            pane_id: response.map(|p| p.try_into().unwrap()),
5015        }
5016    }
5017}
5018
5019impl TryFrom<ProtobufOpenCommandPaneInPlaceResponse> for OpenCommandPaneInPlaceResponse {
5020    type Error = &'static str;
5021    fn try_from(protobuf: ProtobufOpenCommandPaneInPlaceResponse) -> Result<Self, Self::Error> {
5022        match protobuf.pane_id {
5023            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5024            None => Ok(None),
5025        }
5026    }
5027}
5028
5029impl From<OpenCommandPaneInPlaceResponse> for ProtobufOpenCommandPaneInPlaceResponse {
5030    fn from(response: OpenCommandPaneInPlaceResponse) -> Self {
5031        ProtobufOpenCommandPaneInPlaceResponse {
5032            pane_id: response.map(|p| p.try_into().unwrap()),
5033        }
5034    }
5035}
5036
5037impl TryFrom<ProtobufOpenCommandPaneNearPluginResponse> for OpenCommandPaneNearPluginResponse {
5038    type Error = &'static str;
5039    fn try_from(protobuf: ProtobufOpenCommandPaneNearPluginResponse) -> Result<Self, Self::Error> {
5040        match protobuf.pane_id {
5041            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5042            None => Ok(None),
5043        }
5044    }
5045}
5046
5047impl From<OpenCommandPaneNearPluginResponse> for ProtobufOpenCommandPaneNearPluginResponse {
5048    fn from(response: OpenCommandPaneNearPluginResponse) -> Self {
5049        ProtobufOpenCommandPaneNearPluginResponse {
5050            pane_id: response.map(|p| p.try_into().unwrap()),
5051        }
5052    }
5053}
5054
5055impl TryFrom<ProtobufOpenCommandPaneFloatingNearPluginResponse>
5056    for OpenCommandPaneFloatingNearPluginResponse
5057{
5058    type Error = &'static str;
5059    fn try_from(
5060        protobuf: ProtobufOpenCommandPaneFloatingNearPluginResponse,
5061    ) -> Result<Self, Self::Error> {
5062        match protobuf.pane_id {
5063            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5064            None => Ok(None),
5065        }
5066    }
5067}
5068
5069impl From<OpenCommandPaneFloatingNearPluginResponse>
5070    for ProtobufOpenCommandPaneFloatingNearPluginResponse
5071{
5072    fn from(response: OpenCommandPaneFloatingNearPluginResponse) -> Self {
5073        ProtobufOpenCommandPaneFloatingNearPluginResponse {
5074            pane_id: response.map(|p| p.try_into().unwrap()),
5075        }
5076    }
5077}
5078
5079impl TryFrom<ProtobufOpenCommandPaneInPlaceOfPluginResponse>
5080    for OpenCommandPaneInPlaceOfPluginResponse
5081{
5082    type Error = &'static str;
5083    fn try_from(
5084        protobuf: ProtobufOpenCommandPaneInPlaceOfPluginResponse,
5085    ) -> Result<Self, Self::Error> {
5086        match protobuf.pane_id {
5087            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5088            None => Ok(None),
5089        }
5090    }
5091}
5092
5093impl From<OpenCommandPaneInPlaceOfPluginResponse>
5094    for ProtobufOpenCommandPaneInPlaceOfPluginResponse
5095{
5096    fn from(response: OpenCommandPaneInPlaceOfPluginResponse) -> Self {
5097        ProtobufOpenCommandPaneInPlaceOfPluginResponse {
5098            pane_id: response.map(|p| p.try_into().unwrap()),
5099        }
5100    }
5101}
5102
5103impl TryFrom<ProtobufOpenCommandPaneBackgroundResponse> for OpenCommandPaneBackgroundResponse {
5104    type Error = &'static str;
5105    fn try_from(protobuf: ProtobufOpenCommandPaneBackgroundResponse) -> Result<Self, Self::Error> {
5106        match protobuf.pane_id {
5107            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5108            None => Ok(None),
5109        }
5110    }
5111}
5112
5113impl From<OpenCommandPaneBackgroundResponse> for ProtobufOpenCommandPaneBackgroundResponse {
5114    fn from(response: OpenCommandPaneBackgroundResponse) -> Self {
5115        ProtobufOpenCommandPaneBackgroundResponse {
5116            pane_id: response.map(|p| p.try_into().unwrap()),
5117        }
5118    }
5119}
5120
5121impl TryFrom<ProtobufOpenPaneInNewTabResponse> for OpenPaneInNewTabResponse {
5122    type Error = &'static str;
5123    fn try_from(protobuf: ProtobufOpenPaneInNewTabResponse) -> Result<Self, Self::Error> {
5124        let tab_id = protobuf.tab_id.map(|id| id as usize);
5125        let pane_id = match protobuf.pane_id {
5126            Some(pane_id) => Some(pane_id.try_into()?),
5127            None => None,
5128        };
5129        Ok(OpenPaneInNewTabResponse { tab_id, pane_id })
5130    }
5131}
5132
5133impl From<OpenPaneInNewTabResponse> for ProtobufOpenPaneInNewTabResponse {
5134    fn from(response: OpenPaneInNewTabResponse) -> Self {
5135        ProtobufOpenPaneInNewTabResponse {
5136            tab_id: response.tab_id.map(|id| id as u64),
5137            pane_id: response.pane_id.map(|p| p.try_into().unwrap()),
5138        }
5139    }
5140}
5141
5142impl TryFrom<ProtobufOpenCommandPaneInPlaceOfPaneIdResponse>
5143    for OpenCommandPaneInPlaceOfPaneIdResponse
5144{
5145    type Error = &'static str;
5146    fn try_from(
5147        protobuf: ProtobufOpenCommandPaneInPlaceOfPaneIdResponse,
5148    ) -> Result<Self, Self::Error> {
5149        match protobuf.pane_id {
5150            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5151            None => Ok(None),
5152        }
5153    }
5154}
5155
5156impl From<OpenCommandPaneInPlaceOfPaneIdResponse>
5157    for ProtobufOpenCommandPaneInPlaceOfPaneIdResponse
5158{
5159    fn from(response: OpenCommandPaneInPlaceOfPaneIdResponse) -> Self {
5160        ProtobufOpenCommandPaneInPlaceOfPaneIdResponse {
5161            pane_id: response.map(|p| p.try_into().unwrap()),
5162        }
5163    }
5164}
5165
5166impl TryFrom<ProtobufOpenTerminalPaneInPlaceOfPaneIdResponse>
5167    for OpenTerminalPaneInPlaceOfPaneIdResponse
5168{
5169    type Error = &'static str;
5170    fn try_from(
5171        protobuf: ProtobufOpenTerminalPaneInPlaceOfPaneIdResponse,
5172    ) -> Result<Self, Self::Error> {
5173        match protobuf.pane_id {
5174            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5175            None => Ok(None),
5176        }
5177    }
5178}
5179
5180impl From<OpenTerminalPaneInPlaceOfPaneIdResponse>
5181    for ProtobufOpenTerminalPaneInPlaceOfPaneIdResponse
5182{
5183    fn from(response: OpenTerminalPaneInPlaceOfPaneIdResponse) -> Self {
5184        ProtobufOpenTerminalPaneInPlaceOfPaneIdResponse {
5185            pane_id: response.map(|p| p.try_into().unwrap()),
5186        }
5187    }
5188}
5189
5190impl TryFrom<ProtobufOpenEditPaneInPlaceOfPaneIdResponse> for OpenEditPaneInPlaceOfPaneIdResponse {
5191    type Error = &'static str;
5192    fn try_from(
5193        protobuf: ProtobufOpenEditPaneInPlaceOfPaneIdResponse,
5194    ) -> Result<Self, Self::Error> {
5195        match protobuf.pane_id {
5196            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5197            None => Ok(None),
5198        }
5199    }
5200}
5201
5202impl From<OpenEditPaneInPlaceOfPaneIdResponse> for ProtobufOpenEditPaneInPlaceOfPaneIdResponse {
5203    fn from(response: OpenEditPaneInPlaceOfPaneIdResponse) -> Self {
5204        ProtobufOpenEditPaneInPlaceOfPaneIdResponse {
5205            pane_id: response.map(|p| p.try_into().unwrap()),
5206        }
5207    }
5208}
5209
5210impl TryFrom<ProtobufOpenPluginPaneFloatingResponse> for OpenPluginPaneFloatingResponse {
5211    type Error = &'static str;
5212    fn try_from(protobuf: ProtobufOpenPluginPaneFloatingResponse) -> Result<Self, Self::Error> {
5213        match protobuf.pane_id {
5214            Some(pane_id) => Ok(Some(pane_id.try_into()?)),
5215            None => Ok(None),
5216        }
5217    }
5218}
5219
5220impl From<OpenPluginPaneFloatingResponse> for ProtobufOpenPluginPaneFloatingResponse {
5221    fn from(response: OpenPluginPaneFloatingResponse) -> Self {
5222        ProtobufOpenPluginPaneFloatingResponse {
5223            pane_id: response.map(|p| p.try_into().unwrap()),
5224        }
5225    }
5226}
5227
5228#[cfg(test)]
5229mod tests {
5230    use super::*;
5231    use crate::data::PluginCommand;
5232
5233    #[test]
5234    fn set_pane_frame_style_protobuf_round_trip() {
5235        use crate::input::options::PaneFrameStyle;
5236        for style in [
5237            PaneFrameStyle::Full,
5238            PaneFrameStyle::Titles,
5239            PaneFrameStyle::None,
5240        ] {
5241            let original = PluginCommand::SetPaneFrameStyle(style);
5242            let protobuf: ProtobufPluginCommand = original.try_into().expect("encode");
5243            let decoded: PluginCommand = protobuf.try_into().expect("decode");
5244            match decoded {
5245                PluginCommand::SetPaneFrameStyle(decoded_style) => {
5246                    assert_eq!(decoded_style, style)
5247                },
5248                other => panic!("expected SetPaneFrameStyle, got {:?}", other),
5249            }
5250        }
5251    }
5252
5253    #[test]
5254    fn new_pane_protobuf_round_trip() {
5255        let original = PluginCommand::NewPane;
5256        let protobuf: ProtobufPluginCommand = original.try_into().expect("encode");
5257        let decoded: PluginCommand = protobuf.try_into().expect("decode");
5258        match decoded {
5259            PluginCommand::NewPane => {},
5260            other => panic!("expected NewPane, got {:?}", other),
5261        }
5262    }
5263
5264    #[test]
5265    fn toggle_floating_panes_focused_tab_protobuf_round_trip() {
5266        let original = PluginCommand::ToggleFloatingPanes { tab_id: None };
5267        let protobuf: ProtobufPluginCommand = original.try_into().expect("encode");
5268        let decoded: PluginCommand = protobuf.try_into().expect("decode");
5269        match decoded {
5270            PluginCommand::ToggleFloatingPanes { tab_id } => assert_eq!(tab_id, None),
5271            other => panic!("expected ToggleFloatingPanes, got {:?}", other),
5272        }
5273    }
5274
5275    #[test]
5276    fn toggle_floating_panes_with_tab_id_protobuf_round_trip() {
5277        let original = PluginCommand::ToggleFloatingPanes { tab_id: Some(2) };
5278        let protobuf: ProtobufPluginCommand = original.try_into().expect("encode");
5279        let decoded: PluginCommand = protobuf.try_into().expect("decode");
5280        match decoded {
5281            PluginCommand::ToggleFloatingPanes { tab_id } => assert_eq!(tab_id, Some(2)),
5282            other => panic!("expected ToggleFloatingPanes, got {:?}", other),
5283        }
5284    }
5285}