seek/
lib.rs

1use std::{ fs, io::Read, process, env, collections::HashMap };
2use serde::{ Deserialize, Serialize };
3use colored::Colorize;
4use dialoguer::{ theme::ColorfulTheme, Select };
5use serde_json::{ Value, json };
6use tabled::Tabled;
7extern crate dirs;
8
9pub fn get_config_file() -> fs::File {
10    let path: String = dirs::home_dir().unwrap().to_str().unwrap().to_string() + "/seekconfig.json";
11
12    if fs::metadata(&path).is_ok() {
13        return fs::File::open(&path).expect("Failed to open config file");
14    } else {
15        let file = fs::File::create(&path).expect("Failed to create config file");
16        return file;
17    }
18}
19
20pub fn check_path(path: &String) -> bool {
21    fs::metadata(path).is_ok()
22}
23
24pub fn change_app(app: &String, path: &String) {
25
26    let mut p = String::new();
27    if path.starts_with("./") || path.starts_with("/") || path.starts_with(r#".\"#) || path.starts_with(r#"\"#) {
28        p = env::current_dir().unwrap().to_str().unwrap().to_string();
29        p.push_str(r#"\"#);
30        p.push_str(path);
31        
32        if check_path(&p) == false {
33            println!("{}", format!("Path - `{}` does not exist.", &p).red());
34            process::exit(1);
35        }
36    } else {
37        p = path.to_string();
38    }
39    
40    let config: fs::File = get_config_file();
41
42    let mut data = String::new();
43
44    (&config).read_to_string(&mut data).unwrap();
45
46    if data.len() < 1 {
47        data = r#"{"paths": {}, "apps": {}}"#.to_string();
48    }
49
50    let mut v: Value = match serde_json::from_str(&data) {
51        Ok(v) => v,
52        Err(_) => {
53            data = r#"{"paths": {}, "apps": {}}"#.to_string();
54            serde_json::from_str(&data).unwrap()
55        }
56    };
57    
58    if (v["apps"])[app].is_null() == false {
59        
60        println!("An app with the name `{}` already exists!", app);
61
62        let opts = vec!["Yes", "No"];
63        if Select::with_theme(&ColorfulTheme::default())
64            .with_prompt("Do you want to update it?")
65            .items(&opts)
66            .default(1)
67            .interact()
68            .unwrap()
69            == 0
70        {
71            (v["apps"])[app] = json!(p);
72            let data = serde_json::to_string(&v).unwrap();
73            fs::write(
74                dirs::home_dir().unwrap().to_str().unwrap().to_string() + "/seekconfig.json",
75                data,
76            )
77            .expect("Failed to write to file");
78            println!("Updated `{}` with `{}`!", app, p);
79        } else {
80            process::exit(0);
81        }
82    } else {
83        v["apps"][app] = json!(p);
84        let data = serde_json::to_string(&v).unwrap();
85        fs::write(
86            dirs::home_dir().unwrap().to_str().unwrap().to_string() + "/seekconfig.json",
87            data,
88        )
89        .expect("Failed to write to file");
90        println!("Added an app named `{}` with `{}` path!", app, p);
91    }
92    
93}
94
95pub fn change_path(name: &String, path: &String) {
96
97    let mut p = String::new();
98    if path.starts_with("./") || path.starts_with("/") || path.starts_with(r#".\"#) || path.starts_with(r#"\"#) {
99        p = env::current_dir().unwrap().to_str().unwrap().to_string();
100        p.push_str(r#"\"#);
101        p.push_str(path);
102        
103        if check_path(&p) == false {
104            println!("{}", format!("Path - `{}` does not exist.", &p).red());
105            process::exit(1);
106        }
107    } else {
108        p = path.to_string();
109    }
110
111    let config: fs::File = get_config_file();
112
113    let mut data = String::new();
114
115    (&config).read_to_string(&mut data).unwrap();
116
117    if data.len() < 1 {
118        data = r#"{"paths": {}, "apps": {}}"#.to_string();
119    }
120
121    let mut v: Value = match serde_json::from_str(&data) {
122        Ok(v) => v,
123        Err(_) => {
124            data = r#"{"paths": {}, "apps": {}}"#.to_string();
125            serde_json::from_str(&data).unwrap()
126        }
127    };
128
129    if v["paths"][name].is_null() == false {
130        
131        println!("A path shortcut with the name `{}` already exists!", name);
132
133        let opts = vec!["Yes", "No"];
134        if Select::with_theme(&ColorfulTheme::default())
135            .with_prompt("Do you want to update it?")
136            .items(&opts)
137            .default(1)
138            .interact()
139            .unwrap()
140            == 0
141        {
142            v["paths"][name] = json!(p);
143            let data = serde_json::to_string(&v).unwrap();
144            fs::write(
145                dirs::home_dir().unwrap().to_str().unwrap().to_string() + "/seekconfig.json",
146                data,
147            )
148            .expect("Failed to write to file");
149            println!("Updated `{}` path shortcut with `{}`!", name, p);
150        } else {
151            process::exit(0);
152        }
153    } else {
154        v["paths"][name] = json!(p);
155        let data = serde_json::to_string(&v).unwrap();
156        fs::write(
157            dirs::home_dir().unwrap().to_str().unwrap().to_string() + "/seekconfig.json",
158            data,
159        )
160        .expect("Failed to write to file");
161        println!("Added a path shortcut named `{}` with `{}` path!", name, p);
162    }
163    
164}
165
166pub fn help_msg() {
167    println!(r#"
168{} {}
169
170{}
171    seek {}
172
173{}
174    {}
175    {}
176
177    seek --app <APP> <PATH>
178    seek --config <NAME> <FULLPATH>
179
180{}
181    seek --app  discord ../path/to/discord/executable
182    seek --app  code    code-insiders.cmd
183    seek --path seek    ../path/to/seek/code/directory
184    
185    seek code seek
186    {}
187
188    seek code --custom ./a/different/path/which/is/not/saved
189
190Visit the repo for more help - {}
191
192{} {}
193    "#, 
194        "seek".green(), 
195        env!("CARGO_PKG_VERSION"), 
196        "USAGE:".yellow(),
197        "<APP> [PATH]".dimmed(),
198        "CONFIGURATION:".yellow(),
199        "# Adding/Updating an app shortcut".bright_black(),
200        "# Adding/Updating an path shortcut".bright_black(),
201        "EXAMPLES:".yellow(),
202        "# Opens the app `code` with path `seek`".bright_black(),
203        "https://github.com/yxshv/seek".cyan().underline(),
204        "<REQUIRED>".bold(), "[OPTIONAL]".dimmed(),
205    )
206}
207
208pub fn get_app(app: &String) -> Result<String, String> {
209    let config: fs::File = get_config_file();
210
211    let mut data = String::new();
212
213    (&config).read_to_string(&mut data).unwrap();
214
215    if data.len() < 1 {
216        data = r#"{"paths": {}, "apps": {}}"#.to_string();
217    }
218    let v: Value = match serde_json::from_str(&data) {
219        Ok(v) => v,
220        Err(_) => {
221            data = r#"{"paths": {}, "apps": {}}"#.to_string();
222            serde_json::from_str(&data).unwrap()
223        }
224    };
225    if v["apps"][app].is_null() == false {
226        Ok(v["apps"][app].as_str().unwrap().to_string())
227    } else {
228        Err(format!("App `{}` does not exist!", app))
229    }
230}
231
232pub fn get_path(path: &String) -> Result<String, String> {
233    let config: fs::File = get_config_file();
234
235    let mut data = String::new();
236
237    (&config).read_to_string(&mut data).unwrap();
238
239    if data.len() < 1 {
240        data = r#"{"paths": {}, "apps": {}}"#.to_string();
241    }
242    let v: Value = match serde_json::from_str(&data) {
243        Ok(v) => v,
244        Err(_) => {
245            data = r#"{"paths": {}, "apps": {}}"#.to_string();
246            serde_json::from_str(&data).unwrap()
247        }
248    };
249    if v["paths"][path].is_null() == false {
250        Ok(v["paths"][path].as_str().unwrap().to_string())
251    } else {
252        Err(format!("No path short exists with the name - `{}`!", path))
253    }
254}
255
256#[derive(Tabled)]
257pub struct Apps {
258    #[tabled(rename = "Name")]
259    names: String,
260    #[tabled(rename = "Path")]
261    paths: String
262}
263
264#[derive(Tabled)]
265pub struct Path {
266    #[tabled(rename = "Name")]
267    names: String,
268    #[tabled(rename = "Shortcut")]
269    paths: String
270}
271
272#[derive(Serialize, Deserialize)]
273pub struct Object {
274    apps:  HashMap<String, String>,
275    paths: HashMap<String, String>
276}
277
278pub fn apps_list() -> Vec<Apps> {
279
280    let mut apps: Vec<Apps> = Vec::new();
281    
282    let config: fs::File = get_config_file();
283    let mut content: String = String::new();
284
285    (&config).read_to_string(&mut content).unwrap();
286
287    if content.len() < 1 {
288        content = r#"{"paths": {}, "apps": {}}"#.to_string();
289    }
290    let v: Object = match serde_json::from_str(&content) {
291        Ok(v) => v,
292        Err(_) => {
293            content = r#"{"paths": {}, "apps": {}}"#.to_string();
294            serde_json::from_str(&content).unwrap()
295        }
296    };
297
298    for (k, v) in v.apps {
299        apps.push(Apps {
300            names: k,
301            paths: v
302        });
303    }
304
305    apps
306
307}
308
309pub fn paths_list() -> Vec<Apps> {
310
311    let mut apps: Vec<Apps> = Vec::new();
312    
313    let config: fs::File = get_config_file();
314    let mut content: String = String::new();
315
316    (&config).read_to_string(&mut content).unwrap();
317
318    if content.len() < 1 {
319        content = r#"{"paths": {}, "apps": {}}"#.to_string();
320    }
321    let v: Object = match serde_json::from_str(&content) {
322        Ok(v) => v,
323        Err(_) => {
324            content = r#"{"paths": {}, "apps": {}}"#.to_string();
325            serde_json::from_str(&content).unwrap()
326        }
327    };
328
329    for (k, v) in v.paths {
330        apps.push(Apps {
331            names: k,
332            paths: v
333        });
334    }
335
336    apps
337
338}