1use crate::model::{Config, ExpandResult};
2
3pub fn expand<F>(config: &Config, token: &str, command_exists: F) -> ExpandResult
7where
8 F: Fn(&str) -> bool,
9{
10 for abbr in &config.abbr {
11 if abbr.key != token {
12 continue;
13 }
14 if abbr.key == abbr.expand {
16 continue;
17 }
18 if let Some(cmds) = &abbr.when_command_exists {
20 if !cmds.iter().all(|c| command_exists(c)) {
21 continue;
22 }
23 }
24 return ExpandResult::Expanded(abbr.expand.clone());
25 }
26 ExpandResult::PassThrough(token.to_string())
27}
28
29pub fn list(config: &Config) -> Vec<(&str, &str)> {
31 config
32 .abbr
33 .iter()
34 .map(|a| (a.key.as_str(), a.expand.as_str()))
35 .collect()
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use crate::model::{Abbr, Config};
42
43 fn cfg(abbrs: Vec<Abbr>) -> Config {
44 Config {
45 version: 1,
46 keybind: crate::model::KeybindConfig::default(),
47 abbr: abbrs,
48 }
49 }
50
51 fn abbr(key: &str, expand: &str) -> Abbr {
52 Abbr {
53 key: key.into(),
54 expand: expand.into(),
55 when_command_exists: None,
56 }
57 }
58
59 fn abbr_when(key: &str, exp: &str, cmds: Vec<&str>) -> Abbr {
60 Abbr {
61 key: key.into(),
62 expand: exp.into(),
63 when_command_exists: Some(cmds.into_iter().map(String::from).collect()),
64 }
65 }
66
67 #[test]
68 fn match_expands() {
69 let c = cfg(vec![abbr("gcm", "git commit -m")]);
70 assert_eq!(
71 expand(&c, "gcm", |_| true),
72 ExpandResult::Expanded("git commit -m".into())
73 );
74 }
75
76 #[test]
77 fn no_match_passes_through() {
78 let c = cfg(vec![abbr("gcm", "git commit -m")]);
79 assert_eq!(
80 expand(&c, "xyz", |_| true),
81 ExpandResult::PassThrough("xyz".into())
82 );
83 }
84
85 #[test]
86 fn selects_correct_abbr() {
87 let c = cfg(vec![
88 abbr("gcm", "git commit -m"),
89 abbr("gp", "git push"),
90 ]);
91 assert_eq!(
92 expand(&c, "gp", |_| true),
93 ExpandResult::Expanded("git push".into())
94 );
95 }
96
97 #[test]
98 fn key_eq_expand_passes_through() {
99 let c = cfg(vec![abbr("ls", "ls")]);
100 assert_eq!(
101 expand(&c, "ls", |_| true),
102 ExpandResult::PassThrough("ls".into())
103 );
104 }
105
106 #[test]
107 fn when_command_exists_present() {
108 let c = cfg(vec![abbr_when("ls", "lsd", vec!["lsd"])]);
109 assert_eq!(
110 expand(&c, "ls", |_| true),
111 ExpandResult::Expanded("lsd".into())
112 );
113 }
114
115 #[test]
116 fn when_command_exists_absent() {
117 let c = cfg(vec![abbr_when("ls", "lsd", vec!["lsd"])]);
118 assert_eq!(
119 expand(&c, "ls", |_| false),
120 ExpandResult::PassThrough("ls".into())
121 );
122 }
123
124 #[test]
125 fn list_returns_all_pairs() {
126 let c = cfg(vec![
127 abbr("gcm", "git commit -m"),
128 abbr("gp", "git push"),
129 ]);
130 let pairs = list(&c);
131 assert_eq!(pairs, vec![("gcm", "git commit -m"), ("gp", "git push")]);
132 }
133}