1#![feature(never_type)]
2#![feature(exit_status_error)]
3
4use std::collections::HashSet;
5
6use datatypes::Bread;
7
8pub mod args;
9pub mod config;
10pub mod datatypes;
11pub mod fs_operation;
12
13use datatypes::*;
14
15pub fn prompt(mut conf: config::Config) -> Result<Option<HashSet<String>>, String> {
16 if conf.delete {
17 conf.delete = false;
19 let yes = conf.yes;
20 let breads = fs_operation::handle_files(conf).collect::<Vec<_>>();
21 let mut files_changed = None;
22 if yes {
23 let mut cache = HashSet::new();
24 for b in breads {
25 cache.insert(
26 fs_operation::delete_the_crumbs(b).map_err(|e| e.to_string())?,
27 );
28 }
29 if !cache.is_empty() {
30 files_changed = Some(cache)
31 };
32 } else {
33 let mut rl = rustyline::Editor::<()>::new();
34 loop {
35 breads.iter().for_each(|b| println!("{}", b));
36 match rl.readline("Are you sure you want to delete all crumbs? (y/n/s/i): ") {
37 Ok(s) => match s.as_str() {
38 "y" => {
39 let mut cache = HashSet::new();
40 for b in breads {
41 cache.insert(
42 fs_operation::delete_the_crumbs(b).map_err(|e| e.to_string())?,
43 );
44 }
45 if !cache.is_empty() {
46 files_changed = Some(cache)
47 };
48 }
49 "n" => (), "s" => continue,
51 "i" => {
52 files_changed = Some(prompt_bread(breads.into_iter(), &mut rl, "delete")?)
53 }
54 _ => return Err("I don't understand, please give y/n/s/i".to_string()),
55 },
56 Err(e) => return Err(format!("error in prompt readline {}", e.to_string())),
57 }
58 break;
59 }
60 }
61 Ok(files_changed)
62 } else if conf.restore {
63 let yes = conf.yes;
64 let breads = fs_operation::handle_files(conf).collect::<Vec<_>>();
65 let mut files_changed = None;
66 if yes {
67 let mut cache = HashSet::new();
68 for b in breads {
69 cache.insert(
70 fs_operation::restore_the_crumb(b).map_err(|e| e.to_string())?,
71 );
72 }
73 if !cache.is_empty() {
74 files_changed = Some(cache)
75 };
76 } else {
77 let mut rl = rustyline::Editor::<()>::new();
78 loop {
79 breads.iter().for_each(|b| println!("{}", b));
80 match rl.readline("Are you sure you want to restore all crumbs? (y/n/s/i): ") {
81 Ok(s) => match s.as_str() {
82 "y" => {
83 let mut cache = HashSet::new();
84 for b in breads {
85 cache.insert(
86 fs_operation::restore_the_crumb(b).map_err(|e| e.to_string())?,
87 );
88 }
89 if !cache.is_empty() {
90 files_changed = Some(cache)
91 };
92 }
93 "n" => (), "s" => continue,
95 "i" => {
96 files_changed = Some(prompt_bread(breads.into_iter(), &mut rl, "restore")?)
97 }
98 _ => return Err("I don't understand, please give y/n/s/i".to_string()),
99 },
100 Err(e) => return Err(format!("error in prompt readline {}", e.to_string())),
101 }
102 break;
103 }
104 }
105 Ok(files_changed)
106 } else {
107 match conf.output {
108 config::OutputFormat::None => {
109 fs_operation::handle_files(conf).for_each(|b| println!("{}", b))
110 }
111 config::OutputFormat::Json => {
112 println!(
113 "{}",
114 serde_json::to_string(&fs_operation::handle_files(conf).collect::<Vec<_>>())
115 .map_err(|e| e.to_string())?
116 )
117 }
118 config::OutputFormat::List => fs_operation::handle_files(conf).for_each(|b| {
119 b.crumbs
120 .iter()
121 .for_each(|crumb| println!("{}:{}", b.file_path, crumb.list_format()))
122 }),
123 config::OutputFormat::Range => fs_operation::handle_files(conf).for_each(|b| {
124 b.crumbs.iter().for_each(|crumb| {
125 println!(
126 r#"File path: {}
127
128The mark:
129{}
130
131Context around:
132{}
133=======================
134"#,
135 b.file_path,
136 crumb,
137 crumb.range_format()
138 )
139 })
140 }),
141 }
142 Ok(None)
143 }
144}
145
146fn prompt_bread(
147 breads: impl Iterator<Item = Bread>,
148 rl: &mut rustyline::Editor<()>,
149 op: &str,
150) -> Result<HashSet<String>, String> {
151 let mut files_changed = HashSet::new();
152 for b in breads {
153 loop {
154 println!("{}", b);
156 match rl.readline(&format!(
157 "Are you sure you want to {} this bread {}? (y/n/s/i): ",
158 op, b.file_path
159 )) {
160 Ok(s) => match s.as_str() {
161 "y" => match op {
162 "delete" => {
163 files_changed.insert(
164 fs_operation::delete_the_crumbs(b).map_err(|e| e.to_string())?,
165 );
166 }
167 "restore" => {
168 files_changed.insert(
169 fs_operation::restore_the_crumb(b).map_err(|e| e.to_string())?,
170 );
171 }
172 _ => (),
173 },
174 "n" => {}
175 "s" => {
176 continue;
177 }
178 "i" => {
179 let go_to_handle = prompt_crumbs(b.crumbs.iter(), rl, op)?;
180 if go_to_handle.len() != 0 {
181 match op {
182 "delete" => {
183 files_changed.insert(
184 fs_operation::delete_the_crumbs_on_special_index(
185 b,
186 go_to_handle,
187 )
188 .map_err(|e| e.to_string())?,
189 );
190 }
191 "restore" => {
192 files_changed.insert(
193 fs_operation::restore_the_crumb_on_special_index(
194 b,
195 go_to_handle,
196 )
197 .map_err(|e| e.to_string())?,
198 );
199 }
200 _ => (),
201 }
202 }
203 }
204 _ => {
205 println!("I don't understand, please give y/n/s/i");
206 }
207 },
208 Err(e) => return Err(e.to_string()),
209 }
210 break;
211 }
212 }
213 Ok(files_changed)
214}
215
216fn prompt_crumbs<'a>(
217 crumbs: impl Iterator<Item = &'a Crumb>,
218 rl: &mut rustyline::Editor<()>,
219 op: &str,
220) -> Result<HashSet<usize>, String> {
221 let mut going_to_handle_crumbs_indexes = HashSet::new();
222 for (ind, c) in crumbs.enumerate() {
223 loop {
224 println!("{}", c);
225 match rl.readline(&format!(
226 "Are you sure you want to {} this crumb? (y/n/s): ",
227 op
228 )) {
229 Ok(s) => match s.as_str() {
230 "y" => {
231 going_to_handle_crumbs_indexes.insert(ind);
232 }
233 "n" => {}
234 "s" => {
235 continue;
236 }
237 _ => {
238 println!("I don't understand, please give y/n/s");
239 }
240 },
241 Err(e) => return Err(e.to_string()),
242 }
243 break;
244 }
245 }
246 Ok(going_to_handle_crumbs_indexes)
247}