
Small fixes to onboarding. Correct ligature example. Replace`ctrl-escape` and `alt-tab` since they are reserved on windows (and often on linux) and so are caught by the OS. Release Notes: - N/A
765 lines
27 KiB
Rust
765 lines
27 KiB
Rust
use std::sync::Arc;
|
|
|
|
use editor::{EditorSettings, ShowMinimap};
|
|
use fs::Fs;
|
|
use fuzzy::{StringMatch, StringMatchCandidate};
|
|
use gpui::{
|
|
Action, AnyElement, App, Context, FontFeatures, IntoElement, Pixels, SharedString, Task, Window,
|
|
};
|
|
use language::language_settings::{AllLanguageSettings, FormatOnSave};
|
|
use picker::{Picker, PickerDelegate};
|
|
use project::project_settings::ProjectSettings;
|
|
use settings::{Settings as _, update_settings_file};
|
|
use theme::{FontFamilyCache, FontFamilyName, ThemeSettings};
|
|
use ui::{
|
|
ButtonLike, ListItem, ListItemSpacing, NumericStepper, PopoverMenu, SwitchField,
|
|
ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, ToggleState, Tooltip,
|
|
prelude::*,
|
|
};
|
|
|
|
use crate::{ImportCursorSettings, ImportVsCodeSettings, SettingsImportState};
|
|
|
|
fn read_show_mini_map(cx: &App) -> ShowMinimap {
|
|
editor::EditorSettings::get_global(cx).minimap.show
|
|
}
|
|
|
|
fn write_show_mini_map(show: ShowMinimap, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
// This is used to speed up the UI
|
|
// the UI reads the current values to get what toggle state to show on buttons
|
|
// there's a slight delay if we just call update_settings_file so we manually set
|
|
// the value here then call update_settings file to get around the delay
|
|
let mut curr_settings = EditorSettings::get_global(cx).clone();
|
|
curr_settings.minimap.show = show;
|
|
EditorSettings::override_global(curr_settings, cx);
|
|
|
|
update_settings_file::<EditorSettings>(fs, cx, move |editor_settings, _| {
|
|
telemetry::event!(
|
|
"Welcome Minimap Clicked",
|
|
from = editor_settings.minimap.unwrap_or_default(),
|
|
to = show
|
|
);
|
|
editor_settings.minimap.get_or_insert_default().show = Some(show);
|
|
});
|
|
}
|
|
|
|
fn read_inlay_hints(cx: &App) -> bool {
|
|
AllLanguageSettings::get_global(cx)
|
|
.defaults
|
|
.inlay_hints
|
|
.enabled
|
|
}
|
|
|
|
fn write_inlay_hints(enabled: bool, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
let mut curr_settings = AllLanguageSettings::get_global(cx).clone();
|
|
curr_settings.defaults.inlay_hints.enabled = enabled;
|
|
AllLanguageSettings::override_global(curr_settings, cx);
|
|
|
|
update_settings_file::<AllLanguageSettings>(fs, cx, move |all_language_settings, cx| {
|
|
all_language_settings
|
|
.defaults
|
|
.inlay_hints
|
|
.get_or_insert_with(|| {
|
|
AllLanguageSettings::get_global(cx)
|
|
.clone()
|
|
.defaults
|
|
.inlay_hints
|
|
})
|
|
.enabled = enabled;
|
|
});
|
|
}
|
|
|
|
fn read_git_blame(cx: &App) -> bool {
|
|
ProjectSettings::get_global(cx).git.inline_blame_enabled()
|
|
}
|
|
|
|
fn write_git_blame(enabled: bool, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
let mut curr_settings = ProjectSettings::get_global(cx).clone();
|
|
curr_settings
|
|
.git
|
|
.inline_blame
|
|
.get_or_insert_default()
|
|
.enabled = enabled;
|
|
ProjectSettings::override_global(curr_settings, cx);
|
|
|
|
update_settings_file::<ProjectSettings>(fs, cx, move |project_settings, _| {
|
|
project_settings
|
|
.git
|
|
.inline_blame
|
|
.get_or_insert_default()
|
|
.enabled = enabled;
|
|
});
|
|
}
|
|
|
|
fn write_ui_font_family(font: SharedString, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
|
|
telemetry::event!(
|
|
"Welcome Font Changed",
|
|
type = "ui font",
|
|
old = theme_settings.ui_font_family,
|
|
new = font
|
|
);
|
|
theme_settings.ui_font_family = Some(FontFamilyName(font.into()));
|
|
});
|
|
}
|
|
|
|
fn write_ui_font_size(size: Pixels, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
|
|
theme_settings.ui_font_size = Some(size.into());
|
|
});
|
|
}
|
|
|
|
fn write_buffer_font_size(size: Pixels, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
|
|
theme_settings.buffer_font_size = Some(size.into());
|
|
});
|
|
}
|
|
|
|
fn write_buffer_font_family(font_family: SharedString, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
|
|
telemetry::event!(
|
|
"Welcome Font Changed",
|
|
type = "editor font",
|
|
old = theme_settings.buffer_font_family,
|
|
new = font_family
|
|
);
|
|
|
|
theme_settings.buffer_font_family = Some(FontFamilyName(font_family.into()));
|
|
});
|
|
}
|
|
|
|
fn read_font_ligatures(cx: &App) -> bool {
|
|
ThemeSettings::get_global(cx)
|
|
.buffer_font
|
|
.features
|
|
.is_calt_enabled()
|
|
.unwrap_or(true)
|
|
}
|
|
|
|
fn write_font_ligatures(enabled: bool, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
let bit = if enabled { 1 } else { 0 };
|
|
|
|
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
|
|
let mut features = theme_settings
|
|
.buffer_font_features
|
|
.as_mut()
|
|
.map(|features| features.tag_value_list().to_vec())
|
|
.unwrap_or_default();
|
|
|
|
if let Some(calt_index) = features.iter().position(|(tag, _)| tag == "calt") {
|
|
features[calt_index].1 = bit;
|
|
} else {
|
|
features.push(("calt".into(), bit));
|
|
}
|
|
|
|
theme_settings.buffer_font_features = Some(FontFeatures(Arc::new(features)));
|
|
});
|
|
}
|
|
|
|
fn read_format_on_save(cx: &App) -> bool {
|
|
match AllLanguageSettings::get_global(cx).defaults.format_on_save {
|
|
FormatOnSave::On | FormatOnSave::List(_) => true,
|
|
FormatOnSave::Off => false,
|
|
}
|
|
}
|
|
|
|
fn write_format_on_save(format_on_save: bool, cx: &mut App) {
|
|
let fs = <dyn Fs>::global(cx);
|
|
|
|
update_settings_file::<AllLanguageSettings>(fs, cx, move |language_settings, _| {
|
|
language_settings.defaults.format_on_save = Some(match format_on_save {
|
|
true => FormatOnSave::On,
|
|
false => FormatOnSave::Off,
|
|
});
|
|
});
|
|
}
|
|
|
|
fn render_setting_import_button(
|
|
tab_index: isize,
|
|
label: SharedString,
|
|
icon_name: IconName,
|
|
action: &dyn Action,
|
|
imported: bool,
|
|
) -> impl IntoElement {
|
|
let action = action.boxed_clone();
|
|
h_flex().w_full().child(
|
|
ButtonLike::new(label.clone())
|
|
.full_width()
|
|
.style(ButtonStyle::Outlined)
|
|
.size(ButtonSize::Large)
|
|
.tab_index(tab_index)
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.child(
|
|
h_flex()
|
|
.gap_1p5()
|
|
.px_1()
|
|
.child(
|
|
Icon::new(icon_name)
|
|
.color(Color::Muted)
|
|
.size(IconSize::XSmall),
|
|
)
|
|
.child(Label::new(label.clone())),
|
|
)
|
|
.when(imported, |this| {
|
|
this.child(
|
|
h_flex()
|
|
.gap_1p5()
|
|
.child(
|
|
Icon::new(IconName::Check)
|
|
.color(Color::Success)
|
|
.size(IconSize::XSmall),
|
|
)
|
|
.child(Label::new("Imported").size(LabelSize::Small)),
|
|
)
|
|
}),
|
|
)
|
|
.on_click(move |_, window, cx| {
|
|
telemetry::event!("Welcome Import Settings", import_source = label,);
|
|
window.dispatch_action(action.boxed_clone(), cx);
|
|
}),
|
|
)
|
|
}
|
|
|
|
fn render_import_settings_section(tab_index: &mut isize, cx: &App) -> impl IntoElement {
|
|
let import_state = SettingsImportState::global(cx);
|
|
let imports: [(SharedString, IconName, &dyn Action, bool); 2] = [
|
|
(
|
|
"VS Code".into(),
|
|
IconName::EditorVsCode,
|
|
&ImportVsCodeSettings { skip_prompt: false },
|
|
import_state.vscode,
|
|
),
|
|
(
|
|
"Cursor".into(),
|
|
IconName::EditorCursor,
|
|
&ImportCursorSettings { skip_prompt: false },
|
|
import_state.cursor,
|
|
),
|
|
];
|
|
|
|
let [vscode, cursor] = imports.map(|(label, icon_name, action, imported)| {
|
|
*tab_index += 1;
|
|
render_setting_import_button(*tab_index - 1, label, icon_name, action, imported)
|
|
});
|
|
|
|
v_flex()
|
|
.gap_4()
|
|
.child(
|
|
v_flex()
|
|
.child(Label::new("Import Settings").size(LabelSize::Large))
|
|
.child(
|
|
Label::new("Automatically pull your settings from other editors.")
|
|
.color(Color::Muted),
|
|
),
|
|
)
|
|
.child(h_flex().w_full().gap_4().child(vscode).child(cursor))
|
|
}
|
|
|
|
fn render_font_customization_section(
|
|
tab_index: &mut isize,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> impl IntoElement {
|
|
let theme_settings = ThemeSettings::get_global(cx);
|
|
let ui_font_size = theme_settings.ui_font_size(cx);
|
|
let ui_font_family = theme_settings.ui_font.family.clone();
|
|
let buffer_font_family = theme_settings.buffer_font.family.clone();
|
|
let buffer_font_size = theme_settings.buffer_font_size(cx);
|
|
|
|
let ui_font_picker =
|
|
cx.new(|cx| font_picker(ui_font_family.clone(), write_ui_font_family, window, cx));
|
|
|
|
let buffer_font_picker = cx.new(|cx| {
|
|
font_picker(
|
|
buffer_font_family.clone(),
|
|
write_buffer_font_family,
|
|
window,
|
|
cx,
|
|
)
|
|
});
|
|
|
|
let ui_font_handle = ui::PopoverMenuHandle::default();
|
|
let buffer_font_handle = ui::PopoverMenuHandle::default();
|
|
|
|
h_flex()
|
|
.w_full()
|
|
.gap_4()
|
|
.child(
|
|
v_flex()
|
|
.w_full()
|
|
.gap_1()
|
|
.child(Label::new("UI Font"))
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.gap_2()
|
|
.child(
|
|
PopoverMenu::new("ui-font-picker")
|
|
.menu({
|
|
let ui_font_picker = ui_font_picker;
|
|
move |_window, _cx| Some(ui_font_picker.clone())
|
|
})
|
|
.trigger(
|
|
ButtonLike::new("ui-font-family-button")
|
|
.style(ButtonStyle::Outlined)
|
|
.size(ButtonSize::Medium)
|
|
.full_width()
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
})
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.child(Label::new(ui_font_family))
|
|
.child(
|
|
Icon::new(IconName::ChevronUpDown)
|
|
.color(Color::Muted)
|
|
.size(IconSize::XSmall),
|
|
),
|
|
),
|
|
)
|
|
.full_width(true)
|
|
.anchor(gpui::Corner::TopLeft)
|
|
.offset(gpui::Point {
|
|
x: px(0.0),
|
|
y: px(4.0),
|
|
})
|
|
.with_handle(ui_font_handle),
|
|
)
|
|
.child(
|
|
NumericStepper::new(
|
|
"ui-font-size",
|
|
ui_font_size.to_string(),
|
|
move |_, _, cx| {
|
|
write_ui_font_size(ui_font_size - px(1.), cx);
|
|
},
|
|
move |_, _, cx| {
|
|
write_ui_font_size(ui_font_size + px(1.), cx);
|
|
},
|
|
)
|
|
.style(ui::NumericStepperStyle::Outlined)
|
|
.tab_index({
|
|
*tab_index += 2;
|
|
*tab_index - 2
|
|
}),
|
|
),
|
|
),
|
|
)
|
|
.child(
|
|
v_flex()
|
|
.w_full()
|
|
.gap_1()
|
|
.child(Label::new("Editor Font"))
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.gap_2()
|
|
.child(
|
|
PopoverMenu::new("buffer-font-picker")
|
|
.menu({
|
|
let buffer_font_picker = buffer_font_picker;
|
|
move |_window, _cx| Some(buffer_font_picker.clone())
|
|
})
|
|
.trigger(
|
|
ButtonLike::new("buffer-font-family-button")
|
|
.style(ButtonStyle::Outlined)
|
|
.size(ButtonSize::Medium)
|
|
.full_width()
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
})
|
|
.child(
|
|
h_flex()
|
|
.w_full()
|
|
.justify_between()
|
|
.child(Label::new(buffer_font_family))
|
|
.child(
|
|
Icon::new(IconName::ChevronUpDown)
|
|
.color(Color::Muted)
|
|
.size(IconSize::XSmall),
|
|
),
|
|
),
|
|
)
|
|
.full_width(true)
|
|
.anchor(gpui::Corner::TopLeft)
|
|
.offset(gpui::Point {
|
|
x: px(0.0),
|
|
y: px(4.0),
|
|
})
|
|
.with_handle(buffer_font_handle),
|
|
)
|
|
.child(
|
|
NumericStepper::new(
|
|
"buffer-font-size",
|
|
buffer_font_size.to_string(),
|
|
move |_, _, cx| {
|
|
write_buffer_font_size(buffer_font_size - px(1.), cx);
|
|
},
|
|
move |_, _, cx| {
|
|
write_buffer_font_size(buffer_font_size + px(1.), cx);
|
|
},
|
|
)
|
|
.style(ui::NumericStepperStyle::Outlined)
|
|
.tab_index({
|
|
*tab_index += 2;
|
|
*tab_index - 2
|
|
}),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
|
|
type FontPicker = Picker<FontPickerDelegate>;
|
|
|
|
pub struct FontPickerDelegate {
|
|
fonts: Vec<SharedString>,
|
|
filtered_fonts: Vec<StringMatch>,
|
|
selected_index: usize,
|
|
current_font: SharedString,
|
|
on_font_changed: Arc<dyn Fn(SharedString, &mut App) + 'static>,
|
|
}
|
|
|
|
impl FontPickerDelegate {
|
|
fn new(
|
|
current_font: SharedString,
|
|
on_font_changed: impl Fn(SharedString, &mut App) + 'static,
|
|
cx: &mut Context<FontPicker>,
|
|
) -> Self {
|
|
let font_family_cache = FontFamilyCache::global(cx);
|
|
|
|
let fonts: Vec<SharedString> = font_family_cache
|
|
.list_font_families(cx)
|
|
.into_iter()
|
|
.collect();
|
|
|
|
let selected_index = fonts
|
|
.iter()
|
|
.position(|font| *font == current_font)
|
|
.unwrap_or(0);
|
|
|
|
Self {
|
|
fonts: fonts.clone(),
|
|
filtered_fonts: fonts
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(index, font)| StringMatch {
|
|
candidate_id: index,
|
|
string: font.to_string(),
|
|
positions: Vec::new(),
|
|
score: 0.0,
|
|
})
|
|
.collect(),
|
|
selected_index,
|
|
current_font,
|
|
on_font_changed: Arc::new(on_font_changed),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PickerDelegate for FontPickerDelegate {
|
|
type ListItem = AnyElement;
|
|
|
|
fn match_count(&self) -> usize {
|
|
self.filtered_fonts.len()
|
|
}
|
|
|
|
fn selected_index(&self) -> usize {
|
|
self.selected_index
|
|
}
|
|
|
|
fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context<FontPicker>) {
|
|
self.selected_index = ix.min(self.filtered_fonts.len().saturating_sub(1));
|
|
cx.notify();
|
|
}
|
|
|
|
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
|
|
"Search fonts…".into()
|
|
}
|
|
|
|
fn update_matches(
|
|
&mut self,
|
|
query: String,
|
|
_window: &mut Window,
|
|
cx: &mut Context<FontPicker>,
|
|
) -> Task<()> {
|
|
let fonts = self.fonts.clone();
|
|
let current_font = self.current_font.clone();
|
|
|
|
let matches: Vec<StringMatch> = if query.is_empty() {
|
|
fonts
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(index, font)| StringMatch {
|
|
candidate_id: index,
|
|
string: font.to_string(),
|
|
positions: Vec::new(),
|
|
score: 0.0,
|
|
})
|
|
.collect()
|
|
} else {
|
|
let _candidates: Vec<StringMatchCandidate> = fonts
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(id, font)| StringMatchCandidate::new(id, font.as_ref()))
|
|
.collect();
|
|
|
|
fonts
|
|
.iter()
|
|
.enumerate()
|
|
.filter(|(_, font)| font.to_lowercase().contains(&query.to_lowercase()))
|
|
.map(|(index, font)| StringMatch {
|
|
candidate_id: index,
|
|
string: font.to_string(),
|
|
positions: Vec::new(),
|
|
score: 0.0,
|
|
})
|
|
.collect()
|
|
};
|
|
|
|
let selected_index = if query.is_empty() {
|
|
fonts
|
|
.iter()
|
|
.position(|font| *font == current_font)
|
|
.unwrap_or(0)
|
|
} else {
|
|
matches
|
|
.iter()
|
|
.position(|m| fonts[m.candidate_id] == current_font)
|
|
.unwrap_or(0)
|
|
};
|
|
|
|
self.filtered_fonts = matches;
|
|
self.selected_index = selected_index;
|
|
cx.notify();
|
|
|
|
Task::ready(())
|
|
}
|
|
|
|
fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context<FontPicker>) {
|
|
if let Some(font_match) = self.filtered_fonts.get(self.selected_index) {
|
|
let font = font_match.string.clone();
|
|
(self.on_font_changed)(font.into(), cx);
|
|
}
|
|
}
|
|
|
|
fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context<FontPicker>) {}
|
|
|
|
fn render_match(
|
|
&self,
|
|
ix: usize,
|
|
selected: bool,
|
|
_window: &mut Window,
|
|
_cx: &mut Context<FontPicker>,
|
|
) -> Option<Self::ListItem> {
|
|
let font_match = self.filtered_fonts.get(ix)?;
|
|
|
|
Some(
|
|
ListItem::new(ix)
|
|
.inset(true)
|
|
.spacing(ListItemSpacing::Sparse)
|
|
.toggle_state(selected)
|
|
.child(Label::new(font_match.string.clone()))
|
|
.into_any_element(),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn font_picker(
|
|
current_font: SharedString,
|
|
on_font_changed: impl Fn(SharedString, &mut App) + 'static,
|
|
window: &mut Window,
|
|
cx: &mut Context<FontPicker>,
|
|
) -> FontPicker {
|
|
let delegate = FontPickerDelegate::new(current_font, on_font_changed, cx);
|
|
|
|
Picker::uniform_list(delegate, window, cx)
|
|
.show_scrollbar(true)
|
|
.width(rems_from_px(210.))
|
|
.max_height(Some(rems(20.).into()))
|
|
}
|
|
|
|
fn render_popular_settings_section(
|
|
tab_index: &mut isize,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> impl IntoElement {
|
|
const LIGATURE_TOOLTIP: &str =
|
|
"Font ligatures combine two characters into one. For example, turning != into ≠.";
|
|
|
|
v_flex()
|
|
.pt_6()
|
|
.gap_4()
|
|
.border_t_1()
|
|
.border_color(cx.theme().colors().border_variant.opacity(0.5))
|
|
.child(Label::new("Popular Settings").size(LabelSize::Large))
|
|
.child(render_font_customization_section(tab_index, window, cx))
|
|
.child(
|
|
SwitchField::new(
|
|
"onboarding-font-ligatures",
|
|
"Font Ligatures",
|
|
Some("Combine text characters into their associated symbols.".into()),
|
|
if read_font_ligatures(cx) {
|
|
ui::ToggleState::Selected
|
|
} else {
|
|
ui::ToggleState::Unselected
|
|
},
|
|
|toggle_state, _, cx| {
|
|
let enabled = toggle_state == &ToggleState::Selected;
|
|
telemetry::event!(
|
|
"Welcome Font Ligature",
|
|
options = if enabled { "on" } else { "off" },
|
|
);
|
|
|
|
write_font_ligatures(enabled, cx);
|
|
},
|
|
)
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
})
|
|
.tooltip(Tooltip::text(LIGATURE_TOOLTIP)),
|
|
)
|
|
.child(
|
|
SwitchField::new(
|
|
"onboarding-format-on-save",
|
|
"Format on Save",
|
|
Some("Format code automatically when saving.".into()),
|
|
if read_format_on_save(cx) {
|
|
ui::ToggleState::Selected
|
|
} else {
|
|
ui::ToggleState::Unselected
|
|
},
|
|
|toggle_state, _, cx| {
|
|
let enabled = toggle_state == &ToggleState::Selected;
|
|
telemetry::event!(
|
|
"Welcome Format On Save Changed",
|
|
options = if enabled { "on" } else { "off" },
|
|
);
|
|
|
|
write_format_on_save(enabled, cx);
|
|
},
|
|
)
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
}),
|
|
)
|
|
.child(
|
|
SwitchField::new(
|
|
"onboarding-enable-inlay-hints",
|
|
"Inlay Hints",
|
|
Some("See parameter names for function and method calls inline.".into()),
|
|
if read_inlay_hints(cx) {
|
|
ui::ToggleState::Selected
|
|
} else {
|
|
ui::ToggleState::Unselected
|
|
},
|
|
|toggle_state, _, cx| {
|
|
let enabled = toggle_state == &ToggleState::Selected;
|
|
telemetry::event!(
|
|
"Welcome Inlay Hints Changed",
|
|
options = if enabled { "on" } else { "off" },
|
|
);
|
|
|
|
write_inlay_hints(enabled, cx);
|
|
},
|
|
)
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
}),
|
|
)
|
|
.child(
|
|
SwitchField::new(
|
|
"onboarding-git-blame-switch",
|
|
"Inline Git Blame",
|
|
Some("See who committed each line on a given file.".into()),
|
|
if read_git_blame(cx) {
|
|
ui::ToggleState::Selected
|
|
} else {
|
|
ui::ToggleState::Unselected
|
|
},
|
|
|toggle_state, _, cx| {
|
|
let enabled = toggle_state == &ToggleState::Selected;
|
|
telemetry::event!(
|
|
"Welcome Git Blame Changed",
|
|
options = if enabled { "on" } else { "off" },
|
|
);
|
|
|
|
write_git_blame(enabled, cx);
|
|
},
|
|
)
|
|
.tab_index({
|
|
*tab_index += 1;
|
|
*tab_index - 1
|
|
}),
|
|
)
|
|
.child(
|
|
h_flex()
|
|
.items_start()
|
|
.justify_between()
|
|
.child(
|
|
v_flex().child(Label::new("Minimap")).child(
|
|
Label::new("See a high-level overview of your source code.")
|
|
.color(Color::Muted),
|
|
),
|
|
)
|
|
.child(
|
|
ToggleButtonGroup::single_row(
|
|
"onboarding-show-mini-map",
|
|
[
|
|
ToggleButtonSimple::new("Auto", |_, _, cx| {
|
|
write_show_mini_map(ShowMinimap::Auto, cx);
|
|
})
|
|
.tooltip(Tooltip::text(
|
|
"Show the minimap if the editor's scrollbar is visible.",
|
|
)),
|
|
ToggleButtonSimple::new("Always", |_, _, cx| {
|
|
write_show_mini_map(ShowMinimap::Always, cx);
|
|
}),
|
|
ToggleButtonSimple::new("Never", |_, _, cx| {
|
|
write_show_mini_map(ShowMinimap::Never, cx);
|
|
}),
|
|
],
|
|
)
|
|
.selected_index(match read_show_mini_map(cx) {
|
|
ShowMinimap::Auto => 0,
|
|
ShowMinimap::Always => 1,
|
|
ShowMinimap::Never => 2,
|
|
})
|
|
.tab_index(tab_index)
|
|
.style(ToggleButtonGroupStyle::Outlined)
|
|
.width(ui::rems_from_px(3. * 64.)),
|
|
),
|
|
)
|
|
}
|
|
|
|
pub(crate) fn render_editing_page(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
let mut tab_index = 0;
|
|
v_flex()
|
|
.gap_6()
|
|
.child(render_import_settings_section(&mut tab_index, cx))
|
|
.child(render_popular_settings_section(&mut tab_index, window, cx))
|
|
}
|