1#![allow(missing_docs)]
2
3use crate::schema::{status_colors_refinement, syntax_overrides, theme_colors_refinement};
4use crate::{merge_accent_colors, merge_player_colors};
5use collections::HashMap;
6use gpui::{
7 App, Context, Font, FontFallbacks, FontStyle, Global, Pixels, Subscription, Window, px,
8};
9use refineable::Refineable;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12pub use settings::{FontFamilyName, IconThemeName, ThemeAppearanceMode, ThemeName};
13use settings::{IntoGpui, RegisterSetting, Settings, SettingsContent};
14use std::sync::Arc;
15use theme::{Appearance, DEFAULT_ICON_THEME_NAME, SyntaxTheme, Theme, UiDensity};
16
17const MIN_FONT_SIZE: Pixels = px(6.0);
18const MAX_FONT_SIZE: Pixels = px(100.0);
19const MIN_LINE_HEIGHT: f32 = 1.0;
20
21pub(crate) fn ui_density_from_settings(val: settings::UiDensity) -> UiDensity {
22 match val {
23 settings::UiDensity::Compact => UiDensity::Compact,
24 settings::UiDensity::Default => UiDensity::Default,
25 settings::UiDensity::Comfortable => UiDensity::Comfortable,
26 }
27}
28
29pub fn appearance_to_mode(appearance: Appearance) -> ThemeAppearanceMode {
30 match appearance {
31 Appearance::Light => ThemeAppearanceMode::Light,
32 Appearance::Dark => ThemeAppearanceMode::Dark,
33 }
34}
35
36/// Customizable settings for the UI and theme system.
37#[derive(Clone, PartialEq, RegisterSetting)]
38pub struct ThemeSettings {
39 /// The UI font size. Determines the size of text in the UI,
40 /// as well as the size of a [gpui::Rems] unit.
41 ///
42 /// Changing this will impact the size of all UI elements.
43 ui_font_size: Pixels,
44 /// The font used for UI elements.
45 pub ui_font: Font,
46 /// The font size used for buffers, and the terminal.
47 ///
48 /// The terminal font size can be overridden using it's own setting.
49 buffer_font_size: Pixels,
50 /// The font used for buffers, and the terminal.
51 ///
52 /// The terminal font family can be overridden using it's own setting.
53 pub buffer_font: Font,
54 /// The agent font size. Determines the size of text in the agent panel. Falls back to the UI font size if unset.
55 agent_ui_font_size: Option<Pixels>,
56 /// The agent buffer font size. Determines the size of user messages in the agent panel.
57 agent_buffer_font_size: Option<Pixels>,
58 /// The line height for buffers, and the terminal.
59 ///
60 /// Changing this may affect the spacing of some UI elements.
61 ///
62 /// The terminal font family can be overridden using it's own setting.
63 pub buffer_line_height: BufferLineHeight,
64 /// The current theme selection.
65 pub theme: ThemeSelection,
66 /// Manual overrides for the active theme.
67 ///
68 /// Note: This setting is still experimental. See [this tracking issue](https://github.com/zed-industries/zed/issues/18078)
69 pub experimental_theme_overrides: Option<settings::ThemeStyleContent>,
70 /// Manual overrides per theme
71 pub theme_overrides: HashMap<String, settings::ThemeStyleContent>,
72 /// The current icon theme selection.
73 pub icon_theme: IconThemeSelection,
74 /// The density of the UI.
75 /// Note: This setting is still experimental. See [this tracking issue](
76 pub ui_density: UiDensity,
77 /// The amount of fading applied to unnecessary code.
78 pub unnecessary_code_fade: f32,
79}
80
81/// Returns the name of the default theme for the given [`Appearance`].
82pub fn default_theme(appearance: Appearance) -> &'static str {
83 match appearance {
84 Appearance::Light => settings::DEFAULT_LIGHT_THEME,
85 Appearance::Dark => settings::DEFAULT_DARK_THEME,
86 }
87}
88
89#[derive(Default)]
90struct BufferFontSize(Pixels);
91
92impl Global for BufferFontSize {}
93
94#[derive(Default)]
95pub(crate) struct UiFontSize(Pixels);
96
97impl Global for UiFontSize {}
98
99/// In-memory override for the font size in the agent panel.
100#[derive(Default)]
101pub struct AgentFontSize(Pixels);
102
103impl Global for AgentFontSize {}
104
105/// Represents the selection of a theme, which can be either static or dynamic.
106#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
107#[serde(untagged)]
108pub enum ThemeSelection {
109 /// A static theme selection, represented by a single theme name.
110 Static(ThemeName),
111 /// A dynamic theme selection, which can change based the [ThemeMode].
112 Dynamic {
113 /// The mode used to determine which theme to use.
114 #[serde(default)]
115 mode: ThemeAppearanceMode,
116 /// The theme to use for light mode.
117 light: ThemeName,
118 /// The theme to use for dark mode.
119 dark: ThemeName,
120 },
121}
122
123impl From<settings::ThemeSelection> for ThemeSelection {
124 fn from(selection: settings::ThemeSelection) -> Self {
125 match selection {
126 settings::ThemeSelection::Static(theme) => ThemeSelection::Static(theme),
127 settings::ThemeSelection::Dynamic { mode, light, dark } => {
128 ThemeSelection::Dynamic { mode, light, dark }
129 }
130 }
131 }
132}
133
134impl ThemeSelection {
135 /// Returns the theme name for the selected [ThemeMode].
136 pub fn name(&self, system_appearance: Appearance) -> ThemeName {
137 match self {
138 Self::Static(theme) => theme.clone(),
139 Self::Dynamic { mode, light, dark } => match mode {
140 ThemeAppearanceMode::Light => light.clone(),
141 ThemeAppearanceMode::Dark => dark.clone(),
142 ThemeAppearanceMode::System => match system_appearance {
143 Appearance::Light => light.clone(),
144 Appearance::Dark => dark.clone(),
145 },
146 },
147 }
148 }
149
150 /// Returns the [ThemeMode] for the [ThemeSelection].
151 pub fn mode(&self) -> Option<ThemeAppearanceMode> {
152 match self {
153 ThemeSelection::Static(_) => None,
154 ThemeSelection::Dynamic { mode, .. } => Some(*mode),
155 }
156 }
157}
158
159/// Represents the selection of an icon theme, which can be either static or dynamic.
160#[derive(Clone, Debug, PartialEq, Eq)]
161pub enum IconThemeSelection {
162 /// A static icon theme selection, represented by a single icon theme name.
163 Static(IconThemeName),
164 /// A dynamic icon theme selection, which can change based on the [`ThemeMode`].
165 Dynamic {
166 /// The mode used to determine which theme to use.
167 mode: ThemeAppearanceMode,
168 /// The icon theme to use for light mode.
169 light: IconThemeName,
170 /// The icon theme to use for dark mode.
171 dark: IconThemeName,
172 },
173}
174
175impl From<settings::IconThemeSelection> for IconThemeSelection {
176 fn from(selection: settings::IconThemeSelection) -> Self {
177 match selection {
178 settings::IconThemeSelection::Static(theme) => IconThemeSelection::Static(theme),
179 settings::IconThemeSelection::Dynamic { mode, light, dark } => {
180 IconThemeSelection::Dynamic { mode, light, dark }
181 }
182 }
183 }
184}
185
186impl IconThemeSelection {
187 /// Returns the icon theme name based on the given [`Appearance`].
188 pub fn name(&self, system_appearance: Appearance) -> IconThemeName {
189 match self {
190 Self::Static(theme) => theme.clone(),
191 Self::Dynamic { mode, light, dark } => match mode {
192 ThemeAppearanceMode::Light => light.clone(),
193 ThemeAppearanceMode::Dark => dark.clone(),
194 ThemeAppearanceMode::System => match system_appearance {
195 Appearance::Light => light.clone(),
196 Appearance::Dark => dark.clone(),
197 },
198 },
199 }
200 }
201
202 /// Returns the [`ThemeMode`] for the [`IconThemeSelection`].
203 pub fn mode(&self) -> Option<ThemeAppearanceMode> {
204 match self {
205 IconThemeSelection::Static(_) => None,
206 IconThemeSelection::Dynamic { mode, .. } => Some(*mode),
207 }
208 }
209}
210
211/// Sets the theme for the given appearance to the theme with the specified name.
212///
213/// The caller should make sure that the [`Appearance`] matches the theme associated with the name.
214///
215/// If the current [`ThemeAppearanceMode`] is set to [`System`] and the user's system [`Appearance`]
216/// is different than the new theme's [`Appearance`], this function will update the
217/// [`ThemeAppearanceMode`] to the new theme's appearance in order to display the new theme.
218///
219/// [`System`]: ThemeAppearanceMode::System
220pub fn set_theme(
221 current: &mut SettingsContent,
222 theme_name: impl Into<Arc<str>>,
223 theme_appearance: Appearance,
224 system_appearance: Appearance,
225) {
226 let theme_name = ThemeName(theme_name.into());
227
228 let Some(selection) = current.theme.theme.as_mut() else {
229 current.theme.theme = Some(settings::ThemeSelection::Static(theme_name));
230 return;
231 };
232
233 match selection {
234 settings::ThemeSelection::Static(theme) => {
235 *theme = theme_name;
236 }
237 settings::ThemeSelection::Dynamic { mode, light, dark } => {
238 match theme_appearance {
239 Appearance::Light => *light = theme_name,
240 Appearance::Dark => *dark = theme_name,
241 }
242
243 let should_update_mode =
244 !(mode == &ThemeAppearanceMode::System && theme_appearance == system_appearance);
245
246 if should_update_mode {
247 *mode = appearance_to_mode(theme_appearance);
248 }
249 }
250 }
251}
252
253/// Sets the icon theme for the given appearance to the icon theme with the specified name.
254pub fn set_icon_theme(
255 current: &mut SettingsContent,
256 icon_theme_name: IconThemeName,
257 appearance: Appearance,
258) {
259 if let Some(selection) = current.theme.icon_theme.as_mut() {
260 let icon_theme_to_update = match selection {
261 settings::IconThemeSelection::Static(theme) => theme,
262 settings::IconThemeSelection::Dynamic { mode, light, dark } => match mode {
263 ThemeAppearanceMode::Light => light,
264 ThemeAppearanceMode::Dark => dark,
265 ThemeAppearanceMode::System => match appearance {
266 Appearance::Light => light,
267 Appearance::Dark => dark,
268 },
269 },
270 };
271
272 *icon_theme_to_update = icon_theme_name;
273 } else {
274 current.theme.icon_theme = Some(settings::IconThemeSelection::Static(icon_theme_name));
275 }
276}
277
278/// Sets the mode for the theme.
279pub fn set_mode(content: &mut SettingsContent, mode: ThemeAppearanceMode) {
280 let theme = content.theme.as_mut();
281
282 if let Some(selection) = theme.theme.as_mut() {
283 match selection {
284 settings::ThemeSelection::Static(_) => {
285 *selection = settings::ThemeSelection::Dynamic {
286 mode: ThemeAppearanceMode::System,
287 light: ThemeName(settings::DEFAULT_LIGHT_THEME.into()),
288 dark: ThemeName(settings::DEFAULT_DARK_THEME.into()),
289 };
290 }
291 settings::ThemeSelection::Dynamic {
292 mode: mode_to_update,
293 ..
294 } => *mode_to_update = mode,
295 }
296 } else {
297 theme.theme = Some(settings::ThemeSelection::Dynamic {
298 mode,
299 light: ThemeName(settings::DEFAULT_LIGHT_THEME.into()),
300 dark: ThemeName(settings::DEFAULT_DARK_THEME.into()),
301 });
302 }
303
304 if let Some(selection) = theme.icon_theme.as_mut() {
305 match selection {
306 settings::IconThemeSelection::Static(icon_theme) => {
307 *selection = settings::IconThemeSelection::Dynamic {
308 mode,
309 light: icon_theme.clone(),
310 dark: icon_theme.clone(),
311 };
312 }
313 settings::IconThemeSelection::Dynamic {
314 mode: mode_to_update,
315 ..
316 } => *mode_to_update = mode,
317 }
318 } else {
319 theme.icon_theme = Some(settings::IconThemeSelection::Static(IconThemeName(
320 DEFAULT_ICON_THEME_NAME.into(),
321 )));
322 }
323}
324
325/// The buffer's line height.
326#[derive(Clone, Copy, Debug, PartialEq, Default)]
327pub enum BufferLineHeight {
328 /// A less dense line height.
329 #[default]
330 Comfortable,
331 /// The default line height.
332 Standard,
333 /// A custom line height, where 1.0 is the font's height. Must be at least 1.0.
334 Custom(f32),
335}
336
337impl From<settings::BufferLineHeight> for BufferLineHeight {
338 fn from(value: settings::BufferLineHeight) -> Self {
339 match value {
340 settings::BufferLineHeight::Comfortable => BufferLineHeight::Comfortable,
341 settings::BufferLineHeight::Standard => BufferLineHeight::Standard,
342 settings::BufferLineHeight::Custom(line_height) => {
343 BufferLineHeight::Custom(line_height)
344 }
345 }
346 }
347}
348
349impl BufferLineHeight {
350 /// Returns the value of the line height.
351 pub fn value(&self) -> f32 {
352 match self {
353 BufferLineHeight::Comfortable => 1.618,
354 BufferLineHeight::Standard => 1.3,
355 BufferLineHeight::Custom(line_height) => *line_height,
356 }
357 }
358}
359
360impl ThemeSettings {
361 /// Returns the buffer font size.
362 pub fn buffer_font_size(&self, cx: &App) -> Pixels {
363 let font_size = cx
364 .try_global::<BufferFontSize>()
365 .map(|size| size.0)
366 .unwrap_or(self.buffer_font_size);
367 clamp_font_size(font_size)
368 }
369
370 /// Returns the UI font size.
371 pub fn ui_font_size(&self, cx: &App) -> Pixels {
372 let font_size = cx
373 .try_global::<UiFontSize>()
374 .map(|size| size.0)
375 .unwrap_or(self.ui_font_size);
376 clamp_font_size(font_size)
377 }
378
379 /// Returns the agent panel font size. Falls back to the UI font size if unset.
380 pub fn agent_ui_font_size(&self, cx: &App) -> Pixels {
381 cx.try_global::<AgentFontSize>()
382 .map(|size| size.0)
383 .or(self.agent_ui_font_size)
384 .map(clamp_font_size)
385 .unwrap_or_else(|| self.ui_font_size(cx))
386 }
387
388 /// Returns the agent panel buffer font size.
389 pub fn agent_buffer_font_size(&self, cx: &App) -> Pixels {
390 cx.try_global::<AgentFontSize>()
391 .map(|size| size.0)
392 .or(self.agent_buffer_font_size)
393 .map(clamp_font_size)
394 .unwrap_or_else(|| self.buffer_font_size(cx))
395 }
396
397 /// Returns the buffer font size, read from the settings.
398 ///
399 /// The real buffer font size is stored in-memory, to support temporary font size changes.
400 /// Use [`Self::buffer_font_size`] to get the real font size.
401 pub fn buffer_font_size_settings(&self) -> Pixels {
402 self.buffer_font_size
403 }
404
405 /// Returns the UI font size, read from the settings.
406 ///
407 /// The real UI font size is stored in-memory, to support temporary font size changes.
408 /// Use [`Self::ui_font_size`] to get the real font size.
409 pub fn ui_font_size_settings(&self) -> Pixels {
410 self.ui_font_size
411 }
412
413 /// Returns the agent font size, read from the settings.
414 ///
415 /// The real agent font size is stored in-memory, to support temporary font size changes.
416 /// Use [`Self::agent_ui_font_size`] to get the real font size.
417 pub fn agent_ui_font_size_settings(&self) -> Option<Pixels> {
418 self.agent_ui_font_size
419 }
420
421 /// Returns the agent buffer font size, read from the settings.
422 ///
423 /// The real agent buffer font size is stored in-memory, to support temporary font size changes.
424 /// Use [`Self::agent_buffer_font_size`] to get the real font size.
425 pub fn agent_buffer_font_size_settings(&self) -> Option<Pixels> {
426 self.agent_buffer_font_size
427 }
428
429 /// Returns the buffer's line height.
430 pub fn line_height(&self) -> f32 {
431 f32::max(self.buffer_line_height.value(), MIN_LINE_HEIGHT)
432 }
433
434 /// Applies the theme overrides, if there are any, to the current theme.
435 pub fn apply_theme_overrides(&self, mut arc_theme: Arc<Theme>) -> Arc<Theme> {
436 if let Some(experimental_theme_overrides) = &self.experimental_theme_overrides {
437 let mut theme = (*arc_theme).clone();
438 ThemeSettings::modify_theme(&mut theme, experimental_theme_overrides);
439 arc_theme = Arc::new(theme);
440 }
441
442 if let Some(theme_overrides) = self.theme_overrides.get(arc_theme.name.as_ref()) {
443 let mut theme = (*arc_theme).clone();
444 ThemeSettings::modify_theme(&mut theme, theme_overrides);
445 arc_theme = Arc::new(theme);
446 }
447
448 arc_theme
449 }
450
451 fn modify_theme(base_theme: &mut Theme, theme_overrides: &settings::ThemeStyleContent) {
452 if let Some(window_background_appearance) = theme_overrides.window_background_appearance {
453 base_theme.styles.window_background_appearance =
454 window_background_appearance.into_gpui();
455 }
456 let status_color_refinement = status_colors_refinement(&theme_overrides.status);
457
458 base_theme.styles.colors.refine(&theme_colors_refinement(
459 &theme_overrides.colors,
460 &status_color_refinement,
461 ));
462 base_theme.styles.status.refine(&status_color_refinement);
463 merge_player_colors(&mut base_theme.styles.player, &theme_overrides.players);
464 merge_accent_colors(&mut base_theme.styles.accents, &theme_overrides.accents);
465 base_theme.styles.syntax = SyntaxTheme::merge(
466 base_theme.styles.syntax.clone(),
467 syntax_overrides(theme_overrides),
468 );
469 }
470}
471
472/// Observe changes to the adjusted buffer font size.
473pub fn observe_buffer_font_size_adjustment<V: 'static>(
474 cx: &mut Context<V>,
475 f: impl 'static + Fn(&mut V, &mut Context<V>),
476) -> Subscription {
477 cx.observe_global::<BufferFontSize>(f)
478}
479
480/// Gets the font size, adjusted by the difference between the current buffer font size and the one set in the settings.
481pub fn adjusted_font_size(size: Pixels, cx: &App) -> Pixels {
482 let adjusted_font_size =
483 if let Some(BufferFontSize(adjusted_size)) = cx.try_global::<BufferFontSize>() {
484 let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
485 let delta = *adjusted_size - buffer_font_size;
486 size + delta
487 } else {
488 size
489 };
490 clamp_font_size(adjusted_font_size)
491}
492
493/// Adjusts the buffer font size, without persisting the result in the settings.
494/// This will be effective until the app is restarted.
495pub fn adjust_buffer_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
496 let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
497 let adjusted_size = cx
498 .try_global::<BufferFontSize>()
499 .map_or(buffer_font_size, |adjusted_size| adjusted_size.0);
500 cx.set_global(BufferFontSize(clamp_font_size(f(adjusted_size))));
501 cx.refresh_windows();
502}
503
504/// Resets the buffer font size to the default value.
505pub fn reset_buffer_font_size(cx: &mut App) {
506 if cx.has_global::<BufferFontSize>() {
507 cx.remove_global::<BufferFontSize>();
508 cx.refresh_windows();
509 }
510}
511
512#[allow(missing_docs)]
513pub fn setup_ui_font(window: &mut Window, cx: &mut App) -> gpui::Font {
514 let (ui_font, ui_font_size) = {
515 let theme_settings = ThemeSettings::get_global(cx);
516 let font = theme_settings.ui_font.clone();
517 (font, theme_settings.ui_font_size(cx))
518 };
519
520 window.set_rem_size(ui_font_size);
521 ui_font
522}
523
524/// Sets the adjusted UI font size.
525pub fn adjust_ui_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
526 let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
527 let adjusted_size = cx
528 .try_global::<UiFontSize>()
529 .map_or(ui_font_size, |adjusted_size| adjusted_size.0);
530 cx.set_global(UiFontSize(clamp_font_size(f(adjusted_size))));
531 cx.refresh_windows();
532}
533
534/// Resets the UI font size to the default value.
535pub fn reset_ui_font_size(cx: &mut App) {
536 if cx.has_global::<UiFontSize>() {
537 cx.remove_global::<UiFontSize>();
538 cx.refresh_windows();
539 }
540}
541
542/// Sets the adjusted font size of agent responses in the agent panel.
543pub fn adjust_agent_ui_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
544 let agent_ui_font_size = ThemeSettings::get_global(cx).agent_ui_font_size(cx);
545 let adjusted_size = cx
546 .try_global::<AgentFontSize>()
547 .map_or(agent_ui_font_size, |adjusted_size| adjusted_size.0);
548 cx.set_global(AgentFontSize(clamp_font_size(f(adjusted_size))));
549 cx.refresh_windows();
550}
551
552/// Resets the agent response font size in the agent panel to the default value.
553pub fn reset_agent_ui_font_size(cx: &mut App) {
554 if cx.has_global::<AgentFontSize>() {
555 cx.remove_global::<AgentFontSize>();
556 cx.refresh_windows();
557 }
558}
559
560/// Sets the adjusted font size of user messages in the agent panel.
561pub fn adjust_agent_buffer_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
562 let agent_buffer_font_size = ThemeSettings::get_global(cx).agent_buffer_font_size(cx);
563 let adjusted_size = cx
564 .try_global::<AgentFontSize>()
565 .map_or(agent_buffer_font_size, |adjusted_size| adjusted_size.0);
566 cx.set_global(AgentFontSize(clamp_font_size(f(adjusted_size))));
567 cx.refresh_windows();
568}
569
570/// Resets the user message font size in the agent panel to the default value.
571pub fn reset_agent_buffer_font_size(cx: &mut App) {
572 if cx.has_global::<AgentFontSize>() {
573 cx.remove_global::<AgentFontSize>();
574 cx.refresh_windows();
575 }
576}
577
578/// Ensures font size is within the valid range.
579pub fn clamp_font_size(size: Pixels) -> Pixels {
580 size.clamp(MIN_FONT_SIZE, MAX_FONT_SIZE)
581}
582
583fn font_fallbacks_from_settings(
584 fallbacks: Option<Vec<settings::FontFamilyName>>,
585) -> Option<FontFallbacks> {
586 fallbacks.map(|fallbacks| {
587 FontFallbacks::from_fonts(
588 fallbacks
589 .into_iter()
590 .map(|font_family| font_family.0.to_string())
591 .collect(),
592 )
593 })
594}
595
596impl settings::Settings for ThemeSettings {
597 fn from_settings(content: &settings::SettingsContent) -> Self {
598 let content = &content.theme;
599 let theme_selection: ThemeSelection = content.theme.clone().unwrap().into();
600 let icon_theme_selection: IconThemeSelection = content.icon_theme.clone().unwrap().into();
601 Self {
602 ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into_gpui()),
603 ui_font: Font {
604 family: content.ui_font_family.as_ref().unwrap().0.clone().into(),
605 features: content.ui_font_features.clone().unwrap().into_gpui(),
606 fallbacks: font_fallbacks_from_settings(content.ui_font_fallbacks.clone()),
607 weight: content.ui_font_weight.unwrap().into_gpui(),
608 style: Default::default(),
609 },
610 buffer_font: Font {
611 family: content
612 .buffer_font_family
613 .as_ref()
614 .unwrap()
615 .0
616 .clone()
617 .into(),
618 features: content.buffer_font_features.clone().unwrap().into_gpui(),
619 fallbacks: font_fallbacks_from_settings(content.buffer_font_fallbacks.clone()),
620 weight: content.buffer_font_weight.unwrap().into_gpui(),
621 style: FontStyle::default(),
622 },
623 buffer_font_size: clamp_font_size(content.buffer_font_size.unwrap().into_gpui()),
624 buffer_line_height: content.buffer_line_height.unwrap().into(),
625 agent_ui_font_size: content.agent_ui_font_size.map(|s| s.into_gpui()),
626 agent_buffer_font_size: content.agent_buffer_font_size.map(|s| s.into_gpui()),
627 theme: theme_selection,
628 experimental_theme_overrides: content.experimental_theme_overrides.clone(),
629 theme_overrides: content.theme_overrides.clone(),
630 icon_theme: icon_theme_selection,
631 ui_density: ui_density_from_settings(content.ui_density.unwrap_or_default()),
632 unnecessary_code_fade: content.unnecessary_code_fade.unwrap().0.clamp(0.0, 0.9),
633 }
634 }
635}