use super::query::QueryKey;
use super::query::QueryProvider;
use crate::models::context::ContextModel;
use crate::utils;
use anyhow::Result;
use std::path::Path;
use std::path::PathBuf;
pub struct ProjectPathProvider {
raw_value: Option<String>,
}
impl ProjectPathProvider {
pub fn new(raw_value: Option<String>) -> Self {
Self { raw_value }
}
fn find_project_root(start: &Path) -> Option<PathBuf> {
let home = dirs::home_dir();
let mut current = start.parent();
while let Some(dir) = current {
let has_marker = [
".git",
".hg",
"Cargo.toml",
"package.json",
"go.mod",
"pom.xml",
"build.gradle",
".idea",
]
.iter()
.any(|marker| dir.join(marker).exists());
if has_marker {
return Some(dir.to_path_buf());
}
if let Some(ref home) = home {
if dir == home.as_path() {
return None;
}
}
current = dir.parent();
}
None
}
}
impl QueryProvider for ProjectPathProvider {
fn key(&self) -> QueryKey {
QueryKey::ProjectPath
}
fn resolve(&self) -> Result<ContextModel> {
let start_path =
if let Some(raw) = self.raw_value.as_deref().filter(|v| !v.trim().is_empty()) {
let parsed = utils::clipboard::parse_uri_list(raw);
if let Some(first) = parsed.first() {
utils::path::resolve(first)?
} else {
utils::path::resolve(Path::new(raw.trim()))?
}
} else {
std::env::current_dir()?
};
let project_root = if start_path.is_dir() {
start_path
} else {
Self::find_project_root(&start_path).unwrap_or_default()
};
Ok(ContextModel::String(
project_root.to_string_lossy().into_owned(),
))
}
}