settings_ui: Refactor item renderers to render entire field (#39959)

Ben Kunkle created

Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/settings_ui/src/settings_ui.rs | 511 ++++++++++++----------------
1 file changed, 221 insertions(+), 290 deletions(-)

Detailed changes

crates/settings_ui/src/settings_ui.rs 🔗

@@ -8,7 +8,7 @@ use feature_flags::FeatureFlag;
 use fuzzy::StringMatchCandidate;
 use gpui::{
     Action, App, Div, Entity, FocusHandle, Focusable, FontWeight, Global, ReadGlobal as _,
-    ScrollHandle, Subscription, Task, TitlebarOptions, UniformListScrollHandle, Window,
+    ScrollHandle, Stateful, Subscription, Task, TitlebarOptions, UniformListScrollHandle, Window,
     WindowBounds, WindowHandle, WindowOptions, actions, div, point, prelude::*, px, size,
     uniform_list,
 };
@@ -83,12 +83,20 @@ actions!(
 #[action(namespace = settings_editor)]
 struct FocusFile(pub u32);
 
-#[derive(Clone, Copy)]
 struct SettingField<T: 'static> {
     pick: fn(&SettingsContent) -> &Option<T>,
     pick_mut: fn(&mut SettingsContent) -> &mut Option<T>,
 }
 
+impl<T: 'static> Clone for SettingField<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+// manual impl because derive puts a Copy bound on T, which is inaccurate in our case
+impl<T: 'static> Copy for SettingField<T> {}
+
 /// Helper for unimplemented settings, used in combination with `SettingField::unimplemented`
 /// to keep the setting around in the UI with valid pick and pick_mut implementations, but don't actually try to render it.
 /// TODO(settings_ui): In non-dev builds (`#[cfg(not(debug_assertions))]`) make this render as edit-in-json
@@ -99,7 +107,7 @@ impl<T: 'static> SettingField<T> {
     #[allow(unused)]
     fn unimplemented(self) -> SettingField<UnimplementedSettingField> {
         SettingField {
-            pick: |_| &None,
+            pick: |_| &Some(UnimplementedSettingField),
             pick_mut: |_| unreachable!(),
         }
     }
@@ -127,10 +135,6 @@ impl<T> AnySettingField for SettingField<T> {
     }
 
     fn file_set_in(&self, file: SettingsUiFile, cx: &App) -> (settings::SettingsFile, bool) {
-        if AnySettingField::type_id(self) == TypeId::of::<UnimplementedSettingField>() {
-            return (file.to_settings(), true);
-        }
-
         let (file, value) = cx
             .global::<SettingsStore>()
             .get_value_from_file(file.to_settings(), self.pick);
@@ -146,12 +150,13 @@ struct SettingFieldRenderer {
                 TypeId,
                 Box<
                     dyn Fn(
-                        &dyn AnySettingField,
+                        &SettingsWindow,
+                        &SettingItem,
                         SettingsUiFile,
                         Option<&SettingsFieldMetadata>,
                         &mut Window,
-                        &mut App,
-                    ) -> AnyElement,
+                        &mut Context<SettingsWindow>,
+                    ) -> Stateful<Div>,
                 >,
             >,
         >,
@@ -161,62 +166,78 @@ struct SettingFieldRenderer {
 impl Global for SettingFieldRenderer {}
 
 impl SettingFieldRenderer {
-    fn add_renderer<T: 'static>(
+    fn add_basic_renderer<T: 'static>(
         &mut self,
-        renderer: impl Fn(
-            &SettingField<T>,
+        render_control: impl Fn(
+            SettingField<T>,
             SettingsUiFile,
             Option<&SettingsFieldMetadata>,
             &mut Window,
             &mut App,
         ) -> AnyElement
         + 'static,
+    ) -> &mut Self {
+        self.add_renderer(
+            move |settings_window: &SettingsWindow,
+                  item: &SettingItem,
+                  field: SettingField<T>,
+                  settings_file: SettingsUiFile,
+                  metadata: Option<&SettingsFieldMetadata>,
+                  window: &mut Window,
+                  cx: &mut Context<SettingsWindow>| {
+                render_settings_item(
+                    settings_window,
+                    item,
+                    settings_file.clone(),
+                    render_control(field, settings_file, metadata, window, cx),
+                    window,
+                    cx,
+                )
+            },
+        )
+    }
+
+    fn add_renderer<T: 'static>(
+        &mut self,
+        renderer: impl Fn(
+            &SettingsWindow,
+            &SettingItem,
+            SettingField<T>,
+            SettingsUiFile,
+            Option<&SettingsFieldMetadata>,
+            &mut Window,
+            &mut Context<SettingsWindow>,
+        ) -> Stateful<Div>
+        + 'static,
     ) -> &mut Self {
         let key = TypeId::of::<T>();
         let renderer = Box::new(
-            move |any_setting_field: &dyn AnySettingField,
+            move |settings_window: &SettingsWindow,
+                  item: &SettingItem,
                   settings_file: SettingsUiFile,
                   metadata: Option<&SettingsFieldMetadata>,
                   window: &mut Window,
-                  cx: &mut App| {
-                let field = any_setting_field
+                  cx: &mut Context<SettingsWindow>| {
+                let field = *item
+                    .field
+                    .as_ref()
                     .as_any()
                     .downcast_ref::<SettingField<T>>()
                     .unwrap();
-                renderer(field, settings_file, metadata, window, cx)
+                renderer(
+                    settings_window,
+                    item,
+                    field,
+                    settings_file,
+                    metadata,
+                    window,
+                    cx,
+                )
             },
         );
         self.renderers.borrow_mut().insert(key, renderer);
         self
     }
-
-    fn render(
-        &self,
-        any_setting_field: &dyn AnySettingField,
-        settings_file: SettingsUiFile,
-        metadata: Option<&SettingsFieldMetadata>,
-        window: &mut Window,
-        cx: &mut App,
-    ) -> AnyElement {
-        let key = any_setting_field.type_id();
-        if let Some(renderer) = self.renderers.borrow().get(&key) {
-            renderer(any_setting_field, settings_file, metadata, window, cx)
-        } else {
-            Button::new("no-renderer", "NO RENDERER")
-                .style(ButtonStyle::Outlined)
-                .size(ButtonSize::Medium)
-                .icon(Some(IconName::XCircle))
-                .icon_position(IconPosition::Start)
-                .icon_color(Color::Error)
-                .tab_index(0_isize)
-                .tooltip(Tooltip::text(any_setting_field.type_name()))
-                .into_any_element()
-            // panic!(
-            //     "No renderer found for type: {}",
-            //     any_setting_field.type_name()
-            // )
-        }
-    }
 }
 
 struct NonFocusableHandle {
@@ -278,7 +299,7 @@ pub fn init(cx: &mut App) {
 
 fn init_renderers(cx: &mut App) {
     cx.default_global::<SettingFieldRenderer>()
-        .add_renderer::<UnimplementedSettingField>(|_, _, _, _, _| {
+        .add_basic_renderer::<UnimplementedSettingField>(|_, _, _, _, _| {
             Button::new("open-in-settings-file", "Edit in settings.json")
                 .style(ButtonStyle::Outlined)
                 .size(ButtonSize::Medium)
@@ -288,197 +309,70 @@ fn init_renderers(cx: &mut App) {
                 })
                 .into_any_element()
         })
-        .add_renderer::<bool>(|settings_field, file, _, _, cx| {
-            render_toggle_button(*settings_field, file, cx).into_any_element()
-        })
-        .add_renderer::<String>(|settings_field, file, metadata, _, cx| {
-            render_text_field(settings_field.clone(), file, metadata, cx)
-        })
-        .add_renderer::<SaturatingBool>(|settings_field, file, _, _, cx| {
-            render_toggle_button(*settings_field, file, cx)
-        })
-        .add_renderer::<CursorShape>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<RestoreOnStartupBehavior>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<BottomDockLayout>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<OnLastWindowClosed>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<CloseWindowWhenNoItems>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::FontFamilyName>(|settings_field, file, _, window, cx| {
-            // todo(settings_ui): We need to pass in a validator for this to ensure that users that type in invalid font names
-            render_font_picker(settings_field.clone(), file, window, cx)
-        })
+        .add_basic_renderer::<bool>(render_toggle_button)
+        .add_basic_renderer::<String>(render_text_field)
+        .add_basic_renderer::<SaturatingBool>(render_toggle_button)
+        .add_basic_renderer::<CursorShape>(render_dropdown)
+        .add_basic_renderer::<RestoreOnStartupBehavior>(render_dropdown)
+        .add_basic_renderer::<BottomDockLayout>(render_dropdown)
+        .add_basic_renderer::<OnLastWindowClosed>(render_dropdown)
+        .add_basic_renderer::<CloseWindowWhenNoItems>(render_dropdown)
+        .add_basic_renderer::<settings::FontFamilyName>(render_font_picker)
         // todo(settings_ui): This needs custom ui
         // .add_renderer::<settings::BufferLineHeight>(|settings_field, file, _, window, cx| {
         //     // todo(settings_ui): Do we want to expose the custom variant of buffer line height?
         //     // right now there's a manual impl of strum::VariantArray
         //     render_dropdown(*settings_field, file, window, cx)
         // })
-        .add_renderer::<settings::BaseKeymapContent>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::MultiCursorModifier>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::HideMouseMode>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::CurrentLineHighlight>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowWhitespaceSetting>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::SoftWrap>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ScrollBeyondLastLine>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::SnippetSortOrder>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ClosePosition>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::DockSide>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::TerminalDockPosition>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::DockPosition>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::GitGutterSetting>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::GitHunkStyleSetting>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::DiagnosticSeverityContent>(
-            |settings_field, file, _, window, cx| {
-                render_dropdown(*settings_field, file, window, cx)
-            },
-        )
-        .add_renderer::<settings::SeedQuerySetting>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::DoubleClickInMultibuffer>(
-            |settings_field, file, _, window, cx| {
-                render_dropdown(*settings_field, file, window, cx)
-            },
-        )
-        .add_renderer::<settings::GoToDefinitionFallback>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ActivateOnClose>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowDiagnostics>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowCloseButton>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ProjectPanelEntrySpacing>(
-            |settings_field, file, _, window, cx| {
-                render_dropdown(*settings_field, file, window, cx)
-            },
-        )
-        .add_renderer::<settings::RewrapBehavior>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::FormatOnSave>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::IndentGuideColoring>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::IndentGuideBackgroundColoring>(
-            |settings_field, file, _, window, cx| {
-                render_dropdown(*settings_field, file, window, cx)
-            },
-        )
-        .add_renderer::<settings::FileFinderWidthContent>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowDiagnostics>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::WordsCompletionMode>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::LspInsertMode>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::AlternateScroll>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::TerminalBlink>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::CursorShapeContent>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<f32>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<u32>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<u64>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<usize>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<NonZero<usize>>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<NonZeroU32>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<CodeFade>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<FontWeight>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::MinimumContrast>(|settings_field, file, _, window, cx| {
-            render_number_field(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowScrollbar>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ScrollbarDiagnostics>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::ShowMinimap>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::DisplayIn>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::MinimapThumb>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::MinimapThumbBorder>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        })
-        .add_renderer::<settings::SteppingGranularity>(|settings_field, file, _, window, cx| {
-            render_dropdown(*settings_field, file, window, cx)
-        });
-
-    // todo(settings_ui): Figure out how we want to handle discriminant unions
+        .add_basic_renderer::<settings::BaseKeymapContent>(render_dropdown)
+        .add_basic_renderer::<settings::MultiCursorModifier>(render_dropdown)
+        .add_basic_renderer::<settings::HideMouseMode>(render_dropdown)
+        .add_basic_renderer::<settings::CurrentLineHighlight>(render_dropdown)
+        .add_basic_renderer::<settings::ShowWhitespaceSetting>(render_dropdown)
+        .add_basic_renderer::<settings::SoftWrap>(render_dropdown)
+        .add_basic_renderer::<settings::ScrollBeyondLastLine>(render_dropdown)
+        .add_basic_renderer::<settings::SnippetSortOrder>(render_dropdown)
+        .add_basic_renderer::<settings::ClosePosition>(render_dropdown)
+        .add_basic_renderer::<settings::DockSide>(render_dropdown)
+        .add_basic_renderer::<settings::TerminalDockPosition>(render_dropdown)
+        .add_basic_renderer::<settings::DockPosition>(render_dropdown)
+        .add_basic_renderer::<settings::GitGutterSetting>(render_dropdown)
+        .add_basic_renderer::<settings::GitHunkStyleSetting>(render_dropdown)
+        .add_basic_renderer::<settings::DiagnosticSeverityContent>(render_dropdown)
+        .add_basic_renderer::<settings::SeedQuerySetting>(render_dropdown)
+        .add_basic_renderer::<settings::DoubleClickInMultibuffer>(render_dropdown)
+        .add_basic_renderer::<settings::GoToDefinitionFallback>(render_dropdown)
+        .add_basic_renderer::<settings::ActivateOnClose>(render_dropdown)
+        .add_basic_renderer::<settings::ShowDiagnostics>(render_dropdown)
+        .add_basic_renderer::<settings::ShowCloseButton>(render_dropdown)
+        .add_basic_renderer::<settings::ProjectPanelEntrySpacing>(render_dropdown)
+        .add_basic_renderer::<settings::RewrapBehavior>(render_dropdown)
+        .add_basic_renderer::<settings::FormatOnSave>(render_dropdown)
+        .add_basic_renderer::<settings::IndentGuideColoring>(render_dropdown)
+        .add_basic_renderer::<settings::IndentGuideBackgroundColoring>(render_dropdown)
+        .add_basic_renderer::<settings::FileFinderWidthContent>(render_dropdown)
+        .add_basic_renderer::<settings::ShowDiagnostics>(render_dropdown)
+        .add_basic_renderer::<settings::WordsCompletionMode>(render_dropdown)
+        .add_basic_renderer::<settings::LspInsertMode>(render_dropdown)
+        .add_basic_renderer::<settings::AlternateScroll>(render_dropdown)
+        .add_basic_renderer::<settings::TerminalBlink>(render_dropdown)
+        .add_basic_renderer::<settings::CursorShapeContent>(render_dropdown)
+        .add_basic_renderer::<f32>(render_number_field)
+        .add_basic_renderer::<u32>(render_number_field)
+        .add_basic_renderer::<u64>(render_number_field)
+        .add_basic_renderer::<usize>(render_number_field)
+        .add_basic_renderer::<NonZero<usize>>(render_number_field)
+        .add_basic_renderer::<NonZeroU32>(render_number_field)
+        .add_basic_renderer::<CodeFade>(render_number_field)
+        .add_basic_renderer::<FontWeight>(render_number_field)
+        .add_basic_renderer::<settings::MinimumContrast>(render_number_field)
+        .add_basic_renderer::<settings::ShowScrollbar>(render_dropdown)
+        .add_basic_renderer::<settings::ScrollbarDiagnostics>(render_dropdown)
+        .add_basic_renderer::<settings::ShowMinimap>(render_dropdown)
+        .add_basic_renderer::<settings::DisplayIn>(render_dropdown)
+        .add_basic_renderer::<settings::MinimapThumb>(render_dropdown)
+        .add_basic_renderer::<settings::MinimapThumbBorder>(render_dropdown)
+        .add_basic_renderer::<settings::SteppingGranularity>(render_dropdown);
     // .add_renderer::<ThemeSelection>(|settings_field, file, _, window, cx| {
     //     render_dropdown(*settings_field, file, window, cx)
     // });
@@ -636,14 +530,48 @@ impl SettingsPageItem {
                 .into_any_element(),
             SettingsPageItem::SettingItem(setting_item) => {
                 let renderer = cx.default_global::<SettingFieldRenderer>().clone();
-                let (found_in_file, found) = setting_item.field.file_set_in(file.clone(), cx);
-                let file_set_in = SettingsUiFile::from_settings(found_in_file);
+                let (_, found) = setting_item.field.file_set_in(file.clone(), cx);
+
+                let renderers = renderer.renderers.borrow();
+                let field_renderer =
+                    renderers.get(&AnySettingField::type_id(setting_item.field.as_ref()));
+                let field_renderer_or_warning =
+                    field_renderer.ok_or("NO RENDERER").and_then(|renderer| {
+                        if cfg!(debug_assertions) && !found {
+                            Err("NO DEFAULT")
+                        } else {
+                            Ok(renderer)
+                        }
+                    });
 
-                h_flex()
-                    .id(setting_item.title)
-                    .min_w_0()
-                    .gap_2()
-                    .justify_between()
+                let field = match field_renderer_or_warning {
+                    Ok(field_renderer) => field_renderer(
+                        settings_window,
+                        setting_item,
+                        file,
+                        setting_item.metadata.as_deref(),
+                        window,
+                        cx,
+                    ),
+                    Err(warning) => render_settings_item(
+                        settings_window,
+                        setting_item,
+                        file,
+                        Button::new("error-warning", warning)
+                            .style(ButtonStyle::Outlined)
+                            .size(ButtonSize::Medium)
+                            .icon(Some(IconName::Debug))
+                            .icon_position(IconPosition::Start)
+                            .icon_color(Color::Error)
+                            .tab_index(0_isize)
+                            .tooltip(Tooltip::text(setting_item.field.type_name()))
+                            .into_any_element(),
+                        window,
+                        cx,
+                    ),
+                };
+
+                field
                     .pt_4()
                     .map(|this| {
                         if is_last {
@@ -654,58 +582,6 @@ impl SettingsPageItem {
                                 .border_color(cx.theme().colors().border_variant)
                         }
                     })
-                    .child(
-                        v_flex()
-                            .w_full()
-                            .max_w_1_2()
-                            .child(
-                                h_flex()
-                                    .w_full()
-                                    .gap_1()
-                                    .child(Label::new(SharedString::new_static(setting_item.title)))
-                                    .when_some(
-                                        file_set_in.filter(|file_set_in| file_set_in != &file),
-                                        |this, file_set_in| {
-                                            this.child(
-                                                Label::new(format!(
-                                                    "— set in {}",
-                                                    settings_window
-                                                        .display_name(&file_set_in)
-                                                        .expect("File name should exist")
-                                                ))
-                                                .color(Color::Muted)
-                                                .size(LabelSize::Small),
-                                            )
-                                        },
-                                    ),
-                            )
-                            .child(
-                                Label::new(SharedString::new_static(setting_item.description))
-                                    .size(LabelSize::Small)
-                                    .color(Color::Muted),
-                            ),
-                    )
-                    .child(if cfg!(debug_assertions) && !found {
-                        Button::new("no-default-field", "NO DEFAULT")
-                            .size(ButtonSize::Medium)
-                            .icon(IconName::XCircle)
-                            .icon_position(IconPosition::Start)
-                            .icon_color(Color::Error)
-                            .icon_size(IconSize::Small)
-                            .style(ButtonStyle::Outlined)
-                            .tooltip(Tooltip::text(
-                                "This warning is only displayed in dev builds.",
-                            ))
-                            .into_any_element()
-                    } else {
-                        renderer.render(
-                            setting_item.field.as_ref(),
-                            file,
-                            setting_item.metadata.as_deref(),
-                            window,
-                            cx,
-                        )
-                    })
                     .into_any_element()
             }
             SettingsPageItem::SubPageLink(sub_page_link) => h_flex()
@@ -747,6 +623,55 @@ impl SettingsPageItem {
     }
 }
 
+fn render_settings_item(
+    settings_window: &SettingsWindow,
+    setting_item: &SettingItem,
+    file: SettingsUiFile,
+    control: AnyElement,
+    _window: &mut Window,
+    cx: &mut Context<'_, SettingsWindow>,
+) -> Stateful<Div> {
+    let (found_in_file, _) = setting_item.field.file_set_in(file.clone(), cx);
+    let file_set_in = SettingsUiFile::from_settings(found_in_file);
+
+    h_flex()
+        .id(setting_item.title)
+        .min_w_0()
+        .gap_2()
+        .justify_between()
+        .child(
+            v_flex()
+                .w_1_2()
+                .child(
+                    h_flex()
+                        .w_full()
+                        .gap_1()
+                        .child(Label::new(SharedString::new_static(setting_item.title)))
+                        .when_some(
+                            file_set_in.filter(|file_set_in| file_set_in != &file),
+                            |this, file_set_in| {
+                                this.child(
+                                    Label::new(format!(
+                                        "— set in {}",
+                                        settings_window
+                                            .display_name(&file_set_in)
+                                            .expect("File name should exist")
+                                    ))
+                                    .color(Color::Muted)
+                                    .size(LabelSize::Small),
+                                )
+                            },
+                        ),
+                )
+                .child(
+                    Label::new(SharedString::new_static(setting_item.description))
+                        .size(LabelSize::Small)
+                        .color(Color::Muted),
+                ),
+        )
+        .child(control)
+}
+
 struct SettingItem {
     title: &'static str,
     description: &'static str,
@@ -2157,6 +2082,7 @@ fn render_text_field<T: From<String> + Into<String> + AsRef<str> + Clone>(
     field: SettingField<T>,
     file: SettingsUiFile,
     metadata: Option<&SettingsFieldMetadata>,
+    _window: &mut Window,
     cx: &mut App,
 ) -> AnyElement {
     let (_, initial_text) =
@@ -2186,6 +2112,8 @@ fn render_text_field<T: From<String> + Into<String> + AsRef<str> + Clone>(
 fn render_toggle_button<B: Into<bool> + From<bool> + Copy>(
     field: SettingField<B>,
     file: SettingsUiFile,
+    _metadata: Option<&SettingsFieldMetadata>,
+    _window: &mut Window,
     cx: &mut App,
 ) -> AnyElement {
     let (_, value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick);
@@ -2215,6 +2143,7 @@ fn render_toggle_button<B: Into<bool> + From<bool> + Copy>(
 fn render_font_picker(
     field: SettingField<settings::FontFamilyName>,
     file: SettingsUiFile,
+    _metadata: Option<&SettingsFieldMetadata>,
     window: &mut Window,
     cx: &mut App,
 ) -> AnyElement {
@@ -2262,6 +2191,7 @@ fn render_font_picker(
 fn render_number_field<T: NumberFieldType + Send + Sync>(
     field: SettingField<T>,
     file: SettingsUiFile,
+    _metadata: Option<&SettingsFieldMetadata>,
     window: &mut Window,
     cx: &mut App,
 ) -> AnyElement {
@@ -2283,6 +2213,7 @@ fn render_number_field<T: NumberFieldType + Send + Sync>(
 fn render_dropdown<T>(
     field: SettingField<T>,
     file: SettingsUiFile,
+    _metadata: Option<&SettingsFieldMetadata>,
     window: &mut Window,
     cx: &mut App,
 ) -> AnyElement