use std::path::Path; use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher}; use requestty::question::{completions, Completions}; fn auto_complete(p: String) -> Completions { let current: &Path = p.as_ref(); let (mut dir, last) = if p.ends_with('/') { (current, "") } else { let dir = current.parent().unwrap_or_else(|| "/".as_ref()); let last = current .file_name() .and_then(std::ffi::OsStr::to_str) .unwrap_or(""); (dir, last) }; if dir.to_str().unwrap().is_empty() { dir = ".".as_ref(); } let mut files: Completions<_> = match dir.read_dir() { Ok(files) => files .flatten() .flat_map(|file| { let path = file.path(); let is_dir = path.is_dir(); match path.into_os_string().into_string() { Ok(s) if is_dir => Some(s + "/"), Ok(s) => Some(s), Err(_) => None, } }) .collect(), Err(_) => { return completions![p]; } }; if files.is_empty() { return completions![p]; } let fuzzer = SkimMatcherV2::default(); files.sort_by_cached_key(|file| fuzzer.fuzzy_match(file, last).unwrap_or(i64::MAX)); files } fn main() { let question = requestty::Question::input("a") .message("Enter a file") .auto_complete(|p, _| auto_complete(p)) .validate(|p, _| { if (p.as_ref() as &Path).exists() { Ok(()) } else { Err(format!("file `{}` doesn't exist", p)) } }) .build(); println!("{:#?}", requestty::prompt_one(question)); }