1use gpui::{AppContext, FontWeight};
2use project::project_settings::{InlineBlameSettings, ProjectSettings};
3use settings::{EditableSettingControl, Settings};
4use theme::ThemeSettings;
5use ui::{
6 prelude::*, CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer,
7 SettingsGroup,
8};
9
10#[derive(IntoElement)]
11pub struct EditorSettingsControls {}
12
13impl EditorSettingsControls {
14 pub fn new() -> Self {
15 Self {}
16 }
17}
18
19impl RenderOnce for EditorSettingsControls {
20 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
21 SettingsContainer::new()
22 .child(
23 SettingsGroup::new("Font")
24 .child(BufferFontSizeControl)
25 .child(BufferFontWeightControl),
26 )
27 .child(SettingsGroup::new("Editor").child(InlineGitBlameControl))
28 }
29}
30
31#[derive(IntoElement)]
32struct BufferFontSizeControl;
33
34impl EditableSettingControl for BufferFontSizeControl {
35 type Value = Pixels;
36 type Settings = ThemeSettings;
37
38 fn name(&self) -> SharedString {
39 "Buffer Font Size".into()
40 }
41
42 fn read(cx: &AppContext) -> Self::Value {
43 let settings = ThemeSettings::get_global(cx);
44 settings.buffer_font_size
45 }
46
47 fn apply(settings: &mut <Self::Settings as Settings>::FileContent, value: Self::Value) {
48 settings.buffer_font_size = Some(value.into());
49 }
50}
51
52impl RenderOnce for BufferFontSizeControl {
53 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
54 let value = Self::read(cx);
55
56 h_flex()
57 .gap_2()
58 .child(Icon::new(IconName::FontSize))
59 .child(NumericStepper::new(
60 value.to_string(),
61 move |_, cx| {
62 Self::write(value - px(1.), cx);
63 },
64 move |_, cx| {
65 Self::write(value + px(1.), cx);
66 },
67 ))
68 }
69}
70
71#[derive(IntoElement)]
72struct BufferFontWeightControl;
73
74impl EditableSettingControl for BufferFontWeightControl {
75 type Value = FontWeight;
76 type Settings = ThemeSettings;
77
78 fn name(&self) -> SharedString {
79 "Buffer Font Weight".into()
80 }
81
82 fn read(cx: &AppContext) -> Self::Value {
83 let settings = ThemeSettings::get_global(cx);
84 settings.buffer_font.weight
85 }
86
87 fn apply(settings: &mut <Self::Settings as Settings>::FileContent, value: Self::Value) {
88 settings.buffer_font_weight = Some(value.0);
89 }
90}
91
92impl RenderOnce for BufferFontWeightControl {
93 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
94 let value = Self::read(cx);
95
96 h_flex()
97 .gap_2()
98 .child(Icon::new(IconName::FontWeight))
99 .child(DropdownMenu::new(
100 "buffer-font-weight",
101 value.0.to_string(),
102 ContextMenu::build(cx, |mut menu, _cx| {
103 for weight in FontWeight::ALL {
104 menu = menu.custom_entry(
105 move |_cx| Label::new(weight.0.to_string()).into_any_element(),
106 {
107 move |cx| {
108 Self::write(weight, cx);
109 }
110 },
111 )
112 }
113
114 menu
115 }),
116 ))
117 }
118}
119
120#[derive(IntoElement)]
121struct InlineGitBlameControl;
122
123impl EditableSettingControl for InlineGitBlameControl {
124 type Value = bool;
125 type Settings = ProjectSettings;
126
127 fn name(&self) -> SharedString {
128 "Inline Git Blame".into()
129 }
130
131 fn read(cx: &AppContext) -> Self::Value {
132 let settings = ProjectSettings::get_global(cx);
133 settings.git.inline_blame_enabled()
134 }
135
136 fn apply(settings: &mut <Self::Settings as Settings>::FileContent, value: Self::Value) {
137 if let Some(inline_blame) = settings.git.inline_blame.as_mut() {
138 inline_blame.enabled = value;
139 } else {
140 settings.git.inline_blame = Some(InlineBlameSettings {
141 enabled: false,
142 ..Default::default()
143 });
144 }
145 }
146}
147
148impl RenderOnce for InlineGitBlameControl {
149 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
150 let value = Self::read(cx);
151
152 CheckboxWithLabel::new(
153 "inline-git-blame",
154 Label::new(self.name()),
155 value.into(),
156 |selection, cx| {
157 Self::write(
158 match selection {
159 Selection::Selected => true,
160 Selection::Unselected | Selection::Indeterminate => false,
161 },
162 cx,
163 );
164 },
165 )
166 }
167}