1use editor::{EditorSettings, ShowMinimap};
2use fs::Fs;
3use gpui::{App, IntoElement, Pixels, Window};
4use language::language_settings::AllLanguageSettings;
5use project::project_settings::ProjectSettings;
6use settings::{Settings as _, update_settings_file};
7use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
8use ui::{
9 ContextMenu, DropdownMenu, IconButton, Label, LabelCommon, LabelSize, NumericStepper,
10 ParentElement, SharedString, Styled, SwitchColor, SwitchField, ToggleButtonGroup,
11 ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, div, h_flex, px, v_flex,
12};
13
14fn read_show_mini_map(cx: &App) -> ShowMinimap {
15 editor::EditorSettings::get_global(cx).minimap.show
16}
17
18fn write_show_mini_map(show: ShowMinimap, cx: &mut App) {
19 let fs = <dyn Fs>::global(cx);
20
21 update_settings_file::<EditorSettings>(fs, cx, move |editor_settings, _| {
22 editor_settings.minimap.get_or_insert_default().show = Some(show);
23 });
24}
25
26fn read_inlay_hints(cx: &App) -> bool {
27 AllLanguageSettings::get_global(cx)
28 .defaults
29 .inlay_hints
30 .enabled
31}
32
33fn write_inlay_hints(enabled: bool, cx: &mut App) {
34 let fs = <dyn Fs>::global(cx);
35
36 update_settings_file::<AllLanguageSettings>(fs, cx, move |all_language_settings, cx| {
37 all_language_settings
38 .defaults
39 .inlay_hints
40 .get_or_insert_with(|| {
41 AllLanguageSettings::get_global(cx)
42 .clone()
43 .defaults
44 .inlay_hints
45 })
46 .enabled = enabled;
47 });
48}
49
50fn read_git_blame(cx: &App) -> bool {
51 ProjectSettings::get_global(cx).git.inline_blame_enabled()
52}
53
54fn set_git_blame(enabled: bool, cx: &mut App) {
55 let fs = <dyn Fs>::global(cx);
56
57 update_settings_file::<ProjectSettings>(fs, cx, move |project_settings, _| {
58 project_settings
59 .git
60 .inline_blame
61 .get_or_insert_default()
62 .enabled = enabled;
63 });
64}
65
66fn write_ui_font_family(font: SharedString, cx: &mut App) {
67 let fs = <dyn Fs>::global(cx);
68
69 update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
70 theme_settings.ui_font_family = Some(FontFamilyName(font.into()));
71 });
72}
73
74fn write_ui_font_size(size: Pixels, cx: &mut App) {
75 let fs = <dyn Fs>::global(cx);
76
77 update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
78 theme_settings.ui_font_size = Some(size.into());
79 });
80}
81
82fn write_buffer_font_size(size: Pixels, cx: &mut App) {
83 let fs = <dyn Fs>::global(cx);
84
85 update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
86 theme_settings.buffer_font_size = Some(size.into());
87 });
88}
89
90fn write_buffer_font_family(font_family: SharedString, cx: &mut App) {
91 let fs = <dyn Fs>::global(cx);
92
93 update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
94 theme_settings.buffer_font_family = Some(FontFamilyName(font_family.into()));
95 });
96}
97
98pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl IntoElement {
99 let theme_settings = ThemeSettings::get_global(cx);
100 let ui_font_size = theme_settings.ui_font_size(cx);
101 let font_family = theme_settings.buffer_font.family.clone();
102 let buffer_font_size = theme_settings.buffer_font_size(cx);
103
104 v_flex()
105 .gap_4()
106 .child(Label::new("Import Settings").size(LabelSize::Large))
107 .child(
108 Label::new("Automatically pull your settings from other editors.")
109 .size(LabelSize::Small),
110 )
111 .child(
112 h_flex()
113 .child(IconButton::new(
114 "import-vs-code-settings",
115 ui::IconName::Code,
116 ))
117 .child(IconButton::new(
118 "import-cursor-settings",
119 ui::IconName::CursorIBeam,
120 )),
121 )
122 .child(Label::new("Popular Settings").size(LabelSize::Large))
123 .child(
124 h_flex()
125 .gap_4()
126 .justify_between()
127 .child(
128 v_flex()
129 .justify_between()
130 .gap_1()
131 .child(Label::new("UI Font"))
132 .child(
133 h_flex()
134 .justify_between()
135 .gap_2()
136 .child(div().min_w(px(120.)).child(DropdownMenu::new(
137 "ui-font-family",
138 theme_settings.ui_font.family.clone(),
139 ContextMenu::build(window, cx, |mut menu, _, cx| {
140 let font_family_cache = FontFamilyCache::global(cx);
141
142 for font_name in font_family_cache.list_font_families(cx) {
143 menu = menu.custom_entry(
144 {
145 let font_name = font_name.clone();
146 move |_window, _cx| {
147 Label::new(font_name.clone())
148 .into_any_element()
149 }
150 },
151 {
152 let font_name = font_name.clone();
153 move |_window, cx| {
154 write_ui_font_family(font_name.clone(), cx);
155 }
156 },
157 )
158 }
159
160 menu
161 }),
162 )))
163 .child(NumericStepper::new(
164 "ui-font-size",
165 ui_font_size.to_string(),
166 move |_, _, cx| {
167 write_ui_font_size(ui_font_size - px(1.), cx);
168 },
169 move |_, _, cx| {
170 write_ui_font_size(ui_font_size + px(1.), cx);
171 },
172 )),
173 ),
174 )
175 .child(
176 v_flex()
177 .justify_between()
178 .gap_1()
179 .child(Label::new("Editor Font"))
180 .child(
181 h_flex()
182 .justify_between()
183 .gap_2()
184 .child(DropdownMenu::new(
185 "buffer-font-family",
186 font_family,
187 ContextMenu::build(window, cx, |mut menu, _, cx| {
188 let font_family_cache = FontFamilyCache::global(cx);
189
190 for font_name in font_family_cache.list_font_families(cx) {
191 menu = menu.custom_entry(
192 {
193 let font_name = font_name.clone();
194 move |_window, _cx| {
195 Label::new(font_name.clone())
196 .into_any_element()
197 }
198 },
199 {
200 let font_name = font_name.clone();
201 move |_window, cx| {
202 write_buffer_font_family(
203 font_name.clone(),
204 cx,
205 );
206 }
207 },
208 )
209 }
210
211 menu
212 }),
213 ))
214 .child(NumericStepper::new(
215 "buffer-font-size",
216 buffer_font_size.to_string(),
217 move |_, _, cx| {
218 write_buffer_font_size(buffer_font_size - px(1.), cx);
219 },
220 move |_, _, cx| {
221 write_buffer_font_size(buffer_font_size + px(1.), cx);
222 },
223 )),
224 ),
225 ),
226 )
227 .child(
228 h_flex()
229 .justify_between()
230 .child(Label::new("Mini Map"))
231 .child(
232 ToggleButtonGroup::single_row(
233 "onboarding-show-mini-map",
234 [
235 ToggleButtonSimple::new("Auto", |_, _, cx| {
236 write_show_mini_map(ShowMinimap::Auto, cx);
237 }),
238 ToggleButtonSimple::new("Always", |_, _, cx| {
239 write_show_mini_map(ShowMinimap::Always, cx);
240 }),
241 ToggleButtonSimple::new("Never", |_, _, cx| {
242 write_show_mini_map(ShowMinimap::Never, cx);
243 }),
244 ],
245 )
246 .selected_index(match read_show_mini_map(cx) {
247 ShowMinimap::Auto => 0,
248 ShowMinimap::Always => 1,
249 ShowMinimap::Never => 2,
250 })
251 .style(ToggleButtonGroupStyle::Outlined)
252 .button_width(ui::rems_from_px(64.)),
253 ),
254 )
255 .child(
256 SwitchField::new(
257 "onboarding-enable-inlay-hints",
258 "Inlay Hints",
259 "See parameter names for function and method calls inline.",
260 if read_inlay_hints(cx) {
261 ui::ToggleState::Selected
262 } else {
263 ui::ToggleState::Unselected
264 },
265 |toggle_state, _, cx| {
266 write_inlay_hints(toggle_state == &ToggleState::Selected, cx);
267 },
268 )
269 .color(SwitchColor::Accent),
270 )
271 .child(
272 SwitchField::new(
273 "onboarding-git-blame-switch",
274 "Git Blame",
275 "See who committed each line on a given file.",
276 if read_git_blame(cx) {
277 ui::ToggleState::Selected
278 } else {
279 ui::ToggleState::Unselected
280 },
281 |toggle_state, _, cx| {
282 set_git_blame(toggle_state == &ToggleState::Selected, cx);
283 },
284 )
285 .color(SwitchColor::Accent),
286 )
287}