1use std::str::FromStr;
2
3use crate::{
4 client_server_contract::client_server_contract::{
5 client_to_server_msg, server_to_client_msg, ActionMsg, AttachClientMsg,
6 AttachWatcherClientMsg, BackgroundColorMsg, CliPipeOutputMsg, ClientExitedMsg,
7 ClientToServerMsg as ProtoClientToServerMsg, ColorRegistersMsg, ConfigFileUpdatedMsg,
8 ConnStatusMsg, ConnectedMsg, DesktopNotificationResponseMsg, DetachSessionMsg,
9 EmitNestedSessionFrameMsg, ExitMsg, ExitReason as ProtoExitReason,
10 FailedToStartWebServerMsg, FirstClientConnectedMsg, ForegroundColorMsg,
11 ForwardQueryToHostMsg, ForwardedReplyFromHostMsg, HostTerminalFocusChangedMsg,
12 HostTerminalThemeChangedMsg,
13 HostTerminalThemeIndication as ProtoHostTerminalThemeIndication,
14 InputMode as ProtoInputMode, KeyMsg, KillSessionMsg, KittyGraphicsSupportMsg,
15 LayoutMetadata as ProtoLayoutMetadata, LogErrorMsg, LogMsg, MobileActivePaneMsg,
16 MobilePaneMsg, MobileRenderPrefsMsg, MobileSessionMsg, MobileSizeMsg, MobileStateMsg,
17 MobileTabMsg, NestedSessionFrameFromHostMsg, PaneMetadata as ProtoPaneMetadata,
18 PaneRenderUpdateMsg, QueryTerminalSizeMsg, RenamedSessionMsg, RenderMsg,
19 RequestSessionListMsg, ServerToClientMsg as ProtoServerToClientMsg,
20 SetMobileRenderPreferencesMsg, SetSoftKeyboardMsg, SixelSupportMsg,
21 SoftKeyboardVisibilityChangedMsg, StartWebServerMsg, SubscribeToPaneRendersMsg,
22 SubscribedPaneClosedMsg, SwitchSessionMsg, TabMetadata as ProtoTabMetadata,
23 TerminalPixelDimensionsMsg, TerminalResizeMsg, UnblockCliPipeInputMsg,
24 UnblockInputThreadMsg, WebServerStartedMsg,
25 },
26 data::{HostTerminalThemeMode, InputMode, PaneId},
27 errors::prelude::*,
28 ipc::{
29 ClientToServerMsg, ColorRegister, ExitReason, MobileActivePanePayload, MobilePanePayload,
30 MobileRenderPrefsPayload, MobileSessionPayload, MobileSizePayload, MobileStatePayload,
31 MobileTabPayload, PaneReference, PixelDimensions, ServerToClientMsg,
32 },
33};
34use std::collections::BTreeMap;
35use std::path::PathBuf;
36
37impl From<ClientToServerMsg> for ProtoClientToServerMsg {
39 fn from(msg: ClientToServerMsg) -> Self {
40 let message = match msg {
41 ClientToServerMsg::DetachSession { client_ids } => {
42 client_to_server_msg::Message::DetachSession(DetachSessionMsg {
43 client_ids: client_ids.into_iter().map(|id| id as u32).collect(),
44 })
45 },
46 ClientToServerMsg::TerminalPixelDimensions { pixel_dimensions } => {
47 client_to_server_msg::Message::TerminalPixelDimensions(TerminalPixelDimensionsMsg {
48 pixel_dimensions: Some(pixel_dimensions.into()),
49 })
50 },
51 ClientToServerMsg::BackgroundColor { color } => {
52 client_to_server_msg::Message::BackgroundColor(BackgroundColorMsg { color })
53 },
54 ClientToServerMsg::ForegroundColor { color } => {
55 client_to_server_msg::Message::ForegroundColor(ForegroundColorMsg { color })
56 },
57 ClientToServerMsg::ColorRegisters { color_registers } => {
58 client_to_server_msg::Message::ColorRegisters(ColorRegistersMsg {
59 color_registers: color_registers.into_iter().map(|cr| cr.into()).collect(),
60 })
61 },
62 ClientToServerMsg::TerminalResize { new_size } => {
63 client_to_server_msg::Message::TerminalResize(TerminalResizeMsg {
64 new_size: Some(new_size.into()),
65 })
66 },
67 ClientToServerMsg::FirstClientConnected {
68 cli_assets,
69 is_web_client,
70 } => client_to_server_msg::Message::FirstClientConnected(FirstClientConnectedMsg {
71 cli_assets: Some(cli_assets.into()),
72 is_web_client,
73 }),
74 ClientToServerMsg::AttachClient {
75 cli_assets,
76 tab_position_to_focus,
77 pane_to_focus,
78 is_web_client,
79 } => client_to_server_msg::Message::AttachClient(AttachClientMsg {
80 cli_assets: Some(cli_assets.into()),
81 tab_position_to_focus: tab_position_to_focus.map(|pos| pos as u32),
82 pane_to_focus: pane_to_focus.map(|p| p.into()),
83 is_web_client,
84 }),
85 ClientToServerMsg::AttachWatcherClient {
86 terminal_size,
87 is_web_client,
88 } => client_to_server_msg::Message::AttachWatcherClient(AttachWatcherClientMsg {
89 terminal_size: Some(terminal_size.into()),
90 is_web_client,
91 }),
92 ClientToServerMsg::Action {
93 action,
94 terminal_id,
95 client_id,
96 is_cli_client,
97 } => client_to_server_msg::Message::Action(ActionMsg {
98 action: Some(action.into()),
99 terminal_id,
100 client_id: client_id.map(|id| id as u32),
101 is_cli_client,
102 }),
103 ClientToServerMsg::Key {
104 key,
105 raw_bytes,
106 is_kitty_keyboard_protocol,
107 } => client_to_server_msg::Message::Key(KeyMsg {
108 key: Some(key.into()),
109 raw_bytes: raw_bytes.into_iter().map(|b| b as u32).collect(),
110 is_kitty_keyboard_protocol,
111 }),
112 ClientToServerMsg::ClientExited => {
113 client_to_server_msg::Message::ClientExited(ClientExitedMsg {})
114 },
115 ClientToServerMsg::KillSession => {
116 client_to_server_msg::Message::KillSession(KillSessionMsg {})
117 },
118 ClientToServerMsg::ConnStatus => {
119 client_to_server_msg::Message::ConnStatus(ConnStatusMsg {})
120 },
121 ClientToServerMsg::WebServerStarted { base_url } => {
122 client_to_server_msg::Message::WebServerStarted(WebServerStartedMsg { base_url })
123 },
124 ClientToServerMsg::FailedToStartWebServer { error } => {
125 client_to_server_msg::Message::FailedToStartWebServer(FailedToStartWebServerMsg {
126 error,
127 })
128 },
129 ClientToServerMsg::SubscribeToPaneRenders {
130 pane_ids,
131 scrollback,
132 ansi,
133 } => client_to_server_msg::Message::SubscribeToPaneRenders(SubscribeToPaneRendersMsg {
134 pane_ids: pane_ids.into_iter().map(|id| id.into()).collect(),
135 scrollback: scrollback.map(|s| s as u32),
136 ansi,
137 }),
138 ClientToServerMsg::DesktopNotificationResponse { raw_bytes } => {
139 client_to_server_msg::Message::DesktopNotificationResponse(
140 DesktopNotificationResponseMsg { raw_bytes },
141 )
142 },
143 ClientToServerMsg::ForwardedReplyFromHost { token, reply_bytes } => {
144 client_to_server_msg::Message::ForwardedReplyFromHost(ForwardedReplyFromHostMsg {
145 token,
146 reply_bytes,
147 })
148 },
149 ClientToServerMsg::HostTerminalThemeChanged { mode } => {
150 let proto_mode: ProtoHostTerminalThemeIndication = mode.into();
151 client_to_server_msg::Message::HostTerminalThemeChanged(
152 HostTerminalThemeChangedMsg {
153 mode: proto_mode as i32,
154 },
155 )
156 },
157 ClientToServerMsg::SoftKeyboardVisibilityChanged { visible } => {
158 client_to_server_msg::Message::SoftKeyboardVisibilityChanged(
159 SoftKeyboardVisibilityChangedMsg { visible },
160 )
161 },
162 ClientToServerMsg::NestedSessionFrameFromHost { payload_bytes } => {
163 client_to_server_msg::Message::NestedSessionFrameFromHost(
164 NestedSessionFrameFromHostMsg { payload_bytes },
165 )
166 },
167 ClientToServerMsg::KittyGraphicsSupport { supported } => {
168 client_to_server_msg::Message::KittyGraphicsSupport(KittyGraphicsSupportMsg {
169 supported,
170 })
171 },
172 ClientToServerMsg::SixelSupport { supported } => {
173 client_to_server_msg::Message::SixelSupport(SixelSupportMsg { supported })
174 },
175 ClientToServerMsg::RequestSessionList => {
176 client_to_server_msg::Message::RequestSessionList(RequestSessionListMsg {})
177 },
178 ClientToServerMsg::SetMobileRenderPreferences { single_pane, fit } => {
179 client_to_server_msg::Message::SetMobileRenderPreferences(
180 SetMobileRenderPreferencesMsg { single_pane, fit },
181 )
182 },
183 ClientToServerMsg::HostTerminalFocusChanged { focused } => {
184 client_to_server_msg::Message::HostTerminalFocusChanged(
185 HostTerminalFocusChangedMsg { focused },
186 )
187 },
188 };
189
190 ProtoClientToServerMsg {
191 message: Some(message),
192 }
193 }
194}
195
196impl TryFrom<ProtoClientToServerMsg> for ClientToServerMsg {
198 type Error = anyhow::Error;
199
200 fn try_from(msg: ProtoClientToServerMsg) -> Result<Self> {
201 match msg.message {
202 Some(client_to_server_msg::Message::DetachSession(detach)) => {
203 Ok(ClientToServerMsg::DetachSession {
204 client_ids: detach.client_ids.into_iter().map(|id| id as u16).collect(),
205 })
206 },
207 Some(client_to_server_msg::Message::TerminalPixelDimensions(pixel_dims)) => {
208 Ok(ClientToServerMsg::TerminalPixelDimensions {
209 pixel_dimensions: pixel_dims
210 .pixel_dimensions
211 .ok_or_else(|| anyhow!("Missing pixel_dimensions"))?
212 .try_into()?,
213 })
214 },
215 Some(client_to_server_msg::Message::BackgroundColor(bg_color)) => {
216 Ok(ClientToServerMsg::BackgroundColor {
217 color: bg_color.color,
218 })
219 },
220 Some(client_to_server_msg::Message::ForegroundColor(fg_color)) => {
221 Ok(ClientToServerMsg::ForegroundColor {
222 color: fg_color.color,
223 })
224 },
225 Some(client_to_server_msg::Message::ColorRegisters(color_regs)) => {
226 Ok(ClientToServerMsg::ColorRegisters {
227 color_registers: color_regs
228 .color_registers
229 .into_iter()
230 .map(|cr| cr.try_into())
231 .collect::<Result<Vec<_>>>()?,
232 })
233 },
234 Some(client_to_server_msg::Message::TerminalResize(resize)) => {
235 Ok(ClientToServerMsg::TerminalResize {
236 new_size: resize
237 .new_size
238 .ok_or_else(|| anyhow!("Missing new_size"))?
239 .try_into()?,
240 })
241 },
242 Some(client_to_server_msg::Message::FirstClientConnected(first_client)) => {
243 Ok(ClientToServerMsg::FirstClientConnected {
244 cli_assets: first_client
245 .cli_assets
246 .ok_or_else(|| anyhow!("Missing cli_assets"))?
247 .try_into()?,
248 is_web_client: first_client.is_web_client,
249 })
250 },
251 Some(client_to_server_msg::Message::AttachClient(attach)) => {
252 Ok(ClientToServerMsg::AttachClient {
253 cli_assets: attach
254 .cli_assets
255 .ok_or_else(|| anyhow!("Missing cli_assets"))?
256 .try_into()?,
257 tab_position_to_focus: attach.tab_position_to_focus.map(|pos| pos as usize),
258 pane_to_focus: attach.pane_to_focus.map(|p| p.try_into()).transpose()?,
259 is_web_client: attach.is_web_client,
260 })
261 },
262 Some(client_to_server_msg::Message::AttachWatcherClient(attach_watcher)) => {
263 Ok(ClientToServerMsg::AttachWatcherClient {
264 terminal_size: attach_watcher
265 .terminal_size
266 .ok_or_else(|| anyhow::anyhow!("Missing terminal_size"))?
267 .try_into()?,
268 is_web_client: attach_watcher.is_web_client,
269 })
270 },
271 Some(client_to_server_msg::Message::Action(action)) => Ok(ClientToServerMsg::Action {
272 action: action
273 .action
274 .ok_or_else(|| anyhow!("Missing action"))?
275 .try_into()?,
276 terminal_id: action.terminal_id,
277 client_id: action.client_id.map(|id| id as u16),
278 is_cli_client: action.is_cli_client,
279 }),
280 Some(client_to_server_msg::Message::Key(key)) => Ok(ClientToServerMsg::Key {
281 key: key.key.ok_or_else(|| anyhow!("Missing key"))?.try_into()?,
282 raw_bytes: key.raw_bytes.into_iter().map(|b| b as u8).collect(),
283 is_kitty_keyboard_protocol: key.is_kitty_keyboard_protocol,
284 }),
285 Some(client_to_server_msg::Message::ClientExited(_)) => {
286 Ok(ClientToServerMsg::ClientExited)
287 },
288 Some(client_to_server_msg::Message::KillSession(_)) => {
289 Ok(ClientToServerMsg::KillSession)
290 },
291 Some(client_to_server_msg::Message::ConnStatus(_)) => Ok(ClientToServerMsg::ConnStatus),
292 Some(client_to_server_msg::Message::WebServerStarted(web_server)) => {
293 Ok(ClientToServerMsg::WebServerStarted {
294 base_url: web_server.base_url,
295 })
296 },
297 Some(client_to_server_msg::Message::FailedToStartWebServer(failed)) => {
298 Ok(ClientToServerMsg::FailedToStartWebServer {
299 error: failed.error,
300 })
301 },
302 Some(client_to_server_msg::Message::SubscribeToPaneRenders(msg)) => {
303 let pane_ids: Result<Vec<PaneId>> =
304 msg.pane_ids.into_iter().map(|p| p.try_into()).collect();
305 Ok(ClientToServerMsg::SubscribeToPaneRenders {
306 pane_ids: pane_ids?,
307 scrollback: msg.scrollback.map(|s| s as usize),
308 ansi: msg.ansi,
309 })
310 },
311 Some(client_to_server_msg::Message::DesktopNotificationResponse(msg)) => {
312 Ok(ClientToServerMsg::DesktopNotificationResponse {
313 raw_bytes: msg.raw_bytes,
314 })
315 },
316 Some(client_to_server_msg::Message::ForwardedReplyFromHost(msg)) => {
317 Ok(ClientToServerMsg::ForwardedReplyFromHost {
318 token: msg.token,
319 reply_bytes: msg.reply_bytes,
320 })
321 },
322 Some(client_to_server_msg::Message::HostTerminalThemeChanged(msg)) => {
323 let proto_mode = ProtoHostTerminalThemeIndication::try_from(msg.mode)
324 .ok()
325 .ok_or_else(|| anyhow!("Unknown HostTerminalThemeIndication: {}", msg.mode))?;
326 Ok(ClientToServerMsg::HostTerminalThemeChanged {
327 mode: proto_mode.into(),
328 })
329 },
330 Some(client_to_server_msg::Message::SoftKeyboardVisibilityChanged(msg)) => {
331 Ok(ClientToServerMsg::SoftKeyboardVisibilityChanged {
332 visible: msg.visible,
333 })
334 },
335 Some(client_to_server_msg::Message::NestedSessionFrameFromHost(msg)) => {
336 Ok(ClientToServerMsg::NestedSessionFrameFromHost {
337 payload_bytes: msg.payload_bytes,
338 })
339 },
340 Some(client_to_server_msg::Message::KittyGraphicsSupport(msg)) => {
341 Ok(ClientToServerMsg::KittyGraphicsSupport {
342 supported: msg.supported,
343 })
344 },
345 Some(client_to_server_msg::Message::SixelSupport(msg)) => {
346 Ok(ClientToServerMsg::SixelSupport {
347 supported: msg.supported,
348 })
349 },
350 Some(client_to_server_msg::Message::RequestSessionList(_)) => {
351 Ok(ClientToServerMsg::RequestSessionList)
352 },
353 Some(client_to_server_msg::Message::SetMobileRenderPreferences(msg)) => {
354 Ok(ClientToServerMsg::SetMobileRenderPreferences {
355 single_pane: msg.single_pane,
356 fit: msg.fit,
357 })
358 },
359 Some(client_to_server_msg::Message::HostTerminalFocusChanged(msg)) => {
360 Ok(ClientToServerMsg::HostTerminalFocusChanged {
361 focused: msg.focused,
362 })
363 },
364 None => Err(anyhow!("Empty ClientToServerMsg message")),
365 }
366 }
367}
368
369impl From<ServerToClientMsg> for ProtoServerToClientMsg {
371 fn from(msg: ServerToClientMsg) -> Self {
372 let message = match msg {
373 ServerToClientMsg::Render { content } => {
374 server_to_client_msg::Message::Render(RenderMsg { content })
375 },
376 ServerToClientMsg::UnblockInputThread => {
377 server_to_client_msg::Message::UnblockInputThread(UnblockInputThreadMsg {})
378 },
379 ServerToClientMsg::Exit { exit_reason } => {
380 let (proto_exit_reason, payload) = match exit_reason {
381 ExitReason::Error(ref msg) => (ProtoExitReason::Error, Some(msg.clone())),
382 ExitReason::CustomExitStatus(status) => {
383 (ProtoExitReason::CustomExitStatus, Some(status.to_string()))
384 },
385 other => (ProtoExitReason::from(other), None),
386 };
387 server_to_client_msg::Message::Exit(ExitMsg {
388 exit_reason: proto_exit_reason as i32,
389 payload,
390 })
391 },
392 ServerToClientMsg::Connected => {
393 server_to_client_msg::Message::Connected(ConnectedMsg {})
394 },
395 ServerToClientMsg::Log { lines } => {
396 server_to_client_msg::Message::Log(LogMsg { lines })
397 },
398 ServerToClientMsg::LogError { lines } => {
399 server_to_client_msg::Message::LogError(LogErrorMsg { lines })
400 },
401 ServerToClientMsg::SwitchSession { connect_to_session } => {
402 server_to_client_msg::Message::SwitchSession(SwitchSessionMsg {
403 connect_to_session: Some(connect_to_session.into()),
404 })
405 },
406 ServerToClientMsg::UnblockCliPipeInput { pipe_name } => {
407 server_to_client_msg::Message::UnblockCliPipeInput(UnblockCliPipeInputMsg {
408 pipe_name,
409 })
410 },
411 ServerToClientMsg::CliPipeOutput { pipe_name, output } => {
412 server_to_client_msg::Message::CliPipeOutput(CliPipeOutputMsg { pipe_name, output })
413 },
414 ServerToClientMsg::QueryTerminalSize => {
415 server_to_client_msg::Message::QueryTerminalSize(QueryTerminalSizeMsg {})
416 },
417 ServerToClientMsg::StartWebServer => {
418 server_to_client_msg::Message::StartWebServer(StartWebServerMsg {})
419 },
420 ServerToClientMsg::RenamedSession { name } => {
421 server_to_client_msg::Message::RenamedSession(RenamedSessionMsg { name })
422 },
423 ServerToClientMsg::ConfigFileUpdated => {
424 server_to_client_msg::Message::ConfigFileUpdated(ConfigFileUpdatedMsg {})
425 },
426 ServerToClientMsg::PaneRenderUpdate {
427 pane_id,
428 viewport,
429 scrollback,
430 is_initial,
431 } => server_to_client_msg::Message::PaneRenderUpdate(PaneRenderUpdateMsg {
432 pane_id: Some(pane_id.into()),
433 viewport,
434 scrollback: scrollback.clone().unwrap_or_default(),
435 has_scrollback: scrollback.is_some(),
436 is_initial,
437 }),
438 ServerToClientMsg::SubscribedPaneClosed { pane_id } => {
439 server_to_client_msg::Message::SubscribedPaneClosed(SubscribedPaneClosedMsg {
440 pane_id: Some(pane_id.into()),
441 })
442 },
443 ServerToClientMsg::ForwardQueryToHost {
444 token,
445 query_bytes,
446 resolve_async,
447 } => server_to_client_msg::Message::ForwardQueryToHost(ForwardQueryToHostMsg {
448 token,
449 query_bytes,
450 resolve_async,
451 }),
452 ServerToClientMsg::SetSoftKeyboard { on } => {
453 server_to_client_msg::Message::SetSoftKeyboard(SetSoftKeyboardMsg { on })
454 },
455 ServerToClientMsg::EmitNestedSessionFrame { payload_bytes } => {
456 server_to_client_msg::Message::EmitNestedSessionFrame(EmitNestedSessionFrameMsg {
457 payload_bytes,
458 })
459 },
460 ServerToClientMsg::MobileState { payload } => {
461 server_to_client_msg::Message::MobileState(mobile_state_payload_to_proto(payload))
462 },
463 };
464
465 ProtoServerToClientMsg {
466 message: Some(message),
467 }
468 }
469}
470
471fn mobile_state_payload_to_proto(payload: MobileStatePayload) -> MobileStateMsg {
472 MobileStateMsg {
473 session_name: payload.session_name,
474 now_secs: payload.now_secs,
475 is_welcome_screen: payload.is_welcome_screen,
476 desktop_client_connected: payload.desktop_client_connected,
477 desktop_size: payload.desktop_size.map(|s| MobileSizeMsg {
478 cols: s.cols as u32,
479 rows: s.rows as u32,
480 }),
481 active_pane: payload.active_pane.map(|p| MobileActivePaneMsg {
482 pane_id: p.pane_id,
483 is_plugin: p.is_plugin,
484 tab_position: p.tab_position as u32,
485 }),
486 tabs: payload
487 .tabs
488 .into_iter()
489 .map(|t| MobileTabMsg {
490 position: t.position as u32,
491 name: t.name,
492 active: t.active,
493 })
494 .collect(),
495 panes: payload
496 .panes
497 .into_iter()
498 .map(|p| MobilePaneMsg {
499 tab_position: p.tab_position as u32,
500 pane_id: p.pane_id,
501 is_plugin: p.is_plugin,
502 title: p.title,
503 is_floating: p.is_floating,
504 last_activity_secs_ago: p.last_activity_secs_ago,
505 })
506 .collect(),
507 sessions: payload
508 .sessions
509 .into_iter()
510 .map(|s| MobileSessionMsg {
511 name: s.name,
512 web_clients_allowed: s.web_clients_allowed,
513 tab_count: s.tab_count as u32,
514 pane_count: s.pane_count as u32,
515 connected_clients: s.connected_clients as u32,
516 creation_secs_ago: s.creation_secs_ago,
517 })
518 .collect(),
519 render_prefs: Some(MobileRenderPrefsMsg {
520 single_pane: payload.render_prefs.single_pane,
521 fit: payload.render_prefs.fit,
522 active_pane_is_fullscreen: payload.render_prefs.active_pane_is_fullscreen,
523 }),
524 }
525}
526
527fn mobile_state_payload_from_proto(msg: MobileStateMsg) -> MobileStatePayload {
528 MobileStatePayload {
529 session_name: msg.session_name,
530 now_secs: msg.now_secs,
531 is_welcome_screen: msg.is_welcome_screen,
532 desktop_client_connected: msg.desktop_client_connected,
533 desktop_size: msg.desktop_size.map(|s| MobileSizePayload {
534 cols: s.cols as usize,
535 rows: s.rows as usize,
536 }),
537 active_pane: msg.active_pane.map(|p| MobileActivePanePayload {
538 pane_id: p.pane_id,
539 is_plugin: p.is_plugin,
540 tab_position: p.tab_position as usize,
541 }),
542 tabs: msg
543 .tabs
544 .into_iter()
545 .map(|t| MobileTabPayload {
546 position: t.position as usize,
547 name: t.name,
548 active: t.active,
549 })
550 .collect(),
551 panes: msg
552 .panes
553 .into_iter()
554 .map(|p| MobilePanePayload {
555 tab_position: p.tab_position as usize,
556 pane_id: p.pane_id,
557 is_plugin: p.is_plugin,
558 title: p.title,
559 is_floating: p.is_floating,
560 last_activity_secs_ago: p.last_activity_secs_ago,
561 })
562 .collect(),
563 sessions: msg
564 .sessions
565 .into_iter()
566 .map(|s| MobileSessionPayload {
567 name: s.name,
568 web_clients_allowed: s.web_clients_allowed,
569 tab_count: s.tab_count as usize,
570 pane_count: s.pane_count as usize,
571 connected_clients: s.connected_clients as usize,
572 creation_secs_ago: s.creation_secs_ago,
573 })
574 .collect(),
575 render_prefs: msg
576 .render_prefs
577 .map(|p| MobileRenderPrefsPayload {
578 single_pane: p.single_pane,
579 fit: p.fit,
580 active_pane_is_fullscreen: p.active_pane_is_fullscreen,
581 })
582 .unwrap_or(MobileRenderPrefsPayload {
583 single_pane: true,
584 fit: true,
585 active_pane_is_fullscreen: false,
586 }),
587 }
588}
589
590impl TryFrom<ProtoServerToClientMsg> for ServerToClientMsg {
592 type Error = anyhow::Error;
593
594 fn try_from(msg: ProtoServerToClientMsg) -> Result<Self> {
595 match msg.message {
596 Some(server_to_client_msg::Message::Render(render)) => Ok(ServerToClientMsg::Render {
597 content: render.content,
598 }),
599 Some(server_to_client_msg::Message::UnblockInputThread(_)) => {
600 Ok(ServerToClientMsg::UnblockInputThread)
601 },
602 Some(server_to_client_msg::Message::Exit(exit)) => {
603 let proto_exit_reason = ProtoExitReason::try_from(exit.exit_reason)
604 .ok()
605 .ok_or_else(|| anyhow!("Invalid exit_reason"))?;
606
607 let exit_reason = match proto_exit_reason {
608 ProtoExitReason::Error => {
609 let error_msg =
610 exit.payload.unwrap_or_else(|| "Protobuf error".to_string());
611 ExitReason::Error(error_msg)
612 },
613 ProtoExitReason::CustomExitStatus => {
614 let status_str = exit.payload.unwrap_or_else(|| "0".to_string());
615 let status = status_str
616 .parse::<i32>()
617 .map_err(|_| anyhow!("Invalid custom exit status: {}", status_str))?;
618 ExitReason::CustomExitStatus(status)
619 },
620 other => other.try_into()?,
621 };
622
623 Ok(ServerToClientMsg::Exit { exit_reason })
624 },
625 Some(server_to_client_msg::Message::Connected(_)) => Ok(ServerToClientMsg::Connected),
626 Some(server_to_client_msg::Message::Log(log)) => {
627 Ok(ServerToClientMsg::Log { lines: log.lines })
628 },
629 Some(server_to_client_msg::Message::LogError(log_error)) => {
630 Ok(ServerToClientMsg::LogError {
631 lines: log_error.lines,
632 })
633 },
634 Some(server_to_client_msg::Message::SwitchSession(switch)) => {
635 Ok(ServerToClientMsg::SwitchSession {
636 connect_to_session: switch
637 .connect_to_session
638 .ok_or_else(|| anyhow!("Missing connect_to_session"))?
639 .try_into()?,
640 })
641 },
642 Some(server_to_client_msg::Message::UnblockCliPipeInput(unblock)) => {
643 Ok(ServerToClientMsg::UnblockCliPipeInput {
644 pipe_name: unblock.pipe_name,
645 })
646 },
647 Some(server_to_client_msg::Message::CliPipeOutput(pipe_output)) => {
648 Ok(ServerToClientMsg::CliPipeOutput {
649 pipe_name: pipe_output.pipe_name,
650 output: pipe_output.output,
651 })
652 },
653 Some(server_to_client_msg::Message::QueryTerminalSize(_)) => {
654 Ok(ServerToClientMsg::QueryTerminalSize)
655 },
656 Some(server_to_client_msg::Message::StartWebServer(_)) => {
657 Ok(ServerToClientMsg::StartWebServer)
658 },
659 Some(server_to_client_msg::Message::RenamedSession(renamed)) => {
660 Ok(ServerToClientMsg::RenamedSession { name: renamed.name })
661 },
662 Some(server_to_client_msg::Message::ConfigFileUpdated(_)) => {
663 Ok(ServerToClientMsg::ConfigFileUpdated)
664 },
665 Some(server_to_client_msg::Message::PaneRenderUpdate(msg)) => {
666 let pane_id: PaneId = msg
667 .pane_id
668 .ok_or_else(|| anyhow!("Missing pane_id"))?
669 .try_into()?;
670 let scrollback = if msg.has_scrollback {
671 Some(msg.scrollback)
672 } else {
673 None
674 };
675 Ok(ServerToClientMsg::PaneRenderUpdate {
676 pane_id,
677 viewport: msg.viewport,
678 scrollback,
679 is_initial: msg.is_initial,
680 })
681 },
682 Some(server_to_client_msg::Message::SubscribedPaneClosed(msg)) => {
683 let pane_id: PaneId = msg
684 .pane_id
685 .ok_or_else(|| anyhow!("Missing pane_id"))?
686 .try_into()?;
687 Ok(ServerToClientMsg::SubscribedPaneClosed { pane_id })
688 },
689 Some(server_to_client_msg::Message::ForwardQueryToHost(msg)) => {
690 Ok(ServerToClientMsg::ForwardQueryToHost {
691 token: msg.token,
692 query_bytes: msg.query_bytes,
693 resolve_async: msg.resolve_async,
694 })
695 },
696 Some(server_to_client_msg::Message::SetSoftKeyboard(msg)) => {
697 Ok(ServerToClientMsg::SetSoftKeyboard { on: msg.on })
698 },
699 Some(server_to_client_msg::Message::EmitNestedSessionFrame(msg)) => {
700 Ok(ServerToClientMsg::EmitNestedSessionFrame {
701 payload_bytes: msg.payload_bytes,
702 })
703 },
704 Some(server_to_client_msg::Message::MobileState(msg)) => {
705 Ok(ServerToClientMsg::MobileState {
706 payload: mobile_state_payload_from_proto(msg),
707 })
708 },
709 None => Err(anyhow!("Empty ServerToClientMsg message")),
710 }
711 }
712}
713
714impl From<crate::pane_size::Size> for crate::client_server_contract::client_server_contract::Size {
716 fn from(size: crate::pane_size::Size) -> Self {
717 Self {
718 cols: size.cols as u32,
719 rows: size.rows as u32,
720 }
721 }
722}
723
724impl TryFrom<crate::client_server_contract::client_server_contract::Size>
725 for crate::pane_size::Size
726{
727 type Error = anyhow::Error;
728 fn try_from(size: crate::client_server_contract::client_server_contract::Size) -> Result<Self> {
729 Ok(Self {
730 rows: size.rows as usize,
731 cols: size.cols as usize,
732 })
733 }
734}
735
736impl From<PixelDimensions>
737 for crate::client_server_contract::client_server_contract::PixelDimensions
738{
739 fn from(pixel_dims: PixelDimensions) -> Self {
740 Self {
741 text_area_size: pixel_dims.text_area_size.map(|size| {
742 crate::client_server_contract::client_server_contract::SizeInPixels {
743 width: size.width as u32,
744 height: size.height as u32,
745 }
746 }),
747 character_cell_size: pixel_dims.character_cell_size.map(|size| {
748 crate::client_server_contract::client_server_contract::SizeInPixels {
749 width: size.width as u32,
750 height: size.height as u32,
751 }
752 }),
753 }
754 }
755}
756
757impl TryFrom<crate::client_server_contract::client_server_contract::PixelDimensions>
758 for PixelDimensions
759{
760 type Error = anyhow::Error;
761 fn try_from(
762 pixel_dims: crate::client_server_contract::client_server_contract::PixelDimensions,
763 ) -> Result<Self> {
764 Ok(Self {
765 text_area_size: pixel_dims
766 .text_area_size
767 .map(|size| crate::pane_size::SizeInPixels {
768 width: size.width as usize,
769 height: size.height as usize,
770 }),
771 character_cell_size: pixel_dims.character_cell_size.map(|size| {
772 crate::pane_size::SizeInPixels {
773 width: size.width as usize,
774 height: size.height as usize,
775 }
776 }),
777 })
778 }
779}
780
781impl From<PaneReference> for crate::client_server_contract::client_server_contract::PaneReference {
782 fn from(pane_ref: PaneReference) -> Self {
783 Self {
784 pane_id: pane_ref.pane_id,
785 is_plugin: pane_ref.is_plugin,
786 }
787 }
788}
789
790impl TryFrom<crate::client_server_contract::client_server_contract::PaneReference>
791 for PaneReference
792{
793 type Error = anyhow::Error;
794 fn try_from(
795 pane_ref: crate::client_server_contract::client_server_contract::PaneReference,
796 ) -> Result<Self> {
797 Ok(Self {
798 pane_id: pane_ref.pane_id,
799 is_plugin: pane_ref.is_plugin,
800 })
801 }
802}
803
804impl From<ColorRegister> for crate::client_server_contract::client_server_contract::ColorRegister {
805 fn from(color_reg: ColorRegister) -> Self {
806 Self {
807 index: color_reg.index as u32,
808 color: color_reg.color,
809 }
810 }
811}
812
813impl TryFrom<crate::client_server_contract::client_server_contract::ColorRegister>
814 for ColorRegister
815{
816 type Error = anyhow::Error;
817 fn try_from(
818 color_reg: crate::client_server_contract::client_server_contract::ColorRegister,
819 ) -> Result<Self> {
820 Ok(Self {
821 index: color_reg.index as usize,
822 color: color_reg.color,
823 })
824 }
825}
826
827impl From<crate::input::cli_assets::CliAssets>
828 for crate::client_server_contract::client_server_contract::CliAssets
829{
830 fn from(cli_assets: crate::input::cli_assets::CliAssets) -> Self {
831 Self {
832 config_file_path: cli_assets
833 .config_file_path
834 .map(|p| p.to_string_lossy().to_string()),
835 config_dir: cli_assets
836 .config_dir
837 .map(|p| p.to_string_lossy().to_string()),
838 should_ignore_config: cli_assets.should_ignore_config,
839 configuration_options: cli_assets.configuration_options.map(|o| o.into()),
840 layout: cli_assets.layout.map(|l| l.into()),
841 terminal_window_size: Some(cli_assets.terminal_window_size.into()),
842 data_dir: cli_assets.data_dir.map(|p| p.to_string_lossy().to_string()),
843 is_debug: cli_assets.is_debug,
844 max_panes: cli_assets.max_panes.map(|m| m as u32),
845 force_run_layout_commands: cli_assets.force_run_layout_commands,
846 cwd: cli_assets.cwd.map(|p| p.to_string_lossy().to_string()),
847 host_terminal_env: cli_assets.host_terminal_env.into_iter().collect(),
848 }
849 }
850}
851
852impl TryFrom<crate::client_server_contract::client_server_contract::CliAssets>
853 for crate::input::cli_assets::CliAssets
854{
855 type Error = anyhow::Error;
856 fn try_from(
857 cli_assets: crate::client_server_contract::client_server_contract::CliAssets,
858 ) -> Result<Self> {
859 Ok(Self {
860 config_file_path: cli_assets.config_file_path.map(PathBuf::from),
861 config_dir: cli_assets.config_dir.map(PathBuf::from),
862 should_ignore_config: cli_assets.should_ignore_config,
863 configuration_options: cli_assets
864 .configuration_options
865 .map(|o| o.try_into())
866 .transpose()?,
867 layout: cli_assets.layout.map(|l| l.try_into()).transpose()?,
868 terminal_window_size: cli_assets
869 .terminal_window_size
870 .ok_or_else(|| anyhow!("CliAssets missing terminal_window_size"))?
871 .try_into()?,
872 data_dir: cli_assets.data_dir.map(PathBuf::from),
873 is_debug: cli_assets.is_debug,
874 max_panes: cli_assets.max_panes.map(|m| m as usize),
875 force_run_layout_commands: cli_assets.force_run_layout_commands,
876 cwd: cli_assets.cwd.map(PathBuf::from),
877 host_terminal_env: cli_assets.host_terminal_env.into_iter().collect(),
878 })
879 }
880}
881
882impl From<crate::input::options::Options>
883 for crate::client_server_contract::client_server_contract::Options
884{
885 fn from(options: crate::input::options::Options) -> Self {
886 use crate::client_server_contract::client_server_contract::{
887 Clipboard as ProtoClipboard, OnForceClose as ProtoOnForceClose,
888 WebSharing as ProtoWebSharing,
889 };
890
891 Self {
892 simplified_ui: options.simplified_ui,
893 theme: options.theme,
894 theme_dark: options.theme_dark,
895 theme_light: options.theme_light,
896 default_mode: options.default_mode.map(|m| input_mode_to_proto_i32(m)),
897 default_shell: options
898 .default_shell
899 .map(|p| p.to_string_lossy().to_string()),
900 default_cwd: options.default_cwd.map(|p| p.to_string_lossy().to_string()),
901 default_layout: options
902 .default_layout
903 .map(|p| p.to_string_lossy().to_string()),
904 layout_dir: options.layout_dir.map(|p| p.to_string_lossy().to_string()),
905 theme_dir: options.theme_dir.map(|p| p.to_string_lossy().to_string()),
906 mouse_mode: options.mouse_mode,
907 pane_frames: options.pane_frames,
908 mirror_session: options.mirror_session,
909 on_force_close: options.on_force_close.map(|o| match o {
910 crate::input::options::OnForceClose::Quit => ProtoOnForceClose::Quit as i32,
911 crate::input::options::OnForceClose::Detach => ProtoOnForceClose::Detach as i32,
912 }),
913 scroll_buffer_size: options.scroll_buffer_size.map(|s| s as u32),
914 copy_command: options.copy_command,
915 copy_clipboard: options.copy_clipboard.map(|c| match c {
916 crate::input::options::Clipboard::System => ProtoClipboard::System as i32,
917 crate::input::options::Clipboard::Primary => ProtoClipboard::Primary as i32,
918 }),
919 copy_on_select: options.copy_on_select,
920 osc8_hyperlinks: options.osc8_hyperlinks,
921 scrollback_editor: options
922 .scrollback_editor
923 .map(|p| p.to_string_lossy().to_string()),
924 session_name: options.session_name,
925 attach_to_session: options.attach_to_session,
926 auto_layout: options.auto_layout,
927 session_serialization: options.session_serialization,
928 serialize_pane_viewport: options.serialize_pane_viewport,
929 scrollback_lines_to_serialize: options.scrollback_lines_to_serialize.map(|s| s as u32),
930 styled_underlines: options.styled_underlines,
931 serialization_interval: options.serialization_interval,
932 disable_session_metadata: options.disable_session_metadata,
933 support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
934 support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
935 web_server: options.web_server,
936 web_sharing: options.web_sharing.map(|w| match w {
937 crate::data::WebSharing::On => ProtoWebSharing::On as i32,
938 crate::data::WebSharing::Off => ProtoWebSharing::Off as i32,
939 crate::data::WebSharing::Disabled => ProtoWebSharing::Disabled as i32,
940 }),
941 stacked_resize: options.stacked_resize,
942 stacked_pane_list: options.stacked_pane_list,
943 dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
944 show_startup_tips: options.show_startup_tips,
945 show_release_notes: options.show_release_notes,
946 advanced_mouse_actions: options.advanced_mouse_actions,
947 mouse_scroll_resize: options.mouse_scroll_resize,
948 mouse_hover_effects: options.mouse_hover_effects,
949 mouse_hover_tips: options.mouse_hover_tips,
950 web_server_ip: options.web_server_ip.map(|ip| ip.to_string()),
951 web_server_port: options.web_server_port.map(|p| p as u32),
952 web_server_cert: options
953 .web_server_cert
954 .map(|p| p.to_string_lossy().to_string()),
955 web_server_key: options
956 .web_server_key
957 .map(|p| p.to_string_lossy().to_string()),
958 enforce_https_for_localhost: options.enforce_https_for_localhost,
959 post_command_discovery_hook: options.post_command_discovery_hook,
960 client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as u64),
961 visual_bell: options.visual_bell,
962 focus_follows_mouse: options.focus_follows_mouse,
963 mouse_click_through: options.mouse_click_through,
964 osc133_command_selection: options.osc133_command_selection,
965 word_separators: options.word_separators,
966 host_notification_protocol: options
967 .host_notification_protocol
968 .map(|p| p.as_str().to_owned()),
969 pane_frame_style: options.pane_frame_style.map(|s| match s {
970 crate::input::options::PaneFrameStyle::Full => "full".to_owned(),
971 crate::input::options::PaneFrameStyle::Titles => "titles".to_owned(),
972 crate::input::options::PaneFrameStyle::None => "none".to_owned(),
973 }),
974 nested_session_handling: options.nested_session_handling.map(|n| {
975 use crate::client_server_contract::client_server_contract::NestedSessionHandling as ProtoNestedSessionHandling;
976 use crate::input::options::NestedSessionHandling;
977 match n {
978 NestedSessionHandling::Ask => ProtoNestedSessionHandling::Ask as i32,
979 NestedSessionHandling::Fullscreen => {
980 ProtoNestedSessionHandling::Fullscreen as i32
981 },
982 NestedSessionHandling::Descend => ProtoNestedSessionHandling::Descend as i32,
983 NestedSessionHandling::Never => ProtoNestedSessionHandling::Never as i32,
984 }
985 }),
986 }
987 }
988}
989
990impl TryFrom<crate::client_server_contract::client_server_contract::Options>
991 for crate::input::options::Options
992{
993 type Error = anyhow::Error;
994 fn try_from(
995 options: crate::client_server_contract::client_server_contract::Options,
996 ) -> Result<Self> {
997 use crate::client_server_contract::client_server_contract::{
998 Clipboard as ProtoClipboard, NestedSessionHandling as ProtoNestedSessionHandling,
999 OnForceClose as ProtoOnForceClose, WebSharing as ProtoWebSharing,
1000 };
1001
1002 Ok(Self {
1003 simplified_ui: options.simplified_ui,
1004 theme: options.theme,
1005 theme_dark: options.theme_dark,
1006 theme_light: options.theme_light,
1007 default_mode: options
1008 .default_mode
1009 .map(|m| proto_i32_to_input_mode(m))
1010 .transpose()?,
1011 default_shell: options.default_shell.map(std::path::PathBuf::from),
1012 default_cwd: options.default_cwd.map(std::path::PathBuf::from),
1013 default_layout: options.default_layout.map(std::path::PathBuf::from),
1014 layout_dir: options.layout_dir.map(std::path::PathBuf::from),
1015 theme_dir: options.theme_dir.map(std::path::PathBuf::from),
1016 mouse_mode: options.mouse_mode,
1017 pane_frames: options.pane_frames,
1018 pane_frame_style: options.pane_frame_style.as_deref().and_then(|s| match s {
1019 "full" => Some(crate::input::options::PaneFrameStyle::Full),
1020 "titles" => Some(crate::input::options::PaneFrameStyle::Titles),
1021 "none" => Some(crate::input::options::PaneFrameStyle::None),
1022 _ => None,
1023 }),
1024 mirror_session: options.mirror_session,
1025 on_force_close: options
1026 .on_force_close
1027 .map(|o| match ProtoOnForceClose::try_from(o).ok() {
1028 Some(ProtoOnForceClose::Quit) => Ok(crate::input::options::OnForceClose::Quit),
1029 Some(ProtoOnForceClose::Detach) => {
1030 Ok(crate::input::options::OnForceClose::Detach)
1031 },
1032 _ => Err(anyhow!("Invalid OnForceClose value: {}", o)),
1033 })
1034 .transpose()?,
1035 scroll_buffer_size: options.scroll_buffer_size.map(|s| s as usize),
1036 copy_command: options.copy_command,
1037 copy_clipboard: options
1038 .copy_clipboard
1039 .map(|c| match ProtoClipboard::try_from(c).ok() {
1040 Some(ProtoClipboard::System) => Ok(crate::input::options::Clipboard::System),
1041 Some(ProtoClipboard::Primary) => Ok(crate::input::options::Clipboard::Primary),
1042 _ => Err(anyhow!("Invalid Clipboard value: {}", c)),
1043 })
1044 .transpose()?,
1045 copy_on_select: options.copy_on_select,
1046 osc8_hyperlinks: options.osc8_hyperlinks,
1047 scrollback_editor: options.scrollback_editor.map(std::path::PathBuf::from),
1048 session_name: options.session_name,
1049 attach_to_session: options.attach_to_session,
1050 auto_layout: options.auto_layout,
1051 session_serialization: options.session_serialization,
1052 serialize_pane_viewport: options.serialize_pane_viewport,
1053 scrollback_lines_to_serialize: options
1054 .scrollback_lines_to_serialize
1055 .map(|s| s as usize),
1056 styled_underlines: options.styled_underlines,
1057 serialization_interval: options.serialization_interval,
1058 disable_session_metadata: options.disable_session_metadata,
1059 support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
1060 support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
1061 web_server: options.web_server,
1062 web_sharing: options
1063 .web_sharing
1064 .map(|w| match ProtoWebSharing::try_from(w).ok() {
1065 Some(ProtoWebSharing::On) => Ok(crate::data::WebSharing::On),
1066 Some(ProtoWebSharing::Off) => Ok(crate::data::WebSharing::Off),
1067 Some(ProtoWebSharing::Disabled) => Ok(crate::data::WebSharing::Disabled),
1068 _ => Err(anyhow!("Invalid WebSharing value: {}", w)),
1069 })
1070 .transpose()?,
1071 stacked_resize: options.stacked_resize,
1072 stacked_pane_list: options.stacked_pane_list,
1073 dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
1074 show_startup_tips: options.show_startup_tips,
1075 show_release_notes: options.show_release_notes,
1076 advanced_mouse_actions: options.advanced_mouse_actions,
1077 mouse_scroll_resize: options.mouse_scroll_resize,
1078 mouse_hover_effects: options.mouse_hover_effects,
1079 mouse_hover_tips: options.mouse_hover_tips,
1080 web_server_ip: options
1081 .web_server_ip
1082 .map(|ip| ip.parse())
1083 .transpose()
1084 .map_err(|e| anyhow!("Invalid IP address: {}", e))?,
1085 web_server_port: options.web_server_port.map(|p| p as u16),
1086 web_server_cert: options.web_server_cert.map(std::path::PathBuf::from),
1087 web_server_key: options.web_server_key.map(std::path::PathBuf::from),
1088 enforce_https_for_localhost: options.enforce_https_for_localhost,
1089 post_command_discovery_hook: options.post_command_discovery_hook,
1090 client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as usize),
1091 visual_bell: options.visual_bell,
1092 focus_follows_mouse: options.focus_follows_mouse,
1093 mouse_click_through: options.mouse_click_through,
1094 osc133_command_selection: options.osc133_command_selection,
1095 word_separators: options.word_separators,
1096 host_notification_protocol: options
1097 .host_notification_protocol
1098 .map(|p| {
1099 p.parse::<crate::input::options::HostNotificationProtocol>()
1100 .map_err(|e| anyhow!(e))
1101 })
1102 .transpose()?,
1103 nested_session_handling: options
1104 .nested_session_handling
1105 .map(|n| match ProtoNestedSessionHandling::try_from(n).ok() {
1106 Some(ProtoNestedSessionHandling::Ask) => {
1107 Ok(crate::input::options::NestedSessionHandling::Ask)
1108 },
1109 Some(ProtoNestedSessionHandling::Fullscreen) => {
1110 Ok(crate::input::options::NestedSessionHandling::Fullscreen)
1111 },
1112 Some(ProtoNestedSessionHandling::Descend) => {
1113 Ok(crate::input::options::NestedSessionHandling::Descend)
1114 },
1115 Some(ProtoNestedSessionHandling::Never) => {
1116 Ok(crate::input::options::NestedSessionHandling::Never)
1117 },
1118 _ => Err(anyhow!("Invalid NestedSessionHandling value: {}", n)),
1119 })
1120 .transpose()?,
1121 })
1122 }
1123}
1124
1125impl From<crate::input::actions::Action>
1127 for crate::client_server_contract::client_server_contract::Action
1128{
1129 fn from(action: crate::input::actions::Action) -> Self {
1130 use crate::client_server_contract::client_server_contract::{
1131 action::ActionType,
1132 AreFloatingPanesVisibleAction,
1133 BreakPaneAction,
1134 BreakPaneLeftAction,
1135 BreakPaneRightAction,
1136 ChangeFloatingPaneCoordinatesAction,
1137 ClearScreenAction,
1138 ClearScreenByPaneIdAction,
1139 CliPipeAction,
1140 CloseFocusAction,
1141 CloseFocusByPaneIdAction,
1142 ClosePluginPaneAction,
1143 CloseTabAction,
1144 CloseTabByIdAction,
1145 CloseTerminalPaneAction,
1146 ConfirmAction,
1147 CopyAction,
1148 CopyLastCommandOutputAction,
1149 CurrentTabInfoAction,
1150 DenyAction,
1151 DetachAction,
1152 DumpLayoutAction,
1153 DumpScreenAction,
1154 EditFileAction,
1155 EditScrollbackAction,
1156 EditScrollbackByPaneIdAction,
1157 FocusGuestSessionAction,
1158 FocusHostSessionAction,
1159 FocusLastPaneAction,
1160 FocusNextPaneAction,
1161 FocusPaneByPaneIdAction,
1162 FocusPluginPaneWithIdAction,
1163 FocusPreviousPaneAction,
1164 FocusTerminalPaneWithIdAction,
1165 GoToNextTabAction,
1166 GoToPreviousTabAction,
1167 GoToTabAction,
1168 GoToTabByIdAction,
1169 GoToTabNameAction,
1170 HalfPageScrollDownAction,
1171 HalfPageScrollDownByPaneIdAction,
1172 HalfPageScrollUpAction,
1173 HalfPageScrollUpByPaneIdAction,
1174 HideFloatingPanesAction,
1175 KeybindPipeAction,
1176 LaunchOrFocusPluginAction,
1177 LaunchPluginAction,
1178 ListClientsAction,
1179 ListPanesAction,
1180 ListTabsAction,
1181 MouseEventAction,
1182 MoveFocusAction,
1183 MoveFocusOrTabAction,
1184 MovePaneAction,
1185 MovePaneBackwardsAction,
1186 MovePaneBackwardsByPaneIdAction,
1187 MovePaneByPaneIdAction,
1188 MoveTabAction,
1189 MoveTabByTabIdAction,
1190 NewBlockingPaneAction,
1191 NewFloatingPaneAction,
1192 NewFloatingPluginPaneAction,
1193 NewInPlacePaneAction,
1194 NewInPlacePluginPaneAction,
1195 NewPaneAction,
1196 NewStackedPaneAction,
1197 NewTabAction,
1198 NewTiledPaneAction,
1199 NewTiledPluginPaneAction,
1200 NextSwapLayoutAction,
1201 NextSwapLayoutByTabIdAction,
1202 NoOpAction,
1203 OverrideLayoutAction,
1204 PageScrollDownAction,
1205 PageScrollDownByPaneIdAction,
1206 PageScrollUpAction,
1207 PageScrollUpByPaneIdAction,
1208 PaneIdWithPlugin,
1209 PaneNameInputAction,
1210 PasteAction,
1211 PreviousSwapLayoutAction,
1212 PreviousSwapLayoutByTabIdAction,
1213 QueryTabNamesAction,
1214 QuitAction,
1215 RenamePaneByPaneIdAction,
1216 RenamePluginPaneAction,
1217 RenameSessionAction,
1218 RenameTabAction,
1219 RenameTabByIdAction,
1220 RenameTerminalPaneAction,
1221 ResizeAction,
1222 ResizeByPaneIdAction,
1223 RunAction,
1224 SaveSessionAction,
1225 ScrollDownAction,
1226 ScrollDownAtAction,
1227 ScrollDownByPaneIdAction,
1228 ScrollToBottomAction,
1229 ScrollToBottomByPaneIdAction,
1230 ScrollToNextPromptAction,
1231 ScrollToPreviousPromptAction,
1232 ScrollToTopAction,
1233 ScrollToTopByPaneIdAction,
1234 ScrollUpAction,
1235 ScrollUpAtAction,
1236 ScrollUpByPaneIdAction,
1238 SearchAction,
1239 SearchInputAction,
1240 SearchToggleOptionAction,
1241 SelectCommandAtScrollPositionAction,
1242 SetDarkThemeAction,
1243 SetLightThemeAction,
1244 SetPaneBorderlessAction,
1245 SetPaneColorAction,
1246 SetPaneFrameStyleAction,
1247 ShowFloatingPanesAction,
1248 SkipConfirmAction,
1249 StackPanesAction,
1250 StartOrReloadPluginAction,
1251 SwitchFocusAction,
1252 SwitchModeForAllClientsAction,
1253 SwitchSessionAction,
1254 SwitchToModeAction,
1255 TabNameInputAction,
1256 ToggleActiveSyncTabAction,
1257 ToggleActiveSyncTabByTabIdAction,
1258 ToggleFloatingPanesAction,
1259 ToggleFloatingPanesByTabIdAction,
1260 ToggleFocusFullscreenAction,
1261 ToggleFocusNoUiFullscreenAction,
1262 ToggleFullscreenByPaneIdAction,
1263 ToggleGroupMarkingAction,
1264 ToggleHostFullscreenAction,
1265 ToggleMouseModeAction,
1266 ToggleNoUiFullscreenByPaneIdAction,
1267 TogglePaneBorderlessAction,
1268 TogglePaneEmbedOrFloatingAction,
1269 TogglePaneEmbedOrFloatingByPaneIdAction,
1270 TogglePaneFramesAction,
1271 TogglePaneInGroupAction,
1272 TogglePanePinnedAction,
1273 TogglePanePinnedByPaneIdAction,
1274 ToggleTabAction,
1275 ToggleThemeAction,
1276 UndoRenamePaneAction,
1277 UndoRenamePaneByPaneIdAction,
1278 UndoRenameTabAction,
1279 UndoRenameTabByTabIdAction,
1281 WriteAction,
1282 WriteCharsAction,
1283 WriteCharsToPaneIdAction,
1284 WriteToPaneIdAction,
1285 };
1286 use std::collections::HashMap;
1287
1288 let action_type = match action {
1289 crate::input::actions::Action::Quit => ActionType::Quit(QuitAction {}),
1290 crate::input::actions::Action::Write {
1291 key_with_modifier,
1292 bytes,
1293 is_kitty_keyboard_protocol,
1294 } => ActionType::Write(WriteAction {
1295 key_with_modifier: key_with_modifier.map(|k| k.into()),
1296 bytes: bytes.into_iter().map(|b| b as u32).collect(),
1297 is_kitty_keyboard_protocol,
1298 }),
1299 crate::input::actions::Action::WriteChars { chars } => {
1300 ActionType::WriteChars(WriteCharsAction { chars })
1301 },
1302 crate::input::actions::Action::WriteToPaneId { bytes, pane_id } => {
1303 ActionType::WriteToPaneId(WriteToPaneIdAction {
1304 pane_id: Some(pane_id.into()),
1305 bytes: bytes.into_iter().map(|b| b as u32).collect(),
1306 })
1307 },
1308 crate::input::actions::Action::WriteCharsToPaneId { chars, pane_id } => {
1309 ActionType::WriteCharsToPaneId(WriteCharsToPaneIdAction {
1310 pane_id: Some(pane_id.into()),
1311 chars,
1312 })
1313 },
1314 crate::input::actions::Action::Paste { chars, pane_id } => {
1315 ActionType::Paste(PasteAction {
1316 chars,
1317 pane_id: pane_id.map(|p| p.into()),
1318 })
1319 },
1320 crate::input::actions::Action::SwitchToMode { input_mode } => {
1321 ActionType::SwitchToMode(SwitchToModeAction {
1322 input_mode: input_mode_to_proto_i32(input_mode),
1323 })
1324 },
1325 crate::input::actions::Action::SwitchModeForAllClients { input_mode } => {
1326 ActionType::SwitchModeForAllClients(SwitchModeForAllClientsAction {
1327 input_mode: input_mode_to_proto_i32(input_mode),
1328 })
1329 },
1330 crate::input::actions::Action::Resize { resize, direction } => {
1331 ActionType::Resize(ResizeAction {
1332 resize: resize_to_proto_i32(resize),
1333 direction: direction.map(|d| direction_to_proto_i32(d)),
1334 })
1335 },
1336 crate::input::actions::Action::FocusNextPane => {
1337 ActionType::FocusNextPane(FocusNextPaneAction {})
1338 },
1339 crate::input::actions::Action::FocusPreviousPane => {
1340 ActionType::FocusPreviousPane(FocusPreviousPaneAction {})
1341 },
1342 crate::input::actions::Action::FocusLastPane => {
1343 ActionType::FocusLastPane(FocusLastPaneAction {})
1344 },
1345 crate::input::actions::Action::FocusHostSession => {
1346 ActionType::FocusHostSession(FocusHostSessionAction {})
1347 },
1348 crate::input::actions::Action::FocusGuestSession => {
1349 ActionType::FocusGuestSession(FocusGuestSessionAction {})
1350 },
1351 crate::input::actions::Action::ToggleHostFullscreen => {
1352 ActionType::ToggleHostFullscreen(ToggleHostFullscreenAction {})
1353 },
1354 crate::input::actions::Action::SwitchFocus => {
1355 ActionType::SwitchFocus(SwitchFocusAction {})
1356 },
1357 crate::input::actions::Action::MoveFocus { direction } => {
1358 ActionType::MoveFocus(MoveFocusAction {
1359 direction: direction_to_proto_i32(direction),
1360 })
1361 },
1362 crate::input::actions::Action::MoveFocusOrTab { direction } => {
1363 ActionType::MoveFocusOrTab(MoveFocusOrTabAction {
1364 direction: direction_to_proto_i32(direction),
1365 })
1366 },
1367 crate::input::actions::Action::MovePane { direction } => {
1368 ActionType::MovePane(MovePaneAction {
1369 direction: direction.map(|d| direction_to_proto_i32(d)),
1370 })
1371 },
1372 crate::input::actions::Action::MovePaneBackwards => {
1373 ActionType::MovePaneBackwards(MovePaneBackwardsAction {})
1374 },
1375 crate::input::actions::Action::ClearScreen => {
1376 ActionType::ClearScreen(ClearScreenAction {})
1377 },
1378 crate::input::actions::Action::DumpScreen {
1379 file_path,
1380 include_scrollback,
1381 pane_id,
1382 ansi,
1383 } => {
1384 let dump_to_stdout = file_path.is_none();
1385 ActionType::DumpScreen(DumpScreenAction {
1386 file_path: file_path.unwrap_or_default(),
1387 include_scrollback,
1388 pane_id: pane_id.map(|p| p.into()),
1389 dump_to_stdout,
1390 ansi,
1391 })
1392 },
1393 crate::input::actions::Action::DumpLayout => {
1394 ActionType::DumpLayout(DumpLayoutAction {})
1395 },
1396 crate::input::actions::Action::EditScrollback { ansi } => {
1397 ActionType::EditScrollback(EditScrollbackAction { ansi })
1398 },
1399 crate::input::actions::Action::ScrollUp => ActionType::ScrollUp(ScrollUpAction {}),
1400 crate::input::actions::Action::ScrollUpAt { position } => {
1401 ActionType::ScrollUpAt(ScrollUpAtAction {
1402 position: Some(position.into()),
1403 })
1404 },
1405 crate::input::actions::Action::ScrollDown => {
1406 ActionType::ScrollDown(ScrollDownAction {})
1407 },
1408 crate::input::actions::Action::ScrollDownAt { position } => {
1409 ActionType::ScrollDownAt(ScrollDownAtAction {
1410 position: Some(position.into()),
1411 })
1412 },
1413 crate::input::actions::Action::ScrollToBottom => {
1414 ActionType::ScrollToBottom(ScrollToBottomAction {})
1415 },
1416 crate::input::actions::Action::ScrollToTop => {
1417 ActionType::ScrollToTop(ScrollToTopAction {})
1418 },
1419 crate::input::actions::Action::ScrollToPreviousPrompt => {
1420 ActionType::ScrollToPreviousPrompt(ScrollToPreviousPromptAction {})
1421 },
1422 crate::input::actions::Action::ScrollToNextPrompt => {
1423 ActionType::ScrollToNextPrompt(ScrollToNextPromptAction {})
1424 },
1425 crate::input::actions::Action::SelectCommandAtScrollPosition => {
1426 ActionType::SelectCommandAtScrollPosition(SelectCommandAtScrollPositionAction {})
1427 },
1428 crate::input::actions::Action::CopyLastCommandOutput => {
1429 ActionType::CopyLastCommandOutput(CopyLastCommandOutputAction {})
1430 },
1431 crate::input::actions::Action::PageScrollUp => {
1432 ActionType::PageScrollUp(PageScrollUpAction {})
1433 },
1434 crate::input::actions::Action::PageScrollDown => {
1435 ActionType::PageScrollDown(PageScrollDownAction {})
1436 },
1437 crate::input::actions::Action::HalfPageScrollUp => {
1438 ActionType::HalfPageScrollUp(HalfPageScrollUpAction {})
1439 },
1440 crate::input::actions::Action::HalfPageScrollDown => {
1441 ActionType::HalfPageScrollDown(HalfPageScrollDownAction {})
1442 },
1443 crate::input::actions::Action::ToggleFocusFullscreen => {
1444 ActionType::ToggleFocusFullscreen(ToggleFocusFullscreenAction {})
1445 },
1446 crate::input::actions::Action::ToggleFocusNoUiFullscreen => {
1447 ActionType::ToggleFocusNoUiFullscreen(ToggleFocusNoUiFullscreenAction {})
1448 },
1449 crate::input::actions::Action::TogglePaneFrames => {
1450 ActionType::TogglePaneFrames(TogglePaneFramesAction {})
1451 },
1452 crate::input::actions::Action::SetPaneFrameStyle(style) => {
1453 let style = match style {
1454 crate::input::options::PaneFrameStyle::Full => "full",
1455 crate::input::options::PaneFrameStyle::Titles => "titles",
1456 crate::input::options::PaneFrameStyle::None => "none",
1457 };
1458 ActionType::SetPaneFrameStyle(SetPaneFrameStyleAction {
1459 style: style.to_owned(),
1460 })
1461 },
1462 crate::input::actions::Action::ToggleActiveSyncTab => {
1463 ActionType::ToggleActiveSyncTab(ToggleActiveSyncTabAction {})
1464 },
1465 crate::input::actions::Action::NewPane {
1466 direction,
1467 pane_name,
1468 start_suppressed,
1469 } => ActionType::NewPane(NewPaneAction {
1470 direction: direction.map(|d| direction_to_proto_i32(d)),
1471 pane_name,
1472 start_suppressed,
1473 near_current_pane: false,
1474 }),
1475 crate::input::actions::Action::EditFile {
1476 payload,
1477 direction,
1478 floating,
1479 in_place,
1480 close_replaced_pane,
1481 start_suppressed,
1482 coordinates,
1483 near_current_pane,
1484 no_focus,
1485 tab_id,
1486 ..
1487 } => ActionType::EditFile(EditFileAction {
1488 payload: Some(payload.into()),
1489 direction: direction.map(|d| direction_to_proto_i32(d)),
1490 floating,
1491 in_place,
1492 close_replaced_pane,
1493 start_suppressed,
1494 coordinates: coordinates.map(|c| c.into()),
1495 near_current_pane,
1496 tab_id: tab_id.map(|t| t as u32),
1497 no_focus,
1498 }),
1499 crate::input::actions::Action::NewFloatingPane {
1500 command,
1501 pane_name,
1502 coordinates,
1503 near_current_pane,
1504 no_focus,
1505 tab_id,
1506 ..
1507 } => ActionType::NewFloatingPane(NewFloatingPaneAction {
1508 command: command.map(|c| c.into()),
1509 pane_name,
1510 coordinates: coordinates.map(|c| c.into()),
1511 near_current_pane,
1512 tab_id: tab_id.map(|t| t as u32),
1513 no_focus,
1514 }),
1515 crate::input::actions::Action::NewTiledPane {
1516 direction,
1517 command,
1518 pane_name,
1519 near_current_pane,
1520 no_focus,
1521 borderless,
1522 tab_id,
1523 ..
1524 } => ActionType::NewTiledPane(NewTiledPaneAction {
1525 direction: direction.map(|d| direction_to_proto_i32(d)),
1526 command: command.map(|c| c.into()),
1527 pane_name,
1528 near_current_pane,
1529 borderless,
1530 tab_id: tab_id.map(|t| t as u32),
1531 no_focus,
1532 }),
1533 crate::input::actions::Action::NewInPlacePane {
1534 command,
1535 pane_name,
1536 near_current_pane,
1537 no_focus,
1538 pane_id_to_replace,
1539 close_replaced_pane,
1540 tab_id,
1541 ..
1542 } => ActionType::NewInPlacePane(NewInPlacePaneAction {
1543 command: command.map(|c| c.into()),
1544 pane_name,
1545 near_current_pane,
1546 pane_id_to_replace: pane_id_to_replace.and_then(|p| p.try_into().ok()),
1547 close_replaced_pane,
1548 tab_id: tab_id.map(|t| t as u32),
1549 no_focus,
1550 }),
1551 crate::input::actions::Action::NewStackedPane {
1552 command,
1553 pane_name,
1554 near_current_pane,
1555 no_focus,
1556 tab_id,
1557 ..
1558 } => ActionType::NewStackedPane(NewStackedPaneAction {
1559 command: command.map(|c| c.into()),
1560 pane_name,
1561 near_current_pane,
1562 tab_id: tab_id.map(|t| t as u32),
1563 no_focus,
1564 }),
1565 crate::input::actions::Action::NewBlockingPane {
1566 placement,
1567 pane_name,
1568 command,
1569 unblock_condition,
1570 near_current_pane,
1571 no_focus,
1572 tab_id,
1573 ..
1574 } => ActionType::NewBlockingPane(NewBlockingPaneAction {
1575 placement: Some(placement.into()),
1576 pane_name,
1577 command: command.map(|c| c.into()),
1578 unblock_condition: unblock_condition.map(|c| unblock_condition_to_proto_i32(c)),
1579 near_current_pane,
1580 tab_id: tab_id.map(|t| t as u32),
1581 no_focus,
1582 }),
1583 crate::input::actions::Action::TogglePaneEmbedOrFloating => {
1584 ActionType::TogglePaneEmbedOrFloating(TogglePaneEmbedOrFloatingAction {})
1585 },
1586 crate::input::actions::Action::ToggleFloatingPanes => {
1587 ActionType::ToggleFloatingPanes(ToggleFloatingPanesAction {})
1588 },
1589 crate::input::actions::Action::ShowFloatingPanes { tab_id } => {
1590 ActionType::ShowFloatingPanes(ShowFloatingPanesAction {
1591 tab_id: tab_id.map(|id| id as u32),
1592 })
1593 },
1594 crate::input::actions::Action::HideFloatingPanes { tab_id } => {
1595 ActionType::HideFloatingPanes(HideFloatingPanesAction {
1596 tab_id: tab_id.map(|id| id as u32),
1597 })
1598 },
1599 crate::input::actions::Action::AreFloatingPanesVisible { tab_id } => {
1600 ActionType::AreFloatingPanesVisible(AreFloatingPanesVisibleAction {
1601 tab_id: tab_id.map(|id| id as u32),
1602 })
1603 },
1604 crate::input::actions::Action::CloseFocus => {
1605 ActionType::CloseFocus(CloseFocusAction {})
1606 },
1607 crate::input::actions::Action::PaneNameInput { input } => {
1608 ActionType::PaneNameInput(PaneNameInputAction {
1609 input: input.into_iter().map(|b| b as u32).collect(),
1610 })
1611 },
1612 crate::input::actions::Action::UndoRenamePane => {
1613 ActionType::UndoRenamePane(UndoRenamePaneAction {})
1614 },
1615 crate::input::actions::Action::NewTab {
1616 tiled_layout,
1617 floating_layouts,
1618 swap_tiled_layouts,
1619 swap_floating_layouts,
1620 tab_name,
1621 should_change_focus_to_new_tab,
1622 cwd,
1623 initial_panes,
1624 first_pane_unblock_condition,
1625 } => ActionType::NewTab(NewTabAction {
1626 tiled_layout: tiled_layout.map(|l| l.into()),
1627 floating_layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
1628 swap_tiled_layouts: swap_tiled_layouts
1629 .map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
1630 .unwrap_or_default(),
1631 swap_floating_layouts: swap_floating_layouts
1632 .map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
1633 .unwrap_or_default(),
1634 tab_name,
1635 should_change_focus_to_new_tab,
1636 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1637 initial_panes: initial_panes
1638 .map(|panes| panes.into_iter().map(|p| p.into()).collect())
1639 .unwrap_or_default(),
1640 first_pane_unblock_condition: first_pane_unblock_condition
1641 .map(|c| unblock_condition_to_proto_i32(c)),
1642 }),
1643 crate::input::actions::Action::NoOp => ActionType::NoOp(NoOpAction {}),
1644 crate::input::actions::Action::GoToNextTab => {
1645 ActionType::GoToNextTab(GoToNextTabAction {})
1646 },
1647 crate::input::actions::Action::GoToPreviousTab => {
1648 ActionType::GoToPreviousTab(GoToPreviousTabAction {})
1649 },
1650 crate::input::actions::Action::CloseTab => ActionType::CloseTab(CloseTabAction {}),
1651 crate::input::actions::Action::GoToTab { index } => {
1652 ActionType::GoToTab(GoToTabAction { index })
1653 },
1654 crate::input::actions::Action::GoToTabName { name, create } => {
1655 ActionType::GoToTabName(GoToTabNameAction { name, create })
1656 },
1657 crate::input::actions::Action::ToggleTab => ActionType::ToggleTab(ToggleTabAction {}),
1658 crate::input::actions::Action::TabNameInput { input } => {
1659 ActionType::TabNameInput(TabNameInputAction {
1660 input: input.into_iter().map(|b| b as u32).collect(),
1661 })
1662 },
1663 crate::input::actions::Action::UndoRenameTab => {
1664 ActionType::UndoRenameTab(UndoRenameTabAction {})
1665 },
1666 crate::input::actions::Action::MoveTab { direction } => {
1667 ActionType::MoveTab(MoveTabAction {
1668 direction: direction_to_proto_i32(direction),
1669 })
1670 },
1671 crate::input::actions::Action::Run {
1672 command,
1673 near_current_pane,
1674 no_focus,
1675 } => ActionType::Run(RunAction {
1676 command: Some(command.into()),
1677 near_current_pane,
1678 no_focus,
1679 }),
1680 crate::input::actions::Action::Detach => ActionType::Detach(DetachAction {}),
1681 crate::input::actions::Action::SetDarkTheme => {
1682 ActionType::SetDarkTheme(SetDarkThemeAction {})
1683 },
1684 crate::input::actions::Action::SetLightTheme => {
1685 ActionType::SetLightTheme(SetLightThemeAction {})
1686 },
1687 crate::input::actions::Action::ToggleTheme => {
1688 ActionType::ToggleTheme(ToggleThemeAction {})
1689 },
1690 crate::input::actions::Action::SwitchSession {
1691 name,
1692 tab_position,
1693 pane_id,
1694 layout,
1695 cwd,
1696 } => ActionType::SwitchSession(SwitchSessionAction {
1697 name: name.clone(),
1698 tab_position: tab_position.map(|p| p as u32),
1699 pane_id: pane_id.map(|(id, is_plugin)| PaneIdWithPlugin {
1700 pane_id: id,
1701 is_plugin: is_plugin,
1702 }),
1703 layout: layout.as_ref().map(|l| l.clone().into()),
1704 cwd: cwd.as_ref().map(|p| p.to_string_lossy().to_string()),
1705 }),
1706 crate::input::actions::Action::LaunchOrFocusPlugin {
1707 plugin,
1708 should_float,
1709 move_to_focused_tab,
1710 should_open_in_place,
1711 close_replaced_pane,
1712 skip_cache,
1713 tab_id,
1714 ..
1715 } => ActionType::LaunchOrFocusPlugin(LaunchOrFocusPluginAction {
1716 plugin: Some(plugin.into()),
1717 should_float,
1718 move_to_focused_tab,
1719 should_open_in_place,
1720 close_replaced_pane,
1721 skip_cache,
1722 tab_id: tab_id.map(|t| t as u32),
1723 }),
1724 crate::input::actions::Action::LaunchPlugin {
1725 plugin,
1726 should_float,
1727 should_open_in_place,
1728 close_replaced_pane,
1729 skip_cache,
1730 cwd,
1731 no_focus,
1732 tab_id,
1733 ..
1734 } => ActionType::LaunchPlugin(LaunchPluginAction {
1735 plugin: Some(plugin.into()),
1736 should_float,
1737 should_open_in_place,
1738 close_replaced_pane,
1739 skip_cache,
1740 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1741 tab_id: tab_id.map(|t| t as u32),
1742 no_focus,
1743 }),
1744 crate::input::actions::Action::MouseEvent { event } => {
1745 ActionType::MouseEvent(MouseEventAction {
1746 event: Some(event.into()),
1747 })
1748 },
1749 crate::input::actions::Action::Copy => ActionType::Copy(CopyAction {}),
1750 crate::input::actions::Action::Confirm => ActionType::Confirm(ConfirmAction {}),
1751 crate::input::actions::Action::Deny => ActionType::Deny(DenyAction {}),
1752 crate::input::actions::Action::SkipConfirm { action } => {
1753 ActionType::SkipConfirm(Box::new(SkipConfirmAction {
1754 action: Some(Box::new((*action).into())),
1755 }))
1756 },
1757 crate::input::actions::Action::SearchInput { input } => {
1758 ActionType::SearchInput(SearchInputAction {
1759 input: input.into_iter().map(|b| b as u32).collect(),
1760 })
1761 },
1762 crate::input::actions::Action::Search { direction } => {
1763 ActionType::Search(SearchAction {
1764 direction: search_direction_to_proto_i32(direction),
1765 })
1766 },
1767 crate::input::actions::Action::SearchToggleOption { option } => {
1768 ActionType::SearchToggleOption(SearchToggleOptionAction {
1769 option: search_option_to_proto_i32(option),
1770 })
1771 },
1772 crate::input::actions::Action::ToggleMouseMode => {
1773 ActionType::ToggleMouseMode(ToggleMouseModeAction {})
1774 },
1775 crate::input::actions::Action::PreviousSwapLayout => {
1776 ActionType::PreviousSwapLayout(PreviousSwapLayoutAction {})
1777 },
1778 crate::input::actions::Action::NextSwapLayout => {
1779 ActionType::NextSwapLayout(NextSwapLayoutAction {})
1780 },
1781 crate::input::actions::Action::OverrideLayout {
1782 tabs,
1783 retain_existing_terminal_panes,
1784 retain_existing_plugin_panes,
1785 apply_only_to_active_tab,
1786 } => ActionType::OverrideLayout(OverrideLayoutAction {
1787 tabs: tabs.into_iter().map(|t| t.into()).collect(),
1788 retain_existing_terminal_panes,
1789 retain_existing_plugin_panes,
1790 apply_only_to_active_tab,
1791 }),
1792 crate::input::actions::Action::QueryTabNames => {
1793 ActionType::QueryTabNames(QueryTabNamesAction {})
1794 },
1795 crate::input::actions::Action::NewTiledPluginPane {
1796 plugin,
1797 pane_name,
1798 skip_cache,
1799 cwd,
1800 no_focus,
1801 tab_id,
1802 ..
1803 } => ActionType::NewTiledPluginPane(NewTiledPluginPaneAction {
1804 plugin: Some(plugin.into()),
1805 pane_name,
1806 skip_cache,
1807 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1808 tab_id: tab_id.map(|t| t as u32),
1809 no_focus,
1810 }),
1811 crate::input::actions::Action::NewFloatingPluginPane {
1812 plugin,
1813 pane_name,
1814 skip_cache,
1815 cwd,
1816 coordinates,
1817 no_focus,
1818 tab_id,
1819 ..
1820 } => ActionType::NewFloatingPluginPane(NewFloatingPluginPaneAction {
1821 plugin: Some(plugin.into()),
1822 pane_name,
1823 skip_cache,
1824 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1825 coordinates: coordinates.map(|c| c.into()),
1826 tab_id: tab_id.map(|t| t as u32),
1827 no_focus,
1828 }),
1829 crate::input::actions::Action::NewInPlacePluginPane {
1830 plugin,
1831 pane_name,
1832 skip_cache,
1833 close_replaced_pane,
1834 no_focus,
1835 tab_id,
1836 ..
1837 } => ActionType::NewInPlacePluginPane(NewInPlacePluginPaneAction {
1838 plugin: Some(plugin.into()),
1839 pane_name,
1840 skip_cache,
1841 close_replaced_pane,
1842 tab_id: tab_id.map(|t| t as u32),
1843 no_focus,
1844 }),
1845 crate::input::actions::Action::StartOrReloadPlugin { plugin } => {
1846 ActionType::StartOrReloadPlugin(StartOrReloadPluginAction {
1847 plugin: Some(plugin.into()),
1848 })
1849 },
1850 crate::input::actions::Action::CloseTerminalPane { pane_id } => {
1851 ActionType::CloseTerminalPane(CloseTerminalPaneAction { pane_id })
1852 },
1853 crate::input::actions::Action::ClosePluginPane { pane_id } => {
1854 ActionType::ClosePluginPane(ClosePluginPaneAction { pane_id })
1855 },
1856 crate::input::actions::Action::FocusTerminalPaneWithId {
1857 pane_id,
1858 should_float_if_hidden,
1859 should_be_in_place_if_hidden,
1860 } => ActionType::FocusTerminalPaneWithId(FocusTerminalPaneWithIdAction {
1861 pane_id,
1862 should_float_if_hidden,
1863 should_be_in_place_if_hidden,
1864 }),
1865 crate::input::actions::Action::FocusPluginPaneWithId {
1866 pane_id,
1867 should_float_if_hidden,
1868 should_be_in_place_if_hidden,
1869 } => ActionType::FocusPluginPaneWithId(FocusPluginPaneWithIdAction {
1870 pane_id,
1871 should_float_if_hidden,
1872 should_be_in_place_if_hidden,
1873 }),
1874 crate::input::actions::Action::RenameTerminalPane { pane_id, name } => {
1875 ActionType::RenameTerminalPane(RenameTerminalPaneAction {
1876 pane_id,
1877 name: name.into_iter().map(|b| b as u32).collect(),
1878 })
1879 },
1880 crate::input::actions::Action::RenamePluginPane { pane_id, name } => {
1881 ActionType::RenamePluginPane(RenamePluginPaneAction {
1882 pane_id,
1883 name: name.into_iter().map(|b| b as u32).collect(),
1884 })
1885 },
1886 crate::input::actions::Action::RenameTab { tab_index, name } => {
1887 ActionType::RenameTab(RenameTabAction {
1888 tab_index,
1889 name: name.into_iter().map(|b| b as u32).collect(),
1890 })
1891 },
1892 crate::input::actions::Action::GoToTabById { id } => {
1893 ActionType::GoToTabById(GoToTabByIdAction { id })
1894 },
1895 crate::input::actions::Action::CloseTabById { id } => {
1896 ActionType::CloseTabById(CloseTabByIdAction { id })
1897 },
1898 crate::input::actions::Action::RenameTabById { id, name } => {
1899 ActionType::RenameTabById(RenameTabByIdAction { id, name })
1900 },
1901 crate::input::actions::Action::BreakPane => ActionType::BreakPane(BreakPaneAction {}),
1902 crate::input::actions::Action::BreakPaneRight => {
1903 ActionType::BreakPaneRight(BreakPaneRightAction {})
1904 },
1905 crate::input::actions::Action::BreakPaneLeft => {
1906 ActionType::BreakPaneLeft(BreakPaneLeftAction {})
1907 },
1908 crate::input::actions::Action::RenameSession { name } => {
1909 ActionType::RenameSession(RenameSessionAction { name })
1910 },
1911 crate::input::actions::Action::CliPipe {
1912 pipe_id,
1913 name,
1914 payload,
1915 args,
1916 plugin,
1917 configuration,
1918 launch_new,
1919 skip_cache,
1920 floating,
1921 in_place,
1922 cwd,
1923 pane_title,
1924 } => ActionType::CliPipe(CliPipeAction {
1925 pipe_id,
1926 name,
1927 payload,
1928 args: args
1929 .map(|a| a.into_iter().collect::<HashMap<_, _>>())
1930 .unwrap_or_default(),
1931 plugin,
1932 configuration: configuration
1933 .map(|c| c.into_iter().collect::<HashMap<_, _>>())
1934 .unwrap_or_default(),
1935 launch_new,
1936 skip_cache,
1937 floating,
1938 in_place,
1939 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1940 pane_title,
1941 }),
1942 crate::input::actions::Action::KeybindPipe {
1943 name,
1944 payload,
1945 args,
1946 plugin,
1947 plugin_id,
1948 configuration,
1949 launch_new,
1950 skip_cache,
1951 floating,
1952 in_place,
1953 cwd,
1954 pane_title,
1955 } => ActionType::KeybindPipe(KeybindPipeAction {
1956 name,
1957 payload,
1958 args: args
1959 .map(|a| a.into_iter().collect::<HashMap<_, _>>())
1960 .unwrap_or_default(),
1961 plugin,
1962 plugin_id,
1963 configuration: configuration
1964 .map(|c| c.into_iter().collect::<HashMap<_, _>>())
1965 .unwrap_or_default(),
1966 launch_new,
1967 skip_cache,
1968 floating,
1969 in_place,
1970 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1971 pane_title,
1972 }),
1973 crate::input::actions::Action::ListClients => {
1974 ActionType::ListClients(ListClientsAction {})
1975 },
1976 crate::input::actions::Action::ListPanes {
1977 show_tab,
1978 show_command,
1979 show_state,
1980 show_geometry,
1981 show_all,
1982 output_json,
1983 } => ActionType::ListPanes(ListPanesAction {
1984 show_tab,
1985 show_command,
1986 show_state,
1987 show_geometry,
1988 show_all,
1989 output_json,
1990 }),
1991 crate::input::actions::Action::TogglePanePinned => {
1992 ActionType::TogglePanePinned(TogglePanePinnedAction {})
1993 },
1994 crate::input::actions::Action::StackPanes { pane_ids } => {
1995 ActionType::StackPanes(StackPanesAction {
1996 pane_ids: pane_ids.into_iter().map(|id| id.into()).collect(),
1997 })
1998 },
1999 crate::input::actions::Action::ChangeFloatingPaneCoordinates {
2000 pane_id,
2001 coordinates,
2002 } => ActionType::ChangeFloatingPaneCoordinates(ChangeFloatingPaneCoordinatesAction {
2003 pane_id: Some(pane_id.into()),
2004 coordinates: Some(coordinates.into()),
2005 }),
2006 crate::input::actions::Action::TogglePaneBorderless { pane_id } => {
2007 ActionType::TogglePaneBorderless(TogglePaneBorderlessAction {
2008 pane_id: Some(pane_id.into()),
2009 })
2010 },
2011 crate::input::actions::Action::SetPaneBorderless {
2012 pane_id,
2013 borderless,
2014 } => ActionType::SetPaneBorderless(SetPaneBorderlessAction {
2015 pane_id: Some(pane_id.into()),
2016 borderless,
2017 }),
2018 crate::input::actions::Action::TogglePaneInGroup => {
2019 ActionType::TogglePaneInGroup(TogglePaneInGroupAction {})
2020 },
2021 crate::input::actions::Action::ToggleGroupMarking => {
2022 ActionType::ToggleGroupMarking(ToggleGroupMarkingAction {})
2023 },
2024 crate::input::actions::Action::SaveSession => {
2025 ActionType::SaveSession(SaveSessionAction {})
2026 },
2027 crate::input::actions::Action::ListTabs {
2028 show_state,
2029 show_dimensions,
2030 show_panes,
2031 show_layout,
2032 show_all,
2033 output_json,
2034 } => ActionType::ListTabs(ListTabsAction {
2035 show_state,
2036 show_dimensions,
2037 show_panes,
2038 show_layout,
2039 show_all,
2040 output_json,
2041 }),
2042 crate::input::actions::Action::CurrentTabInfo { output_json } => {
2043 ActionType::CurrentTabInfo(CurrentTabInfoAction { output_json })
2044 },
2045 crate::input::actions::Action::SetPaneColor { pane_id, fg, bg } => {
2046 ActionType::SetPaneColor(SetPaneColorAction {
2047 pane_id: Some(pane_id.into()),
2048 fg,
2049 bg,
2050 })
2051 },
2052 crate::input::actions::Action::ScrollUpByPaneId { pane_id } => {
2054 ActionType::ScrollUpByPaneId(ScrollUpByPaneIdAction {
2055 pane_id: Some(pane_id.into()),
2056 })
2057 },
2058 crate::input::actions::Action::ScrollDownByPaneId { pane_id } => {
2059 ActionType::ScrollDownByPaneId(ScrollDownByPaneIdAction {
2060 pane_id: Some(pane_id.into()),
2061 })
2062 },
2063 crate::input::actions::Action::ScrollToTopByPaneId { pane_id } => {
2064 ActionType::ScrollToTopByPaneId(ScrollToTopByPaneIdAction {
2065 pane_id: Some(pane_id.into()),
2066 })
2067 },
2068 crate::input::actions::Action::ScrollToBottomByPaneId { pane_id } => {
2069 ActionType::ScrollToBottomByPaneId(ScrollToBottomByPaneIdAction {
2070 pane_id: Some(pane_id.into()),
2071 })
2072 },
2073 crate::input::actions::Action::PageScrollUpByPaneId { pane_id } => {
2074 ActionType::PageScrollUpByPaneId(PageScrollUpByPaneIdAction {
2075 pane_id: Some(pane_id.into()),
2076 })
2077 },
2078 crate::input::actions::Action::PageScrollDownByPaneId { pane_id } => {
2079 ActionType::PageScrollDownByPaneId(PageScrollDownByPaneIdAction {
2080 pane_id: Some(pane_id.into()),
2081 })
2082 },
2083 crate::input::actions::Action::HalfPageScrollUpByPaneId { pane_id } => {
2084 ActionType::HalfPageScrollUpByPaneId(HalfPageScrollUpByPaneIdAction {
2085 pane_id: Some(pane_id.into()),
2086 })
2087 },
2088 crate::input::actions::Action::HalfPageScrollDownByPaneId { pane_id } => {
2089 ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
2090 pane_id: Some(pane_id.into()),
2091 })
2092 },
2093 crate::input::actions::Action::ResizeByPaneId {
2094 pane_id,
2095 resize,
2096 direction,
2097 } => ActionType::ResizeByPaneId(ResizeByPaneIdAction {
2098 pane_id: Some(pane_id.into()),
2099 resize_action: Some(ResizeAction {
2100 resize: resize_to_proto_i32(resize),
2101 direction: direction.map(|d| direction_to_proto_i32(d)),
2102 }),
2103 }),
2104 crate::input::actions::Action::MovePaneByPaneId { pane_id, direction } => {
2105 ActionType::MovePaneByPaneId(MovePaneByPaneIdAction {
2106 pane_id: Some(pane_id.into()),
2107 direction: direction.map(|d| direction_to_proto_i32(d)),
2108 })
2109 },
2110 crate::input::actions::Action::MovePaneBackwardsByPaneId { pane_id } => {
2111 ActionType::MovePaneBackwardsByPaneId(MovePaneBackwardsByPaneIdAction {
2112 pane_id: Some(pane_id.into()),
2113 })
2114 },
2115 crate::input::actions::Action::ClearScreenByPaneId { pane_id } => {
2116 ActionType::ClearScreenByPaneId(ClearScreenByPaneIdAction {
2117 pane_id: Some(pane_id.into()),
2118 })
2119 },
2120 crate::input::actions::Action::EditScrollbackByPaneId { pane_id, ansi } => {
2121 ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
2122 pane_id: Some(pane_id.into()),
2123 ansi,
2124 })
2125 },
2126 crate::input::actions::Action::ToggleFocusFullscreenByPaneId { pane_id } => {
2127 ActionType::ToggleFullscreenByPaneId(ToggleFullscreenByPaneIdAction {
2128 pane_id: Some(pane_id.into()),
2129 })
2130 },
2131 crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId { pane_id } => {
2132 ActionType::ToggleNoUiFullscreenByPaneId(ToggleNoUiFullscreenByPaneIdAction {
2133 pane_id: Some(pane_id.into()),
2134 })
2135 },
2136 crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
2137 ActionType::TogglePaneEmbedOrFloatingByPaneId(
2138 TogglePaneEmbedOrFloatingByPaneIdAction {
2139 pane_id: Some(pane_id.into()),
2140 },
2141 )
2142 },
2143 crate::input::actions::Action::CloseFocusByPaneId { pane_id } => {
2144 ActionType::CloseFocusByPaneId(CloseFocusByPaneIdAction {
2145 pane_id: Some(pane_id.into()),
2146 })
2147 },
2148 crate::input::actions::Action::RenamePaneByPaneId { pane_id, name } => {
2149 ActionType::RenamePaneByPaneId(RenamePaneByPaneIdAction {
2150 pane_id: pane_id.map(|id| id.into()),
2151 name,
2152 })
2153 },
2154 crate::input::actions::Action::UndoRenamePaneByPaneId { pane_id } => {
2155 ActionType::UndoRenamePaneByPaneId(UndoRenamePaneByPaneIdAction {
2156 pane_id: Some(pane_id.into()),
2157 })
2158 },
2159 crate::input::actions::Action::TogglePanePinnedByPaneId { pane_id } => {
2160 ActionType::TogglePanePinnedByPaneId(TogglePanePinnedByPaneIdAction {
2161 pane_id: Some(pane_id.into()),
2162 })
2163 },
2164 crate::input::actions::Action::FocusPaneByPaneId { pane_id } => {
2165 ActionType::FocusPaneByPaneId(FocusPaneByPaneIdAction {
2166 pane_id: Some(pane_id.into()),
2167 })
2168 },
2169 crate::input::actions::Action::UndoRenameTabByTabId { id } => {
2171 ActionType::UndoRenameTabByTabId(UndoRenameTabByTabIdAction { id })
2172 },
2173 crate::input::actions::Action::ToggleActiveSyncTabByTabId { id } => {
2174 ActionType::ToggleActiveSyncTabByTabId(ToggleActiveSyncTabByTabIdAction { id })
2175 },
2176 crate::input::actions::Action::ToggleFloatingPanesByTabId { id } => {
2177 ActionType::ToggleFloatingPanesByTabId(ToggleFloatingPanesByTabIdAction { id })
2178 },
2179 crate::input::actions::Action::PreviousSwapLayoutByTabId { id } => {
2180 ActionType::PreviousSwapLayoutByTabId(PreviousSwapLayoutByTabIdAction { id })
2181 },
2182 crate::input::actions::Action::NextSwapLayoutByTabId { id } => {
2183 ActionType::NextSwapLayoutByTabId(NextSwapLayoutByTabIdAction { id })
2184 },
2185 crate::input::actions::Action::MoveTabByTabId { id, direction } => {
2186 ActionType::MoveTabByTabId(MoveTabByTabIdAction {
2187 id,
2188 direction: direction_to_proto_i32(direction),
2189 })
2190 },
2191 };
2192
2193 Self {
2194 action_type: Some(action_type),
2195 }
2196 }
2197}
2198
2199impl TryFrom<crate::client_server_contract::client_server_contract::Action>
2200 for crate::input::actions::Action
2201{
2202 type Error = anyhow::Error;
2203 fn try_from(
2204 action: crate::client_server_contract::client_server_contract::Action,
2205 ) -> Result<Self> {
2206 use crate::client_server_contract::client_server_contract::action::ActionType;
2207
2208 let action_type = action
2209 .action_type
2210 .ok_or_else(|| anyhow!("Action missing action_type"))?;
2211
2212 match action_type {
2213 ActionType::Quit(_) => Ok(crate::input::actions::Action::Quit),
2214 ActionType::Write(write_action) => Ok(crate::input::actions::Action::Write {
2215 key_with_modifier: write_action
2216 .key_with_modifier
2217 .map(|k| k.try_into())
2218 .transpose()?,
2219 bytes: write_action.bytes.into_iter().map(|b| b as u8).collect(),
2220 is_kitty_keyboard_protocol: write_action.is_kitty_keyboard_protocol,
2221 }),
2222 ActionType::WriteChars(write_chars_action) => {
2223 Ok(crate::input::actions::Action::WriteChars {
2224 chars: write_chars_action.chars,
2225 })
2226 },
2227 ActionType::WriteToPaneId(write_to_pane_id_action) => {
2228 Ok(crate::input::actions::Action::WriteToPaneId {
2229 bytes: write_to_pane_id_action
2230 .bytes
2231 .into_iter()
2232 .map(|b| b as u8)
2233 .collect(),
2234 pane_id: write_to_pane_id_action
2235 .pane_id
2236 .ok_or_else(|| anyhow!("WriteToPaneId missing pane_id"))?
2237 .try_into()?,
2238 })
2239 },
2240 ActionType::WriteCharsToPaneId(write_chars_to_pane_id_action) => {
2241 Ok(crate::input::actions::Action::WriteCharsToPaneId {
2242 chars: write_chars_to_pane_id_action.chars,
2243 pane_id: write_chars_to_pane_id_action
2244 .pane_id
2245 .ok_or_else(|| anyhow!("WriteCharsToPaneId missing pane_id"))?
2246 .try_into()?,
2247 })
2248 },
2249 ActionType::Paste(paste_action) => Ok(crate::input::actions::Action::Paste {
2250 chars: paste_action.chars,
2251 pane_id: paste_action.pane_id.map(|p| p.try_into()).transpose()?,
2252 }),
2253 ActionType::SwitchToMode(switch_mode_action) => {
2254 Ok(crate::input::actions::Action::SwitchToMode {
2255 input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
2256 })
2257 },
2258 ActionType::SwitchModeForAllClients(switch_mode_action) => {
2259 Ok(crate::input::actions::Action::SwitchModeForAllClients {
2260 input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
2261 })
2262 },
2263 ActionType::Resize(resize_action) => Ok(crate::input::actions::Action::Resize {
2264 resize: proto_i32_to_resize(resize_action.resize)?,
2265 direction: resize_action
2266 .direction
2267 .map(|d| proto_i32_to_direction(d))
2268 .transpose()?,
2269 }),
2270 ActionType::FocusNextPane(_) => Ok(crate::input::actions::Action::FocusNextPane),
2271 ActionType::FocusPreviousPane(_) => {
2272 Ok(crate::input::actions::Action::FocusPreviousPane)
2273 },
2274 ActionType::FocusLastPane(_) => Ok(crate::input::actions::Action::FocusLastPane),
2275 ActionType::SwitchFocus(_) => Ok(crate::input::actions::Action::SwitchFocus),
2276 ActionType::MoveFocus(move_focus_action) => {
2277 Ok(crate::input::actions::Action::MoveFocus {
2278 direction: proto_i32_to_direction(move_focus_action.direction)?,
2279 })
2280 },
2281 ActionType::MoveFocusOrTab(move_focus_action) => {
2282 Ok(crate::input::actions::Action::MoveFocusOrTab {
2283 direction: proto_i32_to_direction(move_focus_action.direction)?,
2284 })
2285 },
2286 ActionType::MovePane(move_pane_action) => Ok(crate::input::actions::Action::MovePane {
2287 direction: move_pane_action
2288 .direction
2289 .map(|d| proto_i32_to_direction(d))
2290 .transpose()?,
2291 }),
2292 ActionType::MovePaneBackwards(_) => {
2293 Ok(crate::input::actions::Action::MovePaneBackwards)
2294 },
2295 ActionType::ClearScreen(_) => Ok(crate::input::actions::Action::ClearScreen),
2296 ActionType::DumpScreen(dump_screen_action) => {
2297 let file_path = if dump_screen_action.dump_to_stdout {
2298 None
2299 } else {
2300 Some(dump_screen_action.file_path)
2301 };
2302 Ok(crate::input::actions::Action::DumpScreen {
2303 file_path,
2304 include_scrollback: dump_screen_action.include_scrollback,
2305 pane_id: dump_screen_action.pane_id.and_then(|p| p.try_into().ok()),
2306 ansi: dump_screen_action.ansi,
2307 })
2308 },
2309 ActionType::DumpLayout(_) => Ok(crate::input::actions::Action::DumpLayout),
2310 ActionType::SaveSession(_) => Ok(crate::input::actions::Action::SaveSession),
2311 ActionType::EditScrollback(edit_scrollback_action) => {
2312 Ok(crate::input::actions::Action::EditScrollback {
2313 ansi: edit_scrollback_action.ansi,
2314 })
2315 },
2316 ActionType::ScrollUp(_) => Ok(crate::input::actions::Action::ScrollUp),
2317 ActionType::ScrollToPreviousPrompt(_) => {
2318 Ok(crate::input::actions::Action::ScrollToPreviousPrompt)
2319 },
2320 ActionType::ScrollToNextPrompt(_) => {
2321 Ok(crate::input::actions::Action::ScrollToNextPrompt)
2322 },
2323 ActionType::SelectCommandAtScrollPosition(_) => {
2324 Ok(crate::input::actions::Action::SelectCommandAtScrollPosition)
2325 },
2326 ActionType::CopyLastCommandOutput(_) => {
2327 Ok(crate::input::actions::Action::CopyLastCommandOutput)
2328 },
2329 ActionType::ScrollUpAt(scroll_action) => {
2330 Ok(crate::input::actions::Action::ScrollUpAt {
2331 position: scroll_action
2332 .position
2333 .ok_or_else(|| anyhow!("ScrollUpAt missing position"))?
2334 .try_into()?,
2335 })
2336 },
2337 ActionType::ScrollDown(_) => Ok(crate::input::actions::Action::ScrollDown),
2338 ActionType::ScrollDownAt(scroll_action) => {
2339 Ok(crate::input::actions::Action::ScrollDownAt {
2340 position: scroll_action
2341 .position
2342 .ok_or_else(|| anyhow!("ScrollDownAt missing position"))?
2343 .try_into()?,
2344 })
2345 },
2346 ActionType::ScrollToBottom(_) => Ok(crate::input::actions::Action::ScrollToBottom),
2347 ActionType::ScrollToTop(_) => Ok(crate::input::actions::Action::ScrollToTop),
2348 ActionType::PageScrollUp(_) => Ok(crate::input::actions::Action::PageScrollUp),
2349 ActionType::PageScrollDown(_) => Ok(crate::input::actions::Action::PageScrollDown),
2350 ActionType::HalfPageScrollUp(_) => Ok(crate::input::actions::Action::HalfPageScrollUp),
2351 ActionType::HalfPageScrollDown(_) => {
2352 Ok(crate::input::actions::Action::HalfPageScrollDown)
2353 },
2354 ActionType::ToggleFocusFullscreen(_) => {
2355 Ok(crate::input::actions::Action::ToggleFocusFullscreen)
2356 },
2357 ActionType::ToggleFocusNoUiFullscreen(_) => {
2358 Ok(crate::input::actions::Action::ToggleFocusNoUiFullscreen)
2359 },
2360 ActionType::TogglePaneFrames(_) => Ok(crate::input::actions::Action::TogglePaneFrames),
2361 ActionType::SetPaneFrameStyle(set_pane_frame_style_action) => {
2362 let style = crate::input::options::PaneFrameStyle::from_str(
2363 &set_pane_frame_style_action.style,
2364 )
2365 .map_err(|e| anyhow!("{}", e))?;
2366 Ok(crate::input::actions::Action::SetPaneFrameStyle(style))
2367 },
2368 ActionType::ToggleActiveSyncTab(_) => {
2369 Ok(crate::input::actions::Action::ToggleActiveSyncTab)
2370 },
2371 ActionType::NewPane(new_pane_action) => Ok(crate::input::actions::Action::NewPane {
2372 direction: new_pane_action
2373 .direction
2374 .map(|d| proto_i32_to_direction(d))
2375 .transpose()?,
2376 pane_name: new_pane_action.pane_name,
2377 start_suppressed: new_pane_action.start_suppressed,
2378 }),
2379 ActionType::EditFile(edit_file_action) => Ok(crate::input::actions::Action::EditFile {
2380 payload: edit_file_action
2381 .payload
2382 .ok_or_else(|| anyhow!("EditFile missing payload"))?
2383 .try_into()?,
2384 direction: edit_file_action
2385 .direction
2386 .map(|d| proto_i32_to_direction(d))
2387 .transpose()?,
2388 floating: edit_file_action.floating,
2389 in_place: edit_file_action.in_place,
2390 close_replaced_pane: edit_file_action.close_replaced_pane,
2391 start_suppressed: edit_file_action.start_suppressed,
2392 coordinates: edit_file_action
2393 .coordinates
2394 .map(|c| c.try_into())
2395 .transpose()?,
2396 near_current_pane: edit_file_action.near_current_pane,
2397 no_focus: edit_file_action.no_focus,
2398 tab_id: edit_file_action.tab_id.map(|t| t as usize),
2399 }),
2400 ActionType::NewFloatingPane(new_floating_action) => {
2401 Ok(crate::input::actions::Action::NewFloatingPane {
2402 command: new_floating_action
2403 .command
2404 .map(|c| c.try_into())
2405 .transpose()?,
2406 pane_name: new_floating_action.pane_name,
2407 coordinates: new_floating_action
2408 .coordinates
2409 .map(|c| c.try_into())
2410 .transpose()?,
2411 near_current_pane: new_floating_action.near_current_pane,
2412 no_focus: new_floating_action.no_focus,
2413 tab_id: new_floating_action.tab_id.map(|t| t as usize),
2414 })
2415 },
2416 ActionType::NewTiledPane(new_tiled_action) => {
2417 Ok(crate::input::actions::Action::NewTiledPane {
2418 direction: new_tiled_action
2419 .direction
2420 .map(|d| proto_i32_to_direction(d))
2421 .transpose()?,
2422 command: new_tiled_action.command.map(|c| c.try_into()).transpose()?,
2423 pane_name: new_tiled_action.pane_name,
2424 near_current_pane: new_tiled_action.near_current_pane,
2425 no_focus: new_tiled_action.no_focus,
2426 borderless: new_tiled_action.borderless,
2427 tab_id: new_tiled_action.tab_id.map(|t| t as usize),
2428 })
2429 },
2430 ActionType::NewInPlacePane(new_in_place_action) => {
2431 Ok(crate::input::actions::Action::NewInPlacePane {
2432 command: new_in_place_action
2433 .command
2434 .map(|c| c.try_into())
2435 .transpose()?,
2436 pane_name: new_in_place_action.pane_name,
2437 near_current_pane: new_in_place_action.near_current_pane,
2438 no_focus: new_in_place_action.no_focus,
2439 pane_id_to_replace: new_in_place_action
2440 .pane_id_to_replace
2441 .and_then(|p| p.try_into().ok()),
2442 close_replaced_pane: new_in_place_action.close_replaced_pane,
2443 tab_id: new_in_place_action.tab_id.map(|t| t as usize),
2444 })
2445 },
2446 ActionType::NewStackedPane(new_stacked_action) => {
2447 Ok(crate::input::actions::Action::NewStackedPane {
2448 command: new_stacked_action
2449 .command
2450 .map(|c| c.try_into())
2451 .transpose()?,
2452 pane_name: new_stacked_action.pane_name,
2453 near_current_pane: new_stacked_action.near_current_pane,
2454 no_focus: new_stacked_action.no_focus,
2455 tab_id: new_stacked_action.tab_id.map(|t| t as usize),
2456 })
2457 },
2458 ActionType::NewBlockingPane(new_blocking_action) => {
2459 Ok(crate::input::actions::Action::NewBlockingPane {
2460 placement: new_blocking_action
2461 .placement
2462 .ok_or_else(|| anyhow!("NewBlockingPane missing placement"))?
2463 .try_into()?,
2464 pane_name: new_blocking_action.pane_name,
2465 command: new_blocking_action
2466 .command
2467 .map(|c| c.try_into())
2468 .transpose()?,
2469 unblock_condition: new_blocking_action
2470 .unblock_condition
2471 .map(|c| proto_i32_to_unblock_condition(c))
2472 .transpose()?,
2473 near_current_pane: new_blocking_action.near_current_pane,
2474 no_focus: new_blocking_action.no_focus,
2475 tab_id: new_blocking_action.tab_id.map(|t| t as usize),
2476 })
2477 },
2478 ActionType::TogglePaneEmbedOrFloating(_) => {
2479 Ok(crate::input::actions::Action::TogglePaneEmbedOrFloating)
2480 },
2481 ActionType::ToggleFloatingPanes(_) => {
2482 Ok(crate::input::actions::Action::ToggleFloatingPanes)
2483 },
2484 ActionType::ShowFloatingPanes(a) => {
2485 Ok(crate::input::actions::Action::ShowFloatingPanes {
2486 tab_id: a.tab_id.map(|id| id as usize),
2487 })
2488 },
2489 ActionType::HideFloatingPanes(a) => {
2490 Ok(crate::input::actions::Action::HideFloatingPanes {
2491 tab_id: a.tab_id.map(|id| id as usize),
2492 })
2493 },
2494 ActionType::AreFloatingPanesVisible(a) => {
2495 Ok(crate::input::actions::Action::AreFloatingPanesVisible {
2496 tab_id: a.tab_id.map(|id| id as usize),
2497 })
2498 },
2499 ActionType::CloseFocus(_) => Ok(crate::input::actions::Action::CloseFocus),
2500 ActionType::PaneNameInput(pane_name_action) => {
2501 Ok(crate::input::actions::Action::PaneNameInput {
2502 input: pane_name_action
2503 .input
2504 .into_iter()
2505 .map(|b| b as u8)
2506 .collect(),
2507 })
2508 },
2509 ActionType::UndoRenamePane(_) => Ok(crate::input::actions::Action::UndoRenamePane),
2510 ActionType::NewTab(new_tab_action) => Ok(crate::input::actions::Action::NewTab {
2511 tiled_layout: new_tab_action
2512 .tiled_layout
2513 .map(|l| l.try_into())
2514 .transpose()?,
2515 floating_layouts: new_tab_action
2516 .floating_layouts
2517 .into_iter()
2518 .map(|l| l.try_into())
2519 .collect::<Result<Vec<_>>>()?,
2520 swap_tiled_layouts: if new_tab_action.swap_tiled_layouts.is_empty() {
2521 None
2522 } else {
2523 Some(
2524 new_tab_action
2525 .swap_tiled_layouts
2526 .into_iter()
2527 .map(|l| l.try_into())
2528 .collect::<Result<Vec<_>>>()?,
2529 )
2530 },
2531 swap_floating_layouts: if new_tab_action.swap_floating_layouts.is_empty() {
2532 None
2533 } else {
2534 Some(
2535 new_tab_action
2536 .swap_floating_layouts
2537 .into_iter()
2538 .map(|l| l.try_into())
2539 .collect::<Result<Vec<_>>>()?,
2540 )
2541 },
2542 tab_name: new_tab_action.tab_name,
2543 should_change_focus_to_new_tab: new_tab_action.should_change_focus_to_new_tab,
2544 cwd: new_tab_action.cwd.map(PathBuf::from),
2545 initial_panes: if new_tab_action.initial_panes.is_empty() {
2546 None
2547 } else {
2548 Some(
2549 new_tab_action
2550 .initial_panes
2551 .into_iter()
2552 .map(|p| p.try_into())
2553 .collect::<Result<Vec<_>>>()?,
2554 )
2555 },
2556
2557 first_pane_unblock_condition: new_tab_action
2558 .first_pane_unblock_condition
2559 .map(|c| proto_i32_to_unblock_condition(c))
2560 .transpose()?,
2561 }),
2562 ActionType::NoOp(_) => Ok(crate::input::actions::Action::NoOp),
2563 ActionType::GoToNextTab(_) => Ok(crate::input::actions::Action::GoToNextTab),
2564 ActionType::GoToPreviousTab(_) => Ok(crate::input::actions::Action::GoToPreviousTab),
2565 ActionType::CloseTab(_) => Ok(crate::input::actions::Action::CloseTab),
2566 ActionType::GoToTab(go_to_tab_action) => Ok(crate::input::actions::Action::GoToTab {
2567 index: go_to_tab_action.index,
2568 }),
2569 ActionType::GoToTabName(go_to_tab_name_action) => {
2570 Ok(crate::input::actions::Action::GoToTabName {
2571 name: go_to_tab_name_action.name,
2572 create: go_to_tab_name_action.create,
2573 })
2574 },
2575 ActionType::ToggleTab(_) => Ok(crate::input::actions::Action::ToggleTab),
2576 ActionType::TabNameInput(tab_name_action) => {
2577 Ok(crate::input::actions::Action::TabNameInput {
2578 input: tab_name_action.input.into_iter().map(|b| b as u8).collect(),
2579 })
2580 },
2581 ActionType::UndoRenameTab(_) => Ok(crate::input::actions::Action::UndoRenameTab),
2582 ActionType::MoveTab(move_tab_action) => Ok(crate::input::actions::Action::MoveTab {
2583 direction: proto_i32_to_direction(move_tab_action.direction)?,
2584 }),
2585 ActionType::Run(run_action) => Ok(crate::input::actions::Action::Run {
2586 command: run_action
2587 .command
2588 .ok_or_else(|| anyhow!("Run missing command"))?
2589 .try_into()?,
2590 near_current_pane: run_action.near_current_pane,
2591 no_focus: run_action.no_focus,
2592 }),
2593 ActionType::Detach(_) => Ok(crate::input::actions::Action::Detach),
2594 ActionType::SetDarkTheme(_) => Ok(crate::input::actions::Action::SetDarkTheme),
2595 ActionType::SetLightTheme(_) => Ok(crate::input::actions::Action::SetLightTheme),
2596 ActionType::ToggleTheme(_) => Ok(crate::input::actions::Action::ToggleTheme),
2597 ActionType::SwitchSession(switch_session_action) => {
2598 Ok(crate::input::actions::Action::SwitchSession {
2599 name: switch_session_action.name.clone(),
2600 tab_position: switch_session_action.tab_position.map(|p| p as usize),
2601 pane_id: switch_session_action
2602 .pane_id
2603 .as_ref()
2604 .map(|p| (p.pane_id, p.is_plugin)),
2605 layout: switch_session_action
2606 .layout
2607 .map(|l| l.try_into())
2608 .transpose()?,
2609 cwd: switch_session_action.cwd.map(PathBuf::from),
2610 })
2611 },
2612 ActionType::LaunchOrFocusPlugin(launch_plugin_action) => {
2613 Ok(crate::input::actions::Action::LaunchOrFocusPlugin {
2614 plugin: launch_plugin_action
2615 .plugin
2616 .ok_or_else(|| anyhow!("LaunchOrFocusPlugin missing plugin"))?
2617 .try_into()?,
2618 should_float: launch_plugin_action.should_float,
2619 move_to_focused_tab: launch_plugin_action.move_to_focused_tab,
2620 should_open_in_place: launch_plugin_action.should_open_in_place,
2621 close_replaced_pane: launch_plugin_action.close_replaced_pane,
2622 skip_cache: launch_plugin_action.skip_cache,
2623 tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
2624 })
2625 },
2626 ActionType::LaunchPlugin(launch_plugin_action) => {
2627 Ok(crate::input::actions::Action::LaunchPlugin {
2628 plugin: launch_plugin_action
2629 .plugin
2630 .ok_or_else(|| anyhow!("LaunchPlugin missing plugin"))?
2631 .try_into()?,
2632 should_float: launch_plugin_action.should_float,
2633 should_open_in_place: launch_plugin_action.should_open_in_place,
2634 close_replaced_pane: launch_plugin_action.close_replaced_pane,
2635 skip_cache: launch_plugin_action.skip_cache,
2636 cwd: launch_plugin_action.cwd.map(PathBuf::from),
2637 no_focus: launch_plugin_action.no_focus,
2638 tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
2639 })
2640 },
2641 ActionType::MouseEvent(mouse_event_action) => {
2642 Ok(crate::input::actions::Action::MouseEvent {
2643 event: mouse_event_action
2644 .event
2645 .ok_or_else(|| anyhow!("MouseEvent missing event"))?
2646 .try_into()?,
2647 })
2648 },
2649 ActionType::Copy(_) => Ok(crate::input::actions::Action::Copy),
2650 ActionType::Confirm(_) => Ok(crate::input::actions::Action::Confirm),
2651 ActionType::Deny(_) => Ok(crate::input::actions::Action::Deny),
2652 ActionType::SkipConfirm(skip_confirm_action) => {
2653 Ok(crate::input::actions::Action::SkipConfirm {
2654 action: Box::new(
2655 skip_confirm_action
2656 .action
2657 .ok_or_else(|| anyhow!("SkipConfirm missing action"))?
2658 .as_ref()
2659 .clone()
2660 .try_into()?,
2661 ),
2662 })
2663 },
2664 ActionType::SearchInput(search_input_action) => {
2665 Ok(crate::input::actions::Action::SearchInput {
2666 input: search_input_action
2667 .input
2668 .into_iter()
2669 .map(|b| b as u8)
2670 .collect(),
2671 })
2672 },
2673 ActionType::Search(search_action) => Ok(crate::input::actions::Action::Search {
2674 direction: proto_i32_to_search_direction(search_action.direction)?,
2675 }),
2676 ActionType::SearchToggleOption(search_toggle_action) => {
2677 Ok(crate::input::actions::Action::SearchToggleOption {
2678 option: proto_i32_to_search_option(search_toggle_action.option)?,
2679 })
2680 },
2681 ActionType::ToggleMouseMode(_) => Ok(crate::input::actions::Action::ToggleMouseMode),
2682 ActionType::PreviousSwapLayout(_) => {
2683 Ok(crate::input::actions::Action::PreviousSwapLayout)
2684 },
2685 ActionType::NextSwapLayout(_) => Ok(crate::input::actions::Action::NextSwapLayout),
2686 ActionType::OverrideLayout(override_layout_action) => {
2687 Ok(crate::input::actions::Action::OverrideLayout {
2688 tabs: override_layout_action
2689 .tabs
2690 .into_iter()
2691 .map(|t| t.try_into())
2692 .collect::<Result<Vec<_>>>()?,
2693 retain_existing_terminal_panes: override_layout_action
2694 .retain_existing_terminal_panes,
2695 retain_existing_plugin_panes: override_layout_action
2696 .retain_existing_plugin_panes,
2697 apply_only_to_active_tab: override_layout_action.apply_only_to_active_tab,
2698 })
2699 },
2700 ActionType::QueryTabNames(_) => Ok(crate::input::actions::Action::QueryTabNames),
2701 ActionType::NewTiledPluginPane(new_tiled_plugin_action) => {
2702 Ok(crate::input::actions::Action::NewTiledPluginPane {
2703 plugin: new_tiled_plugin_action
2704 .plugin
2705 .ok_or_else(|| anyhow!("NewTiledPluginPane missing plugin"))?
2706 .try_into()?,
2707 pane_name: new_tiled_plugin_action.pane_name,
2708 skip_cache: new_tiled_plugin_action.skip_cache,
2709 cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),
2710 no_focus: new_tiled_plugin_action.no_focus,
2711 tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),
2712 })
2713 },
2714 ActionType::NewFloatingPluginPane(new_floating_plugin_action) => {
2715 Ok(crate::input::actions::Action::NewFloatingPluginPane {
2716 plugin: new_floating_plugin_action
2717 .plugin
2718 .ok_or_else(|| anyhow!("NewFloatingPluginPane missing plugin"))?
2719 .try_into()?,
2720 pane_name: new_floating_plugin_action.pane_name,
2721 skip_cache: new_floating_plugin_action.skip_cache,
2722 cwd: new_floating_plugin_action.cwd.map(PathBuf::from),
2723 coordinates: new_floating_plugin_action
2724 .coordinates
2725 .map(|c| c.try_into())
2726 .transpose()?,
2727 no_focus: new_floating_plugin_action.no_focus,
2728 tab_id: new_floating_plugin_action.tab_id.map(|t| t as usize),
2729 })
2730 },
2731 ActionType::NewInPlacePluginPane(new_in_place_plugin_action) => {
2732 Ok(crate::input::actions::Action::NewInPlacePluginPane {
2733 plugin: new_in_place_plugin_action
2734 .plugin
2735 .ok_or_else(|| anyhow!("NewInPlacePluginPane missing plugin"))?
2736 .try_into()?,
2737 pane_name: new_in_place_plugin_action.pane_name,
2738 skip_cache: new_in_place_plugin_action.skip_cache,
2739 close_replaced_pane: new_in_place_plugin_action.close_replaced_pane,
2740 no_focus: new_in_place_plugin_action.no_focus,
2741 tab_id: new_in_place_plugin_action.tab_id.map(|t| t as usize),
2742 })
2743 },
2744 ActionType::StartOrReloadPlugin(start_plugin_action) => {
2745 Ok(crate::input::actions::Action::StartOrReloadPlugin {
2746 plugin: start_plugin_action
2747 .plugin
2748 .ok_or_else(|| anyhow!("StartOrReloadPlugin missing plugin"))?
2749 .try_into()?,
2750 })
2751 },
2752 ActionType::CloseTerminalPane(close_pane_action) => {
2753 Ok(crate::input::actions::Action::CloseTerminalPane {
2754 pane_id: close_pane_action.pane_id,
2755 })
2756 },
2757 ActionType::ClosePluginPane(close_pane_action) => {
2758 Ok(crate::input::actions::Action::ClosePluginPane {
2759 pane_id: close_pane_action.pane_id,
2760 })
2761 },
2762 ActionType::FocusTerminalPaneWithId(focus_pane_action) => {
2763 Ok(crate::input::actions::Action::FocusTerminalPaneWithId {
2764 pane_id: focus_pane_action.pane_id,
2765 should_float_if_hidden: focus_pane_action.should_float_if_hidden,
2766 should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
2767 })
2768 },
2769 ActionType::FocusPluginPaneWithId(focus_pane_action) => {
2770 Ok(crate::input::actions::Action::FocusPluginPaneWithId {
2771 pane_id: focus_pane_action.pane_id,
2772 should_float_if_hidden: focus_pane_action.should_float_if_hidden,
2773 should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
2774 })
2775 },
2776 ActionType::RenameTerminalPane(rename_pane_action) => {
2777 Ok(crate::input::actions::Action::RenameTerminalPane {
2778 pane_id: rename_pane_action.pane_id,
2779 name: rename_pane_action
2780 .name
2781 .into_iter()
2782 .map(|b| b as u8)
2783 .collect(),
2784 })
2785 },
2786 ActionType::RenamePluginPane(rename_pane_action) => {
2787 Ok(crate::input::actions::Action::RenamePluginPane {
2788 pane_id: rename_pane_action.pane_id,
2789 name: rename_pane_action
2790 .name
2791 .into_iter()
2792 .map(|b| b as u8)
2793 .collect(),
2794 })
2795 },
2796 ActionType::RenameTab(rename_tab_action) => {
2797 Ok(crate::input::actions::Action::RenameTab {
2798 tab_index: rename_tab_action.tab_index,
2799 name: rename_tab_action
2800 .name
2801 .into_iter()
2802 .map(|b| b as u8)
2803 .collect(),
2804 })
2805 },
2806 ActionType::GoToTabById(go_to_tab_by_id_action) => {
2807 Ok(crate::input::actions::Action::GoToTabById {
2808 id: go_to_tab_by_id_action.id,
2809 })
2810 },
2811 ActionType::CloseTabById(close_tab_by_id_action) => {
2812 Ok(crate::input::actions::Action::CloseTabById {
2813 id: close_tab_by_id_action.id,
2814 })
2815 },
2816 ActionType::RenameTabById(rename_tab_by_id_action) => {
2817 Ok(crate::input::actions::Action::RenameTabById {
2818 id: rename_tab_by_id_action.id,
2819 name: rename_tab_by_id_action.name,
2820 })
2821 },
2822 ActionType::BreakPane(_) => Ok(crate::input::actions::Action::BreakPane),
2823 ActionType::BreakPaneRight(_) => Ok(crate::input::actions::Action::BreakPaneRight),
2824 ActionType::BreakPaneLeft(_) => Ok(crate::input::actions::Action::BreakPaneLeft),
2825 ActionType::FocusHostSession(_) => Ok(crate::input::actions::Action::FocusHostSession),
2826 ActionType::FocusGuestSession(_) => {
2827 Ok(crate::input::actions::Action::FocusGuestSession)
2828 },
2829 ActionType::ToggleHostFullscreen(_) => {
2830 Ok(crate::input::actions::Action::ToggleHostFullscreen)
2831 },
2832 ActionType::RenameSession(rename_session_action) => {
2833 Ok(crate::input::actions::Action::RenameSession {
2834 name: rename_session_action.name,
2835 })
2836 },
2837 ActionType::CliPipe(cli_pipe_action) => Ok(crate::input::actions::Action::CliPipe {
2838 pipe_id: cli_pipe_action.pipe_id,
2839 name: cli_pipe_action.name,
2840 payload: cli_pipe_action.payload,
2841 args: if cli_pipe_action.args.is_empty() {
2842 None
2843 } else {
2844 Some(cli_pipe_action.args.into_iter().collect())
2845 },
2846 plugin: cli_pipe_action.plugin,
2847 configuration: if cli_pipe_action.configuration.is_empty() {
2848 None
2849 } else {
2850 Some(cli_pipe_action.configuration.into_iter().collect())
2851 },
2852 launch_new: cli_pipe_action.launch_new,
2853 skip_cache: cli_pipe_action.skip_cache,
2854 floating: cli_pipe_action.floating,
2855 in_place: cli_pipe_action.in_place,
2856 cwd: cli_pipe_action.cwd.map(PathBuf::from),
2857 pane_title: cli_pipe_action.pane_title,
2858 }),
2859 ActionType::KeybindPipe(keybind_pipe_action) => {
2860 Ok(crate::input::actions::Action::KeybindPipe {
2861 name: keybind_pipe_action.name,
2862 payload: keybind_pipe_action.payload,
2863 args: if keybind_pipe_action.args.is_empty() {
2864 None
2865 } else {
2866 Some(keybind_pipe_action.args.into_iter().collect())
2867 },
2868 plugin: keybind_pipe_action.plugin,
2869 plugin_id: keybind_pipe_action.plugin_id,
2870 configuration: if keybind_pipe_action.configuration.is_empty() {
2871 None
2872 } else {
2873 Some(keybind_pipe_action.configuration.into_iter().collect())
2874 },
2875 launch_new: keybind_pipe_action.launch_new,
2876 skip_cache: keybind_pipe_action.skip_cache,
2877 floating: keybind_pipe_action.floating,
2878 in_place: keybind_pipe_action.in_place,
2879 cwd: keybind_pipe_action.cwd.map(PathBuf::from),
2880 pane_title: keybind_pipe_action.pane_title,
2881 })
2882 },
2883 ActionType::ListClients(_) => Ok(crate::input::actions::Action::ListClients),
2884 ActionType::ListPanes(list_panes_action) => {
2885 Ok(crate::input::actions::Action::ListPanes {
2886 show_tab: list_panes_action.show_tab,
2887 show_command: list_panes_action.show_command,
2888 show_state: list_panes_action.show_state,
2889 show_geometry: list_panes_action.show_geometry,
2890 show_all: list_panes_action.show_all,
2891 output_json: list_panes_action.output_json,
2892 })
2893 },
2894 ActionType::ListTabs(list_tabs_action) => Ok(crate::input::actions::Action::ListTabs {
2895 show_state: list_tabs_action.show_state,
2896 show_dimensions: list_tabs_action.show_dimensions,
2897 show_panes: list_tabs_action.show_panes,
2898 show_layout: list_tabs_action.show_layout,
2899 show_all: list_tabs_action.show_all,
2900 output_json: list_tabs_action.output_json,
2901 }),
2902 ActionType::CurrentTabInfo(current_tab_info_action) => {
2903 Ok(crate::input::actions::Action::CurrentTabInfo {
2904 output_json: current_tab_info_action.output_json,
2905 })
2906 },
2907 ActionType::TogglePanePinned(_) => Ok(crate::input::actions::Action::TogglePanePinned),
2908 ActionType::StackPanes(stack_panes_action) => {
2909 Ok(crate::input::actions::Action::StackPanes {
2910 pane_ids: stack_panes_action
2911 .pane_ids
2912 .into_iter()
2913 .map(|id| id.try_into())
2914 .collect::<Result<Vec<_>>>()?,
2915 })
2916 },
2917 ActionType::ChangeFloatingPaneCoordinates(change_coords_action) => Ok(
2918 crate::input::actions::Action::ChangeFloatingPaneCoordinates {
2919 pane_id: change_coords_action
2920 .pane_id
2921 .ok_or_else(|| anyhow!("ChangeFloatingPaneCoordinates missing pane_id"))?
2922 .try_into()?,
2923 coordinates: change_coords_action
2924 .coordinates
2925 .ok_or_else(|| {
2926 anyhow!("ChangeFloatingPaneCoordinates missing coordinates")
2927 })?
2928 .try_into()?,
2929 },
2930 ),
2931 ActionType::TogglePaneBorderless(toggle_borderless_action) => {
2932 Ok(crate::input::actions::Action::TogglePaneBorderless {
2933 pane_id: toggle_borderless_action
2934 .pane_id
2935 .ok_or_else(|| anyhow!("TogglePaneBorderless missing pane_id"))?
2936 .try_into()?,
2937 })
2938 },
2939 ActionType::SetPaneBorderless(set_borderless_action) => {
2940 Ok(crate::input::actions::Action::SetPaneBorderless {
2941 pane_id: set_borderless_action
2942 .pane_id
2943 .ok_or_else(|| anyhow!("SetPaneBorderless missing pane_id"))?
2944 .try_into()?,
2945 borderless: set_borderless_action.borderless,
2946 })
2947 },
2948 ActionType::TogglePaneInGroup(_) => {
2949 Ok(crate::input::actions::Action::TogglePaneInGroup)
2950 },
2951 ActionType::ToggleGroupMarking(_) => {
2952 Ok(crate::input::actions::Action::ToggleGroupMarking)
2953 },
2954 ActionType::SetPaneColor(set_pane_color_action) => {
2955 Ok(crate::input::actions::Action::SetPaneColor {
2956 pane_id: set_pane_color_action
2957 .pane_id
2958 .ok_or_else(|| anyhow!("SetPaneColor missing pane_id"))?
2959 .try_into()?,
2960 fg: set_pane_color_action.fg,
2961 bg: set_pane_color_action.bg,
2962 })
2963 },
2964 ActionType::ScrollUpByPaneId(a) => {
2966 Ok(crate::input::actions::Action::ScrollUpByPaneId {
2967 pane_id: a
2968 .pane_id
2969 .ok_or_else(|| anyhow!("ScrollUpByPaneId missing pane_id"))?
2970 .try_into()?,
2971 })
2972 },
2973 ActionType::ScrollDownByPaneId(a) => {
2974 Ok(crate::input::actions::Action::ScrollDownByPaneId {
2975 pane_id: a
2976 .pane_id
2977 .ok_or_else(|| anyhow!("ScrollDownByPaneId missing pane_id"))?
2978 .try_into()?,
2979 })
2980 },
2981 ActionType::ScrollToTopByPaneId(a) => {
2982 Ok(crate::input::actions::Action::ScrollToTopByPaneId {
2983 pane_id: a
2984 .pane_id
2985 .ok_or_else(|| anyhow!("ScrollToTopByPaneId missing pane_id"))?
2986 .try_into()?,
2987 })
2988 },
2989 ActionType::ScrollToBottomByPaneId(a) => {
2990 Ok(crate::input::actions::Action::ScrollToBottomByPaneId {
2991 pane_id: a
2992 .pane_id
2993 .ok_or_else(|| anyhow!("ScrollToBottomByPaneId missing pane_id"))?
2994 .try_into()?,
2995 })
2996 },
2997 ActionType::PageScrollUpByPaneId(a) => {
2998 Ok(crate::input::actions::Action::PageScrollUpByPaneId {
2999 pane_id: a
3000 .pane_id
3001 .ok_or_else(|| anyhow!("PageScrollUpByPaneId missing pane_id"))?
3002 .try_into()?,
3003 })
3004 },
3005 ActionType::PageScrollDownByPaneId(a) => {
3006 Ok(crate::input::actions::Action::PageScrollDownByPaneId {
3007 pane_id: a
3008 .pane_id
3009 .ok_or_else(|| anyhow!("PageScrollDownByPaneId missing pane_id"))?
3010 .try_into()?,
3011 })
3012 },
3013 ActionType::HalfPageScrollUpByPaneId(a) => {
3014 Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {
3015 pane_id: a
3016 .pane_id
3017 .ok_or_else(|| anyhow!("HalfPageScrollUpByPaneId missing pane_id"))?
3018 .try_into()?,
3019 })
3020 },
3021 ActionType::HalfPageScrollDownByPaneId(a) => {
3022 Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {
3023 pane_id: a
3024 .pane_id
3025 .ok_or_else(|| anyhow!("HalfPageScrollDownByPaneId missing pane_id"))?
3026 .try_into()?,
3027 })
3028 },
3029 ActionType::ResizeByPaneId(a) => {
3030 let resize_action = a
3031 .resize_action
3032 .ok_or_else(|| anyhow!("ResizeByPaneId missing resize_action"))?;
3033 let resize = proto_i32_to_resize(resize_action.resize)?;
3034 let direction = resize_action
3035 .direction
3036 .map(|d| proto_i32_to_direction(d))
3037 .transpose()?;
3038 Ok(crate::input::actions::Action::ResizeByPaneId {
3039 pane_id: a
3040 .pane_id
3041 .ok_or_else(|| anyhow!("ResizeByPaneId missing pane_id"))?
3042 .try_into()?,
3043 resize,
3044 direction,
3045 })
3046 },
3047 ActionType::MovePaneByPaneId(a) => {
3048 let direction = a.direction.map(|d| proto_i32_to_direction(d)).transpose()?;
3049 Ok(crate::input::actions::Action::MovePaneByPaneId {
3050 pane_id: a
3051 .pane_id
3052 .ok_or_else(|| anyhow!("MovePaneByPaneId missing pane_id"))?
3053 .try_into()?,
3054 direction,
3055 })
3056 },
3057 ActionType::MovePaneBackwardsByPaneId(a) => {
3058 Ok(crate::input::actions::Action::MovePaneBackwardsByPaneId {
3059 pane_id: a
3060 .pane_id
3061 .ok_or_else(|| anyhow!("MovePaneBackwardsByPaneId missing pane_id"))?
3062 .try_into()?,
3063 })
3064 },
3065 ActionType::ClearScreenByPaneId(a) => {
3066 Ok(crate::input::actions::Action::ClearScreenByPaneId {
3067 pane_id: a
3068 .pane_id
3069 .ok_or_else(|| anyhow!("ClearScreenByPaneId missing pane_id"))?
3070 .try_into()?,
3071 })
3072 },
3073 ActionType::EditScrollbackByPaneId(a) => {
3074 Ok(crate::input::actions::Action::EditScrollbackByPaneId {
3075 pane_id: a
3076 .pane_id
3077 .ok_or_else(|| anyhow!("EditScrollbackByPaneId missing pane_id"))?
3078 .try_into()?,
3079 ansi: a.ansi,
3080 })
3081 },
3082 ActionType::ToggleFullscreenByPaneId(a) => Ok(
3083 crate::input::actions::Action::ToggleFocusFullscreenByPaneId {
3084 pane_id: a
3085 .pane_id
3086 .ok_or_else(|| anyhow!("ToggleFullscreenByPaneId missing pane_id"))?
3087 .try_into()?,
3088 },
3089 ),
3090 ActionType::ToggleNoUiFullscreenByPaneId(a) => Ok(
3091 crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId {
3092 pane_id: a
3093 .pane_id
3094 .ok_or_else(|| anyhow!("ToggleNoUiFullscreenByPaneId missing pane_id"))?
3095 .try_into()?,
3096 },
3097 ),
3098 ActionType::TogglePaneEmbedOrFloatingByPaneId(a) => Ok(
3099 crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId {
3100 pane_id: a
3101 .pane_id
3102 .ok_or_else(|| {
3103 anyhow!("TogglePaneEmbedOrFloatingByPaneId missing pane_id")
3104 })?
3105 .try_into()?,
3106 },
3107 ),
3108 ActionType::CloseFocusByPaneId(a) => {
3109 Ok(crate::input::actions::Action::CloseFocusByPaneId {
3110 pane_id: a
3111 .pane_id
3112 .ok_or_else(|| anyhow!("CloseFocusByPaneId missing pane_id"))?
3113 .try_into()?,
3114 })
3115 },
3116 ActionType::RenamePaneByPaneId(a) => {
3117 Ok(crate::input::actions::Action::RenamePaneByPaneId {
3118 pane_id: a.pane_id.map(|p| p.try_into()).transpose()?,
3119 name: a.name,
3120 })
3121 },
3122 ActionType::UndoRenamePaneByPaneId(a) => {
3123 Ok(crate::input::actions::Action::UndoRenamePaneByPaneId {
3124 pane_id: a
3125 .pane_id
3126 .ok_or_else(|| anyhow!("UndoRenamePaneByPaneId missing pane_id"))?
3127 .try_into()?,
3128 })
3129 },
3130 ActionType::TogglePanePinnedByPaneId(a) => {
3131 Ok(crate::input::actions::Action::TogglePanePinnedByPaneId {
3132 pane_id: a
3133 .pane_id
3134 .ok_or_else(|| anyhow!("TogglePanePinnedByPaneId missing pane_id"))?
3135 .try_into()?,
3136 })
3137 },
3138 ActionType::FocusPaneByPaneId(a) => {
3139 Ok(crate::input::actions::Action::FocusPaneByPaneId {
3140 pane_id: a
3141 .pane_id
3142 .ok_or_else(|| anyhow!("FocusPaneByPaneId missing pane_id"))?
3143 .try_into()?,
3144 })
3145 },
3146 ActionType::UndoRenameTabByTabId(a) => {
3148 Ok(crate::input::actions::Action::UndoRenameTabByTabId { id: a.id })
3149 },
3150 ActionType::ToggleActiveSyncTabByTabId(a) => {
3151 Ok(crate::input::actions::Action::ToggleActiveSyncTabByTabId { id: a.id })
3152 },
3153 ActionType::ToggleFloatingPanesByTabId(a) => {
3154 Ok(crate::input::actions::Action::ToggleFloatingPanesByTabId { id: a.id })
3155 },
3156 ActionType::PreviousSwapLayoutByTabId(a) => {
3157 Ok(crate::input::actions::Action::PreviousSwapLayoutByTabId { id: a.id })
3158 },
3159 ActionType::NextSwapLayoutByTabId(a) => {
3160 Ok(crate::input::actions::Action::NextSwapLayoutByTabId { id: a.id })
3161 },
3162 ActionType::MoveTabByTabId(a) => {
3163 let direction = proto_i32_to_direction(a.direction)?;
3164 Ok(crate::input::actions::Action::MoveTabByTabId {
3165 id: a.id,
3166 direction,
3167 })
3168 },
3169 }
3170 }
3171}
3172
3173impl From<crate::data::KeyWithModifier>
3174 for crate::client_server_contract::client_server_contract::KeyWithModifier
3175{
3176 fn from(key: crate::data::KeyWithModifier) -> Self {
3177 use crate::ipc::enum_conversions::{bare_key_to_proto_i32, key_modifier_to_proto_i32};
3178
3179 let (bare_key_enum, char_data) = match &key.bare_key {
3181 crate::data::BareKey::Char(c) => (
3182 crate::client_server_contract::client_server_contract::BareKey::Char as i32,
3183 Some(c.to_string()),
3184 ),
3185 other => (bare_key_to_proto_i32(*other), None),
3186 };
3187
3188 Self {
3189 bare_key: bare_key_enum,
3190 key_modifiers: key
3191 .key_modifiers
3192 .into_iter()
3193 .map(|modifier| key_modifier_to_proto_i32(modifier))
3194 .collect(),
3195 character: char_data,
3196 }
3197 }
3198}
3199
3200impl TryFrom<crate::client_server_contract::client_server_contract::KeyWithModifier>
3201 for crate::data::KeyWithModifier
3202{
3203 type Error = anyhow::Error;
3204 fn try_from(
3205 key: crate::client_server_contract::client_server_contract::KeyWithModifier,
3206 ) -> Result<Self> {
3207 use crate::ipc::enum_conversions::{bare_key_from_proto_i32, key_modifier_from_proto_i32};
3208 use std::collections::BTreeSet;
3209
3210 let bare_key = if key.bare_key
3212 == crate::client_server_contract::client_server_contract::BareKey::Char as i32
3213 {
3214 let character_str = key
3215 .character
3216 .ok_or_else(|| anyhow!("Character key missing character data"))?;
3217 let character = character_str
3218 .chars()
3219 .next()
3220 .ok_or_else(|| anyhow!("Empty character string"))?;
3221 crate::data::BareKey::Char(character)
3222 } else {
3223 bare_key_from_proto_i32(key.bare_key)?
3224 };
3225
3226 let key_modifiers: Result<BTreeSet<_>> = key
3227 .key_modifiers
3228 .into_iter()
3229 .map(|modifier| key_modifier_from_proto_i32(modifier))
3230 .collect();
3231
3232 Ok(Self {
3233 bare_key,
3234 key_modifiers: key_modifiers?,
3235 })
3236 }
3237}
3238
3239impl From<crate::data::ConnectToSession>
3240 for crate::client_server_contract::client_server_contract::ConnectToSession
3241{
3242 fn from(connect: crate::data::ConnectToSession) -> Self {
3243 Self {
3244 name: connect.name,
3245 tab_position: connect.tab_position.map(|p| p as u32),
3246 pane_id: connect.pane_id.map(|(id, is_plugin)| {
3247 crate::client_server_contract::client_server_contract::PaneIdWithPlugin {
3248 pane_id: id,
3249 is_plugin,
3250 }
3251 }),
3252 layout: connect.layout.map(|l| l.into()),
3253 cwd: connect.cwd.map(|p| p.to_string_lossy().to_string()),
3254 }
3255 }
3256}
3257
3258impl TryFrom<crate::client_server_contract::client_server_contract::ConnectToSession>
3259 for crate::data::ConnectToSession
3260{
3261 type Error = anyhow::Error;
3262 fn try_from(
3263 connect: crate::client_server_contract::client_server_contract::ConnectToSession,
3264 ) -> Result<Self> {
3265 Ok(Self {
3266 name: connect.name,
3267 tab_position: connect.tab_position.map(|p| p as usize),
3268 pane_id: connect.pane_id.map(|p| (p.pane_id, p.is_plugin)),
3269 layout: connect.layout.map(|l| l.try_into()).transpose()?,
3270 cwd: connect.cwd.map(PathBuf::from),
3271 })
3272 }
3273}
3274
3275impl From<crate::data::LayoutInfo>
3276 for crate::client_server_contract::client_server_contract::LayoutInfo
3277{
3278 fn from(layout: crate::data::LayoutInfo) -> Self {
3279 use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
3280 let (layout_type, layout_metadata) = match layout {
3281 crate::data::LayoutInfo::BuiltIn(name) => (LayoutType::BuiltinName(name), None),
3282 crate::data::LayoutInfo::File(path, metadata) => {
3283 (LayoutType::FilePath(path), Some(metadata.into()))
3284 },
3285 crate::data::LayoutInfo::Url(url) => (LayoutType::Url(url), None),
3286 crate::data::LayoutInfo::Stringified(content) => {
3287 (LayoutType::Stringified(content), None)
3288 },
3289 };
3290 Self {
3291 layout_type: Some(layout_type),
3292 layout_metadata,
3293 }
3294 }
3295}
3296
3297impl TryFrom<crate::client_server_contract::client_server_contract::LayoutInfo>
3298 for crate::data::LayoutInfo
3299{
3300 type Error = anyhow::Error;
3301 fn try_from(
3302 layout: crate::client_server_contract::client_server_contract::LayoutInfo,
3303 ) -> Result<Self> {
3304 use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
3305 match layout.layout_type {
3306 Some(LayoutType::BuiltinName(name)) => Ok(crate::data::LayoutInfo::BuiltIn(name)),
3307 Some(LayoutType::FilePath(path)) => {
3308 let layout_metadata = layout
3309 .layout_metadata
3310 .map(|m| m.try_into())
3311 .transpose()?
3312 .unwrap_or_default();
3313 Ok(crate::data::LayoutInfo::File(path, layout_metadata))
3314 },
3315 Some(LayoutType::Url(url)) => Ok(crate::data::LayoutInfo::Url(url)),
3316 Some(LayoutType::Stringified(content)) => {
3317 Ok(crate::data::LayoutInfo::Stringified(content))
3318 },
3319 None => Err(anyhow!("LayoutInfo missing layout_type")),
3320 }
3321 }
3322}
3323
3324impl From<crate::data::LayoutMetadata> for ProtoLayoutMetadata {
3325 fn from(metadata: crate::data::LayoutMetadata) -> Self {
3326 ProtoLayoutMetadata {
3327 tabs: metadata.tabs.into_iter().map(|t| t.into()).collect(),
3328 creation_time: metadata.creation_time,
3329 update_time: metadata.update_time,
3330 }
3331 }
3332}
3333
3334impl TryFrom<ProtoLayoutMetadata> for crate::data::LayoutMetadata {
3335 type Error = anyhow::Error;
3336 fn try_from(proto_metadata: ProtoLayoutMetadata) -> Result<Self> {
3337 let tabs = proto_metadata
3338 .tabs
3339 .into_iter()
3340 .map(|t| t.try_into())
3341 .collect::<Result<Vec<_>>>()?;
3342 Ok(crate::data::LayoutMetadata {
3343 tabs,
3344 creation_time: proto_metadata.creation_time,
3345 update_time: proto_metadata.update_time,
3346 })
3347 }
3348}
3349
3350impl From<crate::data::TabMetadata> for ProtoTabMetadata {
3351 fn from(metadata: crate::data::TabMetadata) -> Self {
3352 ProtoTabMetadata {
3353 pane_metadata: metadata.panes.into_iter().map(|p| p.into()).collect(),
3354 name: metadata.name,
3355 }
3356 }
3357}
3358
3359impl TryFrom<ProtoTabMetadata> for crate::data::TabMetadata {
3360 type Error = anyhow::Error;
3361 fn try_from(proto_metadata: ProtoTabMetadata) -> Result<Self> {
3362 let panes = proto_metadata
3363 .pane_metadata
3364 .into_iter()
3365 .map(|p| p.try_into())
3366 .collect::<Result<Vec<_>>>()?;
3367 Ok(crate::data::TabMetadata {
3368 panes,
3369 name: proto_metadata.name,
3370 })
3371 }
3372}
3373
3374impl From<crate::data::PaneMetadata> for ProtoPaneMetadata {
3375 fn from(metadata: crate::data::PaneMetadata) -> Self {
3376 ProtoPaneMetadata {
3377 name: metadata.name,
3378 is_plugin: metadata.is_plugin,
3379 is_builtin_plugin: metadata.is_builtin_plugin,
3380 }
3381 }
3382}
3383
3384impl TryFrom<ProtoPaneMetadata> for crate::data::PaneMetadata {
3385 type Error = anyhow::Error;
3386 fn try_from(proto_metadata: ProtoPaneMetadata) -> Result<Self> {
3387 Ok(crate::data::PaneMetadata {
3388 name: proto_metadata.name,
3389 is_plugin: proto_metadata.is_plugin,
3390 is_builtin_plugin: proto_metadata.is_builtin_plugin,
3391 })
3392 }
3393}
3394
3395impl From<ExitReason> for ProtoExitReason {
3396 fn from(reason: ExitReason) -> Self {
3397 match reason {
3398 ExitReason::Normal => ProtoExitReason::Normal,
3399 ExitReason::NormalDetached => ProtoExitReason::NormalDetached,
3400 ExitReason::ForceDetached => ProtoExitReason::ForceDetached,
3401 ExitReason::CannotAttach => ProtoExitReason::CannotAttach,
3402 ExitReason::Disconnect => ProtoExitReason::Disconnect,
3403 ExitReason::WebClientsForbidden => ProtoExitReason::WebClientsForbidden,
3404 ExitReason::KickedByHost => ProtoExitReason::KickedByHost,
3405 ExitReason::Error(_msg) => ProtoExitReason::Error,
3406 ExitReason::CustomExitStatus(_status) => ProtoExitReason::CustomExitStatus,
3407 }
3408 }
3409}
3410
3411impl TryFrom<ProtoExitReason> for ExitReason {
3412 type Error = anyhow::Error;
3413 fn try_from(reason: ProtoExitReason) -> Result<Self> {
3414 match reason {
3415 ProtoExitReason::Normal => Ok(ExitReason::Normal),
3416 ProtoExitReason::NormalDetached => Ok(ExitReason::NormalDetached),
3417 ProtoExitReason::ForceDetached => Ok(ExitReason::ForceDetached),
3418 ProtoExitReason::CannotAttach => Ok(ExitReason::CannotAttach),
3419 ProtoExitReason::Disconnect => Ok(ExitReason::Disconnect),
3420 ProtoExitReason::WebClientsForbidden => Ok(ExitReason::WebClientsForbidden),
3421 ProtoExitReason::KickedByHost => Ok(ExitReason::KickedByHost),
3422 ProtoExitReason::Error => Ok(ExitReason::Error("Protobuf error".to_string())),
3423 ProtoExitReason::CustomExitStatus => Ok(ExitReason::CustomExitStatus(0)),
3424 ProtoExitReason::Unspecified => Err(anyhow!("Unspecified exit reason")),
3425 }
3426 }
3427}
3428
3429impl From<HostTerminalThemeMode> for ProtoHostTerminalThemeIndication {
3430 fn from(mode: HostTerminalThemeMode) -> Self {
3431 match mode {
3432 HostTerminalThemeMode::Dark => ProtoHostTerminalThemeIndication::Dark,
3433 HostTerminalThemeMode::Light => ProtoHostTerminalThemeIndication::Light,
3434 }
3435 }
3436}
3437
3438impl From<ProtoHostTerminalThemeIndication> for HostTerminalThemeMode {
3439 fn from(mode: ProtoHostTerminalThemeIndication) -> Self {
3440 match mode {
3441 ProtoHostTerminalThemeIndication::Dark => HostTerminalThemeMode::Dark,
3442 ProtoHostTerminalThemeIndication::Light => HostTerminalThemeMode::Light,
3443 }
3444 }
3445}
3446
3447fn input_mode_to_proto_i32(mode: InputMode) -> i32 {
3449 match mode {
3450 InputMode::Normal => ProtoInputMode::Normal as i32,
3451 InputMode::Locked => ProtoInputMode::Locked as i32,
3452 InputMode::Resize => ProtoInputMode::Resize as i32,
3453 InputMode::Pane => ProtoInputMode::Pane as i32,
3454 InputMode::Tab => ProtoInputMode::Tab as i32,
3455 InputMode::Scroll => ProtoInputMode::Scroll as i32,
3456 InputMode::EnterSearch => ProtoInputMode::EnterSearch as i32,
3457 InputMode::Search => ProtoInputMode::Search as i32,
3458 InputMode::RenameTab => ProtoInputMode::RenameTab as i32,
3459 InputMode::RenamePane => ProtoInputMode::RenamePane as i32,
3460 InputMode::Session => ProtoInputMode::Session as i32,
3461 InputMode::Move => ProtoInputMode::Move as i32,
3462 InputMode::Prompt => ProtoInputMode::Prompt as i32,
3463 InputMode::Tmux => ProtoInputMode::Tmux as i32,
3464 }
3465}
3466
3467fn proto_i32_to_input_mode(i: i32) -> Result<InputMode> {
3468 match ProtoInputMode::try_from(i).ok() {
3469 Some(ProtoInputMode::Normal) => Ok(InputMode::Normal),
3470 Some(ProtoInputMode::Locked) => Ok(InputMode::Locked),
3471 Some(ProtoInputMode::Resize) => Ok(InputMode::Resize),
3472 Some(ProtoInputMode::Pane) => Ok(InputMode::Pane),
3473 Some(ProtoInputMode::Tab) => Ok(InputMode::Tab),
3474 Some(ProtoInputMode::Scroll) => Ok(InputMode::Scroll),
3475 Some(ProtoInputMode::EnterSearch) => Ok(InputMode::EnterSearch),
3476 Some(ProtoInputMode::Search) => Ok(InputMode::Search),
3477 Some(ProtoInputMode::RenameTab) => Ok(InputMode::RenameTab),
3478 Some(ProtoInputMode::RenamePane) => Ok(InputMode::RenamePane),
3479 Some(ProtoInputMode::Session) => Ok(InputMode::Session),
3480 Some(ProtoInputMode::Move) => Ok(InputMode::Move),
3481 Some(ProtoInputMode::Prompt) => Ok(InputMode::Prompt),
3482 Some(ProtoInputMode::Tmux) => Ok(InputMode::Tmux),
3483 _ => Err(anyhow!("Invalid InputMode value: {}", i)),
3484 }
3485}
3486
3487fn resize_to_proto_i32(resize: crate::data::Resize) -> i32 {
3489 use crate::client_server_contract::client_server_contract::ResizeType;
3490 match resize {
3491 crate::data::Resize::Increase => ResizeType::Increase as i32,
3492 crate::data::Resize::Decrease => ResizeType::Decrease as i32,
3493 }
3494}
3495
3496fn direction_to_proto_i32(direction: crate::data::Direction) -> i32 {
3497 use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
3498 match direction {
3499 crate::data::Direction::Left => ProtoDirection::Left as i32,
3500 crate::data::Direction::Right => ProtoDirection::Right as i32,
3501 crate::data::Direction::Up => ProtoDirection::Up as i32,
3502 crate::data::Direction::Down => ProtoDirection::Down as i32,
3503 }
3504}
3505
3506fn search_direction_to_proto_i32(direction: crate::input::actions::SearchDirection) -> i32 {
3507 use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
3508 match direction {
3509 crate::input::actions::SearchDirection::Up => ProtoSearchDirection::Up as i32,
3510 crate::input::actions::SearchDirection::Down => ProtoSearchDirection::Down as i32,
3511 }
3512}
3513
3514fn search_option_to_proto_i32(option: crate::input::actions::SearchOption) -> i32 {
3515 use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
3516 match option {
3517 crate::input::actions::SearchOption::CaseSensitivity => {
3518 ProtoSearchOption::CaseSensitivity as i32
3519 },
3520 crate::input::actions::SearchOption::Wrap => ProtoSearchOption::Wrap as i32,
3521 crate::input::actions::SearchOption::WholeWord => ProtoSearchOption::WholeWord as i32,
3522 }
3523}
3524
3525fn unblock_condition_to_proto_i32(condition: crate::data::UnblockCondition) -> i32 {
3526 use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
3527 match condition {
3528 crate::data::UnblockCondition::OnExitSuccess => ProtoUnblockCondition::OnExitSuccess as i32,
3529 crate::data::UnblockCondition::OnExitFailure => ProtoUnblockCondition::OnExitFailure as i32,
3530 crate::data::UnblockCondition::OnAnyExit => ProtoUnblockCondition::OnAnyExit as i32,
3531 }
3532}
3533
3534fn proto_i32_to_resize(resize: i32) -> Result<crate::data::Resize> {
3537 use crate::client_server_contract::client_server_contract::ResizeType as ProtoResize;
3538 let proto_resize = match resize {
3539 x if x == ProtoResize::Increase as i32 => ProtoResize::Increase,
3540 x if x == ProtoResize::Decrease as i32 => ProtoResize::Decrease,
3541 _ => return Err(anyhow!("Invalid ResizeType: {}", resize)),
3542 };
3543 match proto_resize {
3544 ProtoResize::Increase => Ok(crate::data::Resize::Increase),
3545 ProtoResize::Decrease => Ok(crate::data::Resize::Decrease),
3546 ProtoResize::Unspecified => Err(anyhow!("Unspecified ResizeType")),
3547 }
3548}
3549
3550fn proto_i32_to_direction(direction: i32) -> Result<crate::data::Direction> {
3551 use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
3552 let proto_direction = match direction {
3553 x if x == ProtoDirection::Left as i32 => ProtoDirection::Left,
3554 x if x == ProtoDirection::Right as i32 => ProtoDirection::Right,
3555 x if x == ProtoDirection::Up as i32 => ProtoDirection::Up,
3556 x if x == ProtoDirection::Down as i32 => ProtoDirection::Down,
3557 _ => return Err(anyhow!("Invalid Direction: {}", direction)),
3558 };
3559 match proto_direction {
3560 ProtoDirection::Left => Ok(crate::data::Direction::Left),
3561 ProtoDirection::Right => Ok(crate::data::Direction::Right),
3562 ProtoDirection::Up => Ok(crate::data::Direction::Up),
3563 ProtoDirection::Down => Ok(crate::data::Direction::Down),
3564 ProtoDirection::Unspecified => Err(anyhow!("Unspecified direction")),
3565 }
3566}
3567
3568fn proto_i32_to_search_direction(direction: i32) -> Result<crate::input::actions::SearchDirection> {
3569 use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
3570 let proto_direction = match direction {
3571 x if x == ProtoSearchDirection::Up as i32 => ProtoSearchDirection::Up,
3572 x if x == ProtoSearchDirection::Down as i32 => ProtoSearchDirection::Down,
3573 _ => return Err(anyhow!("Invalid SearchDirection: {}", direction)),
3574 };
3575 match proto_direction {
3576 ProtoSearchDirection::Up => Ok(crate::input::actions::SearchDirection::Up),
3577 ProtoSearchDirection::Down => Ok(crate::input::actions::SearchDirection::Down),
3578 ProtoSearchDirection::Unspecified => Err(anyhow!("Unspecified search direction")),
3579 }
3580}
3581
3582fn proto_i32_to_search_option(option: i32) -> Result<crate::input::actions::SearchOption> {
3583 use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
3584 let proto_option = match option {
3585 x if x == ProtoSearchOption::CaseSensitivity as i32 => ProtoSearchOption::CaseSensitivity,
3586 x if x == ProtoSearchOption::WholeWord as i32 => ProtoSearchOption::WholeWord,
3587 x if x == ProtoSearchOption::Wrap as i32 => ProtoSearchOption::Wrap,
3588 _ => return Err(anyhow!("Invalid SearchOption: {}", option)),
3589 };
3590 match proto_option {
3591 ProtoSearchOption::CaseSensitivity => {
3592 Ok(crate::input::actions::SearchOption::CaseSensitivity)
3593 },
3594 ProtoSearchOption::Wrap => Ok(crate::input::actions::SearchOption::Wrap),
3595 ProtoSearchOption::WholeWord => Ok(crate::input::actions::SearchOption::WholeWord),
3596 ProtoSearchOption::Unspecified => Err(anyhow!("Unspecified search option")),
3597 }
3598}
3599
3600fn proto_i32_to_unblock_condition(condition: i32) -> Result<crate::data::UnblockCondition> {
3601 use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
3602 let proto_condition = match condition {
3603 x if x == ProtoUnblockCondition::OnExitSuccess as i32 => {
3604 ProtoUnblockCondition::OnExitSuccess
3605 },
3606 x if x == ProtoUnblockCondition::OnExitFailure as i32 => {
3607 ProtoUnblockCondition::OnExitFailure
3608 },
3609 x if x == ProtoUnblockCondition::OnAnyExit as i32 => ProtoUnblockCondition::OnAnyExit,
3610 _ => return Err(anyhow!("Invalid UnblockCondition: {}", condition)),
3611 };
3612 match proto_condition {
3613 ProtoUnblockCondition::OnExitSuccess => Ok(crate::data::UnblockCondition::OnExitSuccess),
3614 ProtoUnblockCondition::OnExitFailure => Ok(crate::data::UnblockCondition::OnExitFailure),
3615 ProtoUnblockCondition::OnAnyExit => Ok(crate::data::UnblockCondition::OnAnyExit),
3616 ProtoUnblockCondition::Unspecified => Err(anyhow!("Unspecified unblock condition")),
3617 }
3618}
3619
3620impl From<crate::position::Position>
3622 for crate::client_server_contract::client_server_contract::Position
3623{
3624 fn from(pos: crate::position::Position) -> Self {
3625 Self {
3626 line: pos.line.0 as i32,
3627 column: pos.column.0 as u64,
3628 }
3629 }
3630}
3631
3632impl TryFrom<crate::client_server_contract::client_server_contract::Position>
3634 for crate::position::Position
3635{
3636 type Error = anyhow::Error;
3637 fn try_from(
3638 pos: crate::client_server_contract::client_server_contract::Position,
3639 ) -> Result<Self> {
3640 Ok(Self {
3641 line: crate::position::Line(pos.line as isize),
3642 column: crate::position::Column(pos.column as usize),
3643 })
3644 }
3645}
3646
3647impl From<crate::input::command::OpenFilePayload>
3649 for crate::client_server_contract::client_server_contract::OpenFilePayload
3650{
3651 fn from(payload: crate::input::command::OpenFilePayload) -> Self {
3652 Self {
3653 file_to_open: payload.path.to_string_lossy().to_string(),
3654 line_number: payload.line_number.map(|n| n as u32),
3655 cwd: payload.cwd.map(|p| p.to_string_lossy().to_string()),
3656 originating_plugin: payload.originating_plugin.map(|op| op.into()),
3657 }
3658 }
3659}
3660
3661impl TryFrom<crate::client_server_contract::client_server_contract::OpenFilePayload>
3663 for crate::input::command::OpenFilePayload
3664{
3665 type Error = anyhow::Error;
3666 fn try_from(
3667 payload: crate::client_server_contract::client_server_contract::OpenFilePayload,
3668 ) -> Result<Self> {
3669 Ok(Self {
3670 path: PathBuf::from(payload.file_to_open),
3671 line_number: payload.line_number.map(|n| n as usize),
3672 cwd: payload.cwd.map(PathBuf::from),
3673 originating_plugin: payload
3674 .originating_plugin
3675 .map(|op| op.try_into())
3676 .transpose()?,
3677 })
3678 }
3679}
3680
3681impl From<crate::data::PaneId> for crate::client_server_contract::client_server_contract::PaneId {
3683 fn from(pane_id: crate::data::PaneId) -> Self {
3684 use crate::client_server_contract::client_server_contract::pane_id::PaneType;
3685 match pane_id {
3686 crate::data::PaneId::Terminal(id) => Self {
3687 pane_type: Some(PaneType::Terminal(id)),
3688 },
3689 crate::data::PaneId::Plugin(id) => Self {
3690 pane_type: Some(PaneType::Plugin(id)),
3691 },
3692 }
3693 }
3694}
3695
3696impl TryFrom<crate::client_server_contract::client_server_contract::PaneId>
3698 for crate::data::PaneId
3699{
3700 type Error = anyhow::Error;
3701 fn try_from(
3702 pane_id: crate::client_server_contract::client_server_contract::PaneId,
3703 ) -> Result<Self> {
3704 use crate::client_server_contract::client_server_contract::pane_id::PaneType;
3705 match pane_id
3706 .pane_type
3707 .ok_or_else(|| anyhow!("PaneId missing pane_type"))?
3708 {
3709 PaneType::Terminal(id) => Ok(crate::data::PaneId::Terminal(id)),
3710 PaneType::Plugin(id) => Ok(crate::data::PaneId::Plugin(id)),
3711 }
3712 }
3713}
3714
3715impl From<crate::input::layout::SplitSize>
3717 for crate::client_server_contract::client_server_contract::FloatingCoordinate
3718{
3719 fn from(size: crate::input::layout::SplitSize) -> Self {
3720 match size {
3721 crate::input::layout::SplitSize::Percent(p) => Self {
3722 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Percent(p as f32)),
3723 },
3724 crate::input::layout::SplitSize::Fixed(f) => Self {
3725 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Fixed(f as u32)),
3726 },
3727 }
3728 }
3729}
3730
3731impl TryFrom<crate::client_server_contract::client_server_contract::FloatingCoordinate>
3733 for crate::input::layout::SplitSize
3734{
3735 type Error = anyhow::Error;
3736 fn try_from(
3737 coord: crate::client_server_contract::client_server_contract::FloatingCoordinate,
3738 ) -> Result<Self> {
3739 use crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType;
3740 match coord
3741 .coordinate_type
3742 .ok_or_else(|| anyhow!("FloatingCoordinate missing coordinate_type"))?
3743 {
3744 CoordinateType::Percent(p) => Ok(crate::input::layout::SplitSize::Percent(p as usize)),
3745 CoordinateType::Fixed(f) => Ok(crate::input::layout::SplitSize::Fixed(f as usize)),
3746 }
3747 }
3748}
3749
3750impl From<crate::input::layout::PercentOrFixed>
3752 for crate::client_server_contract::client_server_contract::FloatingCoordinate
3753{
3754 fn from(size: crate::input::layout::PercentOrFixed) -> Self {
3755 match size {
3756 crate::input::layout::PercentOrFixed::Percent(p) => Self {
3757 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Percent(p as f32)),
3758 },
3759 crate::input::layout::PercentOrFixed::Fixed(f) => Self {
3760 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Fixed(f as u32)),
3761 },
3762 }
3763 }
3764}
3765
3766impl TryFrom<crate::client_server_contract::client_server_contract::FloatingCoordinate>
3768 for crate::input::layout::PercentOrFixed
3769{
3770 type Error = anyhow::Error;
3771 fn try_from(
3772 coord: crate::client_server_contract::client_server_contract::FloatingCoordinate,
3773 ) -> Result<Self> {
3774 use crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType;
3775 match coord
3776 .coordinate_type
3777 .ok_or_else(|| anyhow!("FloatingCoordinate missing coordinate_type"))?
3778 {
3779 CoordinateType::Percent(p) => {
3780 Ok(crate::input::layout::PercentOrFixed::Percent(p as usize))
3781 },
3782 CoordinateType::Fixed(f) => Ok(crate::input::layout::PercentOrFixed::Fixed(f as usize)),
3783 }
3784 }
3785}
3786
3787impl From<crate::data::FloatingPaneCoordinates>
3789 for crate::client_server_contract::client_server_contract::FloatingPaneCoordinates
3790{
3791 fn from(coords: crate::data::FloatingPaneCoordinates) -> Self {
3792 Self {
3793 x: coords.x.map(|x| x.into()),
3794 y: coords.y.map(|y| y.into()),
3795 width: coords.width.map(|w| w.into()),
3796 height: coords.height.map(|h| h.into()),
3797 pinned: coords.pinned,
3798 borderless: coords.borderless,
3799 }
3800 }
3801}
3802
3803impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneCoordinates>
3805 for crate::data::FloatingPaneCoordinates
3806{
3807 type Error = anyhow::Error;
3808 fn try_from(
3809 coords: crate::client_server_contract::client_server_contract::FloatingPaneCoordinates,
3810 ) -> Result<Self> {
3811 Ok(Self {
3812 x: coords.x.map(|x| x.try_into()).transpose()?,
3813 y: coords.y.map(|y| y.try_into()).transpose()?,
3814 width: coords.width.map(|w| w.try_into()).transpose()?,
3815 height: coords.height.map(|h| h.try_into()).transpose()?,
3816 pinned: coords.pinned,
3817 borderless: coords.borderless,
3818 })
3819 }
3820}
3821
3822impl From<crate::data::NewPanePlacement>
3824 for crate::client_server_contract::client_server_contract::NewPanePlacement
3825{
3826 fn from(placement: crate::data::NewPanePlacement) -> Self {
3827 use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
3828 use crate::client_server_contract::client_server_contract::{
3829 NoPreferencePlacement, StackedPlacement, TiledPlacement,
3830 };
3831 let placement_type = match placement {
3832 crate::data::NewPanePlacement::NoPreference {
3833 borderless: Some(b),
3834 } => PlacementType::NoPreferenceWithOptions(NoPreferencePlacement {
3835 borderless: Some(b),
3836 }),
3837 crate::data::NewPanePlacement::NoPreference { borderless: None } => {
3838 PlacementType::NoPreference(true)
3839 },
3840 crate::data::NewPanePlacement::Tiled {
3841 direction,
3842 borderless: Some(b),
3843 } => PlacementType::TiledWithOptions(TiledPlacement {
3844 direction: direction.map(direction_to_proto_i32),
3845 borderless: Some(b),
3846 }),
3847 crate::data::NewPanePlacement::Tiled {
3848 direction,
3849 borderless: None,
3850 } => PlacementType::Tiled(direction.map(direction_to_proto_i32).unwrap_or(0)),
3851 crate::data::NewPanePlacement::Floating(coords) => {
3852 PlacementType::Floating(coords.map(|c| c.into()).unwrap_or_default())
3853 },
3854 crate::data::NewPanePlacement::InPlace {
3855 pane_id_to_replace,
3856 close_replaced_pane,
3857 borderless,
3858 } => PlacementType::InPlace(
3859 crate::client_server_contract::client_server_contract::NewPanePlacementInPlace {
3860 pane_id_to_replace: pane_id_to_replace.map(|id| id.into()),
3861 close_replaced_pane,
3862 borderless,
3863 },
3864 ),
3865 crate::data::NewPanePlacement::Stacked {
3866 pane_id_to_stack_under,
3867 borderless: Some(b),
3868 } => PlacementType::StackedWithOptions(StackedPlacement {
3869 pane_id_to_stack_under: pane_id_to_stack_under.map(|id| id.into()),
3870 borderless: Some(b),
3871 }),
3872 crate::data::NewPanePlacement::Stacked {
3873 pane_id_to_stack_under,
3874 borderless: None,
3875 } => PlacementType::Stacked(
3876 pane_id_to_stack_under
3877 .map(|id| id.into())
3878 .unwrap_or_default(),
3879 ),
3880 };
3881 Self {
3882 placement_type: Some(placement_type),
3883 }
3884 }
3885}
3886
3887impl TryFrom<crate::client_server_contract::client_server_contract::NewPanePlacement>
3889 for crate::data::NewPanePlacement
3890{
3891 type Error = anyhow::Error;
3892 fn try_from(
3893 placement: crate::client_server_contract::client_server_contract::NewPanePlacement,
3894 ) -> Result<Self> {
3895 use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
3896 match placement
3897 .placement_type
3898 .ok_or_else(|| anyhow!("NewPanePlacement missing placement_type"))?
3899 {
3900 PlacementType::NoPreferenceWithOptions(opts) => {
3902 Ok(crate::data::NewPanePlacement::NoPreference {
3903 borderless: opts.borderless,
3904 })
3905 },
3906 PlacementType::TiledWithOptions(opts) => {
3907 let direction = opts.direction.map(proto_i32_to_direction).transpose()?;
3908 Ok(crate::data::NewPanePlacement::Tiled {
3909 direction,
3910 borderless: opts.borderless,
3911 })
3912 },
3913 PlacementType::StackedWithOptions(opts) => {
3914 let pane_id = opts
3915 .pane_id_to_stack_under
3916 .map(|id| id.try_into())
3917 .transpose()?;
3918 Ok(crate::data::NewPanePlacement::Stacked {
3919 pane_id_to_stack_under: pane_id,
3920 borderless: opts.borderless,
3921 })
3922 },
3923 PlacementType::NoPreference(_) => {
3925 Ok(crate::data::NewPanePlacement::NoPreference { borderless: None })
3926 },
3927 PlacementType::Tiled(direction) => {
3928 let direction = if direction == 0 {
3929 None
3930 } else {
3931 Some(proto_i32_to_direction(direction)?)
3932 };
3933 Ok(crate::data::NewPanePlacement::Tiled {
3934 direction,
3935 borderless: None,
3936 })
3937 },
3938 PlacementType::Floating(coords) => {
3939 let coords = if coords == Default::default() {
3940 None
3941 } else {
3942 Some(coords.try_into()?)
3943 };
3944 Ok(crate::data::NewPanePlacement::Floating(coords))
3945 },
3946 PlacementType::InPlace(in_place) => Ok(crate::data::NewPanePlacement::InPlace {
3947 pane_id_to_replace: in_place
3948 .pane_id_to_replace
3949 .map(|id| id.try_into())
3950 .transpose()?,
3951 close_replaced_pane: in_place.close_replaced_pane,
3952 borderless: in_place.borderless,
3953 }),
3954 PlacementType::Stacked(pane_id) => {
3955 let pane_id = if pane_id == Default::default() {
3956 None
3957 } else {
3958 Some(pane_id.try_into()?)
3959 };
3960 Ok(crate::data::NewPanePlacement::Stacked {
3961 pane_id_to_stack_under: pane_id,
3962 borderless: None,
3963 })
3964 },
3965 }
3966 }
3967}
3968
3969impl From<crate::input::mouse::MouseEvent>
3971 for crate::client_server_contract::client_server_contract::MouseEvent
3972{
3973 fn from(event: crate::input::mouse::MouseEvent) -> Self {
3974 use crate::client_server_contract::client_server_contract::{
3975 MouseEventType as ProtoMouseEventType, Position,
3976 };
3977
3978 let position = Position {
3979 line: event.position.line.0 as i32,
3980 column: event.position.column.0 as u64,
3981 };
3982
3983 let event_type = match event.event_type {
3984 crate::input::mouse::MouseEventType::Press => ProtoMouseEventType::Press as i32,
3985 crate::input::mouse::MouseEventType::Release => ProtoMouseEventType::Release as i32,
3986 crate::input::mouse::MouseEventType::Motion => ProtoMouseEventType::Motion as i32,
3987 };
3988
3989 Self {
3990 event_type,
3991 left: event.left,
3992 right: event.right,
3993 middle: event.middle,
3994 wheel_up: event.wheel_up,
3995 wheel_down: event.wheel_down,
3996 wheel_left: event.wheel_left,
3997 wheel_right: event.wheel_right,
3998 shift: event.shift,
3999 alt: event.alt,
4000 ctrl: event.ctrl,
4001 position: Some(position),
4002 }
4003 }
4004}
4005
4006impl From<crate::input::command::RunCommandAction>
4008 for crate::client_server_contract::client_server_contract::RunCommandAction
4009{
4010 fn from(action: crate::input::command::RunCommandAction) -> Self {
4011 Self {
4012 command: action.command.to_string_lossy().to_string(),
4013 args: action.args,
4014 cwd: action.cwd.map(|p| p.to_string_lossy().to_string()),
4015 direction: action.direction.map(|d| direction_to_proto_i32(d)),
4016 hold_on_close: action.hold_on_close,
4017 hold_on_start: action.hold_on_start,
4018 originating_plugin: action.originating_plugin.map(|op| op.into()),
4019 use_terminal_title: action.use_terminal_title,
4020 }
4021 }
4022}
4023
4024impl From<crate::data::OriginatingPlugin>
4026 for crate::client_server_contract::client_server_contract::OriginatingPlugin
4027{
4028 fn from(orig: crate::data::OriginatingPlugin) -> Self {
4029 use std::collections::HashMap;
4030 let context: HashMap<String, String> =
4031 orig.context.into_iter().map(|(k, v)| (k, v)).collect();
4032
4033 Self {
4034 plugin_id: orig.plugin_id,
4035 client_id: orig.client_id as u32,
4036 context,
4037 }
4038 }
4039}
4040
4041impl TryFrom<crate::client_server_contract::client_server_contract::OriginatingPlugin>
4043 for crate::data::OriginatingPlugin
4044{
4045 type Error = anyhow::Error;
4046
4047 fn try_from(
4048 orig: crate::client_server_contract::client_server_contract::OriginatingPlugin,
4049 ) -> Result<Self> {
4050 use std::collections::BTreeMap;
4051 let context: BTreeMap<String, String> = orig.context.into_iter().collect();
4052
4053 Ok(Self {
4054 plugin_id: orig.plugin_id,
4055 client_id: orig.client_id as u16,
4056 context,
4057 })
4058 }
4059}
4060
4061fn split_direction_to_proto_i32(direction: crate::input::layout::SplitDirection) -> i32 {
4063 use crate::client_server_contract::client_server_contract::SplitDirection as ProtoSplitDirection;
4064 match direction {
4065 crate::input::layout::SplitDirection::Horizontal => ProtoSplitDirection::Horizontal as i32,
4066 crate::input::layout::SplitDirection::Vertical => ProtoSplitDirection::Vertical as i32,
4067 }
4068}
4069
4070impl From<crate::input::layout::SplitSize>
4072 for crate::client_server_contract::client_server_contract::SplitSize
4073{
4074 fn from(size: crate::input::layout::SplitSize) -> Self {
4075 use crate::client_server_contract::client_server_contract::split_size::SizeType;
4076 match size {
4077 crate::input::layout::SplitSize::Percent(p) => Self {
4078 size_type: Some(SizeType::Percent(p as u32)),
4079 },
4080 crate::input::layout::SplitSize::Fixed(f) => Self {
4081 size_type: Some(SizeType::Fixed(f as u32)),
4082 },
4083 }
4084 }
4085}
4086
4087impl From<crate::input::layout::PercentOrFixed>
4089 for crate::client_server_contract::client_server_contract::PercentOrFixed
4090{
4091 fn from(size: crate::input::layout::PercentOrFixed) -> Self {
4092 use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
4093 match size {
4094 crate::input::layout::PercentOrFixed::Percent(p) => Self {
4095 size_type: Some(SizeType::Percent(p as u32)),
4096 },
4097 crate::input::layout::PercentOrFixed::Fixed(f) => Self {
4098 size_type: Some(SizeType::Fixed(f as u32)),
4099 },
4100 }
4101 }
4102}
4103
4104impl From<crate::input::layout::Run>
4106 for crate::client_server_contract::client_server_contract::Run
4107{
4108 fn from(run: crate::input::layout::Run) -> Self {
4109 use crate::client_server_contract::client_server_contract::run::RunType;
4110 match run {
4111 crate::input::layout::Run::Command(cmd) => Self {
4112 run_type: Some(RunType::Command(
4113 crate::client_server_contract::client_server_contract::RunCommandAction {
4114 command: cmd.command.to_string_lossy().to_string(),
4115 args: cmd.args,
4116 cwd: cmd.cwd.map(|p| p.to_string_lossy().to_string()),
4117 direction: None, hold_on_close: cmd.hold_on_close,
4119 hold_on_start: cmd.hold_on_start,
4120 originating_plugin: cmd.originating_plugin.map(|op| op.into()),
4121 use_terminal_title: cmd.use_terminal_title,
4122 },
4123 )),
4124 },
4125 crate::input::layout::Run::Plugin(plugin) => Self {
4126 run_type: Some(RunType::Plugin(plugin.into())),
4127 },
4128 crate::input::layout::Run::EditFile(path, line_number, cwd) => Self {
4129 run_type: Some(RunType::EditFile(
4130 crate::client_server_contract::client_server_contract::RunEditFileAction {
4131 file_path: path.to_string_lossy().to_string(),
4132 line_number: line_number.map(|n| n as u32),
4133 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
4134 },
4135 )),
4136 },
4137 crate::input::layout::Run::Cwd(path) => Self {
4138 run_type: Some(RunType::Cwd(path.to_string_lossy().to_string())),
4139 },
4140 }
4141 }
4142}
4143
4144impl From<crate::input::layout::TabLayoutInfo>
4146 for crate::client_server_contract::client_server_contract::TabLayoutInfo
4147{
4148 fn from(tab_info: crate::input::layout::TabLayoutInfo) -> Self {
4149 Self {
4150 tab_index: tab_info.tab_index as u32,
4151 tab_name: tab_info.tab_name,
4152 tiled_layout: Some(tab_info.tiled_layout.into()),
4153 floating_layouts: tab_info
4154 .floating_layouts
4155 .into_iter()
4156 .map(|l| l.into())
4157 .collect(),
4158 swap_tiled_layouts: tab_info
4159 .swap_tiled_layouts
4160 .unwrap_or_default()
4161 .into_iter()
4162 .map(|l| l.into())
4163 .collect(),
4164 swap_floating_layouts: tab_info
4165 .swap_floating_layouts
4166 .unwrap_or_default()
4167 .into_iter()
4168 .map(|l| l.into())
4169 .collect(),
4170 }
4171 }
4172}
4173
4174impl TryFrom<crate::client_server_contract::client_server_contract::TabLayoutInfo>
4175 for crate::input::layout::TabLayoutInfo
4176{
4177 type Error = anyhow::Error;
4178
4179 fn try_from(
4180 protobuf_tab: crate::client_server_contract::client_server_contract::TabLayoutInfo,
4181 ) -> Result<Self> {
4182 Ok(crate::input::layout::TabLayoutInfo {
4183 tab_index: protobuf_tab.tab_index as usize,
4184 tab_name: protobuf_tab.tab_name.filter(|s| !s.is_empty()),
4185 tiled_layout: protobuf_tab
4186 .tiled_layout
4187 .ok_or_else(|| anyhow!("missing tiled_layout"))?
4188 .try_into()?,
4189 floating_layouts: protobuf_tab
4190 .floating_layouts
4191 .into_iter()
4192 .map(|l| l.try_into())
4193 .collect::<Result<Vec<_>>>()?,
4194 swap_tiled_layouts: if protobuf_tab.swap_tiled_layouts.is_empty() {
4195 None
4196 } else {
4197 Some(
4198 protobuf_tab
4199 .swap_tiled_layouts
4200 .into_iter()
4201 .map(|l| l.try_into())
4202 .collect::<Result<Vec<_>>>()?,
4203 )
4204 },
4205 swap_floating_layouts: if protobuf_tab.swap_floating_layouts.is_empty() {
4206 None
4207 } else {
4208 Some(
4209 protobuf_tab
4210 .swap_floating_layouts
4211 .into_iter()
4212 .map(|l| l.try_into())
4213 .collect::<Result<Vec<_>>>()?,
4214 )
4215 },
4216 })
4217 }
4218}
4219
4220impl From<crate::input::layout::TiledPaneLayout>
4222 for crate::client_server_contract::client_server_contract::TiledPaneLayout
4223{
4224 fn from(layout: crate::input::layout::TiledPaneLayout) -> Self {
4225 Self {
4226 children_split_direction: split_direction_to_proto_i32(layout.children_split_direction),
4227 name: layout.name,
4228 children: layout.children.into_iter().map(|c| c.into()).collect(),
4229 split_size: layout.split_size.map(|s| s.into()),
4230 run: layout.run.map(|r| r.into()),
4231 borderless: layout.borderless,
4232 focus: layout.focus.map(|f| f.to_string()),
4233 exclude_from_sync: layout.exclude_from_sync,
4234 children_are_stacked: layout.children_are_stacked,
4235 external_children_index: layout.external_children_index.map(|l| l as u32),
4236 is_expanded_in_stack: layout.is_expanded_in_stack,
4237 hide_floating_panes: layout.hide_floating_panes,
4238 pane_initial_contents: layout.pane_initial_contents,
4239 default_fg: layout.default_fg,
4240 default_bg: layout.default_bg,
4241 }
4242 }
4243}
4244
4245impl From<crate::input::layout::FloatingPaneLayout>
4246 for crate::client_server_contract::client_server_contract::FloatingPaneLayout
4247{
4248 fn from(layout: crate::input::layout::FloatingPaneLayout) -> Self {
4249 Self {
4250 name: layout.name,
4251 height: layout.height.map(|h| h.into()),
4252 width: layout.width.map(|w| w.into()),
4253 x: layout.x.map(|x| x.into()),
4254 y: layout.y.map(|y| y.into()),
4255 pinned: layout.pinned,
4256 run: layout.run.map(|r| r.into()),
4257 focus: layout.focus,
4258 already_running: layout.already_running,
4259 pane_initial_contents: layout.pane_initial_contents,
4260 logical_position: layout.logical_position.map(|l| l as u32),
4261 borderless: layout.borderless,
4262 default_fg: layout.default_fg,
4263 default_bg: layout.default_bg,
4264 }
4265 }
4266}
4267
4268impl From<crate::input::layout::SwapTiledLayout>
4269 for crate::client_server_contract::client_server_contract::SwapTiledLayout
4270{
4271 fn from(layout: crate::input::layout::SwapTiledLayout) -> Self {
4272 use crate::client_server_contract::client_server_contract::LayoutConstraintTiledPair;
4273
4274 let constraint_map = layout
4275 .0
4276 .into_iter()
4277 .map(|(constraint, tiled_layout)| LayoutConstraintTiledPair {
4278 constraint: Some(constraint.into()),
4279 layout: Some(tiled_layout.into()),
4280 })
4281 .collect();
4282
4283 Self {
4284 constraint_map,
4285 name: layout.1,
4286 }
4287 }
4288}
4289
4290impl From<crate::input::layout::SwapFloatingLayout>
4291 for crate::client_server_contract::client_server_contract::SwapFloatingLayout
4292{
4293 fn from(layout: crate::input::layout::SwapFloatingLayout) -> Self {
4294 use crate::client_server_contract::client_server_contract::LayoutConstraintFloatingPair;
4295
4296 let constraint_map = layout
4297 .0
4298 .into_iter()
4299 .map(
4300 |(constraint, floating_layouts)| LayoutConstraintFloatingPair {
4301 constraint: Some(constraint.into()),
4302 layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
4303 },
4304 )
4305 .collect();
4306
4307 Self {
4308 constraint_map,
4309 name: layout.1,
4310 }
4311 }
4312}
4313
4314impl From<crate::input::layout::PluginUserConfiguration>
4316 for crate::client_server_contract::client_server_contract::PluginUserConfiguration
4317{
4318 fn from(config: crate::input::layout::PluginUserConfiguration) -> Self {
4319 Self {
4320 configuration: config.inner().clone().into_iter().collect(), }
4322 }
4323}
4324
4325impl From<crate::input::layout::LayoutConstraint>
4327 for crate::client_server_contract::client_server_contract::LayoutConstraintWithValue
4328{
4329 fn from(constraint: crate::input::layout::LayoutConstraint) -> Self {
4330 use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
4331 match constraint {
4332 crate::input::layout::LayoutConstraint::MaxPanes(n) => Self {
4333 constraint_type: ProtoLayoutConstraint::MaxPanes as i32,
4334 value: Some(n as u32),
4335 },
4336 crate::input::layout::LayoutConstraint::MinPanes(n) => Self {
4337 constraint_type: ProtoLayoutConstraint::MinPanes as i32,
4338 value: Some(n as u32),
4339 },
4340 crate::input::layout::LayoutConstraint::ExactPanes(n) => Self {
4341 constraint_type: ProtoLayoutConstraint::ExactPanes as i32,
4342 value: Some(n as u32),
4343 },
4344 crate::input::layout::LayoutConstraint::NoConstraint => Self {
4345 constraint_type: ProtoLayoutConstraint::NoConstraint as i32,
4346 value: None,
4347 },
4348 }
4349 }
4350}
4351
4352impl From<crate::input::layout::RunPlugin>
4354 for crate::client_server_contract::client_server_contract::RunPlugin
4355{
4356 fn from(plugin: crate::input::layout::RunPlugin) -> Self {
4357 Self {
4358 allow_exec_host_cmd: plugin._allow_exec_host_cmd,
4359 location: Some(plugin.location.into()),
4360 configuration: Some(plugin.configuration.into()),
4361 initial_cwd: plugin.initial_cwd.map(|p| p.display().to_string()),
4362 }
4363 }
4364}
4365
4366impl From<crate::input::layout::PluginAlias>
4368 for crate::client_server_contract::client_server_contract::PluginAlias
4369{
4370 fn from(plugin: crate::input::layout::PluginAlias) -> Self {
4371 Self {
4372 name: plugin.name,
4373 configuration: plugin.configuration.map(|c| c.into()),
4374 initial_cwd: plugin.initial_cwd.map(|i| i.display().to_string()),
4375 run_plugin: plugin.run_plugin.map(|r| r.into()),
4376 }
4377 }
4378}
4379
4380impl From<crate::input::layout::RunPluginLocation>
4382 for crate::client_server_contract::client_server_contract::RunPluginLocationData
4383{
4384 fn from(location: crate::input::layout::RunPluginLocation) -> Self {
4385 use crate::client_server_contract::client_server_contract::{
4386 run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
4387 };
4388 match location {
4389 crate::input::layout::RunPluginLocation::File(path) => Self {
4390 location_type: ProtoRunPluginLocation::File as i32,
4391 location_data: Some(LocationData::FilePath(path.to_string_lossy().to_string())),
4392 },
4393 crate::input::layout::RunPluginLocation::Zellij(tag) => Self {
4394 location_type: ProtoRunPluginLocation::Zellij as i32,
4395 location_data: Some(LocationData::ZellijTag(
4396 crate::client_server_contract::client_server_contract::PluginTag {
4397 tag: tag.to_string(),
4398 },
4399 )),
4400 },
4401 crate::input::layout::RunPluginLocation::Remote(url) => Self {
4402 location_type: ProtoRunPluginLocation::Remote as i32,
4403 location_data: Some(LocationData::RemoteUrl(url)),
4404 },
4405 }
4406 }
4407}
4408
4409impl From<crate::input::layout::RunPluginOrAlias>
4411 for crate::client_server_contract::client_server_contract::RunPluginOrAlias
4412{
4413 fn from(plugin: crate::input::layout::RunPluginOrAlias) -> Self {
4414 use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
4415 match plugin {
4416 crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin) => Self {
4417 plugin_type: Some(PluginType::Plugin(run_plugin.into())),
4418 },
4419 crate::input::layout::RunPluginOrAlias::Alias(alias) => Self {
4420 plugin_type: Some(PluginType::Alias(alias.into())),
4421 },
4422 }
4423 }
4424}
4425
4426impl From<crate::data::CommandOrPlugin>
4428 for crate::client_server_contract::client_server_contract::CommandOrPlugin
4429{
4430 fn from(cmd_or_plugin: crate::data::CommandOrPlugin) -> Self {
4431 use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
4432 use crate::client_server_contract::client_server_contract::CommandOrPluginFile;
4433 match cmd_or_plugin {
4434 crate::data::CommandOrPlugin::Command(cmd) => Self {
4435 command_or_plugin_type: Some(CommandOrPluginType::Command(cmd.into())),
4436 },
4437 crate::data::CommandOrPlugin::Plugin(plugin) => Self {
4438 command_or_plugin_type: Some(CommandOrPluginType::Plugin(plugin.into())),
4439 },
4440 crate::data::CommandOrPlugin::File(f) => Self {
4441 command_or_plugin_type: Some(CommandOrPluginType::File(CommandOrPluginFile {
4442 path: f.path.display().to_string(),
4443 line_number: f.line_number.map(|n| n as i32),
4444 cwd: f.cwd.map(|c| c.display().to_string()),
4445 })),
4446 },
4447 }
4448 }
4449}
4450
4451impl TryFrom<crate::client_server_contract::client_server_contract::CommandOrPlugin>
4452 for crate::data::CommandOrPlugin
4453{
4454 type Error = anyhow::Error;
4455
4456 fn try_from(
4457 proto: crate::client_server_contract::client_server_contract::CommandOrPlugin,
4458 ) -> Result<Self> {
4459 use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
4460
4461 let cmd_or_plugin_type = proto
4462 .command_or_plugin_type
4463 .ok_or_else(|| anyhow!("CommandOrPlugin missing command_or_plugin_type"))?;
4464 match cmd_or_plugin_type {
4465 CommandOrPluginType::Command(cmd) => {
4466 Ok(crate::data::CommandOrPlugin::Command(cmd.try_into()?))
4467 },
4468 CommandOrPluginType::Plugin(plugin) => {
4469 Ok(crate::data::CommandOrPlugin::Plugin(plugin.try_into()?))
4470 },
4471 CommandOrPluginType::File(f) => Ok(crate::data::CommandOrPlugin::File(
4472 crate::data::FileToOpen {
4473 path: std::path::PathBuf::from(&f.path),
4474 line_number: f.line_number.map(|n| n as usize),
4475 cwd: f.cwd.map(std::path::PathBuf::from),
4476 },
4477 )),
4478 }
4479 }
4480}
4481
4482impl TryFrom<crate::client_server_contract::client_server_contract::Run>
4484 for crate::input::layout::Run
4485{
4486 type Error = anyhow::Error;
4487
4488 fn try_from(run: crate::client_server_contract::client_server_contract::Run) -> Result<Self> {
4489 use crate::client_server_contract::client_server_contract::run::RunType;
4490
4491 let run_type = run
4492 .run_type
4493 .ok_or_else(|| anyhow!("Run missing run_type"))?;
4494 match run_type {
4495 RunType::Command(cmd) => Ok(crate::input::layout::Run::Command(
4496 crate::input::command::RunCommand {
4497 command: std::path::PathBuf::from(cmd.command),
4498 args: cmd.args,
4499 cwd: cmd.cwd.map(std::path::PathBuf::from),
4500 hold_on_close: cmd.hold_on_close,
4501 hold_on_start: cmd.hold_on_start,
4502 originating_plugin: cmd
4503 .originating_plugin
4504 .map(|op| op.try_into())
4505 .transpose()?,
4506 use_terminal_title: cmd.use_terminal_title,
4507 },
4508 )),
4509 RunType::EditFile(edit) => Ok(crate::input::layout::Run::EditFile(
4510 std::path::PathBuf::from(edit.file_path),
4511 edit.line_number.map(|n| n as usize),
4512 edit.cwd.map(std::path::PathBuf::from),
4513 )),
4514 RunType::Cwd(cwd_str) => Ok(crate::input::layout::Run::Cwd(std::path::PathBuf::from(
4515 cwd_str,
4516 ))),
4517 RunType::Plugin(plugin) => Ok(crate::input::layout::Run::Plugin(plugin.try_into()?)),
4518 }
4519 }
4520}
4521
4522impl TryFrom<crate::client_server_contract::client_server_contract::PercentOrFixed>
4524 for crate::input::layout::PercentOrFixed
4525{
4526 type Error = anyhow::Error;
4527
4528 fn try_from(
4529 value: crate::client_server_contract::client_server_contract::PercentOrFixed,
4530 ) -> Result<Self> {
4531 use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
4532
4533 let size_type = value
4534 .size_type
4535 .ok_or_else(|| anyhow!("PercentOrFixed missing size_type"))?;
4536 match size_type {
4537 SizeType::Percent(percent) => Ok(crate::input::layout::PercentOrFixed::Percent(
4538 percent as usize,
4539 )),
4540 SizeType::Fixed(fixed) => {
4541 Ok(crate::input::layout::PercentOrFixed::Fixed(fixed as usize))
4542 },
4543 }
4544 }
4545}
4546
4547impl TryFrom<crate::client_server_contract::client_server_contract::MouseEvent>
4551 for crate::input::mouse::MouseEvent
4552{
4553 type Error = anyhow::Error;
4554
4555 fn try_from(
4556 event: crate::client_server_contract::client_server_contract::MouseEvent,
4557 ) -> Result<Self> {
4558 use crate::client_server_contract::client_server_contract::MouseEventType as ProtoMouseEventType;
4559
4560 let event_type = match event.event_type {
4561 x if x == ProtoMouseEventType::Press as i32 => {
4562 crate::input::mouse::MouseEventType::Press
4563 },
4564 x if x == ProtoMouseEventType::Release as i32 => {
4565 crate::input::mouse::MouseEventType::Release
4566 },
4567 x if x == ProtoMouseEventType::Motion as i32 => {
4568 crate::input::mouse::MouseEventType::Motion
4569 },
4570 _ => return Err(anyhow!("Invalid MouseEventType: {}", event.event_type)),
4571 };
4572
4573 let position = event
4574 .position
4575 .ok_or_else(|| anyhow!("MouseEvent missing position"))?
4576 .try_into()?;
4577
4578 Ok(crate::input::mouse::MouseEvent {
4579 event_type,
4580 left: event.left,
4581 right: event.right,
4582 middle: event.middle,
4583 wheel_up: event.wheel_up,
4584 wheel_down: event.wheel_down,
4585 wheel_left: event.wheel_left,
4586 wheel_right: event.wheel_right,
4587 shift: event.shift,
4588 alt: event.alt,
4589 ctrl: event.ctrl,
4590 position,
4591 })
4592 }
4593}
4594
4595impl TryFrom<crate::client_server_contract::client_server_contract::RunCommandAction>
4597 for crate::input::command::RunCommandAction
4598{
4599 type Error = anyhow::Error;
4600
4601 fn try_from(
4602 action: crate::client_server_contract::client_server_contract::RunCommandAction,
4603 ) -> Result<Self> {
4604 Ok(crate::input::command::RunCommandAction {
4605 command: std::path::PathBuf::from(action.command),
4606 args: action.args,
4607 cwd: action.cwd.map(std::path::PathBuf::from),
4608 direction: action.direction.map(proto_i32_to_direction).transpose()?,
4609 hold_on_close: action.hold_on_close,
4610 hold_on_start: action.hold_on_start,
4611 originating_plugin: action
4612 .originating_plugin
4613 .map(|op| op.try_into())
4614 .transpose()?,
4615 use_terminal_title: action.use_terminal_title,
4616 })
4617 }
4618}
4619
4620impl TryFrom<crate::client_server_contract::client_server_contract::TiledPaneLayout>
4622 for crate::input::layout::TiledPaneLayout
4623{
4624 type Error = anyhow::Error;
4625
4626 fn try_from(
4627 layout: crate::client_server_contract::client_server_contract::TiledPaneLayout,
4628 ) -> Result<Self> {
4629 use crate::input::layout::{SplitDirection, SplitSize, TiledPaneLayout};
4630
4631 let children_split_direction = match layout.children_split_direction {
4632 x if x
4633 == crate::client_server_contract::client_server_contract::SplitDirection::Horizontal
4634 as i32 =>
4635 {
4636 SplitDirection::Horizontal
4637 },
4638 x if x
4639 == crate::client_server_contract::client_server_contract::SplitDirection::Vertical
4640 as i32 =>
4641 {
4642 SplitDirection::Vertical
4643 },
4644 _ => SplitDirection::Horizontal, };
4646
4647 let children: Result<Vec<_>> = layout.children.into_iter().map(|c| c.try_into()).collect();
4648 let run = layout.run.map(|r| r.try_into()).transpose()?;
4649
4650 let split_size = layout.split_size.and_then(|size| {
4651 use crate::client_server_contract::client_server_contract::split_size::SizeType;
4652 match size.size_type {
4653 Some(SizeType::Percent(percent)) => Some(SplitSize::Percent(percent as usize)),
4654 Some(SizeType::Fixed(fixed)) => Some(SplitSize::Fixed(fixed as usize)),
4655 None => None,
4656 }
4657 });
4658
4659 Ok(TiledPaneLayout {
4660 children_split_direction,
4661 name: layout.name,
4662 children: children?,
4663 split_size,
4664 run,
4665 borderless: layout.borderless,
4666 focus: layout.focus.map(|f| f == "true"), external_children_index: layout.external_children_index.map(|l| l as usize),
4668 children_are_stacked: layout.children_are_stacked,
4669 is_expanded_in_stack: layout.is_expanded_in_stack,
4670 exclude_from_sync: layout.exclude_from_sync,
4671 run_instructions_to_ignore: vec![], hide_floating_panes: layout.hide_floating_panes,
4673 pane_initial_contents: layout.pane_initial_contents,
4674 default_fg: layout.default_fg,
4675 default_bg: layout.default_bg,
4676 })
4677 }
4678}
4679
4680impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneLayout>
4682 for crate::input::layout::FloatingPaneLayout
4683{
4684 type Error = anyhow::Error;
4685
4686 fn try_from(
4687 layout: crate::client_server_contract::client_server_contract::FloatingPaneLayout,
4688 ) -> Result<Self> {
4689 let run = layout.run.map(|r| r.try_into()).transpose()?;
4690 let height = layout.height.map(|h| h.try_into()).transpose()?;
4691 let width = layout.width.map(|w| w.try_into()).transpose()?;
4692 let x = layout.x.map(|x| x.try_into()).transpose()?;
4693 let y = layout.y.map(|y| y.try_into()).transpose()?;
4694
4695 Ok(crate::input::layout::FloatingPaneLayout {
4696 name: layout.name,
4697 height,
4698 width,
4699 x,
4700 y,
4701 pinned: layout.pinned,
4702 run,
4703 focus: layout.focus,
4704 already_running: layout.already_running,
4705 pane_initial_contents: layout.pane_initial_contents,
4706 logical_position: layout.logical_position.map(|p| p as usize),
4707 borderless: layout.borderless,
4708 default_fg: layout.default_fg,
4709 default_bg: layout.default_bg,
4710 })
4711 }
4712}
4713
4714impl TryFrom<crate::client_server_contract::client_server_contract::SwapTiledLayout>
4716 for crate::input::layout::SwapTiledLayout
4717{
4718 type Error = anyhow::Error;
4719
4720 fn try_from(
4721 layout: crate::client_server_contract::client_server_contract::SwapTiledLayout,
4722 ) -> Result<Self> {
4723 let constraint_map: Result<BTreeMap<_, _>> = layout
4724 .constraint_map
4725 .into_iter()
4726 .map(|pair| {
4727 Ok((
4728 pair.constraint
4729 .ok_or_else(|| anyhow!("Missing constraint"))?
4730 .try_into()?,
4731 pair.layout
4732 .ok_or_else(|| anyhow!("Missing layout"))?
4733 .try_into()?,
4734 ))
4735 })
4736 .collect();
4737 Ok((constraint_map?, layout.name))
4738 }
4739}
4740
4741impl TryFrom<crate::client_server_contract::client_server_contract::SwapFloatingLayout>
4743 for crate::input::layout::SwapFloatingLayout
4744{
4745 type Error = anyhow::Error;
4746
4747 fn try_from(
4748 layout: crate::client_server_contract::client_server_contract::SwapFloatingLayout,
4749 ) -> Result<Self> {
4750 let constraint_map: Result<BTreeMap<_, _>> = layout
4751 .constraint_map
4752 .into_iter()
4753 .map(|pair| {
4754 let floating_layouts: Result<Vec<_>> =
4755 pair.layouts.into_iter().map(|l| l.try_into()).collect();
4756 Ok((
4757 pair.constraint
4758 .ok_or_else(|| anyhow!("Missing constraint"))?
4759 .try_into()?,
4760 floating_layouts?,
4761 ))
4762 })
4763 .collect();
4764
4765 Ok((constraint_map?, layout.name))
4766 }
4767}
4768
4769impl TryFrom<crate::client_server_contract::client_server_contract::PluginUserConfiguration>
4771 for crate::input::layout::PluginUserConfiguration
4772{
4773 type Error = anyhow::Error;
4774
4775 fn try_from(
4776 config: crate::client_server_contract::client_server_contract::PluginUserConfiguration,
4777 ) -> Result<Self> {
4778 let btree_map: BTreeMap<String, String> = config.configuration.into_iter().collect();
4779 Ok(crate::input::layout::PluginUserConfiguration::new(
4780 btree_map,
4781 ))
4782 }
4783}
4784
4785impl TryFrom<crate::client_server_contract::client_server_contract::LayoutConstraintWithValue>
4787 for crate::input::layout::LayoutConstraint
4788{
4789 type Error = anyhow::Error;
4790
4791 fn try_from(
4792 constraint: crate::client_server_contract::client_server_contract::LayoutConstraintWithValue,
4793 ) -> Result<Self> {
4794 use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
4795 match constraint.constraint_type {
4796 x if x == ProtoLayoutConstraint::MaxPanes as i32 => {
4797 let value = constraint
4798 .value
4799 .ok_or_else(|| anyhow!("MaxPanes constraint missing value"))?
4800 as usize;
4801 Ok(crate::input::layout::LayoutConstraint::MaxPanes(value))
4802 },
4803 x if x == ProtoLayoutConstraint::MinPanes as i32 => {
4804 let value = constraint
4805 .value
4806 .ok_or_else(|| anyhow!("MinPanes constraint missing value"))?
4807 as usize;
4808 Ok(crate::input::layout::LayoutConstraint::MinPanes(value))
4809 },
4810 x if x == ProtoLayoutConstraint::ExactPanes as i32 => {
4811 let value = constraint
4812 .value
4813 .ok_or_else(|| anyhow!("ExactPanes constraint missing value"))?
4814 as usize;
4815 Ok(crate::input::layout::LayoutConstraint::ExactPanes(value))
4816 },
4817 x if x == ProtoLayoutConstraint::NoConstraint as i32 => {
4818 Ok(crate::input::layout::LayoutConstraint::NoConstraint)
4819 },
4820 _ => Err(anyhow!(
4821 "Invalid LayoutConstraint type: {}",
4822 constraint.constraint_type
4823 )),
4824 }
4825 }
4826}
4827
4828impl TryFrom<crate::client_server_contract::client_server_contract::RunPlugin>
4830 for crate::input::layout::RunPlugin
4831{
4832 type Error = anyhow::Error;
4833
4834 fn try_from(
4835 plugin: crate::client_server_contract::client_server_contract::RunPlugin,
4836 ) -> Result<Self> {
4837 let location = plugin
4838 .location
4839 .ok_or_else(|| anyhow!("RunPlugin missing location"))?
4840 .try_into()?;
4841 let configuration = plugin
4842 .configuration
4843 .ok_or_else(|| anyhow!("RunPlugin missing configuration"))?
4844 .try_into()?;
4845 let initial_cwd = plugin.initial_cwd.map(std::path::PathBuf::from);
4846
4847 Ok(crate::input::layout::RunPlugin {
4848 _allow_exec_host_cmd: plugin.allow_exec_host_cmd,
4849 location,
4850 configuration,
4851 initial_cwd,
4852 })
4853 }
4854}
4855
4856impl TryFrom<crate::client_server_contract::client_server_contract::PluginAlias>
4858 for crate::input::layout::PluginAlias
4859{
4860 type Error = anyhow::Error;
4861
4862 fn try_from(
4863 plugin_alias: crate::client_server_contract::client_server_contract::PluginAlias,
4864 ) -> Result<Self> {
4865 let run_plugin = plugin_alias.run_plugin.and_then(|r| r.try_into().ok());
4866 let configuration = plugin_alias.configuration.and_then(|c| c.try_into().ok());
4867 let initial_cwd = plugin_alias.initial_cwd.map(std::path::PathBuf::from);
4868 Ok(crate::input::layout::PluginAlias {
4869 name: plugin_alias.name,
4870 configuration,
4871 initial_cwd,
4872 run_plugin,
4873 })
4874 }
4875}
4876
4877impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginLocationData>
4879 for crate::input::layout::RunPluginLocation
4880{
4881 type Error = anyhow::Error;
4882
4883 fn try_from(
4884 location: crate::client_server_contract::client_server_contract::RunPluginLocationData,
4885 ) -> Result<Self> {
4886 use crate::client_server_contract::client_server_contract::{
4887 run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
4888 };
4889
4890 let location_data = location
4891 .location_data
4892 .ok_or_else(|| anyhow!("RunPluginLocationData missing location_data"))?;
4893 match location.location_type {
4894 x if x == ProtoRunPluginLocation::File as i32 => {
4895 if let LocationData::FilePath(path) = location_data {
4896 Ok(crate::input::layout::RunPluginLocation::File(
4897 std::path::PathBuf::from(path),
4898 ))
4899 } else {
4900 Err(anyhow!("File location type but wrong data variant"))
4901 }
4902 },
4903 x if x == ProtoRunPluginLocation::Zellij as i32 => {
4904 if let LocationData::ZellijTag(tag) = location_data {
4905 Ok(crate::input::layout::RunPluginLocation::Zellij(
4906 crate::data::PluginTag::new(tag.tag),
4907 ))
4908 } else {
4909 Err(anyhow!("Zellij location type but wrong data variant"))
4910 }
4911 },
4912 x if x == ProtoRunPluginLocation::Remote as i32 => {
4913 if let LocationData::RemoteUrl(url) = location_data {
4914 Ok(crate::input::layout::RunPluginLocation::Remote(url))
4915 } else {
4916 Err(anyhow!("Remote location type but wrong data variant"))
4917 }
4918 },
4919 _ => Err(anyhow!(
4920 "Invalid RunPluginLocation type: {}",
4921 location.location_type
4922 )),
4923 }
4924 }
4925}
4926
4927impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginOrAlias>
4929 for crate::input::layout::RunPluginOrAlias
4930{
4931 type Error = anyhow::Error;
4932
4933 fn try_from(
4934 plugin: crate::client_server_contract::client_server_contract::RunPluginOrAlias,
4935 ) -> Result<Self> {
4936 use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
4937
4938 let plugin_type = plugin
4939 .plugin_type
4940 .ok_or_else(|| anyhow!("RunPluginOrAlias missing plugin_type"))?;
4941 match plugin_type {
4942 PluginType::Plugin(run_plugin) => Ok(
4943 crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin.try_into()?),
4944 ),
4945 PluginType::Alias(plugin_alias) => Ok(crate::input::layout::RunPluginOrAlias::Alias(
4946 plugin_alias.try_into()?,
4947 )),
4948 }
4949 }
4950}