vscode_import.rs

  1use anyhow::Result;
  2use fs::Fs;
  3use serde_json::{Map, Value};
  4
  5use std::sync::Arc;
  6
  7#[derive(Clone, Copy, PartialEq, Eq, Debug)]
  8pub enum VsCodeSettingsSource {
  9    VsCode,
 10    Cursor,
 11}
 12
 13impl std::fmt::Display for VsCodeSettingsSource {
 14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 15        match self {
 16            VsCodeSettingsSource::VsCode => write!(f, "VS Code"),
 17            VsCodeSettingsSource::Cursor => write!(f, "Cursor"),
 18        }
 19    }
 20}
 21
 22pub struct VsCodeSettings {
 23    pub source: VsCodeSettingsSource,
 24    content: Map<String, Value>,
 25}
 26
 27impl VsCodeSettings {
 28    pub fn from_str(content: &str, source: VsCodeSettingsSource) -> Result<Self> {
 29        Ok(Self {
 30            source,
 31            content: serde_json_lenient::from_str(content)?,
 32        })
 33    }
 34
 35    pub async fn load_user_settings(source: VsCodeSettingsSource, fs: Arc<dyn Fs>) -> Result<Self> {
 36        let path = match source {
 37            VsCodeSettingsSource::VsCode => paths::vscode_settings_file(),
 38            VsCodeSettingsSource::Cursor => paths::cursor_settings_file(),
 39        };
 40        let content = fs.load(path).await?;
 41        Ok(Self {
 42            source,
 43            content: serde_json_lenient::from_str(&content)?,
 44        })
 45    }
 46
 47    pub fn read_value(&self, setting: &str) -> Option<&Value> {
 48        if let Some(value) = self.content.get(setting) {
 49            return Some(value);
 50        }
 51        // TODO: maybe check if it's in [platform] settings for current platform as a fallback
 52        // TODO: deal with language specific settings
 53        None
 54    }
 55
 56    pub fn read_string(&self, setting: &str) -> Option<&str> {
 57        self.read_value(setting).and_then(|v| v.as_str())
 58    }
 59
 60    pub fn read_bool(&self, setting: &str) -> Option<bool> {
 61        self.read_value(setting).and_then(|v| v.as_bool())
 62    }
 63
 64    pub fn string_setting(&self, key: &str, setting: &mut Option<String>) {
 65        if let Some(s) = self.content.get(key).and_then(Value::as_str) {
 66            *setting = Some(s.to_owned())
 67        }
 68    }
 69
 70    pub fn bool_setting(&self, key: &str, setting: &mut Option<bool>) {
 71        if let Some(s) = self.content.get(key).and_then(Value::as_bool) {
 72            *setting = Some(s)
 73        }
 74    }
 75
 76    pub fn u32_setting(&self, key: &str, setting: &mut Option<u32>) {
 77        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
 78            *setting = Some(s as u32)
 79        }
 80    }
 81
 82    pub fn u64_setting(&self, key: &str, setting: &mut Option<u64>) {
 83        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
 84            *setting = Some(s)
 85        }
 86    }
 87
 88    pub fn usize_setting(&self, key: &str, setting: &mut Option<usize>) {
 89        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
 90            *setting = Some(s.try_into().unwrap())
 91        }
 92    }
 93
 94    pub fn f32_setting(&self, key: &str, setting: &mut Option<f32>) {
 95        if let Some(s) = self.content.get(key).and_then(Value::as_f64) {
 96            *setting = Some(s as f32)
 97        }
 98    }
 99
100    pub fn enum_setting<T>(
101        &self,
102        key: &str,
103        setting: &mut Option<T>,
104        f: impl FnOnce(&str) -> Option<T>,
105    ) {
106        if let Some(s) = self.content.get(key).and_then(Value::as_str).and_then(f) {
107            *setting = Some(s)
108        }
109    }
110}