use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use super::{expand_tilde, find_ancestor_dir, Config};
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct SkillsConfig {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub search: Vec<String>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub bundled_dir: String,
}
impl Config {
#[must_use]
pub fn skill_search_dirs(&self) -> Vec<PathBuf> {
let cwd = std::env::current_dir().ok();
self.skill_search_dirs_with(cwd.as_deref(), |p| p.is_dir())
}
#[must_use]
pub fn skill_install_dir(&self) -> Option<PathBuf> {
match self.skills.as_ref().and_then(|s| s.search.first()) {
Some(first) => Some(expand_tilde(first)),
None => Self::user_config_dir().map(|dir| dir.join("skills")),
}
}
pub(super) fn skill_search_dirs_with(
&self,
cwd: Option<&Path>,
is_dir: impl Fn(&Path) -> bool,
) -> Vec<PathBuf> {
let skills = self.skills.as_ref();
let mut dirs: Vec<PathBuf> = match skills.filter(|s| !s.search.is_empty()) {
Some(s) => s.search.iter().map(|d| expand_tilde(d)).collect(),
None => vec![self
.skill_install_dir()
.unwrap_or_else(|| PathBuf::from(".newt/skills"))],
};
let bundled = skills
.map(|s| s.bundled_dir.as_str())
.filter(|d| !d.is_empty())
.map(expand_tilde)
.or_else(|| {
cwd.and_then(|cwd| {
find_ancestor_dir(cwd, Path::new(".newt/bundled-skills"), &is_dir)
})
});
dirs.extend(bundled);
dirs
}
}