1mod choice;
2mod cli;
3mod init;
4mod navigation;
5mod view;
6
7use clap::Parser;
8use std::{
9 error::Error,
10 io::{self, Write},
11};
12
13use choice::{Choice, commands_hint, out_of_range_message};
14use cli::{Args, Command};
15use init::init_script;
16use navigation::list_directories;
17use view::View;
18
19pub fn run() -> Result<(), Box<dyn Error>> {
20 let args = Args::parse();
21
22 if let Some(Command::Init { shell }) = args.command {
23 println!("{}", init_script(shell));
24 return Ok(());
25 }
26
27 if let Some(start_dir) = args.start_dir {
28 std::env::set_current_dir(&start_dir)?;
29 }
30
31 let use_color = !args.no_color && std::env::var_os("NO_COLOR").is_none();
32 let view = View::new(use_color);
33
34 loop {
35 view.clear();
36
37 let current_dir = std::env::current_dir()?;
38 let choices = list_directories(¤t_dir, args.show_hidden)?;
39
40 view.muted(&format!("Path: {}", current_dir.display()));
41 view.muted(&format!("{}\n", commands_hint(choices.len())));
42
43 if choices.is_empty() {
44 view.muted("No subdirectories found.");
45 } else {
46 for (index, choice) in choices.iter().enumerate() {
47 view.row(index + 1, &choice.name);
48 }
49 }
50
51 let choice = prompt_choice(&view, choices.len())?;
52
53 match choice {
54 Choice::Quit => {
55 view.clear();
56 println!("{}", current_dir.display());
57 io::stdout().flush()?;
58 return Ok(());
59 }
60 Choice::Back => {
61 if let Some(parent) = current_dir.parent() {
62 std::env::set_current_dir(parent)?;
63 }
64 }
65 Choice::Select(index) => {
66 if let Some(selected) = choices.get(index - 1) {
67 std::env::set_current_dir(&selected.path)?;
68 } else {
69 view.warn(&out_of_range_message(choices.len()));
70 }
71 }
72 }
73 }
74}
75
76fn prompt_choice(view: &View, max_choice: usize) -> io::Result<Choice> {
77 loop {
78 view.prompt("> ");
79 io::stdout().flush()?;
80
81 let mut raw = String::new();
82 io::stdin().read_line(&mut raw)?;
83
84 match raw.parse::<Choice>() {
85 Ok(Choice::Select(value)) if value > max_choice => {
86 view.warn(&out_of_range_message(max_choice));
87 }
88 Ok(choice) => return Ok(choice),
89 Err(_) => view.warn("Enter a number, [b], or [q]."),
90 }
91 }
92}