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 initial_panes: cli_assets
849 .initial_panes
850 .map(|panes| panes.into_iter().map(|p| p.into()).collect())
851 .unwrap_or_default(),
852 }
853 }
854}
855
856impl TryFrom<crate::client_server_contract::client_server_contract::CliAssets>
857 for crate::input::cli_assets::CliAssets
858{
859 type Error = anyhow::Error;
860 fn try_from(
861 cli_assets: crate::client_server_contract::client_server_contract::CliAssets,
862 ) -> Result<Self> {
863 Ok(Self {
864 config_file_path: cli_assets.config_file_path.map(PathBuf::from),
865 config_dir: cli_assets.config_dir.map(PathBuf::from),
866 should_ignore_config: cli_assets.should_ignore_config,
867 configuration_options: cli_assets
868 .configuration_options
869 .map(|o| o.try_into())
870 .transpose()?,
871 layout: cli_assets.layout.map(|l| l.try_into()).transpose()?,
872 terminal_window_size: cli_assets
873 .terminal_window_size
874 .ok_or_else(|| anyhow!("CliAssets missing terminal_window_size"))?
875 .try_into()?,
876 data_dir: cli_assets.data_dir.map(PathBuf::from),
877 is_debug: cli_assets.is_debug,
878 max_panes: cli_assets.max_panes.map(|m| m as usize),
879 force_run_layout_commands: cli_assets.force_run_layout_commands,
880 cwd: cli_assets.cwd.map(PathBuf::from),
881 host_terminal_env: cli_assets.host_terminal_env.into_iter().collect(),
882 initial_panes: if cli_assets.initial_panes.is_empty() {
883 None
884 } else {
885 Some(
886 cli_assets
887 .initial_panes
888 .into_iter()
889 .map(|p| p.try_into())
890 .collect::<Result<Vec<_>>>()?,
891 )
892 },
893 })
894 }
895}
896
897impl From<crate::input::options::Options>
898 for crate::client_server_contract::client_server_contract::Options
899{
900 fn from(options: crate::input::options::Options) -> Self {
901 use crate::client_server_contract::client_server_contract::{
902 Clipboard as ProtoClipboard, OnForceClose as ProtoOnForceClose,
903 WebSharing as ProtoWebSharing,
904 };
905
906 Self {
907 simplified_ui: options.simplified_ui,
908 theme: options.theme,
909 theme_dark: options.theme_dark,
910 theme_light: options.theme_light,
911 default_mode: options.default_mode.map(|m| input_mode_to_proto_i32(m)),
912 default_shell: options
913 .default_shell
914 .map(|p| p.to_string_lossy().to_string()),
915 default_cwd: options.default_cwd.map(|p| p.to_string_lossy().to_string()),
916 default_layout: options
917 .default_layout
918 .map(|p| p.to_string_lossy().to_string()),
919 layout_dir: options.layout_dir.map(|p| p.to_string_lossy().to_string()),
920 theme_dir: options.theme_dir.map(|p| p.to_string_lossy().to_string()),
921 mouse_mode: options.mouse_mode,
922 pane_frames: options.pane_frames,
923 mirror_session: options.mirror_session,
924 on_force_close: options.on_force_close.map(|o| match o {
925 crate::input::options::OnForceClose::Quit => ProtoOnForceClose::Quit as i32,
926 crate::input::options::OnForceClose::Detach => ProtoOnForceClose::Detach as i32,
927 }),
928 scroll_buffer_size: options.scroll_buffer_size.map(|s| s as u32),
929 copy_command: options.copy_command,
930 copy_clipboard: options.copy_clipboard.map(|c| match c {
931 crate::input::options::Clipboard::System => ProtoClipboard::System as i32,
932 crate::input::options::Clipboard::Primary => ProtoClipboard::Primary as i32,
933 }),
934 copy_on_select: options.copy_on_select,
935 osc8_hyperlinks: options.osc8_hyperlinks,
936 scrollback_editor: options
937 .scrollback_editor
938 .map(|p| p.to_string_lossy().to_string()),
939 session_name: options.session_name,
940 attach_to_session: options.attach_to_session,
941 auto_layout: options.auto_layout,
942 session_serialization: options.session_serialization,
943 serialize_pane_viewport: options.serialize_pane_viewport,
944 scrollback_lines_to_serialize: options.scrollback_lines_to_serialize.map(|s| s as u32),
945 styled_underlines: options.styled_underlines,
946 serialization_interval: options.serialization_interval,
947 disable_session_metadata: options.disable_session_metadata,
948 support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
949 support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
950 web_server: options.web_server,
951 web_sharing: options.web_sharing.map(|w| match w {
952 crate::data::WebSharing::On => ProtoWebSharing::On as i32,
953 crate::data::WebSharing::Off => ProtoWebSharing::Off as i32,
954 crate::data::WebSharing::Disabled => ProtoWebSharing::Disabled as i32,
955 }),
956 stacked_resize: options.stacked_resize,
957 stacked_pane_list: options.stacked_pane_list,
958 dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
959 show_startup_tips: options.show_startup_tips,
960 show_release_notes: options.show_release_notes,
961 advanced_mouse_actions: options.advanced_mouse_actions,
962 mouse_scroll_resize: options.mouse_scroll_resize,
963 scroll_mode_sync: options.scroll_mode_sync,
964 mouse_hover_effects: options.mouse_hover_effects,
965 mouse_hover_tips: options.mouse_hover_tips,
966 web_server_ip: options.web_server_ip.map(|ip| ip.to_string()),
967 web_server_port: options.web_server_port.map(|p| p as u32),
968 web_server_cert: options
969 .web_server_cert
970 .map(|p| p.to_string_lossy().to_string()),
971 web_server_key: options
972 .web_server_key
973 .map(|p| p.to_string_lossy().to_string()),
974 enforce_https_for_localhost: options.enforce_https_for_localhost,
975 post_command_discovery_hook: options.post_command_discovery_hook,
976 client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as u64),
977 visual_bell: options.visual_bell,
978 focus_follows_mouse: options.focus_follows_mouse,
979 mouse_click_through: options.mouse_click_through,
980 osc133_command_selection: options.osc133_command_selection,
981 word_separators: options.word_separators,
982 host_notification_protocol: options
983 .host_notification_protocol
984 .map(|p| p.as_str().to_owned()),
985 pane_frame_style: options.pane_frame_style.map(|s| match s {
986 crate::input::options::PaneFrameStyle::Full => "full".to_owned(),
987 crate::input::options::PaneFrameStyle::Titles => "titles".to_owned(),
988 crate::input::options::PaneFrameStyle::None => "none".to_owned(),
989 }),
990 nested_session_handling: options.nested_session_handling.map(|n| {
991 use crate::client_server_contract::client_server_contract::NestedSessionHandling as ProtoNestedSessionHandling;
992 use crate::input::options::NestedSessionHandling;
993 match n {
994 NestedSessionHandling::Ask => ProtoNestedSessionHandling::Ask as i32,
995 NestedSessionHandling::Fullscreen => {
996 ProtoNestedSessionHandling::Fullscreen as i32
997 },
998 NestedSessionHandling::Descend => ProtoNestedSessionHandling::Descend as i32,
999 NestedSessionHandling::Never => ProtoNestedSessionHandling::Never as i32,
1000 }
1001 }),
1002 explicit_theme_hue: options.explicit_theme_hue.map(|hue| {
1003 use crate::client_server_contract::client_server_contract::ThemeHue as ProtoThemeHue;
1004 match hue {
1005 crate::data::ThemeHue::Dark => ProtoThemeHue::Dark as i32,
1006 crate::data::ThemeHue::Light => ProtoThemeHue::Light as i32,
1007 }
1008 }),
1009 }
1010 }
1011}
1012
1013impl TryFrom<crate::client_server_contract::client_server_contract::Options>
1014 for crate::input::options::Options
1015{
1016 type Error = anyhow::Error;
1017 fn try_from(
1018 options: crate::client_server_contract::client_server_contract::Options,
1019 ) -> Result<Self> {
1020 use crate::client_server_contract::client_server_contract::{
1021 Clipboard as ProtoClipboard, NestedSessionHandling as ProtoNestedSessionHandling,
1022 OnForceClose as ProtoOnForceClose, WebSharing as ProtoWebSharing,
1023 };
1024
1025 Ok(Self {
1026 simplified_ui: options.simplified_ui,
1027 theme: options.theme,
1028 theme_dark: options.theme_dark,
1029 theme_light: options.theme_light,
1030 default_mode: options
1031 .default_mode
1032 .map(|m| proto_i32_to_input_mode(m))
1033 .transpose()?,
1034 default_shell: options.default_shell.map(std::path::PathBuf::from),
1035 default_cwd: options.default_cwd.map(std::path::PathBuf::from),
1036 default_layout: options.default_layout.map(std::path::PathBuf::from),
1037 layout_dir: options.layout_dir.map(std::path::PathBuf::from),
1038 theme_dir: options.theme_dir.map(std::path::PathBuf::from),
1039 mouse_mode: options.mouse_mode,
1040 pane_frames: options.pane_frames,
1041 pane_frame_style: options.pane_frame_style.as_deref().and_then(|s| match s {
1042 "full" => Some(crate::input::options::PaneFrameStyle::Full),
1043 "titles" => Some(crate::input::options::PaneFrameStyle::Titles),
1044 "none" => Some(crate::input::options::PaneFrameStyle::None),
1045 _ => None,
1046 }),
1047 mirror_session: options.mirror_session,
1048 on_force_close: options
1049 .on_force_close
1050 .map(|o| match ProtoOnForceClose::try_from(o).ok() {
1051 Some(ProtoOnForceClose::Quit) => Ok(crate::input::options::OnForceClose::Quit),
1052 Some(ProtoOnForceClose::Detach) => {
1053 Ok(crate::input::options::OnForceClose::Detach)
1054 },
1055 _ => Err(anyhow!("Invalid OnForceClose value: {}", o)),
1056 })
1057 .transpose()?,
1058 scroll_buffer_size: options.scroll_buffer_size.map(|s| s as usize),
1059 copy_command: options.copy_command,
1060 copy_clipboard: options
1061 .copy_clipboard
1062 .map(|c| match ProtoClipboard::try_from(c).ok() {
1063 Some(ProtoClipboard::System) => Ok(crate::input::options::Clipboard::System),
1064 Some(ProtoClipboard::Primary) => Ok(crate::input::options::Clipboard::Primary),
1065 _ => Err(anyhow!("Invalid Clipboard value: {}", c)),
1066 })
1067 .transpose()?,
1068 copy_on_select: options.copy_on_select,
1069 osc8_hyperlinks: options.osc8_hyperlinks,
1070 scrollback_editor: options.scrollback_editor.map(std::path::PathBuf::from),
1071 session_name: options.session_name,
1072 attach_to_session: options.attach_to_session,
1073 auto_layout: options.auto_layout,
1074 session_serialization: options.session_serialization,
1075 serialize_pane_viewport: options.serialize_pane_viewport,
1076 scrollback_lines_to_serialize: options
1077 .scrollback_lines_to_serialize
1078 .map(|s| s as usize),
1079 styled_underlines: options.styled_underlines,
1080 serialization_interval: options.serialization_interval,
1081 disable_session_metadata: options.disable_session_metadata,
1082 support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
1083 support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
1084 web_server: options.web_server,
1085 web_sharing: options
1086 .web_sharing
1087 .map(|w| match ProtoWebSharing::try_from(w).ok() {
1088 Some(ProtoWebSharing::On) => Ok(crate::data::WebSharing::On),
1089 Some(ProtoWebSharing::Off) => Ok(crate::data::WebSharing::Off),
1090 Some(ProtoWebSharing::Disabled) => Ok(crate::data::WebSharing::Disabled),
1091 _ => Err(anyhow!("Invalid WebSharing value: {}", w)),
1092 })
1093 .transpose()?,
1094 stacked_resize: options.stacked_resize,
1095 stacked_pane_list: options.stacked_pane_list,
1096 dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
1097 show_startup_tips: options.show_startup_tips,
1098 show_release_notes: options.show_release_notes,
1099 advanced_mouse_actions: options.advanced_mouse_actions,
1100 mouse_scroll_resize: options.mouse_scroll_resize,
1101 scroll_mode_sync: options.scroll_mode_sync,
1102 mouse_hover_effects: options.mouse_hover_effects,
1103 mouse_hover_tips: options.mouse_hover_tips,
1104 web_server_ip: options
1105 .web_server_ip
1106 .map(|ip| ip.parse())
1107 .transpose()
1108 .map_err(|e| anyhow!("Invalid IP address: {}", e))?,
1109 web_server_port: options.web_server_port.map(|p| p as u16),
1110 web_server_cert: options.web_server_cert.map(std::path::PathBuf::from),
1111 web_server_key: options.web_server_key.map(std::path::PathBuf::from),
1112 enforce_https_for_localhost: options.enforce_https_for_localhost,
1113 post_command_discovery_hook: options.post_command_discovery_hook,
1114 client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as usize),
1115 visual_bell: options.visual_bell,
1116 focus_follows_mouse: options.focus_follows_mouse,
1117 mouse_click_through: options.mouse_click_through,
1118 osc133_command_selection: options.osc133_command_selection,
1119 word_separators: options.word_separators,
1120 host_notification_protocol: options
1121 .host_notification_protocol
1122 .map(|p| {
1123 p.parse::<crate::input::options::HostNotificationProtocol>()
1124 .map_err(|e| anyhow!(e))
1125 })
1126 .transpose()?,
1127 nested_session_handling: options
1128 .nested_session_handling
1129 .map(|n| match ProtoNestedSessionHandling::try_from(n).ok() {
1130 Some(ProtoNestedSessionHandling::Ask) => {
1131 Ok(crate::input::options::NestedSessionHandling::Ask)
1132 },
1133 Some(ProtoNestedSessionHandling::Fullscreen) => {
1134 Ok(crate::input::options::NestedSessionHandling::Fullscreen)
1135 },
1136 Some(ProtoNestedSessionHandling::Descend) => {
1137 Ok(crate::input::options::NestedSessionHandling::Descend)
1138 },
1139 Some(ProtoNestedSessionHandling::Never) => {
1140 Ok(crate::input::options::NestedSessionHandling::Never)
1141 },
1142 _ => Err(anyhow!("Invalid NestedSessionHandling value: {}", n)),
1143 })
1144 .transpose()?,
1145 explicit_theme_hue: options
1146 .explicit_theme_hue
1147 .map(|hue| {
1148 use crate::client_server_contract::client_server_contract::ThemeHue as ProtoThemeHue;
1149 match ProtoThemeHue::try_from(hue).ok() {
1150 Some(ProtoThemeHue::Dark) => Ok(crate::data::ThemeHue::Dark),
1151 Some(ProtoThemeHue::Light) => Ok(crate::data::ThemeHue::Light),
1152 _ => Err(anyhow!("Invalid ThemeHue value: {}", hue)),
1153 }
1154 })
1155 .transpose()?,
1156 })
1157 }
1158}
1159
1160impl From<crate::input::actions::Action>
1162 for crate::client_server_contract::client_server_contract::Action
1163{
1164 fn from(action: crate::input::actions::Action) -> Self {
1165 use crate::client_server_contract::client_server_contract::{
1166 action::ActionType,
1167 AreFloatingPanesVisibleAction,
1168 BreakPaneAction,
1169 BreakPaneLeftAction,
1170 BreakPaneRightAction,
1171 ChangeFloatingPaneCoordinatesAction,
1172 ClearScreenAction,
1173 ClearScreenByPaneIdAction,
1174 CliPipeAction,
1175 CloseFocusAction,
1176 CloseFocusByPaneIdAction,
1177 ClosePluginPaneAction,
1178 CloseTabAction,
1179 CloseTabByIdAction,
1180 CloseTerminalPaneAction,
1181 ConfirmAction,
1182 CopyAction,
1183 CopyLastCommandOutputAction,
1184 CurrentTabInfoAction,
1185 DenyAction,
1186 DetachAction,
1187 DumpLayoutAction,
1188 DumpScreenAction,
1189 EditFileAction,
1190 EditScrollbackAction,
1191 EditScrollbackByPaneIdAction,
1192 FocusGuestSessionAction,
1193 FocusHostSessionAction,
1194 FocusLastPaneAction,
1195 FocusNextPaneAction,
1196 FocusPaneByPaneIdAction,
1197 FocusPluginPaneWithIdAction,
1198 FocusPreviousPaneAction,
1199 FocusTerminalPaneWithIdAction,
1200 GoToNextTabAction,
1201 GoToPreviousTabAction,
1202 GoToTabAction,
1203 GoToTabByIdAction,
1204 GoToTabNameAction,
1205 HalfPageScrollDownAction,
1206 HalfPageScrollDownByPaneIdAction,
1207 HalfPageScrollUpAction,
1208 HalfPageScrollUpByPaneIdAction,
1209 HideFloatingPanesAction,
1210 KeybindPipeAction,
1211 LaunchOrFocusPluginAction,
1212 LaunchPluginAction,
1213 ListClientsAction,
1214 ListPanesAction,
1215 ListTabsAction,
1216 MouseEventAction,
1217 MoveFocusAction,
1218 MoveFocusOrTabAction,
1219 MovePaneAction,
1220 MovePaneBackwardsAction,
1221 MovePaneBackwardsByPaneIdAction,
1222 MovePaneByPaneIdAction,
1223 MoveTabAction,
1224 MoveTabByTabIdAction,
1225 NewBlockingPaneAction,
1226 NewFloatingPaneAction,
1227 NewFloatingPluginPaneAction,
1228 NewInPlacePaneAction,
1229 NewInPlacePluginPaneAction,
1230 NewPaneAction,
1231 NewStackedPaneAction,
1232 NewTabAction,
1233 NewTiledPaneAction,
1234 NewTiledPluginPaneAction,
1235 NextSwapLayoutAction,
1236 NextSwapLayoutByTabIdAction,
1237 NoOpAction,
1238 OverrideLayoutAction,
1239 PageScrollDownAction,
1240 PageScrollDownByPaneIdAction,
1241 PageScrollUpAction,
1242 PageScrollUpByPaneIdAction,
1243 PaneIdWithPlugin,
1244 PaneNameInputAction,
1245 PasteAction,
1246 PreviousSwapLayoutAction,
1247 PreviousSwapLayoutByTabIdAction,
1248 QueryTabNamesAction,
1249 QuitAction,
1250 RenamePaneByPaneIdAction,
1251 RenamePluginPaneAction,
1252 RenameSessionAction,
1253 RenameTabAction,
1254 RenameTabByIdAction,
1255 RenameTerminalPaneAction,
1256 ResizeAction,
1257 ResizeByPaneIdAction,
1258 RunAction,
1259 SaveSessionAction,
1260 ScrollDownAction,
1261 ScrollDownAtAction,
1262 ScrollDownByPaneIdAction,
1263 ScrollToBottomAction,
1264 ScrollToBottomByPaneIdAction,
1265 ScrollToNextPromptAction,
1266 ScrollToPreviousPromptAction,
1267 ScrollToTopAction,
1268 ScrollToTopByPaneIdAction,
1269 ScrollUpAction,
1270 ScrollUpAtAction,
1271 ScrollUpByPaneIdAction,
1273 SearchAction,
1274 SearchInputAction,
1275 SearchToggleOptionAction,
1276 SelectCommandAtScrollPositionAction,
1277 SetDarkThemeAction,
1278 SetLightThemeAction,
1279 SetPaneBorderlessAction,
1280 SetPaneColorAction,
1281 SetPaneFrameStyleAction,
1282 ShowFloatingPanesAction,
1283 SkipConfirmAction,
1284 StackPanesAction,
1285 StartOrReloadPluginAction,
1286 SwitchFocusAction,
1287 SwitchModeForAllClientsAction,
1288 SwitchSessionAction,
1289 SwitchToModeAction,
1290 TabNameInputAction,
1291 ToggleActiveSyncTabAction,
1292 ToggleActiveSyncTabByTabIdAction,
1293 ToggleFloatingPanesAction,
1294 ToggleFloatingPanesByTabIdAction,
1295 ToggleFocusFullscreenAction,
1296 ToggleFocusNoUiFullscreenAction,
1297 ToggleFullscreenByPaneIdAction,
1298 ToggleGroupMarkingAction,
1299 ToggleHostFullscreenAction,
1300 ToggleMouseModeAction,
1301 ToggleNoUiFullscreenByPaneIdAction,
1302 TogglePaneBorderlessAction,
1303 TogglePaneEmbedOrFloatingAction,
1304 TogglePaneEmbedOrFloatingByPaneIdAction,
1305 TogglePaneFramesAction,
1306 TogglePaneInGroupAction,
1307 TogglePanePinnedAction,
1308 TogglePanePinnedByPaneIdAction,
1309 ToggleTabAction,
1310 ToggleThemeAction,
1311 UndoRenamePaneAction,
1312 UndoRenamePaneByPaneIdAction,
1313 UndoRenameTabAction,
1314 UndoRenameTabByTabIdAction,
1316 WriteAction,
1317 WriteCharsAction,
1318 WriteCharsToPaneIdAction,
1319 WriteToPaneIdAction,
1320 };
1321 use std::collections::HashMap;
1322
1323 let action_type = match action {
1324 crate::input::actions::Action::Quit => ActionType::Quit(QuitAction {}),
1325 crate::input::actions::Action::Write {
1326 key_with_modifier,
1327 bytes,
1328 is_kitty_keyboard_protocol,
1329 } => ActionType::Write(WriteAction {
1330 key_with_modifier: key_with_modifier.map(|k| k.into()),
1331 bytes: bytes.into_iter().map(|b| b as u32).collect(),
1332 is_kitty_keyboard_protocol,
1333 }),
1334 crate::input::actions::Action::WriteChars { chars } => {
1335 ActionType::WriteChars(WriteCharsAction { chars })
1336 },
1337 crate::input::actions::Action::WriteToPaneId { bytes, pane_id } => {
1338 ActionType::WriteToPaneId(WriteToPaneIdAction {
1339 pane_id: Some(pane_id.into()),
1340 bytes: bytes.into_iter().map(|b| b as u32).collect(),
1341 })
1342 },
1343 crate::input::actions::Action::WriteCharsToPaneId { chars, pane_id } => {
1344 ActionType::WriteCharsToPaneId(WriteCharsToPaneIdAction {
1345 pane_id: Some(pane_id.into()),
1346 chars,
1347 })
1348 },
1349 crate::input::actions::Action::Paste { chars, pane_id } => {
1350 ActionType::Paste(PasteAction {
1351 chars,
1352 pane_id: pane_id.map(|p| p.into()),
1353 })
1354 },
1355 crate::input::actions::Action::SwitchToMode { input_mode } => {
1356 ActionType::SwitchToMode(SwitchToModeAction {
1357 input_mode: input_mode_to_proto_i32(input_mode),
1358 })
1359 },
1360 crate::input::actions::Action::SwitchModeForAllClients { input_mode } => {
1361 ActionType::SwitchModeForAllClients(SwitchModeForAllClientsAction {
1362 input_mode: input_mode_to_proto_i32(input_mode),
1363 })
1364 },
1365 crate::input::actions::Action::Resize { resize, direction } => {
1366 ActionType::Resize(ResizeAction {
1367 resize: resize_to_proto_i32(resize),
1368 direction: direction.map(|d| direction_to_proto_i32(d)),
1369 })
1370 },
1371 crate::input::actions::Action::FocusNextPane => {
1372 ActionType::FocusNextPane(FocusNextPaneAction {})
1373 },
1374 crate::input::actions::Action::FocusPreviousPane => {
1375 ActionType::FocusPreviousPane(FocusPreviousPaneAction {})
1376 },
1377 crate::input::actions::Action::FocusLastPane => {
1378 ActionType::FocusLastPane(FocusLastPaneAction {})
1379 },
1380 crate::input::actions::Action::FocusHostSession => {
1381 ActionType::FocusHostSession(FocusHostSessionAction {})
1382 },
1383 crate::input::actions::Action::FocusGuestSession => {
1384 ActionType::FocusGuestSession(FocusGuestSessionAction {})
1385 },
1386 crate::input::actions::Action::ToggleHostFullscreen => {
1387 ActionType::ToggleHostFullscreen(ToggleHostFullscreenAction {})
1388 },
1389 crate::input::actions::Action::SwitchFocus => {
1390 ActionType::SwitchFocus(SwitchFocusAction {})
1391 },
1392 crate::input::actions::Action::MoveFocus { direction } => {
1393 ActionType::MoveFocus(MoveFocusAction {
1394 direction: direction_to_proto_i32(direction),
1395 })
1396 },
1397 crate::input::actions::Action::MoveFocusOrTab { direction } => {
1398 ActionType::MoveFocusOrTab(MoveFocusOrTabAction {
1399 direction: direction_to_proto_i32(direction),
1400 })
1401 },
1402 crate::input::actions::Action::MovePane { direction } => {
1403 ActionType::MovePane(MovePaneAction {
1404 direction: direction.map(|d| direction_to_proto_i32(d)),
1405 })
1406 },
1407 crate::input::actions::Action::MovePaneBackwards => {
1408 ActionType::MovePaneBackwards(MovePaneBackwardsAction {})
1409 },
1410 crate::input::actions::Action::ClearScreen => {
1411 ActionType::ClearScreen(ClearScreenAction {})
1412 },
1413 crate::input::actions::Action::DumpScreen {
1414 file_path,
1415 include_scrollback,
1416 pane_id,
1417 ansi,
1418 } => {
1419 let dump_to_stdout = file_path.is_none();
1420 ActionType::DumpScreen(DumpScreenAction {
1421 file_path: file_path.unwrap_or_default(),
1422 include_scrollback,
1423 pane_id: pane_id.map(|p| p.into()),
1424 dump_to_stdout,
1425 ansi,
1426 })
1427 },
1428 crate::input::actions::Action::DumpLayout => {
1429 ActionType::DumpLayout(DumpLayoutAction {})
1430 },
1431 crate::input::actions::Action::EditScrollback { ansi } => {
1432 ActionType::EditScrollback(EditScrollbackAction { ansi })
1433 },
1434 crate::input::actions::Action::ScrollUp => ActionType::ScrollUp(ScrollUpAction {}),
1435 crate::input::actions::Action::ScrollUpAt { position } => {
1436 ActionType::ScrollUpAt(ScrollUpAtAction {
1437 position: Some(position.into()),
1438 })
1439 },
1440 crate::input::actions::Action::ScrollDown => {
1441 ActionType::ScrollDown(ScrollDownAction {})
1442 },
1443 crate::input::actions::Action::ScrollDownAt { position } => {
1444 ActionType::ScrollDownAt(ScrollDownAtAction {
1445 position: Some(position.into()),
1446 })
1447 },
1448 crate::input::actions::Action::ScrollToBottom => {
1449 ActionType::ScrollToBottom(ScrollToBottomAction {})
1450 },
1451 crate::input::actions::Action::ScrollToTop => {
1452 ActionType::ScrollToTop(ScrollToTopAction {})
1453 },
1454 crate::input::actions::Action::ScrollToPreviousPrompt => {
1455 ActionType::ScrollToPreviousPrompt(ScrollToPreviousPromptAction {})
1456 },
1457 crate::input::actions::Action::ScrollToNextPrompt => {
1458 ActionType::ScrollToNextPrompt(ScrollToNextPromptAction {})
1459 },
1460 crate::input::actions::Action::SelectCommandAtScrollPosition => {
1461 ActionType::SelectCommandAtScrollPosition(SelectCommandAtScrollPositionAction {})
1462 },
1463 crate::input::actions::Action::CopyLastCommandOutput => {
1464 ActionType::CopyLastCommandOutput(CopyLastCommandOutputAction {})
1465 },
1466 crate::input::actions::Action::PageScrollUp => {
1467 ActionType::PageScrollUp(PageScrollUpAction {})
1468 },
1469 crate::input::actions::Action::PageScrollDown => {
1470 ActionType::PageScrollDown(PageScrollDownAction {})
1471 },
1472 crate::input::actions::Action::HalfPageScrollUp => {
1473 ActionType::HalfPageScrollUp(HalfPageScrollUpAction {})
1474 },
1475 crate::input::actions::Action::HalfPageScrollDown => {
1476 ActionType::HalfPageScrollDown(HalfPageScrollDownAction {})
1477 },
1478 crate::input::actions::Action::ToggleFocusFullscreen => {
1479 ActionType::ToggleFocusFullscreen(ToggleFocusFullscreenAction {})
1480 },
1481 crate::input::actions::Action::ToggleFocusNoUiFullscreen => {
1482 ActionType::ToggleFocusNoUiFullscreen(ToggleFocusNoUiFullscreenAction {})
1483 },
1484 crate::input::actions::Action::TogglePaneFrames => {
1485 ActionType::TogglePaneFrames(TogglePaneFramesAction {})
1486 },
1487 crate::input::actions::Action::SetPaneFrameStyle(style) => {
1488 let style = match style {
1489 crate::input::options::PaneFrameStyle::Full => "full",
1490 crate::input::options::PaneFrameStyle::Titles => "titles",
1491 crate::input::options::PaneFrameStyle::None => "none",
1492 };
1493 ActionType::SetPaneFrameStyle(SetPaneFrameStyleAction {
1494 style: style.to_owned(),
1495 })
1496 },
1497 crate::input::actions::Action::ToggleActiveSyncTab => {
1498 ActionType::ToggleActiveSyncTab(ToggleActiveSyncTabAction {})
1499 },
1500 crate::input::actions::Action::NewPane {
1501 direction,
1502 pane_name,
1503 start_suppressed,
1504 } => ActionType::NewPane(NewPaneAction {
1505 direction: direction.map(|d| direction_to_proto_i32(d)),
1506 pane_name,
1507 start_suppressed,
1508 near_current_pane: false,
1509 }),
1510 crate::input::actions::Action::EditFile {
1511 payload,
1512 direction,
1513 floating,
1514 in_place,
1515 close_replaced_pane,
1516 start_suppressed,
1517 coordinates,
1518 near_current_pane,
1519 no_focus,
1520 tab_id,
1521 ..
1522 } => ActionType::EditFile(EditFileAction {
1523 payload: Some(payload.into()),
1524 direction: direction.map(|d| direction_to_proto_i32(d)),
1525 floating,
1526 in_place,
1527 close_replaced_pane,
1528 start_suppressed,
1529 coordinates: coordinates.map(|c| c.into()),
1530 near_current_pane,
1531 tab_id: tab_id.map(|t| t as u32),
1532 no_focus,
1533 }),
1534 crate::input::actions::Action::NewFloatingPane {
1535 command,
1536 pane_name,
1537 coordinates,
1538 near_current_pane,
1539 no_focus,
1540 tab_id,
1541 ..
1542 } => ActionType::NewFloatingPane(NewFloatingPaneAction {
1543 command: command.map(|c| c.into()),
1544 pane_name,
1545 coordinates: coordinates.map(|c| c.into()),
1546 near_current_pane,
1547 tab_id: tab_id.map(|t| t as u32),
1548 no_focus,
1549 }),
1550 crate::input::actions::Action::NewTiledPane {
1551 direction,
1552 command,
1553 pane_name,
1554 near_current_pane,
1555 no_focus,
1556 borderless,
1557 tab_id,
1558 ..
1559 } => ActionType::NewTiledPane(NewTiledPaneAction {
1560 direction: direction.map(|d| direction_to_proto_i32(d)),
1561 command: command.map(|c| c.into()),
1562 pane_name,
1563 near_current_pane,
1564 borderless,
1565 tab_id: tab_id.map(|t| t as u32),
1566 no_focus,
1567 }),
1568 crate::input::actions::Action::NewInPlacePane {
1569 command,
1570 pane_name,
1571 near_current_pane,
1572 no_focus,
1573 pane_id_to_replace,
1574 close_replaced_pane,
1575 tab_id,
1576 ..
1577 } => ActionType::NewInPlacePane(NewInPlacePaneAction {
1578 command: command.map(|c| c.into()),
1579 pane_name,
1580 near_current_pane,
1581 pane_id_to_replace: pane_id_to_replace.and_then(|p| p.try_into().ok()),
1582 close_replaced_pane,
1583 tab_id: tab_id.map(|t| t as u32),
1584 no_focus,
1585 }),
1586 crate::input::actions::Action::NewStackedPane {
1587 command,
1588 pane_name,
1589 near_current_pane,
1590 no_focus,
1591 tab_id,
1592 ..
1593 } => ActionType::NewStackedPane(NewStackedPaneAction {
1594 command: command.map(|c| c.into()),
1595 pane_name,
1596 near_current_pane,
1597 tab_id: tab_id.map(|t| t as u32),
1598 no_focus,
1599 }),
1600 crate::input::actions::Action::NewBlockingPane {
1601 placement,
1602 pane_name,
1603 command,
1604 unblock_condition,
1605 near_current_pane,
1606 no_focus,
1607 tab_id,
1608 ..
1609 } => ActionType::NewBlockingPane(NewBlockingPaneAction {
1610 placement: Some(placement.into()),
1611 pane_name,
1612 command: command.map(|c| c.into()),
1613 unblock_condition: unblock_condition.map(|c| unblock_condition_to_proto_i32(c)),
1614 near_current_pane,
1615 tab_id: tab_id.map(|t| t as u32),
1616 no_focus,
1617 }),
1618 crate::input::actions::Action::TogglePaneEmbedOrFloating => {
1619 ActionType::TogglePaneEmbedOrFloating(TogglePaneEmbedOrFloatingAction {})
1620 },
1621 crate::input::actions::Action::ToggleFloatingPanes => {
1622 ActionType::ToggleFloatingPanes(ToggleFloatingPanesAction {})
1623 },
1624 crate::input::actions::Action::ShowFloatingPanes { tab_id } => {
1625 ActionType::ShowFloatingPanes(ShowFloatingPanesAction {
1626 tab_id: tab_id.map(|id| id as u32),
1627 })
1628 },
1629 crate::input::actions::Action::HideFloatingPanes { tab_id } => {
1630 ActionType::HideFloatingPanes(HideFloatingPanesAction {
1631 tab_id: tab_id.map(|id| id as u32),
1632 })
1633 },
1634 crate::input::actions::Action::AreFloatingPanesVisible { tab_id } => {
1635 ActionType::AreFloatingPanesVisible(AreFloatingPanesVisibleAction {
1636 tab_id: tab_id.map(|id| id as u32),
1637 })
1638 },
1639 crate::input::actions::Action::CloseFocus => {
1640 ActionType::CloseFocus(CloseFocusAction {})
1641 },
1642 crate::input::actions::Action::PaneNameInput { input } => {
1643 ActionType::PaneNameInput(PaneNameInputAction {
1644 input: input.into_iter().map(|b| b as u32).collect(),
1645 })
1646 },
1647 crate::input::actions::Action::UndoRenamePane => {
1648 ActionType::UndoRenamePane(UndoRenamePaneAction {})
1649 },
1650 crate::input::actions::Action::NewTab {
1651 tiled_layout,
1652 floating_layouts,
1653 swap_tiled_layouts,
1654 swap_floating_layouts,
1655 tab_name,
1656 should_change_focus_to_new_tab,
1657 cwd,
1658 initial_panes,
1659 first_pane_unblock_condition,
1660 } => ActionType::NewTab(NewTabAction {
1661 tiled_layout: tiled_layout.map(|l| l.into()),
1662 floating_layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
1663 swap_tiled_layouts: swap_tiled_layouts
1664 .map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
1665 .unwrap_or_default(),
1666 swap_floating_layouts: swap_floating_layouts
1667 .map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
1668 .unwrap_or_default(),
1669 tab_name,
1670 should_change_focus_to_new_tab,
1671 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1672 initial_panes: initial_panes
1673 .map(|panes| panes.into_iter().map(|p| p.into()).collect())
1674 .unwrap_or_default(),
1675 first_pane_unblock_condition: first_pane_unblock_condition
1676 .map(|c| unblock_condition_to_proto_i32(c)),
1677 }),
1678 crate::input::actions::Action::NoOp => ActionType::NoOp(NoOpAction {}),
1679 crate::input::actions::Action::GoToNextTab => {
1680 ActionType::GoToNextTab(GoToNextTabAction {})
1681 },
1682 crate::input::actions::Action::GoToPreviousTab => {
1683 ActionType::GoToPreviousTab(GoToPreviousTabAction {})
1684 },
1685 crate::input::actions::Action::CloseTab => ActionType::CloseTab(CloseTabAction {}),
1686 crate::input::actions::Action::GoToTab { index } => {
1687 ActionType::GoToTab(GoToTabAction { index })
1688 },
1689 crate::input::actions::Action::GoToTabName { name, create } => {
1690 ActionType::GoToTabName(GoToTabNameAction { name, create })
1691 },
1692 crate::input::actions::Action::ToggleTab => ActionType::ToggleTab(ToggleTabAction {}),
1693 crate::input::actions::Action::TabNameInput { input } => {
1694 ActionType::TabNameInput(TabNameInputAction {
1695 input: input.into_iter().map(|b| b as u32).collect(),
1696 })
1697 },
1698 crate::input::actions::Action::UndoRenameTab => {
1699 ActionType::UndoRenameTab(UndoRenameTabAction {})
1700 },
1701 crate::input::actions::Action::MoveTab { direction } => {
1702 ActionType::MoveTab(MoveTabAction {
1703 direction: direction_to_proto_i32(direction),
1704 })
1705 },
1706 crate::input::actions::Action::Run {
1707 command,
1708 near_current_pane,
1709 no_focus,
1710 } => ActionType::Run(RunAction {
1711 command: Some(command.into()),
1712 near_current_pane,
1713 no_focus,
1714 }),
1715 crate::input::actions::Action::Detach => ActionType::Detach(DetachAction {}),
1716 crate::input::actions::Action::SetDarkTheme => {
1717 ActionType::SetDarkTheme(SetDarkThemeAction {})
1718 },
1719 crate::input::actions::Action::SetLightTheme => {
1720 ActionType::SetLightTheme(SetLightThemeAction {})
1721 },
1722 crate::input::actions::Action::ToggleTheme => {
1723 ActionType::ToggleTheme(ToggleThemeAction {})
1724 },
1725 crate::input::actions::Action::SwitchSession {
1726 name,
1727 tab_position,
1728 pane_id,
1729 layout,
1730 cwd,
1731 } => ActionType::SwitchSession(SwitchSessionAction {
1732 name: name.clone(),
1733 tab_position: tab_position.map(|p| p as u32),
1734 pane_id: pane_id.map(|(id, is_plugin)| PaneIdWithPlugin {
1735 pane_id: id,
1736 is_plugin: is_plugin,
1737 }),
1738 layout: layout.as_ref().map(|l| l.clone().into()),
1739 cwd: cwd.as_ref().map(|p| p.to_string_lossy().to_string()),
1740 }),
1741 crate::input::actions::Action::LaunchOrFocusPlugin {
1742 plugin,
1743 should_float,
1744 move_to_focused_tab,
1745 should_open_in_place,
1746 close_replaced_pane,
1747 skip_cache,
1748 tab_id,
1749 ..
1750 } => ActionType::LaunchOrFocusPlugin(LaunchOrFocusPluginAction {
1751 plugin: Some(plugin.into()),
1752 should_float,
1753 move_to_focused_tab,
1754 should_open_in_place,
1755 close_replaced_pane,
1756 skip_cache,
1757 tab_id: tab_id.map(|t| t as u32),
1758 }),
1759 crate::input::actions::Action::LaunchPlugin {
1760 plugin,
1761 should_float,
1762 should_open_in_place,
1763 close_replaced_pane,
1764 skip_cache,
1765 cwd,
1766 no_focus,
1767 tab_id,
1768 ..
1769 } => ActionType::LaunchPlugin(LaunchPluginAction {
1770 plugin: Some(plugin.into()),
1771 should_float,
1772 should_open_in_place,
1773 close_replaced_pane,
1774 skip_cache,
1775 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1776 tab_id: tab_id.map(|t| t as u32),
1777 no_focus,
1778 }),
1779 crate::input::actions::Action::MouseEvent { event } => {
1780 ActionType::MouseEvent(MouseEventAction {
1781 event: Some(event.into()),
1782 })
1783 },
1784 crate::input::actions::Action::Copy => ActionType::Copy(CopyAction {}),
1785 crate::input::actions::Action::Confirm => ActionType::Confirm(ConfirmAction {}),
1786 crate::input::actions::Action::Deny => ActionType::Deny(DenyAction {}),
1787 crate::input::actions::Action::SkipConfirm { action } => {
1788 ActionType::SkipConfirm(Box::new(SkipConfirmAction {
1789 action: Some(Box::new((*action).into())),
1790 }))
1791 },
1792 crate::input::actions::Action::SearchInput { input } => {
1793 ActionType::SearchInput(SearchInputAction {
1794 input: input.into_iter().map(|b| b as u32).collect(),
1795 })
1796 },
1797 crate::input::actions::Action::Search { direction } => {
1798 ActionType::Search(SearchAction {
1799 direction: search_direction_to_proto_i32(direction),
1800 })
1801 },
1802 crate::input::actions::Action::SearchToggleOption { option } => {
1803 ActionType::SearchToggleOption(SearchToggleOptionAction {
1804 option: search_option_to_proto_i32(option),
1805 })
1806 },
1807 crate::input::actions::Action::ToggleMouseMode => {
1808 ActionType::ToggleMouseMode(ToggleMouseModeAction {})
1809 },
1810 crate::input::actions::Action::PreviousSwapLayout => {
1811 ActionType::PreviousSwapLayout(PreviousSwapLayoutAction {})
1812 },
1813 crate::input::actions::Action::NextSwapLayout => {
1814 ActionType::NextSwapLayout(NextSwapLayoutAction {})
1815 },
1816 crate::input::actions::Action::OverrideLayout {
1817 tabs,
1818 retain_existing_terminal_panes,
1819 retain_existing_plugin_panes,
1820 apply_only_to_active_tab,
1821 } => ActionType::OverrideLayout(OverrideLayoutAction {
1822 tabs: tabs.into_iter().map(|t| t.into()).collect(),
1823 retain_existing_terminal_panes,
1824 retain_existing_plugin_panes,
1825 apply_only_to_active_tab,
1826 }),
1827 crate::input::actions::Action::QueryTabNames => {
1828 ActionType::QueryTabNames(QueryTabNamesAction {})
1829 },
1830 crate::input::actions::Action::NewTiledPluginPane {
1831 plugin,
1832 pane_name,
1833 skip_cache,
1834 cwd,
1835 no_focus,
1836 tab_id,
1837 ..
1838 } => ActionType::NewTiledPluginPane(NewTiledPluginPaneAction {
1839 plugin: Some(plugin.into()),
1840 pane_name,
1841 skip_cache,
1842 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1843 tab_id: tab_id.map(|t| t as u32),
1844 no_focus,
1845 }),
1846 crate::input::actions::Action::NewFloatingPluginPane {
1847 plugin,
1848 pane_name,
1849 skip_cache,
1850 cwd,
1851 coordinates,
1852 no_focus,
1853 tab_id,
1854 ..
1855 } => ActionType::NewFloatingPluginPane(NewFloatingPluginPaneAction {
1856 plugin: Some(plugin.into()),
1857 pane_name,
1858 skip_cache,
1859 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1860 coordinates: coordinates.map(|c| c.into()),
1861 tab_id: tab_id.map(|t| t as u32),
1862 no_focus,
1863 }),
1864 crate::input::actions::Action::NewInPlacePluginPane {
1865 plugin,
1866 pane_name,
1867 skip_cache,
1868 close_replaced_pane,
1869 no_focus,
1870 tab_id,
1871 ..
1872 } => ActionType::NewInPlacePluginPane(NewInPlacePluginPaneAction {
1873 plugin: Some(plugin.into()),
1874 pane_name,
1875 skip_cache,
1876 close_replaced_pane,
1877 tab_id: tab_id.map(|t| t as u32),
1878 no_focus,
1879 }),
1880 crate::input::actions::Action::StartOrReloadPlugin { plugin } => {
1881 ActionType::StartOrReloadPlugin(StartOrReloadPluginAction {
1882 plugin: Some(plugin.into()),
1883 })
1884 },
1885 crate::input::actions::Action::CloseTerminalPane { pane_id } => {
1886 ActionType::CloseTerminalPane(CloseTerminalPaneAction { pane_id })
1887 },
1888 crate::input::actions::Action::ClosePluginPane { pane_id } => {
1889 ActionType::ClosePluginPane(ClosePluginPaneAction { pane_id })
1890 },
1891 crate::input::actions::Action::FocusTerminalPaneWithId {
1892 pane_id,
1893 should_float_if_hidden,
1894 should_be_in_place_if_hidden,
1895 } => ActionType::FocusTerminalPaneWithId(FocusTerminalPaneWithIdAction {
1896 pane_id,
1897 should_float_if_hidden,
1898 should_be_in_place_if_hidden,
1899 }),
1900 crate::input::actions::Action::FocusPluginPaneWithId {
1901 pane_id,
1902 should_float_if_hidden,
1903 should_be_in_place_if_hidden,
1904 } => ActionType::FocusPluginPaneWithId(FocusPluginPaneWithIdAction {
1905 pane_id,
1906 should_float_if_hidden,
1907 should_be_in_place_if_hidden,
1908 }),
1909 crate::input::actions::Action::RenameTerminalPane { pane_id, name } => {
1910 ActionType::RenameTerminalPane(RenameTerminalPaneAction {
1911 pane_id,
1912 name: name.into_iter().map(|b| b as u32).collect(),
1913 })
1914 },
1915 crate::input::actions::Action::RenamePluginPane { pane_id, name } => {
1916 ActionType::RenamePluginPane(RenamePluginPaneAction {
1917 pane_id,
1918 name: name.into_iter().map(|b| b as u32).collect(),
1919 })
1920 },
1921 crate::input::actions::Action::RenameTab { tab_index, name } => {
1922 ActionType::RenameTab(RenameTabAction {
1923 tab_index,
1924 name: name.into_iter().map(|b| b as u32).collect(),
1925 })
1926 },
1927 crate::input::actions::Action::GoToTabById { id } => {
1928 ActionType::GoToTabById(GoToTabByIdAction { id })
1929 },
1930 crate::input::actions::Action::CloseTabById { id } => {
1931 ActionType::CloseTabById(CloseTabByIdAction { id })
1932 },
1933 crate::input::actions::Action::RenameTabById { id, name } => {
1934 ActionType::RenameTabById(RenameTabByIdAction { id, name })
1935 },
1936 crate::input::actions::Action::BreakPane => ActionType::BreakPane(BreakPaneAction {}),
1937 crate::input::actions::Action::BreakPaneRight => {
1938 ActionType::BreakPaneRight(BreakPaneRightAction {})
1939 },
1940 crate::input::actions::Action::BreakPaneLeft => {
1941 ActionType::BreakPaneLeft(BreakPaneLeftAction {})
1942 },
1943 crate::input::actions::Action::RenameSession { name } => {
1944 ActionType::RenameSession(RenameSessionAction { name })
1945 },
1946 crate::input::actions::Action::CliPipe {
1947 pipe_id,
1948 name,
1949 payload,
1950 args,
1951 plugin,
1952 configuration,
1953 launch_new,
1954 skip_cache,
1955 floating,
1956 in_place,
1957 cwd,
1958 pane_title,
1959 } => ActionType::CliPipe(CliPipeAction {
1960 pipe_id,
1961 name,
1962 payload,
1963 args: args
1964 .map(|a| a.into_iter().collect::<HashMap<_, _>>())
1965 .unwrap_or_default(),
1966 plugin,
1967 configuration: configuration
1968 .map(|c| c.into_iter().collect::<HashMap<_, _>>())
1969 .unwrap_or_default(),
1970 launch_new,
1971 skip_cache,
1972 floating,
1973 in_place,
1974 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
1975 pane_title,
1976 }),
1977 crate::input::actions::Action::KeybindPipe {
1978 name,
1979 payload,
1980 args,
1981 plugin,
1982 plugin_id,
1983 configuration,
1984 launch_new,
1985 skip_cache,
1986 floating,
1987 in_place,
1988 cwd,
1989 pane_title,
1990 } => ActionType::KeybindPipe(KeybindPipeAction {
1991 name,
1992 payload,
1993 args: args
1994 .map(|a| a.into_iter().collect::<HashMap<_, _>>())
1995 .unwrap_or_default(),
1996 plugin,
1997 plugin_id,
1998 configuration: configuration
1999 .map(|c| c.into_iter().collect::<HashMap<_, _>>())
2000 .unwrap_or_default(),
2001 launch_new,
2002 skip_cache,
2003 floating,
2004 in_place,
2005 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
2006 pane_title,
2007 }),
2008 crate::input::actions::Action::ListClients => {
2009 ActionType::ListClients(ListClientsAction {})
2010 },
2011 crate::input::actions::Action::ListPanes {
2012 show_tab,
2013 show_command,
2014 show_state,
2015 show_geometry,
2016 show_all,
2017 output_json,
2018 } => ActionType::ListPanes(ListPanesAction {
2019 show_tab,
2020 show_command,
2021 show_state,
2022 show_geometry,
2023 show_all,
2024 output_json,
2025 }),
2026 crate::input::actions::Action::TogglePanePinned => {
2027 ActionType::TogglePanePinned(TogglePanePinnedAction {})
2028 },
2029 crate::input::actions::Action::StackPanes { pane_ids } => {
2030 ActionType::StackPanes(StackPanesAction {
2031 pane_ids: pane_ids.into_iter().map(|id| id.into()).collect(),
2032 })
2033 },
2034 crate::input::actions::Action::ChangeFloatingPaneCoordinates {
2035 pane_id,
2036 coordinates,
2037 } => ActionType::ChangeFloatingPaneCoordinates(ChangeFloatingPaneCoordinatesAction {
2038 pane_id: Some(pane_id.into()),
2039 coordinates: Some(coordinates.into()),
2040 }),
2041 crate::input::actions::Action::TogglePaneBorderless { pane_id } => {
2042 ActionType::TogglePaneBorderless(TogglePaneBorderlessAction {
2043 pane_id: Some(pane_id.into()),
2044 })
2045 },
2046 crate::input::actions::Action::SetPaneBorderless {
2047 pane_id,
2048 borderless,
2049 } => ActionType::SetPaneBorderless(SetPaneBorderlessAction {
2050 pane_id: Some(pane_id.into()),
2051 borderless,
2052 }),
2053 crate::input::actions::Action::TogglePaneInGroup => {
2054 ActionType::TogglePaneInGroup(TogglePaneInGroupAction {})
2055 },
2056 crate::input::actions::Action::ToggleGroupMarking => {
2057 ActionType::ToggleGroupMarking(ToggleGroupMarkingAction {})
2058 },
2059 crate::input::actions::Action::SaveSession => {
2060 ActionType::SaveSession(SaveSessionAction {})
2061 },
2062 crate::input::actions::Action::ListTabs {
2063 show_state,
2064 show_dimensions,
2065 show_panes,
2066 show_layout,
2067 show_all,
2068 output_json,
2069 } => ActionType::ListTabs(ListTabsAction {
2070 show_state,
2071 show_dimensions,
2072 show_panes,
2073 show_layout,
2074 show_all,
2075 output_json,
2076 }),
2077 crate::input::actions::Action::CurrentTabInfo { output_json } => {
2078 ActionType::CurrentTabInfo(CurrentTabInfoAction { output_json })
2079 },
2080 crate::input::actions::Action::SetPaneColor { pane_id, fg, bg } => {
2081 ActionType::SetPaneColor(SetPaneColorAction {
2082 pane_id: Some(pane_id.into()),
2083 fg,
2084 bg,
2085 })
2086 },
2087 crate::input::actions::Action::ScrollUpByPaneId { pane_id } => {
2089 ActionType::ScrollUpByPaneId(ScrollUpByPaneIdAction {
2090 pane_id: Some(pane_id.into()),
2091 })
2092 },
2093 crate::input::actions::Action::ScrollDownByPaneId { pane_id } => {
2094 ActionType::ScrollDownByPaneId(ScrollDownByPaneIdAction {
2095 pane_id: Some(pane_id.into()),
2096 })
2097 },
2098 crate::input::actions::Action::ScrollToTopByPaneId { pane_id } => {
2099 ActionType::ScrollToTopByPaneId(ScrollToTopByPaneIdAction {
2100 pane_id: Some(pane_id.into()),
2101 })
2102 },
2103 crate::input::actions::Action::ScrollToBottomByPaneId { pane_id } => {
2104 ActionType::ScrollToBottomByPaneId(ScrollToBottomByPaneIdAction {
2105 pane_id: Some(pane_id.into()),
2106 })
2107 },
2108 crate::input::actions::Action::PageScrollUpByPaneId { pane_id } => {
2109 ActionType::PageScrollUpByPaneId(PageScrollUpByPaneIdAction {
2110 pane_id: Some(pane_id.into()),
2111 })
2112 },
2113 crate::input::actions::Action::PageScrollDownByPaneId { pane_id } => {
2114 ActionType::PageScrollDownByPaneId(PageScrollDownByPaneIdAction {
2115 pane_id: Some(pane_id.into()),
2116 })
2117 },
2118 crate::input::actions::Action::HalfPageScrollUpByPaneId { pane_id } => {
2119 ActionType::HalfPageScrollUpByPaneId(HalfPageScrollUpByPaneIdAction {
2120 pane_id: Some(pane_id.into()),
2121 })
2122 },
2123 crate::input::actions::Action::HalfPageScrollDownByPaneId { pane_id } => {
2124 ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
2125 pane_id: Some(pane_id.into()),
2126 })
2127 },
2128 crate::input::actions::Action::ResizeByPaneId {
2129 pane_id,
2130 resize,
2131 direction,
2132 } => ActionType::ResizeByPaneId(ResizeByPaneIdAction {
2133 pane_id: Some(pane_id.into()),
2134 resize_action: Some(ResizeAction {
2135 resize: resize_to_proto_i32(resize),
2136 direction: direction.map(|d| direction_to_proto_i32(d)),
2137 }),
2138 }),
2139 crate::input::actions::Action::MovePaneByPaneId { pane_id, direction } => {
2140 ActionType::MovePaneByPaneId(MovePaneByPaneIdAction {
2141 pane_id: Some(pane_id.into()),
2142 direction: direction.map(|d| direction_to_proto_i32(d)),
2143 })
2144 },
2145 crate::input::actions::Action::MovePaneBackwardsByPaneId { pane_id } => {
2146 ActionType::MovePaneBackwardsByPaneId(MovePaneBackwardsByPaneIdAction {
2147 pane_id: Some(pane_id.into()),
2148 })
2149 },
2150 crate::input::actions::Action::ClearScreenByPaneId { pane_id } => {
2151 ActionType::ClearScreenByPaneId(ClearScreenByPaneIdAction {
2152 pane_id: Some(pane_id.into()),
2153 })
2154 },
2155 crate::input::actions::Action::EditScrollbackByPaneId { pane_id, ansi } => {
2156 ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
2157 pane_id: Some(pane_id.into()),
2158 ansi,
2159 })
2160 },
2161 crate::input::actions::Action::ToggleFocusFullscreenByPaneId { pane_id } => {
2162 ActionType::ToggleFullscreenByPaneId(ToggleFullscreenByPaneIdAction {
2163 pane_id: Some(pane_id.into()),
2164 })
2165 },
2166 crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId { pane_id } => {
2167 ActionType::ToggleNoUiFullscreenByPaneId(ToggleNoUiFullscreenByPaneIdAction {
2168 pane_id: Some(pane_id.into()),
2169 })
2170 },
2171 crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
2172 ActionType::TogglePaneEmbedOrFloatingByPaneId(
2173 TogglePaneEmbedOrFloatingByPaneIdAction {
2174 pane_id: Some(pane_id.into()),
2175 },
2176 )
2177 },
2178 crate::input::actions::Action::CloseFocusByPaneId { pane_id } => {
2179 ActionType::CloseFocusByPaneId(CloseFocusByPaneIdAction {
2180 pane_id: Some(pane_id.into()),
2181 })
2182 },
2183 crate::input::actions::Action::RenamePaneByPaneId { pane_id, name } => {
2184 ActionType::RenamePaneByPaneId(RenamePaneByPaneIdAction {
2185 pane_id: pane_id.map(|id| id.into()),
2186 name,
2187 })
2188 },
2189 crate::input::actions::Action::UndoRenamePaneByPaneId { pane_id } => {
2190 ActionType::UndoRenamePaneByPaneId(UndoRenamePaneByPaneIdAction {
2191 pane_id: Some(pane_id.into()),
2192 })
2193 },
2194 crate::input::actions::Action::TogglePanePinnedByPaneId { pane_id } => {
2195 ActionType::TogglePanePinnedByPaneId(TogglePanePinnedByPaneIdAction {
2196 pane_id: Some(pane_id.into()),
2197 })
2198 },
2199 crate::input::actions::Action::FocusPaneByPaneId { pane_id } => {
2200 ActionType::FocusPaneByPaneId(FocusPaneByPaneIdAction {
2201 pane_id: Some(pane_id.into()),
2202 })
2203 },
2204 crate::input::actions::Action::UndoRenameTabByTabId { id } => {
2206 ActionType::UndoRenameTabByTabId(UndoRenameTabByTabIdAction { id })
2207 },
2208 crate::input::actions::Action::ToggleActiveSyncTabByTabId { id } => {
2209 ActionType::ToggleActiveSyncTabByTabId(ToggleActiveSyncTabByTabIdAction { id })
2210 },
2211 crate::input::actions::Action::ToggleFloatingPanesByTabId { id } => {
2212 ActionType::ToggleFloatingPanesByTabId(ToggleFloatingPanesByTabIdAction { id })
2213 },
2214 crate::input::actions::Action::PreviousSwapLayoutByTabId { id } => {
2215 ActionType::PreviousSwapLayoutByTabId(PreviousSwapLayoutByTabIdAction { id })
2216 },
2217 crate::input::actions::Action::NextSwapLayoutByTabId { id } => {
2218 ActionType::NextSwapLayoutByTabId(NextSwapLayoutByTabIdAction { id })
2219 },
2220 crate::input::actions::Action::MoveTabByTabId { id, direction } => {
2221 ActionType::MoveTabByTabId(MoveTabByTabIdAction {
2222 id,
2223 direction: direction_to_proto_i32(direction),
2224 })
2225 },
2226 };
2227
2228 Self {
2229 action_type: Some(action_type),
2230 }
2231 }
2232}
2233
2234impl TryFrom<crate::client_server_contract::client_server_contract::Action>
2235 for crate::input::actions::Action
2236{
2237 type Error = anyhow::Error;
2238 fn try_from(
2239 action: crate::client_server_contract::client_server_contract::Action,
2240 ) -> Result<Self> {
2241 use crate::client_server_contract::client_server_contract::action::ActionType;
2242
2243 let action_type = action
2244 .action_type
2245 .ok_or_else(|| anyhow!("Action missing action_type"))?;
2246
2247 match action_type {
2248 ActionType::Quit(_) => Ok(crate::input::actions::Action::Quit),
2249 ActionType::Write(write_action) => Ok(crate::input::actions::Action::Write {
2250 key_with_modifier: write_action
2251 .key_with_modifier
2252 .map(|k| k.try_into())
2253 .transpose()?,
2254 bytes: write_action.bytes.into_iter().map(|b| b as u8).collect(),
2255 is_kitty_keyboard_protocol: write_action.is_kitty_keyboard_protocol,
2256 }),
2257 ActionType::WriteChars(write_chars_action) => {
2258 Ok(crate::input::actions::Action::WriteChars {
2259 chars: write_chars_action.chars,
2260 })
2261 },
2262 ActionType::WriteToPaneId(write_to_pane_id_action) => {
2263 Ok(crate::input::actions::Action::WriteToPaneId {
2264 bytes: write_to_pane_id_action
2265 .bytes
2266 .into_iter()
2267 .map(|b| b as u8)
2268 .collect(),
2269 pane_id: write_to_pane_id_action
2270 .pane_id
2271 .ok_or_else(|| anyhow!("WriteToPaneId missing pane_id"))?
2272 .try_into()?,
2273 })
2274 },
2275 ActionType::WriteCharsToPaneId(write_chars_to_pane_id_action) => {
2276 Ok(crate::input::actions::Action::WriteCharsToPaneId {
2277 chars: write_chars_to_pane_id_action.chars,
2278 pane_id: write_chars_to_pane_id_action
2279 .pane_id
2280 .ok_or_else(|| anyhow!("WriteCharsToPaneId missing pane_id"))?
2281 .try_into()?,
2282 })
2283 },
2284 ActionType::Paste(paste_action) => Ok(crate::input::actions::Action::Paste {
2285 chars: paste_action.chars,
2286 pane_id: paste_action.pane_id.map(|p| p.try_into()).transpose()?,
2287 }),
2288 ActionType::SwitchToMode(switch_mode_action) => {
2289 Ok(crate::input::actions::Action::SwitchToMode {
2290 input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
2291 })
2292 },
2293 ActionType::SwitchModeForAllClients(switch_mode_action) => {
2294 Ok(crate::input::actions::Action::SwitchModeForAllClients {
2295 input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
2296 })
2297 },
2298 ActionType::Resize(resize_action) => Ok(crate::input::actions::Action::Resize {
2299 resize: proto_i32_to_resize(resize_action.resize)?,
2300 direction: resize_action
2301 .direction
2302 .map(|d| proto_i32_to_direction(d))
2303 .transpose()?,
2304 }),
2305 ActionType::FocusNextPane(_) => Ok(crate::input::actions::Action::FocusNextPane),
2306 ActionType::FocusPreviousPane(_) => {
2307 Ok(crate::input::actions::Action::FocusPreviousPane)
2308 },
2309 ActionType::FocusLastPane(_) => Ok(crate::input::actions::Action::FocusLastPane),
2310 ActionType::SwitchFocus(_) => Ok(crate::input::actions::Action::SwitchFocus),
2311 ActionType::MoveFocus(move_focus_action) => {
2312 Ok(crate::input::actions::Action::MoveFocus {
2313 direction: proto_i32_to_direction(move_focus_action.direction)?,
2314 })
2315 },
2316 ActionType::MoveFocusOrTab(move_focus_action) => {
2317 Ok(crate::input::actions::Action::MoveFocusOrTab {
2318 direction: proto_i32_to_direction(move_focus_action.direction)?,
2319 })
2320 },
2321 ActionType::MovePane(move_pane_action) => Ok(crate::input::actions::Action::MovePane {
2322 direction: move_pane_action
2323 .direction
2324 .map(|d| proto_i32_to_direction(d))
2325 .transpose()?,
2326 }),
2327 ActionType::MovePaneBackwards(_) => {
2328 Ok(crate::input::actions::Action::MovePaneBackwards)
2329 },
2330 ActionType::ClearScreen(_) => Ok(crate::input::actions::Action::ClearScreen),
2331 ActionType::DumpScreen(dump_screen_action) => {
2332 let file_path = if dump_screen_action.dump_to_stdout {
2333 None
2334 } else {
2335 Some(dump_screen_action.file_path)
2336 };
2337 Ok(crate::input::actions::Action::DumpScreen {
2338 file_path,
2339 include_scrollback: dump_screen_action.include_scrollback,
2340 pane_id: dump_screen_action.pane_id.and_then(|p| p.try_into().ok()),
2341 ansi: dump_screen_action.ansi,
2342 })
2343 },
2344 ActionType::DumpLayout(_) => Ok(crate::input::actions::Action::DumpLayout),
2345 ActionType::SaveSession(_) => Ok(crate::input::actions::Action::SaveSession),
2346 ActionType::EditScrollback(edit_scrollback_action) => {
2347 Ok(crate::input::actions::Action::EditScrollback {
2348 ansi: edit_scrollback_action.ansi,
2349 })
2350 },
2351 ActionType::ScrollUp(_) => Ok(crate::input::actions::Action::ScrollUp),
2352 ActionType::ScrollToPreviousPrompt(_) => {
2353 Ok(crate::input::actions::Action::ScrollToPreviousPrompt)
2354 },
2355 ActionType::ScrollToNextPrompt(_) => {
2356 Ok(crate::input::actions::Action::ScrollToNextPrompt)
2357 },
2358 ActionType::SelectCommandAtScrollPosition(_) => {
2359 Ok(crate::input::actions::Action::SelectCommandAtScrollPosition)
2360 },
2361 ActionType::CopyLastCommandOutput(_) => {
2362 Ok(crate::input::actions::Action::CopyLastCommandOutput)
2363 },
2364 ActionType::ScrollUpAt(scroll_action) => {
2365 Ok(crate::input::actions::Action::ScrollUpAt {
2366 position: scroll_action
2367 .position
2368 .ok_or_else(|| anyhow!("ScrollUpAt missing position"))?
2369 .try_into()?,
2370 })
2371 },
2372 ActionType::ScrollDown(_) => Ok(crate::input::actions::Action::ScrollDown),
2373 ActionType::ScrollDownAt(scroll_action) => {
2374 Ok(crate::input::actions::Action::ScrollDownAt {
2375 position: scroll_action
2376 .position
2377 .ok_or_else(|| anyhow!("ScrollDownAt missing position"))?
2378 .try_into()?,
2379 })
2380 },
2381 ActionType::ScrollToBottom(_) => Ok(crate::input::actions::Action::ScrollToBottom),
2382 ActionType::ScrollToTop(_) => Ok(crate::input::actions::Action::ScrollToTop),
2383 ActionType::PageScrollUp(_) => Ok(crate::input::actions::Action::PageScrollUp),
2384 ActionType::PageScrollDown(_) => Ok(crate::input::actions::Action::PageScrollDown),
2385 ActionType::HalfPageScrollUp(_) => Ok(crate::input::actions::Action::HalfPageScrollUp),
2386 ActionType::HalfPageScrollDown(_) => {
2387 Ok(crate::input::actions::Action::HalfPageScrollDown)
2388 },
2389 ActionType::ToggleFocusFullscreen(_) => {
2390 Ok(crate::input::actions::Action::ToggleFocusFullscreen)
2391 },
2392 ActionType::ToggleFocusNoUiFullscreen(_) => {
2393 Ok(crate::input::actions::Action::ToggleFocusNoUiFullscreen)
2394 },
2395 ActionType::TogglePaneFrames(_) => Ok(crate::input::actions::Action::TogglePaneFrames),
2396 ActionType::SetPaneFrameStyle(set_pane_frame_style_action) => {
2397 let style = crate::input::options::PaneFrameStyle::from_str(
2398 &set_pane_frame_style_action.style,
2399 )
2400 .map_err(|e| anyhow!("{}", e))?;
2401 Ok(crate::input::actions::Action::SetPaneFrameStyle(style))
2402 },
2403 ActionType::ToggleActiveSyncTab(_) => {
2404 Ok(crate::input::actions::Action::ToggleActiveSyncTab)
2405 },
2406 ActionType::NewPane(new_pane_action) => Ok(crate::input::actions::Action::NewPane {
2407 direction: new_pane_action
2408 .direction
2409 .map(|d| proto_i32_to_direction(d))
2410 .transpose()?,
2411 pane_name: new_pane_action.pane_name,
2412 start_suppressed: new_pane_action.start_suppressed,
2413 }),
2414 ActionType::EditFile(edit_file_action) => Ok(crate::input::actions::Action::EditFile {
2415 payload: edit_file_action
2416 .payload
2417 .ok_or_else(|| anyhow!("EditFile missing payload"))?
2418 .try_into()?,
2419 direction: edit_file_action
2420 .direction
2421 .map(|d| proto_i32_to_direction(d))
2422 .transpose()?,
2423 floating: edit_file_action.floating,
2424 in_place: edit_file_action.in_place,
2425 close_replaced_pane: edit_file_action.close_replaced_pane,
2426 start_suppressed: edit_file_action.start_suppressed,
2427 coordinates: edit_file_action
2428 .coordinates
2429 .map(|c| c.try_into())
2430 .transpose()?,
2431 near_current_pane: edit_file_action.near_current_pane,
2432 no_focus: edit_file_action.no_focus,
2433 tab_id: edit_file_action.tab_id.map(|t| t as usize),
2434 }),
2435 ActionType::NewFloatingPane(new_floating_action) => {
2436 Ok(crate::input::actions::Action::NewFloatingPane {
2437 command: new_floating_action
2438 .command
2439 .map(|c| c.try_into())
2440 .transpose()?,
2441 pane_name: new_floating_action.pane_name,
2442 coordinates: new_floating_action
2443 .coordinates
2444 .map(|c| c.try_into())
2445 .transpose()?,
2446 near_current_pane: new_floating_action.near_current_pane,
2447 no_focus: new_floating_action.no_focus,
2448 tab_id: new_floating_action.tab_id.map(|t| t as usize),
2449 })
2450 },
2451 ActionType::NewTiledPane(new_tiled_action) => {
2452 Ok(crate::input::actions::Action::NewTiledPane {
2453 direction: new_tiled_action
2454 .direction
2455 .map(|d| proto_i32_to_direction(d))
2456 .transpose()?,
2457 command: new_tiled_action.command.map(|c| c.try_into()).transpose()?,
2458 pane_name: new_tiled_action.pane_name,
2459 near_current_pane: new_tiled_action.near_current_pane,
2460 no_focus: new_tiled_action.no_focus,
2461 borderless: new_tiled_action.borderless,
2462 tab_id: new_tiled_action.tab_id.map(|t| t as usize),
2463 })
2464 },
2465 ActionType::NewInPlacePane(new_in_place_action) => {
2466 Ok(crate::input::actions::Action::NewInPlacePane {
2467 command: new_in_place_action
2468 .command
2469 .map(|c| c.try_into())
2470 .transpose()?,
2471 pane_name: new_in_place_action.pane_name,
2472 near_current_pane: new_in_place_action.near_current_pane,
2473 no_focus: new_in_place_action.no_focus,
2474 pane_id_to_replace: new_in_place_action
2475 .pane_id_to_replace
2476 .and_then(|p| p.try_into().ok()),
2477 close_replaced_pane: new_in_place_action.close_replaced_pane,
2478 tab_id: new_in_place_action.tab_id.map(|t| t as usize),
2479 })
2480 },
2481 ActionType::NewStackedPane(new_stacked_action) => {
2482 Ok(crate::input::actions::Action::NewStackedPane {
2483 command: new_stacked_action
2484 .command
2485 .map(|c| c.try_into())
2486 .transpose()?,
2487 pane_name: new_stacked_action.pane_name,
2488 near_current_pane: new_stacked_action.near_current_pane,
2489 no_focus: new_stacked_action.no_focus,
2490 tab_id: new_stacked_action.tab_id.map(|t| t as usize),
2491 })
2492 },
2493 ActionType::NewBlockingPane(new_blocking_action) => {
2494 Ok(crate::input::actions::Action::NewBlockingPane {
2495 placement: new_blocking_action
2496 .placement
2497 .ok_or_else(|| anyhow!("NewBlockingPane missing placement"))?
2498 .try_into()?,
2499 pane_name: new_blocking_action.pane_name,
2500 command: new_blocking_action
2501 .command
2502 .map(|c| c.try_into())
2503 .transpose()?,
2504 unblock_condition: new_blocking_action
2505 .unblock_condition
2506 .map(|c| proto_i32_to_unblock_condition(c))
2507 .transpose()?,
2508 near_current_pane: new_blocking_action.near_current_pane,
2509 no_focus: new_blocking_action.no_focus,
2510 tab_id: new_blocking_action.tab_id.map(|t| t as usize),
2511 })
2512 },
2513 ActionType::TogglePaneEmbedOrFloating(_) => {
2514 Ok(crate::input::actions::Action::TogglePaneEmbedOrFloating)
2515 },
2516 ActionType::ToggleFloatingPanes(_) => {
2517 Ok(crate::input::actions::Action::ToggleFloatingPanes)
2518 },
2519 ActionType::ShowFloatingPanes(a) => {
2520 Ok(crate::input::actions::Action::ShowFloatingPanes {
2521 tab_id: a.tab_id.map(|id| id as usize),
2522 })
2523 },
2524 ActionType::HideFloatingPanes(a) => {
2525 Ok(crate::input::actions::Action::HideFloatingPanes {
2526 tab_id: a.tab_id.map(|id| id as usize),
2527 })
2528 },
2529 ActionType::AreFloatingPanesVisible(a) => {
2530 Ok(crate::input::actions::Action::AreFloatingPanesVisible {
2531 tab_id: a.tab_id.map(|id| id as usize),
2532 })
2533 },
2534 ActionType::CloseFocus(_) => Ok(crate::input::actions::Action::CloseFocus),
2535 ActionType::PaneNameInput(pane_name_action) => {
2536 Ok(crate::input::actions::Action::PaneNameInput {
2537 input: pane_name_action
2538 .input
2539 .into_iter()
2540 .map(|b| b as u8)
2541 .collect(),
2542 })
2543 },
2544 ActionType::UndoRenamePane(_) => Ok(crate::input::actions::Action::UndoRenamePane),
2545 ActionType::NewTab(new_tab_action) => Ok(crate::input::actions::Action::NewTab {
2546 tiled_layout: new_tab_action
2547 .tiled_layout
2548 .map(|l| l.try_into())
2549 .transpose()?,
2550 floating_layouts: new_tab_action
2551 .floating_layouts
2552 .into_iter()
2553 .map(|l| l.try_into())
2554 .collect::<Result<Vec<_>>>()?,
2555 swap_tiled_layouts: if new_tab_action.swap_tiled_layouts.is_empty() {
2556 None
2557 } else {
2558 Some(
2559 new_tab_action
2560 .swap_tiled_layouts
2561 .into_iter()
2562 .map(|l| l.try_into())
2563 .collect::<Result<Vec<_>>>()?,
2564 )
2565 },
2566 swap_floating_layouts: if new_tab_action.swap_floating_layouts.is_empty() {
2567 None
2568 } else {
2569 Some(
2570 new_tab_action
2571 .swap_floating_layouts
2572 .into_iter()
2573 .map(|l| l.try_into())
2574 .collect::<Result<Vec<_>>>()?,
2575 )
2576 },
2577 tab_name: new_tab_action.tab_name,
2578 should_change_focus_to_new_tab: new_tab_action.should_change_focus_to_new_tab,
2579 cwd: new_tab_action.cwd.map(PathBuf::from),
2580 initial_panes: if new_tab_action.initial_panes.is_empty() {
2581 None
2582 } else {
2583 Some(
2584 new_tab_action
2585 .initial_panes
2586 .into_iter()
2587 .map(|p| p.try_into())
2588 .collect::<Result<Vec<_>>>()?,
2589 )
2590 },
2591
2592 first_pane_unblock_condition: new_tab_action
2593 .first_pane_unblock_condition
2594 .map(|c| proto_i32_to_unblock_condition(c))
2595 .transpose()?,
2596 }),
2597 ActionType::NoOp(_) => Ok(crate::input::actions::Action::NoOp),
2598 ActionType::GoToNextTab(_) => Ok(crate::input::actions::Action::GoToNextTab),
2599 ActionType::GoToPreviousTab(_) => Ok(crate::input::actions::Action::GoToPreviousTab),
2600 ActionType::CloseTab(_) => Ok(crate::input::actions::Action::CloseTab),
2601 ActionType::GoToTab(go_to_tab_action) => Ok(crate::input::actions::Action::GoToTab {
2602 index: go_to_tab_action.index,
2603 }),
2604 ActionType::GoToTabName(go_to_tab_name_action) => {
2605 Ok(crate::input::actions::Action::GoToTabName {
2606 name: go_to_tab_name_action.name,
2607 create: go_to_tab_name_action.create,
2608 })
2609 },
2610 ActionType::ToggleTab(_) => Ok(crate::input::actions::Action::ToggleTab),
2611 ActionType::TabNameInput(tab_name_action) => {
2612 Ok(crate::input::actions::Action::TabNameInput {
2613 input: tab_name_action.input.into_iter().map(|b| b as u8).collect(),
2614 })
2615 },
2616 ActionType::UndoRenameTab(_) => Ok(crate::input::actions::Action::UndoRenameTab),
2617 ActionType::MoveTab(move_tab_action) => Ok(crate::input::actions::Action::MoveTab {
2618 direction: proto_i32_to_direction(move_tab_action.direction)?,
2619 }),
2620 ActionType::Run(run_action) => Ok(crate::input::actions::Action::Run {
2621 command: run_action
2622 .command
2623 .ok_or_else(|| anyhow!("Run missing command"))?
2624 .try_into()?,
2625 near_current_pane: run_action.near_current_pane,
2626 no_focus: run_action.no_focus,
2627 }),
2628 ActionType::Detach(_) => Ok(crate::input::actions::Action::Detach),
2629 ActionType::SetDarkTheme(_) => Ok(crate::input::actions::Action::SetDarkTheme),
2630 ActionType::SetLightTheme(_) => Ok(crate::input::actions::Action::SetLightTheme),
2631 ActionType::ToggleTheme(_) => Ok(crate::input::actions::Action::ToggleTheme),
2632 ActionType::SwitchSession(switch_session_action) => {
2633 Ok(crate::input::actions::Action::SwitchSession {
2634 name: switch_session_action.name.clone(),
2635 tab_position: switch_session_action.tab_position.map(|p| p as usize),
2636 pane_id: switch_session_action
2637 .pane_id
2638 .as_ref()
2639 .map(|p| (p.pane_id, p.is_plugin)),
2640 layout: switch_session_action
2641 .layout
2642 .map(|l| l.try_into())
2643 .transpose()?,
2644 cwd: switch_session_action.cwd.map(PathBuf::from),
2645 })
2646 },
2647 ActionType::LaunchOrFocusPlugin(launch_plugin_action) => {
2648 Ok(crate::input::actions::Action::LaunchOrFocusPlugin {
2649 plugin: launch_plugin_action
2650 .plugin
2651 .ok_or_else(|| anyhow!("LaunchOrFocusPlugin missing plugin"))?
2652 .try_into()?,
2653 should_float: launch_plugin_action.should_float,
2654 move_to_focused_tab: launch_plugin_action.move_to_focused_tab,
2655 should_open_in_place: launch_plugin_action.should_open_in_place,
2656 close_replaced_pane: launch_plugin_action.close_replaced_pane,
2657 skip_cache: launch_plugin_action.skip_cache,
2658 tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
2659 })
2660 },
2661 ActionType::LaunchPlugin(launch_plugin_action) => {
2662 Ok(crate::input::actions::Action::LaunchPlugin {
2663 plugin: launch_plugin_action
2664 .plugin
2665 .ok_or_else(|| anyhow!("LaunchPlugin missing plugin"))?
2666 .try_into()?,
2667 should_float: launch_plugin_action.should_float,
2668 should_open_in_place: launch_plugin_action.should_open_in_place,
2669 close_replaced_pane: launch_plugin_action.close_replaced_pane,
2670 skip_cache: launch_plugin_action.skip_cache,
2671 cwd: launch_plugin_action.cwd.map(PathBuf::from),
2672 no_focus: launch_plugin_action.no_focus,
2673 tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
2674 })
2675 },
2676 ActionType::MouseEvent(mouse_event_action) => {
2677 Ok(crate::input::actions::Action::MouseEvent {
2678 event: mouse_event_action
2679 .event
2680 .ok_or_else(|| anyhow!("MouseEvent missing event"))?
2681 .try_into()?,
2682 })
2683 },
2684 ActionType::Copy(_) => Ok(crate::input::actions::Action::Copy),
2685 ActionType::Confirm(_) => Ok(crate::input::actions::Action::Confirm),
2686 ActionType::Deny(_) => Ok(crate::input::actions::Action::Deny),
2687 ActionType::SkipConfirm(skip_confirm_action) => {
2688 Ok(crate::input::actions::Action::SkipConfirm {
2689 action: Box::new(
2690 skip_confirm_action
2691 .action
2692 .ok_or_else(|| anyhow!("SkipConfirm missing action"))?
2693 .as_ref()
2694 .clone()
2695 .try_into()?,
2696 ),
2697 })
2698 },
2699 ActionType::SearchInput(search_input_action) => {
2700 Ok(crate::input::actions::Action::SearchInput {
2701 input: search_input_action
2702 .input
2703 .into_iter()
2704 .map(|b| b as u8)
2705 .collect(),
2706 })
2707 },
2708 ActionType::Search(search_action) => Ok(crate::input::actions::Action::Search {
2709 direction: proto_i32_to_search_direction(search_action.direction)?,
2710 }),
2711 ActionType::SearchToggleOption(search_toggle_action) => {
2712 Ok(crate::input::actions::Action::SearchToggleOption {
2713 option: proto_i32_to_search_option(search_toggle_action.option)?,
2714 })
2715 },
2716 ActionType::ToggleMouseMode(_) => Ok(crate::input::actions::Action::ToggleMouseMode),
2717 ActionType::PreviousSwapLayout(_) => {
2718 Ok(crate::input::actions::Action::PreviousSwapLayout)
2719 },
2720 ActionType::NextSwapLayout(_) => Ok(crate::input::actions::Action::NextSwapLayout),
2721 ActionType::OverrideLayout(override_layout_action) => {
2722 Ok(crate::input::actions::Action::OverrideLayout {
2723 tabs: override_layout_action
2724 .tabs
2725 .into_iter()
2726 .map(|t| t.try_into())
2727 .collect::<Result<Vec<_>>>()?,
2728 retain_existing_terminal_panes: override_layout_action
2729 .retain_existing_terminal_panes,
2730 retain_existing_plugin_panes: override_layout_action
2731 .retain_existing_plugin_panes,
2732 apply_only_to_active_tab: override_layout_action.apply_only_to_active_tab,
2733 })
2734 },
2735 ActionType::QueryTabNames(_) => Ok(crate::input::actions::Action::QueryTabNames),
2736 ActionType::NewTiledPluginPane(new_tiled_plugin_action) => {
2737 Ok(crate::input::actions::Action::NewTiledPluginPane {
2738 plugin: new_tiled_plugin_action
2739 .plugin
2740 .ok_or_else(|| anyhow!("NewTiledPluginPane missing plugin"))?
2741 .try_into()?,
2742 pane_name: new_tiled_plugin_action.pane_name,
2743 skip_cache: new_tiled_plugin_action.skip_cache,
2744 cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),
2745 no_focus: new_tiled_plugin_action.no_focus,
2746 tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),
2747 })
2748 },
2749 ActionType::NewFloatingPluginPane(new_floating_plugin_action) => {
2750 Ok(crate::input::actions::Action::NewFloatingPluginPane {
2751 plugin: new_floating_plugin_action
2752 .plugin
2753 .ok_or_else(|| anyhow!("NewFloatingPluginPane missing plugin"))?
2754 .try_into()?,
2755 pane_name: new_floating_plugin_action.pane_name,
2756 skip_cache: new_floating_plugin_action.skip_cache,
2757 cwd: new_floating_plugin_action.cwd.map(PathBuf::from),
2758 coordinates: new_floating_plugin_action
2759 .coordinates
2760 .map(|c| c.try_into())
2761 .transpose()?,
2762 no_focus: new_floating_plugin_action.no_focus,
2763 tab_id: new_floating_plugin_action.tab_id.map(|t| t as usize),
2764 })
2765 },
2766 ActionType::NewInPlacePluginPane(new_in_place_plugin_action) => {
2767 Ok(crate::input::actions::Action::NewInPlacePluginPane {
2768 plugin: new_in_place_plugin_action
2769 .plugin
2770 .ok_or_else(|| anyhow!("NewInPlacePluginPane missing plugin"))?
2771 .try_into()?,
2772 pane_name: new_in_place_plugin_action.pane_name,
2773 skip_cache: new_in_place_plugin_action.skip_cache,
2774 close_replaced_pane: new_in_place_plugin_action.close_replaced_pane,
2775 no_focus: new_in_place_plugin_action.no_focus,
2776 tab_id: new_in_place_plugin_action.tab_id.map(|t| t as usize),
2777 })
2778 },
2779 ActionType::StartOrReloadPlugin(start_plugin_action) => {
2780 Ok(crate::input::actions::Action::StartOrReloadPlugin {
2781 plugin: start_plugin_action
2782 .plugin
2783 .ok_or_else(|| anyhow!("StartOrReloadPlugin missing plugin"))?
2784 .try_into()?,
2785 })
2786 },
2787 ActionType::CloseTerminalPane(close_pane_action) => {
2788 Ok(crate::input::actions::Action::CloseTerminalPane {
2789 pane_id: close_pane_action.pane_id,
2790 })
2791 },
2792 ActionType::ClosePluginPane(close_pane_action) => {
2793 Ok(crate::input::actions::Action::ClosePluginPane {
2794 pane_id: close_pane_action.pane_id,
2795 })
2796 },
2797 ActionType::FocusTerminalPaneWithId(focus_pane_action) => {
2798 Ok(crate::input::actions::Action::FocusTerminalPaneWithId {
2799 pane_id: focus_pane_action.pane_id,
2800 should_float_if_hidden: focus_pane_action.should_float_if_hidden,
2801 should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
2802 })
2803 },
2804 ActionType::FocusPluginPaneWithId(focus_pane_action) => {
2805 Ok(crate::input::actions::Action::FocusPluginPaneWithId {
2806 pane_id: focus_pane_action.pane_id,
2807 should_float_if_hidden: focus_pane_action.should_float_if_hidden,
2808 should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
2809 })
2810 },
2811 ActionType::RenameTerminalPane(rename_pane_action) => {
2812 Ok(crate::input::actions::Action::RenameTerminalPane {
2813 pane_id: rename_pane_action.pane_id,
2814 name: rename_pane_action
2815 .name
2816 .into_iter()
2817 .map(|b| b as u8)
2818 .collect(),
2819 })
2820 },
2821 ActionType::RenamePluginPane(rename_pane_action) => {
2822 Ok(crate::input::actions::Action::RenamePluginPane {
2823 pane_id: rename_pane_action.pane_id,
2824 name: rename_pane_action
2825 .name
2826 .into_iter()
2827 .map(|b| b as u8)
2828 .collect(),
2829 })
2830 },
2831 ActionType::RenameTab(rename_tab_action) => {
2832 Ok(crate::input::actions::Action::RenameTab {
2833 tab_index: rename_tab_action.tab_index,
2834 name: rename_tab_action
2835 .name
2836 .into_iter()
2837 .map(|b| b as u8)
2838 .collect(),
2839 })
2840 },
2841 ActionType::GoToTabById(go_to_tab_by_id_action) => {
2842 Ok(crate::input::actions::Action::GoToTabById {
2843 id: go_to_tab_by_id_action.id,
2844 })
2845 },
2846 ActionType::CloseTabById(close_tab_by_id_action) => {
2847 Ok(crate::input::actions::Action::CloseTabById {
2848 id: close_tab_by_id_action.id,
2849 })
2850 },
2851 ActionType::RenameTabById(rename_tab_by_id_action) => {
2852 Ok(crate::input::actions::Action::RenameTabById {
2853 id: rename_tab_by_id_action.id,
2854 name: rename_tab_by_id_action.name,
2855 })
2856 },
2857 ActionType::BreakPane(_) => Ok(crate::input::actions::Action::BreakPane),
2858 ActionType::BreakPaneRight(_) => Ok(crate::input::actions::Action::BreakPaneRight),
2859 ActionType::BreakPaneLeft(_) => Ok(crate::input::actions::Action::BreakPaneLeft),
2860 ActionType::FocusHostSession(_) => Ok(crate::input::actions::Action::FocusHostSession),
2861 ActionType::FocusGuestSession(_) => {
2862 Ok(crate::input::actions::Action::FocusGuestSession)
2863 },
2864 ActionType::ToggleHostFullscreen(_) => {
2865 Ok(crate::input::actions::Action::ToggleHostFullscreen)
2866 },
2867 ActionType::RenameSession(rename_session_action) => {
2868 Ok(crate::input::actions::Action::RenameSession {
2869 name: rename_session_action.name,
2870 })
2871 },
2872 ActionType::CliPipe(cli_pipe_action) => Ok(crate::input::actions::Action::CliPipe {
2873 pipe_id: cli_pipe_action.pipe_id,
2874 name: cli_pipe_action.name,
2875 payload: cli_pipe_action.payload,
2876 args: if cli_pipe_action.args.is_empty() {
2877 None
2878 } else {
2879 Some(cli_pipe_action.args.into_iter().collect())
2880 },
2881 plugin: cli_pipe_action.plugin,
2882 configuration: if cli_pipe_action.configuration.is_empty() {
2883 None
2884 } else {
2885 Some(cli_pipe_action.configuration.into_iter().collect())
2886 },
2887 launch_new: cli_pipe_action.launch_new,
2888 skip_cache: cli_pipe_action.skip_cache,
2889 floating: cli_pipe_action.floating,
2890 in_place: cli_pipe_action.in_place,
2891 cwd: cli_pipe_action.cwd.map(PathBuf::from),
2892 pane_title: cli_pipe_action.pane_title,
2893 }),
2894 ActionType::KeybindPipe(keybind_pipe_action) => {
2895 Ok(crate::input::actions::Action::KeybindPipe {
2896 name: keybind_pipe_action.name,
2897 payload: keybind_pipe_action.payload,
2898 args: if keybind_pipe_action.args.is_empty() {
2899 None
2900 } else {
2901 Some(keybind_pipe_action.args.into_iter().collect())
2902 },
2903 plugin: keybind_pipe_action.plugin,
2904 plugin_id: keybind_pipe_action.plugin_id,
2905 configuration: if keybind_pipe_action.configuration.is_empty() {
2906 None
2907 } else {
2908 Some(keybind_pipe_action.configuration.into_iter().collect())
2909 },
2910 launch_new: keybind_pipe_action.launch_new,
2911 skip_cache: keybind_pipe_action.skip_cache,
2912 floating: keybind_pipe_action.floating,
2913 in_place: keybind_pipe_action.in_place,
2914 cwd: keybind_pipe_action.cwd.map(PathBuf::from),
2915 pane_title: keybind_pipe_action.pane_title,
2916 })
2917 },
2918 ActionType::ListClients(_) => Ok(crate::input::actions::Action::ListClients),
2919 ActionType::ListPanes(list_panes_action) => {
2920 Ok(crate::input::actions::Action::ListPanes {
2921 show_tab: list_panes_action.show_tab,
2922 show_command: list_panes_action.show_command,
2923 show_state: list_panes_action.show_state,
2924 show_geometry: list_panes_action.show_geometry,
2925 show_all: list_panes_action.show_all,
2926 output_json: list_panes_action.output_json,
2927 })
2928 },
2929 ActionType::ListTabs(list_tabs_action) => Ok(crate::input::actions::Action::ListTabs {
2930 show_state: list_tabs_action.show_state,
2931 show_dimensions: list_tabs_action.show_dimensions,
2932 show_panes: list_tabs_action.show_panes,
2933 show_layout: list_tabs_action.show_layout,
2934 show_all: list_tabs_action.show_all,
2935 output_json: list_tabs_action.output_json,
2936 }),
2937 ActionType::CurrentTabInfo(current_tab_info_action) => {
2938 Ok(crate::input::actions::Action::CurrentTabInfo {
2939 output_json: current_tab_info_action.output_json,
2940 })
2941 },
2942 ActionType::TogglePanePinned(_) => Ok(crate::input::actions::Action::TogglePanePinned),
2943 ActionType::StackPanes(stack_panes_action) => {
2944 Ok(crate::input::actions::Action::StackPanes {
2945 pane_ids: stack_panes_action
2946 .pane_ids
2947 .into_iter()
2948 .map(|id| id.try_into())
2949 .collect::<Result<Vec<_>>>()?,
2950 })
2951 },
2952 ActionType::ChangeFloatingPaneCoordinates(change_coords_action) => Ok(
2953 crate::input::actions::Action::ChangeFloatingPaneCoordinates {
2954 pane_id: change_coords_action
2955 .pane_id
2956 .ok_or_else(|| anyhow!("ChangeFloatingPaneCoordinates missing pane_id"))?
2957 .try_into()?,
2958 coordinates: change_coords_action
2959 .coordinates
2960 .ok_or_else(|| {
2961 anyhow!("ChangeFloatingPaneCoordinates missing coordinates")
2962 })?
2963 .try_into()?,
2964 },
2965 ),
2966 ActionType::TogglePaneBorderless(toggle_borderless_action) => {
2967 Ok(crate::input::actions::Action::TogglePaneBorderless {
2968 pane_id: toggle_borderless_action
2969 .pane_id
2970 .ok_or_else(|| anyhow!("TogglePaneBorderless missing pane_id"))?
2971 .try_into()?,
2972 })
2973 },
2974 ActionType::SetPaneBorderless(set_borderless_action) => {
2975 Ok(crate::input::actions::Action::SetPaneBorderless {
2976 pane_id: set_borderless_action
2977 .pane_id
2978 .ok_or_else(|| anyhow!("SetPaneBorderless missing pane_id"))?
2979 .try_into()?,
2980 borderless: set_borderless_action.borderless,
2981 })
2982 },
2983 ActionType::TogglePaneInGroup(_) => {
2984 Ok(crate::input::actions::Action::TogglePaneInGroup)
2985 },
2986 ActionType::ToggleGroupMarking(_) => {
2987 Ok(crate::input::actions::Action::ToggleGroupMarking)
2988 },
2989 ActionType::SetPaneColor(set_pane_color_action) => {
2990 Ok(crate::input::actions::Action::SetPaneColor {
2991 pane_id: set_pane_color_action
2992 .pane_id
2993 .ok_or_else(|| anyhow!("SetPaneColor missing pane_id"))?
2994 .try_into()?,
2995 fg: set_pane_color_action.fg,
2996 bg: set_pane_color_action.bg,
2997 })
2998 },
2999 ActionType::ScrollUpByPaneId(a) => {
3001 Ok(crate::input::actions::Action::ScrollUpByPaneId {
3002 pane_id: a
3003 .pane_id
3004 .ok_or_else(|| anyhow!("ScrollUpByPaneId missing pane_id"))?
3005 .try_into()?,
3006 })
3007 },
3008 ActionType::ScrollDownByPaneId(a) => {
3009 Ok(crate::input::actions::Action::ScrollDownByPaneId {
3010 pane_id: a
3011 .pane_id
3012 .ok_or_else(|| anyhow!("ScrollDownByPaneId missing pane_id"))?
3013 .try_into()?,
3014 })
3015 },
3016 ActionType::ScrollToTopByPaneId(a) => {
3017 Ok(crate::input::actions::Action::ScrollToTopByPaneId {
3018 pane_id: a
3019 .pane_id
3020 .ok_or_else(|| anyhow!("ScrollToTopByPaneId missing pane_id"))?
3021 .try_into()?,
3022 })
3023 },
3024 ActionType::ScrollToBottomByPaneId(a) => {
3025 Ok(crate::input::actions::Action::ScrollToBottomByPaneId {
3026 pane_id: a
3027 .pane_id
3028 .ok_or_else(|| anyhow!("ScrollToBottomByPaneId missing pane_id"))?
3029 .try_into()?,
3030 })
3031 },
3032 ActionType::PageScrollUpByPaneId(a) => {
3033 Ok(crate::input::actions::Action::PageScrollUpByPaneId {
3034 pane_id: a
3035 .pane_id
3036 .ok_or_else(|| anyhow!("PageScrollUpByPaneId missing pane_id"))?
3037 .try_into()?,
3038 })
3039 },
3040 ActionType::PageScrollDownByPaneId(a) => {
3041 Ok(crate::input::actions::Action::PageScrollDownByPaneId {
3042 pane_id: a
3043 .pane_id
3044 .ok_or_else(|| anyhow!("PageScrollDownByPaneId missing pane_id"))?
3045 .try_into()?,
3046 })
3047 },
3048 ActionType::HalfPageScrollUpByPaneId(a) => {
3049 Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {
3050 pane_id: a
3051 .pane_id
3052 .ok_or_else(|| anyhow!("HalfPageScrollUpByPaneId missing pane_id"))?
3053 .try_into()?,
3054 })
3055 },
3056 ActionType::HalfPageScrollDownByPaneId(a) => {
3057 Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {
3058 pane_id: a
3059 .pane_id
3060 .ok_or_else(|| anyhow!("HalfPageScrollDownByPaneId missing pane_id"))?
3061 .try_into()?,
3062 })
3063 },
3064 ActionType::ResizeByPaneId(a) => {
3065 let resize_action = a
3066 .resize_action
3067 .ok_or_else(|| anyhow!("ResizeByPaneId missing resize_action"))?;
3068 let resize = proto_i32_to_resize(resize_action.resize)?;
3069 let direction = resize_action
3070 .direction
3071 .map(|d| proto_i32_to_direction(d))
3072 .transpose()?;
3073 Ok(crate::input::actions::Action::ResizeByPaneId {
3074 pane_id: a
3075 .pane_id
3076 .ok_or_else(|| anyhow!("ResizeByPaneId missing pane_id"))?
3077 .try_into()?,
3078 resize,
3079 direction,
3080 })
3081 },
3082 ActionType::MovePaneByPaneId(a) => {
3083 let direction = a.direction.map(|d| proto_i32_to_direction(d)).transpose()?;
3084 Ok(crate::input::actions::Action::MovePaneByPaneId {
3085 pane_id: a
3086 .pane_id
3087 .ok_or_else(|| anyhow!("MovePaneByPaneId missing pane_id"))?
3088 .try_into()?,
3089 direction,
3090 })
3091 },
3092 ActionType::MovePaneBackwardsByPaneId(a) => {
3093 Ok(crate::input::actions::Action::MovePaneBackwardsByPaneId {
3094 pane_id: a
3095 .pane_id
3096 .ok_or_else(|| anyhow!("MovePaneBackwardsByPaneId missing pane_id"))?
3097 .try_into()?,
3098 })
3099 },
3100 ActionType::ClearScreenByPaneId(a) => {
3101 Ok(crate::input::actions::Action::ClearScreenByPaneId {
3102 pane_id: a
3103 .pane_id
3104 .ok_or_else(|| anyhow!("ClearScreenByPaneId missing pane_id"))?
3105 .try_into()?,
3106 })
3107 },
3108 ActionType::EditScrollbackByPaneId(a) => {
3109 Ok(crate::input::actions::Action::EditScrollbackByPaneId {
3110 pane_id: a
3111 .pane_id
3112 .ok_or_else(|| anyhow!("EditScrollbackByPaneId missing pane_id"))?
3113 .try_into()?,
3114 ansi: a.ansi,
3115 })
3116 },
3117 ActionType::ToggleFullscreenByPaneId(a) => Ok(
3118 crate::input::actions::Action::ToggleFocusFullscreenByPaneId {
3119 pane_id: a
3120 .pane_id
3121 .ok_or_else(|| anyhow!("ToggleFullscreenByPaneId missing pane_id"))?
3122 .try_into()?,
3123 },
3124 ),
3125 ActionType::ToggleNoUiFullscreenByPaneId(a) => Ok(
3126 crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId {
3127 pane_id: a
3128 .pane_id
3129 .ok_or_else(|| anyhow!("ToggleNoUiFullscreenByPaneId missing pane_id"))?
3130 .try_into()?,
3131 },
3132 ),
3133 ActionType::TogglePaneEmbedOrFloatingByPaneId(a) => Ok(
3134 crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId {
3135 pane_id: a
3136 .pane_id
3137 .ok_or_else(|| {
3138 anyhow!("TogglePaneEmbedOrFloatingByPaneId missing pane_id")
3139 })?
3140 .try_into()?,
3141 },
3142 ),
3143 ActionType::CloseFocusByPaneId(a) => {
3144 Ok(crate::input::actions::Action::CloseFocusByPaneId {
3145 pane_id: a
3146 .pane_id
3147 .ok_or_else(|| anyhow!("CloseFocusByPaneId missing pane_id"))?
3148 .try_into()?,
3149 })
3150 },
3151 ActionType::RenamePaneByPaneId(a) => {
3152 Ok(crate::input::actions::Action::RenamePaneByPaneId {
3153 pane_id: a.pane_id.map(|p| p.try_into()).transpose()?,
3154 name: a.name,
3155 })
3156 },
3157 ActionType::UndoRenamePaneByPaneId(a) => {
3158 Ok(crate::input::actions::Action::UndoRenamePaneByPaneId {
3159 pane_id: a
3160 .pane_id
3161 .ok_or_else(|| anyhow!("UndoRenamePaneByPaneId missing pane_id"))?
3162 .try_into()?,
3163 })
3164 },
3165 ActionType::TogglePanePinnedByPaneId(a) => {
3166 Ok(crate::input::actions::Action::TogglePanePinnedByPaneId {
3167 pane_id: a
3168 .pane_id
3169 .ok_or_else(|| anyhow!("TogglePanePinnedByPaneId missing pane_id"))?
3170 .try_into()?,
3171 })
3172 },
3173 ActionType::FocusPaneByPaneId(a) => {
3174 Ok(crate::input::actions::Action::FocusPaneByPaneId {
3175 pane_id: a
3176 .pane_id
3177 .ok_or_else(|| anyhow!("FocusPaneByPaneId missing pane_id"))?
3178 .try_into()?,
3179 })
3180 },
3181 ActionType::UndoRenameTabByTabId(a) => {
3183 Ok(crate::input::actions::Action::UndoRenameTabByTabId { id: a.id })
3184 },
3185 ActionType::ToggleActiveSyncTabByTabId(a) => {
3186 Ok(crate::input::actions::Action::ToggleActiveSyncTabByTabId { id: a.id })
3187 },
3188 ActionType::ToggleFloatingPanesByTabId(a) => {
3189 Ok(crate::input::actions::Action::ToggleFloatingPanesByTabId { id: a.id })
3190 },
3191 ActionType::PreviousSwapLayoutByTabId(a) => {
3192 Ok(crate::input::actions::Action::PreviousSwapLayoutByTabId { id: a.id })
3193 },
3194 ActionType::NextSwapLayoutByTabId(a) => {
3195 Ok(crate::input::actions::Action::NextSwapLayoutByTabId { id: a.id })
3196 },
3197 ActionType::MoveTabByTabId(a) => {
3198 let direction = proto_i32_to_direction(a.direction)?;
3199 Ok(crate::input::actions::Action::MoveTabByTabId {
3200 id: a.id,
3201 direction,
3202 })
3203 },
3204 }
3205 }
3206}
3207
3208impl From<crate::data::KeyWithModifier>
3209 for crate::client_server_contract::client_server_contract::KeyWithModifier
3210{
3211 fn from(key: crate::data::KeyWithModifier) -> Self {
3212 use crate::ipc::enum_conversions::{bare_key_to_proto_i32, key_modifier_to_proto_i32};
3213
3214 let (bare_key_enum, char_data) = match &key.bare_key {
3216 crate::data::BareKey::Char(c) => (
3217 crate::client_server_contract::client_server_contract::BareKey::Char as i32,
3218 Some(c.to_string()),
3219 ),
3220 other => (bare_key_to_proto_i32(*other), None),
3221 };
3222
3223 Self {
3224 bare_key: bare_key_enum,
3225 key_modifiers: key
3226 .key_modifiers
3227 .into_iter()
3228 .map(|modifier| key_modifier_to_proto_i32(modifier))
3229 .collect(),
3230 character: char_data,
3231 }
3232 }
3233}
3234
3235impl TryFrom<crate::client_server_contract::client_server_contract::KeyWithModifier>
3236 for crate::data::KeyWithModifier
3237{
3238 type Error = anyhow::Error;
3239 fn try_from(
3240 key: crate::client_server_contract::client_server_contract::KeyWithModifier,
3241 ) -> Result<Self> {
3242 use crate::ipc::enum_conversions::{bare_key_from_proto_i32, key_modifier_from_proto_i32};
3243 use std::collections::BTreeSet;
3244
3245 let bare_key = if key.bare_key
3247 == crate::client_server_contract::client_server_contract::BareKey::Char as i32
3248 {
3249 let character_str = key
3250 .character
3251 .ok_or_else(|| anyhow!("Character key missing character data"))?;
3252 let character = character_str
3253 .chars()
3254 .next()
3255 .ok_or_else(|| anyhow!("Empty character string"))?;
3256 crate::data::BareKey::Char(character)
3257 } else {
3258 bare_key_from_proto_i32(key.bare_key)?
3259 };
3260
3261 let key_modifiers: Result<BTreeSet<_>> = key
3262 .key_modifiers
3263 .into_iter()
3264 .map(|modifier| key_modifier_from_proto_i32(modifier))
3265 .collect();
3266
3267 Ok(Self {
3268 bare_key,
3269 key_modifiers: key_modifiers?,
3270 })
3271 }
3272}
3273
3274impl From<crate::data::ConnectToSession>
3275 for crate::client_server_contract::client_server_contract::ConnectToSession
3276{
3277 fn from(connect: crate::data::ConnectToSession) -> Self {
3278 Self {
3279 name: connect.name,
3280 tab_position: connect.tab_position.map(|p| p as u32),
3281 pane_id: connect.pane_id.map(|(id, is_plugin)| {
3282 crate::client_server_contract::client_server_contract::PaneIdWithPlugin {
3283 pane_id: id,
3284 is_plugin,
3285 }
3286 }),
3287 layout: connect.layout.map(|l| l.into()),
3288 cwd: connect.cwd.map(|p| p.to_string_lossy().to_string()),
3289 }
3290 }
3291}
3292
3293impl TryFrom<crate::client_server_contract::client_server_contract::ConnectToSession>
3294 for crate::data::ConnectToSession
3295{
3296 type Error = anyhow::Error;
3297 fn try_from(
3298 connect: crate::client_server_contract::client_server_contract::ConnectToSession,
3299 ) -> Result<Self> {
3300 Ok(Self {
3301 name: connect.name,
3302 tab_position: connect.tab_position.map(|p| p as usize),
3303 pane_id: connect.pane_id.map(|p| (p.pane_id, p.is_plugin)),
3304 layout: connect.layout.map(|l| l.try_into()).transpose()?,
3305 cwd: connect.cwd.map(PathBuf::from),
3306 })
3307 }
3308}
3309
3310impl From<crate::data::LayoutInfo>
3311 for crate::client_server_contract::client_server_contract::LayoutInfo
3312{
3313 fn from(layout: crate::data::LayoutInfo) -> Self {
3314 use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
3315 let (layout_type, layout_metadata) = match layout {
3316 crate::data::LayoutInfo::BuiltIn(name) => (LayoutType::BuiltinName(name), None),
3317 crate::data::LayoutInfo::File(path, metadata) => {
3318 (LayoutType::FilePath(path), Some(metadata.into()))
3319 },
3320 crate::data::LayoutInfo::Url(url) => (LayoutType::Url(url), None),
3321 crate::data::LayoutInfo::Stringified(content) => {
3322 (LayoutType::Stringified(content), None)
3323 },
3324 };
3325 Self {
3326 layout_type: Some(layout_type),
3327 layout_metadata,
3328 }
3329 }
3330}
3331
3332impl TryFrom<crate::client_server_contract::client_server_contract::LayoutInfo>
3333 for crate::data::LayoutInfo
3334{
3335 type Error = anyhow::Error;
3336 fn try_from(
3337 layout: crate::client_server_contract::client_server_contract::LayoutInfo,
3338 ) -> Result<Self> {
3339 use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
3340 match layout.layout_type {
3341 Some(LayoutType::BuiltinName(name)) => Ok(crate::data::LayoutInfo::BuiltIn(name)),
3342 Some(LayoutType::FilePath(path)) => {
3343 let layout_metadata = layout
3344 .layout_metadata
3345 .map(|m| m.try_into())
3346 .transpose()?
3347 .unwrap_or_default();
3348 Ok(crate::data::LayoutInfo::File(path, layout_metadata))
3349 },
3350 Some(LayoutType::Url(url)) => Ok(crate::data::LayoutInfo::Url(url)),
3351 Some(LayoutType::Stringified(content)) => {
3352 Ok(crate::data::LayoutInfo::Stringified(content))
3353 },
3354 None => Err(anyhow!("LayoutInfo missing layout_type")),
3355 }
3356 }
3357}
3358
3359impl From<crate::data::LayoutMetadata> for ProtoLayoutMetadata {
3360 fn from(metadata: crate::data::LayoutMetadata) -> Self {
3361 ProtoLayoutMetadata {
3362 tabs: metadata.tabs.into_iter().map(|t| t.into()).collect(),
3363 creation_time: metadata.creation_time,
3364 update_time: metadata.update_time,
3365 }
3366 }
3367}
3368
3369impl TryFrom<ProtoLayoutMetadata> for crate::data::LayoutMetadata {
3370 type Error = anyhow::Error;
3371 fn try_from(proto_metadata: ProtoLayoutMetadata) -> Result<Self> {
3372 let tabs = proto_metadata
3373 .tabs
3374 .into_iter()
3375 .map(|t| t.try_into())
3376 .collect::<Result<Vec<_>>>()?;
3377 Ok(crate::data::LayoutMetadata {
3378 tabs,
3379 creation_time: proto_metadata.creation_time,
3380 update_time: proto_metadata.update_time,
3381 })
3382 }
3383}
3384
3385impl From<crate::data::TabMetadata> for ProtoTabMetadata {
3386 fn from(metadata: crate::data::TabMetadata) -> Self {
3387 ProtoTabMetadata {
3388 pane_metadata: metadata.panes.into_iter().map(|p| p.into()).collect(),
3389 name: metadata.name,
3390 }
3391 }
3392}
3393
3394impl TryFrom<ProtoTabMetadata> for crate::data::TabMetadata {
3395 type Error = anyhow::Error;
3396 fn try_from(proto_metadata: ProtoTabMetadata) -> Result<Self> {
3397 let panes = proto_metadata
3398 .pane_metadata
3399 .into_iter()
3400 .map(|p| p.try_into())
3401 .collect::<Result<Vec<_>>>()?;
3402 Ok(crate::data::TabMetadata {
3403 panes,
3404 name: proto_metadata.name,
3405 })
3406 }
3407}
3408
3409impl From<crate::data::PaneMetadata> for ProtoPaneMetadata {
3410 fn from(metadata: crate::data::PaneMetadata) -> Self {
3411 ProtoPaneMetadata {
3412 name: metadata.name,
3413 is_plugin: metadata.is_plugin,
3414 is_builtin_plugin: metadata.is_builtin_plugin,
3415 }
3416 }
3417}
3418
3419impl TryFrom<ProtoPaneMetadata> for crate::data::PaneMetadata {
3420 type Error = anyhow::Error;
3421 fn try_from(proto_metadata: ProtoPaneMetadata) -> Result<Self> {
3422 Ok(crate::data::PaneMetadata {
3423 name: proto_metadata.name,
3424 is_plugin: proto_metadata.is_plugin,
3425 is_builtin_plugin: proto_metadata.is_builtin_plugin,
3426 })
3427 }
3428}
3429
3430impl From<ExitReason> for ProtoExitReason {
3431 fn from(reason: ExitReason) -> Self {
3432 match reason {
3433 ExitReason::Normal => ProtoExitReason::Normal,
3434 ExitReason::NormalDetached => ProtoExitReason::NormalDetached,
3435 ExitReason::ForceDetached => ProtoExitReason::ForceDetached,
3436 ExitReason::CannotAttach => ProtoExitReason::CannotAttach,
3437 ExitReason::Disconnect => ProtoExitReason::Disconnect,
3438 ExitReason::WebClientsForbidden => ProtoExitReason::WebClientsForbidden,
3439 ExitReason::KickedByHost => ProtoExitReason::KickedByHost,
3440 ExitReason::Error(_msg) => ProtoExitReason::Error,
3441 ExitReason::CustomExitStatus(_status) => ProtoExitReason::CustomExitStatus,
3442 }
3443 }
3444}
3445
3446impl TryFrom<ProtoExitReason> for ExitReason {
3447 type Error = anyhow::Error;
3448 fn try_from(reason: ProtoExitReason) -> Result<Self> {
3449 match reason {
3450 ProtoExitReason::Normal => Ok(ExitReason::Normal),
3451 ProtoExitReason::NormalDetached => Ok(ExitReason::NormalDetached),
3452 ProtoExitReason::ForceDetached => Ok(ExitReason::ForceDetached),
3453 ProtoExitReason::CannotAttach => Ok(ExitReason::CannotAttach),
3454 ProtoExitReason::Disconnect => Ok(ExitReason::Disconnect),
3455 ProtoExitReason::WebClientsForbidden => Ok(ExitReason::WebClientsForbidden),
3456 ProtoExitReason::KickedByHost => Ok(ExitReason::KickedByHost),
3457 ProtoExitReason::Error => Ok(ExitReason::Error("Protobuf error".to_string())),
3458 ProtoExitReason::CustomExitStatus => Ok(ExitReason::CustomExitStatus(0)),
3459 ProtoExitReason::Unspecified => Err(anyhow!("Unspecified exit reason")),
3460 }
3461 }
3462}
3463
3464impl From<HostTerminalThemeMode> for ProtoHostTerminalThemeIndication {
3465 fn from(mode: HostTerminalThemeMode) -> Self {
3466 match mode {
3467 HostTerminalThemeMode::Dark => ProtoHostTerminalThemeIndication::Dark,
3468 HostTerminalThemeMode::Light => ProtoHostTerminalThemeIndication::Light,
3469 }
3470 }
3471}
3472
3473impl From<ProtoHostTerminalThemeIndication> for HostTerminalThemeMode {
3474 fn from(mode: ProtoHostTerminalThemeIndication) -> Self {
3475 match mode {
3476 ProtoHostTerminalThemeIndication::Dark => HostTerminalThemeMode::Dark,
3477 ProtoHostTerminalThemeIndication::Light => HostTerminalThemeMode::Light,
3478 }
3479 }
3480}
3481
3482fn input_mode_to_proto_i32(mode: InputMode) -> i32 {
3484 match mode {
3485 InputMode::Normal => ProtoInputMode::Normal as i32,
3486 InputMode::Locked => ProtoInputMode::Locked as i32,
3487 InputMode::Resize => ProtoInputMode::Resize as i32,
3488 InputMode::Pane => ProtoInputMode::Pane as i32,
3489 InputMode::Tab => ProtoInputMode::Tab as i32,
3490 InputMode::Scroll => ProtoInputMode::Scroll as i32,
3491 InputMode::EnterSearch => ProtoInputMode::EnterSearch as i32,
3492 InputMode::Search => ProtoInputMode::Search as i32,
3493 InputMode::RenameTab => ProtoInputMode::RenameTab as i32,
3494 InputMode::RenamePane => ProtoInputMode::RenamePane as i32,
3495 InputMode::Session => ProtoInputMode::Session as i32,
3496 InputMode::Move => ProtoInputMode::Move as i32,
3497 InputMode::Prompt => ProtoInputMode::Prompt as i32,
3498 InputMode::Tmux => ProtoInputMode::Tmux as i32,
3499 }
3500}
3501
3502fn proto_i32_to_input_mode(i: i32) -> Result<InputMode> {
3503 match ProtoInputMode::try_from(i).ok() {
3504 Some(ProtoInputMode::Normal) => Ok(InputMode::Normal),
3505 Some(ProtoInputMode::Locked) => Ok(InputMode::Locked),
3506 Some(ProtoInputMode::Resize) => Ok(InputMode::Resize),
3507 Some(ProtoInputMode::Pane) => Ok(InputMode::Pane),
3508 Some(ProtoInputMode::Tab) => Ok(InputMode::Tab),
3509 Some(ProtoInputMode::Scroll) => Ok(InputMode::Scroll),
3510 Some(ProtoInputMode::EnterSearch) => Ok(InputMode::EnterSearch),
3511 Some(ProtoInputMode::Search) => Ok(InputMode::Search),
3512 Some(ProtoInputMode::RenameTab) => Ok(InputMode::RenameTab),
3513 Some(ProtoInputMode::RenamePane) => Ok(InputMode::RenamePane),
3514 Some(ProtoInputMode::Session) => Ok(InputMode::Session),
3515 Some(ProtoInputMode::Move) => Ok(InputMode::Move),
3516 Some(ProtoInputMode::Prompt) => Ok(InputMode::Prompt),
3517 Some(ProtoInputMode::Tmux) => Ok(InputMode::Tmux),
3518 _ => Err(anyhow!("Invalid InputMode value: {}", i)),
3519 }
3520}
3521
3522fn resize_to_proto_i32(resize: crate::data::Resize) -> i32 {
3524 use crate::client_server_contract::client_server_contract::ResizeType;
3525 match resize {
3526 crate::data::Resize::Increase => ResizeType::Increase as i32,
3527 crate::data::Resize::Decrease => ResizeType::Decrease as i32,
3528 }
3529}
3530
3531fn direction_to_proto_i32(direction: crate::data::Direction) -> i32 {
3532 use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
3533 match direction {
3534 crate::data::Direction::Left => ProtoDirection::Left as i32,
3535 crate::data::Direction::Right => ProtoDirection::Right as i32,
3536 crate::data::Direction::Up => ProtoDirection::Up as i32,
3537 crate::data::Direction::Down => ProtoDirection::Down as i32,
3538 }
3539}
3540
3541fn search_direction_to_proto_i32(direction: crate::input::actions::SearchDirection) -> i32 {
3542 use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
3543 match direction {
3544 crate::input::actions::SearchDirection::Up => ProtoSearchDirection::Up as i32,
3545 crate::input::actions::SearchDirection::Down => ProtoSearchDirection::Down as i32,
3546 }
3547}
3548
3549fn search_option_to_proto_i32(option: crate::input::actions::SearchOption) -> i32 {
3550 use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
3551 match option {
3552 crate::input::actions::SearchOption::CaseSensitivity => {
3553 ProtoSearchOption::CaseSensitivity as i32
3554 },
3555 crate::input::actions::SearchOption::Wrap => ProtoSearchOption::Wrap as i32,
3556 crate::input::actions::SearchOption::WholeWord => ProtoSearchOption::WholeWord as i32,
3557 }
3558}
3559
3560fn unblock_condition_to_proto_i32(condition: crate::data::UnblockCondition) -> i32 {
3561 use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
3562 match condition {
3563 crate::data::UnblockCondition::OnExitSuccess => ProtoUnblockCondition::OnExitSuccess as i32,
3564 crate::data::UnblockCondition::OnExitFailure => ProtoUnblockCondition::OnExitFailure as i32,
3565 crate::data::UnblockCondition::OnAnyExit => ProtoUnblockCondition::OnAnyExit as i32,
3566 }
3567}
3568
3569fn proto_i32_to_resize(resize: i32) -> Result<crate::data::Resize> {
3572 use crate::client_server_contract::client_server_contract::ResizeType as ProtoResize;
3573 let proto_resize = match resize {
3574 x if x == ProtoResize::Increase as i32 => ProtoResize::Increase,
3575 x if x == ProtoResize::Decrease as i32 => ProtoResize::Decrease,
3576 _ => return Err(anyhow!("Invalid ResizeType: {}", resize)),
3577 };
3578 match proto_resize {
3579 ProtoResize::Increase => Ok(crate::data::Resize::Increase),
3580 ProtoResize::Decrease => Ok(crate::data::Resize::Decrease),
3581 ProtoResize::Unspecified => Err(anyhow!("Unspecified ResizeType")),
3582 }
3583}
3584
3585fn proto_i32_to_direction(direction: i32) -> Result<crate::data::Direction> {
3586 use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
3587 let proto_direction = match direction {
3588 x if x == ProtoDirection::Left as i32 => ProtoDirection::Left,
3589 x if x == ProtoDirection::Right as i32 => ProtoDirection::Right,
3590 x if x == ProtoDirection::Up as i32 => ProtoDirection::Up,
3591 x if x == ProtoDirection::Down as i32 => ProtoDirection::Down,
3592 _ => return Err(anyhow!("Invalid Direction: {}", direction)),
3593 };
3594 match proto_direction {
3595 ProtoDirection::Left => Ok(crate::data::Direction::Left),
3596 ProtoDirection::Right => Ok(crate::data::Direction::Right),
3597 ProtoDirection::Up => Ok(crate::data::Direction::Up),
3598 ProtoDirection::Down => Ok(crate::data::Direction::Down),
3599 ProtoDirection::Unspecified => Err(anyhow!("Unspecified direction")),
3600 }
3601}
3602
3603fn proto_i32_to_search_direction(direction: i32) -> Result<crate::input::actions::SearchDirection> {
3604 use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
3605 let proto_direction = match direction {
3606 x if x == ProtoSearchDirection::Up as i32 => ProtoSearchDirection::Up,
3607 x if x == ProtoSearchDirection::Down as i32 => ProtoSearchDirection::Down,
3608 _ => return Err(anyhow!("Invalid SearchDirection: {}", direction)),
3609 };
3610 match proto_direction {
3611 ProtoSearchDirection::Up => Ok(crate::input::actions::SearchDirection::Up),
3612 ProtoSearchDirection::Down => Ok(crate::input::actions::SearchDirection::Down),
3613 ProtoSearchDirection::Unspecified => Err(anyhow!("Unspecified search direction")),
3614 }
3615}
3616
3617fn proto_i32_to_search_option(option: i32) -> Result<crate::input::actions::SearchOption> {
3618 use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
3619 let proto_option = match option {
3620 x if x == ProtoSearchOption::CaseSensitivity as i32 => ProtoSearchOption::CaseSensitivity,
3621 x if x == ProtoSearchOption::WholeWord as i32 => ProtoSearchOption::WholeWord,
3622 x if x == ProtoSearchOption::Wrap as i32 => ProtoSearchOption::Wrap,
3623 _ => return Err(anyhow!("Invalid SearchOption: {}", option)),
3624 };
3625 match proto_option {
3626 ProtoSearchOption::CaseSensitivity => {
3627 Ok(crate::input::actions::SearchOption::CaseSensitivity)
3628 },
3629 ProtoSearchOption::Wrap => Ok(crate::input::actions::SearchOption::Wrap),
3630 ProtoSearchOption::WholeWord => Ok(crate::input::actions::SearchOption::WholeWord),
3631 ProtoSearchOption::Unspecified => Err(anyhow!("Unspecified search option")),
3632 }
3633}
3634
3635fn proto_i32_to_unblock_condition(condition: i32) -> Result<crate::data::UnblockCondition> {
3636 use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
3637 let proto_condition = match condition {
3638 x if x == ProtoUnblockCondition::OnExitSuccess as i32 => {
3639 ProtoUnblockCondition::OnExitSuccess
3640 },
3641 x if x == ProtoUnblockCondition::OnExitFailure as i32 => {
3642 ProtoUnblockCondition::OnExitFailure
3643 },
3644 x if x == ProtoUnblockCondition::OnAnyExit as i32 => ProtoUnblockCondition::OnAnyExit,
3645 _ => return Err(anyhow!("Invalid UnblockCondition: {}", condition)),
3646 };
3647 match proto_condition {
3648 ProtoUnblockCondition::OnExitSuccess => Ok(crate::data::UnblockCondition::OnExitSuccess),
3649 ProtoUnblockCondition::OnExitFailure => Ok(crate::data::UnblockCondition::OnExitFailure),
3650 ProtoUnblockCondition::OnAnyExit => Ok(crate::data::UnblockCondition::OnAnyExit),
3651 ProtoUnblockCondition::Unspecified => Err(anyhow!("Unspecified unblock condition")),
3652 }
3653}
3654
3655impl From<crate::position::Position>
3657 for crate::client_server_contract::client_server_contract::Position
3658{
3659 fn from(pos: crate::position::Position) -> Self {
3660 Self {
3661 line: pos.line.0 as i32,
3662 column: pos.column.0 as u64,
3663 }
3664 }
3665}
3666
3667impl TryFrom<crate::client_server_contract::client_server_contract::Position>
3669 for crate::position::Position
3670{
3671 type Error = anyhow::Error;
3672 fn try_from(
3673 pos: crate::client_server_contract::client_server_contract::Position,
3674 ) -> Result<Self> {
3675 Ok(Self {
3676 line: crate::position::Line(pos.line as isize),
3677 column: crate::position::Column(pos.column as usize),
3678 })
3679 }
3680}
3681
3682impl From<crate::input::command::OpenFilePayload>
3684 for crate::client_server_contract::client_server_contract::OpenFilePayload
3685{
3686 fn from(payload: crate::input::command::OpenFilePayload) -> Self {
3687 Self {
3688 file_to_open: payload.path.to_string_lossy().to_string(),
3689 line_number: payload.line_number.map(|n| n as u32),
3690 cwd: payload.cwd.map(|p| p.to_string_lossy().to_string()),
3691 originating_plugin: payload.originating_plugin.map(|op| op.into()),
3692 }
3693 }
3694}
3695
3696impl TryFrom<crate::client_server_contract::client_server_contract::OpenFilePayload>
3698 for crate::input::command::OpenFilePayload
3699{
3700 type Error = anyhow::Error;
3701 fn try_from(
3702 payload: crate::client_server_contract::client_server_contract::OpenFilePayload,
3703 ) -> Result<Self> {
3704 Ok(Self {
3705 path: PathBuf::from(payload.file_to_open),
3706 line_number: payload.line_number.map(|n| n as usize),
3707 cwd: payload.cwd.map(PathBuf::from),
3708 originating_plugin: payload
3709 .originating_plugin
3710 .map(|op| op.try_into())
3711 .transpose()?,
3712 })
3713 }
3714}
3715
3716impl From<crate::data::PaneId> for crate::client_server_contract::client_server_contract::PaneId {
3718 fn from(pane_id: crate::data::PaneId) -> Self {
3719 use crate::client_server_contract::client_server_contract::pane_id::PaneType;
3720 match pane_id {
3721 crate::data::PaneId::Terminal(id) => Self {
3722 pane_type: Some(PaneType::Terminal(id)),
3723 },
3724 crate::data::PaneId::Plugin(id) => Self {
3725 pane_type: Some(PaneType::Plugin(id)),
3726 },
3727 }
3728 }
3729}
3730
3731impl TryFrom<crate::client_server_contract::client_server_contract::PaneId>
3733 for crate::data::PaneId
3734{
3735 type Error = anyhow::Error;
3736 fn try_from(
3737 pane_id: crate::client_server_contract::client_server_contract::PaneId,
3738 ) -> Result<Self> {
3739 use crate::client_server_contract::client_server_contract::pane_id::PaneType;
3740 match pane_id
3741 .pane_type
3742 .ok_or_else(|| anyhow!("PaneId missing pane_type"))?
3743 {
3744 PaneType::Terminal(id) => Ok(crate::data::PaneId::Terminal(id)),
3745 PaneType::Plugin(id) => Ok(crate::data::PaneId::Plugin(id)),
3746 }
3747 }
3748}
3749
3750impl From<crate::input::layout::SplitSize>
3752 for crate::client_server_contract::client_server_contract::FloatingCoordinate
3753{
3754 fn from(size: crate::input::layout::SplitSize) -> Self {
3755 match size {
3756 crate::input::layout::SplitSize::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::SplitSize::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::SplitSize
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) => Ok(crate::input::layout::SplitSize::Percent(p as usize)),
3780 CoordinateType::Fixed(f) => Ok(crate::input::layout::SplitSize::Fixed(f as usize)),
3781 }
3782 }
3783}
3784
3785impl From<crate::input::layout::PercentOrFixed>
3787 for crate::client_server_contract::client_server_contract::FloatingCoordinate
3788{
3789 fn from(size: crate::input::layout::PercentOrFixed) -> Self {
3790 match size {
3791 crate::input::layout::PercentOrFixed::Percent(p) => Self {
3792 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Percent(p as f32)),
3793 },
3794 crate::input::layout::PercentOrFixed::Fixed(f) => Self {
3795 coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Fixed(f as u32)),
3796 },
3797 }
3798 }
3799}
3800
3801impl TryFrom<crate::client_server_contract::client_server_contract::FloatingCoordinate>
3803 for crate::input::layout::PercentOrFixed
3804{
3805 type Error = anyhow::Error;
3806 fn try_from(
3807 coord: crate::client_server_contract::client_server_contract::FloatingCoordinate,
3808 ) -> Result<Self> {
3809 use crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType;
3810 match coord
3811 .coordinate_type
3812 .ok_or_else(|| anyhow!("FloatingCoordinate missing coordinate_type"))?
3813 {
3814 CoordinateType::Percent(p) => {
3815 Ok(crate::input::layout::PercentOrFixed::Percent(p as usize))
3816 },
3817 CoordinateType::Fixed(f) => Ok(crate::input::layout::PercentOrFixed::Fixed(f as usize)),
3818 }
3819 }
3820}
3821
3822impl From<crate::data::FloatingPaneCoordinates>
3824 for crate::client_server_contract::client_server_contract::FloatingPaneCoordinates
3825{
3826 fn from(coords: crate::data::FloatingPaneCoordinates) -> Self {
3827 Self {
3828 x: coords.x.map(|x| x.into()),
3829 y: coords.y.map(|y| y.into()),
3830 width: coords.width.map(|w| w.into()),
3831 height: coords.height.map(|h| h.into()),
3832 pinned: coords.pinned,
3833 borderless: coords.borderless,
3834 }
3835 }
3836}
3837
3838impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneCoordinates>
3840 for crate::data::FloatingPaneCoordinates
3841{
3842 type Error = anyhow::Error;
3843 fn try_from(
3844 coords: crate::client_server_contract::client_server_contract::FloatingPaneCoordinates,
3845 ) -> Result<Self> {
3846 Ok(Self {
3847 x: coords.x.map(|x| x.try_into()).transpose()?,
3848 y: coords.y.map(|y| y.try_into()).transpose()?,
3849 width: coords.width.map(|w| w.try_into()).transpose()?,
3850 height: coords.height.map(|h| h.try_into()).transpose()?,
3851 pinned: coords.pinned,
3852 borderless: coords.borderless,
3853 })
3854 }
3855}
3856
3857impl From<crate::data::NewPanePlacement>
3859 for crate::client_server_contract::client_server_contract::NewPanePlacement
3860{
3861 fn from(placement: crate::data::NewPanePlacement) -> Self {
3862 use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
3863 use crate::client_server_contract::client_server_contract::{
3864 NoPreferencePlacement, StackedPlacement, TiledPlacement,
3865 };
3866 let placement_type = match placement {
3867 crate::data::NewPanePlacement::NoPreference {
3868 borderless: Some(b),
3869 } => PlacementType::NoPreferenceWithOptions(NoPreferencePlacement {
3870 borderless: Some(b),
3871 }),
3872 crate::data::NewPanePlacement::NoPreference { borderless: None } => {
3873 PlacementType::NoPreference(true)
3874 },
3875 crate::data::NewPanePlacement::Tiled {
3876 direction,
3877 borderless: Some(b),
3878 } => PlacementType::TiledWithOptions(TiledPlacement {
3879 direction: direction.map(direction_to_proto_i32),
3880 borderless: Some(b),
3881 }),
3882 crate::data::NewPanePlacement::Tiled {
3883 direction,
3884 borderless: None,
3885 } => PlacementType::Tiled(direction.map(direction_to_proto_i32).unwrap_or(0)),
3886 crate::data::NewPanePlacement::Floating(coords) => {
3887 PlacementType::Floating(coords.map(|c| c.into()).unwrap_or_default())
3888 },
3889 crate::data::NewPanePlacement::InPlace {
3890 pane_id_to_replace,
3891 close_replaced_pane,
3892 borderless,
3893 } => PlacementType::InPlace(
3894 crate::client_server_contract::client_server_contract::NewPanePlacementInPlace {
3895 pane_id_to_replace: pane_id_to_replace.map(|id| id.into()),
3896 close_replaced_pane,
3897 borderless,
3898 },
3899 ),
3900 crate::data::NewPanePlacement::Stacked {
3901 pane_id_to_stack_under,
3902 borderless: Some(b),
3903 } => PlacementType::StackedWithOptions(StackedPlacement {
3904 pane_id_to_stack_under: pane_id_to_stack_under.map(|id| id.into()),
3905 borderless: Some(b),
3906 }),
3907 crate::data::NewPanePlacement::Stacked {
3908 pane_id_to_stack_under,
3909 borderless: None,
3910 } => PlacementType::Stacked(
3911 pane_id_to_stack_under
3912 .map(|id| id.into())
3913 .unwrap_or_default(),
3914 ),
3915 };
3916 Self {
3917 placement_type: Some(placement_type),
3918 }
3919 }
3920}
3921
3922impl TryFrom<crate::client_server_contract::client_server_contract::NewPanePlacement>
3924 for crate::data::NewPanePlacement
3925{
3926 type Error = anyhow::Error;
3927 fn try_from(
3928 placement: crate::client_server_contract::client_server_contract::NewPanePlacement,
3929 ) -> Result<Self> {
3930 use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
3931 match placement
3932 .placement_type
3933 .ok_or_else(|| anyhow!("NewPanePlacement missing placement_type"))?
3934 {
3935 PlacementType::NoPreferenceWithOptions(opts) => {
3937 Ok(crate::data::NewPanePlacement::NoPreference {
3938 borderless: opts.borderless,
3939 })
3940 },
3941 PlacementType::TiledWithOptions(opts) => {
3942 let direction = opts.direction.map(proto_i32_to_direction).transpose()?;
3943 Ok(crate::data::NewPanePlacement::Tiled {
3944 direction,
3945 borderless: opts.borderless,
3946 })
3947 },
3948 PlacementType::StackedWithOptions(opts) => {
3949 let pane_id = opts
3950 .pane_id_to_stack_under
3951 .map(|id| id.try_into())
3952 .transpose()?;
3953 Ok(crate::data::NewPanePlacement::Stacked {
3954 pane_id_to_stack_under: pane_id,
3955 borderless: opts.borderless,
3956 })
3957 },
3958 PlacementType::NoPreference(_) => {
3960 Ok(crate::data::NewPanePlacement::NoPreference { borderless: None })
3961 },
3962 PlacementType::Tiled(direction) => {
3963 let direction = if direction == 0 {
3964 None
3965 } else {
3966 Some(proto_i32_to_direction(direction)?)
3967 };
3968 Ok(crate::data::NewPanePlacement::Tiled {
3969 direction,
3970 borderless: None,
3971 })
3972 },
3973 PlacementType::Floating(coords) => {
3974 let coords = if coords == Default::default() {
3975 None
3976 } else {
3977 Some(coords.try_into()?)
3978 };
3979 Ok(crate::data::NewPanePlacement::Floating(coords))
3980 },
3981 PlacementType::InPlace(in_place) => Ok(crate::data::NewPanePlacement::InPlace {
3982 pane_id_to_replace: in_place
3983 .pane_id_to_replace
3984 .map(|id| id.try_into())
3985 .transpose()?,
3986 close_replaced_pane: in_place.close_replaced_pane,
3987 borderless: in_place.borderless,
3988 }),
3989 PlacementType::Stacked(pane_id) => {
3990 let pane_id = if pane_id == Default::default() {
3991 None
3992 } else {
3993 Some(pane_id.try_into()?)
3994 };
3995 Ok(crate::data::NewPanePlacement::Stacked {
3996 pane_id_to_stack_under: pane_id,
3997 borderless: None,
3998 })
3999 },
4000 }
4001 }
4002}
4003
4004impl From<crate::input::mouse::MouseEvent>
4006 for crate::client_server_contract::client_server_contract::MouseEvent
4007{
4008 fn from(event: crate::input::mouse::MouseEvent) -> Self {
4009 use crate::client_server_contract::client_server_contract::{
4010 MouseEventType as ProtoMouseEventType, Position,
4011 };
4012
4013 let position = Position {
4014 line: event.position.line.0 as i32,
4015 column: event.position.column.0 as u64,
4016 };
4017
4018 let event_type = match event.event_type {
4019 crate::input::mouse::MouseEventType::Press => ProtoMouseEventType::Press as i32,
4020 crate::input::mouse::MouseEventType::Release => ProtoMouseEventType::Release as i32,
4021 crate::input::mouse::MouseEventType::Motion => ProtoMouseEventType::Motion as i32,
4022 };
4023
4024 Self {
4025 event_type,
4026 left: event.left,
4027 right: event.right,
4028 middle: event.middle,
4029 wheel_up: event.wheel_up,
4030 wheel_down: event.wheel_down,
4031 wheel_left: event.wheel_left,
4032 wheel_right: event.wheel_right,
4033 shift: event.shift,
4034 alt: event.alt,
4035 ctrl: event.ctrl,
4036 position: Some(position),
4037 }
4038 }
4039}
4040
4041impl From<crate::input::command::RunCommandAction>
4043 for crate::client_server_contract::client_server_contract::RunCommandAction
4044{
4045 fn from(action: crate::input::command::RunCommandAction) -> Self {
4046 Self {
4047 command: action.command.to_string_lossy().to_string(),
4048 args: action.args,
4049 cwd: action.cwd.map(|p| p.to_string_lossy().to_string()),
4050 direction: action.direction.map(|d| direction_to_proto_i32(d)),
4051 hold_on_close: action.hold_on_close,
4052 hold_on_start: action.hold_on_start,
4053 originating_plugin: action.originating_plugin.map(|op| op.into()),
4054 use_terminal_title: action.use_terminal_title,
4055 }
4056 }
4057}
4058
4059impl From<crate::data::OriginatingPlugin>
4061 for crate::client_server_contract::client_server_contract::OriginatingPlugin
4062{
4063 fn from(orig: crate::data::OriginatingPlugin) -> Self {
4064 use std::collections::HashMap;
4065 let context: HashMap<String, String> =
4066 orig.context.into_iter().map(|(k, v)| (k, v)).collect();
4067
4068 Self {
4069 plugin_id: orig.plugin_id,
4070 client_id: orig.client_id as u32,
4071 context,
4072 }
4073 }
4074}
4075
4076impl TryFrom<crate::client_server_contract::client_server_contract::OriginatingPlugin>
4078 for crate::data::OriginatingPlugin
4079{
4080 type Error = anyhow::Error;
4081
4082 fn try_from(
4083 orig: crate::client_server_contract::client_server_contract::OriginatingPlugin,
4084 ) -> Result<Self> {
4085 use std::collections::BTreeMap;
4086 let context: BTreeMap<String, String> = orig.context.into_iter().collect();
4087
4088 Ok(Self {
4089 plugin_id: orig.plugin_id,
4090 client_id: orig.client_id as u16,
4091 context,
4092 })
4093 }
4094}
4095
4096fn split_direction_to_proto_i32(direction: crate::input::layout::SplitDirection) -> i32 {
4098 use crate::client_server_contract::client_server_contract::SplitDirection as ProtoSplitDirection;
4099 match direction {
4100 crate::input::layout::SplitDirection::Horizontal => ProtoSplitDirection::Horizontal as i32,
4101 crate::input::layout::SplitDirection::Vertical => ProtoSplitDirection::Vertical as i32,
4102 }
4103}
4104
4105impl From<crate::input::layout::SplitSize>
4107 for crate::client_server_contract::client_server_contract::SplitSize
4108{
4109 fn from(size: crate::input::layout::SplitSize) -> Self {
4110 use crate::client_server_contract::client_server_contract::split_size::SizeType;
4111 match size {
4112 crate::input::layout::SplitSize::Percent(p) => Self {
4113 size_type: Some(SizeType::Percent(p as u32)),
4114 },
4115 crate::input::layout::SplitSize::Fixed(f) => Self {
4116 size_type: Some(SizeType::Fixed(f as u32)),
4117 },
4118 }
4119 }
4120}
4121
4122impl From<crate::input::layout::PercentOrFixed>
4124 for crate::client_server_contract::client_server_contract::PercentOrFixed
4125{
4126 fn from(size: crate::input::layout::PercentOrFixed) -> Self {
4127 use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
4128 match size {
4129 crate::input::layout::PercentOrFixed::Percent(p) => Self {
4130 size_type: Some(SizeType::Percent(p as u32)),
4131 },
4132 crate::input::layout::PercentOrFixed::Fixed(f) => Self {
4133 size_type: Some(SizeType::Fixed(f as u32)),
4134 },
4135 }
4136 }
4137}
4138
4139impl From<crate::input::layout::Run>
4141 for crate::client_server_contract::client_server_contract::Run
4142{
4143 fn from(run: crate::input::layout::Run) -> Self {
4144 use crate::client_server_contract::client_server_contract::run::RunType;
4145 match run {
4146 crate::input::layout::Run::Command(cmd) => Self {
4147 run_type: Some(RunType::Command(
4148 crate::client_server_contract::client_server_contract::RunCommandAction {
4149 command: cmd.command.to_string_lossy().to_string(),
4150 args: cmd.args,
4151 cwd: cmd.cwd.map(|p| p.to_string_lossy().to_string()),
4152 direction: None, hold_on_close: cmd.hold_on_close,
4154 hold_on_start: cmd.hold_on_start,
4155 originating_plugin: cmd.originating_plugin.map(|op| op.into()),
4156 use_terminal_title: cmd.use_terminal_title,
4157 },
4158 )),
4159 },
4160 crate::input::layout::Run::Plugin(plugin) => Self {
4161 run_type: Some(RunType::Plugin(plugin.into())),
4162 },
4163 crate::input::layout::Run::EditFile(path, line_number, cwd) => Self {
4164 run_type: Some(RunType::EditFile(
4165 crate::client_server_contract::client_server_contract::RunEditFileAction {
4166 file_path: path.to_string_lossy().to_string(),
4167 line_number: line_number.map(|n| n as u32),
4168 cwd: cwd.map(|p| p.to_string_lossy().to_string()),
4169 },
4170 )),
4171 },
4172 crate::input::layout::Run::Cwd(path) => Self {
4173 run_type: Some(RunType::Cwd(path.to_string_lossy().to_string())),
4174 },
4175 }
4176 }
4177}
4178
4179impl From<crate::input::layout::TabLayoutInfo>
4181 for crate::client_server_contract::client_server_contract::TabLayoutInfo
4182{
4183 fn from(tab_info: crate::input::layout::TabLayoutInfo) -> Self {
4184 Self {
4185 tab_index: tab_info.tab_index as u32,
4186 tab_name: tab_info.tab_name,
4187 tiled_layout: Some(tab_info.tiled_layout.into()),
4188 floating_layouts: tab_info
4189 .floating_layouts
4190 .into_iter()
4191 .map(|l| l.into())
4192 .collect(),
4193 swap_tiled_layouts: tab_info
4194 .swap_tiled_layouts
4195 .unwrap_or_default()
4196 .into_iter()
4197 .map(|l| l.into())
4198 .collect(),
4199 swap_floating_layouts: tab_info
4200 .swap_floating_layouts
4201 .unwrap_or_default()
4202 .into_iter()
4203 .map(|l| l.into())
4204 .collect(),
4205 }
4206 }
4207}
4208
4209impl TryFrom<crate::client_server_contract::client_server_contract::TabLayoutInfo>
4210 for crate::input::layout::TabLayoutInfo
4211{
4212 type Error = anyhow::Error;
4213
4214 fn try_from(
4215 protobuf_tab: crate::client_server_contract::client_server_contract::TabLayoutInfo,
4216 ) -> Result<Self> {
4217 Ok(crate::input::layout::TabLayoutInfo {
4218 tab_index: protobuf_tab.tab_index as usize,
4219 tab_name: protobuf_tab.tab_name.filter(|s| !s.is_empty()),
4220 tiled_layout: protobuf_tab
4221 .tiled_layout
4222 .ok_or_else(|| anyhow!("missing tiled_layout"))?
4223 .try_into()?,
4224 floating_layouts: protobuf_tab
4225 .floating_layouts
4226 .into_iter()
4227 .map(|l| l.try_into())
4228 .collect::<Result<Vec<_>>>()?,
4229 swap_tiled_layouts: if protobuf_tab.swap_tiled_layouts.is_empty() {
4230 None
4231 } else {
4232 Some(
4233 protobuf_tab
4234 .swap_tiled_layouts
4235 .into_iter()
4236 .map(|l| l.try_into())
4237 .collect::<Result<Vec<_>>>()?,
4238 )
4239 },
4240 swap_floating_layouts: if protobuf_tab.swap_floating_layouts.is_empty() {
4241 None
4242 } else {
4243 Some(
4244 protobuf_tab
4245 .swap_floating_layouts
4246 .into_iter()
4247 .map(|l| l.try_into())
4248 .collect::<Result<Vec<_>>>()?,
4249 )
4250 },
4251 })
4252 }
4253}
4254
4255impl From<crate::input::layout::TiledPaneLayout>
4257 for crate::client_server_contract::client_server_contract::TiledPaneLayout
4258{
4259 fn from(layout: crate::input::layout::TiledPaneLayout) -> Self {
4260 Self {
4261 children_split_direction: split_direction_to_proto_i32(layout.children_split_direction),
4262 name: layout.name,
4263 children: layout.children.into_iter().map(|c| c.into()).collect(),
4264 split_size: layout.split_size.map(|s| s.into()),
4265 run: layout.run.map(|r| r.into()),
4266 borderless: layout.borderless,
4267 focus: layout.focus.map(|f| f.to_string()),
4268 exclude_from_sync: layout.exclude_from_sync,
4269 children_are_stacked: layout.children_are_stacked,
4270 external_children_index: layout.external_children_index.map(|l| l as u32),
4271 is_expanded_in_stack: layout.is_expanded_in_stack,
4272 hide_floating_panes: layout.hide_floating_panes,
4273 pane_initial_contents: layout.pane_initial_contents,
4274 default_fg: layout.default_fg,
4275 default_bg: layout.default_bg,
4276 }
4277 }
4278}
4279
4280impl From<crate::input::layout::FloatingPaneLayout>
4281 for crate::client_server_contract::client_server_contract::FloatingPaneLayout
4282{
4283 fn from(layout: crate::input::layout::FloatingPaneLayout) -> Self {
4284 Self {
4285 name: layout.name,
4286 height: layout.height.map(|h| h.into()),
4287 width: layout.width.map(|w| w.into()),
4288 x: layout.x.map(|x| x.into()),
4289 y: layout.y.map(|y| y.into()),
4290 pinned: layout.pinned,
4291 run: layout.run.map(|r| r.into()),
4292 focus: layout.focus,
4293 already_running: layout.already_running,
4294 pane_initial_contents: layout.pane_initial_contents,
4295 logical_position: layout.logical_position.map(|l| l as u32),
4296 borderless: layout.borderless,
4297 default_fg: layout.default_fg,
4298 default_bg: layout.default_bg,
4299 }
4300 }
4301}
4302
4303impl From<crate::input::layout::SwapTiledLayout>
4304 for crate::client_server_contract::client_server_contract::SwapTiledLayout
4305{
4306 fn from(layout: crate::input::layout::SwapTiledLayout) -> Self {
4307 use crate::client_server_contract::client_server_contract::LayoutConstraintTiledPair;
4308
4309 let constraint_map = layout
4310 .0
4311 .into_iter()
4312 .map(|(constraint, tiled_layout)| LayoutConstraintTiledPair {
4313 constraint: Some(constraint.into()),
4314 layout: Some(tiled_layout.into()),
4315 })
4316 .collect();
4317
4318 Self {
4319 constraint_map,
4320 name: layout.1,
4321 }
4322 }
4323}
4324
4325impl From<crate::input::layout::SwapFloatingLayout>
4326 for crate::client_server_contract::client_server_contract::SwapFloatingLayout
4327{
4328 fn from(layout: crate::input::layout::SwapFloatingLayout) -> Self {
4329 use crate::client_server_contract::client_server_contract::LayoutConstraintFloatingPair;
4330
4331 let constraint_map = layout
4332 .0
4333 .into_iter()
4334 .map(
4335 |(constraint, floating_layouts)| LayoutConstraintFloatingPair {
4336 constraint: Some(constraint.into()),
4337 layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
4338 },
4339 )
4340 .collect();
4341
4342 Self {
4343 constraint_map,
4344 name: layout.1,
4345 }
4346 }
4347}
4348
4349impl From<crate::input::layout::PluginUserConfiguration>
4351 for crate::client_server_contract::client_server_contract::PluginUserConfiguration
4352{
4353 fn from(config: crate::input::layout::PluginUserConfiguration) -> Self {
4354 Self {
4355 configuration: config.inner().clone().into_iter().collect(), }
4357 }
4358}
4359
4360impl From<crate::input::layout::LayoutConstraint>
4362 for crate::client_server_contract::client_server_contract::LayoutConstraintWithValue
4363{
4364 fn from(constraint: crate::input::layout::LayoutConstraint) -> Self {
4365 use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
4366 match constraint {
4367 crate::input::layout::LayoutConstraint::MaxPanes(n) => Self {
4368 constraint_type: ProtoLayoutConstraint::MaxPanes as i32,
4369 value: Some(n as u32),
4370 },
4371 crate::input::layout::LayoutConstraint::MinPanes(n) => Self {
4372 constraint_type: ProtoLayoutConstraint::MinPanes as i32,
4373 value: Some(n as u32),
4374 },
4375 crate::input::layout::LayoutConstraint::ExactPanes(n) => Self {
4376 constraint_type: ProtoLayoutConstraint::ExactPanes as i32,
4377 value: Some(n as u32),
4378 },
4379 crate::input::layout::LayoutConstraint::NoConstraint => Self {
4380 constraint_type: ProtoLayoutConstraint::NoConstraint as i32,
4381 value: None,
4382 },
4383 }
4384 }
4385}
4386
4387impl From<crate::input::layout::RunPlugin>
4389 for crate::client_server_contract::client_server_contract::RunPlugin
4390{
4391 fn from(plugin: crate::input::layout::RunPlugin) -> Self {
4392 Self {
4393 allow_exec_host_cmd: plugin._allow_exec_host_cmd,
4394 location: Some(plugin.location.into()),
4395 configuration: Some(plugin.configuration.into()),
4396 initial_cwd: plugin.initial_cwd.map(|p| p.display().to_string()),
4397 }
4398 }
4399}
4400
4401impl From<crate::input::layout::PluginAlias>
4403 for crate::client_server_contract::client_server_contract::PluginAlias
4404{
4405 fn from(plugin: crate::input::layout::PluginAlias) -> Self {
4406 Self {
4407 name: plugin.name,
4408 configuration: plugin.configuration.map(|c| c.into()),
4409 initial_cwd: plugin.initial_cwd.map(|i| i.display().to_string()),
4410 run_plugin: plugin.run_plugin.map(|r| r.into()),
4411 }
4412 }
4413}
4414
4415impl From<crate::input::layout::RunPluginLocation>
4417 for crate::client_server_contract::client_server_contract::RunPluginLocationData
4418{
4419 fn from(location: crate::input::layout::RunPluginLocation) -> Self {
4420 use crate::client_server_contract::client_server_contract::{
4421 run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
4422 };
4423 match location {
4424 crate::input::layout::RunPluginLocation::File(path) => Self {
4425 location_type: ProtoRunPluginLocation::File as i32,
4426 location_data: Some(LocationData::FilePath(path.to_string_lossy().to_string())),
4427 },
4428 crate::input::layout::RunPluginLocation::Zellij(tag) => Self {
4429 location_type: ProtoRunPluginLocation::Zellij as i32,
4430 location_data: Some(LocationData::ZellijTag(
4431 crate::client_server_contract::client_server_contract::PluginTag {
4432 tag: tag.to_string(),
4433 },
4434 )),
4435 },
4436 crate::input::layout::RunPluginLocation::Remote(url) => Self {
4437 location_type: ProtoRunPluginLocation::Remote as i32,
4438 location_data: Some(LocationData::RemoteUrl(url)),
4439 },
4440 }
4441 }
4442}
4443
4444impl From<crate::input::layout::RunPluginOrAlias>
4446 for crate::client_server_contract::client_server_contract::RunPluginOrAlias
4447{
4448 fn from(plugin: crate::input::layout::RunPluginOrAlias) -> Self {
4449 use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
4450 match plugin {
4451 crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin) => Self {
4452 plugin_type: Some(PluginType::Plugin(run_plugin.into())),
4453 },
4454 crate::input::layout::RunPluginOrAlias::Alias(alias) => Self {
4455 plugin_type: Some(PluginType::Alias(alias.into())),
4456 },
4457 }
4458 }
4459}
4460
4461impl From<crate::data::CommandOrPlugin>
4463 for crate::client_server_contract::client_server_contract::CommandOrPlugin
4464{
4465 fn from(cmd_or_plugin: crate::data::CommandOrPlugin) -> Self {
4466 use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
4467 use crate::client_server_contract::client_server_contract::CommandOrPluginFile;
4468 match cmd_or_plugin {
4469 crate::data::CommandOrPlugin::Command(cmd) => Self {
4470 command_or_plugin_type: Some(CommandOrPluginType::Command(cmd.into())),
4471 },
4472 crate::data::CommandOrPlugin::Plugin(plugin) => Self {
4473 command_or_plugin_type: Some(CommandOrPluginType::Plugin(plugin.into())),
4474 },
4475 crate::data::CommandOrPlugin::File(f) => Self {
4476 command_or_plugin_type: Some(CommandOrPluginType::File(CommandOrPluginFile {
4477 path: f.path.display().to_string(),
4478 line_number: f.line_number.map(|n| n as i32),
4479 cwd: f.cwd.map(|c| c.display().to_string()),
4480 })),
4481 },
4482 }
4483 }
4484}
4485
4486impl TryFrom<crate::client_server_contract::client_server_contract::CommandOrPlugin>
4487 for crate::data::CommandOrPlugin
4488{
4489 type Error = anyhow::Error;
4490
4491 fn try_from(
4492 proto: crate::client_server_contract::client_server_contract::CommandOrPlugin,
4493 ) -> Result<Self> {
4494 use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
4495
4496 let cmd_or_plugin_type = proto
4497 .command_or_plugin_type
4498 .ok_or_else(|| anyhow!("CommandOrPlugin missing command_or_plugin_type"))?;
4499 match cmd_or_plugin_type {
4500 CommandOrPluginType::Command(cmd) => {
4501 Ok(crate::data::CommandOrPlugin::Command(cmd.try_into()?))
4502 },
4503 CommandOrPluginType::Plugin(plugin) => {
4504 Ok(crate::data::CommandOrPlugin::Plugin(plugin.try_into()?))
4505 },
4506 CommandOrPluginType::File(f) => Ok(crate::data::CommandOrPlugin::File(
4507 crate::data::FileToOpen {
4508 path: std::path::PathBuf::from(&f.path),
4509 line_number: f.line_number.map(|n| n as usize),
4510 cwd: f.cwd.map(std::path::PathBuf::from),
4511 },
4512 )),
4513 }
4514 }
4515}
4516
4517impl TryFrom<crate::client_server_contract::client_server_contract::Run>
4519 for crate::input::layout::Run
4520{
4521 type Error = anyhow::Error;
4522
4523 fn try_from(run: crate::client_server_contract::client_server_contract::Run) -> Result<Self> {
4524 use crate::client_server_contract::client_server_contract::run::RunType;
4525
4526 let run_type = run
4527 .run_type
4528 .ok_or_else(|| anyhow!("Run missing run_type"))?;
4529 match run_type {
4530 RunType::Command(cmd) => Ok(crate::input::layout::Run::Command(
4531 crate::input::command::RunCommand {
4532 command: std::path::PathBuf::from(cmd.command),
4533 args: cmd.args,
4534 cwd: cmd.cwd.map(std::path::PathBuf::from),
4535 hold_on_close: cmd.hold_on_close,
4536 hold_on_start: cmd.hold_on_start,
4537 originating_plugin: cmd
4538 .originating_plugin
4539 .map(|op| op.try_into())
4540 .transpose()?,
4541 use_terminal_title: cmd.use_terminal_title,
4542 },
4543 )),
4544 RunType::EditFile(edit) => Ok(crate::input::layout::Run::EditFile(
4545 std::path::PathBuf::from(edit.file_path),
4546 edit.line_number.map(|n| n as usize),
4547 edit.cwd.map(std::path::PathBuf::from),
4548 )),
4549 RunType::Cwd(cwd_str) => Ok(crate::input::layout::Run::Cwd(std::path::PathBuf::from(
4550 cwd_str,
4551 ))),
4552 RunType::Plugin(plugin) => Ok(crate::input::layout::Run::Plugin(plugin.try_into()?)),
4553 }
4554 }
4555}
4556
4557impl TryFrom<crate::client_server_contract::client_server_contract::PercentOrFixed>
4559 for crate::input::layout::PercentOrFixed
4560{
4561 type Error = anyhow::Error;
4562
4563 fn try_from(
4564 value: crate::client_server_contract::client_server_contract::PercentOrFixed,
4565 ) -> Result<Self> {
4566 use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
4567
4568 let size_type = value
4569 .size_type
4570 .ok_or_else(|| anyhow!("PercentOrFixed missing size_type"))?;
4571 match size_type {
4572 SizeType::Percent(percent) => Ok(crate::input::layout::PercentOrFixed::Percent(
4573 percent as usize,
4574 )),
4575 SizeType::Fixed(fixed) => {
4576 Ok(crate::input::layout::PercentOrFixed::Fixed(fixed as usize))
4577 },
4578 }
4579 }
4580}
4581
4582impl TryFrom<crate::client_server_contract::client_server_contract::MouseEvent>
4586 for crate::input::mouse::MouseEvent
4587{
4588 type Error = anyhow::Error;
4589
4590 fn try_from(
4591 event: crate::client_server_contract::client_server_contract::MouseEvent,
4592 ) -> Result<Self> {
4593 use crate::client_server_contract::client_server_contract::MouseEventType as ProtoMouseEventType;
4594
4595 let event_type = match event.event_type {
4596 x if x == ProtoMouseEventType::Press as i32 => {
4597 crate::input::mouse::MouseEventType::Press
4598 },
4599 x if x == ProtoMouseEventType::Release as i32 => {
4600 crate::input::mouse::MouseEventType::Release
4601 },
4602 x if x == ProtoMouseEventType::Motion as i32 => {
4603 crate::input::mouse::MouseEventType::Motion
4604 },
4605 _ => return Err(anyhow!("Invalid MouseEventType: {}", event.event_type)),
4606 };
4607
4608 let position = event
4609 .position
4610 .ok_or_else(|| anyhow!("MouseEvent missing position"))?
4611 .try_into()?;
4612
4613 Ok(crate::input::mouse::MouseEvent {
4614 event_type,
4615 left: event.left,
4616 right: event.right,
4617 middle: event.middle,
4618 wheel_up: event.wheel_up,
4619 wheel_down: event.wheel_down,
4620 wheel_left: event.wheel_left,
4621 wheel_right: event.wheel_right,
4622 shift: event.shift,
4623 alt: event.alt,
4624 ctrl: event.ctrl,
4625 position,
4626 })
4627 }
4628}
4629
4630impl TryFrom<crate::client_server_contract::client_server_contract::RunCommandAction>
4632 for crate::input::command::RunCommandAction
4633{
4634 type Error = anyhow::Error;
4635
4636 fn try_from(
4637 action: crate::client_server_contract::client_server_contract::RunCommandAction,
4638 ) -> Result<Self> {
4639 Ok(crate::input::command::RunCommandAction {
4640 command: std::path::PathBuf::from(action.command),
4641 args: action.args,
4642 cwd: action.cwd.map(std::path::PathBuf::from),
4643 direction: action.direction.map(proto_i32_to_direction).transpose()?,
4644 hold_on_close: action.hold_on_close,
4645 hold_on_start: action.hold_on_start,
4646 originating_plugin: action
4647 .originating_plugin
4648 .map(|op| op.try_into())
4649 .transpose()?,
4650 use_terminal_title: action.use_terminal_title,
4651 })
4652 }
4653}
4654
4655impl TryFrom<crate::client_server_contract::client_server_contract::TiledPaneLayout>
4657 for crate::input::layout::TiledPaneLayout
4658{
4659 type Error = anyhow::Error;
4660
4661 fn try_from(
4662 layout: crate::client_server_contract::client_server_contract::TiledPaneLayout,
4663 ) -> Result<Self> {
4664 use crate::input::layout::{SplitDirection, SplitSize, TiledPaneLayout};
4665
4666 let children_split_direction = match layout.children_split_direction {
4667 x if x
4668 == crate::client_server_contract::client_server_contract::SplitDirection::Horizontal
4669 as i32 =>
4670 {
4671 SplitDirection::Horizontal
4672 },
4673 x if x
4674 == crate::client_server_contract::client_server_contract::SplitDirection::Vertical
4675 as i32 =>
4676 {
4677 SplitDirection::Vertical
4678 },
4679 _ => SplitDirection::Horizontal, };
4681
4682 let children: Result<Vec<_>> = layout.children.into_iter().map(|c| c.try_into()).collect();
4683 let run = layout.run.map(|r| r.try_into()).transpose()?;
4684
4685 let split_size = layout.split_size.and_then(|size| {
4686 use crate::client_server_contract::client_server_contract::split_size::SizeType;
4687 match size.size_type {
4688 Some(SizeType::Percent(percent)) => Some(SplitSize::Percent(percent as usize)),
4689 Some(SizeType::Fixed(fixed)) => Some(SplitSize::Fixed(fixed as usize)),
4690 None => None,
4691 }
4692 });
4693
4694 Ok(TiledPaneLayout {
4695 children_split_direction,
4696 name: layout.name,
4697 children: children?,
4698 split_size,
4699 run,
4700 borderless: layout.borderless,
4701 focus: layout.focus.map(|f| f == "true"), external_children_index: layout.external_children_index.map(|l| l as usize),
4703 children_are_stacked: layout.children_are_stacked,
4704 is_expanded_in_stack: layout.is_expanded_in_stack,
4705 exclude_from_sync: layout.exclude_from_sync,
4706 run_instructions_to_ignore: vec![], hide_floating_panes: layout.hide_floating_panes,
4708 pane_initial_contents: layout.pane_initial_contents,
4709 default_fg: layout.default_fg,
4710 default_bg: layout.default_bg,
4711 })
4712 }
4713}
4714
4715impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneLayout>
4717 for crate::input::layout::FloatingPaneLayout
4718{
4719 type Error = anyhow::Error;
4720
4721 fn try_from(
4722 layout: crate::client_server_contract::client_server_contract::FloatingPaneLayout,
4723 ) -> Result<Self> {
4724 let run = layout.run.map(|r| r.try_into()).transpose()?;
4725 let height = layout.height.map(|h| h.try_into()).transpose()?;
4726 let width = layout.width.map(|w| w.try_into()).transpose()?;
4727 let x = layout.x.map(|x| x.try_into()).transpose()?;
4728 let y = layout.y.map(|y| y.try_into()).transpose()?;
4729
4730 Ok(crate::input::layout::FloatingPaneLayout {
4731 name: layout.name,
4732 height,
4733 width,
4734 x,
4735 y,
4736 pinned: layout.pinned,
4737 run,
4738 focus: layout.focus,
4739 already_running: layout.already_running,
4740 pane_initial_contents: layout.pane_initial_contents,
4741 logical_position: layout.logical_position.map(|p| p as usize),
4742 borderless: layout.borderless,
4743 default_fg: layout.default_fg,
4744 default_bg: layout.default_bg,
4745 })
4746 }
4747}
4748
4749impl TryFrom<crate::client_server_contract::client_server_contract::SwapTiledLayout>
4751 for crate::input::layout::SwapTiledLayout
4752{
4753 type Error = anyhow::Error;
4754
4755 fn try_from(
4756 layout: crate::client_server_contract::client_server_contract::SwapTiledLayout,
4757 ) -> Result<Self> {
4758 let constraint_map: Result<BTreeMap<_, _>> = layout
4759 .constraint_map
4760 .into_iter()
4761 .map(|pair| {
4762 Ok((
4763 pair.constraint
4764 .ok_or_else(|| anyhow!("Missing constraint"))?
4765 .try_into()?,
4766 pair.layout
4767 .ok_or_else(|| anyhow!("Missing layout"))?
4768 .try_into()?,
4769 ))
4770 })
4771 .collect();
4772 Ok((constraint_map?, layout.name))
4773 }
4774}
4775
4776impl TryFrom<crate::client_server_contract::client_server_contract::SwapFloatingLayout>
4778 for crate::input::layout::SwapFloatingLayout
4779{
4780 type Error = anyhow::Error;
4781
4782 fn try_from(
4783 layout: crate::client_server_contract::client_server_contract::SwapFloatingLayout,
4784 ) -> Result<Self> {
4785 let constraint_map: Result<BTreeMap<_, _>> = layout
4786 .constraint_map
4787 .into_iter()
4788 .map(|pair| {
4789 let floating_layouts: Result<Vec<_>> =
4790 pair.layouts.into_iter().map(|l| l.try_into()).collect();
4791 Ok((
4792 pair.constraint
4793 .ok_or_else(|| anyhow!("Missing constraint"))?
4794 .try_into()?,
4795 floating_layouts?,
4796 ))
4797 })
4798 .collect();
4799
4800 Ok((constraint_map?, layout.name))
4801 }
4802}
4803
4804impl TryFrom<crate::client_server_contract::client_server_contract::PluginUserConfiguration>
4806 for crate::input::layout::PluginUserConfiguration
4807{
4808 type Error = anyhow::Error;
4809
4810 fn try_from(
4811 config: crate::client_server_contract::client_server_contract::PluginUserConfiguration,
4812 ) -> Result<Self> {
4813 let btree_map: BTreeMap<String, String> = config.configuration.into_iter().collect();
4814 Ok(crate::input::layout::PluginUserConfiguration::new(
4815 btree_map,
4816 ))
4817 }
4818}
4819
4820impl TryFrom<crate::client_server_contract::client_server_contract::LayoutConstraintWithValue>
4822 for crate::input::layout::LayoutConstraint
4823{
4824 type Error = anyhow::Error;
4825
4826 fn try_from(
4827 constraint: crate::client_server_contract::client_server_contract::LayoutConstraintWithValue,
4828 ) -> Result<Self> {
4829 use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
4830 match constraint.constraint_type {
4831 x if x == ProtoLayoutConstraint::MaxPanes as i32 => {
4832 let value = constraint
4833 .value
4834 .ok_or_else(|| anyhow!("MaxPanes constraint missing value"))?
4835 as usize;
4836 Ok(crate::input::layout::LayoutConstraint::MaxPanes(value))
4837 },
4838 x if x == ProtoLayoutConstraint::MinPanes as i32 => {
4839 let value = constraint
4840 .value
4841 .ok_or_else(|| anyhow!("MinPanes constraint missing value"))?
4842 as usize;
4843 Ok(crate::input::layout::LayoutConstraint::MinPanes(value))
4844 },
4845 x if x == ProtoLayoutConstraint::ExactPanes as i32 => {
4846 let value = constraint
4847 .value
4848 .ok_or_else(|| anyhow!("ExactPanes constraint missing value"))?
4849 as usize;
4850 Ok(crate::input::layout::LayoutConstraint::ExactPanes(value))
4851 },
4852 x if x == ProtoLayoutConstraint::NoConstraint as i32 => {
4853 Ok(crate::input::layout::LayoutConstraint::NoConstraint)
4854 },
4855 _ => Err(anyhow!(
4856 "Invalid LayoutConstraint type: {}",
4857 constraint.constraint_type
4858 )),
4859 }
4860 }
4861}
4862
4863impl TryFrom<crate::client_server_contract::client_server_contract::RunPlugin>
4865 for crate::input::layout::RunPlugin
4866{
4867 type Error = anyhow::Error;
4868
4869 fn try_from(
4870 plugin: crate::client_server_contract::client_server_contract::RunPlugin,
4871 ) -> Result<Self> {
4872 let location = plugin
4873 .location
4874 .ok_or_else(|| anyhow!("RunPlugin missing location"))?
4875 .try_into()?;
4876 let configuration = plugin
4877 .configuration
4878 .ok_or_else(|| anyhow!("RunPlugin missing configuration"))?
4879 .try_into()?;
4880 let initial_cwd = plugin.initial_cwd.map(std::path::PathBuf::from);
4881
4882 Ok(crate::input::layout::RunPlugin {
4883 _allow_exec_host_cmd: plugin.allow_exec_host_cmd,
4884 location,
4885 configuration,
4886 initial_cwd,
4887 })
4888 }
4889}
4890
4891impl TryFrom<crate::client_server_contract::client_server_contract::PluginAlias>
4893 for crate::input::layout::PluginAlias
4894{
4895 type Error = anyhow::Error;
4896
4897 fn try_from(
4898 plugin_alias: crate::client_server_contract::client_server_contract::PluginAlias,
4899 ) -> Result<Self> {
4900 let run_plugin = plugin_alias.run_plugin.and_then(|r| r.try_into().ok());
4901 let configuration = plugin_alias.configuration.and_then(|c| c.try_into().ok());
4902 let initial_cwd = plugin_alias.initial_cwd.map(std::path::PathBuf::from);
4903 Ok(crate::input::layout::PluginAlias {
4904 name: plugin_alias.name,
4905 configuration,
4906 initial_cwd,
4907 run_plugin,
4908 })
4909 }
4910}
4911
4912impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginLocationData>
4914 for crate::input::layout::RunPluginLocation
4915{
4916 type Error = anyhow::Error;
4917
4918 fn try_from(
4919 location: crate::client_server_contract::client_server_contract::RunPluginLocationData,
4920 ) -> Result<Self> {
4921 use crate::client_server_contract::client_server_contract::{
4922 run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
4923 };
4924
4925 let location_data = location
4926 .location_data
4927 .ok_or_else(|| anyhow!("RunPluginLocationData missing location_data"))?;
4928 match location.location_type {
4929 x if x == ProtoRunPluginLocation::File as i32 => {
4930 if let LocationData::FilePath(path) = location_data {
4931 Ok(crate::input::layout::RunPluginLocation::File(
4932 std::path::PathBuf::from(path),
4933 ))
4934 } else {
4935 Err(anyhow!("File location type but wrong data variant"))
4936 }
4937 },
4938 x if x == ProtoRunPluginLocation::Zellij as i32 => {
4939 if let LocationData::ZellijTag(tag) = location_data {
4940 Ok(crate::input::layout::RunPluginLocation::Zellij(
4941 crate::data::PluginTag::new(tag.tag),
4942 ))
4943 } else {
4944 Err(anyhow!("Zellij location type but wrong data variant"))
4945 }
4946 },
4947 x if x == ProtoRunPluginLocation::Remote as i32 => {
4948 if let LocationData::RemoteUrl(url) = location_data {
4949 Ok(crate::input::layout::RunPluginLocation::Remote(url))
4950 } else {
4951 Err(anyhow!("Remote location type but wrong data variant"))
4952 }
4953 },
4954 _ => Err(anyhow!(
4955 "Invalid RunPluginLocation type: {}",
4956 location.location_type
4957 )),
4958 }
4959 }
4960}
4961
4962impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginOrAlias>
4964 for crate::input::layout::RunPluginOrAlias
4965{
4966 type Error = anyhow::Error;
4967
4968 fn try_from(
4969 plugin: crate::client_server_contract::client_server_contract::RunPluginOrAlias,
4970 ) -> Result<Self> {
4971 use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
4972
4973 let plugin_type = plugin
4974 .plugin_type
4975 .ok_or_else(|| anyhow!("RunPluginOrAlias missing plugin_type"))?;
4976 match plugin_type {
4977 PluginType::Plugin(run_plugin) => Ok(
4978 crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin.try_into()?),
4979 ),
4980 PluginType::Alias(plugin_alias) => Ok(crate::input::layout::RunPluginOrAlias::Alias(
4981 plugin_alias.try_into()?,
4982 )),
4983 }
4984 }
4985}