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