1use serde::de::{self, MapAccess, SeqAccess, Visitor};
2use serde::{Deserialize, Deserializer, Serialize};
3use std::path::PathBuf;
4
5use crate::{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}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct KillWindowRequest {
38 pub target: WindowTarget,
40 pub kill_all_others: bool,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct SelectWindowRequest {
47 pub target: WindowTarget,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53pub struct RenameWindowRequest {
54 pub target: WindowTarget,
56 pub name: String,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct NextWindowRequest {
63 pub target: SessionName,
65 #[serde(default)]
67 pub alerts_only: bool,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72pub struct PreviousWindowRequest {
73 pub target: SessionName,
75 #[serde(default)]
77 pub alerts_only: bool,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub struct LastWindowRequest {
83 pub target: SessionName,
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
89pub struct ListWindowsRequest {
90 pub target: SessionName,
92 pub format: Option<String>,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98pub struct LinkWindowRequest {
99 pub source: WindowTarget,
101 pub target: WindowTarget,
103 #[serde(default)]
105 pub after: bool,
106 #[serde(default)]
108 pub before: bool,
109 #[serde(default)]
111 pub kill_destination: bool,
112 #[serde(default)]
114 pub detached: bool,
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
119pub enum MoveWindowTarget {
120 Session(SessionName),
122 Window(WindowTarget),
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
128pub struct MoveWindowRequest {
129 pub source: Option<WindowTarget>,
131 pub target: MoveWindowTarget,
133 pub renumber: bool,
135 pub kill_destination: bool,
137 pub detached: bool,
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
143pub struct SwapWindowRequest {
144 pub source: WindowTarget,
146 pub target: WindowTarget,
148 pub detached: bool,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
154pub enum RotateWindowDirection {
155 Down,
157 Up,
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
163pub struct RotateWindowRequest {
164 pub target: WindowTarget,
166 pub direction: RotateWindowDirection,
168 #[serde(default)]
170 pub restore_zoom: bool,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub struct ResizeWindowRequest {
176 pub target: WindowTarget,
178 pub width: Option<u16>,
180 pub height: Option<u16>,
182 #[serde(default)]
184 pub adjustment: Option<ResizeWindowAdjustment>,
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
189pub enum ResizeWindowAdjustment {
190 Up(u16),
192 Down(u16),
194 Left(u16),
196 Right(u16),
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
202pub struct RespawnWindowRequest {
203 pub target: WindowTarget,
205 #[serde(default)]
207 pub kill: bool,
208 #[serde(default)]
210 pub environment: Option<Vec<String>>,
211 #[serde(default)]
213 pub command: Option<Vec<String>>,
214 #[serde(default)]
216 pub start_directory: Option<PathBuf>,
217}
218
219impl<'de> Deserialize<'de> for NewWindowRequest {
220 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
221 where
222 D: Deserializer<'de>,
223 {
224 deserializer.deserialize_struct(
225 "NewWindowRequest",
226 &[
227 "target",
228 "name",
229 "detached",
230 "environment",
231 "command",
232 "start_directory",
233 "target_window_index",
234 "insert_at_target",
235 ],
236 NewWindowRequestVisitor,
237 )
238 }
239}
240
241impl<'de> Deserialize<'de> for RespawnWindowRequest {
242 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
243 where
244 D: Deserializer<'de>,
245 {
246 deserializer.deserialize_struct(
247 "RespawnWindowRequest",
248 &[
249 "target",
250 "kill",
251 "environment",
252 "command",
253 "start_directory",
254 ],
255 RespawnWindowRequestVisitor,
256 )
257 }
258}
259
260struct NewWindowRequestVisitor;
261
262impl<'de> Visitor<'de> for NewWindowRequestVisitor {
263 type Value = NewWindowRequest;
264
265 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
266 formatter.write_str("a new-window request")
267 }
268
269 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
270 where
271 A: SeqAccess<'de>,
272 {
273 let target = seq
274 .next_element()?
275 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
276 let name = seq
277 .next_element()?
278 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
279 let detached = seq
280 .next_element()?
281 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
282 let environment = seq
283 .next_element()?
284 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
285 let command = compat_next_element(&mut seq)?;
286 let start_directory = compat_next_element(&mut seq)?;
287 let target_window_index = compat_next_element(&mut seq)?;
288 let insert_at_target = compat_next_element(&mut seq)?;
289
290 Ok(NewWindowRequest {
291 target,
292 name,
293 detached,
294 environment,
295 command,
296 start_directory,
297 target_window_index,
298 insert_at_target,
299 })
300 }
301
302 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
303 where
304 A: MapAccess<'de>,
305 {
306 let mut target = None;
307 let mut name = None;
308 let mut detached = None;
309 let mut environment = None;
310 let mut command = None;
311 let mut start_directory = None;
312 let mut target_window_index = None;
313 let mut insert_at_target = None;
314
315 while let Some(key) = map.next_key::<String>()? {
316 match key.as_str() {
317 "target" => target = Some(map.next_value()?),
318 "name" => name = Some(map.next_value()?),
319 "detached" => detached = Some(map.next_value()?),
320 "environment" => environment = Some(map.next_value()?),
321 "command" => command = Some(map.next_value()?),
322 "start_directory" => start_directory = Some(map.next_value()?),
323 "target_window_index" => target_window_index = Some(map.next_value()?),
324 "insert_at_target" => insert_at_target = Some(map.next_value()?),
325 _ => {
326 let _: de::IgnoredAny = map.next_value()?;
327 }
328 }
329 }
330
331 Ok(NewWindowRequest {
332 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
333 name: name.ok_or_else(|| de::Error::missing_field("name"))?,
334 detached: detached.ok_or_else(|| de::Error::missing_field("detached"))?,
335 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
336 command: command.unwrap_or_default(),
337 start_directory: start_directory.unwrap_or_default(),
338 target_window_index: target_window_index.unwrap_or_default(),
339 insert_at_target: insert_at_target.unwrap_or_default(),
340 })
341 }
342}
343
344struct RespawnWindowRequestVisitor;
345
346impl<'de> Visitor<'de> for RespawnWindowRequestVisitor {
347 type Value = RespawnWindowRequest;
348
349 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 formatter.write_str("a respawn-window request")
351 }
352
353 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
354 where
355 A: SeqAccess<'de>,
356 {
357 let target = seq
358 .next_element()?
359 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
360 let kill = seq
361 .next_element()?
362 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
363 let environment = seq
364 .next_element()?
365 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
366 let command = compat_next_element(&mut seq)?;
367 let start_directory = compat_next_element(&mut seq)?;
368
369 Ok(RespawnWindowRequest {
370 target,
371 kill,
372 environment,
373 command,
374 start_directory,
375 })
376 }
377
378 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
379 where
380 A: MapAccess<'de>,
381 {
382 let mut target = None;
383 let mut kill = None;
384 let mut environment = None;
385 let mut command = None;
386 let mut start_directory = None;
387
388 while let Some(key) = map.next_key::<String>()? {
389 match key.as_str() {
390 "target" => target = Some(map.next_value()?),
391 "kill" => kill = Some(map.next_value()?),
392 "environment" => environment = Some(map.next_value()?),
393 "command" => command = Some(map.next_value()?),
394 "start_directory" => start_directory = Some(map.next_value()?),
395 _ => {
396 let _: de::IgnoredAny = map.next_value()?;
397 }
398 }
399 }
400
401 Ok(RespawnWindowRequest {
402 target: target.ok_or_else(|| de::Error::missing_field("target"))?,
403 kill: kill.ok_or_else(|| de::Error::missing_field("kill"))?,
404 environment: environment.ok_or_else(|| de::Error::missing_field("environment"))?,
405 command: command.unwrap_or_default(),
406 start_directory: start_directory.unwrap_or_default(),
407 })
408 }
409}