pub mod github;
pub mod stdio;
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Capabilities {
pub orgs: bool,
pub code_search: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SearchItem {
Repo(String),
Org(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TreeNode {
pub path: String,
pub is_dir: bool,
pub sha: String,
pub size: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct TreeResult {
pub entries: Vec<TreeNode>,
pub truncated: bool,
pub branch: String,
}
#[derive(Debug, Clone)]
pub struct CodeMatch {
pub repo: String,
pub path: String,
pub sha: String,
pub branch: String,
pub matches: Vec<String>,
}
pub trait Provider: Send + Sync {
fn name(&self) -> &str;
fn capabilities(&self) -> Capabilities;
fn default_orgs(&self) -> Vec<String> {
Vec::new()
}
fn search(&self, query: &str) -> Result<Vec<SearchItem>, String>;
fn org_repos(&self, org: &str) -> Result<Vec<String>, String>;
fn fetch_tree(&self, repo: &str) -> Result<TreeResult, String>;
fn fetch_blob(&self, repo: &str, sha: &str) -> Result<Vec<u8>, String>;
fn search_code(&self, q: &str) -> Result<Vec<CodeMatch>, String>;
fn clone_url(&self, repo: &str) -> Result<String, String>;
fn web_url(
&self,
repo: &str,
path: &str,
branch: &str,
line: Option<u32>,
is_file: bool,
) -> Result<String, String>;
fn org_url(&self, org: &str) -> Result<String, String>;
}
pub fn build(config: &crate::config::Config) -> (Arc<dyn Provider>, Option<String>) {
match config.provider.kind.as_str() {
"github" => (
Arc::new(github::GitHubProvider::new(config.cache.max_mb)),
None,
),
"stdio" => match stdio::StdioProvider::spawn(&config.provider.command) {
Ok(p) => (Arc::new(p), None),
Err(e) => (
Arc::new(github::GitHubProvider::new(config.cache.max_mb)),
Some(format!("provider stdio failed ({e}); fell back to github")),
),
},
other => (
Arc::new(github::GitHubProvider::new(config.cache.max_mb)),
Some(format!("unknown provider kind {other:?}; using github")),
),
}
}
pub fn offline() -> Arc<dyn Provider> {
struct Offline;
impl Provider for Offline {
fn name(&self) -> &str {
"offline"
}
fn capabilities(&self) -> Capabilities {
Capabilities {
orgs: false,
code_search: false,
}
}
fn search(&self, _: &str) -> Result<Vec<SearchItem>, String> {
Err("offline".into())
}
fn org_repos(&self, _: &str) -> Result<Vec<String>, String> {
Err("offline".into())
}
fn fetch_tree(&self, _: &str) -> Result<TreeResult, String> {
Err("offline".into())
}
fn fetch_blob(&self, _: &str, _: &str) -> Result<Vec<u8>, String> {
Err("offline".into())
}
fn search_code(&self, _: &str) -> Result<Vec<CodeMatch>, String> {
Err("offline".into())
}
fn clone_url(&self, _: &str) -> Result<String, String> {
Err("offline".into())
}
fn web_url(
&self,
_: &str,
_: &str,
_: &str,
_: Option<u32>,
_: bool,
) -> Result<String, String> {
Err("offline".into())
}
fn org_url(&self, _: &str) -> Result<String, String> {
Err("offline".into())
}
}
Arc::new(Offline)
}