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}