sway_workspace_manager/
command.rs

1pub enum Position {
2    Prev { cycle: bool },
3    Next { cycle: bool },
4    Start,
5    End,
6    Num { num: usize, extra: bool },
7}
8
9impl Position {
10    pub fn num_existing(
11        &self,
12        current_index: usize,
13        num_workspaces: usize,
14    ) -> Result<usize, swayipc::Error> {
15        let (index, len) = (current_index, num_workspaces);
16
17        match *self {
18            Position::Prev { cycle } => {
19                if index == 1 {
20                    if cycle {
21                        Ok(len)
22                    } else {
23                        Err(swayipc::Error::CommandFailed(
24                            "No previous workspace in the first workspace".to_string(),
25                        ))
26                    }
27                } else {
28                    Ok(index - 1)
29                }
30            }
31
32            Position::Next { cycle } => {
33                if index == len {
34                    if cycle {
35                        Ok(1)
36                    } else {
37                        Err(swayipc::Error::CommandFailed(
38                            "No next workspace in the last workspace".to_string(),
39                        ))
40                    }
41                } else {
42                    Ok(index + 1)
43                }
44            }
45
46            Position::Start => Ok(1),
47
48            Position::End => Ok(len),
49
50            Position::Num { num, extra } => {
51                if 1 <= num && (!extra && num <= len || extra && num <= len + 1) {
52                    Ok(num)
53                } else {
54                    Err(swayipc::Error::CommandFailed(
55                        "Workspace number out of range".to_string(),
56                    ))
57                }
58            }
59        }
60    }
61
62    pub fn num_new(
63        &self,
64        current_index: usize,
65        num_workspaces: usize,
66    ) -> Result<usize, swayipc::Error> {
67        let (index, len) = (current_index, num_workspaces);
68
69        match *self {
70            Position::Prev { cycle: _ } => Ok(index),
71
72            Position::Next { cycle: _ } => Ok(index + 1),
73
74            Position::Start => Ok(1),
75
76            Position::End => Ok(len + 1),
77
78            Position::Num { num, .. } => {
79                if 1 <= num && num <= len + 1 {
80                    Ok(num)
81                } else {
82                    Err(swayipc::Error::CommandFailed(
83                        "Workspace number out of range".to_string(),
84                    ))
85                }
86            }
87        }
88    }
89}
90
91pub enum Command {
92    Reorder { daemon: bool },
93    Switch { target: Position, carry: bool },
94    Create { target: Position, carry: bool },
95    Swap { target: Position },
96    Rename { new_name: String },
97}
98
99impl Command {
100    pub fn new(mut args: impl Iterator<Item = String>) -> Result<Self, &'static str> {
101        args.next();
102
103        let verb = args.next().ok_or("not enough arguments")?;
104
105        if verb.as_str() == "reorder" {
106            let daemon = args.any(|flag| flag.as_str() == "--daemon");
107            return Ok(Self::Reorder { daemon });
108        }
109
110        if verb.as_str() == "rename" {
111            let new_name = args.next().ok_or("not enough argumets")?;
112            return Ok(Self::Rename { new_name });
113        }
114
115        let position = args.next().ok_or("not enough arguments")?;
116
117        let mut cycle = false;
118        let mut extra = false;
119        while let Some(flag) = args.next() {
120            match flag.as_str() {
121                "--cycle" => cycle = true,
122                "--extra" => extra = true,
123                _ => (),
124            };
125        }
126
127        let target = match position.as_str() {
128            "prev" => Ok(Position::Prev { cycle }),
129            "next" => Ok(Position::Next { cycle }),
130            "start" => Ok(Position::Start),
131            "end" => Ok(Position::End),
132            other => other
133                .parse::<usize>()
134                .map(|num| Position::Num { num, extra })
135                .or(Err("invalid target")),
136        }?;
137
138        match verb.as_str() {
139            "switch" => Ok(Self::Switch {
140                target,
141                carry: false,
142            }),
143            "move" => Ok(Self::Switch {
144                target,
145                carry: true,
146            }),
147            "create" => Ok(Self::Create {
148                target,
149                carry: false,
150            }),
151            "move-to-new" => Ok(Self::Create {
152                target,
153                carry: true,
154            }),
155            "swap" => Ok(Self::Swap { target }),
156
157            _ => Err("invalid commnd"),
158        }
159    }
160}