1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#[derive(Debug, Default, PartialEq)]
pub struct LsOptions {
    // TODO: matchers can be combined using Boolean operators
    matcher: Option<Matcher>,
}

impl LsOptions {
    pub fn matcher(&mut self, matcher: Matcher) -> &Self {
        self.matcher = Some(matcher);
        self
    }
}

impl From<&LsOptions> for tokio::process::Command {
    fn from(value: &LsOptions) -> Self {
        let mut cmd = tokio::process::Command::new("kitty");
        cmd.args(["@", "ls"]);

        if let Some(Matcher::Id(id)) = value.matcher {
            cmd.arg("--match");
            cmd.arg(format!("id:{id}"));
        }

        cmd
    }
}

#[derive(Debug, Default, PartialEq)]
pub struct SendTextOptions {
    // TODO: matchers can be combined using Boolean operators
    matcher: Option<Matcher>,
}

impl SendTextOptions {
    pub fn matcher(&mut self, matcher: Matcher) -> &Self {
        self.matcher = Some(matcher);
        self
    }
}

impl From<&SendTextOptions> for tokio::process::Command {
    fn from(value: &SendTextOptions) -> Self {
        let mut cmd = tokio::process::Command::new("kitty");
        cmd.args(["@", "send-text"]);

        if let Some(Matcher::Id(id)) = value.matcher {
            cmd.arg("--match");
            cmd.arg(format!("id:{id}"));
        }

        cmd
    }
}

// id, title, pid, cwd, cmdline, num, env, var, state, neighbor, and recent
#[derive(Debug, PartialEq)]
pub enum Matcher {
    Id(u32),
    // Title(String),
    // Pid(u32),
    // Cwd(String),
    // CmdLine(String),
    // Num(u32),
    // Env(String),
    // Var(String),
    // State(String),
    // Neighbor(String),
    // Recent(u32),
}

#[cfg(test)]
mod tests {
    use pretty_assertions::assert_eq;
    use tokio::process::Command;

    use crate::{remote_command::Matcher, LsOptions, SendTextOptions};

    #[test]
    fn test_ls_options() {
        let cmd = Command::from(&LsOptions::default());
        let cmd = cmd.as_std();

        assert_eq!(cmd.get_program(), "kitty");
        assert_eq!(cmd.get_args().collect::<Vec<_>>(), vec!["@", "ls"]);
    }

    #[test]
    fn test_ls_options_match_id() {
        let cmd = Command::from(LsOptions::default().matcher(Matcher::Id(13)));
        let cmd = cmd.as_std();

        assert_eq!(cmd.get_program(), "kitty");
        assert_eq!(
            cmd.get_args().collect::<Vec<_>>(),
            vec!["@", "ls", "--match", "id:13"]
        );
    }

    #[test]
    fn test_send_text_options() {
        let cmd = Command::from(&SendTextOptions::default());
        let cmd = cmd.as_std();

        assert_eq!(cmd.get_program(), "kitty");
        assert_eq!(cmd.get_args().collect::<Vec<_>>(), vec!["@", "send-text"]);
    }

    #[test]
    fn test_send_text_match_id() {
        let cmd = Command::from(SendTextOptions::default().matcher(Matcher::Id(13)));
        let cmd = cmd.as_std();

        assert_eq!(cmd.get_program(), "kitty");
        assert_eq!(
            cmd.get_args().collect::<Vec<_>>(),
            vec!["@", "send-text", "--match", "id:13"]
        );
    }
}