1pub use super::generated_api::api::{
2 action::{
3 action::OptionalPayload,
4 command_or_plugin::CommandOrPluginType,
5 pane_run::RunType,
6 run_plugin_location_data::LocationData,
7 run_plugin_or_alias::PluginType,
8 Action as ProtobufAction,
9 ActionName as ProtobufActionName,
10 AreFloatingPanesVisiblePayload,
11 BareKey as ProtobufBareKey,
12 CommandOrPlugin as ProtobufCommandOrPlugin,
14 DumpScreenPayload,
15 EditFilePayload,
16 FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates,
17 FloatingPaneLayout as ProtobufFloatingPaneLayout,
18 FloatingPlacement as ProtobufFloatingPlacement,
19 GoToTabNamePayload,
20 HideFloatingPanesPayload,
21 IdAndName,
22 InPlaceConfig as ProtobufInPlaceConfig,
23 KeyModifier as ProtobufKeyModifier,
24 KeyWithModifier as ProtobufKeyWithModifier,
25 LaunchOrFocusPluginPayload,
26 LayoutConstraint as ProtobufLayoutConstraint,
27 LayoutConstraintFloatingPair as ProtobufLayoutConstraintFloatingPair,
28 LayoutConstraintTiledPair as ProtobufLayoutConstraintTiledPair,
29 LayoutConstraintWithValue as ProtobufLayoutConstraintWithValue,
30 MouseEventPayload as ProtobufMouseEventPayload,
31 MovePanePayload,
32 MoveTabDirection as ProtobufMoveTabDirection,
33 NameAndValue as ProtobufNameAndValue,
34 NewBlockingPanePayload,
35 NewFloatingPanePayload,
36 NewInPlacePanePayload,
37 NewPanePayload,
38 NewPanePlacement as ProtobufNewPanePlacement,
39 NewPluginPanePayload,
40 NewTabPayload,
41 NewTiledPanePayload,
42 OverrideLayoutPayload,
43 PaneId as ProtobufPaneId,
44 PaneIdAndShouldFloat,
45 PaneRun as ProtobufPaneRun,
46 PercentOrFixed as ProtobufPercentOrFixed,
47 PluginAlias as ProtobufPluginAlias,
48 PluginConfiguration as ProtobufPluginConfiguration,
49 PluginTag as ProtobufPluginTag,
50 PluginUserConfiguration as ProtobufPluginUserConfiguration,
51 Position as ProtobufPosition,
52 RunCommandAction as ProtobufRunCommandAction,
53 RunEditFileAction as ProtobufRunEditFileAction,
54 RunPlugin as ProtobufRunPlugin,
55 RunPluginLocation as ProtobufRunPluginLocation,
56 RunPluginLocationData as ProtobufRunPluginLocationData,
57 RunPluginOrAlias as ProtobufRunPluginOrAlias,
58 ScrollAtPayload,
59 SearchDirection as ProtobufSearchDirection,
60 SearchOption as ProtobufSearchOption,
61 SetPaneFrameStylePayload,
62 ShowFloatingPanesPayload,
63 SplitDirection as ProtobufSplitDirection,
64 SplitSize as ProtobufSplitSize,
65 StackedPlacement as ProtobufStackedPlacement,
66 SwapFloatingLayout as ProtobufSwapFloatingLayout,
67 SwapTiledLayout as ProtobufSwapTiledLayout,
68 SwitchToModePayload,
69 TabIdAndName,
70 TabLayoutInfo as ProtobufTabLayoutInfo,
71 TiledPaneLayout as ProtobufTiledPaneLayout,
72 TiledPlacement as ProtobufTiledPlacement,
73 UnblockCondition as ProtobufUnblockCondition,
74 WriteCharsPayload,
75 WritePayload,
76 },
77 input_mode::InputMode as ProtobufInputMode,
78 pane_frame_style::PaneFrameStyle as ProtobufPaneFrameStyle,
79 resize::{Resize as ProtobufResize, ResizeDirection as ProtobufResizeDirection},
80};
81use crate::data::{
82 CommandOrPlugin, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier,
83 NewPanePlacement, PaneId, PluginTag, ResizeStrategy, UnblockCondition,
84};
85use crate::errors::prelude::*;
86use crate::input::actions::Action;
87use crate::input::actions::{SearchDirection, SearchOption};
88use crate::input::command::{OpenFilePayload, RunCommandAction};
89use crate::input::layout::SplitSize;
90use crate::input::layout::{
91 FloatingPaneLayout, LayoutConstraint, PercentOrFixed, PluginAlias, PluginUserConfiguration,
92 Run, RunPlugin, RunPluginLocation, RunPluginOrAlias, SplitDirection, SwapFloatingLayout,
93 SwapTiledLayout, TabLayoutInfo, TiledPaneLayout,
94};
95use crate::input::mouse::{MouseEvent, MouseEventType};
96use crate::position::Position;
97
98use std::collections::BTreeMap;
99use std::convert::TryFrom;
100use std::path::PathBuf;
101
102impl TryFrom<ProtobufAction> for Action {
103 type Error = &'static str;
104 fn try_from(protobuf_action: ProtobufAction) -> Result<Self, &'static str> {
105 match ProtobufActionName::try_from(protobuf_action.name).ok() {
106 Some(ProtobufActionName::Quit) => match protobuf_action.optional_payload {
107 Some(_) => Err("The Quit Action should not have a payload"),
108 None => Ok(Action::Quit),
109 },
110 Some(ProtobufActionName::Write) => match protobuf_action.optional_payload {
111 Some(OptionalPayload::WritePayload(write_payload)) => {
112 let key_with_modifier = write_payload
113 .key_with_modifier
114 .and_then(|k| k.try_into().ok());
115 Ok(Action::Write {
116 key_with_modifier,
117 bytes: write_payload.bytes_to_write,
118 is_kitty_keyboard_protocol: write_payload.is_kitty_keyboard_protocol,
119 })
120 },
121 _ => Err("Wrong payload for Action::Write"),
122 },
123 Some(ProtobufActionName::WriteChars) => match protobuf_action.optional_payload {
124 Some(OptionalPayload::WriteCharsPayload(write_chars_payload)) => {
125 Ok(Action::WriteChars {
126 chars: write_chars_payload.chars,
127 })
128 },
129 _ => Err("Wrong payload for Action::WriteChars"),
130 },
131 Some(ProtobufActionName::SwitchToMode) => match protobuf_action.optional_payload {
132 Some(OptionalPayload::SwitchToModePayload(switch_to_mode_payload)) => {
133 let input_mode: InputMode =
134 ProtobufInputMode::try_from(switch_to_mode_payload.input_mode)
135 .ok()
136 .ok_or("Malformed input mode for SwitchToMode Action")?
137 .try_into()?;
138 Ok(Action::SwitchToMode { input_mode })
139 },
140 _ => Err("Wrong payload for Action::SwitchToModePayload"),
141 },
142 Some(ProtobufActionName::SwitchModeForAllClients) => {
143 match protobuf_action.optional_payload {
144 Some(OptionalPayload::SwitchModeForAllClientsPayload(
145 switch_to_mode_payload,
146 )) => {
147 let input_mode: InputMode =
148 ProtobufInputMode::try_from(switch_to_mode_payload.input_mode)
149 .ok()
150 .ok_or("Malformed input mode for SwitchToMode Action")?
151 .try_into()?;
152 Ok(Action::SwitchModeForAllClients { input_mode })
153 },
154 _ => Err("Wrong payload for Action::SwitchModeForAllClients"),
155 }
156 },
157 Some(ProtobufActionName::Resize) => match protobuf_action.optional_payload {
158 Some(OptionalPayload::ResizePayload(resize_payload)) => {
159 let resize_strategy: ResizeStrategy = resize_payload.try_into()?;
160 Ok(Action::Resize {
161 resize: resize_strategy.resize,
162 direction: resize_strategy.direction,
163 })
164 },
165 _ => Err("Wrong payload for Action::Resize"),
166 },
167 Some(ProtobufActionName::FocusNextPane) => match protobuf_action.optional_payload {
168 Some(_) => Err("FocusNextPane should not have a payload"),
169 None => Ok(Action::FocusNextPane),
170 },
171 Some(ProtobufActionName::FocusPreviousPane) => match protobuf_action.optional_payload {
172 Some(_) => Err("FocusPreviousPane should not have a payload"),
173 None => Ok(Action::FocusPreviousPane),
174 },
175 Some(ProtobufActionName::FocusLastPane) => match protobuf_action.optional_payload {
176 Some(_) => Err("FocusLastPane should not have a payload"),
177 None => Ok(Action::FocusLastPane),
178 },
179 Some(ProtobufActionName::SwitchFocus) => match protobuf_action.optional_payload {
180 Some(_) => Err("SwitchFocus should not have a payload"),
181 None => Ok(Action::SwitchFocus),
182 },
183 Some(ProtobufActionName::MoveFocus) => match protobuf_action.optional_payload {
184 Some(OptionalPayload::MoveFocusPayload(move_focus_payload)) => {
185 let direction: Direction =
186 ProtobufResizeDirection::try_from(move_focus_payload)
187 .ok()
188 .ok_or("Malformed resize direction for Action::MoveFocus")?
189 .try_into()?;
190 Ok(Action::MoveFocus { direction })
191 },
192 _ => Err("Wrong payload for Action::MoveFocus"),
193 },
194 Some(ProtobufActionName::MoveFocusOrTab) => match protobuf_action.optional_payload {
195 Some(OptionalPayload::MoveFocusOrTabPayload(move_focus_or_tab_payload)) => {
196 let direction: Direction =
197 ProtobufResizeDirection::try_from(move_focus_or_tab_payload)
198 .ok()
199 .ok_or("Malformed resize direction for Action::MoveFocusOrTab")?
200 .try_into()?;
201 Ok(Action::MoveFocusOrTab { direction })
202 },
203 _ => Err("Wrong payload for Action::MoveFocusOrTab"),
204 },
205 Some(ProtobufActionName::MovePane) => match protobuf_action.optional_payload {
206 Some(OptionalPayload::MovePanePayload(payload)) => {
207 let direction: Option<Direction> = payload
208 .direction
209 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
210 .and_then(|d| d.try_into().ok());
211 Ok(Action::MovePane { direction })
212 },
213 _ => Err("Wrong payload for Action::MovePane"),
214 },
215 Some(ProtobufActionName::MovePaneBackwards) => match protobuf_action.optional_payload {
216 Some(_) => Err("MovePaneBackwards should not have a payload"),
217 None => Ok(Action::MovePaneBackwards),
218 },
219 Some(ProtobufActionName::ClearScreen) => match protobuf_action.optional_payload {
220 Some(_) => Err("ClearScreen should not have a payload"),
221 None => Ok(Action::ClearScreen),
222 },
223 Some(ProtobufActionName::DumpScreen) => match protobuf_action.optional_payload {
224 Some(OptionalPayload::DumpScreenPayload(payload)) => {
225 let file_path = if payload.dump_to_stdout {
226 None
227 } else {
228 Some(payload.file_path)
229 };
230 let include_scrollback = payload.include_scrollback;
231 let pane_id = payload.pane_id.and_then(|p| p.try_into().ok());
232 Ok(Action::DumpScreen {
233 file_path,
234 include_scrollback,
235 pane_id,
236 ansi: payload.ansi,
237 })
238 },
239 _ => Err("Wrong payload for Action::DumpScreen"),
240 },
241 Some(ProtobufActionName::EditScrollback) => match protobuf_action.optional_payload {
242 Some(_) => Err("EditScrollback should not have a payload"),
243 None => Ok(Action::EditScrollback { ansi: false }),
244 },
245 Some(ProtobufActionName::ScrollUp) => match protobuf_action.optional_payload {
246 Some(_) => Err("ScrollUp should not have a payload"),
247 None => Ok(Action::ScrollUp),
248 },
249 Some(ProtobufActionName::ScrollDown) => match protobuf_action.optional_payload {
250 Some(_) => Err("ScrollDown should not have a payload"),
251 None => Ok(Action::ScrollDown),
252 },
253 Some(ProtobufActionName::ScrollUpAt) => match protobuf_action.optional_payload {
254 Some(OptionalPayload::ScrollUpAtPayload(payload)) => {
255 let position = payload
256 .position
257 .ok_or("ScrollUpAtPayload must have a position")?
258 .try_into()?;
259 Ok(Action::ScrollUpAt { position })
260 },
261 _ => Err("Wrong payload for Action::ScrollUpAt"),
262 },
263 Some(ProtobufActionName::ScrollDownAt) => match protobuf_action.optional_payload {
264 Some(OptionalPayload::ScrollDownAtPayload(payload)) => {
265 let position = payload
266 .position
267 .ok_or("ScrollDownAtPayload must have a position")?
268 .try_into()?;
269 Ok(Action::ScrollDownAt { position })
270 },
271 _ => Err("Wrong payload for Action::ScrollDownAt"),
272 },
273 Some(ProtobufActionName::ScrollToBottom) => match protobuf_action.optional_payload {
274 Some(_) => Err("ScrollToBottom should not have a payload"),
275 None => Ok(Action::ScrollToBottom),
276 },
277 Some(ProtobufActionName::ScrollToTop) => match protobuf_action.optional_payload {
278 Some(_) => Err("ScrollToTop should not have a payload"),
279 None => Ok(Action::ScrollToTop),
280 },
281 Some(ProtobufActionName::ScrollToPreviousPrompt) => {
282 match protobuf_action.optional_payload {
283 Some(_) => Err("ScrollToPreviousPrompt should not have a payload"),
284 None => Ok(Action::ScrollToPreviousPrompt),
285 }
286 },
287 Some(ProtobufActionName::ScrollToNextPrompt) => {
288 match protobuf_action.optional_payload {
289 Some(_) => Err("ScrollToNextPrompt should not have a payload"),
290 None => Ok(Action::ScrollToNextPrompt),
291 }
292 },
293 Some(ProtobufActionName::SelectCommandAtScrollPosition) => {
294 match protobuf_action.optional_payload {
295 Some(_) => Err("SelectCommandAtScrollPosition should not have a payload"),
296 None => Ok(Action::SelectCommandAtScrollPosition),
297 }
298 },
299 Some(ProtobufActionName::CopyLastCommandOutput) => {
300 match protobuf_action.optional_payload {
301 Some(_) => Err("CopyLastCommandOutput should not have a payload"),
302 None => Ok(Action::CopyLastCommandOutput),
303 }
304 },
305 Some(ProtobufActionName::PageScrollUp) => match protobuf_action.optional_payload {
306 Some(_) => Err("PageScrollUp should not have a payload"),
307 None => Ok(Action::PageScrollUp),
308 },
309 Some(ProtobufActionName::PageScrollDown) => match protobuf_action.optional_payload {
310 Some(_) => Err("PageScrollDown should not have a payload"),
311 None => Ok(Action::PageScrollDown),
312 },
313 Some(ProtobufActionName::HalfPageScrollUp) => match protobuf_action.optional_payload {
314 Some(_) => Err("HalfPageScrollUp should not have a payload"),
315 None => Ok(Action::HalfPageScrollUp),
316 },
317 Some(ProtobufActionName::HalfPageScrollDown) => {
318 match protobuf_action.optional_payload {
319 Some(_) => Err("HalfPageScrollDown should not have a payload"),
320 None => Ok(Action::HalfPageScrollDown),
321 }
322 },
323 Some(ProtobufActionName::ToggleFocusFullscreen) => {
324 match protobuf_action.optional_payload {
325 Some(_) => Err("ToggleFocusFullscreen should not have a payload"),
326 None => Ok(Action::ToggleFocusFullscreen),
327 }
328 },
329 Some(ProtobufActionName::ToggleFocusNoUiFullscreen) => {
330 match protobuf_action.optional_payload {
331 Some(_) => Err("ToggleFocusNoUiFullscreen should not have a payload"),
332 None => Ok(Action::ToggleFocusNoUiFullscreen),
333 }
334 },
335 Some(ProtobufActionName::TogglePaneFrames) => match protobuf_action.optional_payload {
336 Some(_) => Err("TogglePaneFrames should not have a payload"),
337 None => Ok(Action::TogglePaneFrames),
338 },
339 Some(ProtobufActionName::SetPaneFrameStyle) => match protobuf_action.optional_payload {
340 Some(OptionalPayload::SetPaneFrameStylePayload(payload)) => {
341 match ProtobufPaneFrameStyle::try_from(payload.pane_frame_style).ok() {
342 Some(protobuf_pane_frame_style) => Ok(Action::SetPaneFrameStyle(
343 protobuf_pane_frame_style.try_into()?,
344 )),
345 None => Err("Malformed payload for Action::SetPaneFrameStyle"),
346 }
347 },
348 _ => Err("Wrong payload for Action::SetPaneFrameStyle"),
349 },
350 Some(ProtobufActionName::ToggleActiveSyncTab) => {
351 match protobuf_action.optional_payload {
352 Some(_) => Err("ToggleActiveSyncTab should not have a payload"),
353 None => Ok(Action::ToggleActiveSyncTab),
354 }
355 },
356 Some(ProtobufActionName::NewPane) => match protobuf_action.optional_payload {
357 Some(OptionalPayload::NewPanePayload(payload)) => {
358 let direction: Option<Direction> = payload
359 .direction
360 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
361 .and_then(|d| d.try_into().ok());
362 let pane_name = payload.pane_name;
363 Ok(Action::NewPane {
364 direction,
365 pane_name,
366 start_suppressed: false,
367 })
368 },
369 _ => Err("Wrong payload for Action::NewPane"),
370 },
371 Some(ProtobufActionName::EditFile) => match protobuf_action.optional_payload {
372 Some(OptionalPayload::EditFilePayload(payload)) => {
373 let file_to_edit = PathBuf::from(payload.file_to_edit);
374 let line_number: Option<usize> = payload.line_number.map(|l| l as usize);
375 let cwd: Option<PathBuf> = payload.cwd.map(|p| PathBuf::from(p));
376 let direction: Option<Direction> = payload
377 .direction
378 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
379 .and_then(|d| d.try_into().ok());
380 let near_current_pane = payload.near_current_pane;
381 let should_float = payload.should_float;
382 let should_be_in_place = false;
383 Ok(Action::EditFile {
384 payload: OpenFilePayload::new(file_to_edit, line_number, cwd),
385 direction,
386 floating: should_float,
387 in_place: should_be_in_place,
388 close_replaced_pane: false,
389 start_suppressed: false,
390 coordinates: None,
391 near_current_pane,
392 no_focus: false,
393 tab_id: None,
394 })
395 },
396 _ => Err("Wrong payload for Action::NewPane"),
397 },
398 Some(ProtobufActionName::NewFloatingPane) => match protobuf_action.optional_payload {
399 Some(OptionalPayload::NewFloatingPanePayload(payload)) => {
400 let near_current_pane = payload.near_current_pane;
401 if let Some(payload) = payload.command {
402 let pane_name = payload.pane_name.clone();
403 let run_command_action: RunCommandAction = payload.try_into()?;
404 Ok(Action::NewFloatingPane {
405 command: Some(run_command_action),
406 pane_name,
407 coordinates: None,
408 near_current_pane,
409 no_focus: false,
410 tab_id: None,
411 })
412 } else {
413 Ok(Action::NewFloatingPane {
414 command: None,
415 pane_name: None,
416 coordinates: None,
417 near_current_pane,
418 no_focus: false,
419 tab_id: None,
420 })
421 }
422 },
423 _ => Err("Wrong payload for Action::NewFloatingPane"),
424 },
425 Some(ProtobufActionName::NewTiledPane) => match protobuf_action.optional_payload {
426 Some(OptionalPayload::NewTiledPanePayload(payload)) => {
427 let direction: Option<Direction> = payload
428 .direction
429 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
430 .and_then(|d| d.try_into().ok());
431 let near_current_pane = payload.near_current_pane;
432 let borderless = payload.borderless;
433 if let Some(payload) = payload.command {
434 let pane_name = payload.pane_name.clone();
435 let run_command_action: RunCommandAction = payload.try_into()?;
436 Ok(Action::NewTiledPane {
437 direction,
438 command: Some(run_command_action),
439 pane_name,
440 near_current_pane,
441 no_focus: false,
442 borderless,
443 tab_id: None,
444 })
445 } else {
446 Ok(Action::NewTiledPane {
447 direction,
448 command: None,
449 pane_name: None,
450 near_current_pane,
451 no_focus: false,
452 borderless,
453 tab_id: None,
454 })
455 }
456 },
457 _ => Err("Wrong payload for Action::NewTiledPane"),
458 },
459 Some(ProtobufActionName::TogglePaneEmbedOrFloating) => {
460 match protobuf_action.optional_payload {
461 Some(_) => Err("TogglePaneEmbedOrFloating should not have a payload"),
462 None => Ok(Action::TogglePaneEmbedOrFloating),
463 }
464 },
465 Some(ProtobufActionName::ToggleFloatingPanes) => {
466 match protobuf_action.optional_payload {
467 Some(_) => Err("ToggleFloatingPanes should not have a payload"),
468 None => Ok(Action::ToggleFloatingPanes),
469 }
470 },
471 Some(ProtobufActionName::ShowFloatingPanes) => match protobuf_action.optional_payload {
472 Some(OptionalPayload::ShowFloatingPanesPayload(payload)) => {
473 Ok(Action::ShowFloatingPanes {
474 tab_id: payload.tab_id.map(|id| id as usize),
475 })
476 },
477 None => Ok(Action::ShowFloatingPanes { tab_id: None }),
478 _ => Err("Wrong payload for ShowFloatingPanes"),
479 },
480 Some(ProtobufActionName::HideFloatingPanes) => match protobuf_action.optional_payload {
481 Some(OptionalPayload::HideFloatingPanesPayload(payload)) => {
482 Ok(Action::HideFloatingPanes {
483 tab_id: payload.tab_id.map(|id| id as usize),
484 })
485 },
486 None => Ok(Action::HideFloatingPanes { tab_id: None }),
487 _ => Err("Wrong payload for HideFloatingPanes"),
488 },
489 Some(ProtobufActionName::AreFloatingPanesVisible) => {
490 match protobuf_action.optional_payload {
491 Some(OptionalPayload::AreFloatingPanesVisiblePayload(payload)) => {
492 Ok(Action::AreFloatingPanesVisible {
493 tab_id: payload.tab_id.map(|id| id as usize),
494 })
495 },
496 None => Ok(Action::AreFloatingPanesVisible { tab_id: None }),
497 _ => Err("Wrong payload for AreFloatingPanesVisible"),
498 }
499 },
500 Some(ProtobufActionName::CloseFocus) => match protobuf_action.optional_payload {
501 Some(_) => Err("CloseFocus should not have a payload"),
502 None => Ok(Action::CloseFocus),
503 },
504 Some(ProtobufActionName::PaneNameInput) => match protobuf_action.optional_payload {
505 Some(OptionalPayload::PaneNameInputPayload(bytes)) => {
506 Ok(Action::PaneNameInput { input: bytes })
507 },
508 _ => Err("Wrong payload for Action::PaneNameInput"),
509 },
510 Some(ProtobufActionName::UndoRenamePane) => match protobuf_action.optional_payload {
511 Some(_) => Err("UndoRenamePane should not have a payload"),
512 None => Ok(Action::UndoRenamePane),
513 },
514 Some(ProtobufActionName::NewTab) => {
515 match protobuf_action.optional_payload {
516 Some(OptionalPayload::NewTabPayload(payload)) => {
517 let tiled_layout =
519 payload.tiled_layout.map(|l| l.try_into()).transpose()?;
520
521 let floating_layouts = payload
522 .floating_layouts
523 .into_iter()
524 .map(|l| l.try_into())
525 .collect::<Result<Vec<_>, _>>()?;
526
527 let swap_tiled_layouts = if payload.swap_tiled_layouts.is_empty() {
528 None
529 } else {
530 Some(
531 payload
532 .swap_tiled_layouts
533 .into_iter()
534 .map(|l| l.try_into())
535 .collect::<Result<Vec<_>, _>>()?,
536 )
537 };
538
539 let swap_floating_layouts = if payload.swap_floating_layouts.is_empty() {
540 None
541 } else {
542 Some(
543 payload
544 .swap_floating_layouts
545 .into_iter()
546 .map(|l| l.try_into())
547 .collect::<Result<Vec<_>, _>>()?,
548 )
549 };
550
551 let tab_name = payload.tab_name;
552 let should_change_focus_to_new_tab = payload.should_change_focus_to_new_tab;
553 let cwd = payload.cwd.map(PathBuf::from);
554
555 let initial_panes = if payload.initial_panes.is_empty() {
556 None
557 } else {
558 Some(
559 payload
560 .initial_panes
561 .into_iter()
562 .map(|p| p.try_into())
563 .collect::<Result<Vec<_>, _>>()?,
564 )
565 };
566
567 let first_pane_unblock_condition = payload
568 .first_pane_unblock_condition
569 .and_then(|uc| ProtobufUnblockCondition::try_from(uc).ok())
570 .and_then(|uc| uc.try_into().ok());
571
572 Ok(Action::NewTab {
573 tiled_layout,
574 floating_layouts,
575 swap_tiled_layouts,
576 swap_floating_layouts,
577 tab_name,
578 should_change_focus_to_new_tab,
579 cwd,
580 initial_panes,
581 first_pane_unblock_condition,
582 })
583 },
584 None => {
585 Ok(Action::NewTab {
588 tiled_layout: None,
589 floating_layouts: vec![],
590 swap_tiled_layouts: None,
591 swap_floating_layouts: None,
592 tab_name: None,
593 should_change_focus_to_new_tab: true,
594 cwd: None,
595 initial_panes: None,
596 first_pane_unblock_condition: None,
597 })
598 },
599 _ => Err("Wrong payload for Action::NewTab"),
600 }
601 },
602 Some(ProtobufActionName::NoOp) => match protobuf_action.optional_payload {
603 Some(_) => Err("NoOp should not have a payload"),
604 None => Ok(Action::NoOp),
605 },
606 Some(ProtobufActionName::GoToNextTab) => match protobuf_action.optional_payload {
607 Some(_) => Err("GoToNextTab should not have a payload"),
608 None => Ok(Action::GoToNextTab),
609 },
610 Some(ProtobufActionName::GoToPreviousTab) => match protobuf_action.optional_payload {
611 Some(_) => Err("GoToPreviousTab should not have a payload"),
612 None => Ok(Action::GoToPreviousTab),
613 },
614 Some(ProtobufActionName::CloseTab) => match protobuf_action.optional_payload {
615 Some(_) => Err("CloseTab should not have a payload"),
616 None => Ok(Action::CloseTab),
617 },
618 Some(ProtobufActionName::GoToTab) => match protobuf_action.optional_payload {
619 Some(OptionalPayload::GoToTabPayload(index)) => Ok(Action::GoToTab { index }),
620 _ => Err("Wrong payload for Action::GoToTab"),
621 },
622 Some(ProtobufActionName::GoToTabName) => match protobuf_action.optional_payload {
623 Some(OptionalPayload::GoToTabNamePayload(payload)) => {
624 let tab_name = payload.tab_name;
625 let create = payload.create;
626 Ok(Action::GoToTabName {
627 name: tab_name,
628 create,
629 })
630 },
631 _ => Err("Wrong payload for Action::GoToTabName"),
632 },
633 Some(ProtobufActionName::ToggleTab) => match protobuf_action.optional_payload {
634 Some(_) => Err("ToggleTab should not have a payload"),
635 None => Ok(Action::ToggleTab),
636 },
637 Some(ProtobufActionName::TabNameInput) => match protobuf_action.optional_payload {
638 Some(OptionalPayload::TabNameInputPayload(bytes)) => {
639 Ok(Action::TabNameInput { input: bytes })
640 },
641 _ => Err("Wrong payload for Action::TabNameInput"),
642 },
643 Some(ProtobufActionName::UndoRenameTab) => match protobuf_action.optional_payload {
644 Some(_) => Err("UndoRenameTab should not have a payload"),
645 None => Ok(Action::UndoRenameTab),
646 },
647 Some(ProtobufActionName::MoveTab) => match protobuf_action.optional_payload {
648 Some(OptionalPayload::MoveTabPayload(move_tab_payload)) => {
649 let direction: Direction = ProtobufMoveTabDirection::try_from(move_tab_payload)
650 .ok()
651 .ok_or("Malformed move tab direction for Action::MoveTab")?
652 .try_into()?;
653 Ok(Action::MoveTab { direction })
654 },
655 _ => Err("Wrong payload for Action::MoveTab"),
656 },
657 Some(ProtobufActionName::Run) => match protobuf_action.optional_payload {
658 Some(OptionalPayload::RunPayload(run_command_action)) => {
659 let run_command_action = run_command_action.try_into()?;
660 Ok(Action::Run {
661 command: run_command_action,
662 near_current_pane: false,
663 no_focus: false,
664 })
665 },
666 _ => Err("Wrong payload for Action::Run"),
667 },
668 Some(ProtobufActionName::Detach) => match protobuf_action.optional_payload {
669 Some(_) => Err("Detach should not have a payload"),
670 None => Ok(Action::Detach),
671 },
672 Some(ProtobufActionName::SetDarkTheme) => match protobuf_action.optional_payload {
673 Some(_) => Err("SetDarkTheme should not have a payload"),
674 None => Ok(Action::SetDarkTheme),
675 },
676 Some(ProtobufActionName::SetLightTheme) => match protobuf_action.optional_payload {
677 Some(_) => Err("SetLightTheme should not have a payload"),
678 None => Ok(Action::SetLightTheme),
679 },
680 Some(ProtobufActionName::ToggleTheme) => match protobuf_action.optional_payload {
681 Some(_) => Err("ToggleTheme should not have a payload"),
682 None => Ok(Action::ToggleTheme),
683 },
684 Some(ProtobufActionName::LeftClick) => match protobuf_action.optional_payload {
685 Some(OptionalPayload::LeftClickPayload(payload)) => {
686 let position = payload.try_into()?;
687 Ok(Action::MouseEvent {
688 event: MouseEvent::new_left_press_event(position),
689 })
690 },
691 _ => Err("Wrong payload for Action::LeftClick"),
692 },
693 Some(ProtobufActionName::RightClick) => match protobuf_action.optional_payload {
694 Some(OptionalPayload::RightClickPayload(payload)) => {
695 let position = payload.try_into()?;
696 Ok(Action::MouseEvent {
697 event: MouseEvent::new_right_press_event(position),
698 })
699 },
700 _ => Err("Wrong payload for Action::RightClick"),
701 },
702 Some(ProtobufActionName::MiddleClick) => match protobuf_action.optional_payload {
703 Some(OptionalPayload::MiddleClickPayload(payload)) => {
704 let position = payload.try_into()?;
705 Ok(Action::MouseEvent {
706 event: MouseEvent::new_middle_press_event(position),
707 })
708 },
709 _ => Err("Wrong payload for Action::MiddleClick"),
710 },
711 Some(ProtobufActionName::LaunchOrFocusPlugin) => {
712 match protobuf_action.optional_payload {
713 Some(OptionalPayload::LaunchOrFocusPluginPayload(payload)) => {
714 let configuration: PluginUserConfiguration = payload
715 .plugin_configuration
716 .and_then(|p| PluginUserConfiguration::try_from(p).ok())
717 .unwrap_or_default();
718 let run_plugin_or_alias = RunPluginOrAlias::from_url(
719 &payload.plugin_url.as_str(),
720 &Some(configuration.inner().clone()),
721 None,
722 None,
723 )
724 .map_err(|_| "Malformed LaunchOrFocusPlugin payload")?;
725 let should_float = payload.should_float;
726 let move_to_focused_tab = payload.move_to_focused_tab;
727 let should_open_in_place = payload.should_open_in_place;
728 let skip_plugin_cache = payload.skip_plugin_cache;
729 Ok(Action::LaunchOrFocusPlugin {
730 plugin: run_plugin_or_alias,
731 should_float,
732 move_to_focused_tab,
733 should_open_in_place,
734 close_replaced_pane: false,
735 skip_cache: skip_plugin_cache,
736 tab_id: None,
737 })
738 },
739 _ => Err("Wrong payload for Action::LaunchOrFocusPlugin"),
740 }
741 },
742 Some(ProtobufActionName::LaunchPlugin) => match protobuf_action.optional_payload {
743 Some(OptionalPayload::LaunchOrFocusPluginPayload(payload)) => {
744 let configuration: PluginUserConfiguration = payload
745 .plugin_configuration
746 .and_then(|p| PluginUserConfiguration::try_from(p).ok())
747 .unwrap_or_default();
748 let run_plugin_or_alias = RunPluginOrAlias::from_url(
749 &payload.plugin_url.as_str(),
750 &Some(configuration.inner().clone()),
751 None,
752 None,
753 )
754 .map_err(|_| "Malformed LaunchOrFocusPlugin payload")?;
755 let should_float = payload.should_float;
756 let _move_to_focused_tab = payload.move_to_focused_tab; let should_open_in_place = payload.should_open_in_place;
759 let skip_plugin_cache = payload.skip_plugin_cache;
760 Ok(Action::LaunchPlugin {
761 plugin: run_plugin_or_alias,
762 should_float,
763 should_open_in_place,
764 close_replaced_pane: false,
765 skip_cache: skip_plugin_cache,
766 cwd: None,
767 no_focus: false,
768 tab_id: None,
769 })
770 },
771 _ => Err("Wrong payload for Action::LaunchOrFocusPlugin"),
772 },
773 Some(ProtobufActionName::LeftMouseRelease) => match protobuf_action.optional_payload {
774 Some(OptionalPayload::LeftMouseReleasePayload(payload)) => {
775 let position = payload.try_into()?;
776 Ok(Action::MouseEvent {
777 event: MouseEvent::new_left_release_event(position),
778 })
779 },
780 _ => Err("Wrong payload for Action::LeftMouseRelease"),
781 },
782 Some(ProtobufActionName::RightMouseRelease) => match protobuf_action.optional_payload {
783 Some(OptionalPayload::RightMouseReleasePayload(payload)) => {
784 let position = payload.try_into()?;
785 Ok(Action::MouseEvent {
786 event: MouseEvent::new_right_release_event(position),
787 })
788 },
789 _ => Err("Wrong payload for Action::RightMouseRelease"),
790 },
791 Some(ProtobufActionName::MiddleMouseRelease) => {
792 match protobuf_action.optional_payload {
793 Some(OptionalPayload::MiddleMouseReleasePayload(payload)) => {
794 let position = payload.try_into()?;
795 Ok(Action::MouseEvent {
796 event: MouseEvent::new_middle_release_event(position),
797 })
798 },
799 _ => Err("Wrong payload for Action::MiddleMouseRelease"),
800 }
801 },
802 Some(ProtobufActionName::MouseEvent) => match protobuf_action.optional_payload {
803 Some(OptionalPayload::MouseEventPayload(payload)) => {
804 let event = payload.try_into()?;
805 Ok(Action::MouseEvent { event })
806 },
807 _ => Err("Wrong payload for Action::MouseEvent"),
808 },
809 Some(ProtobufActionName::SearchInput) => match protobuf_action.optional_payload {
810 Some(OptionalPayload::SearchInputPayload(payload)) => {
811 Ok(Action::SearchInput { input: payload })
812 },
813 _ => Err("Wrong payload for Action::SearchInput"),
814 },
815 Some(ProtobufActionName::Search) => match protobuf_action.optional_payload {
816 Some(OptionalPayload::SearchPayload(search_direction)) => Ok(Action::Search {
817 direction: ProtobufSearchDirection::try_from(search_direction)
818 .ok()
819 .ok_or("Malformed payload for Action::Search")?
820 .try_into()?,
821 }),
822 _ => Err("Wrong payload for Action::Search"),
823 },
824 Some(ProtobufActionName::SearchToggleOption) => {
825 match protobuf_action.optional_payload {
826 Some(OptionalPayload::SearchToggleOptionPayload(search_option)) => {
827 Ok(Action::SearchToggleOption {
828 option: ProtobufSearchOption::try_from(search_option)
829 .ok()
830 .ok_or("Malformed payload for Action::SearchToggleOption")?
831 .try_into()?,
832 })
833 },
834 _ => Err("Wrong payload for Action::SearchToggleOption"),
835 }
836 },
837 Some(ProtobufActionName::ToggleMouseMode) => match protobuf_action.optional_payload {
838 Some(_) => Err("ToggleMouseMode should not have a payload"),
839 None => Ok(Action::ToggleMouseMode),
840 },
841 Some(ProtobufActionName::PreviousSwapLayout) => {
842 match protobuf_action.optional_payload {
843 Some(_) => Err("PreviousSwapLayout should not have a payload"),
844 None => Ok(Action::PreviousSwapLayout),
845 }
846 },
847 Some(ProtobufActionName::NextSwapLayout) => match protobuf_action.optional_payload {
848 Some(_) => Err("NextSwapLayout should not have a payload"),
849 None => Ok(Action::NextSwapLayout),
850 },
851 Some(ProtobufActionName::OverrideLayout) => match protobuf_action.optional_payload {
852 Some(OptionalPayload::OverrideLayoutPayload(payload)) => {
853 Ok(Action::OverrideLayout {
854 tabs: payload
855 .tabs
856 .into_iter()
857 .map(|t| t.try_into())
858 .collect::<Result<Vec<_>, _>>()?,
859 retain_existing_terminal_panes: payload.retain_existing_terminal_panes,
860 retain_existing_plugin_panes: payload.retain_existing_plugin_panes,
861 apply_only_to_active_tab: payload.apply_only_to_active_tab,
862 })
863 },
864 Some(_) => Err("Mismatched payload for OverrideLayout"),
865 None => Err("Missing payload for OverrideLayout"),
866 },
867 Some(ProtobufActionName::QueryTabNames) => match protobuf_action.optional_payload {
868 Some(_) => Err("QueryTabNames should not have a payload"),
869 None => Ok(Action::QueryTabNames),
870 },
871 Some(ProtobufActionName::NewTiledPluginPane) => {
872 match protobuf_action.optional_payload {
873 Some(OptionalPayload::NewTiledPluginPanePayload(payload)) => {
874 let run_plugin_location =
875 RunPluginLocation::parse(&payload.plugin_url, None)
876 .map_err(|_| "Malformed NewTiledPluginPane payload")?;
877 let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin {
878 location: run_plugin_location,
879 _allow_exec_host_cmd: false,
880 configuration: PluginUserConfiguration::default(),
881 ..Default::default()
882 });
883 let pane_name = payload.pane_name;
884 let skip_plugin_cache = payload.skip_plugin_cache;
885 Ok(Action::NewTiledPluginPane {
886 plugin: run_plugin,
887 pane_name,
888 skip_cache: skip_plugin_cache,
889 cwd: None,
890 no_focus: false,
891 tab_id: None,
892 })
893 },
894 _ => Err("Wrong payload for Action::NewTiledPluginPane"),
895 }
896 },
897 Some(ProtobufActionName::NewFloatingPluginPane) => {
898 match protobuf_action.optional_payload {
899 Some(OptionalPayload::NewFloatingPluginPanePayload(payload)) => {
900 let run_plugin_location =
901 RunPluginLocation::parse(&payload.plugin_url, None)
902 .map_err(|_| "Malformed NewTiledPluginPane payload")?;
903 let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin {
904 location: run_plugin_location,
905 _allow_exec_host_cmd: false,
906 configuration: PluginUserConfiguration::default(),
907 ..Default::default()
908 });
909 let pane_name = payload.pane_name;
910 let skip_plugin_cache = payload.skip_plugin_cache;
911 Ok(Action::NewFloatingPluginPane {
912 plugin: run_plugin,
913 pane_name,
914 skip_cache: skip_plugin_cache,
915 cwd: None,
916 coordinates: None,
917 no_focus: false,
918 tab_id: None,
919 })
920 },
921 _ => Err("Wrong payload for Action::MiddleClick"),
922 }
923 },
924 Some(ProtobufActionName::StartOrReloadPlugin) => {
925 match protobuf_action.optional_payload {
926 Some(OptionalPayload::StartOrReloadPluginPayload(payload)) => {
927 let run_plugin_or_alias =
928 RunPluginOrAlias::from_url(&payload.as_str(), &None, None, None)
929 .map_err(|_| "Malformed LaunchOrFocusPlugin payload")?;
930
931 Ok(Action::StartOrReloadPlugin {
932 plugin: run_plugin_or_alias,
933 })
934 },
935 _ => Err("Wrong payload for Action::StartOrReloadPlugin"),
936 }
937 },
938 Some(ProtobufActionName::CloseTerminalPane) => match protobuf_action.optional_payload {
939 Some(OptionalPayload::CloseTerminalPanePayload(payload)) => {
940 Ok(Action::CloseTerminalPane { pane_id: payload })
941 },
942 _ => Err("Wrong payload for Action::CloseTerminalPane"),
943 },
944 Some(ProtobufActionName::ClosePluginPane) => match protobuf_action.optional_payload {
945 Some(OptionalPayload::ClosePluginPanePayload(payload)) => {
946 Ok(Action::ClosePluginPane { pane_id: payload })
947 },
948 _ => Err("Wrong payload for Action::ClosePluginPane"),
949 },
950 Some(ProtobufActionName::FocusTerminalPaneWithId) => {
951 match protobuf_action.optional_payload {
952 Some(OptionalPayload::FocusTerminalPaneWithIdPayload(payload)) => {
953 let terminal_pane_id = payload.pane_id;
954 let should_float_if_hidden = payload.should_float;
955 let should_be_in_place_if_hidden = payload.should_be_in_place;
956 Ok(Action::FocusTerminalPaneWithId {
957 pane_id: terminal_pane_id,
958 should_float_if_hidden,
959 should_be_in_place_if_hidden,
960 })
961 },
962 _ => Err("Wrong payload for Action::FocusTerminalPaneWithId"),
963 }
964 },
965 Some(ProtobufActionName::FocusPluginPaneWithId) => {
966 match protobuf_action.optional_payload {
967 Some(OptionalPayload::FocusPluginPaneWithIdPayload(payload)) => {
968 let plugin_pane_id = payload.pane_id;
969 let should_float_if_hidden = payload.should_float;
970 let should_be_in_place_if_hidden = payload.should_be_in_place;
971 Ok(Action::FocusPluginPaneWithId {
972 pane_id: plugin_pane_id,
973 should_float_if_hidden,
974 should_be_in_place_if_hidden,
975 })
976 },
977 _ => Err("Wrong payload for Action::FocusPluginPaneWithId"),
978 }
979 },
980 Some(ProtobufActionName::RenameTerminalPane) => {
981 match protobuf_action.optional_payload {
982 Some(OptionalPayload::RenameTerminalPanePayload(payload)) => {
983 let terminal_pane_id = payload.id;
984 let new_pane_name = payload.name;
985 Ok(Action::RenameTerminalPane {
986 pane_id: terminal_pane_id,
987 name: new_pane_name,
988 })
989 },
990 _ => Err("Wrong payload for Action::RenameTerminalPane"),
991 }
992 },
993 Some(ProtobufActionName::RenamePluginPane) => match protobuf_action.optional_payload {
994 Some(OptionalPayload::RenamePluginPanePayload(payload)) => {
995 let plugin_pane_id = payload.id;
996 let new_pane_name = payload.name;
997 Ok(Action::RenamePluginPane {
998 pane_id: plugin_pane_id,
999 name: new_pane_name,
1000 })
1001 },
1002 _ => Err("Wrong payload for Action::RenamePluginPane"),
1003 },
1004 Some(ProtobufActionName::RenameTab) => match protobuf_action.optional_payload {
1005 Some(OptionalPayload::RenameTabPayload(payload)) => {
1006 let tab_index = payload.id;
1007 let new_tab_name = payload.name;
1008 Ok(Action::RenameTab {
1009 tab_index,
1010 name: new_tab_name,
1011 })
1012 },
1013 _ => Err("Wrong payload for Action::RenameTab"),
1014 },
1015 Some(ProtobufActionName::BreakPane) => match protobuf_action.optional_payload {
1016 Some(_) => Err("BreakPane should not have a payload"),
1017 None => Ok(Action::BreakPane),
1018 },
1019 Some(ProtobufActionName::BreakPaneRight) => match protobuf_action.optional_payload {
1020 Some(_) => Err("BreakPaneRight should not have a payload"),
1021 None => Ok(Action::BreakPaneRight),
1022 },
1023 Some(ProtobufActionName::BreakPaneLeft) => match protobuf_action.optional_payload {
1024 Some(_) => Err("BreakPaneLeft should not have a payload"),
1025 None => Ok(Action::BreakPaneLeft),
1026 },
1027 Some(ProtobufActionName::RenameSession) => match protobuf_action.optional_payload {
1028 Some(OptionalPayload::RenameSessionPayload(name)) => {
1029 Ok(Action::RenameSession { name })
1030 },
1031 _ => Err("Wrong payload for Action::RenameSession"),
1032 },
1033 Some(ProtobufActionName::TogglePanePinned) => match protobuf_action.optional_payload {
1034 Some(_) => Err("TogglePanePinned should not have a payload"),
1035 None => Ok(Action::TogglePanePinned),
1036 },
1037 Some(ProtobufActionName::TogglePaneInGroup) => match protobuf_action.optional_payload {
1038 Some(_) => Err("TogglePaneInGroup should not have a payload"),
1039 None => Ok(Action::TogglePaneInGroup),
1040 },
1041 Some(ProtobufActionName::ToggleGroupMarking) => {
1042 match protobuf_action.optional_payload {
1043 Some(_) => Err("ToggleGroupMarking should not have a payload"),
1044 None => Ok(Action::ToggleGroupMarking),
1045 }
1046 },
1047 Some(ProtobufActionName::KeybindPipe) => match protobuf_action.optional_payload {
1048 Some(_) => Err("KeybindPipe should not have a payload"),
1049 None => Ok(Action::KeybindPipe {
1051 name: None,
1052 payload: None,
1053 args: None,
1054 plugin: None,
1055 configuration: None,
1056 launch_new: false,
1057 skip_cache: false,
1058 floating: None,
1059 in_place: None,
1060 cwd: None,
1061 pane_title: None,
1062 plugin_id: None,
1063 }),
1064 },
1065 Some(ProtobufActionName::NewStackedPane) => match protobuf_action.optional_payload {
1066 Some(_) => Err("NewStackedPane should not have a payload"),
1067 None => Ok(Action::NewStackedPane {
1068 command: None,
1069 pane_name: None,
1070 near_current_pane: false,
1071 no_focus: false,
1072 tab_id: None,
1073 }),
1074 },
1075 Some(ProtobufActionName::NewBlockingPane) => match protobuf_action.optional_payload {
1076 Some(OptionalPayload::NewBlockingPanePayload(payload)) => {
1077 let placement: NewPanePlacement = payload
1078 .placement
1079 .ok_or("NewBlockingPanePayload must have a placement")?
1080 .try_into()?;
1081 let pane_name = payload.pane_name;
1082 let command = payload.command.and_then(|c| c.try_into().ok());
1083 let unblock_condition = payload
1084 .unblock_condition
1085 .and_then(|uc| ProtobufUnblockCondition::try_from(uc).ok())
1086 .and_then(|uc| uc.try_into().ok());
1087 let near_current_pane = payload.near_current_pane;
1088 Ok(Action::NewBlockingPane {
1089 placement,
1090 pane_name,
1091 command,
1092 unblock_condition,
1093 near_current_pane,
1094 no_focus: false,
1095 tab_id: None,
1096 })
1097 },
1098 _ => Err("Wrong payload for Action::NewBlockingPane"),
1099 },
1100 Some(ProtobufActionName::NewInPlacePane) => match protobuf_action.optional_payload {
1101 Some(OptionalPayload::NewInPlacePanePayload(payload)) => {
1102 let near_current_pane = payload.near_current_pane;
1103 let pane_id_to_replace =
1104 payload.pane_id_to_replace.and_then(|p| p.try_into().ok());
1105 let close_replaced_pane = payload.close_replace_pane;
1106 if let Some(command) = payload.command {
1107 let pane_name = command.pane_name.clone();
1108 let run_command_action: RunCommandAction = command.try_into()?;
1109 Ok(Action::NewInPlacePane {
1110 command: Some(run_command_action),
1111 pane_name,
1112 near_current_pane,
1113 no_focus: false,
1114 pane_id_to_replace,
1115 close_replaced_pane,
1116 tab_id: None,
1117 })
1118 } else {
1119 Ok(Action::NewInPlacePane {
1120 command: None,
1121 pane_name: payload.pane_name,
1122 near_current_pane,
1123 no_focus: false,
1124 pane_id_to_replace,
1125 close_replaced_pane,
1126 tab_id: None,
1127 })
1128 }
1129 },
1130 _ => Err("Wrong payload for Action::NewInPlacePane"),
1131 },
1132 Some(ProtobufActionName::FocusHostSession) => match protobuf_action.optional_payload {
1133 Some(_) => Err("FocusHostSession should not have a payload"),
1134 None => Ok(Action::FocusHostSession),
1135 },
1136 Some(ProtobufActionName::FocusGuestSession) => match protobuf_action.optional_payload {
1137 Some(_) => Err("FocusGuestSession should not have a payload"),
1138 None => Ok(Action::FocusGuestSession),
1139 },
1140 Some(ProtobufActionName::ToggleHostFullscreen) => {
1141 match protobuf_action.optional_payload {
1142 Some(_) => Err("ToggleHostFullscreen should not have a payload"),
1143 None => Ok(Action::ToggleHostFullscreen),
1144 }
1145 },
1146 _ => Err("Unknown Action"),
1147 }
1148 }
1149}
1150
1151impl TryFrom<Action> for ProtobufAction {
1152 type Error = &'static str;
1153 fn try_from(action: Action) -> Result<Self, &'static str> {
1154 match action {
1155 Action::Quit => Ok(ProtobufAction {
1156 name: ProtobufActionName::Quit as i32,
1157 optional_payload: None,
1158 }),
1159 Action::Write {
1160 key_with_modifier,
1161 bytes,
1162 is_kitty_keyboard_protocol,
1163 } => {
1164 let protobuf_key_with_modifier = key_with_modifier.and_then(|k| k.try_into().ok());
1165 Ok(ProtobufAction {
1166 name: ProtobufActionName::Write as i32,
1167 optional_payload: Some(OptionalPayload::WritePayload(WritePayload {
1168 key_with_modifier: protobuf_key_with_modifier,
1169 bytes_to_write: bytes,
1170 is_kitty_keyboard_protocol,
1171 })),
1172 })
1173 },
1174 Action::WriteChars {
1175 chars: chars_to_write,
1176 } => Ok(ProtobufAction {
1177 name: ProtobufActionName::WriteChars as i32,
1178 optional_payload: Some(OptionalPayload::WriteCharsPayload(WriteCharsPayload {
1179 chars: chars_to_write,
1180 })),
1181 }),
1182 Action::WriteToPaneId { .. }
1183 | Action::WriteCharsToPaneId { .. }
1184 | Action::Paste { .. }
1185 | Action::GoToTabById { .. }
1186 | Action::CloseTabById { .. }
1187 | Action::RenameTabById { .. }
1188 | Action::ScrollUpByPaneId { .. }
1189 | Action::ScrollDownByPaneId { .. }
1190 | Action::ScrollToTopByPaneId { .. }
1191 | Action::ScrollToBottomByPaneId { .. }
1192 | Action::PageScrollUpByPaneId { .. }
1193 | Action::PageScrollDownByPaneId { .. }
1194 | Action::HalfPageScrollUpByPaneId { .. }
1195 | Action::HalfPageScrollDownByPaneId { .. }
1196 | Action::ResizeByPaneId { .. }
1197 | Action::MovePaneByPaneId { .. }
1198 | Action::MovePaneBackwardsByPaneId { .. }
1199 | Action::ClearScreenByPaneId { .. }
1200 | Action::EditScrollbackByPaneId { .. }
1201 | Action::ToggleFocusFullscreenByPaneId { .. }
1202 | Action::ToggleFocusNoUiFullscreenByPaneId { .. }
1203 | Action::TogglePaneEmbedOrFloatingByPaneId { .. }
1204 | Action::CloseFocusByPaneId { .. }
1205 | Action::RenamePaneByPaneId { .. }
1206 | Action::UndoRenamePaneByPaneId { .. }
1207 | Action::TogglePanePinnedByPaneId { .. }
1208 | Action::FocusPaneByPaneId { .. }
1209 | Action::UndoRenameTabByTabId { .. }
1210 | Action::ToggleActiveSyncTabByTabId { .. }
1211 | Action::ToggleFloatingPanesByTabId { .. }
1212 | Action::PreviousSwapLayoutByTabId { .. }
1213 | Action::NextSwapLayoutByTabId { .. }
1214 | Action::MoveTabByTabId { .. } => {
1215 Err("These are CLI-only actions, not available in keybindings")
1216 },
1217 Action::SwitchToMode { input_mode } => {
1218 let input_mode: ProtobufInputMode = input_mode.try_into()?;
1219 Ok(ProtobufAction {
1220 name: ProtobufActionName::SwitchToMode as i32,
1221 optional_payload: Some(OptionalPayload::SwitchToModePayload(
1222 SwitchToModePayload {
1223 input_mode: input_mode as i32,
1224 },
1225 )),
1226 })
1227 },
1228 Action::SwitchModeForAllClients { input_mode } => {
1229 let input_mode: ProtobufInputMode = input_mode.try_into()?;
1230 Ok(ProtobufAction {
1231 name: ProtobufActionName::SwitchModeForAllClients as i32,
1232 optional_payload: Some(OptionalPayload::SwitchModeForAllClientsPayload(
1233 SwitchToModePayload {
1234 input_mode: input_mode as i32,
1235 },
1236 )),
1237 })
1238 },
1239 Action::Resize { resize, direction } => {
1240 let mut resize: ProtobufResize = resize.try_into()?;
1241 resize.direction = direction.and_then(|d| {
1242 let resize_direction: ProtobufResizeDirection = d.try_into().ok()?;
1243 Some(resize_direction as i32)
1244 });
1245 Ok(ProtobufAction {
1246 name: ProtobufActionName::Resize as i32,
1247 optional_payload: Some(OptionalPayload::ResizePayload(resize)),
1248 })
1249 },
1250 Action::FocusNextPane => Ok(ProtobufAction {
1251 name: ProtobufActionName::FocusNextPane as i32,
1252 optional_payload: None,
1253 }),
1254 Action::FocusPreviousPane => Ok(ProtobufAction {
1255 name: ProtobufActionName::FocusPreviousPane as i32,
1256 optional_payload: None,
1257 }),
1258 Action::FocusLastPane => Ok(ProtobufAction {
1259 name: ProtobufActionName::FocusLastPane as i32,
1260 optional_payload: None,
1261 }),
1262 Action::SwitchFocus => Ok(ProtobufAction {
1263 name: ProtobufActionName::SwitchFocus as i32,
1264 optional_payload: None,
1265 }),
1266 Action::MoveFocus { direction } => {
1267 let direction: ProtobufResizeDirection = direction.try_into()?;
1268 Ok(ProtobufAction {
1269 name: ProtobufActionName::MoveFocus as i32,
1270 optional_payload: Some(OptionalPayload::MoveFocusPayload(direction as i32)),
1271 })
1272 },
1273 Action::MoveFocusOrTab { direction } => {
1274 let direction: ProtobufResizeDirection = direction.try_into()?;
1275 Ok(ProtobufAction {
1276 name: ProtobufActionName::MoveFocusOrTab as i32,
1277 optional_payload: Some(OptionalPayload::MoveFocusOrTabPayload(
1278 direction as i32,
1279 )),
1280 })
1281 },
1282 Action::MovePane { direction } => {
1283 let direction = direction.and_then(|direction| {
1284 let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
1285 Some(protobuf_direction as i32)
1286 });
1287 Ok(ProtobufAction {
1288 name: ProtobufActionName::MovePane as i32,
1289 optional_payload: Some(OptionalPayload::MovePanePayload(MovePanePayload {
1290 direction,
1291 })),
1292 })
1293 },
1294 Action::MovePaneBackwards => Ok(ProtobufAction {
1295 name: ProtobufActionName::MovePaneBackwards as i32,
1296 optional_payload: None,
1297 }),
1298 Action::ClearScreen => Ok(ProtobufAction {
1299 name: ProtobufActionName::ClearScreen as i32,
1300 optional_payload: None,
1301 }),
1302 Action::DumpScreen {
1303 file_path,
1304 include_scrollback,
1305 pane_id,
1306 ansi,
1307 } => {
1308 let dump_to_stdout = file_path.is_none();
1309 Ok(ProtobufAction {
1310 name: ProtobufActionName::DumpScreen as i32,
1311 optional_payload: Some(OptionalPayload::DumpScreenPayload(DumpScreenPayload {
1312 file_path: file_path.unwrap_or_default(),
1313 include_scrollback,
1314 pane_id: pane_id.and_then(|p| p.try_into().ok()),
1315 dump_to_stdout,
1316 ansi,
1317 })),
1318 })
1319 },
1320 Action::EditScrollback { .. } => Ok(ProtobufAction {
1321 name: ProtobufActionName::EditScrollback as i32,
1322 optional_payload: None,
1323 }),
1324 Action::ScrollUp => Ok(ProtobufAction {
1325 name: ProtobufActionName::ScrollUp as i32,
1326 optional_payload: None,
1327 }),
1328 Action::ScrollToPreviousPrompt => Ok(ProtobufAction {
1329 name: ProtobufActionName::ScrollToPreviousPrompt as i32,
1330 optional_payload: None,
1331 }),
1332 Action::ScrollToNextPrompt => Ok(ProtobufAction {
1333 name: ProtobufActionName::ScrollToNextPrompt as i32,
1334 optional_payload: None,
1335 }),
1336 Action::SelectCommandAtScrollPosition => Ok(ProtobufAction {
1337 name: ProtobufActionName::SelectCommandAtScrollPosition as i32,
1338 optional_payload: None,
1339 }),
1340 Action::CopyLastCommandOutput => Ok(ProtobufAction {
1341 name: ProtobufActionName::CopyLastCommandOutput as i32,
1342 optional_payload: None,
1343 }),
1344 Action::ScrollUpAt { position } => {
1345 let position: ProtobufPosition = position.try_into()?;
1346 Ok(ProtobufAction {
1347 name: ProtobufActionName::ScrollUpAt as i32,
1348 optional_payload: Some(OptionalPayload::ScrollUpAtPayload(ScrollAtPayload {
1349 position: Some(position),
1350 })),
1351 })
1352 },
1353 Action::ScrollDown => Ok(ProtobufAction {
1354 name: ProtobufActionName::ScrollDown as i32,
1355 optional_payload: None,
1356 }),
1357 Action::ScrollDownAt { position } => {
1358 let position: ProtobufPosition = position.try_into()?;
1359 Ok(ProtobufAction {
1360 name: ProtobufActionName::ScrollDownAt as i32,
1361 optional_payload: Some(OptionalPayload::ScrollDownAtPayload(ScrollAtPayload {
1362 position: Some(position),
1363 })),
1364 })
1365 },
1366 Action::ScrollToBottom => Ok(ProtobufAction {
1367 name: ProtobufActionName::ScrollToBottom as i32,
1368 optional_payload: None,
1369 }),
1370 Action::ScrollToTop => Ok(ProtobufAction {
1371 name: ProtobufActionName::ScrollToTop as i32,
1372 optional_payload: None,
1373 }),
1374 Action::PageScrollUp => Ok(ProtobufAction {
1375 name: ProtobufActionName::PageScrollUp as i32,
1376 optional_payload: None,
1377 }),
1378 Action::PageScrollDown => Ok(ProtobufAction {
1379 name: ProtobufActionName::PageScrollDown as i32,
1380 optional_payload: None,
1381 }),
1382 Action::HalfPageScrollUp => Ok(ProtobufAction {
1383 name: ProtobufActionName::HalfPageScrollUp as i32,
1384 optional_payload: None,
1385 }),
1386 Action::HalfPageScrollDown => Ok(ProtobufAction {
1387 name: ProtobufActionName::HalfPageScrollDown as i32,
1388 optional_payload: None,
1389 }),
1390 Action::ToggleFocusFullscreen => Ok(ProtobufAction {
1391 name: ProtobufActionName::ToggleFocusFullscreen as i32,
1392 optional_payload: None,
1393 }),
1394 Action::ToggleFocusNoUiFullscreen => Ok(ProtobufAction {
1395 name: ProtobufActionName::ToggleFocusNoUiFullscreen as i32,
1396 optional_payload: None,
1397 }),
1398 Action::TogglePaneFrames => Ok(ProtobufAction {
1399 name: ProtobufActionName::TogglePaneFrames as i32,
1400 optional_payload: None,
1401 }),
1402 Action::SetPaneFrameStyle(pane_frame_style) => Ok(ProtobufAction {
1403 name: ProtobufActionName::SetPaneFrameStyle as i32,
1404 optional_payload: Some(OptionalPayload::SetPaneFrameStylePayload(
1405 SetPaneFrameStylePayload {
1406 pane_frame_style: ProtobufPaneFrameStyle::try_from(pane_frame_style)?
1407 as i32,
1408 },
1409 )),
1410 }),
1411 Action::ToggleActiveSyncTab => Ok(ProtobufAction {
1412 name: ProtobufActionName::ToggleActiveSyncTab as i32,
1413 optional_payload: None,
1414 }),
1415 Action::NewPane {
1416 direction,
1417 pane_name: new_pane_name,
1418 start_suppressed: _start_suppressed,
1419 } => {
1420 let direction = direction.and_then(|direction| {
1421 let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
1422 Some(protobuf_direction as i32)
1423 });
1424 Ok(ProtobufAction {
1425 name: ProtobufActionName::NewPane as i32,
1426 optional_payload: Some(OptionalPayload::NewPanePayload(NewPanePayload {
1427 direction,
1428 pane_name: new_pane_name,
1429 })),
1430 })
1431 },
1432 Action::EditFile {
1433 payload: open_file_payload,
1434 direction,
1435 floating: should_float,
1436 in_place: _should_be_in_place,
1437 close_replaced_pane: _close_replaced_pane,
1438 start_suppressed: _start_suppressed,
1439 coordinates: _floating_pane_coordinates,
1440 near_current_pane,
1441 ..
1442 } => {
1443 let file_to_edit = open_file_payload.path.display().to_string();
1444 let cwd = open_file_payload.cwd.map(|cwd| cwd.display().to_string());
1445 let direction: Option<i32> = direction
1446 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
1447 .map(|d| d as i32);
1448 let line_number = open_file_payload.line_number.map(|l| l as u32);
1449 Ok(ProtobufAction {
1450 name: ProtobufActionName::EditFile as i32,
1451 optional_payload: Some(OptionalPayload::EditFilePayload(EditFilePayload {
1452 file_to_edit,
1453 line_number,
1454 should_float,
1455 direction,
1456 cwd,
1457 near_current_pane,
1458 })),
1459 })
1460 },
1461 Action::NewFloatingPane {
1462 command: run_command_action,
1463 pane_name,
1464 coordinates: _coordinates,
1465 near_current_pane,
1466 ..
1467 } => {
1468 let command = run_command_action.and_then(|r| {
1469 let mut protobuf_run_command_action: ProtobufRunCommandAction =
1470 r.try_into().ok()?;
1471 protobuf_run_command_action.pane_name = pane_name;
1472 Some(protobuf_run_command_action)
1473 });
1474 Ok(ProtobufAction {
1475 name: ProtobufActionName::NewFloatingPane as i32,
1476 optional_payload: Some(OptionalPayload::NewFloatingPanePayload(
1477 NewFloatingPanePayload {
1478 command,
1479 near_current_pane,
1480 },
1481 )),
1482 })
1483 },
1484 Action::NewTiledPane {
1485 direction,
1486 command: run_command_action,
1487 pane_name,
1488 near_current_pane,
1489 borderless,
1490 ..
1491 } => {
1492 let direction = direction.and_then(|direction| {
1493 let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
1494 Some(protobuf_direction as i32)
1495 });
1496 let command = run_command_action.and_then(|r| {
1497 let mut protobuf_run_command_action: ProtobufRunCommandAction =
1498 r.try_into().ok()?;
1499 let pane_name = pane_name.and_then(|n| n.try_into().ok());
1500 protobuf_run_command_action.pane_name = pane_name;
1501 Some(protobuf_run_command_action)
1502 });
1503 Ok(ProtobufAction {
1504 name: ProtobufActionName::NewTiledPane as i32,
1505 optional_payload: Some(OptionalPayload::NewTiledPanePayload(
1506 NewTiledPanePayload {
1507 direction,
1508 command,
1509 near_current_pane,
1510 borderless,
1511 },
1512 )),
1513 })
1514 },
1515 Action::TogglePaneEmbedOrFloating => Ok(ProtobufAction {
1516 name: ProtobufActionName::TogglePaneEmbedOrFloating as i32,
1517 optional_payload: None,
1518 }),
1519 Action::ToggleFloatingPanes => Ok(ProtobufAction {
1520 name: ProtobufActionName::ToggleFloatingPanes as i32,
1521 optional_payload: None,
1522 }),
1523 Action::ShowFloatingPanes { tab_id } => Ok(ProtobufAction {
1524 name: ProtobufActionName::ShowFloatingPanes as i32,
1525 optional_payload: Some(OptionalPayload::ShowFloatingPanesPayload(
1526 ShowFloatingPanesPayload {
1527 tab_id: tab_id.map(|id| id as u32),
1528 },
1529 )),
1530 }),
1531 Action::HideFloatingPanes { tab_id } => Ok(ProtobufAction {
1532 name: ProtobufActionName::HideFloatingPanes as i32,
1533 optional_payload: Some(OptionalPayload::HideFloatingPanesPayload(
1534 HideFloatingPanesPayload {
1535 tab_id: tab_id.map(|id| id as u32),
1536 },
1537 )),
1538 }),
1539 Action::AreFloatingPanesVisible { tab_id } => Ok(ProtobufAction {
1540 name: ProtobufActionName::AreFloatingPanesVisible as i32,
1541 optional_payload: Some(OptionalPayload::AreFloatingPanesVisiblePayload(
1542 AreFloatingPanesVisiblePayload {
1543 tab_id: tab_id.map(|id| id as u32),
1544 },
1545 )),
1546 }),
1547 Action::CloseFocus => Ok(ProtobufAction {
1548 name: ProtobufActionName::CloseFocus as i32,
1549 optional_payload: None,
1550 }),
1551 Action::PaneNameInput { input: bytes } => Ok(ProtobufAction {
1552 name: ProtobufActionName::PaneNameInput as i32,
1553 optional_payload: Some(OptionalPayload::PaneNameInputPayload(bytes)),
1554 }),
1555 Action::UndoRenamePane => Ok(ProtobufAction {
1556 name: ProtobufActionName::UndoRenamePane as i32,
1557 optional_payload: None,
1558 }),
1559 Action::NewTab {
1560 tiled_layout,
1561 floating_layouts,
1562 swap_tiled_layouts,
1563 swap_floating_layouts,
1564 tab_name,
1565 should_change_focus_to_new_tab,
1566 cwd,
1567 initial_panes,
1568 first_pane_unblock_condition,
1569 } => {
1570 let protobuf_tiled_layout = tiled_layout
1572 .as_ref()
1573 .map(|l| l.clone().try_into())
1574 .transpose()?;
1575
1576 let protobuf_floating_layouts = floating_layouts
1577 .iter()
1578 .map(|l| l.clone().try_into())
1579 .collect::<Result<Vec<_>, _>>()?;
1580
1581 let protobuf_swap_tiled_layouts = swap_tiled_layouts
1582 .as_ref()
1583 .map(|layouts| {
1584 layouts
1585 .iter()
1586 .map(|l| l.clone().try_into())
1587 .collect::<Result<Vec<_>, _>>()
1588 })
1589 .transpose()?
1590 .unwrap_or_default();
1591
1592 let protobuf_swap_floating_layouts = swap_floating_layouts
1593 .as_ref()
1594 .map(|layouts| {
1595 layouts
1596 .iter()
1597 .map(|l| l.clone().try_into())
1598 .collect::<Result<Vec<_>, _>>()
1599 })
1600 .transpose()?
1601 .unwrap_or_default();
1602
1603 let cwd_string = cwd.as_ref().map(|p| p.display().to_string());
1604
1605 let protobuf_initial_panes = initial_panes
1606 .as_ref()
1607 .map(|panes| {
1608 panes
1609 .iter()
1610 .map(|p| p.clone().try_into())
1611 .collect::<Result<Vec<_>, _>>()
1612 })
1613 .transpose()?
1614 .unwrap_or_default();
1615
1616 let protobuf_first_pane_unblock_condition = first_pane_unblock_condition
1617 .map(|uc| {
1618 let protobuf_uc: ProtobufUnblockCondition = uc.try_into().ok()?;
1619 Some(protobuf_uc as i32)
1620 })
1621 .flatten();
1622
1623 Ok(ProtobufAction {
1624 name: ProtobufActionName::NewTab as i32,
1625 optional_payload: Some(OptionalPayload::NewTabPayload(NewTabPayload {
1626 tiled_layout: protobuf_tiled_layout,
1627 floating_layouts: protobuf_floating_layouts,
1628 swap_tiled_layouts: protobuf_swap_tiled_layouts,
1629 swap_floating_layouts: protobuf_swap_floating_layouts,
1630 tab_name: tab_name.clone(),
1631 should_change_focus_to_new_tab,
1632 cwd: cwd_string,
1633 initial_panes: protobuf_initial_panes,
1634 first_pane_unblock_condition: protobuf_first_pane_unblock_condition,
1635 })),
1636 })
1637 },
1638 Action::GoToNextTab => Ok(ProtobufAction {
1639 name: ProtobufActionName::GoToNextTab as i32,
1640 optional_payload: None,
1641 }),
1642 Action::GoToPreviousTab => Ok(ProtobufAction {
1643 name: ProtobufActionName::GoToPreviousTab as i32,
1644 optional_payload: None,
1645 }),
1646 Action::CloseTab => Ok(ProtobufAction {
1647 name: ProtobufActionName::CloseTab as i32,
1648 optional_payload: None,
1649 }),
1650 Action::GoToTab { index: tab_index } => Ok(ProtobufAction {
1651 name: ProtobufActionName::GoToTab as i32,
1652 optional_payload: Some(OptionalPayload::GoToTabPayload(tab_index)),
1653 }),
1654 Action::GoToTabName {
1655 name: tab_name,
1656 create,
1657 } => Ok(ProtobufAction {
1658 name: ProtobufActionName::GoToTabName as i32,
1659 optional_payload: Some(OptionalPayload::GoToTabNamePayload(GoToTabNamePayload {
1660 tab_name,
1661 create,
1662 })),
1663 }),
1664 Action::ToggleTab => Ok(ProtobufAction {
1665 name: ProtobufActionName::ToggleTab as i32,
1666 optional_payload: None,
1667 }),
1668 Action::TabNameInput { input: bytes } => Ok(ProtobufAction {
1669 name: ProtobufActionName::TabNameInput as i32,
1670 optional_payload: Some(OptionalPayload::TabNameInputPayload(bytes)),
1671 }),
1672 Action::UndoRenameTab => Ok(ProtobufAction {
1673 name: ProtobufActionName::UndoRenameTab as i32,
1674 optional_payload: None,
1675 }),
1676 Action::MoveTab { direction } => {
1677 let direction: ProtobufMoveTabDirection = direction.try_into()?;
1678 Ok(ProtobufAction {
1679 name: ProtobufActionName::MoveTab as i32,
1680 optional_payload: Some(OptionalPayload::MoveTabPayload(direction as i32)),
1681 })
1682 },
1683 Action::Run {
1684 command: run_command_action,
1685 near_current_pane: _,
1686 no_focus: _,
1687 } => {
1688 let run_command_action: ProtobufRunCommandAction = run_command_action.try_into()?;
1689 Ok(ProtobufAction {
1690 name: ProtobufActionName::Run as i32,
1691 optional_payload: Some(OptionalPayload::RunPayload(run_command_action)),
1692 })
1693 },
1694 Action::Detach => Ok(ProtobufAction {
1695 name: ProtobufActionName::Detach as i32,
1696 optional_payload: None,
1697 }),
1698 Action::SetDarkTheme => Ok(ProtobufAction {
1699 name: ProtobufActionName::SetDarkTheme as i32,
1700 optional_payload: None,
1701 }),
1702 Action::SetLightTheme => Ok(ProtobufAction {
1703 name: ProtobufActionName::SetLightTheme as i32,
1704 optional_payload: None,
1705 }),
1706 Action::ToggleTheme => Ok(ProtobufAction {
1707 name: ProtobufActionName::ToggleTheme as i32,
1708 optional_payload: None,
1709 }),
1710 Action::LaunchOrFocusPlugin {
1711 plugin: run_plugin_or_alias,
1712 should_float,
1713 move_to_focused_tab,
1714 should_open_in_place,
1715 close_replaced_pane: _close_replaced_pane,
1716 skip_cache: skip_plugin_cache,
1717 ..
1718 } => {
1719 let configuration = run_plugin_or_alias.get_configuration().unwrap_or_default();
1720 Ok(ProtobufAction {
1721 name: ProtobufActionName::LaunchOrFocusPlugin as i32,
1722 optional_payload: Some(OptionalPayload::LaunchOrFocusPluginPayload(
1723 LaunchOrFocusPluginPayload {
1724 plugin_url: run_plugin_or_alias.location_string(),
1725 should_float,
1726 move_to_focused_tab,
1727 should_open_in_place,
1728 plugin_configuration: Some(configuration.try_into()?),
1729 skip_plugin_cache,
1730 },
1731 )),
1732 })
1733 },
1734 Action::LaunchPlugin {
1735 plugin: run_plugin_or_alias,
1736 should_float,
1737 should_open_in_place,
1738 close_replaced_pane: _close_replaced_pane,
1739 skip_cache: skip_plugin_cache,
1740 cwd: _cwd,
1741 ..
1742 } => {
1743 let configuration = run_plugin_or_alias.get_configuration().unwrap_or_default();
1744 Ok(ProtobufAction {
1745 name: ProtobufActionName::LaunchPlugin as i32,
1746 optional_payload: Some(OptionalPayload::LaunchOrFocusPluginPayload(
1747 LaunchOrFocusPluginPayload {
1748 plugin_url: run_plugin_or_alias.location_string(),
1749 should_float,
1750 move_to_focused_tab: false,
1751 should_open_in_place,
1752 plugin_configuration: Some(configuration.try_into()?),
1753 skip_plugin_cache,
1754 },
1755 )),
1756 })
1757 },
1758 Action::MouseEvent { event } => {
1759 let payload: ProtobufMouseEventPayload = event.try_into()?;
1760 Ok(ProtobufAction {
1761 name: ProtobufActionName::MouseEvent as i32,
1762 optional_payload: Some(OptionalPayload::MouseEventPayload(payload)),
1763 })
1764 },
1765 Action::SearchInput { input: bytes } => Ok(ProtobufAction {
1766 name: ProtobufActionName::SearchInput as i32,
1767 optional_payload: Some(OptionalPayload::SearchInputPayload(bytes)),
1768 }),
1769 Action::Search {
1770 direction: search_direction,
1771 } => {
1772 let search_direction: ProtobufSearchDirection = search_direction.try_into()?;
1773 Ok(ProtobufAction {
1774 name: ProtobufActionName::Search as i32,
1775 optional_payload: Some(OptionalPayload::SearchPayload(search_direction as i32)),
1776 })
1777 },
1778 Action::SearchToggleOption {
1779 option: search_option,
1780 } => {
1781 let search_option: ProtobufSearchOption = search_option.try_into()?;
1782 Ok(ProtobufAction {
1783 name: ProtobufActionName::SearchToggleOption as i32,
1784 optional_payload: Some(OptionalPayload::SearchToggleOptionPayload(
1785 search_option as i32,
1786 )),
1787 })
1788 },
1789 Action::ToggleMouseMode => Ok(ProtobufAction {
1790 name: ProtobufActionName::ToggleMouseMode as i32,
1791 optional_payload: None,
1792 }),
1793 Action::PreviousSwapLayout => Ok(ProtobufAction {
1794 name: ProtobufActionName::PreviousSwapLayout as i32,
1795 optional_payload: None,
1796 }),
1797 Action::NextSwapLayout => Ok(ProtobufAction {
1798 name: ProtobufActionName::NextSwapLayout as i32,
1799 optional_payload: None,
1800 }),
1801 Action::OverrideLayout {
1802 tabs,
1803 retain_existing_terminal_panes,
1804 retain_existing_plugin_panes,
1805 apply_only_to_active_tab,
1806 } => Ok(ProtobufAction {
1807 name: ProtobufActionName::OverrideLayout as i32,
1808 optional_payload: Some(OptionalPayload::OverrideLayoutPayload(
1809 OverrideLayoutPayload {
1810 tabs: tabs
1811 .into_iter()
1812 .map(|t| t.try_into())
1813 .collect::<Result<Vec<_>, _>>()?,
1814 retain_existing_terminal_panes,
1815 retain_existing_plugin_panes,
1816 apply_only_to_active_tab,
1817 },
1818 )),
1819 }),
1820 Action::QueryTabNames => Ok(ProtobufAction {
1821 name: ProtobufActionName::QueryTabNames as i32,
1822 optional_payload: None,
1823 }),
1824 Action::NewTiledPluginPane {
1825 plugin: run_plugin,
1826 pane_name,
1827 skip_cache: skip_plugin_cache,
1828 cwd: _cwd,
1829 ..
1830 } => Ok(ProtobufAction {
1831 name: ProtobufActionName::NewTiledPluginPane as i32,
1832 optional_payload: Some(OptionalPayload::NewTiledPluginPanePayload(
1833 NewPluginPanePayload {
1834 plugin_url: run_plugin.location_string(),
1835 pane_name,
1836 skip_plugin_cache,
1837 },
1838 )),
1839 }),
1840 Action::NewFloatingPluginPane {
1841 plugin: run_plugin,
1842 pane_name,
1843 skip_cache: skip_plugin_cache,
1844 cwd: _cwd,
1845 coordinates: _coordinates,
1846 ..
1847 } => Ok(ProtobufAction {
1848 name: ProtobufActionName::NewFloatingPluginPane as i32,
1849 optional_payload: Some(OptionalPayload::NewFloatingPluginPanePayload(
1850 NewPluginPanePayload {
1851 plugin_url: run_plugin.location_string(),
1852 pane_name,
1853 skip_plugin_cache,
1854 },
1855 )),
1856 }),
1857 Action::StartOrReloadPlugin { plugin: run_plugin } => Ok(ProtobufAction {
1858 name: ProtobufActionName::StartOrReloadPlugin as i32,
1859 optional_payload: Some(OptionalPayload::StartOrReloadPluginPayload(
1860 run_plugin.location_string(),
1861 )),
1862 }),
1863 Action::CloseTerminalPane {
1864 pane_id: terminal_pane_id,
1865 } => Ok(ProtobufAction {
1866 name: ProtobufActionName::CloseTerminalPane as i32,
1867 optional_payload: Some(OptionalPayload::CloseTerminalPanePayload(terminal_pane_id)),
1868 }),
1869 Action::ClosePluginPane {
1870 pane_id: plugin_pane_id,
1871 } => Ok(ProtobufAction {
1872 name: ProtobufActionName::ClosePluginPane as i32,
1873 optional_payload: Some(OptionalPayload::ClosePluginPanePayload(plugin_pane_id)),
1874 }),
1875 Action::FocusTerminalPaneWithId {
1876 pane_id: terminal_pane_id,
1877 should_float_if_hidden,
1878 should_be_in_place_if_hidden,
1879 } => Ok(ProtobufAction {
1880 name: ProtobufActionName::FocusTerminalPaneWithId as i32,
1881 optional_payload: Some(OptionalPayload::FocusTerminalPaneWithIdPayload(
1882 PaneIdAndShouldFloat {
1883 pane_id: terminal_pane_id,
1884 should_float: should_float_if_hidden,
1885 should_be_in_place: should_be_in_place_if_hidden,
1886 },
1887 )),
1888 }),
1889 Action::FocusPluginPaneWithId {
1890 pane_id: plugin_pane_id,
1891 should_float_if_hidden,
1892 should_be_in_place_if_hidden,
1893 } => Ok(ProtobufAction {
1894 name: ProtobufActionName::FocusPluginPaneWithId as i32,
1895 optional_payload: Some(OptionalPayload::FocusPluginPaneWithIdPayload(
1896 PaneIdAndShouldFloat {
1897 pane_id: plugin_pane_id,
1898 should_float: should_float_if_hidden,
1899 should_be_in_place: should_be_in_place_if_hidden,
1900 },
1901 )),
1902 }),
1903 Action::RenameTerminalPane {
1904 pane_id: terminal_pane_id,
1905 name: new_name,
1906 } => Ok(ProtobufAction {
1907 name: ProtobufActionName::RenameTerminalPane as i32,
1908 optional_payload: Some(OptionalPayload::RenameTerminalPanePayload(IdAndName {
1909 name: new_name,
1910 id: terminal_pane_id,
1911 })),
1912 }),
1913 Action::RenamePluginPane {
1914 pane_id: plugin_pane_id,
1915 name: new_name,
1916 } => Ok(ProtobufAction {
1917 name: ProtobufActionName::RenamePluginPane as i32,
1918 optional_payload: Some(OptionalPayload::RenamePluginPanePayload(IdAndName {
1919 name: new_name,
1920 id: plugin_pane_id,
1921 })),
1922 }),
1923 Action::RenameTab {
1924 tab_index,
1925 name: new_name,
1926 } => Ok(ProtobufAction {
1927 name: ProtobufActionName::RenameTab as i32,
1928 optional_payload: Some(OptionalPayload::RenameTabPayload(IdAndName {
1929 name: new_name,
1930 id: tab_index,
1931 })),
1932 }),
1933 Action::BreakPane => Ok(ProtobufAction {
1934 name: ProtobufActionName::BreakPane as i32,
1935 optional_payload: None,
1936 }),
1937 Action::BreakPaneRight => Ok(ProtobufAction {
1938 name: ProtobufActionName::BreakPaneRight as i32,
1939 optional_payload: None,
1940 }),
1941 Action::BreakPaneLeft => Ok(ProtobufAction {
1942 name: ProtobufActionName::BreakPaneLeft as i32,
1943 optional_payload: None,
1944 }),
1945 Action::RenameSession { name: session_name } => Ok(ProtobufAction {
1946 name: ProtobufActionName::RenameSession as i32,
1947 optional_payload: Some(OptionalPayload::RenameSessionPayload(session_name)),
1948 }),
1949 Action::KeybindPipe { .. } => Ok(ProtobufAction {
1950 name: ProtobufActionName::KeybindPipe as i32,
1951 optional_payload: None,
1952 }),
1953 Action::TogglePanePinned { .. } => Ok(ProtobufAction {
1954 name: ProtobufActionName::TogglePanePinned as i32,
1955 optional_payload: None,
1956 }),
1957 Action::TogglePaneInGroup { .. } => Ok(ProtobufAction {
1958 name: ProtobufActionName::TogglePaneInGroup as i32,
1959 optional_payload: None,
1960 }),
1961 Action::ToggleGroupMarking { .. } => Ok(ProtobufAction {
1962 name: ProtobufActionName::ToggleGroupMarking as i32,
1963 optional_payload: None,
1964 }),
1965 Action::NewStackedPane {
1966 command: _,
1967 pane_name: _,
1968 near_current_pane: _,
1969 ..
1970 } => Ok(ProtobufAction {
1971 name: ProtobufActionName::NewStackedPane as i32,
1972 optional_payload: None,
1973 }),
1974 Action::NewBlockingPane {
1975 placement,
1976 pane_name,
1977 command,
1978 unblock_condition,
1979 near_current_pane,
1980 ..
1981 } => {
1982 let placement: ProtobufNewPanePlacement = placement.try_into()?;
1983 let command = command.and_then(|c| {
1984 let protobuf_command: ProtobufRunCommandAction = c.try_into().ok()?;
1985 Some(protobuf_command)
1986 });
1987 let unblock_condition = unblock_condition
1988 .map(|uc| {
1989 let protobuf_uc: ProtobufUnblockCondition = uc.try_into().ok()?;
1990 Some(protobuf_uc as i32)
1991 })
1992 .flatten();
1993 Ok(ProtobufAction {
1994 name: ProtobufActionName::NewBlockingPane as i32,
1995 optional_payload: Some(OptionalPayload::NewBlockingPanePayload(
1996 NewBlockingPanePayload {
1997 placement: Some(placement),
1998 pane_name,
1999 command,
2000 unblock_condition,
2001 near_current_pane,
2002 },
2003 )),
2004 })
2005 },
2006 Action::NewInPlacePane {
2007 command: run_command_action,
2008 pane_name,
2009 near_current_pane,
2010 pane_id_to_replace,
2011 close_replaced_pane,
2012 ..
2013 } => {
2014 let command = run_command_action.and_then(|r| {
2015 let mut protobuf_run_command_action: ProtobufRunCommandAction =
2016 r.try_into().ok()?;
2017 let pane_name = pane_name.and_then(|n| n.try_into().ok());
2018 protobuf_run_command_action.pane_name = pane_name;
2019 Some(protobuf_run_command_action)
2020 });
2021 let pane_id_to_replace = pane_id_to_replace.and_then(|p| p.try_into().ok());
2022 Ok(ProtobufAction {
2023 name: ProtobufActionName::NewInPlacePane as i32,
2024 optional_payload: Some(OptionalPayload::NewInPlacePanePayload(
2025 NewInPlacePanePayload {
2026 command,
2027 pane_name: None, near_current_pane,
2029 pane_id_to_replace,
2030 close_replace_pane: close_replaced_pane,
2031 },
2032 )),
2033 })
2034 },
2035 Action::FocusHostSession => Ok(ProtobufAction {
2036 name: ProtobufActionName::FocusHostSession as i32,
2037 optional_payload: None,
2038 }),
2039 Action::FocusGuestSession => Ok(ProtobufAction {
2040 name: ProtobufActionName::FocusGuestSession as i32,
2041 optional_payload: None,
2042 }),
2043 Action::ToggleHostFullscreen => Ok(ProtobufAction {
2044 name: ProtobufActionName::ToggleHostFullscreen as i32,
2045 optional_payload: None,
2046 }),
2047 Action::NoOp
2048 | Action::Confirm
2049 | Action::NewInPlacePluginPane {
2050 plugin: _,
2051 pane_name: _,
2052 skip_cache: _,
2053 close_replaced_pane: _,
2054 ..
2055 }
2056 | Action::Deny
2057 | Action::Copy
2058 | Action::DumpLayout
2059 | Action::CliPipe { .. }
2060 | Action::ListClients
2061 | Action::ListPanes { .. }
2062 | Action::StackPanes { pane_ids: _ }
2063 | Action::ChangeFloatingPaneCoordinates {
2064 pane_id: _,
2065 coordinates: _,
2066 }
2067 | Action::TogglePaneBorderless { pane_id: _ }
2068 | Action::SetPaneBorderless { .. }
2069 | Action::SkipConfirm { action: _ }
2070 | Action::SwitchSession { .. }
2071 | Action::SaveSession
2072 | Action::ListTabs { .. }
2073 | Action::CurrentTabInfo { .. }
2074 | Action::SetPaneColor { .. } => Err("Unsupported action"),
2075 }
2076 }
2077}
2078
2079impl TryFrom<ProtobufSearchOption> for SearchOption {
2080 type Error = &'static str;
2081 fn try_from(protobuf_search_option: ProtobufSearchOption) -> Result<Self, &'static str> {
2082 match protobuf_search_option {
2083 ProtobufSearchOption::CaseSensitivity => Ok(SearchOption::CaseSensitivity),
2084 ProtobufSearchOption::WholeWord => Ok(SearchOption::WholeWord),
2085 ProtobufSearchOption::Wrap => Ok(SearchOption::Wrap),
2086 }
2087 }
2088}
2089
2090impl TryFrom<SearchOption> for ProtobufSearchOption {
2091 type Error = &'static str;
2092 fn try_from(search_option: SearchOption) -> Result<Self, &'static str> {
2093 match search_option {
2094 SearchOption::CaseSensitivity => Ok(ProtobufSearchOption::CaseSensitivity),
2095 SearchOption::WholeWord => Ok(ProtobufSearchOption::WholeWord),
2096 SearchOption::Wrap => Ok(ProtobufSearchOption::Wrap),
2097 }
2098 }
2099}
2100
2101impl TryFrom<ProtobufSearchDirection> for SearchDirection {
2102 type Error = &'static str;
2103 fn try_from(protobuf_search_direction: ProtobufSearchDirection) -> Result<Self, &'static str> {
2104 match protobuf_search_direction {
2105 ProtobufSearchDirection::Up => Ok(SearchDirection::Up),
2106 ProtobufSearchDirection::Down => Ok(SearchDirection::Down),
2107 }
2108 }
2109}
2110
2111impl TryFrom<SearchDirection> for ProtobufSearchDirection {
2112 type Error = &'static str;
2113 fn try_from(search_direction: SearchDirection) -> Result<Self, &'static str> {
2114 match search_direction {
2115 SearchDirection::Up => Ok(ProtobufSearchDirection::Up),
2116 SearchDirection::Down => Ok(ProtobufSearchDirection::Down),
2117 }
2118 }
2119}
2120
2121impl TryFrom<ProtobufMoveTabDirection> for Direction {
2122 type Error = &'static str;
2123 fn try_from(
2124 protobuf_move_tab_direction: ProtobufMoveTabDirection,
2125 ) -> Result<Self, &'static str> {
2126 match protobuf_move_tab_direction {
2127 ProtobufMoveTabDirection::Left => Ok(Direction::Left),
2128 ProtobufMoveTabDirection::Right => Ok(Direction::Right),
2129 }
2130 }
2131}
2132
2133impl TryFrom<Direction> for ProtobufMoveTabDirection {
2134 type Error = &'static str;
2135 fn try_from(direction: Direction) -> Result<Self, &'static str> {
2136 match direction {
2137 Direction::Left => Ok(ProtobufMoveTabDirection::Left),
2138 Direction::Right => Ok(ProtobufMoveTabDirection::Right),
2139 _ => Err("Wrong direction for ProtobufMoveTabDirection"),
2140 }
2141 }
2142}
2143
2144impl TryFrom<ProtobufRunCommandAction> for RunCommandAction {
2145 type Error = &'static str;
2146 fn try_from(
2147 protobuf_run_command_action: ProtobufRunCommandAction,
2148 ) -> Result<Self, &'static str> {
2149 let command = PathBuf::from(protobuf_run_command_action.command);
2150 let args: Vec<String> = protobuf_run_command_action.args;
2151 let cwd: Option<PathBuf> = protobuf_run_command_action.cwd.map(|c| PathBuf::from(c));
2152 let direction: Option<Direction> = protobuf_run_command_action
2153 .direction
2154 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
2155 .and_then(|d| d.try_into().ok());
2156 let hold_on_close = protobuf_run_command_action.hold_on_close;
2157 let hold_on_start = protobuf_run_command_action.hold_on_start;
2158 Ok(RunCommandAction {
2159 command,
2160 args,
2161 cwd,
2162 direction,
2163 hold_on_close,
2164 hold_on_start,
2165 ..Default::default()
2166 })
2167 }
2168}
2169
2170impl TryFrom<RunCommandAction> for ProtobufRunCommandAction {
2171 type Error = &'static str;
2172 fn try_from(run_command_action: RunCommandAction) -> Result<Self, &'static str> {
2173 let command = run_command_action.command.display().to_string();
2174 let args: Vec<String> = run_command_action.args;
2175 let cwd = run_command_action.cwd.map(|c| c.display().to_string());
2176 let direction = run_command_action.direction.and_then(|p| {
2177 let direction: ProtobufResizeDirection = p.try_into().ok()?;
2178 Some(direction as i32)
2179 });
2180 let hold_on_close = run_command_action.hold_on_close;
2181 let hold_on_start = run_command_action.hold_on_start;
2182 Ok(ProtobufRunCommandAction {
2183 command,
2184 args,
2185 cwd,
2186 direction,
2187 hold_on_close,
2188 hold_on_start,
2189 pane_name: None,
2190 })
2191 }
2192}
2193
2194impl TryFrom<ProtobufPosition> for Position {
2195 type Error = &'static str;
2196 fn try_from(protobuf_position: ProtobufPosition) -> Result<Self, &'static str> {
2197 Ok(Position::new(
2198 protobuf_position.line as i32,
2199 protobuf_position.column as u16,
2200 ))
2201 }
2202}
2203
2204impl TryFrom<Position> for ProtobufPosition {
2205 type Error = &'static str;
2206 fn try_from(position: Position) -> Result<Self, &'static str> {
2207 Ok(ProtobufPosition {
2208 line: position.line.0 as i64,
2209 column: position.column.0 as i64,
2210 })
2211 }
2212}
2213
2214impl TryFrom<ProtobufMouseEventPayload> for MouseEvent {
2215 type Error = &'static str;
2216 fn try_from(protobuf_event: ProtobufMouseEventPayload) -> Result<Self, &'static str> {
2217 Ok(MouseEvent {
2218 event_type: match protobuf_event.event_type as u32 {
2219 0 => MouseEventType::Press,
2220 1 => MouseEventType::Release,
2221 _ => MouseEventType::Motion,
2222 },
2223 left: protobuf_event.left as bool,
2224 right: protobuf_event.right as bool,
2225 middle: protobuf_event.middle as bool,
2226 wheel_up: protobuf_event.wheel_up as bool,
2227 wheel_down: protobuf_event.wheel_down as bool,
2228 wheel_left: protobuf_event.wheel_left as bool,
2229 wheel_right: protobuf_event.wheel_right as bool,
2230 shift: protobuf_event.shift as bool,
2231 alt: protobuf_event.alt as bool,
2232 ctrl: protobuf_event.ctrl as bool,
2233 position: Position::new(protobuf_event.line as i32, protobuf_event.column as u16),
2234 })
2235 }
2236}
2237
2238impl TryFrom<MouseEvent> for ProtobufMouseEventPayload {
2239 type Error = &'static str;
2240 fn try_from(event: MouseEvent) -> Result<Self, &'static str> {
2241 Ok(ProtobufMouseEventPayload {
2242 event_type: match event.event_type {
2243 MouseEventType::Press => 0,
2244 MouseEventType::Release => 1,
2245 MouseEventType::Motion => 2,
2246 } as u32,
2247 left: event.left as bool,
2248 right: event.right as bool,
2249 middle: event.middle as bool,
2250 wheel_up: event.wheel_up as bool,
2251 wheel_down: event.wheel_down as bool,
2252 wheel_left: event.wheel_left as bool,
2253 wheel_right: event.wheel_right as bool,
2254 shift: event.shift as bool,
2255 alt: event.alt as bool,
2256 ctrl: event.ctrl as bool,
2257 line: event.position.line.0 as i64,
2258 column: event.position.column.0 as i64,
2259 })
2260 }
2261}
2262
2263impl TryFrom<ProtobufPluginConfiguration> for PluginUserConfiguration {
2264 type Error = &'static str;
2265 fn try_from(plugin_configuration: ProtobufPluginConfiguration) -> Result<Self, &'static str> {
2266 let mut converted = BTreeMap::new();
2267 for name_and_value in plugin_configuration.name_and_value {
2268 converted.insert(name_and_value.name, name_and_value.value);
2269 }
2270 Ok(PluginUserConfiguration::new(converted))
2271 }
2272}
2273
2274impl TryFrom<PluginUserConfiguration> for ProtobufPluginConfiguration {
2275 type Error = &'static str;
2276 fn try_from(plugin_configuration: PluginUserConfiguration) -> Result<Self, &'static str> {
2277 let mut converted = vec![];
2278 for (name, value) in plugin_configuration.inner() {
2279 let name_and_value = ProtobufNameAndValue {
2280 name: name.to_owned(),
2281 value: value.to_owned(),
2282 };
2283 converted.push(name_and_value);
2284 }
2285 Ok(ProtobufPluginConfiguration {
2286 name_and_value: converted,
2287 })
2288 }
2289}
2290
2291impl TryFrom<&ProtobufPluginConfiguration> for BTreeMap<String, String> {
2292 type Error = &'static str;
2293 fn try_from(plugin_configuration: &ProtobufPluginConfiguration) -> Result<Self, &'static str> {
2294 let mut converted = BTreeMap::new();
2295 for name_and_value in &plugin_configuration.name_and_value {
2296 converted.insert(
2297 name_and_value.name.to_owned(),
2298 name_and_value.value.to_owned(),
2299 );
2300 }
2301 Ok(converted)
2302 }
2303}
2304
2305impl TryFrom<ProtobufKeyWithModifier> for KeyWithModifier {
2306 type Error = &'static str;
2307 fn try_from(protobuf_key: ProtobufKeyWithModifier) -> Result<Self, &'static str> {
2308 let bare_key = match ProtobufBareKey::try_from(protobuf_key.bare_key).ok() {
2309 Some(ProtobufBareKey::PageDown) => crate::data::BareKey::PageDown,
2310 Some(ProtobufBareKey::PageUp) => crate::data::BareKey::PageUp,
2311 Some(ProtobufBareKey::Left) => crate::data::BareKey::Left,
2312 Some(ProtobufBareKey::Down) => crate::data::BareKey::Down,
2313 Some(ProtobufBareKey::Up) => crate::data::BareKey::Up,
2314 Some(ProtobufBareKey::Right) => crate::data::BareKey::Right,
2315 Some(ProtobufBareKey::Home) => crate::data::BareKey::Home,
2316 Some(ProtobufBareKey::End) => crate::data::BareKey::End,
2317 Some(ProtobufBareKey::Backspace) => crate::data::BareKey::Backspace,
2318 Some(ProtobufBareKey::Delete) => crate::data::BareKey::Delete,
2319 Some(ProtobufBareKey::Insert) => crate::data::BareKey::Insert,
2320 Some(ProtobufBareKey::F1) => crate::data::BareKey::F(1),
2321 Some(ProtobufBareKey::F2) => crate::data::BareKey::F(2),
2322 Some(ProtobufBareKey::F3) => crate::data::BareKey::F(3),
2323 Some(ProtobufBareKey::F4) => crate::data::BareKey::F(4),
2324 Some(ProtobufBareKey::F5) => crate::data::BareKey::F(5),
2325 Some(ProtobufBareKey::F6) => crate::data::BareKey::F(6),
2326 Some(ProtobufBareKey::F7) => crate::data::BareKey::F(7),
2327 Some(ProtobufBareKey::F8) => crate::data::BareKey::F(8),
2328 Some(ProtobufBareKey::F9) => crate::data::BareKey::F(9),
2329 Some(ProtobufBareKey::F10) => crate::data::BareKey::F(10),
2330 Some(ProtobufBareKey::F11) => crate::data::BareKey::F(11),
2331 Some(ProtobufBareKey::F12) => crate::data::BareKey::F(12),
2332 Some(ProtobufBareKey::Char) => {
2333 if let Some(character) = protobuf_key.character {
2334 let ch = character
2335 .chars()
2336 .next()
2337 .ok_or("BareKey::Char requires a character")?;
2338 crate::data::BareKey::Char(ch)
2339 } else {
2340 return Err("BareKey::Char requires a character");
2341 }
2342 },
2343 Some(ProtobufBareKey::Tab) => crate::data::BareKey::Tab,
2344 Some(ProtobufBareKey::Esc) => crate::data::BareKey::Esc,
2345 Some(ProtobufBareKey::Enter) => crate::data::BareKey::Enter,
2346 Some(ProtobufBareKey::CapsLock) => crate::data::BareKey::CapsLock,
2347 Some(ProtobufBareKey::ScrollLock) => crate::data::BareKey::ScrollLock,
2348 Some(ProtobufBareKey::NumLock) => crate::data::BareKey::NumLock,
2349 Some(ProtobufBareKey::PrintScreen) => crate::data::BareKey::PrintScreen,
2350 Some(ProtobufBareKey::Pause) => crate::data::BareKey::Pause,
2351 Some(ProtobufBareKey::Menu) => crate::data::BareKey::Menu,
2352 _ => return Err("Unknown BareKey"),
2353 };
2354
2355 let mut key_modifiers = std::collections::BTreeSet::new();
2356 for modifier in protobuf_key.key_modifiers {
2357 let key_modifier = match ProtobufKeyModifier::try_from(modifier).ok() {
2358 Some(ProtobufKeyModifier::Ctrl) => crate::data::KeyModifier::Ctrl,
2359 Some(ProtobufKeyModifier::Alt) => crate::data::KeyModifier::Alt,
2360 Some(ProtobufKeyModifier::Shift) => crate::data::KeyModifier::Shift,
2361 Some(ProtobufKeyModifier::Super) => crate::data::KeyModifier::Super,
2362 _ => continue,
2363 };
2364 key_modifiers.insert(key_modifier);
2365 }
2366
2367 Ok(KeyWithModifier {
2368 bare_key,
2369 key_modifiers,
2370 })
2371 }
2372}
2373
2374impl TryFrom<KeyWithModifier> for ProtobufKeyWithModifier {
2375 type Error = &'static str;
2376 fn try_from(key: KeyWithModifier) -> Result<Self, &'static str> {
2377 let (bare_key, character) = match key.bare_key {
2378 crate::data::BareKey::PageDown => (ProtobufBareKey::PageDown as i32, None),
2379 crate::data::BareKey::PageUp => (ProtobufBareKey::PageUp as i32, None),
2380 crate::data::BareKey::Left => (ProtobufBareKey::Left as i32, None),
2381 crate::data::BareKey::Down => (ProtobufBareKey::Down as i32, None),
2382 crate::data::BareKey::Up => (ProtobufBareKey::Up as i32, None),
2383 crate::data::BareKey::Right => (ProtobufBareKey::Right as i32, None),
2384 crate::data::BareKey::Home => (ProtobufBareKey::Home as i32, None),
2385 crate::data::BareKey::End => (ProtobufBareKey::End as i32, None),
2386 crate::data::BareKey::Backspace => (ProtobufBareKey::Backspace as i32, None),
2387 crate::data::BareKey::Delete => (ProtobufBareKey::Delete as i32, None),
2388 crate::data::BareKey::Insert => (ProtobufBareKey::Insert as i32, None),
2389 crate::data::BareKey::F(1) => (ProtobufBareKey::F1 as i32, None),
2390 crate::data::BareKey::F(2) => (ProtobufBareKey::F2 as i32, None),
2391 crate::data::BareKey::F(3) => (ProtobufBareKey::F3 as i32, None),
2392 crate::data::BareKey::F(4) => (ProtobufBareKey::F4 as i32, None),
2393 crate::data::BareKey::F(5) => (ProtobufBareKey::F5 as i32, None),
2394 crate::data::BareKey::F(6) => (ProtobufBareKey::F6 as i32, None),
2395 crate::data::BareKey::F(7) => (ProtobufBareKey::F7 as i32, None),
2396 crate::data::BareKey::F(8) => (ProtobufBareKey::F8 as i32, None),
2397 crate::data::BareKey::F(9) => (ProtobufBareKey::F9 as i32, None),
2398 crate::data::BareKey::F(10) => (ProtobufBareKey::F10 as i32, None),
2399 crate::data::BareKey::F(11) => (ProtobufBareKey::F11 as i32, None),
2400 crate::data::BareKey::F(12) => (ProtobufBareKey::F12 as i32, None),
2401 crate::data::BareKey::Char(c) => (ProtobufBareKey::Char as i32, Some(c.to_string())),
2402 crate::data::BareKey::Tab => (ProtobufBareKey::Tab as i32, None),
2403 crate::data::BareKey::Esc => (ProtobufBareKey::Esc as i32, None),
2404 crate::data::BareKey::Enter => (ProtobufBareKey::Enter as i32, None),
2405 crate::data::BareKey::CapsLock => (ProtobufBareKey::CapsLock as i32, None),
2406 crate::data::BareKey::ScrollLock => (ProtobufBareKey::ScrollLock as i32, None),
2407 crate::data::BareKey::NumLock => (ProtobufBareKey::NumLock as i32, None),
2408 crate::data::BareKey::PrintScreen => (ProtobufBareKey::PrintScreen as i32, None),
2409 crate::data::BareKey::Pause => (ProtobufBareKey::Pause as i32, None),
2410 crate::data::BareKey::Menu => (ProtobufBareKey::Menu as i32, None),
2411 _ => return Err("Unsupported BareKey"),
2412 };
2413
2414 let key_modifiers: Vec<i32> = key
2415 .key_modifiers
2416 .iter()
2417 .map(|m| match m {
2418 crate::data::KeyModifier::Ctrl => ProtobufKeyModifier::Ctrl as i32,
2419 crate::data::KeyModifier::Alt => ProtobufKeyModifier::Alt as i32,
2420 crate::data::KeyModifier::Shift => ProtobufKeyModifier::Shift as i32,
2421 crate::data::KeyModifier::Super => ProtobufKeyModifier::Super as i32,
2422 })
2423 .collect();
2424
2425 Ok(ProtobufKeyWithModifier {
2426 bare_key,
2427 key_modifiers,
2428 character,
2429 })
2430 }
2431}
2432
2433impl TryFrom<ProtobufUnblockCondition> for UnblockCondition {
2435 type Error = &'static str;
2436 fn try_from(protobuf_uc: ProtobufUnblockCondition) -> Result<Self, &'static str> {
2437 match protobuf_uc {
2438 ProtobufUnblockCondition::UnblockOnExitSuccess => Ok(UnblockCondition::OnExitSuccess),
2439 ProtobufUnblockCondition::UnblockOnExitFailure => Ok(UnblockCondition::OnExitFailure),
2440 ProtobufUnblockCondition::UnblockOnAnyExit => Ok(UnblockCondition::OnAnyExit),
2441 }
2442 }
2443}
2444
2445impl TryFrom<UnblockCondition> for ProtobufUnblockCondition {
2446 type Error = &'static str;
2447 fn try_from(uc: UnblockCondition) -> Result<Self, &'static str> {
2448 match uc {
2449 UnblockCondition::OnExitSuccess => Ok(ProtobufUnblockCondition::UnblockOnExitSuccess),
2450 UnblockCondition::OnExitFailure => Ok(ProtobufUnblockCondition::UnblockOnExitFailure),
2451 UnblockCondition::OnAnyExit => Ok(ProtobufUnblockCondition::UnblockOnAnyExit),
2452 }
2453 }
2454}
2455
2456impl TryFrom<i32> for UnblockCondition {
2457 type Error = &'static str;
2458 fn try_from(value: i32) -> Result<Self, &'static str> {
2459 match ProtobufUnblockCondition::try_from(value).ok() {
2460 Some(uc) => uc.try_into(),
2461 None => Err("Invalid UnblockCondition value"),
2462 }
2463 }
2464}
2465
2466impl TryFrom<ProtobufPaneId> for PaneId {
2468 type Error = &'static str;
2469 fn try_from(protobuf_pane_id: ProtobufPaneId) -> Result<Self, &'static str> {
2470 use super::generated_api::api::action::pane_id::PaneIdVariant;
2471
2472 match protobuf_pane_id.pane_id_variant {
2473 Some(PaneIdVariant::Terminal(id)) => Ok(PaneId::Terminal(id)),
2474 Some(PaneIdVariant::Plugin(id)) => Ok(PaneId::Plugin(id)),
2475 None => Err("PaneId must have either terminal or plugin id"),
2476 }
2477 }
2478}
2479
2480impl TryFrom<PaneId> for ProtobufPaneId {
2481 type Error = &'static str;
2482 fn try_from(pane_id: PaneId) -> Result<Self, &'static str> {
2483 use super::generated_api::api::action::pane_id::PaneIdVariant;
2484
2485 let pane_id_variant = match pane_id {
2486 PaneId::Terminal(id) => Some(PaneIdVariant::Terminal(id)),
2487 PaneId::Plugin(id) => Some(PaneIdVariant::Plugin(id)),
2488 };
2489 Ok(ProtobufPaneId { pane_id_variant })
2490 }
2491}
2492
2493impl TryFrom<ProtobufSplitSize> for SplitSize {
2495 type Error = &'static str;
2496 fn try_from(protobuf_split_size: ProtobufSplitSize) -> Result<Self, &'static str> {
2497 use super::generated_api::api::action::split_size::SplitSizeVariant;
2498
2499 match protobuf_split_size.split_size_variant {
2500 Some(SplitSizeVariant::Percent(p)) => Ok(SplitSize::Percent(p as usize)),
2501 Some(SplitSizeVariant::Fixed(f)) => Ok(SplitSize::Fixed(f as usize)),
2502 None => Err("SplitSize must have either percent or fixed value"),
2503 }
2504 }
2505}
2506
2507impl TryFrom<SplitSize> for ProtobufSplitSize {
2508 type Error = &'static str;
2509 fn try_from(split_size: SplitSize) -> Result<Self, &'static str> {
2510 use super::generated_api::api::action::split_size::SplitSizeVariant;
2511
2512 let split_size_variant = match split_size {
2513 SplitSize::Percent(p) => Some(SplitSizeVariant::Percent(p as u32)),
2514 SplitSize::Fixed(f) => Some(SplitSizeVariant::Fixed(f as u32)),
2515 };
2516 Ok(ProtobufSplitSize { split_size_variant })
2517 }
2518}
2519
2520impl TryFrom<ProtobufSplitSize> for PercentOrFixed {
2521 type Error = &'static str;
2522 fn try_from(protobuf_split_size: ProtobufSplitSize) -> Result<Self, &'static str> {
2523 use super::generated_api::api::action::split_size::SplitSizeVariant;
2524
2525 match protobuf_split_size.split_size_variant {
2526 Some(SplitSizeVariant::Percent(p)) => Ok(PercentOrFixed::Percent(p as usize)),
2527 Some(SplitSizeVariant::Fixed(f)) => Ok(PercentOrFixed::Fixed(f as usize)),
2528 None => Err("PercentOrFixed must have either percent or fixed value"),
2529 }
2530 }
2531}
2532
2533impl TryFrom<PercentOrFixed> for ProtobufSplitSize {
2534 type Error = &'static str;
2535 fn try_from(percent_or_fixed: PercentOrFixed) -> Result<Self, &'static str> {
2536 use super::generated_api::api::action::split_size::SplitSizeVariant;
2537
2538 let split_size_variant = match percent_or_fixed {
2539 PercentOrFixed::Percent(p) => Some(SplitSizeVariant::Percent(p as u32)),
2540 PercentOrFixed::Fixed(f) => Some(SplitSizeVariant::Fixed(f as u32)),
2541 };
2542 Ok(ProtobufSplitSize { split_size_variant })
2543 }
2544}
2545
2546impl TryFrom<ProtobufFloatingPaneCoordinates> for FloatingPaneCoordinates {
2548 type Error = &'static str;
2549 fn try_from(protobuf_coords: ProtobufFloatingPaneCoordinates) -> Result<Self, &'static str> {
2550 Ok(FloatingPaneCoordinates {
2551 x: protobuf_coords.x.and_then(|x| x.try_into().ok()),
2552 y: protobuf_coords.y.and_then(|y| y.try_into().ok()),
2553 width: protobuf_coords.width.and_then(|w| w.try_into().ok()),
2554 height: protobuf_coords.height.and_then(|h| h.try_into().ok()),
2555 pinned: protobuf_coords.pinned,
2556 borderless: protobuf_coords.borderless,
2557 })
2558 }
2559}
2560
2561impl TryFrom<FloatingPaneCoordinates> for ProtobufFloatingPaneCoordinates {
2562 type Error = &'static str;
2563 fn try_from(coords: FloatingPaneCoordinates) -> Result<Self, &'static str> {
2564 Ok(ProtobufFloatingPaneCoordinates {
2565 x: coords.x.and_then(|x| x.try_into().ok()),
2566 y: coords.y.and_then(|y| y.try_into().ok()),
2567 width: coords.width.and_then(|w| w.try_into().ok()),
2568 height: coords.height.and_then(|h| h.try_into().ok()),
2569 pinned: coords.pinned,
2570 borderless: coords.borderless,
2571 })
2572 }
2573}
2574
2575impl TryFrom<ProtobufNewPanePlacement> for NewPanePlacement {
2577 type Error = &'static str;
2578 fn try_from(protobuf_placement: ProtobufNewPanePlacement) -> Result<Self, &'static str> {
2579 use super::generated_api::api::action::new_pane_placement::PlacementVariant;
2580
2581 match protobuf_placement.placement_variant {
2582 Some(PlacementVariant::NoPreference(opts)) => Ok(NewPanePlacement::NoPreference {
2583 borderless: opts.borderless,
2584 }),
2585 Some(PlacementVariant::Tiled(tiled)) => {
2586 let direction = tiled
2587 .direction
2588 .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
2589 .and_then(|d| d.try_into().ok());
2590 Ok(NewPanePlacement::Tiled {
2591 direction,
2592 borderless: tiled.borderless,
2593 })
2594 },
2595 Some(PlacementVariant::Floating(floating)) => {
2596 let coords = floating.coordinates.and_then(|c| c.try_into().ok());
2597 Ok(NewPanePlacement::Floating(coords))
2598 },
2599 Some(PlacementVariant::InPlace(config)) => {
2600 let pane_id_to_replace =
2601 config.pane_id_to_replace.and_then(|id| id.try_into().ok());
2602 Ok(NewPanePlacement::InPlace {
2603 pane_id_to_replace,
2604 close_replaced_pane: config.close_replaced_pane,
2605 borderless: config.borderless,
2606 })
2607 },
2608 Some(PlacementVariant::Stacked(stacked)) => {
2609 let pane_id = stacked.pane_id.and_then(|id| id.try_into().ok());
2610 Ok(NewPanePlacement::Stacked {
2611 pane_id_to_stack_under: pane_id,
2612 borderless: stacked.borderless,
2613 })
2614 },
2615 None => Err("NewPanePlacement must have a placement variant"),
2616 }
2617 }
2618}
2619
2620impl TryFrom<NewPanePlacement> for ProtobufNewPanePlacement {
2621 type Error = &'static str;
2622 fn try_from(placement: NewPanePlacement) -> Result<Self, &'static str> {
2623 use super::generated_api::api::action::new_pane_placement::PlacementVariant;
2624 use super::generated_api::api::action::NoPreferenceOptions;
2625
2626 let placement_variant = match placement {
2627 NewPanePlacement::NoPreference { borderless } => {
2628 Some(PlacementVariant::NoPreference(NoPreferenceOptions {
2629 borderless,
2630 }))
2631 },
2632 NewPanePlacement::Tiled {
2633 direction,
2634 borderless,
2635 } => {
2636 let direction = direction.and_then(|d| {
2637 let protobuf_direction: ProtobufResizeDirection = d.try_into().ok()?;
2638 Some(protobuf_direction as i32)
2639 });
2640 Some(PlacementVariant::Tiled(ProtobufTiledPlacement {
2641 direction,
2642 borderless,
2643 }))
2644 },
2645 NewPanePlacement::Floating(coords) => {
2646 let coordinates = coords.and_then(|c| c.try_into().ok());
2647 Some(PlacementVariant::Floating(ProtobufFloatingPlacement {
2648 coordinates,
2649 }))
2650 },
2651 NewPanePlacement::InPlace {
2652 pane_id_to_replace,
2653 close_replaced_pane,
2654 borderless,
2655 } => {
2656 let pane_id_to_replace = pane_id_to_replace.and_then(|id| id.try_into().ok());
2657 Some(PlacementVariant::InPlace(ProtobufInPlaceConfig {
2658 pane_id_to_replace,
2659 close_replaced_pane,
2660 borderless,
2661 }))
2662 },
2663 NewPanePlacement::Stacked {
2664 pane_id_to_stack_under,
2665 borderless,
2666 } => {
2667 let pane_id = pane_id_to_stack_under.and_then(|id| id.try_into().ok());
2668 Some(PlacementVariant::Stacked(ProtobufStackedPlacement {
2669 pane_id,
2670 borderless,
2671 }))
2672 },
2673 };
2674
2675 Ok(ProtobufNewPanePlacement { placement_variant })
2676 }
2677}
2678
2679impl TryFrom<ProtobufPercentOrFixed> for PercentOrFixed {
2682 type Error = &'static str;
2683 fn try_from(protobuf: ProtobufPercentOrFixed) -> Result<Self, Self::Error> {
2684 use super::generated_api::api::action::percent_or_fixed::SizeType;
2685 match protobuf.size_type {
2686 Some(SizeType::Percent(p)) => Ok(PercentOrFixed::Percent(p as usize)),
2687 Some(SizeType::Fixed(f)) => Ok(PercentOrFixed::Fixed(f as usize)),
2688 None => Err("PercentOrFixed must have a size_type"),
2689 }
2690 }
2691}
2692
2693impl TryFrom<PercentOrFixed> for ProtobufPercentOrFixed {
2694 type Error = &'static str;
2695 fn try_from(internal: PercentOrFixed) -> Result<Self, Self::Error> {
2696 use super::generated_api::api::action::percent_or_fixed::SizeType;
2697 let size_type = match internal {
2698 PercentOrFixed::Percent(p) => Some(SizeType::Percent(p as u32)),
2699 PercentOrFixed::Fixed(f) => Some(SizeType::Fixed(f as u32)),
2700 };
2701 Ok(ProtobufPercentOrFixed { size_type })
2702 }
2703}
2704
2705impl TryFrom<ProtobufSplitDirection> for SplitDirection {
2706 type Error = &'static str;
2707 fn try_from(protobuf: ProtobufSplitDirection) -> Result<Self, Self::Error> {
2708 match protobuf {
2709 ProtobufSplitDirection::Horizontal => Ok(SplitDirection::Horizontal),
2710 ProtobufSplitDirection::Vertical => Ok(SplitDirection::Vertical),
2711 ProtobufSplitDirection::Unspecified => Err("SplitDirection cannot be unspecified"),
2712 }
2713 }
2714}
2715
2716impl TryFrom<SplitDirection> for ProtobufSplitDirection {
2717 type Error = &'static str;
2718 fn try_from(internal: SplitDirection) -> Result<Self, Self::Error> {
2719 Ok(match internal {
2720 SplitDirection::Horizontal => ProtobufSplitDirection::Horizontal,
2721 SplitDirection::Vertical => ProtobufSplitDirection::Vertical,
2722 })
2723 }
2724}
2725
2726impl TryFrom<ProtobufLayoutConstraint> for LayoutConstraint {
2727 type Error = &'static str;
2728 fn try_from(protobuf: ProtobufLayoutConstraint) -> Result<Self, Self::Error> {
2729 match protobuf {
2730 ProtobufLayoutConstraint::MaxPanes => Ok(LayoutConstraint::MaxPanes(0)),
2731 ProtobufLayoutConstraint::MinPanes => Ok(LayoutConstraint::MinPanes(0)),
2732 ProtobufLayoutConstraint::ExactPanes => Ok(LayoutConstraint::ExactPanes(0)),
2733 ProtobufLayoutConstraint::NoConstraint => Ok(LayoutConstraint::NoConstraint),
2734 ProtobufLayoutConstraint::Unspecified => Err("LayoutConstraint cannot be unspecified"),
2735 }
2736 }
2737}
2738
2739impl TryFrom<LayoutConstraint> for ProtobufLayoutConstraint {
2740 type Error = &'static str;
2741 fn try_from(internal: LayoutConstraint) -> Result<Self, Self::Error> {
2742 Ok(match internal {
2743 LayoutConstraint::MaxPanes(_) => ProtobufLayoutConstraint::MaxPanes,
2744 LayoutConstraint::MinPanes(_) => ProtobufLayoutConstraint::MinPanes,
2745 LayoutConstraint::ExactPanes(_) => ProtobufLayoutConstraint::ExactPanes,
2746 LayoutConstraint::NoConstraint => ProtobufLayoutConstraint::NoConstraint,
2747 })
2748 }
2749}
2750
2751impl TryFrom<ProtobufLayoutConstraintWithValue> for LayoutConstraint {
2752 type Error = &'static str;
2753 fn try_from(protobuf: ProtobufLayoutConstraintWithValue) -> Result<Self, Self::Error> {
2754 let constraint_type = ProtobufLayoutConstraint::try_from(protobuf.constraint_type)
2755 .ok()
2756 .ok_or("Invalid constraint type")?;
2757 match constraint_type {
2758 ProtobufLayoutConstraint::MaxPanes => Ok(LayoutConstraint::MaxPanes(
2759 protobuf.value.unwrap_or(0) as usize,
2760 )),
2761 ProtobufLayoutConstraint::MinPanes => Ok(LayoutConstraint::MinPanes(
2762 protobuf.value.unwrap_or(0) as usize,
2763 )),
2764 ProtobufLayoutConstraint::ExactPanes => Ok(LayoutConstraint::ExactPanes(
2765 protobuf.value.unwrap_or(0) as usize,
2766 )),
2767 ProtobufLayoutConstraint::NoConstraint => Ok(LayoutConstraint::NoConstraint),
2768 ProtobufLayoutConstraint::Unspecified => Err("LayoutConstraint cannot be unspecified"),
2769 }
2770 }
2771}
2772
2773impl TryFrom<LayoutConstraint> for ProtobufLayoutConstraintWithValue {
2774 type Error = &'static str;
2775 fn try_from(internal: LayoutConstraint) -> Result<Self, Self::Error> {
2776 let (constraint_type, value) = match internal {
2777 LayoutConstraint::MaxPanes(v) => {
2778 (ProtobufLayoutConstraint::MaxPanes as i32, Some(v as u32))
2779 },
2780 LayoutConstraint::MinPanes(v) => {
2781 (ProtobufLayoutConstraint::MinPanes as i32, Some(v as u32))
2782 },
2783 LayoutConstraint::ExactPanes(v) => {
2784 (ProtobufLayoutConstraint::ExactPanes as i32, Some(v as u32))
2785 },
2786 LayoutConstraint::NoConstraint => (ProtobufLayoutConstraint::NoConstraint as i32, None),
2787 };
2788 Ok(ProtobufLayoutConstraintWithValue {
2789 constraint_type,
2790 value,
2791 })
2792 }
2793}
2794
2795impl TryFrom<ProtobufPluginTag> for PluginTag {
2796 type Error = &'static str;
2797 fn try_from(protobuf: ProtobufPluginTag) -> Result<Self, Self::Error> {
2798 Ok(PluginTag::new(protobuf.tag))
2799 }
2800}
2801
2802impl TryFrom<PluginTag> for ProtobufPluginTag {
2803 type Error = &'static str;
2804 fn try_from(internal: PluginTag) -> Result<Self, Self::Error> {
2805 Ok(ProtobufPluginTag {
2806 tag: internal.into(),
2807 })
2808 }
2809}
2810
2811impl TryFrom<ProtobufPluginUserConfiguration> for PluginUserConfiguration {
2812 type Error = &'static str;
2813 fn try_from(protobuf: ProtobufPluginUserConfiguration) -> Result<Self, Self::Error> {
2814 let btree_map: BTreeMap<String, String> = protobuf.configuration.into_iter().collect();
2815 Ok(PluginUserConfiguration::new(btree_map))
2816 }
2817}
2818
2819impl TryFrom<PluginUserConfiguration> for ProtobufPluginUserConfiguration {
2820 type Error = &'static str;
2821 fn try_from(internal: PluginUserConfiguration) -> Result<Self, Self::Error> {
2822 let configuration = internal.inner().clone().into_iter().collect();
2823 Ok(ProtobufPluginUserConfiguration { configuration })
2824 }
2825}
2826
2827impl TryFrom<ProtobufRunPluginLocationData> for RunPluginLocation {
2828 type Error = &'static str;
2829 fn try_from(protobuf: ProtobufRunPluginLocationData) -> Result<Self, Self::Error> {
2830 use super::generated_api::api::action::run_plugin_location_data::LocationData;
2831 match protobuf.location_data {
2832 Some(LocationData::FilePath(path)) => Ok(RunPluginLocation::File(PathBuf::from(path))),
2833 Some(LocationData::ZellijTag(tag)) => Ok(RunPluginLocation::Zellij(tag.try_into()?)),
2834 Some(LocationData::RemoteUrl(url)) => Ok(RunPluginLocation::Remote(url)),
2835 None => Err("RunPluginLocationData must have location_data"),
2836 }
2837 }
2838}
2839
2840impl TryFrom<RunPluginLocation> for ProtobufRunPluginLocationData {
2841 type Error = &'static str;
2842 fn try_from(internal: RunPluginLocation) -> Result<Self, Self::Error> {
2843 use super::generated_api::api::action::{
2844 run_plugin_location_data::LocationData,
2845 RunPluginLocation as ProtobufRunPluginLocationType,
2846 };
2847 let (location_type, location_data) = match internal {
2848 RunPluginLocation::File(path) => (
2849 ProtobufRunPluginLocationType::File as i32,
2850 Some(LocationData::FilePath(path.display().to_string())),
2851 ),
2852 RunPluginLocation::Zellij(tag) => (
2853 ProtobufRunPluginLocationType::Zellij as i32,
2854 Some(LocationData::ZellijTag(tag.try_into()?)),
2855 ),
2856 RunPluginLocation::Remote(url) => (
2857 ProtobufRunPluginLocationType::Remote as i32,
2858 Some(LocationData::RemoteUrl(url)),
2859 ),
2860 };
2861 Ok(ProtobufRunPluginLocationData {
2862 location_type,
2863 location_data,
2864 })
2865 }
2866}
2867
2868impl TryFrom<ProtobufRunPlugin> for RunPlugin {
2869 type Error = &'static str;
2870 fn try_from(protobuf: ProtobufRunPlugin) -> Result<Self, Self::Error> {
2871 let location = protobuf
2872 .location
2873 .ok_or("RunPlugin must have location")?
2874 .try_into()?;
2875 let configuration = protobuf
2876 .configuration
2877 .ok_or("RunPlugin must have configuration")?
2878 .try_into()?;
2879 let initial_cwd = protobuf.initial_cwd.map(PathBuf::from);
2880 Ok(RunPlugin {
2881 _allow_exec_host_cmd: protobuf.allow_exec_host_cmd,
2882 location,
2883 configuration,
2884 initial_cwd,
2885 })
2886 }
2887}
2888
2889impl TryFrom<RunPlugin> for ProtobufRunPlugin {
2890 type Error = &'static str;
2891 fn try_from(internal: RunPlugin) -> Result<Self, Self::Error> {
2892 Ok(ProtobufRunPlugin {
2893 allow_exec_host_cmd: internal._allow_exec_host_cmd,
2894 location: Some(internal.location.try_into()?),
2895 configuration: Some(internal.configuration.try_into()?),
2896 initial_cwd: internal.initial_cwd.map(|p| p.display().to_string()),
2897 })
2898 }
2899}
2900
2901impl TryFrom<ProtobufPluginAlias> for PluginAlias {
2902 type Error = &'static str;
2903 fn try_from(protobuf: ProtobufPluginAlias) -> Result<Self, Self::Error> {
2904 let configuration = protobuf.configuration.map(|c| c.try_into()).transpose()?;
2905 let initial_cwd = protobuf.initial_cwd.map(PathBuf::from);
2906 let run_plugin = protobuf.run_plugin.map(|r| r.try_into()).transpose()?;
2907 Ok(PluginAlias {
2908 name: protobuf.name,
2909 configuration,
2910 initial_cwd,
2911 run_plugin,
2912 })
2913 }
2914}
2915
2916impl TryFrom<PluginAlias> for ProtobufPluginAlias {
2917 type Error = &'static str;
2918 fn try_from(internal: PluginAlias) -> Result<Self, Self::Error> {
2919 Ok(ProtobufPluginAlias {
2920 name: internal.name,
2921 configuration: internal.configuration.map(|c| c.try_into()).transpose()?,
2922 initial_cwd: internal.initial_cwd.map(|p| p.display().to_string()),
2923 run_plugin: internal.run_plugin.map(|r| r.try_into()).transpose()?,
2924 })
2925 }
2926}
2927
2928impl TryFrom<ProtobufRunPluginOrAlias> for RunPluginOrAlias {
2929 type Error = &'static str;
2930 fn try_from(protobuf: ProtobufRunPluginOrAlias) -> Result<Self, Self::Error> {
2931 use super::generated_api::api::action::run_plugin_or_alias::PluginType;
2932 match protobuf.plugin_type {
2933 Some(PluginType::Plugin(plugin)) => Ok(RunPluginOrAlias::RunPlugin(plugin.try_into()?)),
2934 Some(PluginType::Alias(alias)) => Ok(RunPluginOrAlias::Alias(alias.try_into()?)),
2935 None => Err("RunPluginOrAlias must have plugin_type"),
2936 }
2937 }
2938}
2939
2940impl TryFrom<RunPluginOrAlias> for ProtobufRunPluginOrAlias {
2941 type Error = &'static str;
2942 fn try_from(internal: RunPluginOrAlias) -> Result<Self, Self::Error> {
2943 use super::generated_api::api::action::run_plugin_or_alias::PluginType;
2944 let plugin_type = match internal {
2945 RunPluginOrAlias::RunPlugin(plugin) => Some(PluginType::Plugin(plugin.try_into()?)),
2946 RunPluginOrAlias::Alias(alias) => Some(PluginType::Alias(alias.try_into()?)),
2947 };
2948 Ok(ProtobufRunPluginOrAlias { plugin_type })
2949 }
2950}
2951
2952impl TryFrom<ProtobufRunEditFileAction> for Run {
2953 type Error = &'static str;
2954 fn try_from(protobuf: ProtobufRunEditFileAction) -> Result<Self, Self::Error> {
2955 let file_path = PathBuf::from(protobuf.file_path);
2956 let line_number = protobuf.line_number.map(|n| n as usize);
2957 let cwd = protobuf.cwd.map(PathBuf::from);
2958 Ok(Run::EditFile(file_path, line_number, cwd))
2959 }
2960}
2961
2962impl TryFrom<ProtobufPaneRun> for Run {
2963 type Error = &'static str;
2964 fn try_from(protobuf: ProtobufPaneRun) -> Result<Self, Self::Error> {
2965 use super::generated_api::api::action::pane_run::RunType;
2966 use crate::input::command::RunCommand;
2967 match protobuf.run_type {
2968 Some(RunType::Command(cmd)) => {
2969 let run_command_action: RunCommandAction = cmd.try_into()?;
2970 let run_command: RunCommand = run_command_action.into();
2971 Ok(Run::Command(run_command))
2972 },
2973 Some(RunType::Plugin(plugin)) => Ok(Run::Plugin(plugin.try_into()?)),
2974 Some(RunType::EditFile(edit)) => edit.try_into(),
2975 Some(RunType::Cwd(cwd)) => Ok(Run::Cwd(PathBuf::from(cwd))),
2976 None => Err("PaneRun must have run_type"),
2977 }
2978 }
2979}
2980
2981impl TryFrom<Run> for ProtobufPaneRun {
2982 type Error = &'static str;
2983 fn try_from(internal: Run) -> Result<Self, Self::Error> {
2984 use super::generated_api::api::action::pane_run::RunType;
2985 let run_type = match internal {
2986 Run::Command(cmd) => {
2987 let run_command_action: RunCommandAction = cmd.into();
2988 Some(RunType::Command(run_command_action.try_into()?))
2989 },
2990 Run::Plugin(plugin) => Some(RunType::Plugin(plugin.try_into()?)),
2991 Run::EditFile(file_path, line_number, cwd) => {
2992 Some(RunType::EditFile(ProtobufRunEditFileAction {
2993 file_path: file_path.display().to_string(),
2994 line_number: line_number.map(|n| n as u32),
2995 cwd: cwd.map(|p| p.display().to_string()),
2996 }))
2997 },
2998 Run::Cwd(cwd) => Some(RunType::Cwd(cwd.display().to_string())),
2999 };
3000 Ok(ProtobufPaneRun { run_type })
3001 }
3002}
3003
3004impl TryFrom<ProtobufCommandOrPlugin> for CommandOrPlugin {
3005 type Error = &'static str;
3006 fn try_from(protobuf: ProtobufCommandOrPlugin) -> Result<Self, Self::Error> {
3007 use super::generated_api::api::action::command_or_plugin::CommandOrPluginType;
3008 match protobuf.command_or_plugin_type {
3009 Some(CommandOrPluginType::Command(cmd)) => {
3010 Ok(CommandOrPlugin::Command(cmd.try_into()?))
3011 },
3012 Some(CommandOrPluginType::Plugin(plugin)) => {
3013 Ok(CommandOrPlugin::Plugin(plugin.try_into()?))
3014 },
3015 Some(CommandOrPluginType::File(f)) => {
3016 Ok(CommandOrPlugin::File(crate::data::FileToOpen {
3017 path: std::path::PathBuf::from(&f.path),
3018 line_number: f.line_number.map(|n| n as usize),
3019 cwd: f.cwd.map(std::path::PathBuf::from),
3020 }))
3021 },
3022 None => Err("CommandOrPlugin must have command_or_plugin_type"),
3023 }
3024 }
3025}
3026
3027impl TryFrom<CommandOrPlugin> for ProtobufCommandOrPlugin {
3028 type Error = &'static str;
3029 fn try_from(internal: CommandOrPlugin) -> Result<Self, Self::Error> {
3030 use super::generated_api::api::action::command_or_plugin::CommandOrPluginType;
3031 use super::generated_api::api::action::CommandOrPluginFile;
3032 let command_or_plugin_type = match internal {
3033 CommandOrPlugin::Command(cmd) => Some(CommandOrPluginType::Command(cmd.try_into()?)),
3034 CommandOrPlugin::Plugin(plugin) => {
3035 Some(CommandOrPluginType::Plugin(plugin.try_into()?))
3036 },
3037 CommandOrPlugin::File(f) => Some(CommandOrPluginType::File(CommandOrPluginFile {
3038 path: f.path.display().to_string(),
3039 line_number: f.line_number.map(|n| n as i32),
3040 cwd: f.cwd.map(|c| c.display().to_string()),
3041 })),
3042 };
3043 Ok(ProtobufCommandOrPlugin {
3044 command_or_plugin_type,
3045 })
3046 }
3047}
3048
3049impl TryFrom<ProtobufTabLayoutInfo> for TabLayoutInfo {
3050 type Error = &'static str;
3051
3052 fn try_from(protobuf_tab: ProtobufTabLayoutInfo) -> Result<Self, Self::Error> {
3053 Ok(TabLayoutInfo {
3054 tab_index: protobuf_tab.tab_index as usize,
3055 tab_name: protobuf_tab.tab_name.filter(|s| !s.is_empty()),
3056 tiled_layout: protobuf_tab
3057 .tiled_layout
3058 .ok_or("missing tiled_layout")?
3059 .try_into()?,
3060 floating_layouts: protobuf_tab
3061 .floating_layouts
3062 .into_iter()
3063 .map(|l| l.try_into())
3064 .collect::<Result<Vec<_>, _>>()?,
3065 swap_tiled_layouts: if protobuf_tab.swap_tiled_layouts.is_empty() {
3066 None
3067 } else {
3068 Some(
3069 protobuf_tab
3070 .swap_tiled_layouts
3071 .into_iter()
3072 .map(|l| l.try_into())
3073 .collect::<Result<Vec<_>, _>>()?,
3074 )
3075 },
3076 swap_floating_layouts: if protobuf_tab.swap_floating_layouts.is_empty() {
3077 None
3078 } else {
3079 Some(
3080 protobuf_tab
3081 .swap_floating_layouts
3082 .into_iter()
3083 .map(|l| l.try_into())
3084 .collect::<Result<Vec<_>, _>>()?,
3085 )
3086 },
3087 })
3088 }
3089}
3090
3091impl TryFrom<TabLayoutInfo> for ProtobufTabLayoutInfo {
3092 type Error = &'static str;
3093
3094 fn try_from(tab_info: TabLayoutInfo) -> Result<Self, Self::Error> {
3095 Ok(ProtobufTabLayoutInfo {
3096 tab_index: tab_info.tab_index as u32,
3097 tab_name: tab_info.tab_name,
3098 tiled_layout: Some(tab_info.tiled_layout.try_into()?),
3099 floating_layouts: tab_info
3100 .floating_layouts
3101 .into_iter()
3102 .map(|l| l.try_into())
3103 .collect::<Result<Vec<_>, _>>()?,
3104 swap_tiled_layouts: tab_info
3105 .swap_tiled_layouts
3106 .unwrap_or_default()
3107 .into_iter()
3108 .map(|l| l.try_into())
3109 .collect::<Result<Vec<_>, _>>()?,
3110 swap_floating_layouts: tab_info
3111 .swap_floating_layouts
3112 .unwrap_or_default()
3113 .into_iter()
3114 .map(|l| l.try_into())
3115 .collect::<Result<Vec<_>, _>>()?,
3116 })
3117 }
3118}
3119
3120impl TryFrom<ProtobufTiledPaneLayout> for TiledPaneLayout {
3121 type Error = &'static str;
3122 fn try_from(protobuf: ProtobufTiledPaneLayout) -> Result<Self, Self::Error> {
3123 let children_split_direction =
3124 ProtobufSplitDirection::try_from(protobuf.children_split_direction)
3125 .ok()
3126 .ok_or("Invalid split direction")?
3127 .try_into()?;
3128 let children = protobuf
3129 .children
3130 .into_iter()
3131 .map(|c| c.try_into())
3132 .collect::<Result<Vec<_>, _>>()?;
3133 let split_size = protobuf.split_size.map(|s| s.try_into()).transpose()?;
3134 let run = protobuf.run.map(|r| r.try_into()).transpose()?;
3135 let focus = protobuf.focus.and_then(|f| {
3136 if f == "true" {
3137 Some(true)
3138 } else if f == "false" {
3139 Some(false)
3140 } else {
3141 None
3142 }
3143 });
3144 let run_instructions_to_ignore = vec![]; Ok(TiledPaneLayout {
3146 children_split_direction,
3147 name: protobuf.name,
3148 children,
3149 split_size,
3150 run,
3151 borderless: Some(protobuf.borderless),
3152 focus,
3153 external_children_index: protobuf.external_children_index.map(|i| i as usize),
3154 children_are_stacked: protobuf.children_are_stacked,
3155 is_expanded_in_stack: protobuf.is_expanded_in_stack,
3156 exclude_from_sync: protobuf.exclude_from_sync,
3157 run_instructions_to_ignore,
3158 hide_floating_panes: protobuf.hide_floating_panes,
3159 pane_initial_contents: protobuf.pane_initial_contents,
3160 default_fg: None,
3161 default_bg: None,
3162 })
3163 }
3164}
3165
3166impl TryFrom<TiledPaneLayout> for ProtobufTiledPaneLayout {
3167 type Error = &'static str;
3168 fn try_from(internal: TiledPaneLayout) -> Result<Self, Self::Error> {
3169 let children_split_direction: ProtobufSplitDirection =
3170 internal.children_split_direction.try_into()?;
3171 let children = internal
3172 .children
3173 .into_iter()
3174 .map(|c| c.try_into())
3175 .collect::<Result<Vec<_>, _>>()?;
3176 let split_size = internal.split_size.map(|s| s.try_into()).transpose()?;
3177 let run = internal.run.map(|r| r.try_into()).transpose()?;
3178 let focus = internal.focus.map(|f| f.to_string());
3179 Ok(ProtobufTiledPaneLayout {
3180 children_split_direction: children_split_direction as i32,
3181 name: internal.name,
3182 children,
3183 split_size,
3184 run,
3185 borderless: internal.borderless.unwrap_or(false),
3186 focus,
3187 external_children_index: internal.external_children_index.map(|i| i as u32),
3188 children_are_stacked: internal.children_are_stacked,
3189 is_expanded_in_stack: internal.is_expanded_in_stack,
3190 exclude_from_sync: internal.exclude_from_sync,
3191 hide_floating_panes: internal.hide_floating_panes,
3192 pane_initial_contents: internal.pane_initial_contents,
3193 })
3194 }
3195}
3196
3197impl TryFrom<ProtobufFloatingPaneLayout> for FloatingPaneLayout {
3198 type Error = &'static str;
3199 fn try_from(protobuf: ProtobufFloatingPaneLayout) -> Result<Self, Self::Error> {
3200 let height = protobuf.height.map(|h| h.try_into()).transpose()?;
3201 let width = protobuf.width.map(|w| w.try_into()).transpose()?;
3202 let x = protobuf.x.map(|x| x.try_into()).transpose()?;
3203 let y = protobuf.y.map(|y| y.try_into()).transpose()?;
3204 let run = protobuf.run.map(|r| r.try_into()).transpose()?;
3205 Ok(FloatingPaneLayout {
3206 name: protobuf.name,
3207 height,
3208 width,
3209 x,
3210 y,
3211 pinned: protobuf.pinned,
3212 run,
3213 focus: protobuf.focus,
3214 already_running: protobuf.already_running,
3215 pane_initial_contents: protobuf.pane_initial_contents,
3216 logical_position: protobuf.logical_position.map(|p| p as usize),
3217 borderless: protobuf.borderless,
3218 default_fg: None,
3219 default_bg: None,
3220 })
3221 }
3222}
3223
3224impl TryFrom<FloatingPaneLayout> for ProtobufFloatingPaneLayout {
3225 type Error = &'static str;
3226 fn try_from(internal: FloatingPaneLayout) -> Result<Self, Self::Error> {
3227 let height = internal.height.map(|h| h.try_into()).transpose()?;
3228 let width = internal.width.map(|w| w.try_into()).transpose()?;
3229 let x = internal.x.map(|x| x.try_into()).transpose()?;
3230 let y = internal.y.map(|y| y.try_into()).transpose()?;
3231 let run = internal.run.map(|r| r.try_into()).transpose()?;
3232 Ok(ProtobufFloatingPaneLayout {
3233 name: internal.name,
3234 height,
3235 width,
3236 x,
3237 y,
3238 pinned: internal.pinned,
3239 run,
3240 focus: internal.focus,
3241 already_running: internal.already_running,
3242 pane_initial_contents: internal.pane_initial_contents,
3243 logical_position: internal.logical_position.map(|p| p as u32),
3244 borderless: internal.borderless,
3245 })
3246 }
3247}
3248
3249impl TryFrom<ProtobufLayoutConstraintTiledPair> for (LayoutConstraint, TiledPaneLayout) {
3250 type Error = &'static str;
3251 fn try_from(protobuf: ProtobufLayoutConstraintTiledPair) -> Result<Self, Self::Error> {
3252 let constraint = protobuf
3253 .constraint
3254 .ok_or("LayoutConstraintTiledPair must have constraint")?
3255 .try_into()?;
3256 let layout = protobuf
3257 .layout
3258 .ok_or("LayoutConstraintTiledPair must have layout")?
3259 .try_into()?;
3260 Ok((constraint, layout))
3261 }
3262}
3263
3264impl TryFrom<(LayoutConstraint, TiledPaneLayout)> for ProtobufLayoutConstraintTiledPair {
3265 type Error = &'static str;
3266 fn try_from(internal: (LayoutConstraint, TiledPaneLayout)) -> Result<Self, Self::Error> {
3267 Ok(ProtobufLayoutConstraintTiledPair {
3268 constraint: Some(internal.0.try_into()?),
3269 layout: Some(internal.1.try_into()?),
3270 })
3271 }
3272}
3273
3274impl TryFrom<ProtobufLayoutConstraintFloatingPair> for (LayoutConstraint, Vec<FloatingPaneLayout>) {
3275 type Error = &'static str;
3276 fn try_from(protobuf: ProtobufLayoutConstraintFloatingPair) -> Result<Self, Self::Error> {
3277 let constraint = protobuf
3278 .constraint
3279 .ok_or("LayoutConstraintFloatingPair must have constraint")?
3280 .try_into()?;
3281 let layouts = protobuf
3282 .layouts
3283 .into_iter()
3284 .map(|l| l.try_into())
3285 .collect::<Result<Vec<_>, _>>()?;
3286 Ok((constraint, layouts))
3287 }
3288}
3289
3290impl TryFrom<(LayoutConstraint, Vec<FloatingPaneLayout>)> for ProtobufLayoutConstraintFloatingPair {
3291 type Error = &'static str;
3292 fn try_from(
3293 internal: (LayoutConstraint, Vec<FloatingPaneLayout>),
3294 ) -> Result<Self, Self::Error> {
3295 Ok(ProtobufLayoutConstraintFloatingPair {
3296 constraint: Some(internal.0.try_into()?),
3297 layouts: internal
3298 .1
3299 .into_iter()
3300 .map(|l| l.try_into())
3301 .collect::<Result<Vec<_>, _>>()?,
3302 })
3303 }
3304}
3305
3306impl TryFrom<ProtobufSwapTiledLayout> for SwapTiledLayout {
3307 type Error = &'static str;
3308 fn try_from(protobuf: ProtobufSwapTiledLayout) -> Result<Self, Self::Error> {
3309 let constraint_map: BTreeMap<LayoutConstraint, TiledPaneLayout> = protobuf
3310 .constraint_map
3311 .into_iter()
3312 .map(|pair| pair.try_into())
3313 .collect::<Result<BTreeMap<_, _>, _>>()?;
3314 Ok((constraint_map, protobuf.name))
3315 }
3316}
3317
3318impl TryFrom<SwapTiledLayout> for ProtobufSwapTiledLayout {
3319 type Error = &'static str;
3320 fn try_from(internal: SwapTiledLayout) -> Result<Self, Self::Error> {
3321 let constraint_map = internal
3322 .0
3323 .into_iter()
3324 .map(|(constraint, layout)| (constraint, layout).try_into())
3325 .collect::<Result<Vec<_>, _>>()?;
3326 Ok(ProtobufSwapTiledLayout {
3327 constraint_map,
3328 name: internal.1,
3329 })
3330 }
3331}
3332
3333impl TryFrom<ProtobufSwapFloatingLayout> for SwapFloatingLayout {
3334 type Error = &'static str;
3335 fn try_from(protobuf: ProtobufSwapFloatingLayout) -> Result<Self, Self::Error> {
3336 let constraint_map: BTreeMap<LayoutConstraint, Vec<FloatingPaneLayout>> = protobuf
3337 .constraint_map
3338 .into_iter()
3339 .map(|pair| pair.try_into())
3340 .collect::<Result<BTreeMap<_, _>, _>>()?;
3341 Ok((constraint_map, protobuf.name))
3342 }
3343}
3344
3345impl TryFrom<SwapFloatingLayout> for ProtobufSwapFloatingLayout {
3346 type Error = &'static str;
3347 fn try_from(internal: SwapFloatingLayout) -> Result<Self, Self::Error> {
3348 let constraint_map = internal
3349 .0
3350 .into_iter()
3351 .map(|(constraint, layouts)| (constraint, layouts).try_into())
3352 .collect::<Result<Vec<_>, _>>()?;
3353 Ok(ProtobufSwapFloatingLayout {
3354 constraint_map,
3355 name: internal.1,
3356 })
3357 }
3358}
3359
3360#[cfg(test)]
3361mod tests {
3362 use super::*;
3363 use crate::input::options::PaneFrameStyle;
3364
3365 #[test]
3366 fn set_pane_frame_style_action_protobuf_round_trip() {
3367 for style in [
3368 PaneFrameStyle::Full,
3369 PaneFrameStyle::Titles,
3370 PaneFrameStyle::None,
3371 ] {
3372 let original = Action::SetPaneFrameStyle(style);
3373 let protobuf: ProtobufAction = original.clone().try_into().expect("encode");
3374 let decoded: Action = protobuf.try_into().expect("decode");
3375 assert_eq!(original, decoded);
3376 }
3377 }
3378
3379 #[test]
3380 fn osc133_actions_protobuf_round_trip() {
3381 for original in [
3382 Action::ScrollToPreviousPrompt,
3383 Action::ScrollToNextPrompt,
3384 Action::SelectCommandAtScrollPosition,
3385 Action::CopyLastCommandOutput,
3386 ] {
3387 let protobuf: ProtobufAction = original.clone().try_into().expect("encode");
3388 let decoded: Action = protobuf.try_into().expect("decode");
3389 assert_eq!(original, decoded);
3390 }
3391 }
3392}