pipe window through to update settings file

This commit is contained in:
Ben Kunkle
2025-12-18 14:11:14 -05:00
parent 8bfa78d34c
commit ef3065abe7
7 changed files with 119 additions and 71 deletions

View File

@@ -17,7 +17,7 @@ where
labels: &'static [&'static str],
should_do_title_case: bool,
tab_index: Option<isize>,
on_change: Rc<dyn Fn(T, &mut App) + 'static>,
on_change: Rc<dyn Fn(T, &mut ui::Window, &mut App) + 'static>,
}
impl<T> EnumVariantDropdown<T>
@@ -29,7 +29,7 @@ where
current_value: T,
variants: &'static [T],
labels: &'static [&'static str],
on_change: impl Fn(T, &mut App) + 'static,
on_change: impl Fn(T, &mut ui::Window, &mut App) + 'static,
) -> Self {
Self {
id: id.into(),
@@ -78,8 +78,8 @@ where
value == current_value,
IconPosition::End,
None,
move |_, cx| {
on_change(value, cx);
move |window, cx| {
on_change(value, window, cx);
},
);
}

View File

@@ -13,13 +13,13 @@ pub struct FontPickerDelegate {
filtered_fonts: Vec<StringMatch>,
selected_index: usize,
current_font: SharedString,
on_font_changed: Arc<dyn Fn(SharedString, &mut App) + 'static>,
on_font_changed: Arc<dyn Fn(SharedString, &mut Window, &mut App) + 'static>,
}
impl FontPickerDelegate {
fn new(
current_font: SharedString,
on_font_changed: impl Fn(SharedString, &mut App) + 'static,
on_font_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
cx: &mut Context<FontPicker>,
) -> Self {
let font_family_cache = FontFamilyCache::global(cx);
@@ -132,10 +132,10 @@ impl PickerDelegate for FontPickerDelegate {
Task::ready(())
}
fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context<FontPicker>) {
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);
(self.on_font_changed)(font.into(), window, cx);
}
}
@@ -168,7 +168,7 @@ impl PickerDelegate for FontPickerDelegate {
pub fn font_picker(
current_font: SharedString,
on_font_changed: impl Fn(SharedString, &mut App) + 'static,
on_font_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
window: &mut Window,
cx: &mut Context<FontPicker>,
) -> FontPicker {

View File

@@ -13,13 +13,13 @@ pub struct IconThemePickerDelegate {
filtered_themes: Vec<StringMatch>,
selected_index: usize,
current_theme: SharedString,
on_theme_changed: Arc<dyn Fn(SharedString, &mut App) + 'static>,
on_theme_changed: Arc<dyn Fn(SharedString, &mut Window, &mut App) + 'static>,
}
impl IconThemePickerDelegate {
fn new(
current_theme: SharedString,
on_theme_changed: impl Fn(SharedString, &mut App) + 'static,
on_theme_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
cx: &mut Context<IconThemePicker>,
) -> Self {
let theme_registry = ThemeRegistry::global(cx);
@@ -32,15 +32,15 @@ impl IconThemePickerDelegate {
let selected_index = icon_themes
.iter()
.position(|icon_themes| *icon_themes == current_theme)
.position(|icon_theme| *icon_theme == current_theme)
.unwrap_or(0);
let filtered_themes = icon_themes
.iter()
.enumerate()
.map(|(index, icon_themes)| StringMatch {
.map(|(index, theme)| StringMatch {
candidate_id: index,
string: icon_themes.to_string(),
string: theme.to_string(),
positions: Vec::new(),
score: 0.0,
})
@@ -67,13 +67,18 @@ impl PickerDelegate for IconThemePickerDelegate {
self.selected_index
}
fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context<IconThemePicker>) {
self.selected_index = ix.min(self.filtered_themes.len().saturating_sub(1));
fn set_selected_index(
&mut self,
index: usize,
_window: &mut Window,
cx: &mut Context<IconThemePicker>,
) {
self.selected_index = index.min(self.filtered_themes.len().saturating_sub(1));
cx.notify();
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
"Search icon theme…".into()
"Search icon themes".into()
}
fn update_matches(
@@ -89,9 +94,9 @@ impl PickerDelegate for IconThemePickerDelegate {
icon_themes
.iter()
.enumerate()
.map(|(index, icon_theme)| StringMatch {
.map(|(index, theme)| StringMatch {
candidate_id: index,
string: icon_theme.to_string(),
string: theme.to_string(),
positions: Vec::new(),
score: 0.0,
})
@@ -100,16 +105,16 @@ impl PickerDelegate for IconThemePickerDelegate {
let _candidates: Vec<StringMatchCandidate> = icon_themes
.iter()
.enumerate()
.map(|(id, icon_theme)| StringMatchCandidate::new(id, icon_theme.as_ref()))
.map(|(id, theme)| StringMatchCandidate::new(id, theme.as_ref()))
.collect();
icon_themes
.iter()
.enumerate()
.filter(|(_, icon_theme)| icon_theme.to_lowercase().contains(&query.to_lowercase()))
.map(|(index, icon_theme)| StringMatch {
.filter(|(_, theme)| theme.to_lowercase().contains(&query.to_lowercase()))
.map(|(index, theme)| StringMatch {
candidate_id: index,
string: icon_theme.to_string(),
string: theme.to_string(),
positions: Vec::new(),
score: 0.0,
})
@@ -119,7 +124,7 @@ impl PickerDelegate for IconThemePickerDelegate {
let selected_index = if query.is_empty() {
icon_themes
.iter()
.position(|icon_theme| *icon_theme == current_theme)
.position(|theme| *theme == current_theme)
.unwrap_or(0)
} else {
matches
@@ -138,12 +143,12 @@ impl PickerDelegate for IconThemePickerDelegate {
fn confirm(
&mut self,
_secondary: bool,
_window: &mut Window,
window: &mut Window,
cx: &mut Context<IconThemePicker>,
) {
if let Some(theme_match) = self.filtered_themes.get(self.selected_index) {
let theme = theme_match.string.clone();
(self.on_theme_changed)(theme.into(), cx);
(self.on_theme_changed)(theme.into(), window, cx);
}
}
@@ -156,15 +161,15 @@ impl PickerDelegate for IconThemePickerDelegate {
fn render_match(
&self,
ix: usize,
index: usize,
selected: bool,
_window: &mut Window,
_cx: &mut Context<IconThemePicker>,
) -> Option<Self::ListItem> {
let theme_match = self.filtered_themes.get(ix)?;
let theme_match = self.filtered_themes.get(index)?;
Some(
ListItem::new(ix)
ListItem::new(index)
.inset(true)
.spacing(ListItemSpacing::Sparse)
.toggle_state(selected)
@@ -176,7 +181,7 @@ impl PickerDelegate for IconThemePickerDelegate {
pub fn icon_theme_picker(
current_theme: SharedString,
on_theme_changed: impl Fn(SharedString, &mut App) + 'static,
on_theme_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
window: &mut Window,
cx: &mut Context<IconThemePicker>,
) -> IconThemePicker {

View File

@@ -9,7 +9,7 @@ use ui::{
pub struct SettingsInputField {
initial_text: Option<String>,
placeholder: Option<&'static str>,
confirm: Option<Box<dyn Fn(Option<String>, &mut App)>>,
confirm: Option<Box<dyn Fn(Option<String>, &mut Window, &mut App)>>,
tab_index: Option<isize>,
}
@@ -34,7 +34,10 @@ impl SettingsInputField {
self
}
pub fn on_confirm(mut self, confirm: impl Fn(Option<String>, &mut App) + 'static) -> Self {
pub fn on_confirm(
mut self,
confirm: impl Fn(Option<String>, &mut Window, &mut App) + 'static,
) -> Self {
self.confirm = Some(Box::new(confirm));
self
}
@@ -83,13 +86,13 @@ impl RenderOnce for SettingsInputField {
.child(editor)
.when_some(self.confirm, |this, confirm| {
this.on_action::<menu::Confirm>({
move |_, _, cx| {
move |_, window, cx| {
let Some(editor) = weak_editor.upgrade() else {
return;
};
let new_value = editor.read_with(cx, |editor, cx| editor.text(cx));
let new_value = (!new_value.is_empty()).then_some(new_value);
confirm(new_value, cx);
confirm(new_value, window, cx);
}
})
})

View File

@@ -13,13 +13,13 @@ pub struct ThemePickerDelegate {
filtered_themes: Vec<StringMatch>,
selected_index: usize,
current_theme: SharedString,
on_theme_changed: Arc<dyn Fn(SharedString, &mut App) + 'static>,
on_theme_changed: Arc<dyn Fn(SharedString, &mut Window, &mut App) + 'static>,
}
impl ThemePickerDelegate {
fn new(
current_theme: SharedString,
on_theme_changed: impl Fn(SharedString, &mut App) + 'static,
on_theme_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
cx: &mut Context<ThemePicker>,
) -> Self {
let theme_registry = ThemeRegistry::global(cx);
@@ -130,10 +130,10 @@ impl PickerDelegate for ThemePickerDelegate {
Task::ready(())
}
fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context<ThemePicker>) {
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<ThemePicker>) {
if let Some(theme_match) = self.filtered_themes.get(self.selected_index) {
let theme = theme_match.string.clone();
(self.on_theme_changed)(theme.into(), cx);
(self.on_theme_changed)(theme.into(), window, cx);
}
}
@@ -166,7 +166,7 @@ impl PickerDelegate for ThemePickerDelegate {
pub fn theme_picker(
current_theme: SharedString,
on_theme_changed: impl Fn(SharedString, &mut App) + 'static,
on_theme_changed: impl Fn(SharedString, &mut Window, &mut App) + 'static,
window: &mut Window,
cx: &mut Context<ThemePicker>,
) -> ThemePicker {

View File

@@ -217,7 +217,7 @@ fn render_api_key_provider(
SettingsInputField::new()
.tab_index(0)
.with_placeholder("xxxxxxxxxxxxxxxxxxxx")
.on_confirm(move |api_key, cx| {
.on_confirm(move |api_key, _window, cx| {
write_key(api_key.filter(|key| !key.is_empty()), cx);
}),
),

View File

@@ -154,7 +154,7 @@ trait AnySettingField {
current_file: &SettingsUiFile,
file_set_in: &settings::SettingsFile,
cx: &App,
) -> Option<Box<dyn Fn(&mut App)>>;
) -> Option<Box<dyn Fn(&mut Window, &mut App)>>;
fn json_path(&self) -> Option<&'static str>;
}
@@ -184,7 +184,7 @@ impl<T: PartialEq + Clone + Send + Sync + 'static> AnySettingField for SettingFi
current_file: &SettingsUiFile,
file_set_in: &settings::SettingsFile,
cx: &App,
) -> Option<Box<dyn Fn(&mut App)>> {
) -> Option<Box<dyn Fn(&mut Window, &mut App)>> {
if file_set_in == &settings::SettingsFile::Default {
return None;
}
@@ -203,7 +203,7 @@ impl<T: PartialEq + Clone + Send + Sync + 'static> AnySettingField for SettingFi
}
let current_file = current_file.clone();
return Some(Box::new(move |cx| {
return Some(Box::new(move |window, cx| {
let store = SettingsStore::global(cx);
let default_value = (this.pick)(store.raw_default_settings());
let is_set_somewhere_other_than_default = store
@@ -215,9 +215,15 @@ impl<T: PartialEq + Clone + Send + Sync + 'static> AnySettingField for SettingFi
} else {
None
};
update_settings_file(current_file.clone(), None, cx, move |settings, _| {
(this.write)(settings, value_to_set);
})
update_settings_file(
current_file.clone(),
None,
window,
cx,
move |settings, _| {
(this.write)(settings, value_to_set);
},
)
// todo(settings_ui): Don't log err
.log_err();
}));
@@ -1068,8 +1074,8 @@ fn render_settings_item(
.icon_size(IconSize::Small)
.tooltip(Tooltip::text("Reset to Default"))
.on_click({
move |_, _, cx| {
reset_to_default(cx);
move |_, window, cx| {
reset_to_default(window, cx);
}
}),
)
@@ -3544,20 +3550,33 @@ fn all_projects(
fn update_settings_file(
file: SettingsUiFile,
file_name: Option<&'static str>,
window: &mut Window,
cx: &mut App,
update: impl 'static + Send + FnOnce(&mut SettingsContent, &App),
) -> Result<()> {
telemetry::event!("Settings Change", setting = file_name, type = file.setting_type());
let original_workspace_window =
window
.root::<SettingsWindow>()
.flatten()
.and_then(|settings_window| {
settings_window.read_with(cx, |settings_window, _cx| {
settings_window.original_window.clone()
})
});
match file {
SettingsUiFile::Project((worktree_id, rel_path)) => {
let rel_path = rel_path.join(paths::local_settings_file_relative_path());
let Some((worktree, project)) = all_projects(None, cx).find_map(|project| {
project
.read(cx)
.worktree_for_id(worktree_id, cx)
.zip(Some(project))
}) else {
let Some((worktree, project)) = all_projects(original_workspace_window.as_ref(), cx)
.find_map(|project| {
project
.read(cx)
.worktree_for_id(worktree_id, cx)
.zip(Some(project))
})
else {
anyhow::bail!("Could not find project with worktree id: {}", worktree_id);
};
@@ -3618,10 +3637,16 @@ fn render_text_field<T: From<String> + Into<String> + AsRef<str> + Clone>(
|editor, placeholder| editor.with_placeholder(placeholder),
)
.on_confirm({
move |new_text, cx| {
update_settings_file(file.clone(), field.json_path, cx, move |settings, _cx| {
(field.write)(settings, new_text.map(Into::into));
})
move |new_text, window, cx| {
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(settings, new_text.map(Into::into));
},
)
.log_err(); // todo(settings_ui) don't log err
}
})
@@ -3646,11 +3671,11 @@ fn render_toggle_button<B: Into<bool> + From<bool> + Copy>(
Switch::new("toggle_button", toggle_state)
.tab_index(0_isize)
.on_click({
move |state, _window, cx| {
move |state, window, cx| {
telemetry::event!("Settings Change", setting = field.json_path, type = file.setting_type());
let state = *state == ui::ToggleState::Selected;
update_settings_file(file.clone(), field.json_path, cx, move |settings, _cx| {
update_settings_file(file.clone(), field.json_path, window, cx, move |settings, _cx| {
(field.write)(settings, Some(state.into()));
})
.log_err(); // todo(settings_ui) don't log err
@@ -3670,11 +3695,17 @@ fn render_number_field<T: NumberFieldType + Send + Sync>(
let value = value.copied().unwrap_or_else(T::min_value);
NumberField::new("numeric_stepper", value, window, cx)
.on_change({
move |value, _window, cx| {
move |value, window, cx| {
let value = *value;
update_settings_file(file.clone(), field.json_path, cx, move |settings, _cx| {
(field.write)(settings, Some(value));
})
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(settings, Some(value));
},
)
.log_err(); // todo(settings_ui) don't log err
}
})
@@ -3702,13 +3733,19 @@ where
let current_value = current_value.copied().unwrap_or(variants()[0]);
EnumVariantDropdown::new("dropdown", current_value, variants(), labels(), {
move |value, cx| {
move |value, window, cx| {
if value == current_value {
return;
}
update_settings_file(file.clone(), field.json_path, cx, move |settings, _cx| {
(field.write)(settings, Some(value));
})
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(settings, Some(value));
},
)
.log_err(); // todo(settings_ui) don't log err
}
})
@@ -3753,10 +3790,11 @@ fn render_font_picker(
Some(cx.new(move |cx| {
font_picker(
current_value.clone().into(),
move |font_name, cx| {
move |font_name, window, cx| {
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(settings, Some(font_name.into()));
@@ -3802,10 +3840,11 @@ fn render_theme_picker(
let current_value = current_value.clone();
theme_picker(
current_value,
move |theme_name, cx| {
move |theme_name, window, cx| {
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(
@@ -3854,10 +3893,11 @@ fn render_icon_theme_picker(
let current_value = current_value.clone();
icon_theme_picker(
current_value,
move |theme_name, cx| {
move |theme_name, window, cx| {
update_settings_file(
file.clone(),
field.json_path,
window,
cx,
move |settings, _cx| {
(field.write)(