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}
98
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
101pub struct LinkWindowRequest {
102 pub source: WindowTarget,
104 pub target: WindowTarget,
106 #[serde(default)]
108 pub after: bool,
109 #[serde(default)]
111 pub before: bool,
112 #[serde(default)]
114 pub kill_destination: bool,
115 #[serde(default)]
117 pub detached: bool,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
122pub enum MoveWindowTarget {
123 Session(SessionName),
125 Window(WindowTarget),
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
131pub struct MoveWindowRequest {
132 pub source: Option<WindowTarget>,
134 pub target: MoveWindowTarget,
136 pub renumber: bool,
138 pub kill_destination: bool,
140 pub detached: bool,
142 #[serde(default)]
144 pub after: bool,
145 #[serde(default)]
147 pub before: bool,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
152pub struct SwapWindowRequest {
153 pub source: WindowTarget,
155 pub target: WindowTarget,
157 pub detached: bool,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub enum RotateWindowDirection {
164 Down,
166 Up,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172pub struct RotateWindowRequest {
173 pub target: WindowTarget,
175 pub direction: RotateWindowDirection,
177 #[serde(default)]
179 pub restore_zoom: bool,
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
184pub struct ResizeWindowRequest {
185 pub target: WindowTarget,
187 pub width: Option<u16>,
189 pub height: Option<u16>,
191 #[serde(default)]
193 pub adjustment: Option<ResizeWindowAdjustment>,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
198pub enum ResizeWindowAdjustment {
199 Up(u16),
201 Down(u16),
203 Left(u16),
205 Right(u16),
207 LargestLinkedSession,
209 SmallestLinkedSession,
211}
212
213#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
215pub struct RespawnWindowRequest {
216 pub target: WindowTarget,
218 #[serde(default)]
220 pub kill: bool,
221 #[serde(default)]
223 pub environment: Option<Vec<String>>,
224 #[serde(default)]
226 pub command: Option<Vec<String>>,
227 #[serde(default)]
229 pub start_directory: Option<PathBuf>,
230}
231
232impl<'de> Deserialize<'de> for NewWindowRequest {
233 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
234 where
235 D: Deserializer<'de>,
236 {
237 deserializer.deserialize_struct(
238 "NewWindowRequest",
239 &[
240 "target",
241 "name",
242 "detached",
243 "environment",
244 "command",
245 "start_directory",
246 "target_window_index",
247 "insert_at_target",
248 "process_command",
249 ],
250 NewWindowRequestVisitor,
251 )
252 }
253}
254
255impl<'de> Deserialize<'de> for RespawnWindowRequest {
256 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
257 where
258 D: Deserializer<'de>,
259 {
260 deserializer.deserialize_struct(
261 "RespawnWindowRequest",
262 &[
263 "target",
264 "kill",
265 "environment",
266 "command",
267 "start_directory",
268 ],
269 RespawnWindowRequestVisitor,
270 )
271 }
272}
273
274impl<'de> Deserialize<'de> for MoveWindowRequest {
275 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
276 where
277 D: Deserializer<'de>,
278 {
279 deserializer.deserialize_struct(
280 "MoveWindowRequest",
281 &[
282 "source",
283 "target",
284 "renumber",
285 "kill_destination",
286 "detached",
287 "after",
288 "before",
289 ],
290 MoveWindowRequestVisitor,
291 )
292 }
293}
294
295struct NewWindowRequestVisitor;
296
297struct MoveWindowRequestVisitor;
298
299impl<'de> Visitor<'de> for NewWindowRequestVisitor {
300 type Value = NewWindowRequest;
301
302 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 formatter.write_str("a new-window request")
304 }
305
306 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
307 where
308 A: SeqAccess<'de>,
309 {
310 let target = seq
311 .next_element()?
312 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
313 let name = seq
314 .next_element()?
315 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
316 let detached = seq
317 .next_element()?
318 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
319 let environment = seq
320 .next_element()?
321 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
322 let command = compat_next_element(&mut seq)?;
323 let start_directory = compat_next_element(&mut seq)?;
324 let target_window_index = compat_next_element(&mut seq)?;
325 let insert_at_target = compat_next_element(&mut seq)?;
326 let process_command = compat_next_element(&mut seq)?;
327
328 Ok(NewWindowRequest {
329 target,
330 name,
331 detached,
332 environment,
333 command,
334 start_directory,
335 target_window_index,
336 insert_at_target,
337 process_command,
338 })
339 }
340
341 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
342 where
343 A: MapAccess<'de>,
344 {
345 let mut target = None;
346 let mut name = None;
347 let mut detached = None;
348 let mut environment = None;
349 let mut command = None;
350 let mut process_command = None;
351 let mut start_directory = None;
352 let mut target_window_index = None;
353 let mut insert_at_target = None;
354
355 while let Some(key) = map.next_key::<String>()? {
356 match key.as_str() {
357 "target" => target = Some(map.next_value()?),
358 "name" => name = Some(map.next_value()?),
359 "detached" => detached = Some(map.next_value()?),
360 "environment" => environment = Some(map.next_value()?),
361 "command" => command = Some(map.next_value()?),
362 "process_command" => process_command = Some(map.next_value()?),
363 "start_directory" => start_directory = Some(map.next_value()?),
364 "target_window_index" => target_window_index = Some(map.next_value()?),
365 "insert_at_target" => insert_at_target = Some(map.next_value()?),
366 _ => {
367 let _: de::IgnoredAny = map.next_value()?;
368 }
369 }
370 }
371
372 Ok(NewWindowRequest {
373 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
374 name: name.ok_or_else(|| de::Error::missing_field("name"))?,
375 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
376 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
377 command: command.unwrap_or_default(),
378 process_command: process_command.unwrap_or_default(),
379 start_directory: start_directory.unwrap_or_default(),
380 target_window_index: target_window_index.unwrap_or_default(),
381 insert_at_target: insert_at_target.unwrap_or_default(),
382 })
383 }
384}
385
386impl<'de> Visitor<'de> for MoveWindowRequestVisitor {
387 type Value = MoveWindowRequest;
388
389 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
390 formatter.write_str("a move-window request")
391 }
392
393 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
394 where
395 A: SeqAccess<'de>,
396 {
397 let source = seq
398 .next_element()?
399 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
400 let target = seq
401 .next_element()?
402 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
403 let renumber = seq
404 .next_element()?
405 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
406 let kill_destination = seq
407 .next_element()?
408 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
409 let detached = seq
410 .next_element()?
411 .ok_or_else(|| de::Error::invalid_length(4, &self))?;
412 let after = compat_next_element(&mut seq)?;
413 let before = compat_next_element(&mut seq)?;
414
415 Ok(MoveWindowRequest {
416 source,
417 target,
418 renumber,
419 kill_destination,
420 detached,
421 after,
422 before,
423 })
424 }
425
426 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
427 where
428 A: MapAccess<'de>,
429 {
430 let mut source = None;
431 let mut target = None;
432 let mut renumber = None;
433 let mut kill_destination = None;
434 let mut detached = None;
435 let mut after = None;
436 let mut before = None;
437
438 while let Some(key) = map.next_key::<String>()? {
439 match key.as_str() {
440 "source" => source = Some(map.next_value()?),
441 "target" => target = Some(map.next_value()?),
442 "renumber" => renumber = Some(map.next_value()?),
443 "kill_destination" => kill_destination = Some(map.next_value()?),
444 "detached" => detached = Some(map.next_value()?),
445 "after" => after = Some(map.next_value()?),
446 "before" => before = Some(map.next_value()?),
447 _ => {
448 let _: de::IgnoredAny = map.next_value()?;
449 }
450 }
451 }
452
453 Ok(MoveWindowRequest {
454 source: source.ok_or_else(|| de::Error::missing_field("source"))?,
455 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
456 renumber: renumber.ok_or_else(|| de::Error::missing_field("renumber"))?,
457 kill_destination: kill_destination
458 .ok_or_else(|| de::Error::missing_field("kill_destination"))?,
459 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
460 after: after.unwrap_or_default(),
461 before: before.unwrap_or_default(),
462 })
463 }
464}
465
466struct RespawnWindowRequestVisitor;
467
468impl<'de> Visitor<'de> for RespawnWindowRequestVisitor {
469 type Value = RespawnWindowRequest;
470
471 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472 formatter.write_str("a respawn-window request")
473 }
474
475 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
476 where
477 A: SeqAccess<'de>,
478 {
479 let target = seq
480 .next_element()?
481 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
482 let kill = seq
483 .next_element()?
484 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
485 let environment = seq
486 .next_element()?
487 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
488 let command = compat_next_element(&mut seq)?;
489 let start_directory = compat_next_element(&mut seq)?;
490
491 Ok(RespawnWindowRequest {
492 target,
493 kill,
494 environment,
495 command,
496 start_directory,
497 })
498 }
499
500 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
501 where
502 A: MapAccess<'de>,
503 {
504 let mut target = None;
505 let mut kill = None;
506 let mut environment = None;
507 let mut command = None;
508 let mut start_directory = None;
509
510 while let Some(key) = map.next_key::<String>()? {
511 match key.as_str() {
512 "target" => target = Some(map.next_value()?),
513 "kill" => kill = Some(map.next_value()?),
514 "environment" => environment = Some(map.next_value()?),
515 "command" => command = Some(map.next_value()?),
516 "start_directory" => start_directory = Some(map.next_value()?),
517 _ => {
518 let _: de::IgnoredAny = map.next_value()?;
519 }
520 }
521 }
522
523 Ok(RespawnWindowRequest {
524 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
525 kill: kill.ok_or_else(|| de::Error::missing_field("kill"))?,
526 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
527 command: command.unwrap_or_default(),
528 start_directory: start_directory.unwrap_or_default(),
529 })
530 }
531}