ui: Follow-up to ui crate teardown (#52747)

Piotr Osiewicz and Lukas Wirth created

- **Remove some of the settings types from ui**
- **drag settings-less ui across the line**

Self-Review Checklist:

- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable

Closes #ISSUE

Release Notes:

- N/A

---------

Co-authored-by: Lukas Wirth <me@lukaswirth.dev>

Change summary

Cargo.lock                                         |  1 
crates/csv_preview/src/csv_preview.rs              |  5 
crates/editor/src/code_context_menus.rs            |  7 -
crates/editor/src/editor.rs                        |  4 
crates/editor/src/editor_settings.rs               | 35 +++++++--
crates/editor/src/hover_popover.rs                 |  5 
crates/git_ui/src/git_panel.rs                     |  3 
crates/git_ui/src/git_panel_settings.rs            | 16 +++-
crates/keymap_editor/src/keymap_editor.rs          |  7 +
crates/outline_panel/src/outline_panel.rs          |  4 
crates/outline_panel/src/outline_panel_settings.rs | 16 +++-
crates/project_panel/src/project_panel.rs          | 10 ++
crates/project_panel/src/project_panel_settings.rs | 12 ++-
crates/terminal_view/src/terminal_view.rs          | 16 ++--
crates/ui/Cargo.toml                               |  1 
crates/ui/src/components/keybinding.rs             |  5 
crates/ui/src/components/keybinding_hint.rs        | 21 ++----
crates/ui/src/components/scrollbar.rs              | 55 ++++-----------
crates/ui/src/components/toggle.rs                 |  3 
crates/zed/src/main.rs                             |  1 
20 files changed, 117 insertions(+), 110 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -18781,7 +18781,6 @@ dependencies = [
  "menu",
  "schemars",
  "serde",
- "settings",
  "smallvec",
  "story",
  "strum 0.27.2",

crates/csv_preview/src/csv_preview.rs 🔗

@@ -122,8 +122,9 @@ impl CsvPreviewView {
     fn new(editor: &Entity<Editor>, cx: &mut Context<Workspace>) -> Entity<Self> {
         let contents = TableLikeContent::default();
         let table_interaction_state = cx.new(|cx| {
-            TableInteractionState::new(cx)
-                .with_custom_scrollbar(ui::Scrollbars::for_settings::<editor::EditorSettings>())
+            TableInteractionState::new(cx).with_custom_scrollbar(ui::Scrollbars::for_settings::<
+                editor::EditorSettingsScrollbarProxy,
+            >())
         });
 
         cx.new(|cx| {

crates/editor/src/code_context_menus.rs 🔗

@@ -287,14 +287,9 @@ impl Drop for CompletionsMenu {
     }
 }
 
+#[derive(Default)]
 struct CompletionMenuScrollBarSetting;
 
-impl ui::scrollbars::GlobalSetting for CompletionMenuScrollBarSetting {
-    fn get_value(_cx: &App) -> &Self {
-        &Self
-    }
-}
-
 impl ui::scrollbars::ScrollbarVisibility for CompletionMenuScrollBarSetting {
     fn visibility(&self, cx: &App) -> ui::scrollbars::ShowScrollbar {
         EditorSettings::get_global(cx).completion_menu_scrollbar

crates/editor/src/editor.rs 🔗

@@ -61,8 +61,8 @@ pub use display_map::{
 pub use edit_prediction_types::Direction;
 pub use editor_settings::{
     CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
-    EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings,
-    ShowMinimap,
+    EditorSettings, EditorSettingsScrollbarProxy, HideMouseMode, ScrollBeyondLastLine,
+    ScrollbarAxes, SearchSettings, ShowMinimap, ui_scrollbar_settings_from_raw,
 };
 pub use element::{
     CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,

crates/editor/src/editor_settings.rs 🔗

@@ -10,7 +10,7 @@ pub use settings::{
     ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
 };
 use settings::{RegisterSetting, RelativeLineNumbers, Settings};
-use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
+use ui::scrollbars::ShowScrollbar;
 
 /// Imports from the VSCode settings at
 /// https://code.visualstudio.com/docs/reference/default-settings
@@ -183,12 +183,6 @@ impl EditorSettings {
     }
 }
 
-impl ScrollbarVisibility for EditorSettings {
-    fn visibility(&self, _cx: &App) -> ShowScrollbar {
-        self.scrollbar.show
-    }
-}
-
 impl Settings for EditorSettings {
     fn from_settings(content: &settings::SettingsContent) -> Self {
         let editor = content.editor.clone();
@@ -217,7 +211,7 @@ impl Settings for EditorSettings {
                 code_actions: toolbar.code_actions.unwrap(),
             },
             scrollbar: Scrollbar {
-                show: scrollbar.show.map(Into::into).unwrap(),
+                show: scrollbar.show.map(ui_scrollbar_settings_from_raw).unwrap(),
                 git_diff: scrollbar.git_diff.unwrap()
                     && content
                         .git
@@ -294,9 +288,32 @@ impl Settings for EditorSettings {
             },
             lsp_document_colors: editor.lsp_document_colors.unwrap(),
             minimum_contrast_for_highlights: editor.minimum_contrast_for_highlights.unwrap().0,
-            completion_menu_scrollbar: editor.completion_menu_scrollbar.map(Into::into).unwrap(),
+            completion_menu_scrollbar: editor
+                .completion_menu_scrollbar
+                .map(ui_scrollbar_settings_from_raw)
+                .unwrap(),
             completion_detail_alignment: editor.completion_detail_alignment.unwrap(),
             diff_view_style: editor.diff_view_style.unwrap(),
         }
     }
 }
+
+#[derive(Default)]
+pub struct EditorSettingsScrollbarProxy;
+
+impl ui::scrollbars::ScrollbarVisibility for EditorSettingsScrollbarProxy {
+    fn visibility(&self, cx: &App) -> ShowScrollbar {
+        EditorSettings::get_global(cx).scrollbar.show
+    }
+}
+
+pub fn ui_scrollbar_settings_from_raw(
+    value: settings::ShowScrollbar,
+) -> ui::scrollbars::ShowScrollbar {
+    match value {
+        settings::ShowScrollbar::Auto => ShowScrollbar::Auto,
+        settings::ShowScrollbar::System => ShowScrollbar::System,
+        settings::ShowScrollbar::Always => ShowScrollbar::Always,
+        settings::ShowScrollbar::Never => ShowScrollbar::Never,
+    }
+}

crates/editor/src/hover_popover.rs 🔗

@@ -2,6 +2,7 @@ use crate::{
     ActiveDiagnostic, Anchor, AnchorRangeExt, DisplayPoint, DisplayRow, Editor, EditorSettings,
     EditorSnapshot, GlobalDiagnosticRenderer, HighlightKey, Hover,
     display_map::{InlayOffset, ToDisplayPoint, is_invisible},
+    editor_settings::EditorSettingsScrollbarProxy,
     hover_links::{InlayHighlight, RangeInEditor},
     movement::TextLayoutDetails,
     scroll::ScrollAmount,
@@ -1048,7 +1049,7 @@ impl InfoPopover {
                         ),
                 )
                 .custom_scrollbars(
-                    Scrollbars::for_settings::<EditorSettings>()
+                    Scrollbars::for_settings::<EditorSettingsScrollbarProxy>()
                         .tracked_scroll_handle(&self.scroll_handle),
                     window,
                     cx,
@@ -1176,7 +1177,7 @@ impl DiagnosticPopover {
                         CopyButton::new("copy-diagnostic", message).tooltip_label("Copy Diagnostic")
                     }))
                     .custom_scrollbars(
-                        Scrollbars::for_settings::<EditorSettings>()
+                        Scrollbars::for_settings::<EditorSettingsScrollbarProxy>()
                             .tracked_scroll_handle(&self.scroll_handle),
                         window,
                         cx,

crates/git_ui/src/git_panel.rs 🔗

@@ -2,6 +2,7 @@ use crate::askpass_modal::AskPassModal;
 use crate::commit_modal::CommitModal;
 use crate::commit_tooltip::CommitTooltip;
 use crate::commit_view::CommitView;
+use crate::git_panel_settings::GitPanelScrollbarAccessor;
 use crate::project_diff::{self, BranchDiff, Diff, ProjectDiff};
 use crate::remote_output::{self, RemoteAction, SuccessMessage};
 use crate::{branch_picker, picker_prompt, render_remote_button};
@@ -4885,7 +4886,7 @@ impl GitPanel {
                         }),
                     )
                     .custom_scrollbars(
-                        Scrollbars::for_settings::<GitPanelSettings>()
+                        Scrollbars::for_settings::<GitPanelScrollbarAccessor>()
                             .tracked_scroll_handle(&self.scroll_handle)
                             .with_track_along(
                                 ScrollAxes::Horizontal,

crates/git_ui/src/git_panel_settings.rs 🔗

@@ -1,4 +1,4 @@
-use editor::EditorSettings;
+use editor::{EditorSettings, ui_scrollbar_settings_from_raw};
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -32,7 +32,10 @@ pub struct GitPanelSettings {
     pub starts_open: bool,
 }
 
-impl ScrollbarVisibility for GitPanelSettings {
+#[derive(Default)]
+pub(crate) struct GitPanelScrollbarAccessor;
+
+impl ScrollbarVisibility for GitPanelScrollbarAccessor {
     fn visibility(&self, cx: &ui::App) -> ShowScrollbar {
         // TODO: This PR should have defined Editor's `scrollbar.axis`
         // as an Option<ScrollbarAxis>, not a ScrollbarAxes as it would allow you to
@@ -42,7 +45,8 @@ impl ScrollbarVisibility for GitPanelSettings {
         // so we can show each axis based on the settings.
         //
         // We should fix this. PR: https://github.com/zed-industries/zed/pull/19495
-        self.scrollbar
+        GitPanelSettings::get_global(cx)
+            .scrollbar
             .show
             .unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
     }
@@ -59,7 +63,11 @@ impl Settings for GitPanelSettings {
             file_icons: git_panel.file_icons.unwrap(),
             folder_icons: git_panel.folder_icons.unwrap(),
             scrollbar: ScrollbarSettings {
-                show: git_panel.scrollbar.unwrap().show.map(Into::into),
+                show: git_panel
+                    .scrollbar
+                    .unwrap()
+                    .show
+                    .map(ui_scrollbar_settings_from_raw),
             },
             fallback_branch_name: git_panel.fallback_branch_name.unwrap(),
             sort_by_path: git_panel.sort_by_path.unwrap(),

crates/keymap_editor/src/keymap_editor.rs 🔗

@@ -542,8 +542,9 @@ impl KeymapEditor {
         let _keymap_subscription =
             cx.observe_global_in::<KeymapEventChannel>(window, Self::on_keymap_changed);
         let table_interaction_state = cx.new(|cx| {
-            TableInteractionState::new(cx)
-                .with_custom_scrollbar(ui::Scrollbars::for_settings::<editor::EditorSettings>())
+            TableInteractionState::new(cx).with_custom_scrollbar(ui::Scrollbars::for_settings::<
+                editor::EditorSettingsScrollbarProxy,
+            >())
         });
 
         let keystroke_editor = cx.new(|cx| {
@@ -2184,7 +2185,7 @@ impl Render for KeymapEditor {
                                             .cloned()
                                             .unwrap_or_default()
                                             .into_any_element(),
-                                        |binding| ui::KeyBinding::from_keystrokes(binding.keystrokes.clone(), binding.source).into_any_element()
+                                        |binding| ui::KeyBinding::from_keystrokes(binding.keystrokes.clone(), binding.source == KeybindSource::Vim).into_any_element()
                                     );
 
                                     let action_arguments = match binding.action().arguments.clone()

crates/outline_panel/src/outline_panel.rs 🔗

@@ -62,6 +62,8 @@ use workspace::{
 };
 use worktree::{Entry, ProjectEntryId, WorktreeId};
 
+use crate::outline_panel_settings::OutlinePanelSettingsScrollbarProxy;
+
 actions!(
     outline_panel,
     [
@@ -4805,7 +4807,7 @@ impl OutlinePanel {
                 .size_full()
                 .child(list_contents.size_full().flex_shrink())
                 .custom_scrollbars(
-                    Scrollbars::for_settings::<OutlinePanelSettings>()
+                    Scrollbars::for_settings::<OutlinePanelSettingsScrollbarProxy>()
                         .tracked_scroll_handle(&self.scroll_handle.clone())
                         .with_track_along(
                             ScrollAxes::Horizontal,

crates/outline_panel/src/outline_panel_settings.rs 🔗

@@ -1,4 +1,4 @@
-use editor::EditorSettings;
+use editor::{EditorSettings, ui_scrollbar_settings_from_raw};
 use gpui::{App, Pixels};
 use settings::RegisterSetting;
 pub use settings::{DockSide, Settings, ShowIndentGuides};
@@ -33,9 +33,13 @@ pub struct IndentGuidesSettings {
     pub show: ShowIndentGuides,
 }
 
-impl ScrollbarVisibility for OutlinePanelSettings {
+#[derive(Default)]
+pub(crate) struct OutlinePanelSettingsScrollbarProxy;
+
+impl ScrollbarVisibility for OutlinePanelSettingsScrollbarProxy {
     fn visibility(&self, cx: &App) -> ShowScrollbar {
-        self.scrollbar
+        OutlinePanelSettings::get_global(cx)
+            .scrollbar
             .show
             .unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
     }
@@ -65,7 +69,11 @@ impl Settings for OutlinePanelSettings {
             auto_reveal_entries: panel.auto_reveal_entries.unwrap(),
             auto_fold_dirs: panel.auto_fold_dirs.unwrap(),
             scrollbar: ScrollbarSettings {
-                show: panel.scrollbar.unwrap().show.map(Into::into),
+                show: panel
+                    .scrollbar
+                    .unwrap()
+                    .show
+                    .map(ui_scrollbar_settings_from_raw),
             },
             expand_outlines_with_depth: panel.expand_outlines_with_depth.unwrap(),
         }

crates/project_panel/src/project_panel.rs 🔗

@@ -82,7 +82,10 @@ use zed_actions::{
     workspace::OpenWithSystem,
 };
 
-use crate::undo::{ProjectPanelOperation, UndoManager};
+use crate::{
+    project_panel_settings::ProjectPanelScrollbarProxy,
+    undo::{ProjectPanelOperation, UndoManager},
+};
 
 const PROJECT_PANEL_KEY: &str = "ProjectPanel";
 const NEW_ENTRY_ID: ProjectEntryId = ProjectEntryId::MAX;
@@ -7038,8 +7041,9 @@ impl Render for ProjectPanel {
                 )
                 .custom_scrollbars(
                     {
-                        let mut scrollbars = Scrollbars::for_settings::<ProjectPanelSettings>()
-                            .tracked_scroll_handle(&self.scroll_handle);
+                        let mut scrollbars =
+                            Scrollbars::for_settings::<ProjectPanelScrollbarProxy>()
+                                .tracked_scroll_handle(&self.scroll_handle);
                         if horizontal_scroll {
                             scrollbars = scrollbars.with_track_along(
                                 ScrollAxes::Horizontal,

crates/project_panel/src/project_panel_settings.rs 🔗

@@ -1,4 +1,4 @@
-use editor::EditorSettings;
+use editor::{EditorSettings, ui_scrollbar_settings_from_raw};
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -81,9 +81,13 @@ impl AutoOpenSettings {
     }
 }
 
-impl ScrollbarVisibility for ProjectPanelSettings {
+#[derive(Default)]
+pub(crate) struct ProjectPanelScrollbarProxy;
+
+impl ScrollbarVisibility for ProjectPanelScrollbarProxy {
     fn visibility(&self, cx: &ui::App) -> ShowScrollbar {
-        self.scrollbar
+        ProjectPanelSettings::get_global(cx)
+            .scrollbar
             .show
             .unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
     }
@@ -120,7 +124,7 @@ impl Settings for ProjectPanelSettings {
             scrollbar: {
                 let scrollbar = project_panel.scrollbar.unwrap();
                 ScrollbarSettings {
-                    show: scrollbar.show.map(Into::into),
+                    show: scrollbar.show.map(ui_scrollbar_settings_from_raw),
                     horizontal_scroll: scrollbar.horizontal_scroll.unwrap(),
                 }
             },

crates/terminal_view/src/terminal_view.rs 🔗

@@ -6,7 +6,10 @@ pub mod terminal_scrollbar;
 mod terminal_slash_command;
 
 use assistant_slash_command::SlashCommandRegistry;
-use editor::{Editor, EditorSettings, actions::SelectAll, blink_manager::BlinkManager};
+use editor::{
+    Editor, EditorSettings, actions::SelectAll, blink_manager::BlinkManager,
+    ui_scrollbar_settings_from_raw,
+};
 use gpui::{
     Action, AnyElement, App, ClipboardEntry, DismissEvent, Entity, EventEmitter, ExternalPaths,
     FocusHandle, Focusable, Font, KeyContext, KeyDownEvent, Keystroke, MouseButton, MouseDownEvent,
@@ -48,7 +51,7 @@ use terminal_slash_command::TerminalSlashCommand;
 use ui::{
     ContextMenu, Divider, ScrollAxes, Scrollbars, Tooltip, WithScrollbar,
     prelude::*,
-    scrollbars::{self, GlobalSetting, ScrollbarVisibility},
+    scrollbars::{self, ScrollbarVisibility},
 };
 use util::ResultExt;
 use workspace::{
@@ -1121,20 +1124,15 @@ fn regex_search_for_query(query: &SearchQuery) -> Option<RegexSearch> {
     }
 }
 
+#[derive(Default)]
 struct TerminalScrollbarSettingsWrapper;
 
-impl GlobalSetting for TerminalScrollbarSettingsWrapper {
-    fn get_value(_cx: &App) -> &Self {
-        &Self
-    }
-}
-
 impl ScrollbarVisibility for TerminalScrollbarSettingsWrapper {
     fn visibility(&self, cx: &App) -> scrollbars::ShowScrollbar {
         TerminalSettings::get_global(cx)
             .scrollbar
             .show
-            .map(Into::into)
+            .map(ui_scrollbar_settings_from_raw)
             .unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
     }
 }

crates/ui/Cargo.toml 🔗

@@ -23,7 +23,6 @@ itertools.workspace = true
 menu.workspace = true
 schemars.workspace = true
 serde.workspace = true
-settings.workspace = true
 smallvec.workspace = true
 story = { workspace = true, optional = true }
 strum.workspace = true

crates/ui/src/components/keybinding.rs 🔗

@@ -8,7 +8,6 @@ use gpui::{
     Modifiers, Window, relative,
 };
 use itertools::Itertools;
-use settings::KeybindSource;
 
 #[derive(Debug)]
 enum Source {
@@ -103,11 +102,11 @@ impl KeyBinding {
         }
     }
 
-    pub fn from_keystrokes(keystrokes: Rc<[KeybindingKeystroke]>, source: KeybindSource) -> Self {
+    pub fn from_keystrokes(keystrokes: Rc<[KeybindingKeystroke]>, vim_mode: bool) -> Self {
         Self {
             source: Source::Keystrokes { keystrokes },
             size: None,
-            vim_mode: source == KeybindSource::Vim,
+            vim_mode,
             platform_style: PlatformStyle::platform(),
             disabled: false,
         }

crates/ui/src/components/keybinding_hint.rs 🔗

@@ -14,11 +14,10 @@ use theme::Appearance;
 /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
 /// use ui::prelude::*;
 /// use ui::{KeyBinding, KeybindingHint};
-/// use settings::KeybindSource;
 ///
 /// # fn example(cx: &App) {
 /// let hint = KeybindingHint::new(
-///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-s").unwrap())].into(), KeybindSource::Base),
+///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-s").unwrap())].into(), false),
 ///     Hsla::black()
 /// )
 ///     .prefix("Save:")
@@ -46,11 +45,10 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::new(
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), false),
     ///     Hsla::black()
     /// );
     /// # }
@@ -76,12 +74,11 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::with_prefix(
     ///     "Copy:",
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-c").unwrap())].into(), false),
     ///     Hsla::black()
     /// );
     /// # }
@@ -111,11 +108,10 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::with_suffix(
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-v").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-v").unwrap())].into(), false),
     ///     "Paste",
     ///     Hsla::black()
     /// );
@@ -145,11 +141,10 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::new(
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-x").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-x").unwrap())].into(), false),
     ///     Hsla::black()
     /// )
     ///     .prefix("Cut:");
@@ -170,11 +165,10 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::new(
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-f").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-f").unwrap())].into(), false),
     ///     Hsla::black()
     /// )
     ///     .suffix("Find");
@@ -195,11 +189,10 @@ impl KeybindingHint {
     /// use gpui::{App, Hsla, KeybindingKeystroke, Keystroke};
     /// use ui::prelude::*;
     /// use ui::{KeyBinding, KeybindingHint};
-    /// use settings::KeybindSource;
     ///
     /// # fn example(cx: &App) {
     /// let hint = KeybindingHint::new(
-    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-z").unwrap())].into(), KeybindSource::Base),
+    ///     KeyBinding::from_keystrokes(vec![KeybindingKeystroke::from_keystroke(Keystroke::parse("ctrl-z").unwrap())].into(), false),
     ///     Hsla::black()
     /// )
     ///     .size(Pixels::from(16.0));

crates/ui/src/components/scrollbar.rs 🔗

@@ -16,7 +16,6 @@ use gpui::{
     size,
 };
 use gpui_util::ResultExt;
-use settings::SettingsStore;
 use smallvec::SmallVec;
 use theme::ActiveTheme as _;
 
@@ -34,7 +33,6 @@ pub mod scrollbars {
     use gpui::{App, Global};
     use schemars::JsonSchema;
     use serde::{Deserialize, Serialize};
-    use settings::Settings;
 
     /// When to show the scrollbar in the editor.
     ///
@@ -54,28 +52,7 @@ pub mod scrollbars {
         Never,
     }
 
-    impl From<settings::ShowScrollbar> for ShowScrollbar {
-        fn from(value: settings::ShowScrollbar) -> Self {
-            match value {
-                settings::ShowScrollbar::Auto => ShowScrollbar::Auto,
-                settings::ShowScrollbar::System => ShowScrollbar::System,
-                settings::ShowScrollbar::Always => ShowScrollbar::Always,
-                settings::ShowScrollbar::Never => ShowScrollbar::Never,
-            }
-        }
-    }
-
-    pub trait GlobalSetting {
-        fn get_value(cx: &App) -> &Self;
-    }
-
-    impl<T: Settings> GlobalSetting for T {
-        fn get_value(cx: &App) -> &T {
-            T::get_global(cx)
-        }
-    }
-
-    pub trait ScrollbarVisibility: GlobalSetting + 'static {
+    pub trait ScrollbarVisibility: 'static {
         fn visibility(&self, cx: &App) -> ShowScrollbar;
     }
 
@@ -103,11 +80,9 @@ where
     let element_id = config.id.take().unwrap_or_else(|| caller_location.into());
     let track_color = config.track_color;
 
-    let state = window.use_keyed_state(element_id, cx, |window, cx| {
+    let state = window.use_keyed_state(element_id, cx, |_, cx| {
         let parent_id = cx.entity_id();
-        ScrollbarStateWrapper(
-            cx.new(|cx| ScrollbarState::new_from_config(config, parent_id, window, cx)),
-        )
+        ScrollbarStateWrapper(cx.new(|cx| ScrollbarState::new_from_config(config, parent_id, cx)))
     });
 
     state.update(cx, |state, cx| {
@@ -399,8 +374,8 @@ impl Scrollbars {
         Self::new_with_setting(show_along, |_| ShowScrollbar::Always)
     }
 
-    pub fn for_settings<S: ScrollbarVisibility>() -> Scrollbars {
-        Scrollbars::new_with_setting(ScrollAxes::Both, |cx| S::get_value(cx).visibility(cx))
+    pub fn for_settings<S: ScrollbarVisibility + Default>() -> Scrollbars {
+        Scrollbars::new_with_setting(ScrollAxes::Both, |cx| S::default().visibility(cx))
     }
 }
 
@@ -589,6 +564,16 @@ enum ParentHoverEvent {
     Outside,
 }
 
+pub fn on_new_scrollbars<T: gpui::Global>(cx: &mut App) {
+    cx.observe_new::<ScrollbarState>(|_, window, cx| {
+        if let Some(window) = window {
+            cx.observe_global_in::<T>(window, ScrollbarState::settings_changed)
+                .detach();
+        }
+    })
+    .detach();
+}
+
 /// This is used to ensure notifies within the state do not notify the parent
 /// unintentionally.
 struct ScrollbarStateWrapper<T: ScrollableHandle>(Entity<ScrollbarState<T>>);
@@ -611,15 +596,7 @@ struct ScrollbarState<T: ScrollableHandle = ScrollHandle> {
 }
 
 impl<T: ScrollableHandle> ScrollbarState<T> {
-    fn new_from_config(
-        config: Scrollbars<T>,
-        parent_id: EntityId,
-        window: &mut Window,
-        cx: &mut Context<Self>,
-    ) -> Self {
-        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed)
-            .detach();
-
+    fn new_from_config(config: Scrollbars<T>, parent_id: EntityId, cx: &mut Context<Self>) -> Self {
         let (manually_added, scroll_handle) = match config.scrollable_handle {
             Handle::Tracked(handle) => (true, handle),
             Handle::Untracked(func) => (false, func()),

crates/ui/src/components/toggle.rs 🔗

@@ -2,7 +2,6 @@ use gpui::{
     AnyElement, AnyView, ClickEvent, ElementId, Hsla, IntoElement, KeybindingKeystroke, Keystroke,
     Styled, Window, div, hsla, prelude::*,
 };
-use settings::KeybindSource;
 use std::{rc::Rc, sync::Arc};
 
 use crate::utils::is_light;
@@ -1051,7 +1050,7 @@ impl Component for Switch {
                                         Keystroke::parse("cmd-s").unwrap(),
                                     )]
                                     .into(),
-                                    KeybindSource::Base,
+                                    false,
                                 )))
                                 .into_any_element(),
                         )],

crates/zed/src/main.rs 🔗

@@ -537,6 +537,7 @@ fn main() {
             tx.send(Some(options)).log_err();
         })
         .detach();
+        ui::on_new_scrollbars::<SettingsStore>(cx);
 
         let node_runtime = NodeRuntime::new(client.http_client(), Some(shell_env_loaded_rx), rx);