1use crate::command::CommandBuilder;
2use crate::error::CommandError;
3use crate::protocol::KittyMessage;
4use serde::Deserialize;
5use serde_json::Map;
6
7#[derive(Debug, Deserialize)]
8pub struct ProcessInfo {
9 pub pid: Option<u64>,
10 #[serde(default)]
11 pub cmdline: Vec<String>,
12 pub cwd: Option<String>,
13}
14
15pub struct RunCommand {
16 data: Option<String>,
17 cmdline: Option<String>,
18 env: Option<Map<String, serde_json::Value>>,
19 allow_remote_control: bool,
20 remote_control_password: Option<String>,
21}
22
23impl RunCommand {
24 pub fn new() -> Self {
25 Self {
26 data: None,
27 cmdline: None,
28 env: None,
29 allow_remote_control: false,
30 remote_control_password: None,
31 }
32 }
33
34 pub fn data(mut self, value: impl Into<String>) -> Self {
35 self.data = Some(value.into());
36 self
37 }
38
39 pub fn cmdline(mut self, value: impl Into<String>) -> Self {
40 self.cmdline = Some(value.into());
41 self
42 }
43
44 pub fn env(mut self, value: Map<String, serde_json::Value>) -> Self {
45 self.env = Some(value);
46 self
47 }
48
49 pub fn allow_remote_control(mut self, value: bool) -> Self {
50 self.allow_remote_control = value;
51 self
52 }
53
54 pub fn remote_control_password(mut self, value: impl Into<String>) -> Self {
55 self.remote_control_password = Some(value.into());
56 self
57 }
58
59 pub fn build(self) -> Result<KittyMessage, CommandError> {
60 let mut payload = Map::new();
61
62 if let Some(data) = self.data {
63 payload.insert("data".to_string(), serde_json::Value::String(data));
64 }
65
66 if let Some(cmdline) = self.cmdline {
67 payload.insert("cmdline".to_string(), serde_json::Value::String(cmdline));
68 }
69
70 if let Some(env) = self.env {
71 payload.insert("env".to_string(), serde_json::Value::Object(env));
72 }
73
74 if self.allow_remote_control {
75 payload.insert("allow_remote_control".to_string(), serde_json::Value::Bool(true));
76 }
77
78 if let Some(remote_control_password) = self.remote_control_password {
79 payload.insert("remote_control_password".to_string(), serde_json::Value::String(remote_control_password));
80 }
81
82 Ok(CommandBuilder::new("run")
83 .payload(serde_json::Value::Object(payload))
84 .build())
85 }
86}
87
88pub struct KittenCommand {
89 args: Option<String>,
90 match_spec: Option<String>,
91}
92
93impl KittenCommand {
94 pub fn new() -> Self {
95 Self {
96 args: None,
97 match_spec: None,
98 }
99 }
100
101 pub fn args(mut self, value: impl Into<String>) -> Self {
102 self.args = Some(value.into());
103 self
104 }
105
106 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
107 self.match_spec = Some(spec.into());
108 self
109 }
110
111 pub fn build(self) -> Result<KittyMessage, CommandError> {
112 let mut payload = Map::new();
113
114 if let Some(args) = self.args {
115 payload.insert("args".to_string(), serde_json::Value::String(args));
116 }
117
118 if let Some(match_spec) = self.match_spec {
119 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
120 }
121
122 Ok(CommandBuilder::new("kitten")
123 .payload(serde_json::Value::Object(payload))
124 .build())
125 }
126}
127
128pub struct LaunchCommand {
129 args: Option<String>,
130 window_title: Option<String>,
131 cwd: Option<String>,
132 env: Option<Map<String, serde_json::Value>>,
133 var: Option<Map<String, serde_json::Value>>,
134 tab_title: Option<String>,
135 window_type: Option<String>,
136 keep_focus: bool,
137 copy_colors: bool,
138 copy_cmdline: bool,
139 copy_env: bool,
140 hold: bool,
141 location: Option<String>,
142 allow_remote_control: bool,
143 remote_control_password: Option<String>,
144 stdin_source: Option<String>,
145 stdin_add_formatting: bool,
146 stdin_add_line_wrap_markers: bool,
147 spacing: Option<String>,
148 marker: Option<String>,
149 logo: Option<String>,
150 logo_position: Option<String>,
151 logo_alpha: Option<f32>,
152 self_window: bool,
153 os_window_title: Option<String>,
154 os_window_name: Option<String>,
155 os_window_class: Option<String>,
156 os_window_state: Option<String>,
157 color: Option<String>,
158 watcher: Option<String>,
159 bias: Option<i32>,
160}
161
162impl LaunchCommand {
163 pub fn new() -> Self {
164 Self {
165 args: None,
166 window_title: None,
167 cwd: None,
168 env: None,
169 var: None,
170 tab_title: None,
171 window_type: None,
172 keep_focus: false,
173 copy_colors: false,
174 copy_cmdline: false,
175 copy_env: false,
176 hold: false,
177 location: None,
178 allow_remote_control: false,
179 remote_control_password: None,
180 stdin_source: None,
181 stdin_add_formatting: false,
182 stdin_add_line_wrap_markers: false,
183 spacing: None,
184 marker: None,
185 logo: None,
186 logo_position: None,
187 logo_alpha: None,
188 self_window: false,
189 os_window_title: None,
190 os_window_name: None,
191 os_window_class: None,
192 os_window_state: None,
193 color: None,
194 watcher: None,
195 bias: None,
196 }
197 }
198
199 pub fn args(mut self, value: impl Into<String>) -> Self {
200 self.args = Some(value.into());
201 self
202 }
203
204 pub fn window_title(mut self, value: impl Into<String>) -> Self {
205 self.window_title = Some(value.into());
206 self
207 }
208
209 pub fn cwd(mut self, value: impl Into<String>) -> Self {
210 self.cwd = Some(value.into());
211 self
212 }
213
214 pub fn env(mut self, value: Map<String, serde_json::Value>) -> Self {
215 self.env = Some(value);
216 self
217 }
218
219 pub fn var(mut self, value: Map<String, serde_json::Value>) -> Self {
220 self.var = Some(value);
221 self
222 }
223
224 pub fn tab_title(mut self, value: impl Into<String>) -> Self {
225 self.tab_title = Some(value.into());
226 self
227 }
228
229 pub fn window_type(mut self, value: impl Into<String>) -> Self {
230 self.window_type = Some(value.into());
231 self
232 }
233
234 pub fn keep_focus(mut self, value: bool) -> Self {
235 self.keep_focus = value;
236 self
237 }
238
239 pub fn copy_colors(mut self, value: bool) -> Self {
240 self.copy_colors = value;
241 self
242 }
243
244 pub fn copy_cmdline(mut self, value: bool) -> Self {
245 self.copy_cmdline = value;
246 self
247 }
248
249 pub fn copy_env(mut self, value: bool) -> Self {
250 self.copy_env = value;
251 self
252 }
253
254 pub fn hold(mut self, value: bool) -> Self {
255 self.hold = value;
256 self
257 }
258
259 pub fn location(mut self, value: impl Into<String>) -> Self {
260 self.location = Some(value.into());
261 self
262 }
263
264 pub fn allow_remote_control(mut self, value: bool) -> Self {
265 self.allow_remote_control = value;
266 self
267 }
268
269 pub fn remote_control_password(mut self, value: impl Into<String>) -> Self {
270 self.remote_control_password = Some(value.into());
271 self
272 }
273
274 pub fn stdin_source(mut self, value: impl Into<String>) -> Self {
275 self.stdin_source = Some(value.into());
276 self
277 }
278
279 pub fn stdin_add_formatting(mut self, value: bool) -> Self {
280 self.stdin_add_formatting = value;
281 self
282 }
283
284 pub fn stdin_add_line_wrap_markers(mut self, value: bool) -> Self {
285 self.stdin_add_line_wrap_markers = value;
286 self
287 }
288
289 pub fn spacing(mut self, value: impl Into<String>) -> Self {
290 self.spacing = Some(value.into());
291 self
292 }
293
294 pub fn marker(mut self, value: impl Into<String>) -> Self {
295 self.marker = Some(value.into());
296 self
297 }
298
299 pub fn logo(mut self, value: impl Into<String>) -> Self {
300 self.logo = Some(value.into());
301 self
302 }
303
304 pub fn logo_position(mut self, value: impl Into<String>) -> Self {
305 self.logo_position = Some(value.into());
306 self
307 }
308
309 pub fn logo_alpha(mut self, value: f32) -> Self {
310 self.logo_alpha = Some(value);
311 self
312 }
313
314 pub fn self_window(mut self, value: bool) -> Self {
315 self.self_window = value;
316 self
317 }
318
319 pub fn os_window_title(mut self, value: impl Into<String>) -> Self {
320 self.os_window_title = Some(value.into());
321 self
322 }
323
324 pub fn os_window_name(mut self, value: impl Into<String>) -> Self {
325 self.os_window_name = Some(value.into());
326 self
327 }
328
329 pub fn os_window_class(mut self, value: impl Into<String>) -> Self {
330 self.os_window_class = Some(value.into());
331 self
332 }
333
334 pub fn os_window_state(mut self, value: impl Into<String>) -> Self {
335 self.os_window_state = Some(value.into());
336 self
337 }
338
339 pub fn color(mut self, value: impl Into<String>) -> Self {
340 self.color = Some(value.into());
341 self
342 }
343
344 pub fn watcher(mut self, value: impl Into<String>) -> Self {
345 self.watcher = Some(value.into());
346 self
347 }
348
349 pub fn bias(mut self, value: i32) -> Self {
350 self.bias = Some(value);
351 self
352 }
353
354 pub fn build(self) -> Result<KittyMessage, CommandError> {
355 let mut payload = Map::new();
356
357 if let Some(args) = self.args {
358 payload.insert("args".to_string(), serde_json::Value::String(args));
359 }
360
361 if let Some(window_title) = self.window_title {
362 payload.insert("window_title".to_string(), serde_json::Value::String(window_title));
363 }
364
365 if let Some(cwd) = self.cwd {
366 payload.insert("cwd".to_string(), serde_json::Value::String(cwd));
367 }
368
369 if let Some(env) = self.env {
370 payload.insert("env".to_string(), serde_json::Value::Object(env));
371 }
372
373 if let Some(var) = self.var {
374 payload.insert("var".to_string(), serde_json::Value::Object(var));
375 }
376
377 if let Some(tab_title) = self.tab_title {
378 payload.insert("tab_title".to_string(), serde_json::Value::String(tab_title));
379 }
380
381 if let Some(window_type) = self.window_type {
382 payload.insert("window_type".to_string(), serde_json::Value::String(window_type));
383 }
384
385 if self.keep_focus {
386 payload.insert("keep_focus".to_string(), serde_json::Value::Bool(true));
387 }
388
389 if self.copy_colors {
390 payload.insert("copy_colors".to_string(), serde_json::Value::Bool(true));
391 }
392
393 if self.copy_cmdline {
394 payload.insert("copy_cmdline".to_string(), serde_json::Value::Bool(true));
395 }
396
397 if self.copy_env {
398 payload.insert("copy_env".to_string(), serde_json::Value::Bool(true));
399 }
400
401 if self.hold {
402 payload.insert("hold".to_string(), serde_json::Value::Bool(true));
403 }
404
405 if let Some(location) = self.location {
406 payload.insert("location".to_string(), serde_json::Value::String(location));
407 }
408
409 if self.allow_remote_control {
410 payload.insert("allow_remote_control".to_string(), serde_json::Value::Bool(true));
411 }
412
413 if let Some(remote_control_password) = self.remote_control_password {
414 payload.insert("remote_control_password".to_string(), serde_json::Value::String(remote_control_password));
415 }
416
417 if let Some(stdin_source) = self.stdin_source {
418 payload.insert("stdin_source".to_string(), serde_json::Value::String(stdin_source));
419 }
420
421 if self.stdin_add_formatting {
422 payload.insert("stdin_add_formatting".to_string(), serde_json::Value::Bool(true));
423 }
424
425 if self.stdin_add_line_wrap_markers {
426 payload.insert("stdin_add_line_wrap_markers".to_string(), serde_json::Value::Bool(true));
427 }
428
429 if let Some(spacing) = self.spacing {
430 payload.insert("spacing".to_string(), serde_json::Value::String(spacing));
431 }
432
433 if let Some(marker) = self.marker {
434 payload.insert("marker".to_string(), serde_json::Value::String(marker));
435 }
436
437 if let Some(logo) = self.logo {
438 payload.insert("logo".to_string(), serde_json::Value::String(logo));
439 }
440
441 if let Some(logo_position) = self.logo_position {
442 payload.insert("logo_position".to_string(), serde_json::Value::String(logo_position));
443 }
444
445 if let Some(logo_alpha) = self.logo_alpha {
446 payload.insert("logo_alpha".to_string(), serde_json::json!(logo_alpha));
447 }
448
449 if self.self_window {
450 payload.insert("self".to_string(), serde_json::Value::Bool(true));
451 }
452
453 if let Some(os_window_title) = self.os_window_title {
454 payload.insert("os_window_title".to_string(), serde_json::Value::String(os_window_title));
455 }
456
457 if let Some(os_window_name) = self.os_window_name {
458 payload.insert("os_window_name".to_string(), serde_json::Value::String(os_window_name));
459 }
460
461 if let Some(os_window_class) = self.os_window_class {
462 payload.insert("os_window_class".to_string(), serde_json::Value::String(os_window_class));
463 }
464
465 if let Some(os_window_state) = self.os_window_state {
466 payload.insert("os_window_state".to_string(), serde_json::Value::String(os_window_state));
467 }
468
469 if let Some(color) = self.color {
470 payload.insert("color".to_string(), serde_json::Value::String(color));
471 }
472
473 if let Some(watcher) = self.watcher {
474 payload.insert("watcher".to_string(), serde_json::Value::String(watcher));
475 }
476
477 if let Some(bias) = self.bias {
478 payload.insert("bias".to_string(), serde_json::json!(bias));
479 }
480
481 Ok(CommandBuilder::new("launch")
482 .payload(serde_json::Value::Object(payload))
483 .build())
484 }
485}
486
487pub struct EnvCommand {
488 env: Map<String, serde_json::Value>,
489}
490
491impl EnvCommand {
492 pub fn new(env: Map<String, serde_json::Value>) -> Self {
493 Self { env }
494 }
495
496 pub fn build(self) -> Result<KittyMessage, CommandError> {
497 let mut payload = Map::new();
498
499 if self.env.is_empty() {
500 return Err(CommandError::MissingParameter("env".to_string(), "env".to_string()));
501 }
502
503 payload.insert("env".to_string(), serde_json::Value::Object(self.env));
504
505 Ok(CommandBuilder::new("env")
506 .payload(serde_json::Value::Object(payload))
507 .build())
508 }
509}
510
511pub struct SetUserVarsCommand {
512 var: Vec<String>,
513 match_spec: Option<String>,
514}
515
516impl SetUserVarsCommand {
517 pub fn new(var: Vec<String>) -> Self {
518 Self {
519 var,
520 match_spec: None,
521 }
522 }
523
524 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
525 self.match_spec = Some(spec.into());
526 self
527 }
528
529 pub fn build(self) -> Result<KittyMessage, CommandError> {
530 let mut payload = Map::new();
531
532 if self.var.is_empty() {
533 return Err(CommandError::MissingParameter("var".to_string(), "set-user-vars".to_string()));
534 }
535
536 payload.insert("var".to_string(), serde_json::json!(self.var));
537
538 if let Some(match_spec) = self.match_spec {
539 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
540 }
541
542 Ok(CommandBuilder::new("set-user-vars")
543 .payload(serde_json::Value::Object(payload))
544 .build())
545 }
546}
547
548pub struct LoadConfigCommand {
549 paths: Vec<String>,
550 override_config: bool,
551 ignore_overrides: bool,
552}
553
554impl LoadConfigCommand {
555 pub fn new(paths: Vec<String>) -> Self {
556 Self {
557 paths,
558 override_config: false,
559 ignore_overrides: false,
560 }
561 }
562
563 pub fn override_config(mut self, value: bool) -> Self {
564 self.override_config = value;
565 self
566 }
567
568 pub fn ignore_overrides(mut self, value: bool) -> Self {
569 self.ignore_overrides = value;
570 self
571 }
572
573 pub fn build(self) -> Result<KittyMessage, CommandError> {
574 let mut payload = Map::new();
575
576 if self.paths.is_empty() {
577 return Err(CommandError::MissingParameter("paths".to_string(), "load-config".to_string()));
578 }
579
580 payload.insert("paths".to_string(), serde_json::json!(self.paths));
581
582 if self.override_config {
583 payload.insert("override".to_string(), serde_json::Value::Bool(true));
584 }
585
586 if self.ignore_overrides {
587 payload.insert("ignore_overrides".to_string(), serde_json::Value::Bool(true));
588 }
589
590 Ok(CommandBuilder::new("load-config")
591 .payload(serde_json::Value::Object(payload))
592 .build())
593 }
594}
595
596pub struct ResizeOSWindowCommand {
597 match_spec: Option<String>,
598 self_window: bool,
599 incremental: bool,
600 action: Option<String>,
601 unit: Option<String>,
602 width: Option<i32>,
603 height: Option<i32>,
604}
605
606impl ResizeOSWindowCommand {
607 pub fn new() -> Self {
608 Self {
609 match_spec: None,
610 self_window: false,
611 incremental: false,
612 action: None,
613 unit: None,
614 width: None,
615 height: None,
616 }
617 }
618
619 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
620 self.match_spec = Some(spec.into());
621 self
622 }
623
624 pub fn self_window(mut self, value: bool) -> Self {
625 self.self_window = value;
626 self
627 }
628
629 pub fn incremental(mut self, value: bool) -> Self {
630 self.incremental = value;
631 self
632 }
633
634 pub fn action(mut self, value: impl Into<String>) -> Self {
635 self.action = Some(value.into());
636 self
637 }
638
639 pub fn unit(mut self, value: impl Into<String>) -> Self {
640 self.unit = Some(value.into());
641 self
642 }
643
644 pub fn width(mut self, value: i32) -> Self {
645 self.width = Some(value);
646 self
647 }
648
649 pub fn height(mut self, value: i32) -> Self {
650 self.height = Some(value);
651 self
652 }
653
654 pub fn build(self) -> Result<KittyMessage, CommandError> {
655 let mut payload = Map::new();
656
657 if let Some(match_spec) = self.match_spec {
658 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
659 }
660
661 if self.self_window {
662 payload.insert("self".to_string(), serde_json::Value::Bool(true));
663 }
664
665 if self.incremental {
666 payload.insert("incremental".to_string(), serde_json::Value::Bool(true));
667 }
668
669 if let Some(action) = self.action {
670 payload.insert("action".to_string(), serde_json::Value::String(action));
671 }
672
673 if let Some(unit) = self.unit {
674 payload.insert("unit".to_string(), serde_json::Value::String(unit));
675 }
676
677 if let Some(width) = self.width {
678 payload.insert("width".to_string(), serde_json::json!(width));
679 }
680
681 if let Some(height) = self.height {
682 payload.insert("height".to_string(), serde_json::json!(height));
683 }
684
685 Ok(CommandBuilder::new("resize-os-window")
686 .payload(serde_json::Value::Object(payload))
687 .build())
688 }
689}
690
691pub struct DisableLigaturesCommand {
692 strategy: Option<String>,
693 match_window: Option<String>,
694 match_tab: Option<String>,
695 all: bool,
696}
697
698impl DisableLigaturesCommand {
699 pub fn new() -> Self {
700 Self {
701 strategy: None,
702 match_window: None,
703 match_tab: None,
704 all: false,
705 }
706 }
707
708 pub fn strategy(mut self, value: impl Into<String>) -> Self {
709 self.strategy = Some(value.into());
710 self
711 }
712
713 pub fn match_window(mut self, spec: impl Into<String>) -> Self {
714 self.match_window = Some(spec.into());
715 self
716 }
717
718 pub fn match_tab(mut self, spec: impl Into<String>) -> Self {
719 self.match_tab = Some(spec.into());
720 self
721 }
722
723 pub fn all(mut self, value: bool) -> Self {
724 self.all = value;
725 self
726 }
727
728 pub fn build(self) -> Result<KittyMessage, CommandError> {
729 let mut payload = Map::new();
730
731 if let Some(strategy) = self.strategy {
732 payload.insert("strategy".to_string(), serde_json::Value::String(strategy));
733 }
734
735 if let Some(match_window) = self.match_window {
736 payload.insert("match_window".to_string(), serde_json::Value::String(match_window));
737 }
738
739 if let Some(match_tab) = self.match_tab {
740 payload.insert("match_tab".to_string(), serde_json::Value::String(match_tab));
741 }
742
743 if self.all {
744 payload.insert("all".to_string(), serde_json::Value::Bool(true));
745 }
746
747 Ok(CommandBuilder::new("disable-ligatures")
748 .payload(serde_json::Value::Object(payload))
749 .build())
750 }
751}
752
753pub struct SignalChildCommand {
754 signals: Vec<i32>,
755 match_spec: Option<String>,
756}
757
758impl SignalChildCommand {
759 pub fn new(signals: Vec<i32>) -> Self {
760 Self {
761 signals,
762 match_spec: None,
763 }
764 }
765
766 pub fn match_spec(mut self, spec: impl Into<String>) -> Self {
767 self.match_spec = Some(spec.into());
768 self
769 }
770
771 pub fn build(self) -> Result<KittyMessage, CommandError> {
772 let mut payload = Map::new();
773
774 if self.signals.is_empty() {
775 return Err(CommandError::MissingParameter("signals".to_string(), "signal-child".to_string()));
776 }
777
778 payload.insert("signals".to_string(), serde_json::json!(self.signals));
779
780 if let Some(match_spec) = self.match_spec {
781 payload.insert("match".to_string(), serde_json::Value::String(match_spec));
782 }
783
784 Ok(CommandBuilder::new("signal-child")
785 .payload(serde_json::Value::Object(payload))
786 .build())
787 }
788}
789
790#[cfg(test)]
791mod tests {
792 use super::*;
793
794 #[test]
795 fn test_run_basic() {
796 let cmd = RunCommand::new().build();
797 assert!(cmd.is_ok());
798 let msg = cmd.unwrap();
799 assert_eq!(msg.cmd, "run");
800 }
801
802 #[test]
803 fn test_run_with_options() {
804 let cmd = RunCommand::new()
805 .data("test data")
806 .cmdline("bash")
807 .allow_remote_control(true)
808 .build();
809 assert!(cmd.is_ok());
810 let msg = cmd.unwrap();
811 assert_eq!(msg.cmd, "run");
812 }
813
814 #[test]
815 fn test_kitten_basic() {
816 let cmd = KittenCommand::new().build();
817 assert!(cmd.is_ok());
818 let msg = cmd.unwrap();
819 assert_eq!(msg.cmd, "kitten");
820 }
821
822 #[test]
823 fn test_kitten_with_args() {
824 let cmd = KittenCommand::new().args("diff").build();
825 assert!(cmd.is_ok());
826 let msg = cmd.unwrap();
827 assert_eq!(msg.cmd, "kitten");
828 }
829
830 #[test]
831 fn test_launch_basic() {
832 let cmd = LaunchCommand::new().build();
833 assert!(cmd.is_ok());
834 let msg = cmd.unwrap();
835 assert_eq!(msg.cmd, "launch");
836 }
837
838 #[test]
839 fn test_launch_with_options() {
840 let cmd = LaunchCommand::new()
841 .args("bash")
842 .window_title("Test")
843 .cwd("/home")
844 .keep_focus(true)
845 .build();
846 assert!(cmd.is_ok());
847 let msg = cmd.unwrap();
848 assert_eq!(msg.cmd, "launch");
849 }
850
851 #[test]
852 fn test_env_basic() {
853 let mut env_map = Map::new();
854 env_map.insert("PATH".to_string(), serde_json::Value::String("/usr/bin".to_string()));
855 let cmd = EnvCommand::new(env_map).build();
856 assert!(cmd.is_ok());
857 let msg = cmd.unwrap();
858 assert_eq!(msg.cmd, "env");
859 }
860
861 #[test]
862 fn test_env_empty() {
863 let cmd = EnvCommand::new(Map::new()).build();
864 assert!(cmd.is_err());
865 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
866 assert_eq!(field, "env");
867 assert_eq!(cmd_name, "env");
868 } else {
869 panic!("Expected MissingParameter error");
870 }
871 }
872
873 #[test]
874 fn test_set_user_vars_basic() {
875 let cmd = SetUserVarsCommand::new(vec!["var1".to_string(), "var2".to_string()]).build();
876 assert!(cmd.is_ok());
877 let msg = cmd.unwrap();
878 assert_eq!(msg.cmd, "set-user-vars");
879 }
880
881 #[test]
882 fn test_set_user_vars_empty() {
883 let cmd = SetUserVarsCommand::new(vec![]).build();
884 assert!(cmd.is_err());
885 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
886 assert_eq!(field, "var");
887 assert_eq!(cmd_name, "set-user-vars");
888 } else {
889 panic!("Expected MissingParameter error");
890 }
891 }
892
893 #[test]
894 fn test_load_config_basic() {
895 let cmd = LoadConfigCommand::new(vec!["kitty.conf".to_string()]).build();
896 assert!(cmd.is_ok());
897 let msg = cmd.unwrap();
898 assert_eq!(msg.cmd, "load-config");
899 }
900
901 #[test]
902 fn test_load_config_empty() {
903 let cmd = LoadConfigCommand::new(vec![]).build();
904 assert!(cmd.is_err());
905 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
906 assert_eq!(field, "paths");
907 assert_eq!(cmd_name, "load-config");
908 } else {
909 panic!("Expected MissingParameter error");
910 }
911 }
912
913 #[test]
914 fn test_resize_os_window_basic() {
915 let cmd = ResizeOSWindowCommand::new().build();
916 assert!(cmd.is_ok());
917 let msg = cmd.unwrap();
918 assert_eq!(msg.cmd, "resize-os-window");
919 }
920
921 #[test]
922 fn test_resize_os_window_with_options() {
923 let cmd = ResizeOSWindowCommand::new()
924 .width(800)
925 .height(600)
926 .unit("px")
927 .build();
928 assert!(cmd.is_ok());
929 let msg = cmd.unwrap();
930 assert_eq!(msg.cmd, "resize-os-window");
931 }
932
933 #[test]
934 fn test_disable_ligatures_basic() {
935 let cmd = DisableLigaturesCommand::new().build();
936 assert!(cmd.is_ok());
937 let msg = cmd.unwrap();
938 assert_eq!(msg.cmd, "disable-ligatures");
939 }
940
941 #[test]
942 fn test_disable_ligatures_with_options() {
943 let cmd = DisableLigaturesCommand::new()
944 .strategy("never")
945 .all(true)
946 .build();
947 assert!(cmd.is_ok());
948 let msg = cmd.unwrap();
949 assert_eq!(msg.cmd, "disable-ligatures");
950 }
951
952 #[test]
953 fn test_signal_child_basic() {
954 let cmd = SignalChildCommand::new(vec![9, 15]).build();
955 assert!(cmd.is_ok());
956 let msg = cmd.unwrap();
957 assert_eq!(msg.cmd, "signal-child");
958 }
959
960 #[test]
961 fn test_signal_child_empty() {
962 let cmd = SignalChildCommand::new(vec![]).build();
963 assert!(cmd.is_err());
964 if let Err(CommandError::MissingParameter(field, cmd_name)) = cmd {
965 assert_eq!(field, "signals");
966 assert_eq!(cmd_name, "signal-child");
967 } else {
968 panic!("Expected MissingParameter error");
969 }
970 }
971}