editing_page.rs

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