use anyhow::Result;
use miniserde::{json, Deserialize, Serialize};
use std::{
fmt::{self, Display},
path::{Path, PathBuf},
};
pub mod setup;
pub struct Completions {
pub completions: Vec<String>,
}
impl Display for Completions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
let last = self.completions.len() - 1;
for (index, completion) in self.completions.iter().enumerate() {
if index == last {
write!(f, "{}", completion)?;
} else {
writeln!(f, "{}", completion)?;
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CompletionData {
#[serde(rename = "cli-name")]
pub cli_name: String,
pub commands: Option<Vec<CompletionItem>>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CompletionItem {
pub name: String,
pub flags: Vec<String>,
}
pub struct Completer {
pub completion_data: CompletionData,
pub config_path: PathBuf,
}
impl Completer {
pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Completer> {
let text = std::fs::read_to_string(&config_path).unwrap();
let completion_data = json::from_str::<CompletionData>(&text)?;
let completer = Completer {
config_path: config_path.as_ref().to_owned(),
completion_data,
};
Ok(completer)
}
pub fn from<P: AsRef<Path>>(p: P) -> Result<Completer> {
Self::new(p.as_ref().to_owned())
}
pub fn get_completions(&self) -> Completions {
let args = std::env::args().collect::<Vec<String>>();
let mut completions = vec![];
if args.len() > 2 {
let current_word = args[2].replace("--word=", "");
let mut line = args[4].to_string();
let position = args[6].parse::<u64>().unwrap();
if position > line.len() as u64 {
line.push_str(" ");
}
let split = line.split(" ").collect::<Vec<&str>>();
match split.len() {
2 => {
if current_word == "" {
for command in self.completion_data.commands.as_ref().unwrap().iter() {
completions.push(command.name.to_string());
}
} else {
for command in self.completion_data.commands.as_ref().unwrap().iter() {
if command.name.starts_with(¤t_word) {
completions.push(command.name.to_string());
}
}
}
}
_ => {
if current_word.starts_with("--") || current_word == "" {
for command in self.completion_data.commands.as_ref().unwrap().iter() {
if command.name == split[1] {
for flag in command.flags.iter() {
if flag.starts_with(¤t_word) {
completions.push(flag.to_string());
}
}
}
}
}
}
}
}
Completions { completions }
}
pub fn install(&self) -> Result<()> {
setup::install(&self)?;
Ok(())
}
pub fn display_completions(completions: &Vec<String>) {
for completion in completions.iter() {
println!("{}", completion);
}
}
}