use crate::config::{Config, LLMProvider};
use crate::i18n::TargetLanguage;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "Litho (deepwiki-rs)")]
#[command(
about = "AI-based high-performance generation engine for documentation, It can intelligently analyze project structures, identify core modules, and generate professional architecture documentation."
)]
#[command(author = "Sopaco")]
#[command(version)]
pub struct Args {
#[command(subcommand)]
pub command: Option<Commands>,
#[arg(short, long, default_value = ".")]
pub project_path: PathBuf,
#[arg(short, long, default_value = "./litho.docs")]
pub output_path: PathBuf,
#[arg(short, long)]
pub config: Option<PathBuf>,
#[arg(short, long)]
pub name: Option<String>,
#[arg(long)]
pub skip_preprocessing: bool,
#[arg(long)]
pub skip_research: bool,
#[arg(long)]
pub skip_documentation: bool,
#[arg(short, long)]
pub verbose: bool,
#[arg(long)]
pub model_efficient: Option<String>,
#[arg(long)]
pub model_powerful: Option<String>,
#[arg(long)]
pub llm_api_base_url: Option<String>,
#[arg(long)]
pub llm_api_key: Option<String>,
#[arg(long)]
pub max_tokens: Option<u32>,
#[arg(long)]
pub temperature: Option<f64>,
#[arg(long)]
pub max_parallels: Option<usize>,
#[arg(long)]
pub llm_provider: Option<String>,
#[arg(long)]
pub target_language: Option<String>,
#[arg(long, default_value = "false", action = clap::ArgAction::SetTrue)]
pub disable_preset_tools: bool,
#[arg(long)]
pub no_cache: bool,
#[arg(long)]
pub force_regenerate: bool,
#[arg(long)]
pub boundary_max_insights: Option<usize>,
#[arg(long)]
pub boundary_code_limit: Option<usize>,
#[arg(long)]
pub boundary_include_source: Option<bool>,
#[arg(long)]
pub boundary_only_directories_when_files_more_than: Option<usize>,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
SyncKnowledge {
#[arg(short, long)]
config: Option<PathBuf>,
#[arg(long)]
force: bool,
},
}
impl Args {
pub fn to_config(self) -> Config {
let target_lang = if let Some(ref lang_str) = self.target_language {
lang_str.parse::<TargetLanguage>().unwrap_or_default()
} else {
TargetLanguage::default()
};
let mut config = if let Some(config_path) = &self.config {
let msg = target_lang.msg_config_read_error().replace("{:?}", &format!("{:?}", config_path));
Config::from_file(config_path).expect(&msg)
} else {
let default_config_path = std::env::current_dir()
.unwrap_or_else(|_| std::path::PathBuf::from("."))
.join("litho.toml");
if default_config_path.exists() {
let msg = target_lang.msg_config_read_error().replace("{:?}", &format!("{:?}", default_config_path));
Config::from_file(&default_config_path).expect(&msg)
} else {
Config::default()
}
};
config.project_path = self.project_path.clone();
config.output_path = self.output_path;
config.internal_path = self.project_path.join(".litho");
if let Some(name) = self.name {
config.project_name = Some(name);
}
if let Some(provider_str) = self.llm_provider {
if let Ok(provider) = provider_str.parse::<LLMProvider>() {
config.llm.provider = provider;
} else {
let msg = target_lang.msg_unknown_provider().replace("{}", &provider_str);
eprintln!("{}", msg);
}
}
if let Some(llm_api_base_url) = self.llm_api_base_url {
config.llm.api_base_url = llm_api_base_url;
} else {
if config.llm.provider == LLMProvider::Ollama {
config.llm.api_base_url = "http://localhost:11434".to_owned();
}
}
if let Some(llm_api_key) = self.llm_api_key {
config.llm.api_key = llm_api_key;
}
if let Some(model_efficient) = self.model_efficient {
config.llm.model_efficient = model_efficient;
}
if let Some(model_powerful) = self.model_powerful {
config.llm.model_powerful = model_powerful;
} else {
config.llm.model_powerful = config.llm.model_efficient.to_string();
}
if let Some(max_tokens) = self.max_tokens {
config.llm.max_tokens = max_tokens;
}
if let Some(temperature) = self.temperature {
config.llm.temperature = Some(temperature);
}
if let Some(max_parallels) = self.max_parallels {
config.llm.max_parallels = max_parallels;
}
config.llm.disable_preset_tools = self.disable_preset_tools;
if let Some(target_language_str) = self.target_language {
if let Ok(target_language) = target_language_str.parse::<TargetLanguage>() {
config.target_language = target_language;
} else {
let msg = target_lang.msg_unknown_language().replace("{}", &target_language_str);
eprintln!("{}", msg);
}
}
if self.no_cache {
config.cache.enabled = false;
}
if let Some(max_insights) = self.boundary_max_insights {
config.boundary_analysis.max_boundary_insights = max_insights;
}
if let Some(code_limit) = self.boundary_code_limit {
config.boundary_analysis.code_insights_limit = code_limit;
}
if let Some(include_source) = self.boundary_include_source {
config.boundary_analysis.include_source_code = include_source;
}
if let Some(only_dirs_threshold) = self.boundary_only_directories_when_files_more_than {
config.boundary_analysis.only_directories_when_files_more_than = Some(only_dirs_threshold);
}
config
}
}