1pub mod list;
2pub mod terminal;
3pub mod fixtures;
4
5use list::Entry;
6
7use std::env;
8use std::path::{Path, PathBuf};
9use std::fs::{create_dir_all, metadata, OpenOptions};
10use list::List;
11use fixtures::command_assistors;
12use termion::input::TermRead;
13use termion::event::Key;
14use termion::raw::{IntoRawMode, RawTerminal};
15use std::io::{ Write, stdout, stdin, StdoutLock};
16use termion::screen::AlternateScreen;
17use easy_hasher::easy_hasher::*;
18
19pub mod app {
20 use super::*;
21
22 pub fn run<P: AsRef<Path>>(path: P, all: bool, test: bool, fzf_hook_path: Option<PathBuf>, fzc_hook_path: Option<PathBuf>, fzd_hook_path: Option<PathBuf>) -> LsKey {
23 if test {
24 let mut path = path.as_ref().to_path_buf();
25 create_dir_all(&path).expect("Failed to create directories.");
26 path.push(".lsk_test_output");
27 std::fs::File::create(&path).expect("failed to create lsk output file");
28 }
29 let path = path.as_ref();
30 let mut ls_key = LsKey::new(path, all, test, fzf_hook_path.clone(), fzc_hook_path.clone(), fzd_hook_path.clone());
31 ls_key.update_file_display(false);
32 ls_key.run_cmd();
33 let mut list = ls_key.list.clone();
34
35 while ls_key.is_fuzzed {
36 ls_key.list = list;
37 let display = ls_key.display.clone();
38 if let Some(fuzzy_list) = ls_key.fuzzy_list.clone() {
39 let _list = ls_key.list;
40 ls_key = LsKey::new(path, all, test, fzf_hook_path.clone(), fzc_hook_path.clone(), fzd_hook_path.clone());
41 ls_key.list = fuzzy_list.clone();
42 ls_key.display = display;
43 } else if !ls_key.halt {
44 let _list = ls_key.list;
45 ls_key = LsKey::new(path, all, test, fzf_hook_path.clone(), fzc_hook_path.clone(), fzd_hook_path.clone());
46 ls_key.list = _list;
47 ls_key.display = display;
48 }
49 ls_key.update_file_display(false);
50 ls_key.run_cmd();
51 list = ls_key.list.clone();
52 }
53
54 ls_key
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Default)]
59pub struct LsKey {
60 pub list: List,
61 pub all: bool,
62 pub input: Input,
63 pub fuzzy_list: Option<List>,
64 pub pre_fuzz_list: Option<List>,
65 pub display: Option<(PathBuf, String)>,
66 pub halt: bool,
67 pub is_fuzzed: bool,
68 pub test: bool,
69 pub input_vec: Vec<String>,
70 pub output_vec: Vec<String>,
71 pub fzf_hook_path: Option<PathBuf>,
72 pub fzc_hook_path: Option<PathBuf>,
73 pub fzd_hook_path: Option<PathBuf>,
74 pub default_editor: String,
75 pub default_opener: String,
76}
77
78impl LsKey {
79 pub fn new<P: AsRef<Path>>(path: P, all: bool, test: bool, fzf_hook_path: Option<PathBuf>, fzc_hook_path: Option<PathBuf>, fzd_hook_path: Option<PathBuf>) -> Self {
80 let mut ls_key: LsKey = Default::default();
81 let list = if all {
82 list::List::new(path)
83 .list_include_hidden()
84 .unwrap()
85 } else {
86 list::List::new(path)
87 .list_skip_hidden()
88 .unwrap()
89 };
90
91 match env::var("EDITOR") {
92 Ok(editor) => {
93 ls_key.default_editor = editor
94 },
95 Err(_) => {
96 ls_key.default_editor = "nano".to_string()
97 }
98 };
99
100 match env::var("LSK_FILE_OPENER") {
101 Ok(editor) => {
102 ls_key.default_opener = editor
103 },
104 Err(_) => {
105 ls_key.default_opener = "xdg-open".to_string()
106 }
107 };
108
109 ls_key.list = list;
110 ls_key.all = all;
111 ls_key.halt = true;
112 ls_key.is_fuzzed = false;
113 ls_key.test = test;
114 ls_key.fzf_hook_path = fzf_hook_path;
115 ls_key.fzc_hook_path = fzc_hook_path;
116 ls_key.fzd_hook_path = fzd_hook_path;
117
118 ls_key
119 }
120
121 fn fuzzy_score(&mut self, mut input: String) -> list::fuzzy_score::Scores {
122 let files = &self.list.files;
123
124 let mut input_vec_str: Vec<&str> = input.split(" ").collect();
125
126 if input_vec_str.iter().count() > 1{
127 input_vec_str.pop();
128 input = input_vec_str.into_iter().collect();
129 }
130 let score_list = |entry: Entry| {
131 (
132 entry.clone(),
133 list::fuzzy_score::score(entry.path.to_str().unwrap(), &input)
134 )
135 };
136
137 let files_score: Vec<list::fuzzy_score::Score> =
138 files.iter()
139 .map(|file| list::fuzzy_score::Score::Files(score_list(
140 Entry {
141 path: file.path.to_path_buf(),
142 file_type: file.file_type.clone(),
143 key: file.key
144 }
145 )
146 )
147 )
148 .collect();
149
150 let files = files_score;
151
152 list::fuzzy_score::Scores {
153 files,
154 }
155 }
156
157 fn fuzzy_rank(&mut self, mut scores: list::fuzzy_score::Scores) -> list::fuzzy_score::Scores {
158 scores.files.sort_by(|a, b| list::fuzzy_score::order(a, b));
159
160 scores
161 }
162
163 fn fuzzy_filter(&mut self, scores: list::fuzzy_score::Scores) -> list::fuzzy_score::Scores {
165 let mut files_vec: Vec<list::fuzzy_score::Score> = vec![];
166 for score in scores.files.iter() {
167 let path = score.score().0;
168 let score = score.score().1;
169
170 let thing = (path, score.clone());
171
172 if score.is_some() {
173 files_vec.push(list::fuzzy_score::Score::Files(thing));
174 }
175 }
176
177 list::fuzzy_score::Scores {
178 files: files_vec,
179 }
180 }
181
182 pub fn fuzzy_update(&mut self, input: String) -> Self {
183 let scores = self.fuzzy_score(input);
184 let scores = self.fuzzy_rank(scores);
185 let scores = self.fuzzy_filter(scores);
186 let list = self.scores_to_list(scores);
187 self.update_file_display(false);
188 self.fuzzy_list = Some(list);
189
190 self.clone()
191 }
192
193
194 pub fn scores_to_list(&mut self, scores: list::fuzzy_score::Scores) -> list::List {
195 let files_list: Vec<Entry> = scores.files.iter().map(|score|
196 Entry {
197 path: score.score().0.path,
198 file_type: score.score().0.file_type,
199 key: score.score().0.key
200 }
201 ).collect();
202
203 self.list.files = files_list;
204
205 self.list.clone()
206 }
207
208 pub fn update(&mut self, list: List) {
209 let list = if self.all {
210 list
211 .list_include_hidden()
212 .unwrap()
213 } else {
214 list
215 .list_skip_hidden()
216 .unwrap()
217 };
218
219 self.list = list;
220 }
221
222 pub fn update_file_display(&mut self, mut filter: bool) {
223 let mut go = true;
224 let entries_count = self.list.files.iter().count();
225 let mut start = 0;
226 let mut end = entries_count;
227 if let Some(ls) = &self.list.filter {
228 start = ls.clone().into_iter().nth(0).unwrap();
229 end = *ls.into_iter().last().unwrap();
230 } else {
231 }
232 while go {
233 let entries = self.list.order_and_sort_list(true, filter);
234 let mut entries_keyed: Vec<String> = list::key_entries(entries.clone());
235 if end < entries_count {
236 let last = format!("[{}...{}]", end, entries_count);
237 entries_keyed.push(last);
238 }
239 let res = terminal::input_n_display::grid(entries_keyed.clone());
240 if let Some(r) = res {
241 let grid = r.0;
242 let width = r.1;
243 let height = r.2;
244 let display: terminal::input_n_display::Display;
245 let _display = grid.fit_into_width(width);
246 let pad: usize;
247 if _display.is_some() && !self.test {
248 display = _display.unwrap(); pad = 4;
250 } else {
251 display = grid.fit_into_columns(1);
252 pad = 5;
253 }
254 let grid_row_count = display.row_count();
255 if (grid_row_count + pad) > height {
256 let mut filter_vec: Vec<usize> = vec![];
260
261 let diff = (grid_row_count + pad).checked_sub(height).unwrap_or(1);
262
263 end = end.checked_sub(diff).unwrap_or(end);
264 let range = start..end;
265
266 range.into_iter().for_each(|i|
267 filter_vec.push(i)
268 );
269
270 self.list.filter = Some(filter_vec);
271 filter = true;
272
273
274 } else {
275 go = false;
276 }
277
278 self.display = Some((self.list.parent_path.clone(), display.to_string()));
279 } else {
280 go = false;
281 }
282 }
283 }
284
285 fn return_file_by_key_mode(&mut self, input: Input, is_fuzzed: bool) {
286 let get_file = |key_string: String| {
287 let key: usize = key_string.parse().unwrap();
288 self.list.get_file_by_key(key, !is_fuzzed).unwrap()
289 };
290
291 let mut n = 0;
292 let mut format_cmd = |key: PathBuf| {
293 n +=1;
294 let file_string = get_file(key.to_str().unwrap().to_string()).to_str().unwrap().to_string();
295 let file_string = file_string.replace(" ", r"\ ");
296 format!(r#"{}={}"#, n, file_string)
297 };
298
299 if let Some (r) = input.args {
300 let _output_vec: Vec<std::process::Output> =
301 r.iter()
302 .map(|key|
303 format_cmd(PathBuf::from(key))
304 ).map(|statement|
305 format!(r#""$(printf '{} \n ')""#, statement)
306 ).map(|cmd|
307 terminal::parent_shell::type_text(
308 cmd,
309 0
310 )
311 ).collect();
312 } else {
313 ()
314 }
315 }
316
317 pub fn filter_mode(&mut self, list: List) {
318 let input_string: String = self.input.display.iter().collect();
319 let mut input_vec_str: Vec<&str> = input_string.split("-").collect();
320 let mut key_vec: Vec<usize> = vec![];
321
322 let last = input_vec_str.iter().last();
324 let mut open_range = false;
325 if let Some(l) = last {
326 if l == &"" {
327 open_range = true;
328 }
329 }
330
331 if open_range {
333 input_vec_str.pop();
334 }
335
336 for i in input_vec_str.into_iter() {
338 let key: Result<usize, std::num::ParseIntError> = i.parse();
339 if key.is_ok() {
340 key_vec.push(key.unwrap());
341 }
342
343 }
344
345 let end: usize;
346 let start = key_vec.clone().into_iter().nth(0).unwrap();
347
348 if open_range {
349 end = list.files.iter().count() + 1;
350 } else {
351 end = key_vec.clone().into_iter().nth(1).unwrap() + 1;
352 }
353
354 let range = start..end;
355
356 let mut filter_vec: Vec<usize> = vec![];
357
358 range.into_iter().for_each(|i|
359 filter_vec.push(i)
360 );
361
362 self.list.filter = Some(filter_vec);
363 self.update_file_display(true);
364 self.run_cmd()
365 }
366
367 pub fn key_mode(&mut self, list: List, input: Input, is_fuzzed: bool) {
368 let key: usize = input.cmd.unwrap().parse().unwrap();
369 match key {
370 0 => {
371 self.list.parent_path.pop();
372 let file_pathbuf = self.list.parent_path.clone();
373 self.list.parent_path.pop();
374 let list = self.list.clone().update(file_pathbuf);
375 self.update(list);
376 self.halt = false;
377 let halt = self.list.filter.is_some();
378 self.update_file_display(halt);
379 if !halt {
380 self.run_cmd();
381 }
382 },
383 _ => {
384 let file_pathbuf = list.get_file_by_key(key, !is_fuzzed).unwrap();
385 if metadata(file_pathbuf.clone()).unwrap().is_dir() {
386 let list = self.list.clone().update(file_pathbuf);
387 self.update(list);
388 self.halt = false;
389 let halt = self.list.filter.is_some();
390 self.update_file_display(halt);
391 if !halt {
392 self.run_cmd();
393 }
394 } else {
395 let file_path =
396 file_pathbuf
397 .to_str().unwrap()
398 .to_string();
399 terminal::shell::spawn(self.default_editor.clone(), vec![file_path]);
400 self.halt = true;
401 self.update_file_display(self.halt);
402 self.run_cmd();
403 }
404 }
405 }
406 }
407
408 fn cmd_mode(&mut self, input: Input) {
409 let args = input.args;
410 if let Some(a) = args {
411 let args = a;
412 let cmd = input.cmd.unwrap();
414 let list_parent_path = self.list.parent_path.clone();
415 let mut path_cache = command_assistors::PathCache::new(
416 list_parent_path.as_path()
417 );
418 path_cache.switch();
419 match cmd.as_str() {
420 _ => {
441 terminal::shell::spawn(cmd.to_string(), args);
442 }
443 }
444 path_cache.switch_back();
445 } else {
446 let as_read = input.as_read.as_str();
447 match as_read {
448 "q" => (),
449 "fzf" => {
450 let mut path_cache = command_assistors::PathCache::new(
451 self.list.parent_path.as_path()
452 );
453 path_cache.switch();
454 let fzf_pathbuf = self.fzf_hook_path.as_ref().expect("fzf fail: no fzf hook path specified");
455 let fzf_path_string = fzf_pathbuf.clone().into_os_string().into_string().unwrap();
456 let file_path = terminal::shell::cmd(fzf_path_string).unwrap();
457 terminal::shell::spawn(self.default_editor.clone(), vec![file_path]);
460 path_cache.switch_back();
461 },
462 "fzc" => {
463 let mut path_cache = command_assistors::PathCache::new(
464 self.list.parent_path.as_path()
465 );
466 path_cache.switch();
467 let fzc_pathbuf = self.fzc_hook_path.as_ref().expect("fzc fail: no fzc hook path specified");
468 let fzc_path_string = fzc_pathbuf.clone().into_os_string().into_string().unwrap();
469 let cmd = terminal::shell::cmd(fzc_path_string).unwrap();
470 let input = Input::new();
471 let input = input.parse(cmd);
472 path_cache.switch_back();
475 self.cmd_mode(input);
476 },
477 "fzd" => {
478 let list_parent_path = self.list.parent_path.clone();
479 let mut path_cache = command_assistors::PathCache::new(
480 list_parent_path.as_path()
481 );
482 path_cache.switch();
483 let fzd_pathbuf = self.fzd_hook_path.as_ref().expect("fzd fail: no fzd hook path specified");
484 let fzd_path_string = fzd_pathbuf.clone().into_os_string().into_string().unwrap();
485 let dir = terminal::shell::cmd(fzd_path_string).unwrap();
486 let mut dir_pathbuf = PathBuf::from(dir);
487 let mut pathbuf_vec: Vec<PathBuf> = vec![];
488 if metadata(dir_pathbuf.clone()).unwrap().is_dir() {
489 loop {
490 if dir_pathbuf != PathBuf::from("") {
491 if dir_pathbuf != PathBuf::from("/") {
492 pathbuf_vec.push(dir_pathbuf.clone());
493 } else {
494 break
495 }
496 } else {
497 break
498 }
499 dir_pathbuf.pop();
500 }
501 for dir_pathbuf in pathbuf_vec.iter().rev() {
502 let list = self.list.clone().update(dir_pathbuf);
503 self.update(list);
504 }
505 self.halt = false;
506 let halt = self.list.filter.is_some();
507 self.update_file_display(halt);
508 }
509 path_cache.switch_back();
510 },
511 "zsh" => {
512 let mut path_cache = command_assistors::PathCache::new(
513 self.list.parent_path.as_path()
514 );
515 path_cache.switch();
516 terminal::shell::spawn("zsh".to_string(), vec![]);
521 path_cache.switch_back();
522 },
523 _ => {
524 let mut path_cache = command_assistors::PathCache::new(
525 self.list.parent_path.as_path()
526 );
527 path_cache.switch();
528 let _output = terminal::shell::cmd(as_read.to_string()).unwrap();
529 path_cache.switch_back();
530 }
531 }
532 }
533 }
534
535 fn open_file_by_key_mode(&mut self, input: Input, is_fuzzed: bool) {
536 let get_file = |key_string: String| {
537 let key: usize = key_string.parse().unwrap();
538 self.list.get_file_by_key(key, !is_fuzzed).unwrap()
539 };
540
541 if let Some (r) = input.args {
550 let _output_vec: Vec<String> =
551 r.iter()
552 .map(|key|
553 get_file(key.to_string())
554 ).map(|file|
555 terminal::shell::cmd(format!("{:?} {:?}", self.default_opener, file)).unwrap()
556 ).collect();
557 } else {
558 ()
559 }
560
561 self.halt = false;
562 let halt = self.list.filter.is_some();
563 self.update_file_display(halt);
564 if !halt {
565 self.run_cmd();
566 }
567 }
568
569 fn key_related_mode(&mut self, input: Result<Option<String>, std::io::Error>, is_fuzzed: bool) {
570 match input {
571 Ok(t) => {
572 if let Some(i) = t {
573 let input = Input::new();
574 let input = input.parse(i);
575 match input.clone().cmd_type.unwrap() {
578 CmdType::SingleKey => {
579 self.key_mode(self.list.clone(), input, is_fuzzed);
580 },
581 CmdType::OpenKeys => {
582 self.open_file_by_key_mode(input, is_fuzzed);
583 },
584 CmdType::MultipleKeys => {
585 self.return_file_by_key_mode(input, is_fuzzed);
591 },
592 CmdType::FilterKeys => {
593 self.filter_mode(self.list.clone());
594 },
595 _ => ()
596 }
597 } else {
598 ()
599 }
600 },
601 Err(_) => ()
602 }
603 }
604
605 fn run_cmd(&mut self) {
611 let mut execute = false;
613 while !execute {
614 let (input,_execute) = self.read_process_chars();
615 execute = _execute;
616 if execute && !self.input.full_backspace {
617 self.key_related_mode(Ok(input), self.is_fuzzed);
618 } else if !execute && self.input.full_backspace {
619 } else {
620 break
621 }
622 self.input.full_backspace = false;
623 }
624 }
625
626 fn test_data_update(&mut self, input: Option<String>) {
627 if self.test == true {
628 if input.is_some() {
629 let hash = sha256(&input.clone().unwrap());
630 let original_dir = self.clone().list.path_history.into_iter().nth(0);
631 if original_dir.is_some() {
632 let mut original_dir = original_dir.unwrap();
633 original_dir.push(".lsk_test_output");
635 let mut file = OpenOptions::new()
636 .write(true)
637 .append(true)
638 .open(original_dir.clone().into_os_string().into_string().unwrap())
639 .unwrap();
640
641 if let Err(e) = writeln!(file, "{}", hash.to_hex_string()) {
642 eprintln!("Couldn't write to file: {}", e);
643 }
644 }
645 }
646 if self.display.is_some() {
647 let hash = sha256(&self.display.clone().unwrap().1);
648 let original_dir = self.clone().list.path_history.into_iter().nth(0);
649
650 if original_dir.is_some() {
651 let mut original_dir = original_dir.unwrap();
652 original_dir.push(".lsk_test_output");
654 let mut file = OpenOptions::new()
655 .write(true)
656 .append(true)
657 .open(original_dir.clone().into_os_string().into_string().unwrap())
658 .unwrap();
659
660 if let Err(e) = writeln!(file, "{}", hash.to_hex_string()) {
661 eprintln!("Couldn't write to file: {}", e);
662 }
663 }
664 }
665 }
666 }
667
668 fn read_process_chars(&mut self) -> (Option<String>, bool) {
669 self.input = Input::new();
670 let stdin = stdin();
671 let stdout = stdout();
672 let stdout = stdout.lock().into_raw_mode().unwrap();
673 let mut screen: AlternateScreen<RawTerminal<StdoutLock>> = AlternateScreen::from(stdout);
674 let stdin = stdin.lock();
675 let mut result: Option<String> = None;
676 let mut is_fuzzed = false;
677 let orig_ls_key = self.clone();
678
679 clear_display(&mut screen);
680
681 let input_string: String = self.input.display.iter().collect();
682 self.test_data_update(Some(input_string));
683 display_files(self.clone(), b"", &mut screen, (0, 3));
684
685 for c in stdin.keys() {
686 self.input.full_backspace;
687 clear_display(&mut screen);
688 let c = c.unwrap();
689
690 self.input.match_event(c);
691 let mut input_string: String = self.input.display.iter().collect();
692 let input = self.input.clone();
693 let first = input.display.iter().nth(0);
694 let input = self.input.clone();
695 let last = input.display.iter().last();
696 let mut _input = self.input.clone();
697
698 let place = (0, 1);
699 if let Some(_) = first {
700
701 if self.input.unwiddle {
702 self.fuzzy_list = self.pre_fuzz_list.clone();
703 if let Some(x) = self.pre_fuzz_list.clone() {
704 self.list = x;
705 }
706 if self.input.full_backspace {
707 *self = orig_ls_key.clone();
708 is_fuzzed = false;
709 }
710 }
711 self.test_data_update(Some(input_string.clone()));
712 display_input(input_string.clone(), &mut screen, place);
713
714 let some_mode = self.mode_parse(input_string.clone());
715
716 if let Some(mode) = some_mode {
717 match mode {
718 Mode::Cmd(_) => {
719 if &last == &Some(&'\n') {
720 self.cmd_read();
721
722 input_string = "".to_string();
724 self.input.display = input_string.chars().collect();
725 clear_display(&mut screen);
726 }
727 },
728 Mode::Work => {
729 if &last == &Some(&'\n') {
730 let path = self.list.parent_path.clone();
731 let path = path.to_str().unwrap();
732 let cmd = format!(r#""$(printf 'cd {} \n ')""#, path).to_string();
733 terminal::parent_shell::type_text(cmd, 0);
734 self.is_fuzzed = false;
735 break
736 } else {
737
738 }
739 },
740 Mode::Fuzzy(fuzzy_mode_input) => {
741 if !is_fuzzed {
742 self.pre_fuzz_list = Some(self.list.clone());
743 }
744 let _show = self.display.clone();
745 let some_keys = parse_keys(fuzzy_mode_input.as_str());
746
747 if let Some(keys) = some_keys {
748 input_string = keys;
749 self.input.display = input_string.chars().collect();
750 } else {
751
752 if self.input.unwiddle {
753 self.fuzzy_list = self.pre_fuzz_list.clone();
754 if let Some(x) = self.pre_fuzz_list.clone() {
755 self.list = x;
756 }
757 }
758
759 if self.input.display.iter().last() != Some(&'\n') {
760 self.fuzzy_update(fuzzy_mode_input);
761 }
762 }
763
764 is_fuzzed = true;
765 }
766 }
767 }
768 }
769
770 if self.input.full_backspace {
783 *self = orig_ls_key.clone();
784 is_fuzzed = false;
785 }
786 self.test_data_update(Some(input_string.clone()));
787 display_files(self.clone(), b"", &mut screen, (0, 3));
788
789 if self.input.display.iter().last() == Some(&'\n') {
790 self.input.display.pop();
791 let input_string: String = self.input.display.iter().collect();
792 result = Some(input_string);
793 self.is_fuzzed = is_fuzzed;
794 if self.is_fuzzed {
795 }
796 break
797 }
798 }
799
800 write!(screen, "{}", termion::cursor::Show).unwrap();
801
802 (result, self.input.execute)
803 }
804
805 pub fn mode_parse(&mut self, mut input: String) -> Option<Mode> {
806 let len = input.len();
807 let mode = if len >= 2 {
808 let mode = input.as_str();
809 if mode == "w\n" {
810 Some(Mode::Work)
811 } else {
812 let mode: String = input.drain(..2).collect();
813 let mode = mode.as_str();
814 match mode {
815 "s " => Some(Mode::Fuzzy(input.clone())),
816 "c " => Some(Mode::Cmd(input.clone())),
817 _ => None
818 }
819 }
820 } else {
821 None
822 };
823
824 mode
825 }
826
827 fn cmd_read(&mut self) -> String {
828 self.input.display.pop();
829 let input_string: String = self.input.display.iter().collect();
830 let cmd_mode = self.mode_parse(input_string.clone()).unwrap(); match cmd_mode {
833 Mode::Cmd(cmd_mode_input) => {
834 let input = Input::new();
835 let input = input.parse(cmd_mode_input);
836
837 match input.clone().cmd_type.unwrap() {
838 CmdType::Cmd => {
839 self.cmd_mode(input);
840 },
841 _ => {}
842 }
843 }
845 _ => { }
846 }
847
848 input_string
849 }
850}
851
852
853fn clear_display(screen: &mut AlternateScreen<RawTerminal<StdoutLock>>) {
854 write!(
855 screen,
856 "{}",
857 termion::clear::All
858 ).unwrap();
859 screen.flush().unwrap();
860}
861
862fn display_input(input_string: String, screen: &mut AlternateScreen<RawTerminal<StdoutLock>>, position: (u16, u16)) {
863 write!(screen,
864 "{}{}{}{}", format!("{}", input_string.as_str()
865 ),
866 termion::clear::AfterCursor,
867 termion::cursor::Goto(position.0, position.1 + 1),
868 termion::cursor::Hide,
869 ).unwrap();
870 screen.flush().unwrap();
871}
872
873fn display_files(ls_key: LsKey, some_stuff: &[u8], screen: &mut AlternateScreen<RawTerminal<StdoutLock>>, position: (u16, u16)) {
874 let show = ls_key.clone().display;
875 if let Some(x) = show {
876 if x.0 == ls_key.list.parent_path {
877 let display = str::replace(x.1.as_str(), "\n", "\n\r");
879 write!(
880 screen,
881 "{}{}{}\n", format!("{}", std::str::from_utf8(&some_stuff).unwrap()),
882 termion::cursor::Goto(position.0, position.1),
883 termion::cursor::Hide,
884
885 ).unwrap();
886 screen.flush().unwrap();
887
888 write!(screen,
889 "{}{}{}{}", format!("{}", display.as_str()
890 ),
891 termion::clear::AfterCursor,
892 termion::cursor::Goto(position.0, position.1 + 1),
893 termion::cursor::Hide,
894 ).unwrap();
895 screen.flush().unwrap();
896
897 write!(
898 screen,
899 "{}",
900 termion::cursor::Goto(0, 3),
901 ).unwrap();
902 screen.flush().unwrap();
903 }
904 }
905}
906
907#[derive(Debug, Clone, PartialEq)]
908pub enum CmdType {
909 SingleKey,
910 MultipleKeys,
911 OpenKeys,
912 FilterKeys,
913 Cmd,
914}
915#[derive(Debug, Clone, PartialEq, Default)]
916pub struct Input {
917 pub cmd: Option<String>,
918 pub args: Option<Vec<String>>,
919 pub as_read: String,
920 pub cmd_type: Option<CmdType>,
921 pub display: Vec<char>,
922 pub execute: bool,
923 pub unwiddle: bool, pub full_backspace: bool,
925}
926
927
928
929impl Input {
930 pub fn new() -> Self {
931 let mut input: Input = Default::default();
932 input.execute = true;
933 input.unwiddle = false;
934 input.full_backspace = false;
935
936 input
937 }
938
939 pub fn match_event(&mut self, c: termion::event::Key) {
940 self.unwiddle = false;
941 match c {
942 Key::Char(c) => {
943 match c {
944 _ => {
945 self.display.push(c);
946 }
947 }
948 }
949 Key::Alt(c) => println!("^{}", c),
950 Key::Ctrl(c) => println!("*{}", c),
951 Key::Esc => println!("ESC"),
952 Key::Left => println!("←"),
953 Key::Right => println!("→"),
954 Key::Up => println!("↑"),
955 Key::Down => println!("↓"),
956 Key::Backspace => {
957 self.unwiddle = true;
958 if self.display.pop().is_some() {
959 let count = self.display.iter().count();
960 if count == 0 {
961 self.execute = false;
962 self.full_backspace = true;
963 }
964 }
965
966 },
967 _ => {}
968 }
969 }
970
971 fn defang_args(&self, args: Vec<String>) -> Option<Vec<String>> {
972 let count = args.clone().iter().count();
973 let empty_item = args.clone().iter().any(|x| *x == "".to_string());
974 let is_valid = if empty_item && count <= 1 {
975 false
976 } else {
977 true
978 };
979
980 if is_valid && count != 0 {
981 Some(args)
982 } else {
983 None
984 }
985 }
986
987 pub fn parse(mut self, input: String) -> Self {
988 let (cmd, args) = self.parse_cmd(input.clone());
989 let is_key = if args == None {
990 let key: Result<usize, std::num::ParseIntError> = cmd.clone().unwrap().parse();
991 match key {
992 Ok(_) => Some(true),
993 Err(_) => Some(false)
994 }
995 } else {
996 Some(false)
997 };
998
999 let is_filter = {
1000 let mut res = false;
1001 let mut input_vec_str: Vec<&str> = input.split("-").collect();
1002
1003 if input_vec_str.iter().count() > 1 {
1005 res = true;
1006 }
1007
1008 if res {
1009 let last = input_vec_str.iter().last();
1011 let mut open_range = false;
1012 if let Some(l) = last {
1013 if l == &"" {
1014 open_range = true;
1015 }
1016 }
1017
1018 if open_range {
1020 input_vec_str.pop();
1021 }
1022
1023 for i in input_vec_str.into_iter() {
1025 let key: Result<usize, std::num::ParseIntError> = i.parse();
1026 if !key.is_ok() {
1027 res = false;
1028 break;
1029 } else {
1030 res = true;
1031 }
1032 }
1033 } res
1036 };
1037
1038
1039 let are_all_keys = if let Some(c) = cmd.clone() {
1040 if c == "r".to_string() {
1041 let _args = args.clone();
1042 if let Some(a) = _args {
1043 self.are_all_keys(a)
1044 }
1045 else {
1046 false
1047 }
1048 } else {
1049 false
1050 }
1051 } else {
1052 false
1053 };
1054
1055 let are_all_keys_open = if let Some(c) = cmd.clone() {
1056 if c == "o".to_string() {
1057 let _args = args.clone();
1058 if let Some(a) = _args {
1059 self.are_all_keys(a)
1060 }
1061 else {
1062 false
1063 }
1064 } else {
1065 false
1066 }
1067 } else {
1068 false
1069 };
1070
1071 let cmd_type = if are_all_keys {
1072 CmdType::MultipleKeys
1073 } else if are_all_keys_open {
1074 CmdType::OpenKeys
1075 } else if is_filter {
1076 CmdType::FilterKeys
1077 } else if let Some(k) = is_key {
1078 if k {
1079 CmdType::SingleKey
1080 } else {
1081 CmdType::Cmd
1082 }
1083 } else if is_filter {
1084 CmdType::FilterKeys
1085 } else {
1086 CmdType::Cmd
1087 };
1088
1089 self.cmd = cmd;
1095 self.args = args;
1096 self.as_read = input;
1097 self.cmd_type = Some(cmd_type);
1098
1099 self
1100 }
1101
1102 fn parse_cmd(&self, input: String) -> (Option<String>, Option<Vec<String>>) {
1103 let mut input: Vec<String> = input.clone().split(" ").map(|s| s.to_string()).collect();
1104 let cmd = input.remove(0);
1105
1106 let args = self.defang_args(input);
1107 (Some(cmd), args)
1108 }
1109
1110 fn are_all_keys(&self, input: Vec<String>) -> bool {
1111 let is_num = |x: &str| {
1112 let res: Result<usize, std::num::ParseIntError> = x.parse();
1113 match res {
1114 Ok(_) => true,
1115 Err(_) => false
1116 }
1117 };
1118 let is_all_nums = !input.iter().any(|x| !is_num(x.as_str()));
1119
1120 is_all_nums
1121 }
1122
1123 }
1135
1136#[derive(Debug, Clone, PartialEq)]
1137pub enum Mode {
1138 Fuzzy(String),
1139 Cmd(String),
1140 Work,
1141}
1142
1143fn parse_keys(input: &str) -> Option<String> {
1144 let x = input;
1145 let mut y: Vec<&str> = x.split(" ").collect();
1146 let mut count = y.iter().count();
1147
1148 let some = if count > 1 {
1149 y.remove(0);
1150
1151 let mut n = 0;
1152 let single_key: bool;
1153 if count == 2 {
1154 single_key = true;
1155 } else {
1156 single_key = false;
1157 }
1158 loop {
1159 y.insert(n, " ");
1160 count = count - 1;
1161 n = n + 2;
1162 if count == 1 {
1163 break
1164 }
1165 }
1166
1167 if single_key {
1168 y.remove(0);
1169 }
1170
1171 let z: String = y.into_iter().collect();
1172
1173 if z == "".to_string() {
1174 None
1175 } else {
1176 Some(z)
1177 }
1178
1179 } else {
1180 None
1181 };
1182
1183 some
1184}
1185
1186#[cfg(test)]
1187mod app_test {
1188 use std::fs::metadata;
1189 use std::path::{Path, PathBuf};
1190 use std::process::Command;
1191 use fixtures::{Fixture, command_assistors};
1192 use termion::terminal_size;
1193 use super::{Input, LsKey, CmdType, Mode};
1194 use super::*;
1195
1196 macro_rules! test {
1197 (
1198 $test_mode_bool: expr, $list_all_bool: expr, $name:ident,
1201 $test_file_path :expr, $delay: expr, $input1: expr,
1204 $input2: expr,
1205 $input3: expr,
1206 $input4: expr,
1207 $input5: expr,
1208 $input6: expr,
1209 $input7: expr,
1210 $sub_path: expr, $intent: expr, $file_hash: expr,
1213 $test_macro: ident ) => {
1215
1216 #[test]
1217 #[$test_macro]
1218 fn $name() {
1219 let path = format!("/tmp/lsk_tests/{}/", $sub_path);
1220
1221 let mut fixture = Fixture::new()
1222 .add_dirpath(path.clone())
1223 .add_dirpath(format!("{}basilides/", path.clone()))
1224 .add_dirpath(format!("{}cyrinus/", path.clone()))
1225 .add_dirpath(format!("{}nabor/", path.clone()))
1226 .add_dirpath(format!("{}nazarius/", path.clone()))
1227 .add_dirpath(format!("{}primus/", path.clone()))
1228 .add_dirpath(format!("{}felician/", path.clone()))
1229 .add_dirpath(format!("{}marcelinus/", path.clone()))
1230 .add_dirpath(format!("{}isidore/", path.clone()))
1231 .add_dirpath(format!("{}margaret/", path.clone()))
1232 .add_dirpath(format!("{}angela/", path.clone()))
1233 .add_dirpath(format!("{}francis/", path.clone()))
1234 .add_dirpath(format!("{}gregory/", path.clone()))
1235 .add_dirpath(format!("{}joseph/", path.clone()))
1236 .add_dirpath(format!("{}anne/", path.clone()))
1237 .add_dirpath(format!("{}joachim/", path.clone()))
1238 .add_dirpath(format!("{}faustina/", path.clone()))
1239 .add_dirpath(format!("{}john/", path.clone()))
1240 .add_dirpath(format!("{}peter/", path.clone()))
1241 .add_dirpath(format!("{}cecilia/", path.clone()))
1242 .add_dirpath(format!("{}rita/", path.clone()))
1243 .add_dirpath(format!("{}magdelene/", path.clone()))
1244 .add_dirpath(format!("{}expeditus/", path.clone()))
1245 .add_dirpath(format!("{}sebastian/", path.clone()))
1246 .add_dirpath(format!("{}gabriel/", path.clone()))
1247 .add_dirpath(format!("{}michael/", path.clone()))
1248 .add_dirpath(format!("{}jude/", path.clone()))
1249 .add_dirpath(format!("{}anthony/", path.clone()))
1250 .add_dirpath(format!("{}nicholaus/", path.clone()))
1251 .add_dirpath(format!("{}teresa/", path.clone()))
1252 .build();
1253
1254 let path_path = Path::new(path.clone().as_str()).to_path_buf();
1255
1256 let mut sample_files_files = PathBuf::from(".fixtures");
1257 sample_files_files.push("sample_files");
1258
1259 let mut path_test = path_path.clone();
1260 path_test.push("sample_files");
1261
1262 let md = metadata(path_test.clone());
1263 let test_path_string = path_test.clone().into_os_string().into_string().unwrap();
1264
1265 if !md.is_ok() {
1266 fixture.build();
1267 Command::new("cp")
1268 .arg("-r".to_string())
1269 .arg(sample_files_files.clone().into_os_string().into_string().unwrap())
1270 .arg(test_path_string.clone())
1271 .output()
1272 .expect("failed to execute lsk process");
1273 }
1274
1275 let mut path_cache = command_assistors::PathCache::new(&path_test);
1276 path_cache.switch();
1278
1279 println!("");
1280 let text_vec = vec![
1281 format!(r#""{}""#, $input1),
1282 format!(r#""{}""#, $input2),
1283 format!(r#""{}""#, $input3),
1284 format!(r#""{}""#, $input4),
1285 format!(r#""{}""#, $input5),
1286 format!(r#""{}""#, $input6),
1287 format!(r#""{}""#, $input7),
1288 ];
1289
1290 if !$test_mode_bool {
1296 let term_size = terminal_size().unwrap();
1297 let term_width = term_size.0;
1298 let term_height = term_size.1;
1299
1300 assert_eq!(term_width, 31);
1301 assert_eq!(term_height, 15);
1302 }
1303
1304 let spawn = super::terminal::parent_shell::type_text_spawn(text_vec, $delay);
1305 let fzf = PathBuf::from("/home/me/.fzf.sh");
1306 let fzc = PathBuf::from("/home/me/.fzc.sh");
1307 let fzd = PathBuf::from("/home/me/.fzd.sh");
1308 let _ls_key = super::app::run(test_path_string.clone(), $list_all_bool, true, Some(fzf), Some(fzc), Some(fzd));
1309 spawn.join().expect("failed to spawn thread");
1310
1311 let mut test_output_path = path_path.clone();
1312 test_output_path.push("sample_files");
1313 test_output_path.push(".lsk_test_output");
1314 let test_output_path_string = test_output_path.clone().into_os_string().into_string().unwrap();
1315 let output_mv_to_path_string = path_path.clone().into_os_string().into_string().unwrap();
1316
1317 Command::new("mv")
1318 .arg(test_output_path_string)
1319 .arg(output_mv_to_path_string.clone())
1320 .output()
1321 .expect("failed to execute lsk process");
1322
1323 let few_ms = std::time::Duration::from_millis(100);
1324 std::thread::sleep(few_ms);
1325
1326 let mut output_mv_to_path = path_path.clone();
1327 output_mv_to_path.push(".lsk_test_output");
1328 let output_mv_to_path_string = output_mv_to_path.clone().into_os_string().into_string().unwrap();
1329
1330 println!("\npath:\n{}", output_mv_to_path_string.clone());
1331
1332 let file256 = file_sha256(output_mv_to_path_string.clone());
1333
1334 match file256 {
1335 Ok(h) => {
1336 assert_eq!(
1337 h.to_hex_string(),
1338 $file_hash.to_string()
1339 )
1340 },
1341 Err(..) => assert!(false)
1342 }
1343
1344 path_cache.switch_back();
1345
1346 std::fs::remove_file(output_mv_to_path_string).unwrap();
1347 }
1348 };
1349 }
1350
1351 test!(
1352 true, false, macro_fzc_enter_file,
1355 "Makefile",
1356 100, "$(printf 'c fzc\r')", "$(printf 'vimread\r')","$(printf ':q\r')", "$(printf 'q\r')", "", "", "", "macro_fzc_enter_file",
1365 ">Run lsk\n>Open file using vim with fzc hook\n>Quite vim\n>Quite lsk",
1366 "64e1b450ebdc532da6ebd5b11df4347d67b48405aa166b05800180e1a1136bf2",
1367 ignore);
1369
1370 test!(
1371 false, false, macro_term_size_enter_file,
1374 "Makefile",
1375 100, "$(printf '5\r')", "$(printf ':q\r')","$(printf 'q\r')", "", "", "", "", "macro_enter_file",
1384 ">Run lsk\n>Open file by key (2)\n>Quite vim\n>Quite lsk",
1385 "dab8010a2c67e6986aa511180b41132058be77ad72a9c9c5fc076e371dccf584",
1386 ignore);
1388
1389 test!(
1390 true, false, macro_enter_file,
1393 "Makefile",
1394 100, "$(printf '5\r')", "$(printf ':q\r')","$(printf 'q\r')", "", "", "", "", "macro_enter_file",
1403 ">Run lsk\n>Open file by key (2)\n>Quite vim\n>Quite lsk",
1404 "99150c8a4c5960ee34cfbbb8393a65a9fe1c544394c1d02bf6a0a5cf0ad9b6a9",
1405 ignore);
1407
1408 test!(
1409 true, true, macro_enter_file_list_all,
1412 ".eternal",
1413 100, "$(printf '2\r')", "$(printf ':q\r')","$(printf 'q\r')", "", "", "", "", "macro_enter_file_list_all",
1422 ">Run lsk\n>Open hidden file by key (2)\n>Quite vim\n>Quite lsk",
1423 "e539e2c5a37d677c59fd71ca1739ae398ed467fc9dd506ec2512533f5d070ae4",
1424 ignore);
1426
1427 test!(
1428 true, false,
1430 macro_fuzzy_enter_file,
1431 "intercession",
1432 100, "$(printf 's boo\r')",
1434 "$(printf '4\r')",
1435 "$(printf ':q\r')",
1436 "$(printf 'q\r')",
1437 "",
1438 "",
1439 "",
1440 "macro_fuzzy_enter_file",
1441 ">Run lsk\n>Fuzzy widdle\n>Open file by key (1)\n>Quite vim\n>Quite lsk",
1442 "d7e51ab94b12bcb1773b2a92d0b4dec550c38f845add73850347a8bd03cc8f49",
1443 ignore);
1445
1446 test!(
1447 true, false,
1449 macro_fuzzy_enter_dir,
1450 "a-file",
1451 100, "$(printf 's ins\r')",
1453 "$(printf '4\r')",
1454 "$(printf 'q\r')",
1455 "",
1456 "",
1457 "",
1458 "",
1459 "macro_fuzzy_enter_dir",
1460 ">Run lsk\n>Fuzzy widdle\n>Open dir by key (1)\n>Quite vim\n>Quite lsk",
1461 "9127fec0401b363161da1931c49795066cb21a98fd025be9816655019be48b2f",
1462 ignore);
1464
1465 test!(
1466 true, false,
1468 macro_fuzzy_enter_dir_go_back_then_repeat,
1469 "a-file",
1470 100, "$(printf 's do\r')",
1472 "$(printf '2\r')",
1473 "$(printf '0\r')",
1474 "$(printf 's do\r')",
1475 "$(printf '2\r')",
1476 "$(printf 'q\r')",
1477 "",
1478 "macro_fuzzy_enter_dir",
1479 ">Run lsk\n>Fuzzy widdle\n>Open dir by key (1)\n>Go back (0) and repeat\n>Quite vim\n>Quite lsk",
1480 "27a1709e1aaa369079a83d411e082c22bccca5987b008d71865e091864264e9f",
1481 ignore);
1483
1484 test!(
1485 true, false,
1487 macro_go_back_fuzzy_enter_back_into_dir,
1488 "a-file",
1489 100, "$(printf '0\r')",
1491 "$(printf 's sa\r')",
1492 "$(printf '2\r')",
1493 "$(printf 'q\r')",
1494 "",
1495 "",
1496 "",
1497 "macro_go_back_fuzzy_enter_back_into_dir",
1498 ">Run lsk\n>Go back (0)\n>Fuzzy widdle\n>Open back into original dir by key (2)\n>\n>Quite lsk",
1499 "399976731f562f608d1d4c04afc1fa4f8f3530acf8683c39917d8771afebe5d1",
1500 ignore);
1502
1503 test!(
1504 true, false,
1506 macro_walk_in_park,
1507 "a-file",
1508 100, "$(printf '24\r')",
1510 "$(printf '1\r')",
1511 "$(printf 's con\r')",
1512 "$(printf '2\r')",
1513 "$(printf ':q\r')",
1514 "$(printf 'q\r')",
1515 "",
1516 "macro_walk_in_park",
1517 ">Run lsk\n>Go back (0)\n>Fuzzy widdle\n>Open back into original dir by key (2)\n>\n>Quite lsk",
1518 "668f2e7980c6260f572e837375b1e4a2beea20d3683b5293f0b968f00a4e68b0",
1519 ignore);
1521
1522 test!(
1523 true, false, macro_fuzzy_backspace,
1526 "Makefile",
1527 100,
1528 "s itf",
1529 "BackSpace",
1530 "BackSpace",
1531 "BackSpace",
1532 "BackSpace",
1533 "BackSpace",
1534 "q\r",
1535 "macro_fuzzy_backspace",
1536 ">Run lsk\n>OFuzzy widdle (2)\n>Backspace fully (bad behavior)\n>Quite lsk",
1537 "ee86f4888a18c074a2df32a467ee94027ea5f437d0fede8125e3526e07ee8147",
1538 ignore);
1540
1541 test!(
1542 true, false, macro_bad_fuzzy_backspace_enter,
1545 "Makefile",
1546 100,
1547 "s itf",
1548 "BackSpace",
1549 "BackSpace",
1550 "",
1551 "",
1552 "\r",
1553 "q\r",
1554 "macro_bad_fuzzy_backspace_enter",
1555 ">Run lsk\n>OFuzzy widdle (2)\n>Backspace partially (bad behavior)\n>Quite lsk",
1556 "83f5005ed89aca8834f69b3e064afca283c3ec6f90000e6e902473e1a582d11c",
1557 ignore);
1559
1560 test!(
1561 true, false, macro_file_range,
1564 "Makefile",
1565 100,
1566 "20-25\r",
1567 "24\r",
1568 "1\r",
1569 "11\r",
1570 "",
1571 ":q\r",
1572 "q\r",
1573 "macro_file_range",
1574 ">Run lsk\n>List range 20-25\n>Enter rust dir\nEnter redox dir\n>Open filesystem.toml\n>Quite Vim\n>Quite lsk",
1575 "f5f1e7f641b5f348080ca2f86c0dffa8530cfab308cd9ec61d4cb9b8fa4cf3b7",
1576 ignore);
1578
1579 test!(
1580 true, true, macro_list_all_fuzzy_file_range,
1583 "Makefile",
1584 100,
1585 "s m\r",
1586 "1-10\r",
1587 "10\r",
1588 "9\r",
1589 ":q\r",
1590 "0\r",
1591 "q\r",
1592 "macro_list_all_all_file_range",
1593 ">Run lsk\n>List all\n>Fuzzy search 'm'\n>List range 1-10\n>Enter mk dir\n>Open qemu.mk\n>Quite Vim\n>Go back/up a dir level\n>Quite lsk",
1594 "0eea81e276ad3766422bf859f4d9d3e76b84ef11e9d5233fe1aa206f8115e4f8",
1595 ignore);
1597
1598 test!(
1599 true, true, macro_list_all_fuzzy_undo_open_range,
1602 "Makefile",
1603 100,
1604 "s i\r",
1605 "5-17\n",
1606 "7-\r",
1607 "17\r",
1608 ":q\r",
1609 "1-\n",
1610 "q\r",
1611 "macro_list_all_fuzzy_undo_open_range",
1612 ">Run lsk\n>List all\n>Fuzzy search 'i'\n>List range 5 - 17.\n>List range 7 open-ended\n>Open last one, key 17\n>Quite Vim\n>List entire range, 1-\n>Quite lsk",
1613 "83796531204cd54871410774f6858b0e79b2e291eb7c0a77b06a1314bca8ebd7",
1614 ignore);
1616
1617 test!(
1618 true, true, macro_list_all_fuzzy_dir,
1621 "Makefile",
1622 100,
1623 "s i\r",
1624 "c fzd\r",
1625 "redoxgitl\r",
1626 "1\r",
1627 "1\r",
1628 ":q\r",
1629 "q\r",
1630 "macro_list_all_fuzzy_dir",
1631 ">Run lsk\n>List all\n>Fuzzy search 'i'\n>List range 5 - 17.\n>List range 7 open-ended\n>Open rust-toolchain fie with command vim\n>Quite Vim\n>List entire range, 1-\n>Quite lsk",
1632 "20fc38f75c6739dbce70e86974cc2b7f58f8212279c47f05fe29f639ab1977f7",
1633 ignore);
1635
1636 test!(
1639 true, true, macro_bad_list_all_fuzzy_dir,
1642 "Makefile",
1643 100,
1644 "s i\r",
1645 "7-\n",
1646 "c fzd\r",
1647 "bin\r",
1648 "1\r",
1649 ":q\r",
1650 "q\r",
1651 "macro_list_all_fuzzy_dir",
1652 ">Run lsk\n>List all\n>Fuzzy search 'i'\n>List range 5 - 17.\n>List range 7 open-ended\n>Open bind dir fzd command, but main.rs doesn't show.\n>Quite lsk",
1653 "9d2896a092c094c6073fe65408d38aa5d672dccf3f34597174774d8098194075",
1654 ignore);
1656
1657
1658 #[test]
1659 #[ignore]fn parse() {
1661 let input = Input::new();
1662 let input = input.parse("vim Cargo.toml".to_string());
1663
1664 assert_eq!(
1665 Some(CmdType::Cmd),
1666 input.cmd_type
1667 );
1668
1669 assert_eq!(
1670 Some("vim".to_string()),
1671 input.cmd
1672 );
1673
1674 assert_eq!(
1675 Some(vec!["Cargo.toml".to_string()]),
1676 input.args
1677 );
1678 }
1679
1680 #[test]
1681 #[ignore]fn parse_long() {
1683 let input = Input::new();
1684 let input = input.parse("git clone https://github.com/7db9a/ls-key --depth 1".to_string());
1685
1686 assert_eq!(
1687 Some(CmdType::Cmd),
1688 input.cmd_type
1689 );
1690
1691 assert_eq!(
1694 Some("git".to_string()),
1695 input.cmd
1696 );
1697
1698 assert_eq!(
1699 Some(vec![
1700 "clone".to_string(),
1701 "https://github.com/7db9a/ls-key".to_string(),
1702 "--depth".to_string(),
1703 "1".to_string()
1704 ]),
1705 input.args
1706 );
1707 }
1708
1709 #[test]
1710 #[ignore]fn parse_single_cmd() {
1712 let input = Input::new();
1713 let input = input.parse("vim".to_string());
1714
1715 assert_eq!(
1716 Some(CmdType::Cmd),
1717 input.cmd_type
1718 );
1719
1720 assert_eq!(
1721 Some("vim".to_string()),
1722 input.cmd
1723 );
1724
1725 assert_eq!(
1726 None,
1727 input.args
1728 );
1729 }
1730
1731 #[test]
1732 #[ignore]fn parse_key() {
1734 let input = Input::new();
1735 let input = input.parse("33".to_string());
1736
1737 assert_eq!(
1738 Some(CmdType::SingleKey),
1739 input.cmd_type
1740 );
1741
1742 assert_eq!(
1743 Some("33".to_string()),
1744 input.cmd
1745 );
1746
1747 assert_eq!(
1748 None,
1749 input.args
1750 );
1751 }
1752
1753 #[test]
1754 #[ignore]fn parse_bad() {
1756 let input = Input::new();
1757 let input = input.parse(" vim Cargo.toml".to_string());
1758
1759 assert_eq!(
1760 Some(CmdType::Cmd),
1761 input.cmd_type
1762 );
1763
1764 assert_eq!(
1765 Some("".to_string()),
1766 input.cmd
1767 );
1768
1769 assert_eq!(
1770 None,
1771 input.args
1772 );
1773 }
1774
1775 #[test]
1776 #[ignore]fn parse_cmd() {
1778 let input = Input::new();
1779 let (cmd, args) = input.parse_cmd("vim Cargo.toml".to_string());
1780
1781 assert_eq!(
1782 cmd,
1783 Some("vim".to_string())
1784 );
1785
1786 assert_eq!(
1787 args,
1788 Some(vec!["Cargo.toml".to_string()])
1789 )
1790 }
1791
1792 #[test]
1813 #[ignore]fn test_mode_parse() {
1815 let mut ls_key = LsKey::new("/tmp", false, false, None, None, None);
1816 let input_single = "s something".to_string();
1817 let some_fuzzy_search_single = ls_key.mode_parse(input_single.clone());
1818
1819 let input_multi = "s something and more".to_string();
1820 let some_fuzzy_search_multi = ls_key.mode_parse(input_multi.clone());
1821
1822 let input_invalid = "sd".to_string();
1823 let some_fuzzy_search_invalid = ls_key.mode_parse(input_invalid.clone());
1824
1825 let input_lack_more = "s".to_string();
1826 let some_fuzzy_search_lack_more = ls_key.mode_parse(input_lack_more.clone());
1827
1828 let input_wrong = "d something".to_string();
1829 let some_fuzzy_search_wrong = ls_key.mode_parse(input_wrong.clone());
1830
1831 assert_eq!(
1832 some_fuzzy_search_invalid,
1833 None
1834 );
1835
1836 assert_eq!(
1837 some_fuzzy_search_lack_more,
1838 None
1839 );
1840
1841 assert_eq!(
1842 some_fuzzy_search_single,
1843 Some(Mode::Fuzzy("something".to_string()))
1844 );
1845
1846 assert_eq!(
1847 some_fuzzy_search_multi,
1848 Some(Mode::Fuzzy("something and more".to_string()))
1849
1850 );
1851
1852 assert_eq!(
1853 some_fuzzy_search_wrong,
1854 None
1855 );
1856 }
1857
1858 #[test]
1859 #[ignore]fn test_bad_mode_parse() {
1861 let mut ls_key = LsKey::new("/tmp", false, false, None, None, None);
1862
1863 let input_lack = "s ".to_string();
1864 let some_fuzzy_search_lack = ls_key.mode_parse(input_lack.clone());
1865
1866 assert_eq!(
1867 some_fuzzy_search_lack,
1868 None
1869 );
1870 }
1871}