1pub use super::generated_api::api::{
2 action::{Action as ProtobufAction, Position as ProtobufPosition},
3 event::{
4 event::Payload as ProtobufEventPayload,
5 layout_parsing_error::ErrorType as ProtobufLayoutParsingErrorType,
6 pane_scrollback_response, ActionCompletePayload as ProtobufActionCompletePayload,
7 AvailableLayoutInfoPayload as ProtobufAvailableLayoutInfoPayload,
8 ClientInfo as ProtobufClientInfo, ClientPaneHistory as ProtobufClientPaneHistory,
9 ClientTabHistory as ProtobufClientTabHistory, ContextItem as ProtobufContextItem,
10 CopyDestination as ProtobufCopyDestination, CwdChangedPayload as ProtobufCwdChangedPayload,
11 Event as ProtobufEvent, EventNameList as ProtobufEventNameList,
12 EventType as ProtobufEventType, FileMetadata as ProtobufFileMetadata,
13 InputModeKeybinds as ProtobufInputModeKeybinds, KdlError as ProtobufKdlError,
14 KdlErrorVariant as ProtobufKdlErrorVariant, KeyBind as ProtobufKeyBind,
15 LayoutInfo as ProtobufLayoutInfo, LayoutMetadata as ProtobufLayoutMetadata,
16 LayoutParsingError as ProtobufLayoutParsingError,
17 LayoutWithError as ProtobufLayoutWithError, ModeUpdatePayload as ProtobufModeUpdatePayload,
18 PaneContents as ProtobufPaneContents, PaneContentsEntry as ProtobufPaneContentsEntry,
19 PaneId as ProtobufPaneId, PaneInfo as ProtobufPaneInfo,
20 PaneManifest as ProtobufPaneManifest, PaneMetadata as ProtobufPaneMetadata,
21 PaneRenderReportPayload as ProtobufPaneRenderReportPayload,
22 PaneScrollbackResponse as ProtobufPaneScrollbackResponse, PaneType as ProtobufPaneType,
23 PluginConfigurationChangedPayload as ProtobufPluginConfigurationChangedPayload,
24 PluginInfo as ProtobufPluginInfo, ResurrectableSession as ProtobufResurrectableSession,
25 SelectedText as ProtobufSelectedText, SessionManifest as ProtobufSessionManifest,
26 SyntaxError as ProtobufSyntaxError, TabInfo as ProtobufTabInfo,
27 TabMetadata as ProtobufTabMetadata, UserActionPayload as ProtobufUserActionPayload,
28 WebServerStatusPayload as ProtobufWebServerStatusPayload, WebSharing as ProtobufWebSharing,
29 *,
30 },
31 input_mode::InputMode as ProtobufInputMode,
32 key::Key as ProtobufKey,
33 style::Style as ProtobufStyle,
34};
35#[allow(hidden_glob_reexports)]
36use crate::data::{
37 ClientId, ClientInfo, CopyDestination, Event, EventType, FileMetadata, InputMode,
38 KeyWithModifier, LayoutInfo, LayoutMetadata, ModeInfo, Mouse, PaneContents, PaneId, PaneInfo,
39 PaneManifest, PaneMetadata, PaneScrollbackResponse, PermissionStatus, PluginCapabilities,
40 PluginInfo, SelectedText, SessionInfo, Style, TabInfo, TabMetadata, WebServerStatus,
41 WebSharing,
42};
43
44use crate::errors::prelude::*;
45use crate::input::actions::Action;
46
47use std::collections::{BTreeMap, HashMap, HashSet};
48use std::convert::TryFrom;
49use std::net::IpAddr;
50use std::path::PathBuf;
51use std::str::FromStr;
52use std::time::Duration;
53
54impl TryFrom<ProtobufEvent> for Event {
55 type Error = &'static str;
56 fn try_from(protobuf_event: ProtobufEvent) -> Result<Self, &'static str> {
57 match ProtobufEventType::from_i32(protobuf_event.name) {
58 Some(ProtobufEventType::ModeUpdate) => match protobuf_event.payload {
59 Some(ProtobufEventPayload::ModeUpdatePayload(protobuf_mode_update_payload)) => {
60 let mode_info: ModeInfo = protobuf_mode_update_payload.try_into()?;
61 Ok(Event::ModeUpdate(mode_info))
62 },
63 _ => Err("Malformed payload for the ModeUpdate Event"),
64 },
65 Some(ProtobufEventType::TabUpdate) => match protobuf_event.payload {
66 Some(ProtobufEventPayload::TabUpdatePayload(protobuf_tab_info_payload)) => {
67 let mut tab_infos: Vec<TabInfo> = vec![];
68 for protobuf_tab_info in protobuf_tab_info_payload.tab_info {
69 tab_infos.push(TabInfo::try_from(protobuf_tab_info)?);
70 }
71 Ok(Event::TabUpdate(tab_infos))
72 },
73 _ => Err("Malformed payload for the TabUpdate Event"),
74 },
75 Some(ProtobufEventType::PaneUpdate) => match protobuf_event.payload {
76 Some(ProtobufEventPayload::PaneUpdatePayload(protobuf_pane_update_payload)) => {
77 let mut pane_manifest: HashMap<usize, Vec<PaneInfo>> = HashMap::new();
78 for protobuf_pane_manifest in protobuf_pane_update_payload.pane_manifest {
79 let tab_index = protobuf_pane_manifest.tab_index as usize;
80 let mut panes = vec![];
81 for protobuf_pane_info in protobuf_pane_manifest.panes {
82 panes.push(protobuf_pane_info.try_into()?);
83 }
84 if pane_manifest.contains_key(&tab_index) {
85 return Err("Duplicate tab definition in pane manifest");
86 }
87 pane_manifest.insert(tab_index, panes);
88 }
89 Ok(Event::PaneUpdate(PaneManifest {
90 panes: pane_manifest,
91 }))
92 },
93 _ => Err("Malformed payload for the PaneUpdate Event"),
94 },
95 Some(ProtobufEventType::Key) => match protobuf_event.payload {
96 Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => {
97 Ok(Event::Key(protobuf_key.try_into()?))
98 },
99 _ => Err("Malformed payload for the Key Event"),
100 },
101 Some(ProtobufEventType::Mouse) => match protobuf_event.payload {
102 Some(ProtobufEventPayload::MouseEventPayload(protobuf_mouse)) => {
103 Ok(Event::Mouse(protobuf_mouse.try_into()?))
104 },
105 _ => Err("Malformed payload for the Mouse Event"),
106 },
107 Some(ProtobufEventType::Timer) => match protobuf_event.payload {
108 Some(ProtobufEventPayload::TimerPayload(seconds)) => {
109 Ok(Event::Timer(seconds as f64))
110 },
111 _ => Err("Malformed payload for the Timer Event"),
112 },
113 Some(ProtobufEventType::CopyToClipboard) => match protobuf_event.payload {
114 Some(ProtobufEventPayload::CopyToClipboardPayload(copy_to_clipboard)) => {
115 let protobuf_copy_to_clipboard =
116 ProtobufCopyDestination::from_i32(copy_to_clipboard)
117 .ok_or("Malformed copy to clipboard payload")?;
118 Ok(Event::CopyToClipboard(
119 protobuf_copy_to_clipboard.try_into()?,
120 ))
121 },
122 _ => Err("Malformed payload for the Copy To Clipboard Event"),
123 },
124 Some(ProtobufEventType::SystemClipboardFailure) => match protobuf_event.payload {
125 None => Ok(Event::SystemClipboardFailure),
126 _ => Err("Malformed payload for the system clipboard failure Event"),
127 },
128 Some(ProtobufEventType::InputReceived) => match protobuf_event.payload {
129 None => Ok(Event::InputReceived),
130 _ => Err("Malformed payload for the input received Event"),
131 },
132 Some(ProtobufEventType::Visible) => match protobuf_event.payload {
133 Some(ProtobufEventPayload::VisiblePayload(is_visible)) => {
134 Ok(Event::Visible(is_visible))
135 },
136 _ => Err("Malformed payload for the visible Event"),
137 },
138 Some(ProtobufEventType::CustomMessage) => match protobuf_event.payload {
139 Some(ProtobufEventPayload::CustomMessagePayload(custom_message_payload)) => {
140 Ok(Event::CustomMessage(
141 custom_message_payload.message_name,
142 custom_message_payload.payload,
143 ))
144 },
145 _ => Err("Malformed payload for the custom message Event"),
146 },
147 Some(ProtobufEventType::FileSystemCreate) => match protobuf_event.payload {
148 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
149 let file_paths = file_list_payload
150 .paths
151 .iter()
152 .zip(file_list_payload.paths_metadata.iter())
153 .map(|(p, m)| (PathBuf::from(p), m.into()))
154 .collect();
155 Ok(Event::FileSystemCreate(file_paths))
156 },
157 _ => Err("Malformed payload for the file system create Event"),
158 },
159 Some(ProtobufEventType::FileSystemRead) => match protobuf_event.payload {
160 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
161 let file_paths = file_list_payload
162 .paths
163 .iter()
164 .zip(file_list_payload.paths_metadata.iter())
165 .map(|(p, m)| (PathBuf::from(p), m.into()))
166 .collect();
167 Ok(Event::FileSystemRead(file_paths))
168 },
169 _ => Err("Malformed payload for the file system read Event"),
170 },
171 Some(ProtobufEventType::FileSystemUpdate) => match protobuf_event.payload {
172 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
173 let file_paths = file_list_payload
174 .paths
175 .iter()
176 .zip(file_list_payload.paths_metadata.iter())
177 .map(|(p, m)| (PathBuf::from(p), m.into()))
178 .collect();
179 Ok(Event::FileSystemUpdate(file_paths))
180 },
181 _ => Err("Malformed payload for the file system update Event"),
182 },
183 Some(ProtobufEventType::FileSystemDelete) => match protobuf_event.payload {
184 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
185 let file_paths = file_list_payload
186 .paths
187 .iter()
188 .zip(file_list_payload.paths_metadata.iter())
189 .map(|(p, m)| (PathBuf::from(p), m.into()))
190 .collect();
191 Ok(Event::FileSystemDelete(file_paths))
192 },
193 _ => Err("Malformed payload for the file system delete Event"),
194 },
195 Some(ProtobufEventType::PermissionRequestResult) => match protobuf_event.payload {
196 Some(ProtobufEventPayload::PermissionRequestResultPayload(payload)) => {
197 if payload.granted {
198 Ok(Event::PermissionRequestResult(PermissionStatus::Granted))
199 } else {
200 Ok(Event::PermissionRequestResult(PermissionStatus::Denied))
201 }
202 },
203 _ => Err("Malformed payload for the file system delete Event"),
204 },
205 Some(ProtobufEventType::SessionUpdate) => match protobuf_event.payload {
206 Some(ProtobufEventPayload::SessionUpdatePayload(
207 protobuf_session_update_payload,
208 )) => {
209 let mut session_infos: Vec<SessionInfo> = vec![];
210 let mut resurrectable_sessions: Vec<(String, Duration)> = vec![];
211 for protobuf_session_info in protobuf_session_update_payload.session_manifests {
212 session_infos.push(SessionInfo::try_from(protobuf_session_info)?);
213 }
214 for protobuf_resurrectable_session in
215 protobuf_session_update_payload.resurrectable_sessions
216 {
217 resurrectable_sessions.push(protobuf_resurrectable_session.into());
218 }
219 Ok(Event::SessionUpdate(
220 session_infos,
221 resurrectable_sessions.into(),
222 ))
223 },
224 _ => Err("Malformed payload for the SessionUpdate Event"),
225 },
226 Some(ProtobufEventType::RunCommandResult) => match protobuf_event.payload {
227 Some(ProtobufEventPayload::RunCommandResultPayload(run_command_result_payload)) => {
228 Ok(Event::RunCommandResult(
229 run_command_result_payload.exit_code,
230 run_command_result_payload.stdout,
231 run_command_result_payload.stderr,
232 run_command_result_payload
233 .context
234 .into_iter()
235 .map(|c_i| (c_i.name, c_i.value))
236 .collect(),
237 ))
238 },
239 _ => Err("Malformed payload for the RunCommandResult Event"),
240 },
241 Some(ProtobufEventType::WebRequestResult) => match protobuf_event.payload {
242 Some(ProtobufEventPayload::WebRequestResultPayload(web_request_result_payload)) => {
243 Ok(Event::WebRequestResult(
244 web_request_result_payload.status as u16,
245 web_request_result_payload
246 .headers
247 .into_iter()
248 .map(|h| (h.name, h.value))
249 .collect(),
250 web_request_result_payload.body,
251 web_request_result_payload
252 .context
253 .into_iter()
254 .map(|c_i| (c_i.name, c_i.value))
255 .collect(),
256 ))
257 },
258 _ => Err("Malformed payload for the WebRequestResult Event"),
259 },
260 Some(ProtobufEventType::CommandPaneOpened) => match protobuf_event.payload {
261 Some(ProtobufEventPayload::CommandPaneOpenedPayload(
262 command_pane_opened_payload,
263 )) => Ok(Event::CommandPaneOpened(
264 command_pane_opened_payload.terminal_pane_id,
265 command_pane_opened_payload
266 .context
267 .into_iter()
268 .map(|c_i| (c_i.name, c_i.value))
269 .collect(),
270 )),
271 _ => Err("Malformed payload for the CommandPaneOpened Event"),
272 },
273 Some(ProtobufEventType::CommandPaneExited) => match protobuf_event.payload {
274 Some(ProtobufEventPayload::CommandPaneExitedPayload(
275 command_pane_exited_payload,
276 )) => Ok(Event::CommandPaneExited(
277 command_pane_exited_payload.terminal_pane_id,
278 command_pane_exited_payload.exit_code,
279 command_pane_exited_payload
280 .context
281 .into_iter()
282 .map(|c_i| (c_i.name, c_i.value))
283 .collect(),
284 )),
285 _ => Err("Malformed payload for the CommandPaneExited Event"),
286 },
287 Some(ProtobufEventType::PaneClosed) => match protobuf_event.payload {
288 Some(ProtobufEventPayload::PaneClosedPayload(pane_closed_payload)) => {
289 let pane_id = pane_closed_payload
290 .pane_id
291 .ok_or("Malformed payload for the PaneClosed Event")?;
292 Ok(Event::PaneClosed(PaneId::try_from(pane_id)?))
293 },
294 _ => Err("Malformed payload for the PaneClosed Event"),
295 },
296 Some(ProtobufEventType::EditPaneOpened) => match protobuf_event.payload {
297 Some(ProtobufEventPayload::EditPaneOpenedPayload(command_pane_opened_payload)) => {
298 Ok(Event::EditPaneOpened(
299 command_pane_opened_payload.terminal_pane_id,
300 command_pane_opened_payload
301 .context
302 .into_iter()
303 .map(|c_i| (c_i.name, c_i.value))
304 .collect(),
305 ))
306 },
307 _ => Err("Malformed payload for the EditPaneOpened Event"),
308 },
309 Some(ProtobufEventType::EditPaneExited) => match protobuf_event.payload {
310 Some(ProtobufEventPayload::EditPaneExitedPayload(command_pane_exited_payload)) => {
311 Ok(Event::EditPaneExited(
312 command_pane_exited_payload.terminal_pane_id,
313 command_pane_exited_payload.exit_code,
314 command_pane_exited_payload
315 .context
316 .into_iter()
317 .map(|c_i| (c_i.name, c_i.value))
318 .collect(),
319 ))
320 },
321 _ => Err("Malformed payload for the EditPaneExited Event"),
322 },
323 Some(ProtobufEventType::CommandPaneReRun) => match protobuf_event.payload {
324 Some(ProtobufEventPayload::CommandPaneRerunPayload(command_pane_rerun_payload)) => {
325 Ok(Event::CommandPaneReRun(
326 command_pane_rerun_payload.terminal_pane_id,
327 command_pane_rerun_payload
328 .context
329 .into_iter()
330 .map(|c_i| (c_i.name, c_i.value))
331 .collect(),
332 ))
333 },
334 _ => Err("Malformed payload for the CommandPaneReRun Event"),
335 },
336 Some(ProtobufEventType::FailedToWriteConfigToDisk) => match protobuf_event.payload {
337 Some(ProtobufEventPayload::FailedToWriteConfigToDiskPayload(
338 failed_to_write_configuration_payload,
339 )) => Ok(Event::FailedToWriteConfigToDisk(
340 failed_to_write_configuration_payload.file_path,
341 )),
342 _ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
343 },
344 Some(ProtobufEventType::ListClients) => match protobuf_event.payload {
345 Some(ProtobufEventPayload::ListClientsPayload(mut list_clients_payload)) => {
346 Ok(Event::ListClients(
347 list_clients_payload
348 .client_info
349 .drain(..)
350 .filter_map(|c| c.try_into().ok())
351 .collect(),
352 ))
353 },
354 _ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
355 },
356 Some(ProtobufEventType::HostFolderChanged) => match protobuf_event.payload {
357 Some(ProtobufEventPayload::HostFolderChangedPayload(
358 host_folder_changed_payload,
359 )) => Ok(Event::HostFolderChanged(PathBuf::from(
360 host_folder_changed_payload.new_host_folder_path,
361 ))),
362 _ => Err("Malformed payload for the HostFolderChanged Event"),
363 },
364 Some(ProtobufEventType::FailedToChangeHostFolder) => match protobuf_event.payload {
365 Some(ProtobufEventPayload::FailedToChangeHostFolderPayload(
366 failed_to_change_host_folder_payload,
367 )) => Ok(Event::FailedToChangeHostFolder(
368 failed_to_change_host_folder_payload.error_message,
369 )),
370 _ => Err("Malformed payload for the FailedToChangeHostFolder Event"),
371 },
372 Some(ProtobufEventType::PastedText) => match protobuf_event.payload {
373 Some(ProtobufEventPayload::PastedTextPayload(pasted_text_payload)) => {
374 Ok(Event::PastedText(pasted_text_payload.pasted_text))
375 },
376 _ => Err("Malformed payload for the PastedText Event"),
377 },
378 Some(ProtobufEventType::ConfigWasWrittenToDisk) => match protobuf_event.payload {
379 None => Ok(Event::ConfigWasWrittenToDisk),
380 _ => Err("Malformed payload for the ConfigWasWrittenToDisk Event"),
381 },
382 Some(ProtobufEventType::WebServerStatus) => match protobuf_event.payload {
383 Some(ProtobufEventPayload::WebServerStatusPayload(web_server_status)) => {
384 Ok(Event::WebServerStatus(web_server_status.try_into()?))
385 },
386 _ => Err("Malformed payload for the WebServerStatus Event"),
387 },
388 Some(ProtobufEventType::BeforeClose) => match protobuf_event.payload {
389 None => Ok(Event::BeforeClose),
390 _ => Err("Malformed payload for the BeforeClose Event"),
391 },
392 Some(ProtobufEventType::FailedToStartWebServer) => match protobuf_event.payload {
393 Some(ProtobufEventPayload::FailedToStartWebServerPayload(
394 failed_to_start_web_server_payload,
395 )) => Ok(Event::FailedToStartWebServer(
396 failed_to_start_web_server_payload.error,
397 )),
398 _ => Err("Malformed payload for the FailedToStartWebServer Event"),
399 },
400 Some(ProtobufEventType::InterceptedKeyPress) => match protobuf_event.payload {
401 Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => {
402 Ok(Event::InterceptedKeyPress(protobuf_key.try_into()?))
403 },
404 _ => Err("Malformed payload for the InterceptedKeyPress Event"),
405 },
406 Some(ProtobufEventType::PaneRenderReport) => match protobuf_event.payload {
407 Some(ProtobufEventPayload::PaneRenderReportPayload(protobuf_payload)) => {
408 Ok(Event::PaneRenderReport(protobuf_payload.try_into()?))
409 },
410 _ => Err("Malformed payload for the PaneRenderReport Event"),
411 },
412 Some(ProtobufEventType::PaneRenderReportWithAnsi) => match protobuf_event.payload {
413 Some(ProtobufEventPayload::PaneRenderReportWithAnsiPayload(protobuf_payload)) => {
414 Ok(Event::PaneRenderReportWithAnsi(
415 protobuf_payload.try_into()?,
416 ))
417 },
418 _ => Err("Malformed payload for the PaneRenderReportWithAnsi Event"),
419 },
420 Some(ProtobufEventType::UserAction) => match protobuf_event.payload {
421 Some(ProtobufEventPayload::UserActionPayload(protobuf_payload)) => {
422 let action: Action = protobuf_payload
423 .action
424 .ok_or("Missing action in UserAction payload")?
425 .try_into()
426 .map_err(|_| "Failed to convert Action in UserAction payload")?;
427 let client_id = protobuf_payload.client_id as u16;
428 let terminal_id = protobuf_payload.terminal_id;
429 let cli_client_id = protobuf_payload.cli_client_id.map(|id| id as u16);
430 Ok(Event::UserAction(
431 action,
432 client_id,
433 terminal_id,
434 cli_client_id,
435 ))
436 },
437 _ => Err("Malformed payload for the UserAction Event"),
438 },
439 Some(ProtobufEventType::ActionComplete) => match protobuf_event.payload {
440 Some(ProtobufEventPayload::ActionCompletePayload(protobuf_payload)) => {
441 let action: Action = protobuf_payload
442 .action
443 .ok_or("Missing action in ActionComplete payload")?
444 .try_into()
445 .map_err(|_| "Failed to convert Action in ActionComplete payload")?;
446 let pane_id = protobuf_payload
447 .pane_id
448 .map(|id| id.try_into())
449 .transpose()
450 .map_err(|_| "Failed to convert PaneId in ActionComplete payload")?;
451 let context: BTreeMap<String, String> = protobuf_payload
452 .context
453 .into_iter()
454 .map(|item| (item.name, item.value))
455 .collect();
456 Ok(Event::ActionComplete(action, pane_id, context))
457 },
458 _ => Err("Malformed payload for the ActionComplete Event"),
459 },
460 Some(ProtobufEventType::CwdChanged) => match protobuf_event.payload {
461 Some(ProtobufEventPayload::CwdChangedPayload(protobuf_payload)) => {
462 let pane_id: PaneId = protobuf_payload
463 .pane_id
464 .ok_or("Missing pane_id in CwdChanged payload")?
465 .try_into()
466 .map_err(|_| "Failed to convert PaneId in CwdChanged payload")?;
467 let new_cwd = PathBuf::from(protobuf_payload.new_cwd);
468 let focused_client_ids: Vec<ClientId> = protobuf_payload
469 .focused_client_ids
470 .into_iter()
471 .map(|id| id as u16)
472 .collect();
473 Ok(Event::CwdChanged(pane_id, new_cwd, focused_client_ids))
474 },
475 _ => Err("Malformed payload for the CwdChanged Event"),
476 },
477 Some(ProtobufEventType::AvailableLayoutInfo) => match protobuf_event.payload {
478 Some(ProtobufEventPayload::AvailableLayoutInfoPayload(
479 available_layout_info_payload,
480 )) => {
481 let mut available_layouts: Vec<LayoutInfo> = vec![];
482 let mut layouts_with_errors: Vec<crate::data::LayoutWithError> = vec![];
483
484 for protobuf_layout_info in available_layout_info_payload.available_layouts {
485 available_layouts.push(LayoutInfo::try_from(protobuf_layout_info)?);
486 }
487
488 for protobuf_error in available_layout_info_payload.layouts_with_errors {
489 layouts_with_errors
490 .push(crate::data::LayoutWithError::try_from(protobuf_error)?);
491 }
492
493 Ok(Event::AvailableLayoutInfo(
494 available_layouts,
495 layouts_with_errors,
496 ))
497 },
498 _ => Err("Malformed payload for the AvailableLayoutInfo Event"),
499 },
500 Some(ProtobufEventType::PluginConfigurationChanged) => match protobuf_event.payload {
501 Some(ProtobufEventPayload::PluginConfigurationChangedPayload(payload)) => {
502 let configuration = payload
503 .configuration
504 .into_iter()
505 .map(|item| (item.name, item.value))
506 .collect();
507 Ok(Event::PluginConfigurationChanged(configuration))
508 },
509 _ => Err("Malformed payload for PluginConfigurationChanged Event"),
510 },
511 Some(ProtobufEventType::HighlightClicked) => match protobuf_event.payload {
512 Some(ProtobufEventPayload::HighlightClickedPayload(p)) => {
513 let pane_id = p
514 .pane_id
515 .ok_or("Missing pane_id in HighlightClicked")?
516 .try_into()?;
517 let context = p
518 .context
519 .into_iter()
520 .map(|item| (item.name, item.value))
521 .collect();
522 Ok(Event::HighlightClicked {
523 pane_id,
524 pattern: p.pattern,
525 matched_string: p.matched_string,
526 context,
527 })
528 },
529 _ => Err("Malformed payload for HighlightClicked Event"),
530 },
531 Some(ProtobufEventType::InitialKeybinds) => match protobuf_event.payload {
532 Some(ProtobufEventPayload::InitialKeybindsPayload(p)) => {
533 let keybinds = p
534 .keybinds
535 .into_iter()
536 .filter_map(|imk| {
537 let mode: InputMode =
538 ProtobufInputMode::from_i32(imk.mode)?.try_into().ok()?;
539 let key_binds: Vec<(KeyWithModifier, Vec<Action>)> = imk
540 .key_bind
541 .into_iter()
542 .filter_map(|kb| {
543 let key: KeyWithModifier = kb.key?.try_into().ok()?;
544 let actions: Vec<Action> = kb
545 .action
546 .into_iter()
547 .filter_map(|a| a.try_into().ok())
548 .collect();
549 Some((key, actions))
550 })
551 .collect();
552 Some((mode, key_binds))
553 })
554 .collect();
555 Ok(Event::InitialKeybinds(keybinds))
556 },
557 _ => Err("Malformed payload for InitialKeybinds Event"),
558 },
559 None => Err("Unknown Protobuf Event"),
560 }
561 }
562}
563
564impl TryFrom<ProtobufClientInfo> for ClientInfo {
565 type Error = &'static str;
566 fn try_from(protobuf_client_info: ProtobufClientInfo) -> Result<Self, &'static str> {
567 Ok(ClientInfo::new(
568 protobuf_client_info.client_id as u16,
569 protobuf_client_info
570 .pane_id
571 .ok_or("No pane id found")?
572 .try_into()?,
573 protobuf_client_info.running_command,
574 protobuf_client_info.is_current_client,
575 ))
576 }
577}
578
579impl TryFrom<ClientInfo> for ProtobufClientInfo {
580 type Error = &'static str;
581 fn try_from(client_info: ClientInfo) -> Result<Self, &'static str> {
582 Ok(ProtobufClientInfo {
583 client_id: client_info.client_id as u32,
584 pane_id: Some(client_info.pane_id.try_into()?),
585 running_command: client_info.running_command,
586 is_current_client: client_info.is_current_client,
587 })
588 }
589}
590
591impl TryFrom<Event> for ProtobufEvent {
592 type Error = &'static str;
593 fn try_from(event: Event) -> Result<Self, &'static str> {
594 match event {
595 Event::ModeUpdate(mode_info) => {
596 let protobuf_mode_update_payload = mode_info.try_into()?;
597 Ok(ProtobufEvent {
598 name: ProtobufEventType::ModeUpdate as i32,
599 payload: Some(event::Payload::ModeUpdatePayload(
600 protobuf_mode_update_payload,
601 )),
602 })
603 },
604 Event::TabUpdate(tab_infos) => {
605 let mut protobuf_tab_infos = vec![];
606 for tab_info in tab_infos {
607 protobuf_tab_infos.push(tab_info.try_into()?);
608 }
609 let tab_update_payload = TabUpdatePayload {
610 tab_info: protobuf_tab_infos,
611 };
612 Ok(ProtobufEvent {
613 name: ProtobufEventType::TabUpdate as i32,
614 payload: Some(event::Payload::TabUpdatePayload(tab_update_payload)),
615 })
616 },
617 Event::PaneUpdate(pane_manifest) => {
618 let mut protobuf_pane_manifests = vec![];
619 for (tab_index, pane_infos) in pane_manifest.panes {
620 let mut protobuf_pane_infos = vec![];
621 for pane_info in pane_infos {
622 protobuf_pane_infos.push(pane_info.try_into()?);
623 }
624 protobuf_pane_manifests.push(ProtobufPaneManifest {
625 tab_index: tab_index as u32,
626 panes: protobuf_pane_infos,
627 });
628 }
629 Ok(ProtobufEvent {
630 name: ProtobufEventType::PaneUpdate as i32,
631 payload: Some(event::Payload::PaneUpdatePayload(PaneUpdatePayload {
632 pane_manifest: protobuf_pane_manifests,
633 })),
634 })
635 },
636 Event::Key(key) => Ok(ProtobufEvent {
637 name: ProtobufEventType::Key as i32,
638 payload: Some(event::Payload::KeyPayload(key.try_into()?)),
639 }),
640 Event::Mouse(mouse_event) => {
641 let protobuf_mouse_payload = mouse_event.try_into()?;
642 Ok(ProtobufEvent {
643 name: ProtobufEventType::Mouse as i32,
644 payload: Some(event::Payload::MouseEventPayload(protobuf_mouse_payload)),
645 })
646 },
647 Event::Timer(seconds) => Ok(ProtobufEvent {
648 name: ProtobufEventType::Timer as i32,
649 payload: Some(event::Payload::TimerPayload(seconds as f32)),
650 }),
651 Event::CopyToClipboard(clipboard_destination) => {
652 let protobuf_copy_destination: ProtobufCopyDestination =
653 clipboard_destination.try_into()?;
654 Ok(ProtobufEvent {
655 name: ProtobufEventType::CopyToClipboard as i32,
656 payload: Some(event::Payload::CopyToClipboardPayload(
657 protobuf_copy_destination as i32,
658 )),
659 })
660 },
661 Event::SystemClipboardFailure => Ok(ProtobufEvent {
662 name: ProtobufEventType::SystemClipboardFailure as i32,
663 payload: None,
664 }),
665 Event::InputReceived => Ok(ProtobufEvent {
666 name: ProtobufEventType::InputReceived as i32,
667 payload: None,
668 }),
669 Event::Visible(is_visible) => Ok(ProtobufEvent {
670 name: ProtobufEventType::Visible as i32,
671 payload: Some(event::Payload::VisiblePayload(is_visible)),
672 }),
673 Event::CustomMessage(message, payload) => Ok(ProtobufEvent {
674 name: ProtobufEventType::CustomMessage as i32,
675 payload: Some(event::Payload::CustomMessagePayload(CustomMessagePayload {
676 message_name: message,
677 payload,
678 })),
679 }),
680 Event::FileSystemCreate(event_paths) => {
681 let mut paths = vec![];
682 let mut paths_metadata = vec![];
683 for (path, path_metadata) in event_paths {
684 paths.push(path.display().to_string());
685 paths_metadata.push(path_metadata.into());
686 }
687 let file_list_payload = FileListPayload {
688 paths,
689 paths_metadata,
690 };
691 Ok(ProtobufEvent {
692 name: ProtobufEventType::FileSystemCreate as i32,
693 payload: Some(event::Payload::FileListPayload(file_list_payload)),
694 })
695 },
696 Event::FileSystemRead(event_paths) => {
697 let mut paths = vec![];
698 let mut paths_metadata = vec![];
699 for (path, path_metadata) in event_paths {
700 paths.push(path.display().to_string());
701 paths_metadata.push(path_metadata.into());
702 }
703 let file_list_payload = FileListPayload {
704 paths,
705 paths_metadata,
706 };
707 Ok(ProtobufEvent {
708 name: ProtobufEventType::FileSystemRead as i32,
709 payload: Some(event::Payload::FileListPayload(file_list_payload)),
710 })
711 },
712 Event::FileSystemUpdate(event_paths) => {
713 let mut paths = vec![];
714 let mut paths_metadata = vec![];
715 for (path, path_metadata) in event_paths {
716 paths.push(path.display().to_string());
717 paths_metadata.push(path_metadata.into());
718 }
719 let file_list_payload = FileListPayload {
720 paths,
721 paths_metadata,
722 };
723 Ok(ProtobufEvent {
724 name: ProtobufEventType::FileSystemUpdate as i32,
725 payload: Some(event::Payload::FileListPayload(file_list_payload)),
726 })
727 },
728 Event::FileSystemDelete(event_paths) => {
729 let mut paths = vec![];
730 let mut paths_metadata = vec![];
731 for (path, path_metadata) in event_paths {
732 paths.push(path.display().to_string());
733 paths_metadata.push(path_metadata.into());
734 }
735 let file_list_payload = FileListPayload {
736 paths,
737 paths_metadata,
738 };
739 Ok(ProtobufEvent {
740 name: ProtobufEventType::FileSystemDelete as i32,
741 payload: Some(event::Payload::FileListPayload(file_list_payload)),
742 })
743 },
744 Event::PermissionRequestResult(permission_status) => {
745 let granted = match permission_status {
746 PermissionStatus::Granted => true,
747 PermissionStatus::Denied => false,
748 };
749 Ok(ProtobufEvent {
750 name: ProtobufEventType::PermissionRequestResult as i32,
751 payload: Some(event::Payload::PermissionRequestResultPayload(
752 PermissionRequestResultPayload { granted },
753 )),
754 })
755 },
756 Event::SessionUpdate(session_infos, resurrectable_sessions) => {
757 let mut protobuf_session_manifests = vec![];
758 for session_info in session_infos {
759 protobuf_session_manifests.push(session_info.try_into()?);
760 }
761 let mut protobuf_resurrectable_sessions = vec![];
762 for resurrectable_session in resurrectable_sessions {
763 protobuf_resurrectable_sessions.push(resurrectable_session.into());
764 }
765 let session_update_payload = SessionUpdatePayload {
766 session_manifests: protobuf_session_manifests,
767 resurrectable_sessions: protobuf_resurrectable_sessions,
768 };
769 Ok(ProtobufEvent {
770 name: ProtobufEventType::SessionUpdate as i32,
771 payload: Some(event::Payload::SessionUpdatePayload(session_update_payload)),
772 })
773 },
774 Event::RunCommandResult(exit_code, stdout, stderr, context) => {
775 let run_command_result_payload = RunCommandResultPayload {
776 exit_code,
777 stdout,
778 stderr,
779 context: context
780 .into_iter()
781 .map(|(name, value)| ContextItem { name, value })
782 .collect(),
783 };
784 Ok(ProtobufEvent {
785 name: ProtobufEventType::RunCommandResult as i32,
786 payload: Some(event::Payload::RunCommandResultPayload(
787 run_command_result_payload,
788 )),
789 })
790 },
791 Event::WebRequestResult(status, headers, body, context) => {
792 let web_request_result_payload = WebRequestResultPayload {
793 status: status as i32,
794 headers: headers
795 .into_iter()
796 .map(|(name, value)| Header { name, value })
797 .collect(),
798 body,
799 context: context
800 .into_iter()
801 .map(|(name, value)| ContextItem { name, value })
802 .collect(),
803 };
804 Ok(ProtobufEvent {
805 name: ProtobufEventType::WebRequestResult as i32,
806 payload: Some(event::Payload::WebRequestResultPayload(
807 web_request_result_payload,
808 )),
809 })
810 },
811 Event::CommandPaneOpened(terminal_pane_id, context) => {
812 let command_pane_opened_payload = CommandPaneOpenedPayload {
813 terminal_pane_id,
814 context: context
815 .into_iter()
816 .map(|(name, value)| ContextItem { name, value })
817 .collect(),
818 };
819 Ok(ProtobufEvent {
820 name: ProtobufEventType::CommandPaneOpened as i32,
821 payload: Some(event::Payload::CommandPaneOpenedPayload(
822 command_pane_opened_payload,
823 )),
824 })
825 },
826 Event::CommandPaneExited(terminal_pane_id, exit_code, context) => {
827 let command_pane_exited_payload = CommandPaneExitedPayload {
828 terminal_pane_id,
829 exit_code,
830 context: context
831 .into_iter()
832 .map(|(name, value)| ContextItem { name, value })
833 .collect(),
834 };
835 Ok(ProtobufEvent {
836 name: ProtobufEventType::CommandPaneExited as i32,
837 payload: Some(event::Payload::CommandPaneExitedPayload(
838 command_pane_exited_payload,
839 )),
840 })
841 },
842 Event::PaneClosed(pane_id) => Ok(ProtobufEvent {
843 name: ProtobufEventType::PaneClosed as i32,
844 payload: Some(event::Payload::PaneClosedPayload(PaneClosedPayload {
845 pane_id: Some(pane_id.try_into()?),
846 })),
847 }),
848 Event::EditPaneOpened(terminal_pane_id, context) => {
849 let command_pane_opened_payload = EditPaneOpenedPayload {
850 terminal_pane_id,
851 context: context
852 .into_iter()
853 .map(|(name, value)| ContextItem { name, value })
854 .collect(),
855 };
856 Ok(ProtobufEvent {
857 name: ProtobufEventType::EditPaneOpened as i32,
858 payload: Some(event::Payload::EditPaneOpenedPayload(
859 command_pane_opened_payload,
860 )),
861 })
862 },
863 Event::EditPaneExited(terminal_pane_id, exit_code, context) => {
864 let command_pane_exited_payload = EditPaneExitedPayload {
865 terminal_pane_id,
866 exit_code,
867 context: context
868 .into_iter()
869 .map(|(name, value)| ContextItem { name, value })
870 .collect(),
871 };
872 Ok(ProtobufEvent {
873 name: ProtobufEventType::EditPaneExited as i32,
874 payload: Some(event::Payload::EditPaneExitedPayload(
875 command_pane_exited_payload,
876 )),
877 })
878 },
879 Event::CommandPaneReRun(terminal_pane_id, context) => {
880 let command_pane_rerun_payload = CommandPaneReRunPayload {
881 terminal_pane_id,
882 context: context
883 .into_iter()
884 .map(|(name, value)| ContextItem { name, value })
885 .collect(),
886 };
887 Ok(ProtobufEvent {
888 name: ProtobufEventType::CommandPaneReRun as i32,
889 payload: Some(event::Payload::CommandPaneRerunPayload(
890 command_pane_rerun_payload,
891 )),
892 })
893 },
894 Event::FailedToWriteConfigToDisk(file_path) => Ok(ProtobufEvent {
895 name: ProtobufEventType::FailedToWriteConfigToDisk as i32,
896 payload: Some(event::Payload::FailedToWriteConfigToDiskPayload(
897 FailedToWriteConfigToDiskPayload { file_path },
898 )),
899 }),
900 Event::ListClients(mut client_info_list) => Ok(ProtobufEvent {
901 name: ProtobufEventType::ListClients as i32,
902 payload: Some(event::Payload::ListClientsPayload(ListClientsPayload {
903 client_info: client_info_list
904 .drain(..)
905 .filter_map(|c| c.try_into().ok())
906 .collect(),
907 })),
908 }),
909 Event::HostFolderChanged(new_host_folder_path) => Ok(ProtobufEvent {
910 name: ProtobufEventType::HostFolderChanged as i32,
911 payload: Some(event::Payload::HostFolderChangedPayload(
912 HostFolderChangedPayload {
913 new_host_folder_path: new_host_folder_path.display().to_string(),
914 },
915 )),
916 }),
917 Event::FailedToChangeHostFolder(error_message) => Ok(ProtobufEvent {
918 name: ProtobufEventType::FailedToChangeHostFolder as i32,
919 payload: Some(event::Payload::FailedToChangeHostFolderPayload(
920 FailedToChangeHostFolderPayload { error_message },
921 )),
922 }),
923 Event::PastedText(pasted_text) => Ok(ProtobufEvent {
924 name: ProtobufEventType::PastedText as i32,
925 payload: Some(event::Payload::PastedTextPayload(PastedTextPayload {
926 pasted_text,
927 })),
928 }),
929 Event::ConfigWasWrittenToDisk => Ok(ProtobufEvent {
930 name: ProtobufEventType::ConfigWasWrittenToDisk as i32,
931 payload: None,
932 }),
933 Event::WebServerStatus(web_server_status) => Ok(ProtobufEvent {
934 name: ProtobufEventType::WebServerStatus as i32,
935 payload: Some(event::Payload::WebServerStatusPayload(
936 ProtobufWebServerStatusPayload::try_from(web_server_status)?,
937 )),
938 }),
939 Event::BeforeClose => Ok(ProtobufEvent {
940 name: ProtobufEventType::BeforeClose as i32,
941 payload: None,
942 }),
943 Event::FailedToStartWebServer(error) => Ok(ProtobufEvent {
944 name: ProtobufEventType::FailedToStartWebServer as i32,
945 payload: Some(event::Payload::FailedToStartWebServerPayload(
946 FailedToStartWebServerPayload { error },
947 )),
948 }),
949 Event::InterceptedKeyPress(key) => Ok(ProtobufEvent {
950 name: ProtobufEventType::InterceptedKeyPress as i32,
951 payload: Some(event::Payload::KeyPayload(key.try_into()?)),
952 }),
953 Event::PaneRenderReport(pane_contents_map) => Ok(ProtobufEvent {
954 name: ProtobufEventType::PaneRenderReport as i32,
955 payload: Some(event::Payload::PaneRenderReportPayload(
956 pane_contents_map.try_into()?,
957 )),
958 }),
959 Event::PaneRenderReportWithAnsi(pane_contents_map) => Ok(ProtobufEvent {
960 name: ProtobufEventType::PaneRenderReportWithAnsi as i32,
961 payload: Some(event::Payload::PaneRenderReportWithAnsiPayload(
962 pane_contents_map.try_into()?,
963 )),
964 }),
965 Event::UserAction(action, client_id, terminal_id, cli_client_id) => {
966 let protobuf_action: ProtobufAction = action
967 .try_into()
968 .map_err(|_| "Failed to convert Action to protobuf")?;
969 let protobuf_payload = ProtobufUserActionPayload {
970 action: Some(protobuf_action),
971 client_id: client_id as u32,
972 terminal_id,
973 cli_client_id: cli_client_id.map(|id| id as u32),
974 };
975 Ok(ProtobufEvent {
976 name: ProtobufEventType::UserAction as i32,
977 payload: Some(event::Payload::UserActionPayload(protobuf_payload)),
978 })
979 },
980 Event::ActionComplete(action, pane_id, context) => {
981 let protobuf_action = action.try_into()?;
982 let protobuf_pane_id = pane_id.map(|id| id.try_into()).transpose()?;
983 let context_items: Vec<ProtobufContextItem> = context
984 .into_iter()
985 .map(|(name, value)| ProtobufContextItem { name, value })
986 .collect();
987 let action_complete_payload = ProtobufActionCompletePayload {
988 action: Some(protobuf_action),
989 pane_id: protobuf_pane_id,
990 context: context_items,
991 };
992 Ok(ProtobufEvent {
993 name: ProtobufEventType::ActionComplete as i32,
994 payload: Some(event::Payload::ActionCompletePayload(
995 action_complete_payload,
996 )),
997 })
998 },
999 Event::CwdChanged(pane_id, new_cwd, focused_client_ids) => {
1000 let protobuf_pane_id: ProtobufPaneId = pane_id.try_into()?;
1001 let new_cwd_string = new_cwd
1002 .to_str()
1003 .ok_or("Failed to convert PathBuf to string")?
1004 .to_string();
1005 let focused_client_ids_u32: Vec<u32> =
1006 focused_client_ids.into_iter().map(|id| id as u32).collect();
1007 let cwd_changed_payload = ProtobufCwdChangedPayload {
1008 pane_id: Some(protobuf_pane_id),
1009 new_cwd: new_cwd_string,
1010 focused_client_ids: focused_client_ids_u32,
1011 };
1012 Ok(ProtobufEvent {
1013 name: ProtobufEventType::CwdChanged as i32,
1014 payload: Some(event::Payload::CwdChangedPayload(cwd_changed_payload)),
1015 })
1016 },
1017 Event::AvailableLayoutInfo(available_layouts, layouts_with_errors) => {
1018 let mut protobuf_available_layouts = vec![];
1019 let mut protobuf_layouts_with_errors = vec![];
1020
1021 for layout_info in available_layouts {
1022 protobuf_available_layouts.push(layout_info.try_into()?);
1023 }
1024
1025 for layout_error in layouts_with_errors {
1026 protobuf_layouts_with_errors.push(layout_error.try_into()?);
1027 }
1028
1029 let available_layout_info_payload = ProtobufAvailableLayoutInfoPayload {
1030 available_layouts: protobuf_available_layouts,
1031 layouts_with_errors: protobuf_layouts_with_errors,
1032 };
1033
1034 Ok(ProtobufEvent {
1035 name: ProtobufEventType::AvailableLayoutInfo as i32,
1036 payload: Some(event::Payload::AvailableLayoutInfoPayload(
1037 available_layout_info_payload,
1038 )),
1039 })
1040 },
1041 Event::PluginConfigurationChanged(configuration) => {
1042 let configuration_items: Vec<ProtobufContextItem> = configuration
1043 .into_iter()
1044 .map(|(name, value)| ProtobufContextItem { name, value })
1045 .collect();
1046
1047 let payload = ProtobufPluginConfigurationChangedPayload {
1048 configuration: configuration_items,
1049 };
1050
1051 Ok(ProtobufEvent {
1052 name: ProtobufEventType::PluginConfigurationChanged as i32,
1053 payload: Some(event::Payload::PluginConfigurationChangedPayload(payload)),
1054 })
1055 },
1056 Event::HighlightClicked {
1057 pane_id,
1058 pattern,
1059 matched_string,
1060 context,
1061 } => Ok(ProtobufEvent {
1062 name: ProtobufEventType::HighlightClicked as i32,
1063 payload: Some(event::Payload::HighlightClickedPayload(
1064 HighlightClickedPayload {
1065 pane_id: pane_id.try_into().ok(),
1066 pattern,
1067 matched_string,
1068 context: context
1069 .into_iter()
1070 .map(|(name, value)| ProtobufContextItem { name, value })
1071 .collect(),
1072 },
1073 )),
1074 }),
1075 Event::InitialKeybinds(keybinds) => {
1076 let mut protobuf_keybinds: Vec<ProtobufInputModeKeybinds> = vec![];
1077 for (input_mode, input_mode_keybinds) in keybinds {
1078 let mode: ProtobufInputMode = input_mode.try_into()?;
1079 let mut key_binds: Vec<ProtobufKeyBind> = vec![];
1080 for (key, actions) in input_mode_keybinds {
1081 let protobuf_key: ProtobufKey = key.try_into()?;
1082 let mut protobuf_actions: Vec<ProtobufAction> = vec![];
1083 for action in actions {
1084 if let Ok(protobuf_action) = action.try_into() {
1085 protobuf_actions.push(protobuf_action);
1086 }
1087 }
1088 key_binds.push(ProtobufKeyBind {
1089 key: Some(protobuf_key),
1090 action: protobuf_actions,
1091 });
1092 }
1093 protobuf_keybinds.push(ProtobufInputModeKeybinds {
1094 mode: mode as i32,
1095 key_bind: key_binds,
1096 });
1097 }
1098 Ok(ProtobufEvent {
1099 name: ProtobufEventType::InitialKeybinds as i32,
1100 payload: Some(event::Payload::InitialKeybindsPayload(
1101 InitialKeybindsPayload {
1102 keybinds: protobuf_keybinds,
1103 },
1104 )),
1105 })
1106 },
1107 }
1108 }
1109}
1110
1111impl TryFrom<SessionInfo> for ProtobufSessionManifest {
1112 type Error = &'static str;
1113 fn try_from(session_info: SessionInfo) -> Result<Self, &'static str> {
1114 let mut protobuf_pane_manifests = vec![];
1115 for (tab_index, pane_infos) in session_info.panes.panes {
1116 let mut protobuf_pane_infos = vec![];
1117 for pane_info in pane_infos {
1118 protobuf_pane_infos.push(pane_info.try_into()?);
1119 }
1120 protobuf_pane_manifests.push(ProtobufPaneManifest {
1121 tab_index: tab_index as u32,
1122 panes: protobuf_pane_infos,
1123 });
1124 }
1125 Ok(ProtobufSessionManifest {
1126 name: session_info.name,
1127 panes: protobuf_pane_manifests,
1128 tabs: session_info
1129 .tabs
1130 .iter()
1131 .filter_map(|t| t.clone().try_into().ok())
1132 .collect(),
1133 connected_clients: session_info.connected_clients as u32,
1134 is_current_session: session_info.is_current_session,
1135 available_layouts: session_info
1136 .available_layouts
1137 .into_iter()
1138 .filter_map(|l| ProtobufLayoutInfo::try_from(l).ok())
1139 .collect(),
1140 plugins: session_info
1141 .plugins
1142 .into_iter()
1143 .map(|p| ProtobufPluginInfo::from(p))
1144 .collect(),
1145 web_clients_allowed: session_info.web_clients_allowed,
1146 web_client_count: session_info.web_client_count as u32,
1147 tab_history: session_info
1148 .tab_history
1149 .into_iter()
1150 .map(|t| ProtobufClientTabHistory::from(t))
1151 .collect(),
1152 pane_history: session_info
1153 .pane_history
1154 .into_iter()
1155 .map(|p| ProtobufClientPaneHistory::from(p))
1156 .collect(),
1157 creation_time: session_info.creation_time.as_secs(),
1158 })
1159 }
1160}
1161
1162impl From<(u16, Vec<usize>)> for ProtobufClientTabHistory {
1163 fn from((client_id, tab_history): (u16, Vec<usize>)) -> ProtobufClientTabHistory {
1164 ProtobufClientTabHistory {
1165 client_id: client_id as u32,
1166 tab_history: tab_history.into_iter().map(|t| t as u32).collect(),
1167 }
1168 }
1169}
1170
1171impl From<(u16, Vec<PaneId>)> for ProtobufClientPaneHistory {
1172 fn from((client_id, pane_history): (u16, Vec<PaneId>)) -> ProtobufClientPaneHistory {
1173 ProtobufClientPaneHistory {
1174 client_id: client_id as u32,
1175 pane_history: pane_history
1176 .into_iter()
1177 .filter_map(|p| p.try_into().ok())
1178 .collect(),
1179 }
1180 }
1181}
1182impl From<(u32, PluginInfo)> for ProtobufPluginInfo {
1183 fn from((plugin_id, plugin_info): (u32, PluginInfo)) -> ProtobufPluginInfo {
1184 ProtobufPluginInfo {
1185 plugin_id,
1186 plugin_url: plugin_info.location,
1187 plugin_config: plugin_info
1188 .configuration
1189 .into_iter()
1190 .map(|(name, value)| ContextItem { name, value })
1191 .collect(),
1192 }
1193 }
1194}
1195
1196impl TryFrom<ProtobufSessionManifest> for SessionInfo {
1197 type Error = &'static str;
1198 fn try_from(protobuf_session_manifest: ProtobufSessionManifest) -> Result<Self, &'static str> {
1199 let mut pane_manifest: HashMap<usize, Vec<PaneInfo>> = HashMap::new();
1200 for protobuf_pane_manifest in protobuf_session_manifest.panes {
1201 let tab_index = protobuf_pane_manifest.tab_index as usize;
1202 let mut panes = vec![];
1203 for protobuf_pane_info in protobuf_pane_manifest.panes {
1204 panes.push(protobuf_pane_info.try_into()?);
1205 }
1206 if pane_manifest.contains_key(&tab_index) {
1207 return Err("Duplicate tab definition in pane manifest");
1208 }
1209 pane_manifest.insert(tab_index, panes);
1210 }
1211 let panes = PaneManifest {
1212 panes: pane_manifest,
1213 };
1214 let mut plugins = BTreeMap::new();
1215 for plugin_info in protobuf_session_manifest.plugins.into_iter() {
1216 let mut configuration = BTreeMap::new();
1217 for context_item in plugin_info.plugin_config.into_iter() {
1218 configuration.insert(context_item.name, context_item.value);
1219 }
1220 plugins.insert(
1221 plugin_info.plugin_id,
1222 PluginInfo {
1223 location: plugin_info.plugin_url,
1224 configuration,
1225 },
1226 );
1227 }
1228 let mut tab_history = BTreeMap::new();
1229 for client_tab_history in protobuf_session_manifest.tab_history.into_iter() {
1230 let client_id = client_tab_history.client_id;
1231 let tab_history_for_client = client_tab_history
1232 .tab_history
1233 .iter()
1234 .map(|t| *t as usize)
1235 .collect();
1236 tab_history.insert(client_id as u16, tab_history_for_client);
1237 }
1238 let mut pane_history = BTreeMap::new();
1239 for client_pane_history in protobuf_session_manifest.pane_history.into_iter() {
1240 let client_id = client_pane_history.client_id;
1241 let pane_history_for_client = client_pane_history
1242 .pane_history
1243 .into_iter()
1244 .filter_map(|p| p.try_into().ok())
1245 .collect();
1246 pane_history.insert(client_id as u16, pane_history_for_client);
1247 }
1248 Ok(SessionInfo {
1249 name: protobuf_session_manifest.name,
1250 tabs: protobuf_session_manifest
1251 .tabs
1252 .iter()
1253 .filter_map(|t| t.clone().try_into().ok())
1254 .collect(),
1255 panes,
1256 connected_clients: protobuf_session_manifest.connected_clients as usize,
1257 is_current_session: protobuf_session_manifest.is_current_session,
1258 available_layouts: protobuf_session_manifest
1259 .available_layouts
1260 .into_iter()
1261 .filter_map(|l| LayoutInfo::try_from(l).ok())
1262 .collect(),
1263 plugins,
1264 web_clients_allowed: protobuf_session_manifest.web_clients_allowed,
1265 web_client_count: protobuf_session_manifest.web_client_count as usize,
1266 tab_history,
1267 pane_history,
1268 creation_time: Duration::from_secs(protobuf_session_manifest.creation_time),
1269 })
1270 }
1271}
1272
1273impl TryFrom<LayoutInfo> for ProtobufLayoutInfo {
1274 type Error = &'static str;
1275 fn try_from(layout_info: LayoutInfo) -> Result<Self, &'static str> {
1276 match layout_info {
1277 LayoutInfo::File(name, layout_metadata) => Ok(ProtobufLayoutInfo {
1278 source: "file".to_owned(),
1279 name,
1280 layout_metadata: Some(layout_metadata.try_into()?),
1281 }),
1282 LayoutInfo::BuiltIn(name) => Ok(ProtobufLayoutInfo {
1283 source: "built-in".to_owned(),
1284 name,
1285 layout_metadata: None,
1286 }),
1287 LayoutInfo::Url(name) => Ok(ProtobufLayoutInfo {
1288 source: "url".to_owned(),
1289 name,
1290 layout_metadata: None,
1291 }),
1292 LayoutInfo::Stringified(stringified_layout) => Ok(ProtobufLayoutInfo {
1293 source: "stringified".to_owned(),
1294 name: stringified_layout.clone(),
1295 layout_metadata: None,
1296 }),
1297 }
1298 }
1299}
1300
1301impl TryFrom<ProtobufLayoutInfo> for LayoutInfo {
1302 type Error = &'static str;
1303 fn try_from(protobuf_layout_info: ProtobufLayoutInfo) -> Result<Self, &'static str> {
1304 match protobuf_layout_info.source.as_str() {
1305 "file" => {
1306 let layout_metadata = protobuf_layout_info
1307 .layout_metadata
1308 .map(|m| m.try_into())
1309 .transpose()?
1310 .unwrap_or_default();
1311 Ok(LayoutInfo::File(protobuf_layout_info.name, layout_metadata))
1312 },
1313 "built-in" => Ok(LayoutInfo::BuiltIn(protobuf_layout_info.name)),
1314 "url" => Ok(LayoutInfo::Url(protobuf_layout_info.name)),
1315 "stringified" => Ok(LayoutInfo::Stringified(protobuf_layout_info.name)),
1316 _ => Err("Unknown source for layout"),
1317 }
1318 }
1319}
1320
1321impl TryFrom<ProtobufLayoutMetadata> for LayoutMetadata {
1322 type Error = &'static str;
1323 fn try_from(protobuf_metadata: ProtobufLayoutMetadata) -> Result<Self, &'static str> {
1324 let tabs = protobuf_metadata
1325 .tabs
1326 .into_iter()
1327 .map(|t| t.try_into())
1328 .collect::<Result<Vec<_>, _>>()?;
1329 Ok(LayoutMetadata {
1330 tabs,
1331 creation_time: protobuf_metadata.creation_time,
1332 update_time: protobuf_metadata.update_time,
1333 })
1334 }
1335}
1336
1337impl TryFrom<LayoutMetadata> for ProtobufLayoutMetadata {
1338 type Error = &'static str;
1339 fn try_from(metadata: LayoutMetadata) -> Result<Self, &'static str> {
1340 let tabs = metadata
1341 .tabs
1342 .into_iter()
1343 .map(|t| t.try_into())
1344 .collect::<Result<Vec<_>, _>>()?;
1345 Ok(ProtobufLayoutMetadata {
1346 tabs,
1347 creation_time: metadata.creation_time,
1348 update_time: metadata.update_time,
1349 })
1350 }
1351}
1352
1353impl TryFrom<ProtobufTabMetadata> for TabMetadata {
1354 type Error = &'static str;
1355 fn try_from(protobuf_metadata: ProtobufTabMetadata) -> Result<Self, &'static str> {
1356 let panes = protobuf_metadata
1357 .pane_metadata
1358 .into_iter()
1359 .map(|p| p.try_into())
1360 .collect::<Result<Vec<_>, _>>()?;
1361 Ok(TabMetadata {
1362 panes,
1363 name: protobuf_metadata.name,
1364 })
1365 }
1366}
1367
1368impl TryFrom<TabMetadata> for ProtobufTabMetadata {
1369 type Error = &'static str;
1370 fn try_from(metadata: TabMetadata) -> Result<Self, &'static str> {
1371 let pane_metadata = metadata
1372 .panes
1373 .into_iter()
1374 .map(|p| p.try_into())
1375 .collect::<Result<Vec<_>, _>>()?;
1376 Ok(ProtobufTabMetadata {
1377 pane_metadata,
1378 name: metadata.name,
1379 })
1380 }
1381}
1382
1383impl TryFrom<ProtobufPaneMetadata> for PaneMetadata {
1384 type Error = &'static str;
1385 fn try_from(protobuf_metadata: ProtobufPaneMetadata) -> Result<Self, &'static str> {
1386 Ok(PaneMetadata {
1387 name: protobuf_metadata.name,
1388 is_plugin: protobuf_metadata.is_plugin,
1389 is_builtin_plugin: protobuf_metadata.is_builtin_plugin,
1390 })
1391 }
1392}
1393
1394impl TryFrom<PaneMetadata> for ProtobufPaneMetadata {
1395 type Error = &'static str;
1396 fn try_from(metadata: PaneMetadata) -> Result<Self, &'static str> {
1397 Ok(ProtobufPaneMetadata {
1398 name: metadata.name,
1399 is_plugin: metadata.is_plugin,
1400 is_builtin_plugin: metadata.is_builtin_plugin,
1401 })
1402 }
1403}
1404
1405impl TryFrom<ProtobufLayoutWithError> for crate::data::LayoutWithError {
1407 type Error = &'static str;
1408 fn try_from(protobuf: ProtobufLayoutWithError) -> Result<Self, Self::Error> {
1409 Ok(crate::data::LayoutWithError {
1410 layout_name: protobuf.layout_name,
1411 error: protobuf.error.ok_or("Missing error field")?.try_into()?,
1412 })
1413 }
1414}
1415
1416impl TryFrom<crate::data::LayoutWithError> for ProtobufLayoutWithError {
1417 type Error = &'static str;
1418 fn try_from(layout_error: crate::data::LayoutWithError) -> Result<Self, Self::Error> {
1419 Ok(ProtobufLayoutWithError {
1420 layout_name: layout_error.layout_name,
1421 error: Some(layout_error.error.try_into()?),
1422 })
1423 }
1424}
1425
1426impl TryFrom<ProtobufLayoutParsingError> for crate::data::LayoutParsingError {
1428 type Error = &'static str;
1429 fn try_from(protobuf: ProtobufLayoutParsingError) -> Result<Self, Self::Error> {
1430 match protobuf.error_type.ok_or("Missing error_type")? {
1431 ProtobufLayoutParsingErrorType::KdlError(kdl_variant) => {
1432 Ok(crate::data::LayoutParsingError::KdlError {
1433 kdl_error: kdl_variant
1434 .kdl_error
1435 .ok_or("Missing kdl_error")?
1436 .try_into()?,
1437 file_name: kdl_variant.file_name,
1438 source_code: kdl_variant.source_code,
1439 })
1440 },
1441 ProtobufLayoutParsingErrorType::SyntaxError(_) => {
1442 Ok(crate::data::LayoutParsingError::SyntaxError)
1443 },
1444 }
1445 }
1446}
1447
1448impl TryFrom<crate::data::LayoutParsingError> for ProtobufLayoutParsingError {
1449 type Error = &'static str;
1450 fn try_from(error: crate::data::LayoutParsingError) -> Result<Self, Self::Error> {
1451 let error_type = match error {
1452 crate::data::LayoutParsingError::KdlError {
1453 kdl_error,
1454 file_name,
1455 source_code,
1456 } => ProtobufLayoutParsingErrorType::KdlError(ProtobufKdlErrorVariant {
1457 kdl_error: Some(kdl_error.try_into()?),
1458 file_name,
1459 source_code,
1460 }),
1461 crate::data::LayoutParsingError::SyntaxError => {
1462 ProtobufLayoutParsingErrorType::SyntaxError(ProtobufSyntaxError {})
1463 },
1464 };
1465 Ok(ProtobufLayoutParsingError {
1466 error_type: Some(error_type),
1467 })
1468 }
1469}
1470
1471impl TryFrom<ProtobufKdlError> for crate::input::config::KdlError {
1473 type Error = &'static str;
1474 fn try_from(protobuf: ProtobufKdlError) -> Result<Self, Self::Error> {
1475 Ok(crate::input::config::KdlError {
1476 error_message: protobuf.error_message,
1477 src: None, offset: protobuf.offset.map(|o| o as usize),
1479 len: protobuf.len.map(|l| l as usize),
1480 help_message: protobuf.help_message,
1481 })
1482 }
1483}
1484
1485impl TryFrom<crate::input::config::KdlError> for ProtobufKdlError {
1486 type Error = &'static str;
1487 fn try_from(kdl: crate::input::config::KdlError) -> Result<Self, Self::Error> {
1488 Ok(ProtobufKdlError {
1489 error_message: kdl.error_message,
1490 offset: kdl.offset.map(|o| o as u64),
1492 len: kdl.len.map(|l| l as u64),
1493 help_message: kdl.help_message,
1494 })
1495 }
1496}
1497
1498impl TryFrom<CopyDestination> for ProtobufCopyDestination {
1499 type Error = &'static str;
1500 fn try_from(copy_destination: CopyDestination) -> Result<Self, &'static str> {
1501 match copy_destination {
1502 CopyDestination::Command => Ok(ProtobufCopyDestination::Command),
1503 CopyDestination::Primary => Ok(ProtobufCopyDestination::Primary),
1504 CopyDestination::System => Ok(ProtobufCopyDestination::System),
1505 }
1506 }
1507}
1508
1509impl TryFrom<ProtobufCopyDestination> for CopyDestination {
1510 type Error = &'static str;
1511 fn try_from(protobuf_copy_destination: ProtobufCopyDestination) -> Result<Self, &'static str> {
1512 match protobuf_copy_destination {
1513 ProtobufCopyDestination::Command => Ok(CopyDestination::Command),
1514 ProtobufCopyDestination::Primary => Ok(CopyDestination::Primary),
1515 ProtobufCopyDestination::System => Ok(CopyDestination::System),
1516 }
1517 }
1518}
1519
1520impl TryFrom<MouseEventPayload> for Mouse {
1521 type Error = &'static str;
1522 fn try_from(mouse_event_payload: MouseEventPayload) -> Result<Self, &'static str> {
1523 match MouseEventName::from_i32(mouse_event_payload.mouse_event_name) {
1524 Some(MouseEventName::MouseScrollUp) => match mouse_event_payload.mouse_event_payload {
1525 Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
1526 Ok(Mouse::ScrollUp(line_count as usize))
1527 },
1528 _ => Err("Malformed payload for mouse scroll up"),
1529 },
1530 Some(MouseEventName::MouseScrollDown) => {
1531 match mouse_event_payload.mouse_event_payload {
1532 Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
1533 Ok(Mouse::ScrollDown(line_count as usize))
1534 },
1535 _ => Err("Malformed payload for mouse scroll down"),
1536 }
1537 },
1538 Some(MouseEventName::MouseLeftClick) => match mouse_event_payload.mouse_event_payload {
1539 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1540 Mouse::LeftClick(position.line as isize, position.column as usize),
1541 ),
1542 _ => Err("Malformed payload for mouse left click"),
1543 },
1544 Some(MouseEventName::MouseRightClick) => {
1545 match mouse_event_payload.mouse_event_payload {
1546 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1547 Mouse::RightClick(position.line as isize, position.column as usize),
1548 ),
1549 _ => Err("Malformed payload for mouse right click"),
1550 }
1551 },
1552 Some(MouseEventName::MouseHold) => match mouse_event_payload.mouse_event_payload {
1553 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1554 Mouse::Hold(position.line as isize, position.column as usize),
1555 ),
1556 _ => Err("Malformed payload for mouse hold"),
1557 },
1558 Some(MouseEventName::MouseRelease) => match mouse_event_payload.mouse_event_payload {
1559 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1560 Mouse::Release(position.line as isize, position.column as usize),
1561 ),
1562 _ => Err("Malformed payload for mouse release"),
1563 },
1564 Some(MouseEventName::MouseHover) => match mouse_event_payload.mouse_event_payload {
1565 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1566 Mouse::Hover(position.line as isize, position.column as usize),
1567 ),
1568 _ => Err("Malformed payload for mouse hover"),
1569 },
1570 None => Err("Malformed payload for MouseEventName"),
1571 }
1572 }
1573}
1574
1575impl TryFrom<Mouse> for MouseEventPayload {
1576 type Error = &'static str;
1577 fn try_from(mouse: Mouse) -> Result<Self, &'static str> {
1578 match mouse {
1579 Mouse::ScrollUp(number_of_lines) => Ok(MouseEventPayload {
1580 mouse_event_name: MouseEventName::MouseScrollUp as i32,
1581 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
1582 number_of_lines as u32,
1583 )),
1584 }),
1585 Mouse::ScrollDown(number_of_lines) => Ok(MouseEventPayload {
1586 mouse_event_name: MouseEventName::MouseScrollDown as i32,
1587 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
1588 number_of_lines as u32,
1589 )),
1590 }),
1591 Mouse::LeftClick(line, column) => Ok(MouseEventPayload {
1592 mouse_event_name: MouseEventName::MouseLeftClick as i32,
1593 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1594 ProtobufPosition {
1595 line: line as i64,
1596 column: column as i64,
1597 },
1598 )),
1599 }),
1600 Mouse::RightClick(line, column) => Ok(MouseEventPayload {
1601 mouse_event_name: MouseEventName::MouseRightClick as i32,
1602 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1603 ProtobufPosition {
1604 line: line as i64,
1605 column: column as i64,
1606 },
1607 )),
1608 }),
1609 Mouse::Hold(line, column) => Ok(MouseEventPayload {
1610 mouse_event_name: MouseEventName::MouseHold as i32,
1611 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1612 ProtobufPosition {
1613 line: line as i64,
1614 column: column as i64,
1615 },
1616 )),
1617 }),
1618 Mouse::Release(line, column) => Ok(MouseEventPayload {
1619 mouse_event_name: MouseEventName::MouseRelease as i32,
1620 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1621 ProtobufPosition {
1622 line: line as i64,
1623 column: column as i64,
1624 },
1625 )),
1626 }),
1627 Mouse::Hover(line, column) => Ok(MouseEventPayload {
1628 mouse_event_name: MouseEventName::MouseHover as i32,
1629 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1630 ProtobufPosition {
1631 line: line as i64,
1632 column: column as i64,
1633 },
1634 )),
1635 }),
1636 }
1637 }
1638}
1639
1640impl TryFrom<ProtobufPaneInfo> for PaneInfo {
1641 type Error = &'static str;
1642 fn try_from(protobuf_pane_info: ProtobufPaneInfo) -> Result<Self, &'static str> {
1643 Ok(PaneInfo {
1644 id: protobuf_pane_info.id,
1645 is_plugin: protobuf_pane_info.is_plugin,
1646 is_focused: protobuf_pane_info.is_focused,
1647 is_fullscreen: protobuf_pane_info.is_fullscreen,
1648 is_floating: protobuf_pane_info.is_floating,
1649 is_suppressed: protobuf_pane_info.is_suppressed,
1650 title: protobuf_pane_info.title,
1651 exited: protobuf_pane_info.exited,
1652 exit_status: protobuf_pane_info.exit_status,
1653 is_held: protobuf_pane_info.is_held,
1654 pane_x: protobuf_pane_info.pane_x as usize,
1655 pane_content_x: protobuf_pane_info.pane_content_x as usize,
1656 pane_y: protobuf_pane_info.pane_y as usize,
1657 pane_content_y: protobuf_pane_info.pane_content_y as usize,
1658 pane_rows: protobuf_pane_info.pane_rows as usize,
1659 pane_content_rows: protobuf_pane_info.pane_content_rows as usize,
1660 pane_columns: protobuf_pane_info.pane_columns as usize,
1661 pane_content_columns: protobuf_pane_info.pane_content_columns as usize,
1662 cursor_coordinates_in_pane: protobuf_pane_info
1663 .cursor_coordinates_in_pane
1664 .map(|position| (position.column as usize, position.line as usize)),
1665 terminal_command: protobuf_pane_info.terminal_command,
1666 plugin_url: protobuf_pane_info.plugin_url,
1667 is_selectable: protobuf_pane_info.is_selectable,
1668 index_in_pane_group: protobuf_pane_info
1669 .index_in_pane_group
1670 .iter()
1671 .map(|index_in_pane_group| {
1672 (
1673 index_in_pane_group.client_id as u16,
1674 index_in_pane_group.index as usize,
1675 )
1676 })
1677 .collect(),
1678 default_fg: protobuf_pane_info.default_fg,
1679 default_bg: protobuf_pane_info.default_bg,
1680 })
1681 }
1682}
1683
1684impl TryFrom<PaneInfo> for ProtobufPaneInfo {
1685 type Error = &'static str;
1686 fn try_from(pane_info: PaneInfo) -> Result<Self, &'static str> {
1687 Ok(ProtobufPaneInfo {
1688 id: pane_info.id,
1689 is_plugin: pane_info.is_plugin,
1690 is_focused: pane_info.is_focused,
1691 is_fullscreen: pane_info.is_fullscreen,
1692 is_floating: pane_info.is_floating,
1693 is_suppressed: pane_info.is_suppressed,
1694 title: pane_info.title,
1695 exited: pane_info.exited,
1696 exit_status: pane_info.exit_status,
1697 is_held: pane_info.is_held,
1698 pane_x: pane_info.pane_x as u32,
1699 pane_content_x: pane_info.pane_content_x as u32,
1700 pane_y: pane_info.pane_y as u32,
1701 pane_content_y: pane_info.pane_content_y as u32,
1702 pane_rows: pane_info.pane_rows as u32,
1703 pane_content_rows: pane_info.pane_content_rows as u32,
1704 pane_columns: pane_info.pane_columns as u32,
1705 pane_content_columns: pane_info.pane_content_columns as u32,
1706 cursor_coordinates_in_pane: pane_info.cursor_coordinates_in_pane.map(|(x, y)| {
1707 ProtobufPosition {
1708 column: x as i64,
1709 line: y as i64,
1710 }
1711 }),
1712 terminal_command: pane_info.terminal_command,
1713 plugin_url: pane_info.plugin_url,
1714 is_selectable: pane_info.is_selectable,
1715 index_in_pane_group: pane_info
1716 .index_in_pane_group
1717 .iter()
1718 .map(|(&client_id, &index)| IndexInPaneGroup {
1719 client_id: client_id as u32,
1720 index: index as u32,
1721 })
1722 .collect(),
1723 default_fg: pane_info.default_fg,
1724 default_bg: pane_info.default_bg,
1725 })
1726 }
1727}
1728
1729impl TryFrom<ProtobufTabInfo> for TabInfo {
1730 type Error = &'static str;
1731 fn try_from(protobuf_tab_info: ProtobufTabInfo) -> Result<Self, &'static str> {
1732 Ok(TabInfo {
1733 position: protobuf_tab_info.position as usize,
1734 name: protobuf_tab_info.name,
1735 active: protobuf_tab_info.active,
1736 panes_to_hide: protobuf_tab_info.panes_to_hide as usize,
1737 is_fullscreen_active: protobuf_tab_info.is_fullscreen_active,
1738 is_sync_panes_active: protobuf_tab_info.is_sync_panes_active,
1739 are_floating_panes_visible: protobuf_tab_info.are_floating_panes_visible,
1740 other_focused_clients: protobuf_tab_info
1741 .other_focused_clients
1742 .iter()
1743 .map(|c| *c as u16)
1744 .collect(),
1745 active_swap_layout_name: protobuf_tab_info.active_swap_layout_name,
1746 is_swap_layout_dirty: protobuf_tab_info.is_swap_layout_dirty,
1747 viewport_rows: protobuf_tab_info.viewport_rows as usize,
1748 viewport_columns: protobuf_tab_info.viewport_columns as usize,
1749 display_area_rows: protobuf_tab_info.display_area_rows as usize,
1750 display_area_columns: protobuf_tab_info.display_area_columns as usize,
1751 selectable_tiled_panes_count: protobuf_tab_info.selectable_tiled_panes_count as usize,
1752 selectable_floating_panes_count: protobuf_tab_info.selectable_floating_panes_count
1753 as usize,
1754 tab_id: protobuf_tab_info.tab_id as usize,
1755 has_bell_notification: protobuf_tab_info.has_bell_notification,
1756 is_flashing_bell: protobuf_tab_info.is_flashing_bell,
1757 })
1758 }
1759}
1760
1761impl TryFrom<TabInfo> for ProtobufTabInfo {
1762 type Error = &'static str;
1763 fn try_from(tab_info: TabInfo) -> Result<Self, &'static str> {
1764 Ok(ProtobufTabInfo {
1765 position: tab_info.position as u32,
1766 name: tab_info.name,
1767 active: tab_info.active,
1768 panes_to_hide: tab_info.panes_to_hide as u32,
1769 is_fullscreen_active: tab_info.is_fullscreen_active,
1770 is_sync_panes_active: tab_info.is_sync_panes_active,
1771 are_floating_panes_visible: tab_info.are_floating_panes_visible,
1772 other_focused_clients: tab_info
1773 .other_focused_clients
1774 .iter()
1775 .map(|c| *c as u32)
1776 .collect(),
1777 active_swap_layout_name: tab_info.active_swap_layout_name,
1778 is_swap_layout_dirty: tab_info.is_swap_layout_dirty,
1779 viewport_rows: tab_info.viewport_rows as u32,
1780 viewport_columns: tab_info.viewport_columns as u32,
1781 display_area_rows: tab_info.display_area_rows as u32,
1782 display_area_columns: tab_info.display_area_columns as u32,
1783 selectable_tiled_panes_count: tab_info.selectable_tiled_panes_count as u32,
1784 selectable_floating_panes_count: tab_info.selectable_floating_panes_count as u32,
1785 tab_id: tab_info.tab_id as u32,
1786 has_bell_notification: tab_info.has_bell_notification,
1787 is_flashing_bell: tab_info.is_flashing_bell,
1788 })
1789 }
1790}
1791
1792impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
1793 type Error = &'static str;
1794 fn try_from(
1795 mut protobuf_mode_update_payload: ProtobufModeUpdatePayload,
1796 ) -> Result<Self, &'static str> {
1797 let current_mode: InputMode =
1798 ProtobufInputMode::from_i32(protobuf_mode_update_payload.current_mode)
1799 .ok_or("Malformed InputMode in the ModeUpdate Event")?
1800 .try_into()?;
1801 let base_mode: Option<InputMode> = protobuf_mode_update_payload
1802 .base_mode
1803 .and_then(|b_m| ProtobufInputMode::from_i32(b_m)?.try_into().ok());
1804 let keybinds: Vec<(InputMode, Vec<(KeyWithModifier, Vec<Action>)>)> =
1805 protobuf_mode_update_payload
1806 .keybinds
1807 .iter_mut()
1808 .filter_map(|k| {
1809 let input_mode: InputMode = ProtobufInputMode::from_i32(k.mode)
1810 .ok_or("Malformed InputMode in the ModeUpdate Event")
1811 .ok()?
1812 .try_into()
1813 .ok()?;
1814 let mut keybinds: Vec<(KeyWithModifier, Vec<Action>)> = vec![];
1815 for mut protobuf_keybind in k.key_bind.drain(..) {
1816 let key: KeyWithModifier = protobuf_keybind.key.unwrap().try_into().ok()?;
1817 let mut actions: Vec<Action> = vec![];
1818 for action in protobuf_keybind.action.drain(..) {
1819 if let Ok(action) = action.try_into() {
1820 actions.push(action);
1821 }
1822 }
1823 keybinds.push((key, actions));
1824 }
1825 Some((input_mode, keybinds))
1826 })
1827 .collect();
1828 let style: Style = protobuf_mode_update_payload
1829 .style
1830 .and_then(|m| m.try_into().ok())
1831 .ok_or("malformed payload for mode_info")?;
1832 let session_name = protobuf_mode_update_payload.session_name;
1833 let editor = protobuf_mode_update_payload
1834 .editor
1835 .map(|e| PathBuf::from(e));
1836 let shell = protobuf_mode_update_payload.shell.map(|s| PathBuf::from(s));
1837 let web_clients_allowed = protobuf_mode_update_payload.web_clients_allowed;
1838 let web_sharing = protobuf_mode_update_payload
1839 .web_sharing
1840 .and_then(|w| ProtobufWebSharing::from_i32(w))
1841 .map(|w| w.into());
1842 let capabilities = PluginCapabilities {
1843 arrow_fonts: protobuf_mode_update_payload.arrow_fonts_support,
1844 };
1845 let currently_marking_pane_group =
1846 protobuf_mode_update_payload.currently_marking_pane_group;
1847 let is_web_client = protobuf_mode_update_payload.is_web_client;
1848
1849 let web_server_ip = protobuf_mode_update_payload
1850 .web_server_ip
1851 .as_ref()
1852 .and_then(|web_server_ip| IpAddr::from_str(web_server_ip).ok());
1853
1854 let web_server_port = protobuf_mode_update_payload
1855 .web_server_port
1856 .map(|w| w as u16);
1857
1858 let web_server_capability = protobuf_mode_update_payload.web_server_capability;
1859
1860 let mode_info = ModeInfo {
1861 mode: current_mode,
1862 keybinds,
1863 style,
1864 capabilities,
1865 session_name,
1866 base_mode,
1867 editor,
1868 shell,
1869 web_clients_allowed,
1870 web_sharing,
1871 currently_marking_pane_group,
1872 is_web_client,
1873 web_server_ip,
1874 web_server_port,
1875 web_server_capability,
1876 };
1877 Ok(mode_info)
1878 }
1879}
1880
1881impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
1882 type Error = &'static str;
1883 fn try_from(mode_info: ModeInfo) -> Result<Self, &'static str> {
1884 let current_mode: ProtobufInputMode = mode_info.mode.try_into()?;
1885 let base_mode: Option<ProtobufInputMode> = mode_info
1886 .base_mode
1887 .and_then(|mode| ProtobufInputMode::try_from(mode).ok());
1888 let style: ProtobufStyle = mode_info.style.try_into()?;
1889 let arrow_fonts_support: bool = mode_info.capabilities.arrow_fonts;
1890 let session_name = mode_info.session_name;
1891 let editor = mode_info.editor.map(|e| e.display().to_string());
1892 let shell = mode_info.shell.map(|s| s.display().to_string());
1893 let web_clients_allowed = mode_info.web_clients_allowed;
1894 let web_sharing = mode_info.web_sharing.map(|w| w as i32);
1895 let currently_marking_pane_group = mode_info.currently_marking_pane_group;
1896 let is_web_client = mode_info.is_web_client;
1897 let web_server_ip = mode_info.web_server_ip.map(|i| format!("{}", i));
1898 let web_server_port = mode_info.web_server_port.map(|p| p as u32);
1899 let web_server_capability = mode_info.web_server_capability;
1900 let mut protobuf_input_mode_keybinds: Vec<ProtobufInputModeKeybinds> = vec![];
1901 for (input_mode, input_mode_keybinds) in mode_info.keybinds {
1902 let mode: ProtobufInputMode = input_mode.try_into()?;
1903 let mut keybinds: Vec<ProtobufKeyBind> = vec![];
1904 for (key, actions) in input_mode_keybinds {
1905 let protobuf_key: ProtobufKey = key.try_into()?;
1906 let mut protobuf_actions: Vec<ProtobufAction> = vec![];
1907 for action in actions {
1908 if let Ok(protobuf_action) = action.try_into() {
1909 protobuf_actions.push(protobuf_action);
1910 }
1911 }
1912 let key_bind = ProtobufKeyBind {
1913 key: Some(protobuf_key),
1914 action: protobuf_actions,
1915 };
1916 keybinds.push(key_bind);
1917 }
1918 let input_mode_keybind = ProtobufInputModeKeybinds {
1919 mode: mode as i32,
1920 key_bind: keybinds,
1921 };
1922 protobuf_input_mode_keybinds.push(input_mode_keybind);
1923 }
1924 Ok(ProtobufModeUpdatePayload {
1925 current_mode: current_mode as i32,
1926 style: Some(style),
1927 keybinds: protobuf_input_mode_keybinds,
1928 arrow_fonts_support,
1929 session_name,
1930 base_mode: base_mode.map(|b_m| b_m as i32),
1931 editor,
1932 shell,
1933 web_clients_allowed,
1934 web_sharing,
1935 currently_marking_pane_group,
1936 is_web_client,
1937 web_server_ip,
1938 web_server_port,
1939 web_server_capability,
1940 })
1941 }
1942}
1943
1944impl TryFrom<ProtobufEventNameList> for HashSet<EventType> {
1945 type Error = &'static str;
1946 fn try_from(protobuf_event_name_list: ProtobufEventNameList) -> Result<Self, &'static str> {
1947 let event_types: Vec<ProtobufEventType> = protobuf_event_name_list
1948 .event_types
1949 .iter()
1950 .filter_map(|i| ProtobufEventType::from_i32(*i))
1951 .collect();
1952 let event_types: Vec<EventType> = event_types
1953 .iter()
1954 .filter_map(|e| EventType::try_from(*e).ok())
1955 .collect();
1956 Ok(event_types.into_iter().collect())
1957 }
1958}
1959
1960impl TryFrom<HashSet<EventType>> for ProtobufEventNameList {
1961 type Error = &'static str;
1962 fn try_from(event_types: HashSet<EventType>) -> Result<Self, &'static str> {
1963 let protobuf_event_name_list = ProtobufEventNameList {
1964 event_types: event_types
1965 .iter()
1966 .filter_map(|e| ProtobufEventType::try_from(*e).ok())
1967 .map(|e| e as i32)
1968 .collect(),
1969 };
1970 Ok(protobuf_event_name_list)
1971 }
1972}
1973
1974impl TryFrom<ProtobufEventType> for EventType {
1975 type Error = &'static str;
1976 fn try_from(protobuf_event_type: ProtobufEventType) -> Result<Self, &'static str> {
1977 Ok(match protobuf_event_type {
1978 ProtobufEventType::ModeUpdate => EventType::ModeUpdate,
1979 ProtobufEventType::TabUpdate => EventType::TabUpdate,
1980 ProtobufEventType::PaneUpdate => EventType::PaneUpdate,
1981 ProtobufEventType::Key => EventType::Key,
1982 ProtobufEventType::Mouse => EventType::Mouse,
1983 ProtobufEventType::Timer => EventType::Timer,
1984 ProtobufEventType::CopyToClipboard => EventType::CopyToClipboard,
1985 ProtobufEventType::SystemClipboardFailure => EventType::SystemClipboardFailure,
1986 ProtobufEventType::InputReceived => EventType::InputReceived,
1987 ProtobufEventType::Visible => EventType::Visible,
1988 ProtobufEventType::CustomMessage => EventType::CustomMessage,
1989 ProtobufEventType::FileSystemCreate => EventType::FileSystemCreate,
1990 ProtobufEventType::FileSystemRead => EventType::FileSystemRead,
1991 ProtobufEventType::FileSystemUpdate => EventType::FileSystemUpdate,
1992 ProtobufEventType::FileSystemDelete => EventType::FileSystemDelete,
1993 ProtobufEventType::PermissionRequestResult => EventType::PermissionRequestResult,
1994 ProtobufEventType::SessionUpdate => EventType::SessionUpdate,
1995 ProtobufEventType::RunCommandResult => EventType::RunCommandResult,
1996 ProtobufEventType::WebRequestResult => EventType::WebRequestResult,
1997 ProtobufEventType::CommandPaneOpened => EventType::CommandPaneOpened,
1998 ProtobufEventType::CommandPaneExited => EventType::CommandPaneExited,
1999 ProtobufEventType::PaneClosed => EventType::PaneClosed,
2000 ProtobufEventType::EditPaneOpened => EventType::EditPaneOpened,
2001 ProtobufEventType::EditPaneExited => EventType::EditPaneExited,
2002 ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
2003 ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk,
2004 ProtobufEventType::ListClients => EventType::ListClients,
2005 ProtobufEventType::HostFolderChanged => EventType::HostFolderChanged,
2006 ProtobufEventType::FailedToChangeHostFolder => EventType::FailedToChangeHostFolder,
2007 ProtobufEventType::PastedText => EventType::PastedText,
2008 ProtobufEventType::ConfigWasWrittenToDisk => EventType::ConfigWasWrittenToDisk,
2009 ProtobufEventType::WebServerStatus => EventType::WebServerStatus,
2010 ProtobufEventType::BeforeClose => EventType::BeforeClose,
2011 ProtobufEventType::FailedToStartWebServer => EventType::FailedToStartWebServer,
2012 ProtobufEventType::InterceptedKeyPress => EventType::InterceptedKeyPress,
2013 ProtobufEventType::PaneRenderReport => EventType::PaneRenderReport,
2014 ProtobufEventType::PaneRenderReportWithAnsi => EventType::PaneRenderReportWithAnsi,
2015 ProtobufEventType::UserAction => EventType::UserAction,
2016 ProtobufEventType::ActionComplete => EventType::ActionComplete,
2017 ProtobufEventType::CwdChanged => EventType::CwdChanged,
2018 ProtobufEventType::AvailableLayoutInfo => EventType::AvailableLayoutInfo,
2019 ProtobufEventType::PluginConfigurationChanged => EventType::PluginConfigurationChanged,
2020 ProtobufEventType::HighlightClicked => EventType::HighlightClicked,
2021 ProtobufEventType::InitialKeybinds => EventType::InitialKeybinds,
2022 })
2023 }
2024}
2025
2026impl TryFrom<EventType> for ProtobufEventType {
2027 type Error = &'static str;
2028 fn try_from(event_type: EventType) -> Result<Self, &'static str> {
2029 Ok(match event_type {
2030 EventType::ModeUpdate => ProtobufEventType::ModeUpdate,
2031 EventType::TabUpdate => ProtobufEventType::TabUpdate,
2032 EventType::PaneUpdate => ProtobufEventType::PaneUpdate,
2033 EventType::Key => ProtobufEventType::Key,
2034 EventType::Mouse => ProtobufEventType::Mouse,
2035 EventType::Timer => ProtobufEventType::Timer,
2036 EventType::CopyToClipboard => ProtobufEventType::CopyToClipboard,
2037 EventType::SystemClipboardFailure => ProtobufEventType::SystemClipboardFailure,
2038 EventType::InputReceived => ProtobufEventType::InputReceived,
2039 EventType::Visible => ProtobufEventType::Visible,
2040 EventType::CustomMessage => ProtobufEventType::CustomMessage,
2041 EventType::FileSystemCreate => ProtobufEventType::FileSystemCreate,
2042 EventType::FileSystemRead => ProtobufEventType::FileSystemRead,
2043 EventType::FileSystemUpdate => ProtobufEventType::FileSystemUpdate,
2044 EventType::FileSystemDelete => ProtobufEventType::FileSystemDelete,
2045 EventType::PermissionRequestResult => ProtobufEventType::PermissionRequestResult,
2046 EventType::SessionUpdate => ProtobufEventType::SessionUpdate,
2047 EventType::RunCommandResult => ProtobufEventType::RunCommandResult,
2048 EventType::WebRequestResult => ProtobufEventType::WebRequestResult,
2049 EventType::CommandPaneOpened => ProtobufEventType::CommandPaneOpened,
2050 EventType::CommandPaneExited => ProtobufEventType::CommandPaneExited,
2051 EventType::PaneClosed => ProtobufEventType::PaneClosed,
2052 EventType::EditPaneOpened => ProtobufEventType::EditPaneOpened,
2053 EventType::EditPaneExited => ProtobufEventType::EditPaneExited,
2054 EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
2055 EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk,
2056 EventType::ListClients => ProtobufEventType::ListClients,
2057 EventType::HostFolderChanged => ProtobufEventType::HostFolderChanged,
2058 EventType::FailedToChangeHostFolder => ProtobufEventType::FailedToChangeHostFolder,
2059 EventType::PastedText => ProtobufEventType::PastedText,
2060 EventType::ConfigWasWrittenToDisk => ProtobufEventType::ConfigWasWrittenToDisk,
2061 EventType::WebServerStatus => ProtobufEventType::WebServerStatus,
2062 EventType::BeforeClose => ProtobufEventType::BeforeClose,
2063 EventType::FailedToStartWebServer => ProtobufEventType::FailedToStartWebServer,
2064 EventType::InterceptedKeyPress => ProtobufEventType::InterceptedKeyPress,
2065 EventType::PaneRenderReport => ProtobufEventType::PaneRenderReport,
2066 EventType::PaneRenderReportWithAnsi => ProtobufEventType::PaneRenderReportWithAnsi,
2067 EventType::UserAction => ProtobufEventType::UserAction,
2068 EventType::ActionComplete => ProtobufEventType::ActionComplete,
2069 EventType::CwdChanged => ProtobufEventType::CwdChanged,
2070 EventType::AvailableLayoutInfo => ProtobufEventType::AvailableLayoutInfo,
2071 EventType::PluginConfigurationChanged => ProtobufEventType::PluginConfigurationChanged,
2072 EventType::HighlightClicked => ProtobufEventType::HighlightClicked,
2073 EventType::InitialKeybinds => ProtobufEventType::InitialKeybinds,
2074 })
2075 }
2076}
2077
2078impl From<ProtobufResurrectableSession> for (String, Duration) {
2079 fn from(protobuf_resurrectable_session: ProtobufResurrectableSession) -> (String, Duration) {
2080 (
2081 protobuf_resurrectable_session.name,
2082 Duration::from_secs(protobuf_resurrectable_session.creation_time),
2083 )
2084 }
2085}
2086
2087impl From<(String, Duration)> for ProtobufResurrectableSession {
2088 fn from(session_name_and_creation_time: (String, Duration)) -> ProtobufResurrectableSession {
2089 ProtobufResurrectableSession {
2090 name: session_name_and_creation_time.0,
2091 creation_time: session_name_and_creation_time.1.as_secs(),
2092 }
2093 }
2094}
2095
2096impl From<&ProtobufFileMetadata> for Option<FileMetadata> {
2097 fn from(protobuf_file_metadata: &ProtobufFileMetadata) -> Option<FileMetadata> {
2098 if protobuf_file_metadata.metadata_is_set {
2099 Some(FileMetadata {
2100 is_file: protobuf_file_metadata.is_file,
2101 is_dir: protobuf_file_metadata.is_dir,
2102 is_symlink: protobuf_file_metadata.is_symlink,
2103 len: protobuf_file_metadata.len,
2104 })
2105 } else {
2106 None
2107 }
2108 }
2109}
2110
2111impl From<Option<FileMetadata>> for ProtobufFileMetadata {
2112 fn from(file_metadata: Option<FileMetadata>) -> ProtobufFileMetadata {
2113 match file_metadata {
2114 Some(file_metadata) => ProtobufFileMetadata {
2115 metadata_is_set: true,
2116 is_file: file_metadata.is_file,
2117 is_dir: file_metadata.is_dir,
2118 is_symlink: file_metadata.is_symlink,
2119 len: file_metadata.len,
2120 },
2121 None => ProtobufFileMetadata {
2122 metadata_is_set: false,
2123 ..Default::default()
2124 },
2125 }
2126 }
2127}
2128
2129#[test]
2130fn serialize_mode_update_event() {
2131 use prost::Message;
2132 let mode_update_event = Event::ModeUpdate(Default::default());
2133 let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
2134 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2135 let deserialized_protobuf_event: ProtobufEvent =
2136 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2137 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2138 assert_eq!(
2139 mode_update_event, deserialized_event,
2140 "Event properly serialized/deserialized without change"
2141 );
2142}
2143
2144#[test]
2145fn serialize_mode_update_event_with_non_default_values() {
2146 use crate::data::{BareKey, Palette, PaletteColor, ThemeHue};
2147 use prost::Message;
2148 let mode_update_event = Event::ModeUpdate(ModeInfo {
2149 mode: InputMode::Locked,
2150 keybinds: vec![
2151 (
2152 InputMode::Locked,
2153 vec![(
2154 KeyWithModifier::new(BareKey::Char('b')).with_alt_modifier(),
2155 vec![Action::SwitchToMode {
2156 input_mode: InputMode::Normal,
2157 }],
2158 )],
2159 ),
2160 (
2161 InputMode::Tab,
2162 vec![(
2163 KeyWithModifier::new(BareKey::Up).with_alt_modifier(),
2164 vec![Action::SwitchToMode {
2165 input_mode: InputMode::Pane,
2166 }],
2167 )],
2168 ),
2169 (
2170 InputMode::Pane,
2171 vec![
2172 (
2173 KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
2174 vec![
2175 Action::SwitchToMode {
2176 input_mode: InputMode::Tmux,
2177 },
2178 Action::Write {
2179 key_with_modifier: None,
2180 bytes: vec![10],
2181 is_kitty_keyboard_protocol: false,
2182 },
2183 ],
2184 ),
2185 (
2186 KeyWithModifier::new(BareKey::Char('a')),
2187 vec![Action::WriteChars {
2188 chars: "foo".to_owned(),
2189 }],
2190 ),
2191 ],
2192 ),
2193 ],
2194 style: Style {
2195 colors: Palette {
2196 source: crate::data::PaletteSource::Default,
2197 theme_hue: ThemeHue::Light,
2198 fg: PaletteColor::Rgb((1, 1, 1)),
2199 bg: PaletteColor::Rgb((200, 200, 200)),
2200 black: PaletteColor::EightBit(1),
2201 red: PaletteColor::EightBit(2),
2202 green: PaletteColor::EightBit(2),
2203 yellow: PaletteColor::EightBit(2),
2204 blue: PaletteColor::EightBit(2),
2205 magenta: PaletteColor::EightBit(2),
2206 cyan: PaletteColor::EightBit(2),
2207 white: PaletteColor::EightBit(2),
2208 orange: PaletteColor::EightBit(2),
2209 gray: PaletteColor::EightBit(2),
2210 purple: PaletteColor::EightBit(2),
2211 gold: PaletteColor::EightBit(2),
2212 silver: PaletteColor::EightBit(2),
2213 pink: PaletteColor::EightBit(2),
2214 brown: PaletteColor::Rgb((222, 221, 220)),
2215 }
2216 .into(),
2217 rounded_corners: true,
2219 hide_session_name: false,
2220 },
2221 capabilities: PluginCapabilities { arrow_fonts: false },
2222 session_name: Some("my awesome test session".to_owned()),
2223 base_mode: Some(InputMode::Locked),
2224 editor: Some(PathBuf::from("my_awesome_editor")),
2225 shell: Some(PathBuf::from("my_awesome_shell")),
2226 web_clients_allowed: Some(true),
2227 web_sharing: Some(WebSharing::default()),
2228 currently_marking_pane_group: Some(false),
2229 is_web_client: Some(false),
2230 web_server_ip: IpAddr::from_str("127.0.0.1").ok(),
2231 web_server_port: Some(8082),
2232 web_server_capability: Some(true),
2233 });
2234 let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
2235 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2236 let deserialized_protobuf_event: ProtobufEvent =
2237 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2238 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2239 assert_eq!(
2240 mode_update_event, deserialized_event,
2241 "Event properly serialized/deserialized without change"
2242 );
2243}
2244
2245#[test]
2246fn serialize_tab_update_event() {
2247 use prost::Message;
2248 let tab_update_event = Event::TabUpdate(Default::default());
2249 let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
2250 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2251 let deserialized_protobuf_event: ProtobufEvent =
2252 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2253 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2254 assert_eq!(
2255 tab_update_event, deserialized_event,
2256 "Event properly serialized/deserialized without change"
2257 );
2258}
2259
2260#[test]
2261fn serialize_tab_update_event_with_non_default_values() {
2262 use prost::Message;
2263 let tab_update_event = Event::TabUpdate(vec![
2264 TabInfo {
2265 position: 0,
2266 name: "First tab".to_owned(),
2267 active: true,
2268 panes_to_hide: 2,
2269 is_fullscreen_active: true,
2270 is_sync_panes_active: false,
2271 are_floating_panes_visible: true,
2272 other_focused_clients: vec![2, 3, 4],
2273 active_swap_layout_name: Some("my cool swap layout".to_owned()),
2274 is_swap_layout_dirty: false,
2275 viewport_rows: 10,
2276 viewport_columns: 10,
2277 display_area_rows: 10,
2278 display_area_columns: 10,
2279 selectable_tiled_panes_count: 10,
2280 selectable_floating_panes_count: 10,
2281 tab_id: 0,
2282 has_bell_notification: false,
2283 is_flashing_bell: false,
2284 },
2285 TabInfo {
2286 position: 1,
2287 name: "Secondtab".to_owned(),
2288 active: false,
2289 panes_to_hide: 5,
2290 is_fullscreen_active: false,
2291 is_sync_panes_active: true,
2292 are_floating_panes_visible: true,
2293 other_focused_clients: vec![1, 5, 111],
2294 active_swap_layout_name: None,
2295 is_swap_layout_dirty: true,
2296 viewport_rows: 10,
2297 viewport_columns: 10,
2298 display_area_rows: 10,
2299 display_area_columns: 10,
2300 selectable_tiled_panes_count: 10,
2301 selectable_floating_panes_count: 10,
2302 tab_id: 1,
2303 has_bell_notification: false,
2304 is_flashing_bell: false,
2305 },
2306 TabInfo::default(),
2307 ]);
2308 let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
2309 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2310 let deserialized_protobuf_event: ProtobufEvent =
2311 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2312 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2313 assert_eq!(
2314 tab_update_event, deserialized_event,
2315 "Event properly serialized/deserialized without change"
2316 );
2317}
2318
2319#[test]
2320fn serialize_pane_update_event() {
2321 use prost::Message;
2322 let pane_update_event = Event::PaneUpdate(Default::default());
2323 let protobuf_event: ProtobufEvent = pane_update_event.clone().try_into().unwrap();
2324 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2325 let deserialized_protobuf_event: ProtobufEvent =
2326 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2327 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2328 assert_eq!(
2329 pane_update_event, deserialized_event,
2330 "Event properly serialized/deserialized without change"
2331 );
2332}
2333
2334#[test]
2335fn serialize_key_event() {
2336 use crate::data::BareKey;
2337 use prost::Message;
2338 let key_event = Event::Key(KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier());
2339 let protobuf_event: ProtobufEvent = key_event.clone().try_into().unwrap();
2340 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2341 let deserialized_protobuf_event: ProtobufEvent =
2342 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2343 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2344 assert_eq!(
2345 key_event, deserialized_event,
2346 "Event properly serialized/deserialized without change"
2347 );
2348}
2349
2350#[test]
2351fn serialize_mouse_event() {
2352 use prost::Message;
2353 let mouse_event = Event::Mouse(Mouse::LeftClick(1, 1));
2354 let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
2355 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2356 let deserialized_protobuf_event: ProtobufEvent =
2357 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2358 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2359 assert_eq!(
2360 mouse_event, deserialized_event,
2361 "Event properly serialized/deserialized without change"
2362 );
2363}
2364
2365#[test]
2366fn serialize_mouse_event_without_position() {
2367 use prost::Message;
2368 let mouse_event = Event::Mouse(Mouse::ScrollUp(17));
2369 let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
2370 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2371 let deserialized_protobuf_event: ProtobufEvent =
2372 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2373 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2374 assert_eq!(
2375 mouse_event, deserialized_event,
2376 "Event properly serialized/deserialized without change"
2377 );
2378}
2379
2380#[test]
2381fn serialize_timer_event() {
2382 use prost::Message;
2383 let timer_event = Event::Timer(1.5);
2384 let protobuf_event: ProtobufEvent = timer_event.clone().try_into().unwrap();
2385 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2386 let deserialized_protobuf_event: ProtobufEvent =
2387 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2388 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2389 assert_eq!(
2390 timer_event, deserialized_event,
2391 "Event properly serialized/deserialized without change"
2392 );
2393}
2394
2395#[test]
2396fn serialize_copy_to_clipboard_event() {
2397 use prost::Message;
2398 let copy_event = Event::CopyToClipboard(CopyDestination::Primary);
2399 let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
2400 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2401 let deserialized_protobuf_event: ProtobufEvent =
2402 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2403 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2404 assert_eq!(
2405 copy_event, deserialized_event,
2406 "Event properly serialized/deserialized without change"
2407 );
2408}
2409
2410#[test]
2411fn serialize_clipboard_failure_event() {
2412 use prost::Message;
2413 let copy_event = Event::SystemClipboardFailure;
2414 let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
2415 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2416 let deserialized_protobuf_event: ProtobufEvent =
2417 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2418 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2419 assert_eq!(
2420 copy_event, deserialized_event,
2421 "Event properly serialized/deserialized without change"
2422 );
2423}
2424
2425#[test]
2426fn serialize_input_received_event() {
2427 use prost::Message;
2428 let input_received_event = Event::InputReceived;
2429 let protobuf_event: ProtobufEvent = input_received_event.clone().try_into().unwrap();
2430 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2431 let deserialized_protobuf_event: ProtobufEvent =
2432 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2433 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2434 assert_eq!(
2435 input_received_event, deserialized_event,
2436 "Event properly serialized/deserialized without change"
2437 );
2438}
2439
2440#[test]
2441fn serialize_visible_event() {
2442 use prost::Message;
2443 let visible_event = Event::Visible(true);
2444 let protobuf_event: ProtobufEvent = visible_event.clone().try_into().unwrap();
2445 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2446 let deserialized_protobuf_event: ProtobufEvent =
2447 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2448 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2449 assert_eq!(
2450 visible_event, deserialized_event,
2451 "Event properly serialized/deserialized without change"
2452 );
2453}
2454
2455#[test]
2456fn serialize_custom_message_event() {
2457 use prost::Message;
2458 let custom_message_event = Event::CustomMessage("foo".to_owned(), "bar".to_owned());
2459 let protobuf_event: ProtobufEvent = custom_message_event.clone().try_into().unwrap();
2460 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2461 let deserialized_protobuf_event: ProtobufEvent =
2462 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2463 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2464 assert_eq!(
2465 custom_message_event, deserialized_event,
2466 "Event properly serialized/deserialized without change"
2467 );
2468}
2469
2470#[test]
2471fn serialize_file_system_create_event() {
2472 use prost::Message;
2473 let file_system_event = Event::FileSystemCreate(vec![
2474 ("/absolute/path".into(), None),
2475 ("./relative_path".into(), Default::default()),
2476 ]);
2477 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
2478 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2479 let deserialized_protobuf_event: ProtobufEvent =
2480 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2481 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2482 assert_eq!(
2483 file_system_event, deserialized_event,
2484 "Event properly serialized/deserialized without change"
2485 );
2486}
2487
2488#[test]
2489fn serialize_file_system_read_event() {
2490 use prost::Message;
2491 let file_system_event = Event::FileSystemRead(vec![
2492 ("/absolute/path".into(), None),
2493 ("./relative_path".into(), Default::default()),
2494 ]);
2495 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
2496 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2497 let deserialized_protobuf_event: ProtobufEvent =
2498 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2499 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2500 assert_eq!(
2501 file_system_event, deserialized_event,
2502 "Event properly serialized/deserialized without change"
2503 );
2504}
2505
2506#[test]
2507fn serialize_file_system_update_event() {
2508 use prost::Message;
2509 let file_system_event = Event::FileSystemUpdate(vec![
2510 ("/absolute/path".into(), None),
2511 ("./relative_path".into(), Some(Default::default())),
2512 ]);
2513 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
2514 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2515 let deserialized_protobuf_event: ProtobufEvent =
2516 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2517 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2518 assert_eq!(
2519 file_system_event, deserialized_event,
2520 "Event properly serialized/deserialized without change"
2521 );
2522}
2523
2524#[test]
2525fn serialize_file_system_delete_event() {
2526 use prost::Message;
2527 let file_system_event = Event::FileSystemDelete(vec![
2528 ("/absolute/path".into(), None),
2529 ("./relative_path".into(), Default::default()),
2530 ]);
2531 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
2532 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2533 let deserialized_protobuf_event: ProtobufEvent =
2534 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2535 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2536 assert_eq!(
2537 file_system_event, deserialized_event,
2538 "Event properly serialized/deserialized without change"
2539 );
2540}
2541
2542#[test]
2543fn serialize_session_update_event() {
2544 use prost::Message;
2545 let session_update_event = Event::SessionUpdate(Default::default(), Default::default());
2546 let protobuf_event: ProtobufEvent = session_update_event.clone().try_into().unwrap();
2547 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2548 let deserialized_protobuf_event: ProtobufEvent =
2549 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2550 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2551 assert_eq!(
2552 session_update_event, deserialized_event,
2553 "Event properly serialized/deserialized without change"
2554 );
2555}
2556
2557#[test]
2558fn serialize_session_update_event_with_non_default_values() {
2559 use prost::Message;
2560 let tab_infos = vec![
2561 TabInfo {
2562 position: 0,
2563 name: "First tab".to_owned(),
2564 active: true,
2565 panes_to_hide: 2,
2566 is_fullscreen_active: true,
2567 is_sync_panes_active: false,
2568 are_floating_panes_visible: true,
2569 other_focused_clients: vec![2, 3, 4],
2570 active_swap_layout_name: Some("my cool swap layout".to_owned()),
2571 is_swap_layout_dirty: false,
2572 viewport_rows: 10,
2573 viewport_columns: 10,
2574 display_area_rows: 10,
2575 display_area_columns: 10,
2576 selectable_tiled_panes_count: 10,
2577 selectable_floating_panes_count: 10,
2578 tab_id: 0,
2579 has_bell_notification: false,
2580 is_flashing_bell: false,
2581 },
2582 TabInfo {
2583 position: 1,
2584 name: "Secondtab".to_owned(),
2585 active: false,
2586 panes_to_hide: 5,
2587 is_fullscreen_active: false,
2588 is_sync_panes_active: true,
2589 are_floating_panes_visible: true,
2590 other_focused_clients: vec![1, 5, 111],
2591 active_swap_layout_name: None,
2592 is_swap_layout_dirty: true,
2593 viewport_rows: 10,
2594 viewport_columns: 10,
2595 display_area_rows: 10,
2596 display_area_columns: 10,
2597 selectable_tiled_panes_count: 10,
2598 selectable_floating_panes_count: 10,
2599 tab_id: 1,
2600 has_bell_notification: false,
2601 is_flashing_bell: false,
2602 },
2603 TabInfo::default(),
2604 ];
2605 let mut panes = HashMap::new();
2606 let mut index_in_pane_group_1 = BTreeMap::new();
2607 index_in_pane_group_1.insert(1, 0);
2608 index_in_pane_group_1.insert(2, 0);
2609 index_in_pane_group_1.insert(3, 0);
2610 let mut index_in_pane_group_2 = BTreeMap::new();
2611 index_in_pane_group_2.insert(1, 1);
2612 index_in_pane_group_2.insert(2, 1);
2613 index_in_pane_group_2.insert(3, 1);
2614 let panes_list = vec![
2615 PaneInfo {
2616 id: 1,
2617 is_plugin: false,
2618 is_focused: true,
2619 is_fullscreen: true,
2620 is_floating: false,
2621 is_suppressed: false,
2622 title: "pane 1".to_owned(),
2623 exited: false,
2624 exit_status: None,
2625 is_held: false,
2626 pane_x: 0,
2627 pane_content_x: 1,
2628 pane_y: 0,
2629 pane_content_y: 1,
2630 pane_rows: 5,
2631 pane_content_rows: 4,
2632 pane_columns: 22,
2633 pane_content_columns: 21,
2634 cursor_coordinates_in_pane: Some((0, 0)),
2635 terminal_command: Some("foo".to_owned()),
2636 plugin_url: None,
2637 is_selectable: true,
2638 index_in_pane_group: index_in_pane_group_1,
2639 default_fg: None,
2640 default_bg: None,
2641 },
2642 PaneInfo {
2643 id: 1,
2644 is_plugin: true,
2645 is_focused: true,
2646 is_fullscreen: true,
2647 is_floating: false,
2648 is_suppressed: false,
2649 title: "pane 1".to_owned(),
2650 exited: false,
2651 exit_status: None,
2652 is_held: false,
2653 pane_x: 0,
2654 pane_content_x: 1,
2655 pane_y: 0,
2656 pane_content_y: 1,
2657 pane_rows: 5,
2658 pane_content_rows: 4,
2659 pane_columns: 22,
2660 pane_content_columns: 21,
2661 cursor_coordinates_in_pane: Some((0, 0)),
2662 terminal_command: None,
2663 plugin_url: Some("i_am_a_fake_plugin".to_owned()),
2664 is_selectable: true,
2665 index_in_pane_group: index_in_pane_group_2,
2666 default_fg: None,
2667 default_bg: None,
2668 },
2669 ];
2670 panes.insert(0, panes_list);
2671 let mut plugins = BTreeMap::new();
2672 let mut plugin_configuration = BTreeMap::new();
2673 plugin_configuration.insert("config_key".to_owned(), "config_value".to_owned());
2674 plugins.insert(
2675 1,
2676 PluginInfo {
2677 location: "https://example.com/my-plugin.wasm".to_owned(),
2678 configuration: plugin_configuration,
2679 },
2680 );
2681 let mut tab_history = BTreeMap::new();
2682 tab_history.insert(1, vec![1, 2, 3]);
2683 tab_history.insert(2, vec![1, 2, 3]);
2684 let session_info_1 = SessionInfo {
2685 name: "session 1".to_owned(),
2686 tabs: tab_infos,
2687 panes: PaneManifest { panes },
2688 connected_clients: 2,
2689 is_current_session: true,
2690 available_layouts: vec![
2691 LayoutInfo::File(
2692 "layout 1".to_owned(),
2693 LayoutMetadata {
2694 tabs: vec![],
2695 creation_time: "0".to_owned(),
2696 update_time: "0".to_owned(),
2697 },
2698 ),
2699 LayoutInfo::BuiltIn("layout2".to_owned()),
2700 LayoutInfo::File(
2701 "layout3".to_owned(),
2702 LayoutMetadata {
2703 tabs: vec![],
2704 creation_time: "0".to_owned(),
2705 update_time: "0".to_owned(),
2706 },
2707 ),
2708 ],
2709 plugins,
2710 web_clients_allowed: false,
2711 web_client_count: 1,
2712 tab_history,
2713 pane_history: Default::default(),
2714 creation_time: Duration::from_secs(100),
2715 };
2716 let session_info_2 = SessionInfo {
2717 name: "session 2".to_owned(),
2718 tabs: vec![],
2719 panes: PaneManifest {
2720 panes: HashMap::new(),
2721 },
2722 connected_clients: 0,
2723 is_current_session: false,
2724 available_layouts: vec![
2725 LayoutInfo::File(
2726 "layout 1".to_owned(),
2727 LayoutMetadata {
2728 tabs: vec![],
2729 creation_time: "0".to_owned(),
2730 update_time: "0".to_owned(),
2731 },
2732 ),
2733 LayoutInfo::BuiltIn("layout2".to_owned()),
2734 LayoutInfo::File(
2735 "layout3".to_owned(),
2736 LayoutMetadata {
2737 tabs: vec![],
2738 creation_time: "0".to_owned(),
2739 update_time: "0".to_owned(),
2740 },
2741 ),
2742 ],
2743 plugins: Default::default(),
2744 web_clients_allowed: false,
2745 web_client_count: 0,
2746 tab_history: Default::default(),
2747 pane_history: Default::default(),
2748 creation_time: Duration::from_secs(200),
2749 };
2750 let session_infos = vec![session_info_1, session_info_2];
2751 let resurrectable_sessions = vec![];
2752
2753 let session_update_event = Event::SessionUpdate(session_infos, resurrectable_sessions);
2754 let protobuf_event: ProtobufEvent = session_update_event.clone().try_into().unwrap();
2755 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2756 let deserialized_protobuf_event: ProtobufEvent =
2757 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2758 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2759 assert_eq!(
2760 session_update_event, deserialized_event,
2761 "Event properly serialized/deserialized without change"
2762 );
2763}
2764
2765impl TryFrom<ProtobufPaneId> for PaneId {
2769 type Error = &'static str;
2770 fn try_from(protobuf_pane_id: ProtobufPaneId) -> Result<Self, &'static str> {
2771 match ProtobufPaneType::from_i32(protobuf_pane_id.pane_type) {
2772 Some(ProtobufPaneType::Terminal) => Ok(PaneId::Terminal(protobuf_pane_id.id)),
2773 Some(ProtobufPaneType::Plugin) => Ok(PaneId::Plugin(protobuf_pane_id.id)),
2774 None => Err("Failed to convert PaneId"),
2775 }
2776 }
2777}
2778
2779impl TryFrom<PaneId> for ProtobufPaneId {
2783 type Error = &'static str;
2784 fn try_from(pane_id: PaneId) -> Result<Self, &'static str> {
2785 match pane_id {
2786 PaneId::Terminal(id) => Ok(ProtobufPaneId {
2787 pane_type: ProtobufPaneType::Terminal as i32,
2788 id,
2789 }),
2790 PaneId::Plugin(id) => Ok(ProtobufPaneId {
2791 pane_type: ProtobufPaneType::Plugin as i32,
2792 id,
2793 }),
2794 }
2795 }
2796}
2797
2798impl Into<ProtobufWebSharing> for WebSharing {
2799 fn into(self) -> ProtobufWebSharing {
2800 match self {
2801 WebSharing::On => ProtobufWebSharing::On,
2802 WebSharing::Off => ProtobufWebSharing::Off,
2803 WebSharing::Disabled => ProtobufWebSharing::Disabled,
2804 }
2805 }
2806}
2807
2808impl Into<WebSharing> for ProtobufWebSharing {
2809 fn into(self) -> WebSharing {
2810 match self {
2811 ProtobufWebSharing::On => WebSharing::On,
2812 ProtobufWebSharing::Off => WebSharing::Off,
2813 ProtobufWebSharing::Disabled => WebSharing::Disabled,
2814 }
2815 }
2816}
2817
2818impl TryFrom<WebServerStatus> for ProtobufWebServerStatusPayload {
2819 type Error = &'static str;
2820 fn try_from(web_server_status: WebServerStatus) -> Result<Self, &'static str> {
2821 match web_server_status {
2822 WebServerStatus::Online(url) => Ok(ProtobufWebServerStatusPayload {
2823 web_server_status_indication: WebServerStatusIndication::Online as i32,
2824 payload: Some(url),
2825 }),
2826 WebServerStatus::DifferentVersion(version) => Ok(ProtobufWebServerStatusPayload {
2827 web_server_status_indication: WebServerStatusIndication::DifferentVersion as i32,
2828 payload: Some(format!("{}", version)),
2829 }),
2830 WebServerStatus::Offline => Ok(ProtobufWebServerStatusPayload {
2831 web_server_status_indication: WebServerStatusIndication::Offline as i32,
2832 payload: None,
2833 }),
2834 }
2835 }
2836}
2837
2838impl TryFrom<ProtobufWebServerStatusPayload> for WebServerStatus {
2839 type Error = &'static str;
2840 fn try_from(
2841 protobuf_web_server_status: ProtobufWebServerStatusPayload,
2842 ) -> Result<Self, &'static str> {
2843 match WebServerStatusIndication::from_i32(
2844 protobuf_web_server_status.web_server_status_indication,
2845 ) {
2846 Some(WebServerStatusIndication::Online) => {
2847 let payload = protobuf_web_server_status
2848 .payload
2849 .ok_or("payload_not_found")?;
2850 Ok(WebServerStatus::Online(payload))
2851 },
2852 Some(WebServerStatusIndication::DifferentVersion) => {
2853 let payload = protobuf_web_server_status
2854 .payload
2855 .ok_or("payload_not_found")?;
2856 Ok(WebServerStatus::DifferentVersion(payload))
2857 },
2858 Some(WebServerStatusIndication::Offline) => Ok(WebServerStatus::Offline),
2859 None => Err("Unknown status"),
2860 }
2861 }
2862}
2863
2864impl TryFrom<ProtobufPaneRenderReportPayload> for HashMap<PaneId, PaneContents> {
2865 type Error = &'static str;
2866 fn try_from(protobuf_payload: ProtobufPaneRenderReportPayload) -> Result<Self, &'static str> {
2867 let mut pane_contents_map = HashMap::new();
2868
2869 for entry in protobuf_payload.pane_contents {
2870 let pane_id = entry
2871 .pane_id
2872 .ok_or("Missing pane_id in PaneContentsEntry")?
2873 .try_into()?;
2874 let pane_contents = entry
2875 .pane_contents
2876 .ok_or("Missing pane_contents in PaneContentsEntry")?
2877 .try_into()?;
2878 pane_contents_map.insert(pane_id, pane_contents);
2879 }
2880
2881 Ok(pane_contents_map)
2882 }
2883}
2884
2885impl TryFrom<HashMap<PaneId, PaneContents>> for ProtobufPaneRenderReportPayload {
2886 type Error = &'static str;
2887 fn try_from(pane_contents_map: HashMap<PaneId, PaneContents>) -> Result<Self, &'static str> {
2888 let mut pane_contents_vec = vec![];
2889
2890 for (pane_id, pane_contents) in pane_contents_map {
2891 pane_contents_vec.push(ProtobufPaneContentsEntry {
2892 pane_id: Some(pane_id.try_into()?),
2893 pane_contents: Some(pane_contents.try_into()?),
2894 });
2895 }
2896
2897 Ok(ProtobufPaneRenderReportPayload {
2898 pane_contents: pane_contents_vec,
2899 })
2900 }
2901}
2902
2903impl TryFrom<ProtobufPaneContents> for PaneContents {
2904 type Error = &'static str;
2905 fn try_from(protobuf_contents: ProtobufPaneContents) -> Result<Self, &'static str> {
2906 let selected_text = protobuf_contents
2907 .selected_text
2908 .map(|st| st.try_into())
2909 .transpose()?;
2910
2911 Ok(PaneContents {
2912 viewport: protobuf_contents.viewport,
2913 selected_text,
2914 lines_above_viewport: protobuf_contents.lines_above_viewport,
2915 lines_below_viewport: protobuf_contents.lines_below_viewport,
2916 })
2917 }
2918}
2919
2920impl TryFrom<PaneContents> for ProtobufPaneContents {
2921 type Error = &'static str;
2922 fn try_from(pane_contents: PaneContents) -> Result<Self, &'static str> {
2923 let selected_text = pane_contents
2924 .selected_text
2925 .map(|st| st.try_into())
2926 .transpose()?;
2927
2928 Ok(ProtobufPaneContents {
2929 viewport: pane_contents.viewport,
2930 selected_text,
2931 lines_above_viewport: pane_contents.lines_above_viewport,
2932 lines_below_viewport: pane_contents.lines_below_viewport,
2933 })
2934 }
2935}
2936
2937impl TryFrom<ProtobufPaneScrollbackResponse> for PaneScrollbackResponse {
2938 type Error = &'static str;
2939 fn try_from(protobuf_response: ProtobufPaneScrollbackResponse) -> Result<Self, &'static str> {
2940 match protobuf_response.response {
2941 Some(pane_scrollback_response::Response::Ok(pane_contents)) => {
2942 Ok(PaneScrollbackResponse::Ok(pane_contents.try_into()?))
2943 },
2944 Some(pane_scrollback_response::Response::Err(error_msg)) => {
2945 Ok(PaneScrollbackResponse::Err(error_msg))
2946 },
2947 None => Err("PaneScrollbackResponse missing response field"),
2948 }
2949 }
2950}
2951
2952impl TryFrom<PaneScrollbackResponse> for ProtobufPaneScrollbackResponse {
2953 type Error = &'static str;
2954 fn try_from(response: PaneScrollbackResponse) -> Result<Self, &'static str> {
2955 let response_field = match response {
2956 PaneScrollbackResponse::Ok(pane_contents) => {
2957 pane_scrollback_response::Response::Ok(pane_contents.try_into()?)
2958 },
2959 PaneScrollbackResponse::Err(error_msg) => {
2960 pane_scrollback_response::Response::Err(error_msg)
2961 },
2962 };
2963 Ok(ProtobufPaneScrollbackResponse {
2964 response: Some(response_field),
2965 })
2966 }
2967}
2968
2969impl TryFrom<ProtobufSelectedText> for SelectedText {
2970 type Error = &'static str;
2971 fn try_from(protobuf_selected_text: ProtobufSelectedText) -> Result<Self, &'static str> {
2972 Ok(SelectedText {
2973 start: protobuf_selected_text
2974 .start
2975 .ok_or("Missing start in SelectedText")?
2976 .try_into()?,
2977 end: protobuf_selected_text
2978 .end
2979 .ok_or("Missing end in SelectedText")?
2980 .try_into()?,
2981 })
2982 }
2983}
2984
2985impl TryFrom<SelectedText> for ProtobufSelectedText {
2986 type Error = &'static str;
2987 fn try_from(selected_text: SelectedText) -> Result<Self, &'static str> {
2988 Ok(ProtobufSelectedText {
2989 start: Some(selected_text.start.try_into()?),
2990 end: Some(selected_text.end.try_into()?),
2991 })
2992 }
2993}
2994
2995#[test]
2996fn serialize_pane_render_report_with_ansi_event() {
2997 use prost::Message;
2998 let pane_render_report_with_ansi_event = Event::PaneRenderReportWithAnsi(Default::default());
2999 let protobuf_event: ProtobufEvent = pane_render_report_with_ansi_event
3000 .clone()
3001 .try_into()
3002 .unwrap();
3003 let serialized_protobuf_event = protobuf_event.encode_to_vec();
3004 let deserialized_protobuf_event: ProtobufEvent =
3005 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
3006 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
3007 assert_eq!(
3008 pane_render_report_with_ansi_event, deserialized_event,
3009 "Event properly serialized/deserialized without change"
3010 );
3011}
3012
3013#[test]
3014fn serialize_pane_render_report_with_ansi_event_with_data() {
3015 use prost::Message;
3016 use std::collections::HashMap;
3017 let mut pane_contents_map = HashMap::new();
3018 pane_contents_map.insert(
3019 PaneId::Terminal(1),
3020 PaneContents {
3021 viewport: vec![
3022 "\x1b[31mred text\x1b[0m".to_owned(),
3023 "\x1b[1mbold text\x1b[0m".to_owned(),
3024 ],
3025 selected_text: None,
3026 lines_above_viewport: vec![],
3027 lines_below_viewport: vec![],
3028 },
3029 );
3030 let event = Event::PaneRenderReportWithAnsi(pane_contents_map);
3031 let protobuf_event: ProtobufEvent = event.clone().try_into().unwrap();
3032 let serialized_protobuf_event = protobuf_event.encode_to_vec();
3033 let deserialized_protobuf_event: ProtobufEvent =
3034 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
3035 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
3036 assert_eq!(
3037 event, deserialized_event,
3038 "PaneRenderReportWithAnsi event with ANSI data properly serialized/deserialized"
3039 );
3040}