config.rs

 1use async_gen::{AsyncIter, r#gen};
 2use anyhow::Context;
 3use clap::Parser;
 4use rmcp::serde_json;
 5use std::{fs::FileType, path::{Path, PathBuf}};
 6
 7#[derive(Parser, Debug)]
 8#[command(version, about)]
 9pub struct CommandLineArgs {
10    #[arg(short, long, value_name = "FILE")]
11    pub config: PathBuf,
12}
13
14#[derive(serde::Deserialize, Debug)]
15pub struct Command {
16    pub command: String,
17    pub args: Vec<String>,
18}
19
20#[derive(serde::Deserialize, Debug)]
21pub struct Config {
22    pub lsp_server_command: Command,
23
24	/// An absolute path pointing to the root of the project on disk.
25    pub project_root: PathBuf,
26}
27
28impl Config {
29    pub async fn load(path: &PathBuf) -> anyhow::Result<Self> {
30        let config_content = tokio::fs::read_to_string(path).await?;
31        let config: Config = serde_json::from_str(&config_content)?;
32        Ok(config)
33    }
34
35    /// Returns a `Some` containing an absolute `` to the file if it is in the
36    /// project, otherwise returns `None`
37    pub async fn path_in_project<P>(&self, path: P) -> anyhow::Result<Option<PathBuf>>
38    where
39        P: AsRef<Path>,
40    {
41		let joined = self.project_root.join(&path);
42		match tokio::fs::try_exists(joined.as_path()).await {
43			Ok(true) => anyhow::Ok(Some(joined)),
44			Ok(false) => anyhow::Ok(None),
45			Err(err) => anyhow::bail!("Could not look for path {:?} in project {:?}, error: {}", path.as_ref(), self.project_root, err)
46		}
47	}
48}