settings_ui.rs

  1use anyhow::Context as _;
  2use fs::Fs;
  3use gpui::{AnyElement, App, AppContext as _, ReadGlobal as _, Window};
  4use smallvec::SmallVec;
  5
  6use crate::SettingsStore;
  7
  8pub trait SettingsUi {
  9    fn settings_ui_item() -> SettingsUiItem {
 10        SettingsUiItem::None
 11    }
 12    fn settings_ui_entry() -> SettingsUiEntry;
 13}
 14
 15pub struct SettingsUiEntry {
 16    // todo(settings_ui): move this back here once there isn't a None variant
 17    // pub path: &'static str,
 18    // pub title: &'static str,
 19    pub item: SettingsUiEntryVariant,
 20}
 21
 22pub enum SettingsUiEntryVariant {
 23    Group {
 24        path: &'static str,
 25        title: &'static str,
 26        items: Vec<SettingsUiEntry>,
 27    },
 28    Item {
 29        path: &'static str,
 30        item: SettingsUiItemSingle,
 31    },
 32    // todo(settings_ui): remove
 33    None,
 34}
 35
 36pub enum SettingsUiItemSingle {
 37    SwitchField,
 38    NumericStepper,
 39    ToggleGroup(&'static [&'static str]),
 40    /// This should be used when toggle group size > 6
 41    DropDown(&'static [&'static str]),
 42    Custom(Box<dyn Fn(SettingsValue<serde_json::Value>, &mut Window, &mut App) -> AnyElement>),
 43}
 44
 45pub struct SettingsValue<T> {
 46    pub title: &'static str,
 47    pub path: SmallVec<[&'static str; 1]>,
 48    pub value: Option<T>,
 49    pub default_value: T,
 50}
 51
 52impl<T> SettingsValue<T> {
 53    pub fn read(&self) -> &T {
 54        match &self.value {
 55            Some(value) => value,
 56            None => &self.default_value,
 57        }
 58    }
 59}
 60
 61impl SettingsValue<serde_json::Value> {
 62    pub fn write_value(path: &SmallVec<[&'static str; 1]>, value: serde_json::Value, cx: &mut App) {
 63        let settings_store = SettingsStore::global(cx);
 64        let fs = <dyn Fs>::global(cx);
 65
 66        let rx = settings_store.update_settings_file_at_path(fs.clone(), path.as_slice(), value);
 67        let path = path.clone();
 68        cx.background_spawn(async move {
 69            rx.await?
 70                .with_context(|| format!("Failed to update setting at path `{:?}`", path.join(".")))
 71        })
 72        .detach_and_log_err(cx);
 73    }
 74}
 75
 76impl<T: serde::Serialize> SettingsValue<T> {
 77    pub fn write(
 78        path: &SmallVec<[&'static str; 1]>,
 79        value: T,
 80        cx: &mut App,
 81    ) -> Result<(), serde_json::Error> {
 82        SettingsValue::write_value(path, serde_json::to_value(value)?, cx);
 83        Ok(())
 84    }
 85}
 86
 87pub enum SettingsUiItem {
 88    Group {
 89        title: &'static str,
 90        items: Vec<SettingsUiEntry>,
 91    },
 92    Single(SettingsUiItemSingle),
 93    None,
 94}
 95
 96impl SettingsUi for bool {
 97    fn settings_ui_item() -> SettingsUiItem {
 98        SettingsUiItem::Single(SettingsUiItemSingle::SwitchField)
 99    }
100
101    fn settings_ui_entry() -> SettingsUiEntry {
102        SettingsUiEntry {
103            item: SettingsUiEntryVariant::None,
104        }
105    }
106}
107
108impl SettingsUi for u64 {
109    fn settings_ui_item() -> SettingsUiItem {
110        SettingsUiItem::Single(SettingsUiItemSingle::NumericStepper)
111    }
112
113    fn settings_ui_entry() -> SettingsUiEntry {
114        SettingsUiEntry {
115            item: SettingsUiEntryVariant::None,
116        }
117    }
118}