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, Deserialize)]
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}
143
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146pub struct SwapWindowRequest {
147 pub source: WindowTarget,
149 pub target: WindowTarget,
151 pub detached: bool,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
157pub enum RotateWindowDirection {
158 Down,
160 Up,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
166pub struct RotateWindowRequest {
167 pub target: WindowTarget,
169 pub direction: RotateWindowDirection,
171 #[serde(default)]
173 pub restore_zoom: bool,
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
178pub struct ResizeWindowRequest {
179 pub target: WindowTarget,
181 pub width: Option<u16>,
183 pub height: Option<u16>,
185 #[serde(default)]
187 pub adjustment: Option<ResizeWindowAdjustment>,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
192pub enum ResizeWindowAdjustment {
193 Up(u16),
195 Down(u16),
197 Left(u16),
199 Right(u16),
201}
202
203#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
205pub struct RespawnWindowRequest {
206 pub target: WindowTarget,
208 #[serde(default)]
210 pub kill: bool,
211 #[serde(default)]
213 pub environment: Option<Vec<String>>,
214 #[serde(default)]
216 pub command: Option<Vec<String>>,
217 #[serde(default)]
219 pub start_directory: Option<PathBuf>,
220}
221
222impl<'de> Deserialize<'de> for NewWindowRequest {
223 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
224 where
225 D: Deserializer<'de>,
226 {
227 deserializer.deserialize_struct(
228 "NewWindowRequest",
229 &[
230 "target",
231 "name",
232 "detached",
233 "environment",
234 "command",
235 "start_directory",
236 "target_window_index",
237 "insert_at_target",
238 "process_command",
239 ],
240 NewWindowRequestVisitor,
241 )
242 }
243}
244
245impl<'de> Deserialize<'de> for RespawnWindowRequest {
246 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
247 where
248 D: Deserializer<'de>,
249 {
250 deserializer.deserialize_struct(
251 "RespawnWindowRequest",
252 &[
253 "target",
254 "kill",
255 "environment",
256 "command",
257 "start_directory",
258 ],
259 RespawnWindowRequestVisitor,
260 )
261 }
262}
263
264struct NewWindowRequestVisitor;
265
266impl<'de> Visitor<'de> for NewWindowRequestVisitor {
267 type Value = NewWindowRequest;
268
269 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 formatter.write_str("a new-window request")
271 }
272
273 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
274 where
275 A: SeqAccess<'de>,
276 {
277 let target = seq
278 .next_element()?
279 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
280 let name = seq
281 .next_element()?
282 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
283 let detached = seq
284 .next_element()?
285 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
286 let environment = seq
287 .next_element()?
288 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
289 let command = compat_next_element(&mut seq)?;
290 let start_directory = compat_next_element(&mut seq)?;
291 let target_window_index = compat_next_element(&mut seq)?;
292 let insert_at_target = compat_next_element(&mut seq)?;
293 let process_command = compat_next_element(&mut seq)?;
294
295 Ok(NewWindowRequest {
296 target,
297 name,
298 detached,
299 environment,
300 command,
301 start_directory,
302 target_window_index,
303 insert_at_target,
304 process_command,
305 })
306 }
307
308 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
309 where
310 A: MapAccess<'de>,
311 {
312 let mut target = None;
313 let mut name = None;
314 let mut detached = None;
315 let mut environment = None;
316 let mut command = None;
317 let mut process_command = None;
318 let mut start_directory = None;
319 let mut target_window_index = None;
320 let mut insert_at_target = None;
321
322 while let Some(key) = map.next_key::<String>()? {
323 match key.as_str() {
324 "target" => target = Some(map.next_value()?),
325 "name" => name = Some(map.next_value()?),
326 "detached" => detached = Some(map.next_value()?),
327 "environment" => environment = Some(map.next_value()?),
328 "command" => command = Some(map.next_value()?),
329 "process_command" => process_command = Some(map.next_value()?),
330 "start_directory" => start_directory = Some(map.next_value()?),
331 "target_window_index" => target_window_index = Some(map.next_value()?),
332 "insert_at_target" => insert_at_target = Some(map.next_value()?),
333 _ => {
334 let _: de::IgnoredAny = map.next_value()?;
335 }
336 }
337 }
338
339 Ok(NewWindowRequest {
340 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
341 name: name.ok_or_else(|| de::Error::missing_field("name"))?,
342 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
343 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
344 command: command.unwrap_or_default(),
345 process_command: process_command.unwrap_or_default(),
346 start_directory: start_directory.unwrap_or_default(),
347 target_window_index: target_window_index.unwrap_or_default(),
348 insert_at_target: insert_at_target.unwrap_or_default(),
349 })
350 }
351}
352
353struct RespawnWindowRequestVisitor;
354
355impl<'de> Visitor<'de> for RespawnWindowRequestVisitor {
356 type Value = RespawnWindowRequest;
357
358 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359 formatter.write_str("a respawn-window request")
360 }
361
362 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
363 where
364 A: SeqAccess<'de>,
365 {
366 let target = seq
367 .next_element()?
368 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
369 let kill = seq
370 .next_element()?
371 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
372 let environment = seq
373 .next_element()?
374 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
375 let command = compat_next_element(&mut seq)?;
376 let start_directory = compat_next_element(&mut seq)?;
377
378 Ok(RespawnWindowRequest {
379 target,
380 kill,
381 environment,
382 command,
383 start_directory,
384 })
385 }
386
387 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
388 where
389 A: MapAccess<'de>,
390 {
391 let mut target = None;
392 let mut kill = None;
393 let mut environment = None;
394 let mut command = None;
395 let mut start_directory = None;
396
397 while let Some(key) = map.next_key::<String>()? {
398 match key.as_str() {
399 "target" => target = Some(map.next_value()?),
400 "kill" => kill = Some(map.next_value()?),
401 "environment" => environment = Some(map.next_value()?),
402 "command" => command = Some(map.next_value()?),
403 "start_directory" => start_directory = Some(map.next_value()?),
404 _ => {
405 let _: de::IgnoredAny = map.next_value()?;
406 }
407 }
408 }
409
410 Ok(RespawnWindowRequest {
411 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
412 kill: kill.ok_or_else(|| de::Error::missing_field("kill"))?,
413 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
414 command: command.unwrap_or_default(),
415 start_directory: start_directory.unwrap_or_default(),
416 })
417 }
418}