settings_ui: Dynamic languages list (#40123)

Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
This commit is contained in:
Ben Kunkle
2025-10-13 13:47:14 -04:00
committed by GitHub
parent 997f6c6a19
commit bd13c90acc
2 changed files with 69 additions and 104 deletions
+25 -72
View File
@@ -1,13 +1,14 @@
use gpui::App;
use settings::{LanguageSettingsContent, SettingsContent};
use std::sync::Arc;
use ui::{IntoElement, SharedString};
use crate::{
LOCAL, SettingField, SettingItem, SettingsFieldMetadata, SettingsPage, SettingsPageItem,
SubPageLink, USER, sub_page_stack,
SubPageLink, USER, all_language_names, sub_page_stack,
};
pub(crate) fn settings_data() -> Vec<SettingsPage> {
pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
vec![
SettingsPage {
title: "General",
@@ -1405,74 +1406,27 @@ pub(crate) fn settings_data() -> Vec<SettingsPage> {
},
SettingsPage {
title: "Languages",
items: vec![
SettingsPageItem::SectionHeader(LANGUAGES_SECTION_HEADER),
SettingsPageItem::SubPageLink(SubPageLink {
title: "JSON",
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
}),
SettingsPageItem::SubPageLink(SubPageLink {
title: "JSONC",
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
}),
SettingsPageItem::SubPageLink(SubPageLink {
title: "Rust",
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
}),
SettingsPageItem::SubPageLink(SubPageLink {
title: "Python",
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
}),
SettingsPageItem::SubPageLink(SubPageLink {
title: "TSX",
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
}),
],
items: {
let mut items = vec![SettingsPageItem::SectionHeader(LANGUAGES_SECTION_HEADER)];
// todo(settings_ui): Refresh on extension (un)/installed
// Note that `crates/json_schema_store` solves the same problem, there is probably a way to unify the two
items.extend(all_language_names(cx).into_iter().map(|language_name| {
SettingsPageItem::SubPageLink(SubPageLink {
title: language_name,
files: USER | LOCAL,
render: Arc::new(|this, window, cx| {
this.render_page_items(
language_settings_data().iter().enumerate(),
None,
window,
cx,
)
.into_any_element()
}),
})
}));
items
},
},
SettingsPage {
title: "Search & Files",
@@ -4678,8 +4632,7 @@ const LANGUAGES_SECTION_HEADER: &'static str = "Languages";
fn language_settings_data() -> Vec<SettingsPageItem> {
fn current_language() -> Option<SharedString> {
sub_page_stack().iter().find_map(|page| {
(page.section_header == LANGUAGES_SECTION_HEADER)
.then(|| SharedString::new_static(page.link.title))
(page.section_header == LANGUAGES_SECTION_HEADER).then(|| page.link.title.clone())
})
}
+44 -32
View File
@@ -608,7 +608,7 @@ impl SettingsPageItem {
.into_any_element()
}
SettingsPageItem::SubPageLink(sub_page_link) => h_flex()
.id(sub_page_link.title)
.id(sub_page_link.title.clone())
.w_full()
.min_w_0()
.gap_2()
@@ -623,24 +623,27 @@ impl SettingsPageItem {
v_flex()
.w_full()
.max_w_1_2()
.child(Label::new(SharedString::new_static(sub_page_link.title))),
.child(Label::new(sub_page_link.title.clone())),
)
.child(
Button::new(("sub-page".into(), sub_page_link.title), "Configure")
.icon(IconName::ChevronRight)
.tab_index(0_isize)
.icon_position(IconPosition::End)
.icon_color(Color::Muted)
.icon_size(IconSize::Small)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium),
Button::new(
("sub-page".into(), sub_page_link.title.clone()),
"Configure",
)
.icon(IconName::ChevronRight)
.tab_index(0_isize)
.icon_position(IconPosition::End)
.icon_color(Color::Muted)
.icon_size(IconSize::Small)
.style(ButtonStyle::Outlined)
.size(ButtonSize::Medium)
.on_click({
let sub_page_link = sub_page_link.clone();
cx.listener(move |this, _, _, cx| {
this.push_sub_page(sub_page_link.clone(), section_header, cx)
})
}),
)
.on_click({
let sub_page_link = sub_page_link.clone();
cx.listener(move |this, _, _, cx| {
this.push_sub_page(sub_page_link.clone(), section_header, cx)
})
})
.into_any_element(),
}
}
@@ -765,7 +768,7 @@ impl PartialEq for SettingItem {
#[derive(Clone)]
struct SubPageLink {
title: &'static str,
title: SharedString,
files: FileMask,
render: Arc<
dyn Fn(&mut SettingsWindow, &mut Window, &mut Context<SettingsWindow>) -> AnyElement
@@ -781,6 +784,20 @@ impl PartialEq for SubPageLink {
}
}
fn all_language_names(cx: &App) -> Vec<SharedString> {
workspace::AppState::global(cx)
.upgrade()
.map_or(vec![], |state| {
state
.languages
.language_names()
.into_iter()
.filter(|name| name.as_ref() != "Zed Keybind Context")
.map(Into::into)
.collect()
})
}
#[allow(unused)]
#[derive(Clone, PartialEq)]
enum SettingsUiFile {
@@ -1049,15 +1066,9 @@ impl SettingsWindow {
header_index = index;
any_found_since_last_header = false;
}
SettingsPageItem::SettingItem(setting_item) => {
if !setting_item.files.contains(current_file) {
page_filter[index] = false;
} else {
any_found_since_last_header = true;
}
}
SettingsPageItem::SubPageLink(sub_page_link) => {
if !sub_page_link.files.contains(current_file) {
SettingsPageItem::SettingItem(SettingItem { files, .. })
| SettingsPageItem::SubPageLink(SubPageLink { files, .. }) => {
if !files.contains(current_file) {
page_filter[index] = false;
} else {
any_found_since_last_header = true;
@@ -1246,12 +1257,13 @@ impl SettingsWindow {
SettingsPageItem::SubPageLink(sub_page_link) => {
documents.push(bm25::Document {
id: key_index,
contents: [page.title, header_str, sub_page_link.title].join("\n"),
contents: [page.title, header_str, sub_page_link.title.as_ref()]
.join("\n"),
});
push_candidates(
&mut fuzzy_match_candidates,
key_index,
sub_page_link.title,
sub_page_link.title.as_ref(),
);
}
}
@@ -1288,7 +1300,7 @@ impl SettingsWindow {
fn build_ui(&mut self, window: &mut Window, cx: &mut Context<SettingsWindow>) {
if self.pages.is_empty() {
self.pages = page_data::settings_data();
self.pages = page_data::settings_data(cx);
self.build_navbar(cx);
self.setup_navbar_focus_subscriptions(window, cx);
self.build_content_handles(window, cx);
@@ -1809,11 +1821,11 @@ impl SettingsWindow {
fn render_sub_page_breadcrumbs(&self) -> impl IntoElement {
let mut items = vec![];
items.push(self.current_page().title);
items.push(self.current_page().title.into());
items.extend(
sub_page_stack()
.iter()
.flat_map(|page| [page.section_header, page.link.title]),
.flat_map(|page| [page.section_header.into(), page.link.title.clone()]),
);
let last = items.pop().unwrap();
@@ -1822,7 +1834,7 @@ impl SettingsWindow {
.children(
items
.into_iter()
.flat_map(|item| [item, "/"])
.flat_map(|item| [item, "/".into()])
.map(|item| Label::new(item).color(Color::Muted)),
)
.child(Label::new(last))