1use serde::de::{self, MapAccess, SeqAccess, Visitor};
2use serde::{Deserialize, Deserializer, Serialize};
3use std::path::PathBuf;
4
5use crate::{ProcessCommand, SessionName, WindowTarget};
6
7use super::compat::compat_next_element;
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11pub struct NewWindowRequest {
12 pub target: SessionName,
14 pub name: Option<String>,
16 pub detached: bool,
18 #[serde(default)]
20 pub environment: Option<Vec<String>>,
21 #[serde(default)]
23 pub command: Option<Vec<String>>,
24 #[serde(default)]
26 pub start_directory: Option<PathBuf>,
27 #[serde(default)]
29 pub target_window_index: Option<u32>,
30 #[serde(default)]
32 pub insert_at_target: bool,
33 #[serde(default)]
35 pub process_command: Option<ProcessCommand>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct KillWindowRequest {
41 pub target: WindowTarget,
43 pub kill_all_others: bool,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct SelectWindowRequest {
50 pub target: WindowTarget,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56pub struct RenameWindowRequest {
57 pub target: WindowTarget,
59 pub name: String,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65pub struct NextWindowRequest {
66 pub target: SessionName,
68 #[serde(default)]
70 pub alerts_only: bool,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub struct PreviousWindowRequest {
76 pub target: SessionName,
78 #[serde(default)]
80 pub alerts_only: bool,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85pub struct LastWindowRequest {
86 pub target: SessionName,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92pub struct ListWindowsRequest {
93 pub target: SessionName,
95 pub format: Option<String>,
97 #[serde(default)]
99 pub filter: Option<String>,
100 #[serde(default)]
102 pub sort_order: Option<String>,
103 #[serde(default)]
105 pub reversed: bool,
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub struct LinkWindowRequest {
111 pub source: WindowTarget,
113 pub target: WindowTarget,
115 #[serde(default)]
117 pub after: bool,
118 #[serde(default)]
120 pub before: bool,
121 #[serde(default)]
123 pub kill_destination: bool,
124 #[serde(default)]
126 pub detached: bool,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub enum MoveWindowTarget {
132 Session(SessionName),
134 Window(WindowTarget),
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
140pub struct MoveWindowRequest {
141 pub source: Option<WindowTarget>,
143 pub target: MoveWindowTarget,
145 pub renumber: bool,
147 pub kill_destination: bool,
149 pub detached: bool,
151 #[serde(default)]
153 pub after: bool,
154 #[serde(default)]
156 pub before: bool,
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub struct SwapWindowRequest {
162 pub source: WindowTarget,
164 pub target: WindowTarget,
166 pub detached: bool,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
172pub enum RotateWindowDirection {
173 Down,
175 Up,
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
181pub struct RotateWindowRequest {
182 pub target: WindowTarget,
184 pub direction: RotateWindowDirection,
186 #[serde(default)]
188 pub restore_zoom: bool,
189}
190
191#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
193pub struct ResizeWindowRequest {
194 pub target: WindowTarget,
196 pub width: Option<u16>,
198 pub height: Option<u16>,
200 #[serde(default)]
202 pub adjustment: Option<ResizeWindowAdjustment>,
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
207pub enum ResizeWindowAdjustment {
208 Up(u16),
210 Down(u16),
212 Left(u16),
214 Right(u16),
216 LargestLinkedSession,
218 SmallestLinkedSession,
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
224pub struct RespawnWindowRequest {
225 pub target: WindowTarget,
227 #[serde(default)]
229 pub kill: bool,
230 #[serde(default)]
232 pub environment: Option<Vec<String>>,
233 #[serde(default)]
235 pub command: Option<Vec<String>>,
236 #[serde(default)]
238 pub start_directory: Option<PathBuf>,
239}
240
241impl<'de> Deserialize<'de> for NewWindowRequest {
242 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
243 where
244 D: Deserializer<'de>,
245 {
246 deserializer.deserialize_struct(
247 "NewWindowRequest",
248 &[
249 "target",
250 "name",
251 "detached",
252 "environment",
253 "command",
254 "start_directory",
255 "target_window_index",
256 "insert_at_target",
257 "process_command",
258 ],
259 NewWindowRequestVisitor,
260 )
261 }
262}
263
264impl<'de> Deserialize<'de> for RespawnWindowRequest {
265 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
266 where
267 D: Deserializer<'de>,
268 {
269 deserializer.deserialize_struct(
270 "RespawnWindowRequest",
271 &[
272 "target",
273 "kill",
274 "environment",
275 "command",
276 "start_directory",
277 ],
278 RespawnWindowRequestVisitor,
279 )
280 }
281}
282
283impl<'de> Deserialize<'de> for MoveWindowRequest {
284 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
285 where
286 D: Deserializer<'de>,
287 {
288 deserializer.deserialize_struct(
289 "MoveWindowRequest",
290 &[
291 "source",
292 "target",
293 "renumber",
294 "kill_destination",
295 "detached",
296 "after",
297 "before",
298 ],
299 MoveWindowRequestVisitor,
300 )
301 }
302}
303
304struct NewWindowRequestVisitor;
305
306struct MoveWindowRequestVisitor;
307
308impl<'de> Visitor<'de> for NewWindowRequestVisitor {
309 type Value = NewWindowRequest;
310
311 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 formatter.write_str("a new-window request")
313 }
314
315 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
316 where
317 A: SeqAccess<'de>,
318 {
319 let target = seq
320 .next_element()?
321 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
322 let name = seq
323 .next_element()?
324 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
325 let detached = seq
326 .next_element()?
327 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
328 let environment = seq
329 .next_element()?
330 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
331 let command = compat_next_element(&mut seq)?;
332 let start_directory = compat_next_element(&mut seq)?;
333 let target_window_index = compat_next_element(&mut seq)?;
334 let insert_at_target = compat_next_element(&mut seq)?;
335 let process_command = compat_next_element(&mut seq)?;
336
337 Ok(NewWindowRequest {
338 target,
339 name,
340 detached,
341 environment,
342 command,
343 start_directory,
344 target_window_index,
345 insert_at_target,
346 process_command,
347 })
348 }
349
350 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
351 where
352 A: MapAccess<'de>,
353 {
354 let mut target = None;
355 let mut name = None;
356 let mut detached = None;
357 let mut environment = None;
358 let mut command = None;
359 let mut process_command = None;
360 let mut start_directory = None;
361 let mut target_window_index = None;
362 let mut insert_at_target = None;
363
364 while let Some(key) = map.next_key::<String>()? {
365 match key.as_str() {
366 "target" => target = Some(map.next_value()?),
367 "name" => name = Some(map.next_value()?),
368 "detached" => detached = Some(map.next_value()?),
369 "environment" => environment = Some(map.next_value()?),
370 "command" => command = Some(map.next_value()?),
371 "process_command" => process_command = Some(map.next_value()?),
372 "start_directory" => start_directory = Some(map.next_value()?),
373 "target_window_index" => target_window_index = Some(map.next_value()?),
374 "insert_at_target" => insert_at_target = Some(map.next_value()?),
375 _ => {
376 let _: de::IgnoredAny = map.next_value()?;
377 }
378 }
379 }
380
381 Ok(NewWindowRequest {
382 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
383 name: name.unwrap_or_default(),
384 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
385 environment: environment.unwrap_or_default(),
386 command: command.unwrap_or_default(),
387 process_command: process_command.unwrap_or_default(),
388 start_directory: start_directory.unwrap_or_default(),
389 target_window_index: target_window_index.unwrap_or_default(),
390 insert_at_target: insert_at_target.unwrap_or_default(),
391 })
392 }
393}
394
395impl<'de> Visitor<'de> for MoveWindowRequestVisitor {
396 type Value = MoveWindowRequest;
397
398 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399 formatter.write_str("a move-window request")
400 }
401
402 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
403 where
404 A: SeqAccess<'de>,
405 {
406 let source = seq
407 .next_element()?
408 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
409 let target = seq
410 .next_element()?
411 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
412 let renumber = seq
413 .next_element()?
414 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
415 let kill_destination = seq
416 .next_element()?
417 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
418 let detached = seq
419 .next_element()?
420 .ok_or_else(|| de::Error::invalid_length(4, &self))?;
421 let after = compat_next_element(&mut seq)?;
422 let before = compat_next_element(&mut seq)?;
423
424 Ok(MoveWindowRequest {
425 source,
426 target,
427 renumber,
428 kill_destination,
429 detached,
430 after,
431 before,
432 })
433 }
434
435 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
436 where
437 A: MapAccess<'de>,
438 {
439 let mut source = None;
440 let mut target = None;
441 let mut renumber = None;
442 let mut kill_destination = None;
443 let mut detached = None;
444 let mut after = None;
445 let mut before = None;
446
447 while let Some(key) = map.next_key::<String>()? {
448 match key.as_str() {
449 "source" => source = Some(map.next_value()?),
450 "target" => target = Some(map.next_value()?),
451 "renumber" => renumber = Some(map.next_value()?),
452 "kill_destination" => kill_destination = Some(map.next_value()?),
453 "detached" => detached = Some(map.next_value()?),
454 "after" => after = Some(map.next_value()?),
455 "before" => before = Some(map.next_value()?),
456 _ => {
457 let _: de::IgnoredAny = map.next_value()?;
458 }
459 }
460 }
461
462 Ok(MoveWindowRequest {
463 source: source.unwrap_or_default(),
464 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
465 renumber: renumber.ok_or_else(|| de::Error::missing_field("renumber"))?,
466 kill_destination: kill_destination
467 .ok_or_else(|| de::Error::missing_field("kill_destination"))?,
468 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
469 after: after.unwrap_or_default(),
470 before: before.unwrap_or_default(),
471 })
472 }
473}
474
475struct RespawnWindowRequestVisitor;
476
477impl<'de> Visitor<'de> for RespawnWindowRequestVisitor {
478 type Value = RespawnWindowRequest;
479
480 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
481 formatter.write_str("a respawn-window request")
482 }
483
484 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
485 where
486 A: SeqAccess<'de>,
487 {
488 let target = seq
489 .next_element()?
490 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
491 let kill = seq
492 .next_element()?
493 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
494 let environment = seq
495 .next_element()?
496 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
497 let command = compat_next_element(&mut seq)?;
498 let start_directory = compat_next_element(&mut seq)?;
499
500 Ok(RespawnWindowRequest {
501 target,
502 kill,
503 environment,
504 command,
505 start_directory,
506 })
507 }
508
509 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
510 where
511 A: MapAccess<'de>,
512 {
513 let mut target = None;
514 let mut kill = None;
515 let mut environment = None;
516 let mut command = None;
517 let mut start_directory = None;
518
519 while let Some(key) = map.next_key::<String>()? {
520 match key.as_str() {
521 "target" => target = Some(map.next_value()?),
522 "kill" => kill = Some(map.next_value()?),
523 "environment" => environment = Some(map.next_value()?),
524 "command" => command = Some(map.next_value()?),
525 "start_directory" => start_directory = Some(map.next_value()?),
526 _ => {
527 let _: de::IgnoredAny = map.next_value()?;
528 }
529 }
530 }
531
532 Ok(RespawnWindowRequest {
533 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
534 kill: kill.unwrap_or_default(),
535 environment: environment.unwrap_or_default(),
536 command: command.unwrap_or_default(),
537 start_directory: start_directory.unwrap_or_default(),
538 })
539 }
540}