alfred_workflow_rust_project/
workflow_item.rs

1use std::collections::HashMap;
2
3use serde::ser::SerializeSeq;
4use serde::{Deserialize, Serialize, Serializer};
5
6use crate::common::EnumIdent;
7use crate::icon::Icon;
8
9// the key used for modifier
10pub enum ModKey {
11    CMD,
12    CTRL,
13    ALT,
14    FN,
15    SHIFT,
16}
17
18#[derive(Serialize, Deserialize)]
19pub struct Modifier {
20    #[serde(skip_serializing_if = "Option::is_none")]
21    arg: Option<Vec<String>>,
22    subtitle: String,
23    valid: bool,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    icon: Option<Icon>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    variables: Option<HashMap<String, String>>,
28}
29
30impl Modifier {
31    pub fn new() -> Modifier {
32        return Modifier {
33            arg: None,
34            subtitle: "".to_string(),
35            valid: true,
36            icon: None,
37            variables: None,
38        };
39    }
40
41    pub fn valid(mut self, v: bool) -> Modifier {
42        self.valid = v;
43        self
44    }
45
46    pub fn subtitle(mut self, title: &str) -> Modifier {
47        self.subtitle = title.to_string();
48        self
49    }
50
51    pub fn icon(mut self, icon: Icon) -> Modifier {
52        self.icon = Some(icon);
53        self
54    }
55
56    pub fn args(mut self, arg: &str) -> Modifier {
57        let mut args = self.arg.unwrap_or_default();
58        args.push(arg.to_string());
59        self.arg = Some(args);
60        self
61    }
62
63    pub fn vars(mut self, name: &str, value: &str) -> Modifier {
64        let mut map = self.variables.unwrap_or_default();
65        map.insert(name.to_string(), value.to_string());
66        self.variables = Some(map);
67        self
68    }
69}
70
71pub enum ItemType {
72    DEFAULT,
73    FILE,
74    FILE2,
75}
76
77impl EnumIdent for ModKey {
78    fn name(&self) -> &'static str {
79        match self {
80            ModKey::CMD => "cmd",
81            ModKey::FN => "fn",
82            ModKey::CTRL => "ctrl",
83            ModKey::ALT => "alt",
84            ModKey::SHIFT => "shift",
85        }
86    }
87}
88
89impl EnumIdent for ItemType {
90    fn name(&self) -> &'static str {
91        match self {
92            ItemType::DEFAULT => "default",
93            ItemType::FILE => "file",
94            ItemType::FILE2 => "file:skipcheck",
95        }
96    }
97}
98
99#[derive(Serialize, Deserialize)]
100pub struct WorkflowItem {
101    #[serde(skip_serializing_if = "Option::is_none")]
102    uid: Option<String>,
103    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
104    item_type: Option<String>,
105    title: String,
106    #[serde(skip_serializing_if = "Option::is_none")]
107    subtitle: Option<String>,
108    #[serde(skip_serializing_if = "Option::is_none")]
109    icon: Option<Icon>,
110    valid: bool,
111    #[serde(rename = "match", skip_serializing_if = "Option::is_none")]
112    matches: Option<String>,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    mods: Option<HashMap<String, Modifier>>,
115    #[serde(skip_serializing_if = "Option::is_none")]
116    arg: Option<Vec<String>>,
117    #[serde(rename = "action", skip_serializing_if = "Option::is_none")]
118    actions: Option<Action>,
119    #[serde(skip_serializing_if = "Option::is_none")]
120    text: Option<ItemText>,
121    #[serde(rename = "quicklookurl", skip_serializing_if = "Option::is_none")]
122    quick_look: Option<String>,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    autocomplete: Option<String>,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    variables: Option<HashMap<String, String>>,
127}
128
129impl WorkflowItem {
130    pub fn new(title: &str) -> WorkflowItem {
131        WorkflowItem {
132            title: title.to_string(),
133            uid: None,
134            item_type: None,
135            subtitle: None,
136            icon: None,
137            valid: true,
138            matches: None,
139            mods: None,
140            arg: None,
141            actions: None,
142            text: None,
143            quick_look: None,
144            autocomplete: None,
145            variables: None,
146        }
147    }
148
149    pub fn uid(mut self, uid: &str) -> WorkflowItem {
150        self.uid = Some(uid.to_string());
151        self
152    }
153
154    pub fn item_type(mut self, item_type: ItemType) -> WorkflowItem {
155        self.item_type = Some(item_type.name().to_string());
156        self
157    }
158
159    pub fn subtitle(mut self, subtitle: &str) -> WorkflowItem {
160        self.subtitle = Some(subtitle.to_string());
161        self
162    }
163
164    pub fn icon(mut self, icon: Icon) -> WorkflowItem {
165        self.icon = Some(icon);
166        self
167    }
168
169    pub fn valid(mut self, v: bool) -> WorkflowItem {
170        self.valid = v;
171        self
172    }
173
174    pub fn matches(mut self, matches: &str) -> WorkflowItem {
175        self.matches = Some(matches.to_string());
176        self
177    }
178
179    pub fn mods(mut self, keys: Vec<ModKey>, modifier: Modifier) -> WorkflowItem {
180        // do nothing if no keys
181        if keys.len() <= 0 {
182            return self;
183        }
184
185        let x1: Vec<&str> = keys.iter().map(|x| x.name()).collect();
186        let key_str = x1.join("+");
187
188        let mut map = self.mods.unwrap_or_default();
189        map.insert(key_str, modifier);
190        self.mods = Some(map);
191        self
192    }
193
194    pub fn actions(mut self, action: Action) -> WorkflowItem {
195        self.actions = Some(action);
196        self
197    }
198    pub fn text(mut self, text: ItemText) -> WorkflowItem {
199        self.text = Some(text);
200        self
201    }
202    pub fn quick_look(mut self, look_uri: &str) -> WorkflowItem {
203        self.quick_look = Some(look_uri.to_string());
204        self
205    }
206    pub fn auto_complete(mut self, auto_complete: &str) -> WorkflowItem {
207        self.autocomplete = Some(auto_complete.to_string());
208        self
209    }
210    pub fn vars(mut self, name: &str, value: &str) -> WorkflowItem {
211        let mut vars = self.variables.unwrap_or_default();
212        vars.insert(name.to_string(), value.to_string());
213        self.variables = Some(vars);
214        self
215    }
216    pub fn args(mut self, arg: &str) -> WorkflowItem {
217        let mut vec = self.arg.unwrap_or_default();
218        vec.push(arg.to_string());
219        self.arg = Some(vec);
220        self
221    }
222}
223
224// in later
225#[derive(Deserialize)]
226pub enum Action {
227    SingleItem(String),
228    MultiItem(Vec<String>),
229    ObjectItem(ActionItem),
230}
231
232impl Serialize for Action {
233    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
234        where
235            S: Serializer,
236    {
237        match self {
238            Action::SingleItem(var) => serializer.serialize_str(var),
239            Action::MultiItem(var) => {
240                let mut seq = serializer.serialize_seq(Some(var.len()))?;
241                for e in var {
242                    seq.serialize_element(e)?;
243                }
244                seq.end()
245            }
246            Action::ObjectItem(var) => ActionItem::serialize(var, serializer),
247        }
248    }
249}
250
251#[derive(Serialize, Deserialize)]
252pub struct ActionItem {
253    #[serde(skip_serializing_if = "Option::is_none")]
254    text: Option<Vec<String>>,
255    #[serde(skip_serializing_if = "Option::is_none")]
256    url: Option<String>,
257    #[serde(skip_serializing_if = "Option::is_none")]
258    file: Option<String>,
259    #[serde(skip_serializing_if = "Option::is_none")]
260    auto: Option<String>,
261}
262
263impl ActionItem {
264    pub fn new() -> ActionItem {
265        ActionItem {
266            text: None,
267            url: None,
268            file: None,
269            auto: None,
270        }
271    }
272
273    pub fn text(mut self, text: &str) -> ActionItem {
274        let mut texts = self.text.unwrap_or_default();
275        texts.push(text.to_string());
276        self.text = Some(texts);
277        self
278    }
279
280    pub fn texts(mut self, texts: Vec<&str>) -> ActionItem {
281        let mut a_texts = self.text.unwrap_or_default();
282        texts.iter().for_each(|it| a_texts.push(it.to_string()));
283        self.text = Some(a_texts);
284        self
285    }
286
287    pub fn url(mut self, url: &str) -> ActionItem {
288        self.url = Some(url.to_string());
289        self
290    }
291
292    pub fn file(mut self, file: &str) -> ActionItem {
293        self.file = Some(file.to_string());
294        self
295    }
296
297    pub fn auto(mut self, auto: &str) -> ActionItem {
298        self.auto = Some(auto.to_string());
299        self
300    }
301}
302
303#[derive(Serialize, Deserialize)]
304pub struct ItemText {
305    #[serde(skip_serializing_if = "Option::is_none")]
306    copy: Option<String>,
307    #[serde(skip_serializing_if = "Option::is_none")]
308    #[serde(rename = "largetype")]
309    large_type: Option<String>,
310}
311
312impl ItemText {
313    pub fn new(copy_text: &str) -> ItemText {
314        ItemText {
315            copy: Some(copy_text.to_string()),
316            large_type: None,
317        }
318    }
319
320    pub fn large_text(mut self, text: &str) -> ItemText {
321        self.large_type = Some(text.to_string());
322        self
323    }
324}