Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/feature_flags/src/feature_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ pub trait FeatureFlagAppExt {
fn flag_value<T: FeatureFlag>(&self) -> T::Value;
fn is_staff(&self) -> bool;

/// Whether feature flag overrides from settings are honored for the
/// current user. Overrides are a staff-only affordance.
fn feature_flag_overrides_enabled(&self) -> bool;

fn on_flags_ready<F>(&mut self, callback: F) -> Subscription
where
F: FnMut(OnFlagsReady, &mut App) + 'static;
Expand Down Expand Up @@ -253,6 +257,11 @@ impl FeatureFlagAppExt for App {
.unwrap_or(false)
}

fn feature_flag_overrides_enabled(&self) -> bool {
self.try_global::<FeatureFlagStore>()
.map_or(false, |store| store.overrides_enabled())
}

fn on_flags_ready<F>(&mut self, mut callback: F) -> Subscription
where
F: FnMut(OnFlagsReady, &mut App) + 'static,
Expand Down
37 changes: 27 additions & 10 deletions crates/feature_flags/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ impl FeatureFlagStore {
self.staff
}

/// Whether feature flag overrides from settings should be honored.
///
/// Overrides are a staff-only affordance, so non-staff users in release
/// builds can't flip flags through `settings.json` or the settings UI.
/// Debug builds are always treated as staff, and `ZED_DISABLE_STAFF`
/// forces the user to be treated as non-staff for testing.
pub fn overrides_enabled(&self) -> bool {
(cfg!(debug_assertions) || self.staff) && !*ZED_DISABLE_STAFF
}

pub fn server_flags_received(&self) -> bool {
self.server_flags_received
}
Expand Down Expand Up @@ -158,8 +168,12 @@ impl FeatureFlagStore {
return Some(T::Value::on_variant());
}

if let Some(override_key) = FeatureFlagsSettings::get_global(cx).overrides.get(T::NAME) {
return variant_from_key::<T::Value>(override_key);
// Only apply overrides when they are specifically enabled.
if self.overrides_enabled() {
if let Some(override_key) = FeatureFlagsSettings::get_global(cx).overrides.get(T::NAME)
{
return variant_from_key::<T::Value>(override_key);
}
}

// Staff default: resolve to the enabled variant.
Expand Down Expand Up @@ -194,15 +208,18 @@ impl FeatureFlagStore {
return on_variant_key;
}

if let Some(requested) = FeatureFlagsSettings::get_global(cx)
.overrides
.get(descriptor.name)
{
if let Some(variant) = (descriptor.variants)()
.into_iter()
.find(|v| v.override_key == requested.as_str())
// Only apply overrides when they are specifically enabled.
if self.overrides_enabled() {
if let Some(requested) = FeatureFlagsSettings::get_global(cx)
.overrides
.get(descriptor.name)
{
return variant.override_key;
if let Some(variant) = (descriptor.variants)()
.into_iter()
.find(|v| v.override_key == requested.as_str())
{
return variant.override_key;
}
}
}

Expand Down
90 changes: 46 additions & 44 deletions crates/settings_ui/src/page_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ macro_rules! concat_sections {
}

pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
let mut pages = vec![
vec![
general_page(cx),
appearance_page(),
keymap_page(),
Expand All @@ -77,56 +77,58 @@ pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
collaboration_page(),
ai_page(cx),
network_page(),
];
developer_page(cx),
]
}

fn developer_page(cx: &App) -> SettingsPage {
use feature_flags::FeatureFlagAppExt as _;
if cx.is_staff() || cfg!(debug_assertions) {
pages.push(developer_page());

let mut items: Vec<SettingsPageItem> = Vec::new();

// Feature flag overrides are a staff-only affordance, so only surface the section when the overrides are enabled.
if cx.feature_flag_overrides_enabled() {
items.push(SettingsPageItem::SectionHeader("Feature Flags"));
items.push(SettingsPageItem::SubPageLink(SubPageLink {
title: "Feature Flags".into(),
r#type: Default::default(),
description: None,
json_path: Some("feature_flags"),
in_json: true,
files: USER,
render: crate::pages::render_feature_flags_page,
}));
}

pages
}
items.push(SettingsPageItem::SectionHeader("Instrumentation"));
items.push(SettingsPageItem::SettingItem(SettingItem {
title: "Performance Profiler",
description: "Collect timing data for foreground and background executor tasks so they can be inspected via `zed: open performance profiler`. May lead to increased memory usage.",
field: Box::new(SettingField {
json_path: Some("instrumentation.performance_profiler.enabled"),
pick: |settings_content| {
settings_content
.instrumentation
.as_ref()
.and_then(|i| i.performance_profiler.as_ref())
.and_then(|p| p.enabled.as_ref())
},
write: |settings_content, value, _| {
settings_content
.instrumentation
.get_or_insert_default()
.performance_profiler
.get_or_insert_default()
.enabled = value;
},
}),
metadata: None,
files: USER,
}));

fn developer_page() -> SettingsPage {
SettingsPage {
title: "Developer",
items: Box::new([
SettingsPageItem::SectionHeader("Feature Flags"),
SettingsPageItem::SubPageLink(SubPageLink {
title: "Feature Flags".into(),
r#type: Default::default(),
description: None,
json_path: Some("feature_flags"),
in_json: true,
files: USER,
render: crate::pages::render_feature_flags_page,
}),
SettingsPageItem::SectionHeader("Instrumentation"),
SettingsPageItem::SettingItem(SettingItem {
title: "Performance Profiler",
description: "Collect timing data for foreground and background executor tasks so they can be inspected via `zed: open performance profiler`. May lead to increased memory usage.",
field: Box::new(SettingField {
json_path: Some("instrumentation.performance_profiler.enabled"),
pick: |settings_content| {
settings_content
.instrumentation
.as_ref()
.and_then(|i| i.performance_profiler.as_ref())
.and_then(|p| p.enabled.as_ref())
},
write: |settings_content, value, _| {
settings_content
.instrumentation
.get_or_insert_default()
.performance_profiler
.get_or_insert_default()
.enabled = value;
},
}),
metadata: None,
files: USER,
}),
]),
items: items.into_boxed_slice(),
}
}

Expand Down
Loading