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