1pub use super::generated_api::api::{
2 action::{Action as ProtobufAction, Position as ProtobufPosition},
3 event::{
4 event::Payload as ProtobufEventPayload, ClientInfo as ProtobufClientInfo,
5 ClientTabHistory as ProtobufClientTabHistory, CopyDestination as ProtobufCopyDestination,
6 Event as ProtobufEvent, EventNameList as ProtobufEventNameList,
7 EventType as ProtobufEventType, FileMetadata as ProtobufFileMetadata,
8 InputModeKeybinds as ProtobufInputModeKeybinds, KeyBind as ProtobufKeyBind,
9 LayoutInfo as ProtobufLayoutInfo, ModeUpdatePayload as ProtobufModeUpdatePayload,
10 PaneId as ProtobufPaneId, PaneInfo as ProtobufPaneInfo,
11 PaneManifest as ProtobufPaneManifest, PaneType as ProtobufPaneType,
12 PluginInfo as ProtobufPluginInfo, ResurrectableSession as ProtobufResurrectableSession,
13 SessionManifest as ProtobufSessionManifest, TabInfo as ProtobufTabInfo,
14 WebServerStatusPayload as ProtobufWebServerStatusPayload, WebSharing as ProtobufWebSharing,
15 *,
16 },
17 input_mode::InputMode as ProtobufInputMode,
18 key::Key as ProtobufKey,
19 style::Style as ProtobufStyle,
20};
21#[allow(hidden_glob_reexports)]
22use crate::data::{
23 ClientInfo, CopyDestination, Event, EventType, FileMetadata, InputMode, KeyWithModifier,
24 LayoutInfo, ModeInfo, Mouse, PaneId, PaneInfo, PaneManifest, PermissionStatus,
25 PluginCapabilities, PluginInfo, SessionInfo, Style, TabInfo, WebServerStatus, WebSharing,
26};
27
28use crate::errors::prelude::*;
29use crate::input::actions::Action;
30
31use std::collections::{BTreeMap, HashMap, HashSet};
32use std::convert::TryFrom;
33use std::net::IpAddr;
34use std::path::PathBuf;
35use std::str::FromStr;
36use std::time::Duration;
37
38impl TryFrom<ProtobufEvent> for Event {
39 type Error = &'static str;
40 fn try_from(protobuf_event: ProtobufEvent) -> Result<Self, &'static str> {
41 match ProtobufEventType::from_i32(protobuf_event.name) {
42 Some(ProtobufEventType::ModeUpdate) => match protobuf_event.payload {
43 Some(ProtobufEventPayload::ModeUpdatePayload(protobuf_mode_update_payload)) => {
44 let mode_info: ModeInfo = protobuf_mode_update_payload.try_into()?;
45 Ok(Event::ModeUpdate(mode_info))
46 },
47 _ => Err("Malformed payload for the ModeUpdate Event"),
48 },
49 Some(ProtobufEventType::TabUpdate) => match protobuf_event.payload {
50 Some(ProtobufEventPayload::TabUpdatePayload(protobuf_tab_info_payload)) => {
51 let mut tab_infos: Vec<TabInfo> = vec![];
52 for protobuf_tab_info in protobuf_tab_info_payload.tab_info {
53 tab_infos.push(TabInfo::try_from(protobuf_tab_info)?);
54 }
55 Ok(Event::TabUpdate(tab_infos))
56 },
57 _ => Err("Malformed payload for the TabUpdate Event"),
58 },
59 Some(ProtobufEventType::PaneUpdate) => match protobuf_event.payload {
60 Some(ProtobufEventPayload::PaneUpdatePayload(protobuf_pane_update_payload)) => {
61 let mut pane_manifest: HashMap<usize, Vec<PaneInfo>> = HashMap::new();
62 for protobuf_pane_manifest in protobuf_pane_update_payload.pane_manifest {
63 let tab_index = protobuf_pane_manifest.tab_index as usize;
64 let mut panes = vec![];
65 for protobuf_pane_info in protobuf_pane_manifest.panes {
66 panes.push(protobuf_pane_info.try_into()?);
67 }
68 if pane_manifest.contains_key(&tab_index) {
69 return Err("Duplicate tab definition in pane manifest");
70 }
71 pane_manifest.insert(tab_index, panes);
72 }
73 Ok(Event::PaneUpdate(PaneManifest {
74 panes: pane_manifest,
75 }))
76 },
77 _ => Err("Malformed payload for the PaneUpdate Event"),
78 },
79 Some(ProtobufEventType::Key) => match protobuf_event.payload {
80 Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => {
81 Ok(Event::Key(protobuf_key.try_into()?))
82 },
83 _ => Err("Malformed payload for the Key Event"),
84 },
85 Some(ProtobufEventType::Mouse) => match protobuf_event.payload {
86 Some(ProtobufEventPayload::MouseEventPayload(protobuf_mouse)) => {
87 Ok(Event::Mouse(protobuf_mouse.try_into()?))
88 },
89 _ => Err("Malformed payload for the Mouse Event"),
90 },
91 Some(ProtobufEventType::Timer) => match protobuf_event.payload {
92 Some(ProtobufEventPayload::TimerPayload(seconds)) => {
93 Ok(Event::Timer(seconds as f64))
94 },
95 _ => Err("Malformed payload for the Timer Event"),
96 },
97 Some(ProtobufEventType::CopyToClipboard) => match protobuf_event.payload {
98 Some(ProtobufEventPayload::CopyToClipboardPayload(copy_to_clipboard)) => {
99 let protobuf_copy_to_clipboard =
100 ProtobufCopyDestination::from_i32(copy_to_clipboard)
101 .ok_or("Malformed copy to clipboard payload")?;
102 Ok(Event::CopyToClipboard(
103 protobuf_copy_to_clipboard.try_into()?,
104 ))
105 },
106 _ => Err("Malformed payload for the Copy To Clipboard Event"),
107 },
108 Some(ProtobufEventType::SystemClipboardFailure) => match protobuf_event.payload {
109 None => Ok(Event::SystemClipboardFailure),
110 _ => Err("Malformed payload for the system clipboard failure Event"),
111 },
112 Some(ProtobufEventType::InputReceived) => match protobuf_event.payload {
113 None => Ok(Event::InputReceived),
114 _ => Err("Malformed payload for the input received Event"),
115 },
116 Some(ProtobufEventType::Visible) => match protobuf_event.payload {
117 Some(ProtobufEventPayload::VisiblePayload(is_visible)) => {
118 Ok(Event::Visible(is_visible))
119 },
120 _ => Err("Malformed payload for the visible Event"),
121 },
122 Some(ProtobufEventType::CustomMessage) => match protobuf_event.payload {
123 Some(ProtobufEventPayload::CustomMessagePayload(custom_message_payload)) => {
124 Ok(Event::CustomMessage(
125 custom_message_payload.message_name,
126 custom_message_payload.payload,
127 ))
128 },
129 _ => Err("Malformed payload for the custom message Event"),
130 },
131 Some(ProtobufEventType::FileSystemCreate) => match protobuf_event.payload {
132 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
133 let file_paths = file_list_payload
134 .paths
135 .iter()
136 .zip(file_list_payload.paths_metadata.iter())
137 .map(|(p, m)| (PathBuf::from(p), m.into()))
138 .collect();
139 Ok(Event::FileSystemCreate(file_paths))
140 },
141 _ => Err("Malformed payload for the file system create Event"),
142 },
143 Some(ProtobufEventType::FileSystemRead) => match protobuf_event.payload {
144 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
145 let file_paths = file_list_payload
146 .paths
147 .iter()
148 .zip(file_list_payload.paths_metadata.iter())
149 .map(|(p, m)| (PathBuf::from(p), m.into()))
150 .collect();
151 Ok(Event::FileSystemRead(file_paths))
152 },
153 _ => Err("Malformed payload for the file system read Event"),
154 },
155 Some(ProtobufEventType::FileSystemUpdate) => match protobuf_event.payload {
156 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
157 let file_paths = file_list_payload
158 .paths
159 .iter()
160 .zip(file_list_payload.paths_metadata.iter())
161 .map(|(p, m)| (PathBuf::from(p), m.into()))
162 .collect();
163 Ok(Event::FileSystemUpdate(file_paths))
164 },
165 _ => Err("Malformed payload for the file system update Event"),
166 },
167 Some(ProtobufEventType::FileSystemDelete) => match protobuf_event.payload {
168 Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
169 let file_paths = file_list_payload
170 .paths
171 .iter()
172 .zip(file_list_payload.paths_metadata.iter())
173 .map(|(p, m)| (PathBuf::from(p), m.into()))
174 .collect();
175 Ok(Event::FileSystemDelete(file_paths))
176 },
177 _ => Err("Malformed payload for the file system delete Event"),
178 },
179 Some(ProtobufEventType::PermissionRequestResult) => match protobuf_event.payload {
180 Some(ProtobufEventPayload::PermissionRequestResultPayload(payload)) => {
181 if payload.granted {
182 Ok(Event::PermissionRequestResult(PermissionStatus::Granted))
183 } else {
184 Ok(Event::PermissionRequestResult(PermissionStatus::Denied))
185 }
186 },
187 _ => Err("Malformed payload for the file system delete Event"),
188 },
189 Some(ProtobufEventType::SessionUpdate) => match protobuf_event.payload {
190 Some(ProtobufEventPayload::SessionUpdatePayload(
191 protobuf_session_update_payload,
192 )) => {
193 let mut session_infos: Vec<SessionInfo> = vec![];
194 let mut resurrectable_sessions: Vec<(String, Duration)> = vec![];
195 for protobuf_session_info in protobuf_session_update_payload.session_manifests {
196 session_infos.push(SessionInfo::try_from(protobuf_session_info)?);
197 }
198 for protobuf_resurrectable_session in
199 protobuf_session_update_payload.resurrectable_sessions
200 {
201 resurrectable_sessions.push(protobuf_resurrectable_session.into());
202 }
203 Ok(Event::SessionUpdate(
204 session_infos,
205 resurrectable_sessions.into(),
206 ))
207 },
208 _ => Err("Malformed payload for the SessionUpdate Event"),
209 },
210 Some(ProtobufEventType::RunCommandResult) => match protobuf_event.payload {
211 Some(ProtobufEventPayload::RunCommandResultPayload(run_command_result_payload)) => {
212 Ok(Event::RunCommandResult(
213 run_command_result_payload.exit_code,
214 run_command_result_payload.stdout,
215 run_command_result_payload.stderr,
216 run_command_result_payload
217 .context
218 .into_iter()
219 .map(|c_i| (c_i.name, c_i.value))
220 .collect(),
221 ))
222 },
223 _ => Err("Malformed payload for the RunCommandResult Event"),
224 },
225 Some(ProtobufEventType::WebRequestResult) => match protobuf_event.payload {
226 Some(ProtobufEventPayload::WebRequestResultPayload(web_request_result_payload)) => {
227 Ok(Event::WebRequestResult(
228 web_request_result_payload.status as u16,
229 web_request_result_payload
230 .headers
231 .into_iter()
232 .map(|h| (h.name, h.value))
233 .collect(),
234 web_request_result_payload.body,
235 web_request_result_payload
236 .context
237 .into_iter()
238 .map(|c_i| (c_i.name, c_i.value))
239 .collect(),
240 ))
241 },
242 _ => Err("Malformed payload for the WebRequestResult Event"),
243 },
244 Some(ProtobufEventType::CommandPaneOpened) => match protobuf_event.payload {
245 Some(ProtobufEventPayload::CommandPaneOpenedPayload(
246 command_pane_opened_payload,
247 )) => Ok(Event::CommandPaneOpened(
248 command_pane_opened_payload.terminal_pane_id,
249 command_pane_opened_payload
250 .context
251 .into_iter()
252 .map(|c_i| (c_i.name, c_i.value))
253 .collect(),
254 )),
255 _ => Err("Malformed payload for the CommandPaneOpened Event"),
256 },
257 Some(ProtobufEventType::CommandPaneExited) => match protobuf_event.payload {
258 Some(ProtobufEventPayload::CommandPaneExitedPayload(
259 command_pane_exited_payload,
260 )) => Ok(Event::CommandPaneExited(
261 command_pane_exited_payload.terminal_pane_id,
262 command_pane_exited_payload.exit_code,
263 command_pane_exited_payload
264 .context
265 .into_iter()
266 .map(|c_i| (c_i.name, c_i.value))
267 .collect(),
268 )),
269 _ => Err("Malformed payload for the CommandPaneExited Event"),
270 },
271 Some(ProtobufEventType::PaneClosed) => match protobuf_event.payload {
272 Some(ProtobufEventPayload::PaneClosedPayload(pane_closed_payload)) => {
273 let pane_id = pane_closed_payload
274 .pane_id
275 .ok_or("Malformed payload for the PaneClosed Event")?;
276 Ok(Event::PaneClosed(PaneId::try_from(pane_id)?))
277 },
278 _ => Err("Malformed payload for the PaneClosed Event"),
279 },
280 Some(ProtobufEventType::EditPaneOpened) => match protobuf_event.payload {
281 Some(ProtobufEventPayload::EditPaneOpenedPayload(command_pane_opened_payload)) => {
282 Ok(Event::EditPaneOpened(
283 command_pane_opened_payload.terminal_pane_id,
284 command_pane_opened_payload
285 .context
286 .into_iter()
287 .map(|c_i| (c_i.name, c_i.value))
288 .collect(),
289 ))
290 },
291 _ => Err("Malformed payload for the EditPaneOpened Event"),
292 },
293 Some(ProtobufEventType::EditPaneExited) => match protobuf_event.payload {
294 Some(ProtobufEventPayload::EditPaneExitedPayload(command_pane_exited_payload)) => {
295 Ok(Event::EditPaneExited(
296 command_pane_exited_payload.terminal_pane_id,
297 command_pane_exited_payload.exit_code,
298 command_pane_exited_payload
299 .context
300 .into_iter()
301 .map(|c_i| (c_i.name, c_i.value))
302 .collect(),
303 ))
304 },
305 _ => Err("Malformed payload for the EditPaneExited Event"),
306 },
307 Some(ProtobufEventType::CommandPaneReRun) => match protobuf_event.payload {
308 Some(ProtobufEventPayload::CommandPaneRerunPayload(command_pane_rerun_payload)) => {
309 Ok(Event::CommandPaneReRun(
310 command_pane_rerun_payload.terminal_pane_id,
311 command_pane_rerun_payload
312 .context
313 .into_iter()
314 .map(|c_i| (c_i.name, c_i.value))
315 .collect(),
316 ))
317 },
318 _ => Err("Malformed payload for the CommandPaneReRun Event"),
319 },
320 Some(ProtobufEventType::FailedToWriteConfigToDisk) => match protobuf_event.payload {
321 Some(ProtobufEventPayload::FailedToWriteConfigToDiskPayload(
322 failed_to_write_configuration_payload,
323 )) => Ok(Event::FailedToWriteConfigToDisk(
324 failed_to_write_configuration_payload.file_path,
325 )),
326 _ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
327 },
328 Some(ProtobufEventType::ListClients) => match protobuf_event.payload {
329 Some(ProtobufEventPayload::ListClientsPayload(mut list_clients_payload)) => {
330 Ok(Event::ListClients(
331 list_clients_payload
332 .client_info
333 .drain(..)
334 .filter_map(|c| c.try_into().ok())
335 .collect(),
336 ))
337 },
338 _ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
339 },
340 Some(ProtobufEventType::HostFolderChanged) => match protobuf_event.payload {
341 Some(ProtobufEventPayload::HostFolderChangedPayload(
342 host_folder_changed_payload,
343 )) => Ok(Event::HostFolderChanged(PathBuf::from(
344 host_folder_changed_payload.new_host_folder_path,
345 ))),
346 _ => Err("Malformed payload for the HostFolderChanged Event"),
347 },
348 Some(ProtobufEventType::FailedToChangeHostFolder) => match protobuf_event.payload {
349 Some(ProtobufEventPayload::FailedToChangeHostFolderPayload(
350 failed_to_change_host_folder_payload,
351 )) => Ok(Event::FailedToChangeHostFolder(
352 failed_to_change_host_folder_payload.error_message,
353 )),
354 _ => Err("Malformed payload for the FailedToChangeHostFolder Event"),
355 },
356 Some(ProtobufEventType::PastedText) => match protobuf_event.payload {
357 Some(ProtobufEventPayload::PastedTextPayload(pasted_text_payload)) => {
358 Ok(Event::PastedText(pasted_text_payload.pasted_text))
359 },
360 _ => Err("Malformed payload for the PastedText Event"),
361 },
362 Some(ProtobufEventType::ConfigWasWrittenToDisk) => match protobuf_event.payload {
363 None => Ok(Event::ConfigWasWrittenToDisk),
364 _ => Err("Malformed payload for the ConfigWasWrittenToDisk Event"),
365 },
366 Some(ProtobufEventType::WebServerStatus) => match protobuf_event.payload {
367 Some(ProtobufEventPayload::WebServerStatusPayload(web_server_status)) => {
368 Ok(Event::WebServerStatus(web_server_status.try_into()?))
369 },
370 _ => Err("Malformed payload for the WebServerStatus Event"),
371 },
372 Some(ProtobufEventType::BeforeClose) => match protobuf_event.payload {
373 None => Ok(Event::BeforeClose),
374 _ => Err("Malformed payload for the BeforeClose Event"),
375 },
376 Some(ProtobufEventType::FailedToStartWebServer) => match protobuf_event.payload {
377 Some(ProtobufEventPayload::FailedToStartWebServerPayload(
378 failed_to_start_web_server_payload,
379 )) => Ok(Event::FailedToStartWebServer(
380 failed_to_start_web_server_payload.error,
381 )),
382 _ => Err("Malformed payload for the FailedToStartWebServer Event"),
383 },
384 Some(ProtobufEventType::InterceptedKeyPress) => match protobuf_event.payload {
385 Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => {
386 Ok(Event::InterceptedKeyPress(protobuf_key.try_into()?))
387 },
388 _ => Err("Malformed payload for the InterceptedKeyPress Event"),
389 },
390 None => Err("Unknown Protobuf Event"),
391 }
392 }
393}
394
395impl TryFrom<ProtobufClientInfo> for ClientInfo {
396 type Error = &'static str;
397 fn try_from(protobuf_client_info: ProtobufClientInfo) -> Result<Self, &'static str> {
398 Ok(ClientInfo::new(
399 protobuf_client_info.client_id as u16,
400 protobuf_client_info
401 .pane_id
402 .ok_or("No pane id found")?
403 .try_into()?,
404 protobuf_client_info.running_command,
405 protobuf_client_info.is_current_client,
406 ))
407 }
408}
409
410impl TryFrom<ClientInfo> for ProtobufClientInfo {
411 type Error = &'static str;
412 fn try_from(client_info: ClientInfo) -> Result<Self, &'static str> {
413 Ok(ProtobufClientInfo {
414 client_id: client_info.client_id as u32,
415 pane_id: Some(client_info.pane_id.try_into()?),
416 running_command: client_info.running_command,
417 is_current_client: client_info.is_current_client,
418 })
419 }
420}
421
422impl TryFrom<Event> for ProtobufEvent {
423 type Error = &'static str;
424 fn try_from(event: Event) -> Result<Self, &'static str> {
425 match event {
426 Event::ModeUpdate(mode_info) => {
427 let protobuf_mode_update_payload = mode_info.try_into()?;
428 Ok(ProtobufEvent {
429 name: ProtobufEventType::ModeUpdate as i32,
430 payload: Some(event::Payload::ModeUpdatePayload(
431 protobuf_mode_update_payload,
432 )),
433 })
434 },
435 Event::TabUpdate(tab_infos) => {
436 let mut protobuf_tab_infos = vec![];
437 for tab_info in tab_infos {
438 protobuf_tab_infos.push(tab_info.try_into()?);
439 }
440 let tab_update_payload = TabUpdatePayload {
441 tab_info: protobuf_tab_infos,
442 };
443 Ok(ProtobufEvent {
444 name: ProtobufEventType::TabUpdate as i32,
445 payload: Some(event::Payload::TabUpdatePayload(tab_update_payload)),
446 })
447 },
448 Event::PaneUpdate(pane_manifest) => {
449 let mut protobuf_pane_manifests = vec![];
450 for (tab_index, pane_infos) in pane_manifest.panes {
451 let mut protobuf_pane_infos = vec![];
452 for pane_info in pane_infos {
453 protobuf_pane_infos.push(pane_info.try_into()?);
454 }
455 protobuf_pane_manifests.push(ProtobufPaneManifest {
456 tab_index: tab_index as u32,
457 panes: protobuf_pane_infos,
458 });
459 }
460 Ok(ProtobufEvent {
461 name: ProtobufEventType::PaneUpdate as i32,
462 payload: Some(event::Payload::PaneUpdatePayload(PaneUpdatePayload {
463 pane_manifest: protobuf_pane_manifests,
464 })),
465 })
466 },
467 Event::Key(key) => Ok(ProtobufEvent {
468 name: ProtobufEventType::Key as i32,
469 payload: Some(event::Payload::KeyPayload(key.try_into()?)),
470 }),
471 Event::Mouse(mouse_event) => {
472 let protobuf_mouse_payload = mouse_event.try_into()?;
473 Ok(ProtobufEvent {
474 name: ProtobufEventType::Mouse as i32,
475 payload: Some(event::Payload::MouseEventPayload(protobuf_mouse_payload)),
476 })
477 },
478 Event::Timer(seconds) => Ok(ProtobufEvent {
479 name: ProtobufEventType::Timer as i32,
480 payload: Some(event::Payload::TimerPayload(seconds as f32)),
481 }),
482 Event::CopyToClipboard(clipboard_destination) => {
483 let protobuf_copy_destination: ProtobufCopyDestination =
484 clipboard_destination.try_into()?;
485 Ok(ProtobufEvent {
486 name: ProtobufEventType::CopyToClipboard as i32,
487 payload: Some(event::Payload::CopyToClipboardPayload(
488 protobuf_copy_destination as i32,
489 )),
490 })
491 },
492 Event::SystemClipboardFailure => Ok(ProtobufEvent {
493 name: ProtobufEventType::SystemClipboardFailure as i32,
494 payload: None,
495 }),
496 Event::InputReceived => Ok(ProtobufEvent {
497 name: ProtobufEventType::InputReceived as i32,
498 payload: None,
499 }),
500 Event::Visible(is_visible) => Ok(ProtobufEvent {
501 name: ProtobufEventType::Visible as i32,
502 payload: Some(event::Payload::VisiblePayload(is_visible)),
503 }),
504 Event::CustomMessage(message, payload) => Ok(ProtobufEvent {
505 name: ProtobufEventType::CustomMessage as i32,
506 payload: Some(event::Payload::CustomMessagePayload(CustomMessagePayload {
507 message_name: message,
508 payload,
509 })),
510 }),
511 Event::FileSystemCreate(event_paths) => {
512 let mut paths = vec![];
513 let mut paths_metadata = vec![];
514 for (path, path_metadata) in event_paths {
515 paths.push(path.display().to_string());
516 paths_metadata.push(path_metadata.into());
517 }
518 let file_list_payload = FileListPayload {
519 paths,
520 paths_metadata,
521 };
522 Ok(ProtobufEvent {
523 name: ProtobufEventType::FileSystemCreate as i32,
524 payload: Some(event::Payload::FileListPayload(file_list_payload)),
525 })
526 },
527 Event::FileSystemRead(event_paths) => {
528 let mut paths = vec![];
529 let mut paths_metadata = vec![];
530 for (path, path_metadata) in event_paths {
531 paths.push(path.display().to_string());
532 paths_metadata.push(path_metadata.into());
533 }
534 let file_list_payload = FileListPayload {
535 paths,
536 paths_metadata,
537 };
538 Ok(ProtobufEvent {
539 name: ProtobufEventType::FileSystemRead as i32,
540 payload: Some(event::Payload::FileListPayload(file_list_payload)),
541 })
542 },
543 Event::FileSystemUpdate(event_paths) => {
544 let mut paths = vec![];
545 let mut paths_metadata = vec![];
546 for (path, path_metadata) in event_paths {
547 paths.push(path.display().to_string());
548 paths_metadata.push(path_metadata.into());
549 }
550 let file_list_payload = FileListPayload {
551 paths,
552 paths_metadata,
553 };
554 Ok(ProtobufEvent {
555 name: ProtobufEventType::FileSystemUpdate as i32,
556 payload: Some(event::Payload::FileListPayload(file_list_payload)),
557 })
558 },
559 Event::FileSystemDelete(event_paths) => {
560 let mut paths = vec![];
561 let mut paths_metadata = vec![];
562 for (path, path_metadata) in event_paths {
563 paths.push(path.display().to_string());
564 paths_metadata.push(path_metadata.into());
565 }
566 let file_list_payload = FileListPayload {
567 paths,
568 paths_metadata,
569 };
570 Ok(ProtobufEvent {
571 name: ProtobufEventType::FileSystemDelete as i32,
572 payload: Some(event::Payload::FileListPayload(file_list_payload)),
573 })
574 },
575 Event::PermissionRequestResult(permission_status) => {
576 let granted = match permission_status {
577 PermissionStatus::Granted => true,
578 PermissionStatus::Denied => false,
579 };
580 Ok(ProtobufEvent {
581 name: ProtobufEventType::PermissionRequestResult as i32,
582 payload: Some(event::Payload::PermissionRequestResultPayload(
583 PermissionRequestResultPayload { granted },
584 )),
585 })
586 },
587 Event::SessionUpdate(session_infos, resurrectable_sessions) => {
588 let mut protobuf_session_manifests = vec![];
589 for session_info in session_infos {
590 protobuf_session_manifests.push(session_info.try_into()?);
591 }
592 let mut protobuf_resurrectable_sessions = vec![];
593 for resurrectable_session in resurrectable_sessions {
594 protobuf_resurrectable_sessions.push(resurrectable_session.into());
595 }
596 let session_update_payload = SessionUpdatePayload {
597 session_manifests: protobuf_session_manifests,
598 resurrectable_sessions: protobuf_resurrectable_sessions,
599 };
600 Ok(ProtobufEvent {
601 name: ProtobufEventType::SessionUpdate as i32,
602 payload: Some(event::Payload::SessionUpdatePayload(session_update_payload)),
603 })
604 },
605 Event::RunCommandResult(exit_code, stdout, stderr, context) => {
606 let run_command_result_payload = RunCommandResultPayload {
607 exit_code,
608 stdout,
609 stderr,
610 context: context
611 .into_iter()
612 .map(|(name, value)| ContextItem { name, value })
613 .collect(),
614 };
615 Ok(ProtobufEvent {
616 name: ProtobufEventType::RunCommandResult as i32,
617 payload: Some(event::Payload::RunCommandResultPayload(
618 run_command_result_payload,
619 )),
620 })
621 },
622 Event::WebRequestResult(status, headers, body, context) => {
623 let web_request_result_payload = WebRequestResultPayload {
624 status: status as i32,
625 headers: headers
626 .into_iter()
627 .map(|(name, value)| Header { name, value })
628 .collect(),
629 body,
630 context: context
631 .into_iter()
632 .map(|(name, value)| ContextItem { name, value })
633 .collect(),
634 };
635 Ok(ProtobufEvent {
636 name: ProtobufEventType::WebRequestResult as i32,
637 payload: Some(event::Payload::WebRequestResultPayload(
638 web_request_result_payload,
639 )),
640 })
641 },
642 Event::CommandPaneOpened(terminal_pane_id, context) => {
643 let command_pane_opened_payload = CommandPaneOpenedPayload {
644 terminal_pane_id,
645 context: context
646 .into_iter()
647 .map(|(name, value)| ContextItem { name, value })
648 .collect(),
649 };
650 Ok(ProtobufEvent {
651 name: ProtobufEventType::CommandPaneOpened as i32,
652 payload: Some(event::Payload::CommandPaneOpenedPayload(
653 command_pane_opened_payload,
654 )),
655 })
656 },
657 Event::CommandPaneExited(terminal_pane_id, exit_code, context) => {
658 let command_pane_exited_payload = CommandPaneExitedPayload {
659 terminal_pane_id,
660 exit_code,
661 context: context
662 .into_iter()
663 .map(|(name, value)| ContextItem { name, value })
664 .collect(),
665 };
666 Ok(ProtobufEvent {
667 name: ProtobufEventType::CommandPaneExited as i32,
668 payload: Some(event::Payload::CommandPaneExitedPayload(
669 command_pane_exited_payload,
670 )),
671 })
672 },
673 Event::PaneClosed(pane_id) => Ok(ProtobufEvent {
674 name: ProtobufEventType::PaneClosed as i32,
675 payload: Some(event::Payload::PaneClosedPayload(PaneClosedPayload {
676 pane_id: Some(pane_id.try_into()?),
677 })),
678 }),
679 Event::EditPaneOpened(terminal_pane_id, context) => {
680 let command_pane_opened_payload = EditPaneOpenedPayload {
681 terminal_pane_id,
682 context: context
683 .into_iter()
684 .map(|(name, value)| ContextItem { name, value })
685 .collect(),
686 };
687 Ok(ProtobufEvent {
688 name: ProtobufEventType::EditPaneOpened as i32,
689 payload: Some(event::Payload::EditPaneOpenedPayload(
690 command_pane_opened_payload,
691 )),
692 })
693 },
694 Event::EditPaneExited(terminal_pane_id, exit_code, context) => {
695 let command_pane_exited_payload = EditPaneExitedPayload {
696 terminal_pane_id,
697 exit_code,
698 context: context
699 .into_iter()
700 .map(|(name, value)| ContextItem { name, value })
701 .collect(),
702 };
703 Ok(ProtobufEvent {
704 name: ProtobufEventType::EditPaneExited as i32,
705 payload: Some(event::Payload::EditPaneExitedPayload(
706 command_pane_exited_payload,
707 )),
708 })
709 },
710 Event::CommandPaneReRun(terminal_pane_id, context) => {
711 let command_pane_rerun_payload = CommandPaneReRunPayload {
712 terminal_pane_id,
713 context: context
714 .into_iter()
715 .map(|(name, value)| ContextItem { name, value })
716 .collect(),
717 };
718 Ok(ProtobufEvent {
719 name: ProtobufEventType::CommandPaneReRun as i32,
720 payload: Some(event::Payload::CommandPaneRerunPayload(
721 command_pane_rerun_payload,
722 )),
723 })
724 },
725 Event::FailedToWriteConfigToDisk(file_path) => Ok(ProtobufEvent {
726 name: ProtobufEventType::FailedToWriteConfigToDisk as i32,
727 payload: Some(event::Payload::FailedToWriteConfigToDiskPayload(
728 FailedToWriteConfigToDiskPayload { file_path },
729 )),
730 }),
731 Event::ListClients(mut client_info_list) => Ok(ProtobufEvent {
732 name: ProtobufEventType::ListClients as i32,
733 payload: Some(event::Payload::ListClientsPayload(ListClientsPayload {
734 client_info: client_info_list
735 .drain(..)
736 .filter_map(|c| c.try_into().ok())
737 .collect(),
738 })),
739 }),
740 Event::HostFolderChanged(new_host_folder_path) => Ok(ProtobufEvent {
741 name: ProtobufEventType::HostFolderChanged as i32,
742 payload: Some(event::Payload::HostFolderChangedPayload(
743 HostFolderChangedPayload {
744 new_host_folder_path: new_host_folder_path.display().to_string(),
745 },
746 )),
747 }),
748 Event::FailedToChangeHostFolder(error_message) => Ok(ProtobufEvent {
749 name: ProtobufEventType::FailedToChangeHostFolder as i32,
750 payload: Some(event::Payload::FailedToChangeHostFolderPayload(
751 FailedToChangeHostFolderPayload { error_message },
752 )),
753 }),
754 Event::PastedText(pasted_text) => Ok(ProtobufEvent {
755 name: ProtobufEventType::PastedText as i32,
756 payload: Some(event::Payload::PastedTextPayload(PastedTextPayload {
757 pasted_text,
758 })),
759 }),
760 Event::ConfigWasWrittenToDisk => Ok(ProtobufEvent {
761 name: ProtobufEventType::ConfigWasWrittenToDisk as i32,
762 payload: None,
763 }),
764 Event::WebServerStatus(web_server_status) => Ok(ProtobufEvent {
765 name: ProtobufEventType::WebServerStatus as i32,
766 payload: Some(event::Payload::WebServerStatusPayload(
767 ProtobufWebServerStatusPayload::try_from(web_server_status)?,
768 )),
769 }),
770 Event::BeforeClose => Ok(ProtobufEvent {
771 name: ProtobufEventType::BeforeClose as i32,
772 payload: None,
773 }),
774 Event::FailedToStartWebServer(error) => Ok(ProtobufEvent {
775 name: ProtobufEventType::FailedToStartWebServer as i32,
776 payload: Some(event::Payload::FailedToStartWebServerPayload(
777 FailedToStartWebServerPayload { error },
778 )),
779 }),
780 Event::InterceptedKeyPress(key) => Ok(ProtobufEvent {
781 name: ProtobufEventType::InterceptedKeyPress as i32,
782 payload: Some(event::Payload::KeyPayload(key.try_into()?)),
783 }),
784 }
785 }
786}
787
788impl TryFrom<SessionInfo> for ProtobufSessionManifest {
789 type Error = &'static str;
790 fn try_from(session_info: SessionInfo) -> Result<Self, &'static str> {
791 let mut protobuf_pane_manifests = vec![];
792 for (tab_index, pane_infos) in session_info.panes.panes {
793 let mut protobuf_pane_infos = vec![];
794 for pane_info in pane_infos {
795 protobuf_pane_infos.push(pane_info.try_into()?);
796 }
797 protobuf_pane_manifests.push(ProtobufPaneManifest {
798 tab_index: tab_index as u32,
799 panes: protobuf_pane_infos,
800 });
801 }
802 Ok(ProtobufSessionManifest {
803 name: session_info.name,
804 panes: protobuf_pane_manifests,
805 tabs: session_info
806 .tabs
807 .iter()
808 .filter_map(|t| t.clone().try_into().ok())
809 .collect(),
810 connected_clients: session_info.connected_clients as u32,
811 is_current_session: session_info.is_current_session,
812 available_layouts: session_info
813 .available_layouts
814 .into_iter()
815 .filter_map(|l| ProtobufLayoutInfo::try_from(l).ok())
816 .collect(),
817 plugins: session_info
818 .plugins
819 .into_iter()
820 .map(|p| ProtobufPluginInfo::from(p))
821 .collect(),
822 web_clients_allowed: session_info.web_clients_allowed,
823 web_client_count: session_info.web_client_count as u32,
824 tab_history: session_info
825 .tab_history
826 .into_iter()
827 .map(|t| ProtobufClientTabHistory::from(t))
828 .collect(),
829 })
830 }
831}
832
833impl From<(u16, Vec<usize>)> for ProtobufClientTabHistory {
834 fn from((client_id, tab_history): (u16, Vec<usize>)) -> ProtobufClientTabHistory {
835 ProtobufClientTabHistory {
836 client_id: client_id as u32,
837 tab_history: tab_history.into_iter().map(|t| t as u32).collect(),
838 }
839 }
840}
841impl From<(u32, PluginInfo)> for ProtobufPluginInfo {
842 fn from((plugin_id, plugin_info): (u32, PluginInfo)) -> ProtobufPluginInfo {
843 ProtobufPluginInfo {
844 plugin_id,
845 plugin_url: plugin_info.location,
846 plugin_config: plugin_info
847 .configuration
848 .into_iter()
849 .map(|(name, value)| ContextItem { name, value })
850 .collect(),
851 }
852 }
853}
854
855impl TryFrom<ProtobufSessionManifest> for SessionInfo {
856 type Error = &'static str;
857 fn try_from(protobuf_session_manifest: ProtobufSessionManifest) -> Result<Self, &'static str> {
858 let mut pane_manifest: HashMap<usize, Vec<PaneInfo>> = HashMap::new();
859 for protobuf_pane_manifest in protobuf_session_manifest.panes {
860 let tab_index = protobuf_pane_manifest.tab_index as usize;
861 let mut panes = vec![];
862 for protobuf_pane_info in protobuf_pane_manifest.panes {
863 panes.push(protobuf_pane_info.try_into()?);
864 }
865 if pane_manifest.contains_key(&tab_index) {
866 return Err("Duplicate tab definition in pane manifest");
867 }
868 pane_manifest.insert(tab_index, panes);
869 }
870 let panes = PaneManifest {
871 panes: pane_manifest,
872 };
873 let mut plugins = BTreeMap::new();
874 for plugin_info in protobuf_session_manifest.plugins.into_iter() {
875 let mut configuration = BTreeMap::new();
876 for context_item in plugin_info.plugin_config.into_iter() {
877 configuration.insert(context_item.name, context_item.value);
878 }
879 plugins.insert(
880 plugin_info.plugin_id,
881 PluginInfo {
882 location: plugin_info.plugin_url,
883 configuration,
884 },
885 );
886 }
887 let mut tab_history = BTreeMap::new();
888 for client_tab_history in protobuf_session_manifest.tab_history.into_iter() {
889 let client_id = client_tab_history.client_id;
890 let tab_history_for_client = client_tab_history
891 .tab_history
892 .iter()
893 .map(|t| *t as usize)
894 .collect();
895 tab_history.insert(client_id as u16, tab_history_for_client);
896 }
897 Ok(SessionInfo {
898 name: protobuf_session_manifest.name,
899 tabs: protobuf_session_manifest
900 .tabs
901 .iter()
902 .filter_map(|t| t.clone().try_into().ok())
903 .collect(),
904 panes,
905 connected_clients: protobuf_session_manifest.connected_clients as usize,
906 is_current_session: protobuf_session_manifest.is_current_session,
907 available_layouts: protobuf_session_manifest
908 .available_layouts
909 .into_iter()
910 .filter_map(|l| LayoutInfo::try_from(l).ok())
911 .collect(),
912 plugins,
913 web_clients_allowed: protobuf_session_manifest.web_clients_allowed,
914 web_client_count: protobuf_session_manifest.web_client_count as usize,
915 tab_history,
916 })
917 }
918}
919
920impl TryFrom<LayoutInfo> for ProtobufLayoutInfo {
921 type Error = &'static str;
922 fn try_from(layout_info: LayoutInfo) -> Result<Self, &'static str> {
923 match layout_info {
924 LayoutInfo::File(name) => Ok(ProtobufLayoutInfo {
925 source: "file".to_owned(),
926 name,
927 }),
928 LayoutInfo::BuiltIn(name) => Ok(ProtobufLayoutInfo {
929 source: "built-in".to_owned(),
930 name,
931 }),
932 LayoutInfo::Url(name) => Ok(ProtobufLayoutInfo {
933 source: "url".to_owned(),
934 name,
935 }),
936 LayoutInfo::Stringified(stringified_layout) => Ok(ProtobufLayoutInfo {
937 source: "stringified".to_owned(),
938 name: stringified_layout.clone(),
939 }),
940 }
941 }
942}
943
944impl TryFrom<ProtobufLayoutInfo> for LayoutInfo {
945 type Error = &'static str;
946 fn try_from(protobuf_layout_info: ProtobufLayoutInfo) -> Result<Self, &'static str> {
947 match protobuf_layout_info.source.as_str() {
948 "file" => Ok(LayoutInfo::File(protobuf_layout_info.name)),
949 "built-in" => Ok(LayoutInfo::BuiltIn(protobuf_layout_info.name)),
950 "url" => Ok(LayoutInfo::Url(protobuf_layout_info.name)),
951 "stringified" => Ok(LayoutInfo::Stringified(protobuf_layout_info.name)),
952 _ => Err("Unknown source for layout"),
953 }
954 }
955}
956
957impl TryFrom<CopyDestination> for ProtobufCopyDestination {
958 type Error = &'static str;
959 fn try_from(copy_destination: CopyDestination) -> Result<Self, &'static str> {
960 match copy_destination {
961 CopyDestination::Command => Ok(ProtobufCopyDestination::Command),
962 CopyDestination::Primary => Ok(ProtobufCopyDestination::Primary),
963 CopyDestination::System => Ok(ProtobufCopyDestination::System),
964 }
965 }
966}
967
968impl TryFrom<ProtobufCopyDestination> for CopyDestination {
969 type Error = &'static str;
970 fn try_from(protobuf_copy_destination: ProtobufCopyDestination) -> Result<Self, &'static str> {
971 match protobuf_copy_destination {
972 ProtobufCopyDestination::Command => Ok(CopyDestination::Command),
973 ProtobufCopyDestination::Primary => Ok(CopyDestination::Primary),
974 ProtobufCopyDestination::System => Ok(CopyDestination::System),
975 }
976 }
977}
978
979impl TryFrom<MouseEventPayload> for Mouse {
980 type Error = &'static str;
981 fn try_from(mouse_event_payload: MouseEventPayload) -> Result<Self, &'static str> {
982 match MouseEventName::from_i32(mouse_event_payload.mouse_event_name) {
983 Some(MouseEventName::MouseScrollUp) => match mouse_event_payload.mouse_event_payload {
984 Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
985 Ok(Mouse::ScrollUp(line_count as usize))
986 },
987 _ => Err("Malformed payload for mouse scroll up"),
988 },
989 Some(MouseEventName::MouseScrollDown) => {
990 match mouse_event_payload.mouse_event_payload {
991 Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
992 Ok(Mouse::ScrollDown(line_count as usize))
993 },
994 _ => Err("Malformed payload for mouse scroll down"),
995 }
996 },
997 Some(MouseEventName::MouseLeftClick) => match mouse_event_payload.mouse_event_payload {
998 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
999 Mouse::LeftClick(position.line as isize, position.column as usize),
1000 ),
1001 _ => Err("Malformed payload for mouse left click"),
1002 },
1003 Some(MouseEventName::MouseRightClick) => {
1004 match mouse_event_payload.mouse_event_payload {
1005 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1006 Mouse::RightClick(position.line as isize, position.column as usize),
1007 ),
1008 _ => Err("Malformed payload for mouse right click"),
1009 }
1010 },
1011 Some(MouseEventName::MouseHold) => match mouse_event_payload.mouse_event_payload {
1012 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1013 Mouse::Hold(position.line as isize, position.column as usize),
1014 ),
1015 _ => Err("Malformed payload for mouse hold"),
1016 },
1017 Some(MouseEventName::MouseRelease) => match mouse_event_payload.mouse_event_payload {
1018 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1019 Mouse::Release(position.line as isize, position.column as usize),
1020 ),
1021 _ => Err("Malformed payload for mouse release"),
1022 },
1023 Some(MouseEventName::MouseHover) => match mouse_event_payload.mouse_event_payload {
1024 Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
1025 Mouse::Hover(position.line as isize, position.column as usize),
1026 ),
1027 _ => Err("Malformed payload for mouse hover"),
1028 },
1029 None => Err("Malformed payload for MouseEventName"),
1030 }
1031 }
1032}
1033
1034impl TryFrom<Mouse> for MouseEventPayload {
1035 type Error = &'static str;
1036 fn try_from(mouse: Mouse) -> Result<Self, &'static str> {
1037 match mouse {
1038 Mouse::ScrollUp(number_of_lines) => Ok(MouseEventPayload {
1039 mouse_event_name: MouseEventName::MouseScrollUp as i32,
1040 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
1041 number_of_lines as u32,
1042 )),
1043 }),
1044 Mouse::ScrollDown(number_of_lines) => Ok(MouseEventPayload {
1045 mouse_event_name: MouseEventName::MouseScrollDown as i32,
1046 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
1047 number_of_lines as u32,
1048 )),
1049 }),
1050 Mouse::LeftClick(line, column) => Ok(MouseEventPayload {
1051 mouse_event_name: MouseEventName::MouseLeftClick as i32,
1052 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1053 ProtobufPosition {
1054 line: line as i64,
1055 column: column as i64,
1056 },
1057 )),
1058 }),
1059 Mouse::RightClick(line, column) => Ok(MouseEventPayload {
1060 mouse_event_name: MouseEventName::MouseRightClick as i32,
1061 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1062 ProtobufPosition {
1063 line: line as i64,
1064 column: column as i64,
1065 },
1066 )),
1067 }),
1068 Mouse::Hold(line, column) => Ok(MouseEventPayload {
1069 mouse_event_name: MouseEventName::MouseHold as i32,
1070 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1071 ProtobufPosition {
1072 line: line as i64,
1073 column: column as i64,
1074 },
1075 )),
1076 }),
1077 Mouse::Release(line, column) => Ok(MouseEventPayload {
1078 mouse_event_name: MouseEventName::MouseRelease as i32,
1079 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1080 ProtobufPosition {
1081 line: line as i64,
1082 column: column as i64,
1083 },
1084 )),
1085 }),
1086 Mouse::Hover(line, column) => Ok(MouseEventPayload {
1087 mouse_event_name: MouseEventName::MouseHover as i32,
1088 mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
1089 ProtobufPosition {
1090 line: line as i64,
1091 column: column as i64,
1092 },
1093 )),
1094 }),
1095 }
1096 }
1097}
1098
1099impl TryFrom<ProtobufPaneInfo> for PaneInfo {
1100 type Error = &'static str;
1101 fn try_from(protobuf_pane_info: ProtobufPaneInfo) -> Result<Self, &'static str> {
1102 Ok(PaneInfo {
1103 id: protobuf_pane_info.id,
1104 is_plugin: protobuf_pane_info.is_plugin,
1105 is_focused: protobuf_pane_info.is_focused,
1106 is_fullscreen: protobuf_pane_info.is_fullscreen,
1107 is_floating: protobuf_pane_info.is_floating,
1108 is_suppressed: protobuf_pane_info.is_suppressed,
1109 title: protobuf_pane_info.title,
1110 exited: protobuf_pane_info.exited,
1111 exit_status: protobuf_pane_info.exit_status,
1112 is_held: protobuf_pane_info.is_held,
1113 pane_x: protobuf_pane_info.pane_x as usize,
1114 pane_content_x: protobuf_pane_info.pane_content_x as usize,
1115 pane_y: protobuf_pane_info.pane_y as usize,
1116 pane_content_y: protobuf_pane_info.pane_content_y as usize,
1117 pane_rows: protobuf_pane_info.pane_rows as usize,
1118 pane_content_rows: protobuf_pane_info.pane_content_rows as usize,
1119 pane_columns: protobuf_pane_info.pane_columns as usize,
1120 pane_content_columns: protobuf_pane_info.pane_content_columns as usize,
1121 cursor_coordinates_in_pane: protobuf_pane_info
1122 .cursor_coordinates_in_pane
1123 .map(|position| (position.column as usize, position.line as usize)),
1124 terminal_command: protobuf_pane_info.terminal_command,
1125 plugin_url: protobuf_pane_info.plugin_url,
1126 is_selectable: protobuf_pane_info.is_selectable,
1127 index_in_pane_group: protobuf_pane_info
1128 .index_in_pane_group
1129 .iter()
1130 .map(|index_in_pane_group| {
1131 (
1132 index_in_pane_group.client_id as u16,
1133 index_in_pane_group.index as usize,
1134 )
1135 })
1136 .collect(),
1137 })
1138 }
1139}
1140
1141impl TryFrom<PaneInfo> for ProtobufPaneInfo {
1142 type Error = &'static str;
1143 fn try_from(pane_info: PaneInfo) -> Result<Self, &'static str> {
1144 Ok(ProtobufPaneInfo {
1145 id: pane_info.id,
1146 is_plugin: pane_info.is_plugin,
1147 is_focused: pane_info.is_focused,
1148 is_fullscreen: pane_info.is_fullscreen,
1149 is_floating: pane_info.is_floating,
1150 is_suppressed: pane_info.is_suppressed,
1151 title: pane_info.title,
1152 exited: pane_info.exited,
1153 exit_status: pane_info.exit_status,
1154 is_held: pane_info.is_held,
1155 pane_x: pane_info.pane_x as u32,
1156 pane_content_x: pane_info.pane_content_x as u32,
1157 pane_y: pane_info.pane_y as u32,
1158 pane_content_y: pane_info.pane_content_y as u32,
1159 pane_rows: pane_info.pane_rows as u32,
1160 pane_content_rows: pane_info.pane_content_rows as u32,
1161 pane_columns: pane_info.pane_columns as u32,
1162 pane_content_columns: pane_info.pane_content_columns as u32,
1163 cursor_coordinates_in_pane: pane_info.cursor_coordinates_in_pane.map(|(x, y)| {
1164 ProtobufPosition {
1165 column: x as i64,
1166 line: y as i64,
1167 }
1168 }),
1169 terminal_command: pane_info.terminal_command,
1170 plugin_url: pane_info.plugin_url,
1171 is_selectable: pane_info.is_selectable,
1172 index_in_pane_group: pane_info
1173 .index_in_pane_group
1174 .iter()
1175 .map(|(&client_id, &index)| IndexInPaneGroup {
1176 client_id: client_id as u32,
1177 index: index as u32,
1178 })
1179 .collect(),
1180 })
1181 }
1182}
1183
1184impl TryFrom<ProtobufTabInfo> for TabInfo {
1185 type Error = &'static str;
1186 fn try_from(protobuf_tab_info: ProtobufTabInfo) -> Result<Self, &'static str> {
1187 Ok(TabInfo {
1188 position: protobuf_tab_info.position as usize,
1189 name: protobuf_tab_info.name,
1190 active: protobuf_tab_info.active,
1191 panes_to_hide: protobuf_tab_info.panes_to_hide as usize,
1192 is_fullscreen_active: protobuf_tab_info.is_fullscreen_active,
1193 is_sync_panes_active: protobuf_tab_info.is_sync_panes_active,
1194 are_floating_panes_visible: protobuf_tab_info.are_floating_panes_visible,
1195 other_focused_clients: protobuf_tab_info
1196 .other_focused_clients
1197 .iter()
1198 .map(|c| *c as u16)
1199 .collect(),
1200 active_swap_layout_name: protobuf_tab_info.active_swap_layout_name,
1201 is_swap_layout_dirty: protobuf_tab_info.is_swap_layout_dirty,
1202 viewport_rows: protobuf_tab_info.viewport_rows as usize,
1203 viewport_columns: protobuf_tab_info.viewport_columns as usize,
1204 display_area_rows: protobuf_tab_info.display_area_rows as usize,
1205 display_area_columns: protobuf_tab_info.display_area_columns as usize,
1206 selectable_tiled_panes_count: protobuf_tab_info.selectable_tiled_panes_count as usize,
1207 selectable_floating_panes_count: protobuf_tab_info.selectable_floating_panes_count
1208 as usize,
1209 })
1210 }
1211}
1212
1213impl TryFrom<TabInfo> for ProtobufTabInfo {
1214 type Error = &'static str;
1215 fn try_from(tab_info: TabInfo) -> Result<Self, &'static str> {
1216 Ok(ProtobufTabInfo {
1217 position: tab_info.position as u32,
1218 name: tab_info.name,
1219 active: tab_info.active,
1220 panes_to_hide: tab_info.panes_to_hide as u32,
1221 is_fullscreen_active: tab_info.is_fullscreen_active,
1222 is_sync_panes_active: tab_info.is_sync_panes_active,
1223 are_floating_panes_visible: tab_info.are_floating_panes_visible,
1224 other_focused_clients: tab_info
1225 .other_focused_clients
1226 .iter()
1227 .map(|c| *c as u32)
1228 .collect(),
1229 active_swap_layout_name: tab_info.active_swap_layout_name,
1230 is_swap_layout_dirty: tab_info.is_swap_layout_dirty,
1231 viewport_rows: tab_info.viewport_rows as u32,
1232 viewport_columns: tab_info.viewport_columns as u32,
1233 display_area_rows: tab_info.display_area_rows as u32,
1234 display_area_columns: tab_info.display_area_columns as u32,
1235 selectable_tiled_panes_count: tab_info.selectable_tiled_panes_count as u32,
1236 selectable_floating_panes_count: tab_info.selectable_floating_panes_count as u32,
1237 })
1238 }
1239}
1240
1241impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
1242 type Error = &'static str;
1243 fn try_from(
1244 mut protobuf_mode_update_payload: ProtobufModeUpdatePayload,
1245 ) -> Result<Self, &'static str> {
1246 let current_mode: InputMode =
1247 ProtobufInputMode::from_i32(protobuf_mode_update_payload.current_mode)
1248 .ok_or("Malformed InputMode in the ModeUpdate Event")?
1249 .try_into()?;
1250 let base_mode: Option<InputMode> = protobuf_mode_update_payload
1251 .base_mode
1252 .and_then(|b_m| ProtobufInputMode::from_i32(b_m)?.try_into().ok());
1253 let keybinds: Vec<(InputMode, Vec<(KeyWithModifier, Vec<Action>)>)> =
1254 protobuf_mode_update_payload
1255 .keybinds
1256 .iter_mut()
1257 .filter_map(|k| {
1258 let input_mode: InputMode = ProtobufInputMode::from_i32(k.mode)
1259 .ok_or("Malformed InputMode in the ModeUpdate Event")
1260 .ok()?
1261 .try_into()
1262 .ok()?;
1263 let mut keybinds: Vec<(KeyWithModifier, Vec<Action>)> = vec![];
1264 for mut protobuf_keybind in k.key_bind.drain(..) {
1265 let key: KeyWithModifier = protobuf_keybind.key.unwrap().try_into().ok()?;
1266 let mut actions: Vec<Action> = vec![];
1267 for action in protobuf_keybind.action.drain(..) {
1268 if let Ok(action) = action.try_into() {
1269 actions.push(action);
1270 }
1271 }
1272 keybinds.push((key, actions));
1273 }
1274 Some((input_mode, keybinds))
1275 })
1276 .collect();
1277 let style: Style = protobuf_mode_update_payload
1278 .style
1279 .and_then(|m| m.try_into().ok())
1280 .ok_or("malformed payload for mode_info")?;
1281 let session_name = protobuf_mode_update_payload.session_name;
1282 let editor = protobuf_mode_update_payload
1283 .editor
1284 .map(|e| PathBuf::from(e));
1285 let shell = protobuf_mode_update_payload.shell.map(|s| PathBuf::from(s));
1286 let web_clients_allowed = protobuf_mode_update_payload.web_clients_allowed;
1287 let web_sharing = protobuf_mode_update_payload
1288 .web_sharing
1289 .and_then(|w| ProtobufWebSharing::from_i32(w))
1290 .map(|w| w.into());
1291 let capabilities = PluginCapabilities {
1292 arrow_fonts: protobuf_mode_update_payload.arrow_fonts_support,
1293 };
1294 let currently_marking_pane_group =
1295 protobuf_mode_update_payload.currently_marking_pane_group;
1296 let is_web_client = protobuf_mode_update_payload.is_web_client;
1297
1298 let web_server_ip = protobuf_mode_update_payload
1299 .web_server_ip
1300 .as_ref()
1301 .and_then(|web_server_ip| IpAddr::from_str(web_server_ip).ok());
1302
1303 let web_server_port = protobuf_mode_update_payload
1304 .web_server_port
1305 .map(|w| w as u16);
1306
1307 let web_server_capability = protobuf_mode_update_payload.web_server_capability;
1308
1309 let mode_info = ModeInfo {
1310 mode: current_mode,
1311 keybinds,
1312 style,
1313 capabilities,
1314 session_name,
1315 base_mode,
1316 editor,
1317 shell,
1318 web_clients_allowed,
1319 web_sharing,
1320 currently_marking_pane_group,
1321 is_web_client,
1322 web_server_ip,
1323 web_server_port,
1324 web_server_capability,
1325 };
1326 Ok(mode_info)
1327 }
1328}
1329
1330impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
1331 type Error = &'static str;
1332 fn try_from(mode_info: ModeInfo) -> Result<Self, &'static str> {
1333 let current_mode: ProtobufInputMode = mode_info.mode.try_into()?;
1334 let base_mode: Option<ProtobufInputMode> = mode_info
1335 .base_mode
1336 .and_then(|mode| ProtobufInputMode::try_from(mode).ok());
1337 let style: ProtobufStyle = mode_info.style.try_into()?;
1338 let arrow_fonts_support: bool = mode_info.capabilities.arrow_fonts;
1339 let session_name = mode_info.session_name;
1340 let editor = mode_info.editor.map(|e| e.display().to_string());
1341 let shell = mode_info.shell.map(|s| s.display().to_string());
1342 let web_clients_allowed = mode_info.web_clients_allowed;
1343 let web_sharing = mode_info.web_sharing.map(|w| w as i32);
1344 let currently_marking_pane_group = mode_info.currently_marking_pane_group;
1345 let is_web_client = mode_info.is_web_client;
1346 let web_server_ip = mode_info.web_server_ip.map(|i| format!("{}", i));
1347 let web_server_port = mode_info.web_server_port.map(|p| p as u32);
1348 let web_server_capability = mode_info.web_server_capability;
1349 let mut protobuf_input_mode_keybinds: Vec<ProtobufInputModeKeybinds> = vec![];
1350 for (input_mode, input_mode_keybinds) in mode_info.keybinds {
1351 let mode: ProtobufInputMode = input_mode.try_into()?;
1352 let mut keybinds: Vec<ProtobufKeyBind> = vec![];
1353 for (key, actions) in input_mode_keybinds {
1354 let protobuf_key: ProtobufKey = key.try_into()?;
1355 let mut protobuf_actions: Vec<ProtobufAction> = vec![];
1356 for action in actions {
1357 if let Ok(protobuf_action) = action.try_into() {
1358 protobuf_actions.push(protobuf_action);
1359 }
1360 }
1361 let key_bind = ProtobufKeyBind {
1362 key: Some(protobuf_key),
1363 action: protobuf_actions,
1364 };
1365 keybinds.push(key_bind);
1366 }
1367 let input_mode_keybind = ProtobufInputModeKeybinds {
1368 mode: mode as i32,
1369 key_bind: keybinds,
1370 };
1371 protobuf_input_mode_keybinds.push(input_mode_keybind);
1372 }
1373 Ok(ProtobufModeUpdatePayload {
1374 current_mode: current_mode as i32,
1375 style: Some(style),
1376 keybinds: protobuf_input_mode_keybinds,
1377 arrow_fonts_support,
1378 session_name,
1379 base_mode: base_mode.map(|b_m| b_m as i32),
1380 editor,
1381 shell,
1382 web_clients_allowed,
1383 web_sharing,
1384 currently_marking_pane_group,
1385 is_web_client,
1386 web_server_ip,
1387 web_server_port,
1388 web_server_capability,
1389 })
1390 }
1391}
1392
1393impl TryFrom<ProtobufEventNameList> for HashSet<EventType> {
1394 type Error = &'static str;
1395 fn try_from(protobuf_event_name_list: ProtobufEventNameList) -> Result<Self, &'static str> {
1396 let event_types: Vec<ProtobufEventType> = protobuf_event_name_list
1397 .event_types
1398 .iter()
1399 .filter_map(|i| ProtobufEventType::from_i32(*i))
1400 .collect();
1401 let event_types: Vec<EventType> = event_types
1402 .iter()
1403 .filter_map(|e| EventType::try_from(*e).ok())
1404 .collect();
1405 Ok(event_types.into_iter().collect())
1406 }
1407}
1408
1409impl TryFrom<HashSet<EventType>> for ProtobufEventNameList {
1410 type Error = &'static str;
1411 fn try_from(event_types: HashSet<EventType>) -> Result<Self, &'static str> {
1412 let protobuf_event_name_list = ProtobufEventNameList {
1413 event_types: event_types
1414 .iter()
1415 .filter_map(|e| ProtobufEventType::try_from(*e).ok())
1416 .map(|e| e as i32)
1417 .collect(),
1418 };
1419 Ok(protobuf_event_name_list)
1420 }
1421}
1422
1423impl TryFrom<ProtobufEventType> for EventType {
1424 type Error = &'static str;
1425 fn try_from(protobuf_event_type: ProtobufEventType) -> Result<Self, &'static str> {
1426 Ok(match protobuf_event_type {
1427 ProtobufEventType::ModeUpdate => EventType::ModeUpdate,
1428 ProtobufEventType::TabUpdate => EventType::TabUpdate,
1429 ProtobufEventType::PaneUpdate => EventType::PaneUpdate,
1430 ProtobufEventType::Key => EventType::Key,
1431 ProtobufEventType::Mouse => EventType::Mouse,
1432 ProtobufEventType::Timer => EventType::Timer,
1433 ProtobufEventType::CopyToClipboard => EventType::CopyToClipboard,
1434 ProtobufEventType::SystemClipboardFailure => EventType::SystemClipboardFailure,
1435 ProtobufEventType::InputReceived => EventType::InputReceived,
1436 ProtobufEventType::Visible => EventType::Visible,
1437 ProtobufEventType::CustomMessage => EventType::CustomMessage,
1438 ProtobufEventType::FileSystemCreate => EventType::FileSystemCreate,
1439 ProtobufEventType::FileSystemRead => EventType::FileSystemRead,
1440 ProtobufEventType::FileSystemUpdate => EventType::FileSystemUpdate,
1441 ProtobufEventType::FileSystemDelete => EventType::FileSystemDelete,
1442 ProtobufEventType::PermissionRequestResult => EventType::PermissionRequestResult,
1443 ProtobufEventType::SessionUpdate => EventType::SessionUpdate,
1444 ProtobufEventType::RunCommandResult => EventType::RunCommandResult,
1445 ProtobufEventType::WebRequestResult => EventType::WebRequestResult,
1446 ProtobufEventType::CommandPaneOpened => EventType::CommandPaneOpened,
1447 ProtobufEventType::CommandPaneExited => EventType::CommandPaneExited,
1448 ProtobufEventType::PaneClosed => EventType::PaneClosed,
1449 ProtobufEventType::EditPaneOpened => EventType::EditPaneOpened,
1450 ProtobufEventType::EditPaneExited => EventType::EditPaneExited,
1451 ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
1452 ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk,
1453 ProtobufEventType::ListClients => EventType::ListClients,
1454 ProtobufEventType::HostFolderChanged => EventType::HostFolderChanged,
1455 ProtobufEventType::FailedToChangeHostFolder => EventType::FailedToChangeHostFolder,
1456 ProtobufEventType::PastedText => EventType::PastedText,
1457 ProtobufEventType::ConfigWasWrittenToDisk => EventType::ConfigWasWrittenToDisk,
1458 ProtobufEventType::WebServerStatus => EventType::WebServerStatus,
1459 ProtobufEventType::BeforeClose => EventType::BeforeClose,
1460 ProtobufEventType::FailedToStartWebServer => EventType::FailedToStartWebServer,
1461 ProtobufEventType::InterceptedKeyPress => EventType::InterceptedKeyPress,
1462 })
1463 }
1464}
1465
1466impl TryFrom<EventType> for ProtobufEventType {
1467 type Error = &'static str;
1468 fn try_from(event_type: EventType) -> Result<Self, &'static str> {
1469 Ok(match event_type {
1470 EventType::ModeUpdate => ProtobufEventType::ModeUpdate,
1471 EventType::TabUpdate => ProtobufEventType::TabUpdate,
1472 EventType::PaneUpdate => ProtobufEventType::PaneUpdate,
1473 EventType::Key => ProtobufEventType::Key,
1474 EventType::Mouse => ProtobufEventType::Mouse,
1475 EventType::Timer => ProtobufEventType::Timer,
1476 EventType::CopyToClipboard => ProtobufEventType::CopyToClipboard,
1477 EventType::SystemClipboardFailure => ProtobufEventType::SystemClipboardFailure,
1478 EventType::InputReceived => ProtobufEventType::InputReceived,
1479 EventType::Visible => ProtobufEventType::Visible,
1480 EventType::CustomMessage => ProtobufEventType::CustomMessage,
1481 EventType::FileSystemCreate => ProtobufEventType::FileSystemCreate,
1482 EventType::FileSystemRead => ProtobufEventType::FileSystemRead,
1483 EventType::FileSystemUpdate => ProtobufEventType::FileSystemUpdate,
1484 EventType::FileSystemDelete => ProtobufEventType::FileSystemDelete,
1485 EventType::PermissionRequestResult => ProtobufEventType::PermissionRequestResult,
1486 EventType::SessionUpdate => ProtobufEventType::SessionUpdate,
1487 EventType::RunCommandResult => ProtobufEventType::RunCommandResult,
1488 EventType::WebRequestResult => ProtobufEventType::WebRequestResult,
1489 EventType::CommandPaneOpened => ProtobufEventType::CommandPaneOpened,
1490 EventType::CommandPaneExited => ProtobufEventType::CommandPaneExited,
1491 EventType::PaneClosed => ProtobufEventType::PaneClosed,
1492 EventType::EditPaneOpened => ProtobufEventType::EditPaneOpened,
1493 EventType::EditPaneExited => ProtobufEventType::EditPaneExited,
1494 EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
1495 EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk,
1496 EventType::ListClients => ProtobufEventType::ListClients,
1497 EventType::HostFolderChanged => ProtobufEventType::HostFolderChanged,
1498 EventType::FailedToChangeHostFolder => ProtobufEventType::FailedToChangeHostFolder,
1499 EventType::PastedText => ProtobufEventType::PastedText,
1500 EventType::ConfigWasWrittenToDisk => ProtobufEventType::ConfigWasWrittenToDisk,
1501 EventType::WebServerStatus => ProtobufEventType::WebServerStatus,
1502 EventType::BeforeClose => ProtobufEventType::BeforeClose,
1503 EventType::FailedToStartWebServer => ProtobufEventType::FailedToStartWebServer,
1504 EventType::InterceptedKeyPress => ProtobufEventType::InterceptedKeyPress,
1505 })
1506 }
1507}
1508
1509impl From<ProtobufResurrectableSession> for (String, Duration) {
1510 fn from(protobuf_resurrectable_session: ProtobufResurrectableSession) -> (String, Duration) {
1511 (
1512 protobuf_resurrectable_session.name,
1513 Duration::from_secs(protobuf_resurrectable_session.creation_time),
1514 )
1515 }
1516}
1517
1518impl From<(String, Duration)> for ProtobufResurrectableSession {
1519 fn from(session_name_and_creation_time: (String, Duration)) -> ProtobufResurrectableSession {
1520 ProtobufResurrectableSession {
1521 name: session_name_and_creation_time.0,
1522 creation_time: session_name_and_creation_time.1.as_secs(),
1523 }
1524 }
1525}
1526
1527impl From<&ProtobufFileMetadata> for Option<FileMetadata> {
1528 fn from(protobuf_file_metadata: &ProtobufFileMetadata) -> Option<FileMetadata> {
1529 if protobuf_file_metadata.metadata_is_set {
1530 Some(FileMetadata {
1531 is_file: protobuf_file_metadata.is_file,
1532 is_dir: protobuf_file_metadata.is_dir,
1533 is_symlink: protobuf_file_metadata.is_symlink,
1534 len: protobuf_file_metadata.len,
1535 })
1536 } else {
1537 None
1538 }
1539 }
1540}
1541
1542impl From<Option<FileMetadata>> for ProtobufFileMetadata {
1543 fn from(file_metadata: Option<FileMetadata>) -> ProtobufFileMetadata {
1544 match file_metadata {
1545 Some(file_metadata) => ProtobufFileMetadata {
1546 metadata_is_set: true,
1547 is_file: file_metadata.is_file,
1548 is_dir: file_metadata.is_dir,
1549 is_symlink: file_metadata.is_symlink,
1550 len: file_metadata.len,
1551 },
1552 None => ProtobufFileMetadata {
1553 metadata_is_set: false,
1554 ..Default::default()
1555 },
1556 }
1557 }
1558}
1559
1560#[test]
1561fn serialize_mode_update_event() {
1562 use prost::Message;
1563 let mode_update_event = Event::ModeUpdate(Default::default());
1564 let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
1565 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1566 let deserialized_protobuf_event: ProtobufEvent =
1567 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1568 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1569 assert_eq!(
1570 mode_update_event, deserialized_event,
1571 "Event properly serialized/deserialized without change"
1572 );
1573}
1574
1575#[test]
1576fn serialize_mode_update_event_with_non_default_values() {
1577 use crate::data::{BareKey, Palette, PaletteColor, ThemeHue};
1578 use prost::Message;
1579 let mode_update_event = Event::ModeUpdate(ModeInfo {
1580 mode: InputMode::Locked,
1581 keybinds: vec![
1582 (
1583 InputMode::Locked,
1584 vec![(
1585 KeyWithModifier::new(BareKey::Char('b')).with_alt_modifier(),
1586 vec![Action::SwitchToMode(InputMode::Normal)],
1587 )],
1588 ),
1589 (
1590 InputMode::Tab,
1591 vec![(
1592 KeyWithModifier::new(BareKey::Up).with_alt_modifier(),
1593 vec![Action::SwitchToMode(InputMode::Pane)],
1594 )],
1595 ),
1596 (
1597 InputMode::Pane,
1598 vec![
1599 (
1600 KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
1601 vec![
1602 Action::SwitchToMode(InputMode::Tmux),
1603 Action::Write(None, vec![10], false),
1604 ],
1605 ),
1606 (
1607 KeyWithModifier::new(BareKey::Char('a')),
1608 vec![Action::WriteChars("foo".to_owned())],
1609 ),
1610 ],
1611 ),
1612 ],
1613 style: Style {
1614 colors: Palette {
1615 source: crate::data::PaletteSource::Default,
1616 theme_hue: ThemeHue::Light,
1617 fg: PaletteColor::Rgb((1, 1, 1)),
1618 bg: PaletteColor::Rgb((200, 200, 200)),
1619 black: PaletteColor::EightBit(1),
1620 red: PaletteColor::EightBit(2),
1621 green: PaletteColor::EightBit(2),
1622 yellow: PaletteColor::EightBit(2),
1623 blue: PaletteColor::EightBit(2),
1624 magenta: PaletteColor::EightBit(2),
1625 cyan: PaletteColor::EightBit(2),
1626 white: PaletteColor::EightBit(2),
1627 orange: PaletteColor::EightBit(2),
1628 gray: PaletteColor::EightBit(2),
1629 purple: PaletteColor::EightBit(2),
1630 gold: PaletteColor::EightBit(2),
1631 silver: PaletteColor::EightBit(2),
1632 pink: PaletteColor::EightBit(2),
1633 brown: PaletteColor::Rgb((222, 221, 220)),
1634 }
1635 .into(),
1636 rounded_corners: true,
1638 hide_session_name: false,
1639 },
1640 capabilities: PluginCapabilities { arrow_fonts: false },
1641 session_name: Some("my awesome test session".to_owned()),
1642 base_mode: Some(InputMode::Locked),
1643 editor: Some(PathBuf::from("my_awesome_editor")),
1644 shell: Some(PathBuf::from("my_awesome_shell")),
1645 web_clients_allowed: Some(true),
1646 web_sharing: Some(WebSharing::default()),
1647 currently_marking_pane_group: Some(false),
1648 is_web_client: Some(false),
1649 web_server_ip: IpAddr::from_str("127.0.0.1").ok(),
1650 web_server_port: Some(8082),
1651 web_server_capability: Some(true),
1652 });
1653 let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
1654 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1655 let deserialized_protobuf_event: ProtobufEvent =
1656 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1657 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1658 assert_eq!(
1659 mode_update_event, deserialized_event,
1660 "Event properly serialized/deserialized without change"
1661 );
1662}
1663
1664#[test]
1665fn serialize_tab_update_event() {
1666 use prost::Message;
1667 let tab_update_event = Event::TabUpdate(Default::default());
1668 let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
1669 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1670 let deserialized_protobuf_event: ProtobufEvent =
1671 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1672 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1673 assert_eq!(
1674 tab_update_event, deserialized_event,
1675 "Event properly serialized/deserialized without change"
1676 );
1677}
1678
1679#[test]
1680fn serialize_tab_update_event_with_non_default_values() {
1681 use prost::Message;
1682 let tab_update_event = Event::TabUpdate(vec![
1683 TabInfo {
1684 position: 0,
1685 name: "First tab".to_owned(),
1686 active: true,
1687 panes_to_hide: 2,
1688 is_fullscreen_active: true,
1689 is_sync_panes_active: false,
1690 are_floating_panes_visible: true,
1691 other_focused_clients: vec![2, 3, 4],
1692 active_swap_layout_name: Some("my cool swap layout".to_owned()),
1693 is_swap_layout_dirty: false,
1694 viewport_rows: 10,
1695 viewport_columns: 10,
1696 display_area_rows: 10,
1697 display_area_columns: 10,
1698 selectable_tiled_panes_count: 10,
1699 selectable_floating_panes_count: 10,
1700 },
1701 TabInfo {
1702 position: 1,
1703 name: "Secondtab".to_owned(),
1704 active: false,
1705 panes_to_hide: 5,
1706 is_fullscreen_active: false,
1707 is_sync_panes_active: true,
1708 are_floating_panes_visible: true,
1709 other_focused_clients: vec![1, 5, 111],
1710 active_swap_layout_name: None,
1711 is_swap_layout_dirty: true,
1712 viewport_rows: 10,
1713 viewport_columns: 10,
1714 display_area_rows: 10,
1715 display_area_columns: 10,
1716 selectable_tiled_panes_count: 10,
1717 selectable_floating_panes_count: 10,
1718 },
1719 TabInfo::default(),
1720 ]);
1721 let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
1722 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1723 let deserialized_protobuf_event: ProtobufEvent =
1724 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1725 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1726 assert_eq!(
1727 tab_update_event, deserialized_event,
1728 "Event properly serialized/deserialized without change"
1729 );
1730}
1731
1732#[test]
1733fn serialize_pane_update_event() {
1734 use prost::Message;
1735 let pane_update_event = Event::PaneUpdate(Default::default());
1736 let protobuf_event: ProtobufEvent = pane_update_event.clone().try_into().unwrap();
1737 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1738 let deserialized_protobuf_event: ProtobufEvent =
1739 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1740 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1741 assert_eq!(
1742 pane_update_event, deserialized_event,
1743 "Event properly serialized/deserialized without change"
1744 );
1745}
1746
1747#[test]
1748fn serialize_key_event() {
1749 use crate::data::BareKey;
1750 use prost::Message;
1751 let key_event = Event::Key(KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier());
1752 let protobuf_event: ProtobufEvent = key_event.clone().try_into().unwrap();
1753 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1754 let deserialized_protobuf_event: ProtobufEvent =
1755 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1756 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1757 assert_eq!(
1758 key_event, deserialized_event,
1759 "Event properly serialized/deserialized without change"
1760 );
1761}
1762
1763#[test]
1764fn serialize_mouse_event() {
1765 use prost::Message;
1766 let mouse_event = Event::Mouse(Mouse::LeftClick(1, 1));
1767 let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
1768 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1769 let deserialized_protobuf_event: ProtobufEvent =
1770 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1771 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1772 assert_eq!(
1773 mouse_event, deserialized_event,
1774 "Event properly serialized/deserialized without change"
1775 );
1776}
1777
1778#[test]
1779fn serialize_mouse_event_without_position() {
1780 use prost::Message;
1781 let mouse_event = Event::Mouse(Mouse::ScrollUp(17));
1782 let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
1783 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1784 let deserialized_protobuf_event: ProtobufEvent =
1785 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1786 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1787 assert_eq!(
1788 mouse_event, deserialized_event,
1789 "Event properly serialized/deserialized without change"
1790 );
1791}
1792
1793#[test]
1794fn serialize_timer_event() {
1795 use prost::Message;
1796 let timer_event = Event::Timer(1.5);
1797 let protobuf_event: ProtobufEvent = timer_event.clone().try_into().unwrap();
1798 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1799 let deserialized_protobuf_event: ProtobufEvent =
1800 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1801 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1802 assert_eq!(
1803 timer_event, deserialized_event,
1804 "Event properly serialized/deserialized without change"
1805 );
1806}
1807
1808#[test]
1809fn serialize_copy_to_clipboard_event() {
1810 use prost::Message;
1811 let copy_event = Event::CopyToClipboard(CopyDestination::Primary);
1812 let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
1813 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1814 let deserialized_protobuf_event: ProtobufEvent =
1815 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1816 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1817 assert_eq!(
1818 copy_event, deserialized_event,
1819 "Event properly serialized/deserialized without change"
1820 );
1821}
1822
1823#[test]
1824fn serialize_clipboard_failure_event() {
1825 use prost::Message;
1826 let copy_event = Event::SystemClipboardFailure;
1827 let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
1828 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1829 let deserialized_protobuf_event: ProtobufEvent =
1830 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1831 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1832 assert_eq!(
1833 copy_event, deserialized_event,
1834 "Event properly serialized/deserialized without change"
1835 );
1836}
1837
1838#[test]
1839fn serialize_input_received_event() {
1840 use prost::Message;
1841 let input_received_event = Event::InputReceived;
1842 let protobuf_event: ProtobufEvent = input_received_event.clone().try_into().unwrap();
1843 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1844 let deserialized_protobuf_event: ProtobufEvent =
1845 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1846 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1847 assert_eq!(
1848 input_received_event, deserialized_event,
1849 "Event properly serialized/deserialized without change"
1850 );
1851}
1852
1853#[test]
1854fn serialize_visible_event() {
1855 use prost::Message;
1856 let visible_event = Event::Visible(true);
1857 let protobuf_event: ProtobufEvent = visible_event.clone().try_into().unwrap();
1858 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1859 let deserialized_protobuf_event: ProtobufEvent =
1860 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1861 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1862 assert_eq!(
1863 visible_event, deserialized_event,
1864 "Event properly serialized/deserialized without change"
1865 );
1866}
1867
1868#[test]
1869fn serialize_custom_message_event() {
1870 use prost::Message;
1871 let custom_message_event = Event::CustomMessage("foo".to_owned(), "bar".to_owned());
1872 let protobuf_event: ProtobufEvent = custom_message_event.clone().try_into().unwrap();
1873 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1874 let deserialized_protobuf_event: ProtobufEvent =
1875 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1876 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1877 assert_eq!(
1878 custom_message_event, deserialized_event,
1879 "Event properly serialized/deserialized without change"
1880 );
1881}
1882
1883#[test]
1884fn serialize_file_system_create_event() {
1885 use prost::Message;
1886 let file_system_event = Event::FileSystemCreate(vec![
1887 ("/absolute/path".into(), None),
1888 ("./relative_path".into(), Default::default()),
1889 ]);
1890 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
1891 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1892 let deserialized_protobuf_event: ProtobufEvent =
1893 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1894 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1895 assert_eq!(
1896 file_system_event, deserialized_event,
1897 "Event properly serialized/deserialized without change"
1898 );
1899}
1900
1901#[test]
1902fn serialize_file_system_read_event() {
1903 use prost::Message;
1904 let file_system_event = Event::FileSystemRead(vec![
1905 ("/absolute/path".into(), None),
1906 ("./relative_path".into(), Default::default()),
1907 ]);
1908 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
1909 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1910 let deserialized_protobuf_event: ProtobufEvent =
1911 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1912 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1913 assert_eq!(
1914 file_system_event, deserialized_event,
1915 "Event properly serialized/deserialized without change"
1916 );
1917}
1918
1919#[test]
1920fn serialize_file_system_update_event() {
1921 use prost::Message;
1922 let file_system_event = Event::FileSystemUpdate(vec![
1923 ("/absolute/path".into(), None),
1924 ("./relative_path".into(), Some(Default::default())),
1925 ]);
1926 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
1927 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1928 let deserialized_protobuf_event: ProtobufEvent =
1929 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1930 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1931 assert_eq!(
1932 file_system_event, deserialized_event,
1933 "Event properly serialized/deserialized without change"
1934 );
1935}
1936
1937#[test]
1938fn serialize_file_system_delete_event() {
1939 use prost::Message;
1940 let file_system_event = Event::FileSystemDelete(vec![
1941 ("/absolute/path".into(), None),
1942 ("./relative_path".into(), Default::default()),
1943 ]);
1944 let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
1945 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1946 let deserialized_protobuf_event: ProtobufEvent =
1947 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1948 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1949 assert_eq!(
1950 file_system_event, deserialized_event,
1951 "Event properly serialized/deserialized without change"
1952 );
1953}
1954
1955#[test]
1956fn serialize_session_update_event() {
1957 use prost::Message;
1958 let session_update_event = Event::SessionUpdate(Default::default(), Default::default());
1959 let protobuf_event: ProtobufEvent = session_update_event.clone().try_into().unwrap();
1960 let serialized_protobuf_event = protobuf_event.encode_to_vec();
1961 let deserialized_protobuf_event: ProtobufEvent =
1962 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
1963 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
1964 assert_eq!(
1965 session_update_event, deserialized_event,
1966 "Event properly serialized/deserialized without change"
1967 );
1968}
1969
1970#[test]
1971fn serialize_session_update_event_with_non_default_values() {
1972 use prost::Message;
1973 let tab_infos = vec![
1974 TabInfo {
1975 position: 0,
1976 name: "First tab".to_owned(),
1977 active: true,
1978 panes_to_hide: 2,
1979 is_fullscreen_active: true,
1980 is_sync_panes_active: false,
1981 are_floating_panes_visible: true,
1982 other_focused_clients: vec![2, 3, 4],
1983 active_swap_layout_name: Some("my cool swap layout".to_owned()),
1984 is_swap_layout_dirty: false,
1985 viewport_rows: 10,
1986 viewport_columns: 10,
1987 display_area_rows: 10,
1988 display_area_columns: 10,
1989 selectable_tiled_panes_count: 10,
1990 selectable_floating_panes_count: 10,
1991 },
1992 TabInfo {
1993 position: 1,
1994 name: "Secondtab".to_owned(),
1995 active: false,
1996 panes_to_hide: 5,
1997 is_fullscreen_active: false,
1998 is_sync_panes_active: true,
1999 are_floating_panes_visible: true,
2000 other_focused_clients: vec![1, 5, 111],
2001 active_swap_layout_name: None,
2002 is_swap_layout_dirty: true,
2003 viewport_rows: 10,
2004 viewport_columns: 10,
2005 display_area_rows: 10,
2006 display_area_columns: 10,
2007 selectable_tiled_panes_count: 10,
2008 selectable_floating_panes_count: 10,
2009 },
2010 TabInfo::default(),
2011 ];
2012 let mut panes = HashMap::new();
2013 let mut index_in_pane_group_1 = BTreeMap::new();
2014 index_in_pane_group_1.insert(1, 0);
2015 index_in_pane_group_1.insert(2, 0);
2016 index_in_pane_group_1.insert(3, 0);
2017 let mut index_in_pane_group_2 = BTreeMap::new();
2018 index_in_pane_group_2.insert(1, 1);
2019 index_in_pane_group_2.insert(2, 1);
2020 index_in_pane_group_2.insert(3, 1);
2021 let panes_list = vec![
2022 PaneInfo {
2023 id: 1,
2024 is_plugin: false,
2025 is_focused: true,
2026 is_fullscreen: true,
2027 is_floating: false,
2028 is_suppressed: false,
2029 title: "pane 1".to_owned(),
2030 exited: false,
2031 exit_status: None,
2032 is_held: false,
2033 pane_x: 0,
2034 pane_content_x: 1,
2035 pane_y: 0,
2036 pane_content_y: 1,
2037 pane_rows: 5,
2038 pane_content_rows: 4,
2039 pane_columns: 22,
2040 pane_content_columns: 21,
2041 cursor_coordinates_in_pane: Some((0, 0)),
2042 terminal_command: Some("foo".to_owned()),
2043 plugin_url: None,
2044 is_selectable: true,
2045 index_in_pane_group: index_in_pane_group_1,
2046 },
2047 PaneInfo {
2048 id: 1,
2049 is_plugin: true,
2050 is_focused: true,
2051 is_fullscreen: true,
2052 is_floating: false,
2053 is_suppressed: false,
2054 title: "pane 1".to_owned(),
2055 exited: false,
2056 exit_status: None,
2057 is_held: false,
2058 pane_x: 0,
2059 pane_content_x: 1,
2060 pane_y: 0,
2061 pane_content_y: 1,
2062 pane_rows: 5,
2063 pane_content_rows: 4,
2064 pane_columns: 22,
2065 pane_content_columns: 21,
2066 cursor_coordinates_in_pane: Some((0, 0)),
2067 terminal_command: None,
2068 plugin_url: Some("i_am_a_fake_plugin".to_owned()),
2069 is_selectable: true,
2070 index_in_pane_group: index_in_pane_group_2,
2071 },
2072 ];
2073 panes.insert(0, panes_list);
2074 let mut plugins = BTreeMap::new();
2075 let mut plugin_configuration = BTreeMap::new();
2076 plugin_configuration.insert("config_key".to_owned(), "config_value".to_owned());
2077 plugins.insert(
2078 1,
2079 PluginInfo {
2080 location: "https://example.com/my-plugin.wasm".to_owned(),
2081 configuration: plugin_configuration,
2082 },
2083 );
2084 let mut tab_history = BTreeMap::new();
2085 tab_history.insert(1, vec![1, 2, 3]);
2086 tab_history.insert(2, vec![1, 2, 3]);
2087 let session_info_1 = SessionInfo {
2088 name: "session 1".to_owned(),
2089 tabs: tab_infos,
2090 panes: PaneManifest { panes },
2091 connected_clients: 2,
2092 is_current_session: true,
2093 available_layouts: vec![
2094 LayoutInfo::File("layout 1".to_owned()),
2095 LayoutInfo::BuiltIn("layout2".to_owned()),
2096 LayoutInfo::File("layout3".to_owned()),
2097 ],
2098 plugins,
2099 web_clients_allowed: false,
2100 web_client_count: 1,
2101 tab_history,
2102 };
2103 let session_info_2 = SessionInfo {
2104 name: "session 2".to_owned(),
2105 tabs: vec![],
2106 panes: PaneManifest {
2107 panes: HashMap::new(),
2108 },
2109 connected_clients: 0,
2110 is_current_session: false,
2111 available_layouts: vec![
2112 LayoutInfo::File("layout 1".to_owned()),
2113 LayoutInfo::BuiltIn("layout2".to_owned()),
2114 LayoutInfo::File("layout3".to_owned()),
2115 ],
2116 plugins: Default::default(),
2117 web_clients_allowed: false,
2118 web_client_count: 0,
2119 tab_history: Default::default(),
2120 };
2121 let session_infos = vec![session_info_1, session_info_2];
2122 let resurrectable_sessions = vec![];
2123
2124 let session_update_event = Event::SessionUpdate(session_infos, resurrectable_sessions);
2125 let protobuf_event: ProtobufEvent = session_update_event.clone().try_into().unwrap();
2126 let serialized_protobuf_event = protobuf_event.encode_to_vec();
2127 let deserialized_protobuf_event: ProtobufEvent =
2128 Message::decode(serialized_protobuf_event.as_slice()).unwrap();
2129 let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
2130 assert_eq!(
2131 session_update_event, deserialized_event,
2132 "Event properly serialized/deserialized without change"
2133 );
2134}
2135
2136impl TryFrom<ProtobufPaneId> for PaneId {
2140 type Error = &'static str;
2141 fn try_from(protobuf_pane_id: ProtobufPaneId) -> Result<Self, &'static str> {
2142 match ProtobufPaneType::from_i32(protobuf_pane_id.pane_type) {
2143 Some(ProtobufPaneType::Terminal) => Ok(PaneId::Terminal(protobuf_pane_id.id)),
2144 Some(ProtobufPaneType::Plugin) => Ok(PaneId::Plugin(protobuf_pane_id.id)),
2145 None => Err("Failed to convert PaneId"),
2146 }
2147 }
2148}
2149
2150impl TryFrom<PaneId> for ProtobufPaneId {
2154 type Error = &'static str;
2155 fn try_from(pane_id: PaneId) -> Result<Self, &'static str> {
2156 match pane_id {
2157 PaneId::Terminal(id) => Ok(ProtobufPaneId {
2158 pane_type: ProtobufPaneType::Terminal as i32,
2159 id,
2160 }),
2161 PaneId::Plugin(id) => Ok(ProtobufPaneId {
2162 pane_type: ProtobufPaneType::Plugin as i32,
2163 id,
2164 }),
2165 }
2166 }
2167}
2168
2169impl Into<ProtobufWebSharing> for WebSharing {
2170 fn into(self) -> ProtobufWebSharing {
2171 match self {
2172 WebSharing::On => ProtobufWebSharing::On,
2173 WebSharing::Off => ProtobufWebSharing::Off,
2174 WebSharing::Disabled => ProtobufWebSharing::Disabled,
2175 }
2176 }
2177}
2178
2179impl Into<WebSharing> for ProtobufWebSharing {
2180 fn into(self) -> WebSharing {
2181 match self {
2182 ProtobufWebSharing::On => WebSharing::On,
2183 ProtobufWebSharing::Off => WebSharing::Off,
2184 ProtobufWebSharing::Disabled => WebSharing::Disabled,
2185 }
2186 }
2187}
2188
2189impl TryFrom<WebServerStatus> for ProtobufWebServerStatusPayload {
2190 type Error = &'static str;
2191 fn try_from(web_server_status: WebServerStatus) -> Result<Self, &'static str> {
2192 match web_server_status {
2193 WebServerStatus::Online(url) => Ok(ProtobufWebServerStatusPayload {
2194 web_server_status_indication: WebServerStatusIndication::Online as i32,
2195 payload: Some(url),
2196 }),
2197 WebServerStatus::DifferentVersion(version) => Ok(ProtobufWebServerStatusPayload {
2198 web_server_status_indication: WebServerStatusIndication::DifferentVersion as i32,
2199 payload: Some(format!("{}", version)),
2200 }),
2201 WebServerStatus::Offline => Ok(ProtobufWebServerStatusPayload {
2202 web_server_status_indication: WebServerStatusIndication::Offline as i32,
2203 payload: None,
2204 }),
2205 }
2206 }
2207}
2208
2209impl TryFrom<ProtobufWebServerStatusPayload> for WebServerStatus {
2210 type Error = &'static str;
2211 fn try_from(
2212 protobuf_web_server_status: ProtobufWebServerStatusPayload,
2213 ) -> Result<Self, &'static str> {
2214 match WebServerStatusIndication::from_i32(
2215 protobuf_web_server_status.web_server_status_indication,
2216 ) {
2217 Some(WebServerStatusIndication::Online) => {
2218 let payload = protobuf_web_server_status
2219 .payload
2220 .ok_or("payload_not_found")?;
2221 Ok(WebServerStatus::Online(payload))
2222 },
2223 Some(WebServerStatusIndication::DifferentVersion) => {
2224 let payload = protobuf_web_server_status
2225 .payload
2226 .ok_or("payload_not_found")?;
2227 Ok(WebServerStatus::DifferentVersion(payload))
2228 },
2229 Some(WebServerStatusIndication::Offline) => Ok(WebServerStatus::Offline),
2230 None => Err("Unknown status"),
2231 }
2232 }
2233}