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