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