1use clap::{command, Arg, ArgMatches};
2use std::fs::read_dir;
3use std::path::{Path, PathBuf};
4
5pub fn args_handler() -> ArgMatches {
7 let match_results: ArgMatches = command!()
8 .about("A simple CLI tool to quickly leap to a directory")
9 .arg(Arg::new("target").required(true))
10 .arg(
11 Arg::new("up")
12 .action(clap::ArgAction::SetTrue)
13 .short('u')
14 .long("up")
15 .help("Leap upwards to Parent directories without following any subfolders"),
16 )
17 .arg(
18 Arg::new("path")
19 .action(clap::ArgAction::SetTrue)
20 .short('p')
21 .long("path")
22 .help("Return Path without leaping"),
23 )
24 .get_matches();
25
26 match_results
27}
28
29pub fn get_entries(path: &Path, is_upward: bool) -> Option<Vec<PathBuf>> {
31 dir_collect_entries(path, is_upward)
32}
33
34pub fn find(mut entries: Vec<PathBuf>, target: &str, is_upward: bool) -> Option<PathBuf> {
36 let mut found = find_target(&entries, target);
37
38 while found.is_none() {
39 if let Some(unsearched_entries) = follow(&entries, is_upward) {
40 found = find_target(&unsearched_entries, target);
41 entries = unsearched_entries;
42 } else {
43 return None;
45 }
46 }
47
48 if found.is_some() {
49 return Some(found.unwrap().to_path_buf());
50 }
51
52 None
53}
54
55pub fn follow(entries: &[PathBuf], is_upward: bool) -> Option<Vec<PathBuf>> {
57 let mut unsearched_entries: Vec<PathBuf> = Vec::new();
58
59 for e in entries {
61 if e.is_dir() {
63 if is_upward {
64 if e.parent().is_some() {
65 return Some(vec![e.parent().unwrap().to_path_buf()]);
66 }
67 }
68
69 if let Some(sub_entries) = get_entries(e.as_path(), is_upward) {
70 for se in sub_entries {
71 unsearched_entries.push(se);
72 }
73 }
74 }
75 }
76
77 if unsearched_entries.is_empty() {
78 return None;
79 }
80
81 Some(unsearched_entries)
82}
83
84fn find_target(entries: &[PathBuf], target: &str) -> Option<PathBuf> {
85 for e in entries {
86 if e.to_string_lossy().ends_with(target) {
87 return Some(e.to_path_buf());
88 }
89 }
90
91 None
92}
93
94fn dir_collect_entries(mut input_dir: &Path, upward: bool) -> Option<Vec<PathBuf>> {
95 if input_dir.parent().is_none() {
96 return None;
97 }
98
99 input_dir = match upward {
100 true => input_dir.parent().unwrap(),
101 false => input_dir,
102 };
103
104 let mut entries = Vec::new();
105
106 match read_dir(input_dir) {
107 Ok(dirs) => {
108 for entry in dirs {
109 match entry {
110 Ok(e) => {
111 entries.push(e.path());
112 }
113 Err(err) => println!("{}", err),
114 }
115 }
116 }
117 Err(err) => {
118 println!("{}", err);
119 }
120 }
121
122 Some(entries)
123}