kitty_rc/commands/
layout.rs1use crate::command::CommandBuilder;
2use crate::error::CommandError;
3use crate::protocol::KittyMessage;
4
5pub struct GotoLayoutCommand {
6 layout: String,
7 match_spec: Option<String>,
8}
9
10impl GotoLayoutCommand {
11 pub fn new(layout: impl Into<String>) -> Self {
12 Self {
13 layout: layout.into(),
14 match_spec: None,
15 }
16 }
17
18 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
19 self.match_spec = Some(spec.into());
20 self
21 }
22
23 pub fn build(self) -> Result<KittyMessage, CommandError> {
24 let mut payload = serde_json::Map::new();
25
26 if self.layout.is_empty() {
27 return Err(CommandError::MissingParameter(
28 "layout".to_string(),
29 "goto-layout".to_string(),
30 ));
31 }
32
33 payload.insert("layout".to_string(), serde_json::Value::String(self.layout));
34
35 if let Some(match_spec) = self.match_spec {
36 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
37 }
38
39 Ok(CommandBuilder::new("goto-layout")
40 .payload(serde_json::Value::Object(payload))
41 .build())
42 }
43}
44
45pub struct SetEnabledLayoutsCommand {
46 layouts: Vec<String>,
47 match_spec: Option<String>,
48 configured: bool,
49}
50
51impl SetEnabledLayoutsCommand {
52 pub fn new(layouts: Vec<String>) -> Self {
53 Self {
54 layouts,
55 match_spec: None,
56 configured: false,
57 }
58 }
59
60 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
61 self.match_spec = Some(spec.into());
62 self
63 }
64
65 pub fn configured(mut self, value: bool) -> Self {
66 self.configured = value;
67 self
68 }
69
70 pub fn build(self) -> Result<KittyMessage, CommandError> {
71 let mut payload = serde_json::Map::new();
72
73 if self.layouts.is_empty() {
74 return Err(CommandError::MissingParameter(
75 "layouts".to_string(),
76 "set-enabled-layouts".to_string(),
77 ));
78 }
79
80 let layouts_value: Vec<serde_json::Value> = self
81 .layouts
82 .into_iter()
83 .map(serde_json::Value::String)
84 .collect();
85
86 payload.insert(
87 "layouts".to_string(),
88 serde_json::Value::Array(layouts_value),
89 );
90
91 if let Some(match_spec) = self.match_spec {
92 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
93 }
94
95 if self.configured {
96 payload.insert("configured".to_string(), serde_json::Value::Bool(true));
97 }
98
99 Ok(CommandBuilder::new("set-enabled-layouts")
100 .payload(serde_json::Value::Object(payload))
101 .build())
102 }
103}
104
105pub struct LastUsedLayoutCommand {
106 match_spec: Option<String>,
107 all: bool,
108}
109
110impl LastUsedLayoutCommand {
111 pub fn new() -> Self {
112 Self {
113 match_spec: None,
114 all: false,
115 }
116 }
117
118 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
119 self.match_spec = Some(spec.into());
120 self
121 }
122
123 pub fn all(mut self, value: bool) -> Self {
124 self.all = value;
125 self
126 }
127
128 pub fn build(self) -> Result<KittyMessage, CommandError> {
129 let mut payload = serde_json::Map::new();
130
131 if let Some(match_spec) = self.match_spec {
132 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
133 }
134
135 if self.all {
136 payload.insert("all".to_string(), serde_json::Value::Bool(true));
137 }
138
139 Ok(CommandBuilder::new("last-used-layout")
140 .payload(serde_json::Value::Object(payload))
141 .build())
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn test_goto_layout() {
151 let cmd = GotoLayoutCommand::new("tall").build();
152 assert!(cmd.is_ok());
153 let msg = cmd.unwrap();
154 assert_eq!(msg.cmd, "goto-layout");
155 assert!(msg.payload.is_some());
156 }
157
158 #[test]
159 fn test_goto_layout_empty() {
160 let cmd = GotoLayoutCommand::new("").build();
161 assert!(cmd.is_err());
162 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
163 assert_eq!(field, "layout");
164 assert_eq!(cmd_name, "goto-layout");
165 } else {
166 panic!("Expected MissingParameter error");
167 }
168 }
169
170 #[test]
171 fn test_goto_layout_with_match() {
172 let cmd = GotoLayoutCommand::new("grid").match_spec("id:0").build();
173 assert!(cmd.is_ok());
174 let msg = cmd.unwrap();
175 assert_eq!(msg.cmd, "goto-layout");
176 }
177
178 #[test]
179 fn test_set_enabled_layouts() {
180 let layouts = vec!["tall".to_string(), "grid".to_string()];
181 let cmd = SetEnabledLayoutsCommand::new(layouts).build();
182 assert!(cmd.is_ok());
183 let msg = cmd.unwrap();
184 assert_eq!(msg.cmd, "set-enabled-layouts");
185 assert!(msg.payload.is_some());
186 }
187
188 #[test]
189 fn test_set_enabled_layouts_empty() {
190 let cmd = SetEnabledLayoutsCommand::new(vec![]).build();
191 assert!(cmd.is_err());
192 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
193 assert_eq!(field, "layouts");
194 assert_eq!(cmd_name, "set-enabled-layouts");
195 } else {
196 panic!("Expected MissingParameter error");
197 }
198 }
199
200 #[test]
201 fn test_set_enabled_layouts_with_match() {
202 let layouts = vec!["stack".to_string()];
203 let cmd = SetEnabledLayoutsCommand::new(layouts)
204 .match_spec("id:1")
205 .build();
206 assert!(cmd.is_ok());
207 let msg = cmd.unwrap();
208 assert_eq!(msg.cmd, "set-enabled-layouts");
209 }
210
211 #[test]
212 fn test_set_enabled_layouts_configured() {
213 let layouts = vec!["tall".to_string()];
214 let cmd = SetEnabledLayoutsCommand::new(layouts)
215 .configured(true)
216 .build();
217 assert!(cmd.is_ok());
218 let msg = cmd.unwrap();
219 assert_eq!(msg.cmd, "set-enabled-layouts");
220 }
221
222 #[test]
223 fn test_last_used_layout() {
224 let cmd = LastUsedLayoutCommand::new().build();
225 assert!(cmd.is_ok());
226 let msg = cmd.unwrap();
227 assert_eq!(msg.cmd, "last-used-layout");
228 }
229
230 #[test]
231 fn test_last_used_layout_with_match() {
232 let cmd = LastUsedLayoutCommand::new().match_spec("id:0").build();
233 assert!(cmd.is_ok());
234 let msg = cmd.unwrap();
235 assert_eq!(msg.cmd, "last-used-layout");
236 }
237
238 #[test]
239 fn test_last_used_layout_all() {
240 let cmd = LastUsedLayoutCommand::new().all(true).build();
241 assert!(cmd.is_ok());
242 let msg = cmd.unwrap();
243 assert_eq!(msg.cmd, "last-used-layout");
244 }
245}