1mod appearance_settings_controls;
2
3use std::any::TypeId;
4
5use command_palette_hooks::CommandPaletteFilter;
6use editor::EditorSettingsControls;
7use feature_flags::{FeatureFlag, FeatureFlagViewExt};
8use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, actions};
9use ui::prelude::*;
10use workspace::item::{Item, ItemEvent};
11use workspace::{Workspace, with_active_or_new_workspace};
12
13use crate::appearance_settings_controls::AppearanceSettingsControls;
14
15pub mod keybindings;
16pub mod ui_components;
17
18pub struct SettingsUiFeatureFlag;
19
20impl FeatureFlag for SettingsUiFeatureFlag {
21 const NAME: &'static str = "settings-ui";
22}
23
24actions!(
25 zed,
26 [
27 /// Opens the settings editor.
28 OpenSettingsEditor
29 ]
30);
31
32pub fn init(cx: &mut App) {
33 cx.on_action(|_: &OpenSettingsEditor, cx| {
34 with_active_or_new_workspace(cx, move |workspace, window, cx| {
35 let existing = workspace
36 .active_pane()
37 .read(cx)
38 .items()
39 .find_map(|item| item.downcast::<SettingsPage>());
40
41 if let Some(existing) = existing {
42 workspace.activate_item(&existing, true, true, window, cx);
43 } else {
44 let settings_page = SettingsPage::new(workspace, cx);
45 workspace.add_item_to_active_pane(Box::new(settings_page), None, true, window, cx)
46 }
47 });
48 });
49
50 cx.observe_new(|_workspace: &mut Workspace, window, cx| {
51 let Some(window) = window else {
52 return;
53 };
54
55 let settings_ui_actions = [TypeId::of::<OpenSettingsEditor>()];
56
57 CommandPaletteFilter::update_global(cx, |filter, _cx| {
58 filter.hide_action_types(&settings_ui_actions);
59 });
60
61 cx.observe_flag::<SettingsUiFeatureFlag, _>(
62 window,
63 move |is_enabled, _workspace, _, cx| {
64 if is_enabled {
65 CommandPaletteFilter::update_global(cx, |filter, _cx| {
66 filter.show_action_types(settings_ui_actions.iter());
67 });
68 } else {
69 CommandPaletteFilter::update_global(cx, |filter, _cx| {
70 filter.hide_action_types(&settings_ui_actions);
71 });
72 }
73 },
74 )
75 .detach();
76 })
77 .detach();
78
79 keybindings::init(cx);
80}
81
82pub struct SettingsPage {
83 focus_handle: FocusHandle,
84}
85
86impl SettingsPage {
87 pub fn new(_workspace: &Workspace, cx: &mut Context<Workspace>) -> Entity<Self> {
88 cx.new(|cx| Self {
89 focus_handle: cx.focus_handle(),
90 })
91 }
92}
93
94impl EventEmitter<ItemEvent> for SettingsPage {}
95
96impl Focusable for SettingsPage {
97 fn focus_handle(&self, _cx: &App) -> FocusHandle {
98 self.focus_handle.clone()
99 }
100}
101
102impl Item for SettingsPage {
103 type Event = ItemEvent;
104
105 fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
106 Some(Icon::new(IconName::Settings))
107 }
108
109 fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
110 "Settings".into()
111 }
112
113 fn show_toolbar(&self) -> bool {
114 false
115 }
116
117 fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
118 f(*event)
119 }
120}
121
122impl Render for SettingsPage {
123 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
124 v_flex()
125 .p_4()
126 .size_full()
127 .gap_4()
128 .child(Label::new("Settings").size(LabelSize::Large))
129 .child(
130 v_flex().gap_1().child(Label::new("Appearance")).child(
131 v_flex()
132 .elevation_2(cx)
133 .child(AppearanceSettingsControls::new()),
134 ),
135 )
136 .child(
137 v_flex().gap_1().child(Label::new("Editor")).child(
138 v_flex()
139 .elevation_2(cx)
140 .child(EditorSettingsControls::new()),
141 ),
142 )
143 }
144}