asimov_cli/commands/proxy/
install.rs1use crate::{BoxError, StandardOptions};
4use clap::ValueEnum;
5use std::path::{Path, PathBuf};
6
7#[derive(Clone, Copy, Debug, ValueEnum)]
8pub enum ProxyInstallTarget {
9 #[cfg(feature = "unstable")]
11 Cursor,
12
13 #[cfg(feature = "unstable")]
15 Obsidian,
16
17 #[cfg(feature = "unstable")]
19 VSCode,
20
21 Zed,
23}
24
25pub async fn install(
26 mut apps: Vec<ProxyInstallTarget>,
27 flags: &StandardOptions,
28) -> Result<(), BoxError> {
29 use ProxyInstallTarget::*;
30 let home_path = dirs::home_dir().expect("HOME should be set");
31 if apps.is_empty() {
32 apps.extend_from_slice(&[
33 #[cfg(feature = "unstable")]
34 Cursor,
35 #[cfg(feature = "unstable")]
36 Obsidian,
37 #[cfg(feature = "unstable")]
38 VSCode,
39 Zed,
40 ]);
41 }
42 for app in apps {
43 install_app(app, &home_path, flags).await?;
44 }
45 Ok(())
46}
47
48pub async fn install_app(
49 app: ProxyInstallTarget,
50 home_path: &PathBuf,
51 flags: &StandardOptions,
52) -> Result<(), BoxError> {
53 use ProxyInstallTarget::*;
54 match app {
55 #[cfg(feature = "unstable")]
56 Cursor => {
57 todo!() },
60
61 #[cfg(feature = "unstable")]
62 Obsidian => {
63 todo!() },
65
66 #[cfg(feature = "unstable")]
67 VSCode => {
68 todo!() },
70
71 Zed => {
72 if flags.verbose > 0 {
74 eprintln!("Configuring Zed...");
75 }
76 let path = home_path.join(".config/zed/settings.json");
77 if !path.exists() {
78 eprintln!("error: {} not found.", path.display());
79 return Ok(());
80 }
81 patch_jsonc_file_with_edikt(
82 &path,
83 &["language_models", "openai_compatible", "ASIMOV"],
84 include_str!("config/zed-provider.jsonc"),
85 )?;
86 if flags.verbose > 0 {
87 eprintln!("Configured Zed: {}", path.display());
88 }
89 },
90 };
91 Ok(())
92}
93
94fn patch_jsonc_file_with_edikt(
95 file_path: impl AsRef<Path>,
96 json_path: &[&str],
97 patch: &str,
98) -> Result<(), BoxError> {
99 use edikt_core::{Document, Step};
100 let file_path = file_path.as_ref();
101 let input = std::fs::read_to_string(&file_path).unwrap_or_else(|_| "{}".to_string());
102 let mut cst = edikt_jsonc::parse(&input)?;
103 cst.set(
104 json_path
105 .into_iter()
106 .map(ToString::to_string)
107 .map(Step::Field)
108 .collect::<Vec<Step>>()
109 .as_slice(),
110 &edikt_jsonc::parse(patch)?.to_value(),
111 )?;
112 let output = cst.to_source();
113 std::fs::write(&file_path, output)?;
114 Ok(())
115}
116
117#[cfg(false)]
118fn patch_jsonc_file_with_jsonc_parser(
119 file_path: impl AsRef<Path>,
120 json_path: &[&str],
121 _patch: &str,
122) -> Result<(), BoxError> {
123 use jsonc_parser::cst::CstRootNode;
124 let file_path = file_path.as_ref();
125 let input = std::fs::read_to_string(&file_path).unwrap_or_else(|_| "{}".to_string());
126 let cst = CstRootNode::parse(&input, &Default::default())?;
127 let mut cursor = cst.object_value_or_set();
128 for key in json_path {
129 cursor = cursor.object_value_or_set(key);
130 }
131 let output = cst.to_string();
133 std::fs::write(&file_path, output)?;
134 Ok(())
135}