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}