lnchr 0.2.2

A fuzzy terminal app launcher
use directories::ProjectDirs;
use std::{
    fs::{self, create_dir_all},
    path::PathBuf,
};

fn data_dir() -> Option<PathBuf> {
    ProjectDirs::from("", "", "lnchr").map(|d| d.data_dir().to_owned())
}

pub struct History {
    path: PathBuf,
    items: Vec<String>,
}

impl History {
    pub fn items(&self) -> &[String] {
        &self.items
    }

    pub fn from_title(title: &str) -> Option<Self> {
        let path = data_dir()?.join(format!("{title}.history"));

        if !path.exists() {
            return Some(Self {
                path,
                items: Vec::new(),
            });
        }

        let items: Vec<String> = match fs::read_to_string(&path) {
            Ok(t) => t.lines().map(|line| line.to_string()).collect(),
            Err(e) => {
                eprintln!("{e}");
                return None;
            }
        };

        Some(Self { path, items })
    }

    pub fn do_sort(&self, names: &mut Vec<String>) {
        for item in self.items.iter().rev() {
            if let Some(pos) = names.iter().position(|x| x == item) {
                names.remove(pos);
                names.insert(0, item.to_string());
            }
        }
    }

    pub fn save(&mut self, new_item: &str) {
        if let Err(e) = create_dir_all(self.path.parent().unwrap()) {
            eprintln!("{e}");
            return;
        }

        match self.items.iter().position(|x| x == new_item) {
            Some(index) => {
                self.items.remove(index);
                self.items.insert(0, new_item.to_string());
            }
            None => {
                self.items.insert(0, new_item.to_string());
            }
        }

        if let Err(e) = fs::write(&self.path, self.items.join("\n")) {
            eprintln!("{e}");
        }
    }
}