use super::super::{
directory, script,
types::CommandType,
};
use super::builtins::BUILTIN_COMMANDS;
use std::{fs, io, path::PathBuf};
pub fn complete(
command_directory_path: &str,
shell: &str,
args: &[String],
) -> Result<String, String> {
let mut target = PathBuf::from(&command_directory_path);
let mut is_file = false;
let mut args_peekable = args.iter().peekable();
if let Some(subcommand) = args_peekable.peek() {
if BUILTIN_COMMANDS.get(*subcommand).is_some() {
return Ok(String::new());
}
}
while let Some(arg) = args_peekable.peek() {
target.push(arg);
if let Some(resolved) = script::resolve_source_path(&target) {
target = resolved;
is_file = true;
args_peekable.next();
break;
} else if target.is_dir() {
args_peekable.next();
} else {
target.pop();
break;
}
}
let remaining_args: Vec<_> = args_peekable.collect();
return match is_file {
false => {
let ignorer = directory::TomeIgnorer::new(std::path::Path::new(command_directory_path));
let paths_raw: io::Result<_> = fs::read_dir(target.to_str().unwrap());
let mut paths: Vec<_> = match paths_raw {
Err(_a) => return Err("Invalid argument to completion".to_string()),
Ok(a) => a,
}
.filter_map(|r| match r {
Ok(path_buf) => {
let path = path_buf.path();
if ignorer.is_ignored(&path) {
return None;
}
if path.is_file() && !script::is_tome_script(&path) {
return None;
}
let name = path.file_name().unwrap().to_str().unwrap_or("").to_owned();
Some(script::strip_source_suffix(&name).to_owned())
}
Err(_) => None,
})
.collect();
if target.to_str().unwrap() == command_directory_path {
for command in BUILTIN_COMMANDS.keys() {
paths.push(command.to_owned());
}
}
paths.sort_by_key(|f| f.to_owned());
Ok(paths.join(" "))
}
true => match script::Script::load(target.to_str().unwrap_or_default()) {
Ok(script) => {
script.get_execution_body(CommandType::Completion, shell, &remaining_args)
}
Err(error) => return Err(format!("IOError loading file: {:?}", error)),
},
};
}