settings_ui: Move settings UI trait to file content (#37337)

Closes #ISSUE

Initially, the `SettingsUi` trait was tied to `Settings`, however, given
that the `Settings::FileContent` type (which may be the same as the type
that implements `Settings`) will be the type that more directly maps to
the JSON structure (and therefore have the documentation, correct field
names (or `serde` rename attributes), etc) it makes more sense to have
the deriving of `SettingsUi` occur on the `FileContent` type rather than
the `Settings` type.

In order for this to work a relatively important change had to be made
to the derive macro, that being that it now "unwraps" options into their
inner type, so a field with type `Option<Foo>` where `Foo: SettingsUi`
will treat the field as if it were just `Foo`, expecting there to be a
default set in `default.json`. This imposes some restrictions on what
`Settings::FileContent` can be as seen in 1e19398 where `FileContent`
itself can't be optional without manually implementing `SettingsUi`, as
well as introducing some risk that if the `FileContent` type has
`serde(default)`, the default value will override the default value from
`default.json` in the UI even though it may differ (but it should!).

A future PR should probably replace the other settings with `FileContent
= Option<T>` (all of which currently have `T == bool`) with wrapper
structs and have `KEY = None` so the further niceties
`derive(SettingsUi)` will provide such as path renaming, custom UI, auto
naming and doc comment extraction can be used.

Release Notes:

- N/A *or* Added/Fixed/Improved ...
This commit is contained in:
Ben Kunkle
2025-09-01 18:42:33 -04:00
committed by GitHub
parent 8a8a9a4f07
commit 60d17cccd3
30 changed files with 137 additions and 95 deletions
+2 -2
View File
@@ -48,7 +48,7 @@ pub enum NotifyWhenAgentWaiting {
Never,
}
#[derive(Default, Clone, Debug, SettingsUi)]
#[derive(Default, Clone, Debug)]
pub struct AgentSettings {
pub enabled: bool,
pub button: bool,
@@ -223,7 +223,7 @@ impl AgentSettingsContent {
}
}
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug, Default)]
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug, Default, SettingsUi)]
pub struct AgentSettingsContent {
/// Whether the Agent is enabled.
///
+2 -2
View File
@@ -4,7 +4,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct AudioSettings {
/// Opt into the new audio system.
#[serde(rename = "experimental.rodio_audio", default)]
@@ -12,7 +12,7 @@ pub struct AudioSettings {
}
/// Configuration of audio in Zed.
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
#[serde(default)]
pub struct AudioSettingsContent {
/// Whether to use the experimental audio system
+7 -6
View File
@@ -113,20 +113,19 @@ impl Drop for MacOsUnmounter {
}
}
#[derive(SettingsUi)]
struct AutoUpdateSetting(bool);
/// Whether or not to automatically check for updates.
///
/// Default: true
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize, SettingsUi)]
#[serde(transparent)]
struct AutoUpdateSettingContent(bool);
impl Settings for AutoUpdateSetting {
const KEY: Option<&'static str> = Some("auto_update");
type FileContent = Option<AutoUpdateSettingContent>;
type FileContent = AutoUpdateSettingContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
let auto_update = [
@@ -136,17 +135,19 @@ impl Settings for AutoUpdateSetting {
sources.user,
]
.into_iter()
.find_map(|value| value.copied().flatten())
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
.find_map(|value| value.copied())
.unwrap_or(*sources.default);
Ok(Self(auto_update.0))
}
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
vscode.enum_setting("update.mode", current, |s| match s {
let mut cur = &mut Some(*current);
vscode.enum_setting("update.mode", &mut cur, |s| match s {
"none" | "manual" => Some(AutoUpdateSettingContent(false)),
_ => Some(AutoUpdateSettingContent(true)),
});
*current = cur.unwrap();
}
}
+2 -2
View File
@@ -4,14 +4,14 @@ use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Deserialize, Debug, SettingsUi)]
#[derive(Deserialize, Debug)]
pub struct CallSettings {
pub mute_on_join: bool,
pub share_on_join: bool,
}
/// Configuration of voice calls in Zed.
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct CallSettingsContent {
/// Whether the microphone should be muted when joining a channel or a call.
///
+6 -6
View File
@@ -96,12 +96,12 @@ actions!(
]
);
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct ClientSettingsContent {
server_url: Option<String>,
}
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct ClientSettings {
pub server_url: String,
}
@@ -122,12 +122,12 @@ impl Settings for ClientSettings {
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
}
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema)]
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct ProxySettingsContent {
proxy: Option<String>,
}
#[derive(Deserialize, Default, SettingsUi)]
#[derive(Deserialize, Default)]
pub struct ProxySettings {
pub proxy: Option<String>,
}
@@ -520,14 +520,14 @@ impl<T: 'static> Drop for PendingEntitySubscription<T> {
}
}
#[derive(Copy, Clone, Deserialize, Debug, SettingsUi)]
#[derive(Copy, Clone, Deserialize, Debug)]
pub struct TelemetrySettings {
pub diagnostics: bool,
pub metrics: bool,
}
/// Control what info is collected by Zed.
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct TelemetrySettingsContent {
/// Send debug info like crash reports.
///
+5 -5
View File
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
use workspace::dock::DockPosition;
#[derive(Deserialize, Debug, SettingsUi)]
#[derive(Deserialize, Debug)]
pub struct CollaborationPanelSettings {
pub button: bool,
pub dock: DockPosition,
@@ -20,14 +20,14 @@ pub enum ChatPanelButton {
WhenInCall,
}
#[derive(Deserialize, Debug, SettingsUi)]
#[derive(Deserialize, Debug)]
pub struct ChatPanelSettings {
pub button: ChatPanelButton,
pub dock: DockPosition,
pub default_width: Pixels,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct ChatPanelSettingsContent {
/// When to show the panel button in the status bar.
///
@@ -43,14 +43,14 @@ pub struct ChatPanelSettingsContent {
pub default_width: Option<f32>,
}
#[derive(Deserialize, Debug, SettingsUi)]
#[derive(Deserialize, Debug)]
pub struct NotificationPanelSettings {
pub button: bool,
pub dock: DockPosition,
pub default_width: Pixels,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct PanelSettingsContent {
/// Whether to show the panel button in the status bar.
///
+2
View File
@@ -14,6 +14,8 @@ pub enum DebugPanelDockPosition {
#[derive(Serialize, Deserialize, JsonSchema, Clone, Copy, SettingsUi)]
#[serde(default)]
// todo(settings_ui) @ben: I'm pretty sure not having the fields be optional here is a bug,
// it means the defaults will override previously set values if a single key is missing
#[settings_ui(group = "Debugger", path = "debugger")]
pub struct DebuggerSettings {
/// Determines the stepping granularity.
+2 -2
View File
@@ -11,7 +11,7 @@ use util::serde::default_true;
/// Imports from the VSCode settings at
/// https://code.visualstudio.com/docs/reference/default-settings
#[derive(Deserialize, Clone, SettingsUi)]
#[derive(Deserialize, Clone)]
pub struct EditorSettings {
pub cursor_blink: bool,
pub cursor_shape: Option<CursorShape>,
@@ -415,7 +415,7 @@ pub enum SnippetSortOrder {
None,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct EditorSettingsContent {
/// Whether the cursor blinks in the editor.
///
@@ -3,7 +3,7 @@ use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, SettingsUi)]
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct FileFinderSettings {
pub file_icons: bool,
pub modal_max_width: Option<FileFinderWidth>,
@@ -11,7 +11,7 @@ pub struct FileFinderSettings {
pub include_ignored: Option<bool>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct FileFinderSettingsContent {
/// Whether to show file icons in the file finder.
///
+2 -2
View File
@@ -36,7 +36,7 @@ pub enum StatusStyle {
LabelColor,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct GitPanelSettingsContent {
/// Whether to show the panel button in the status bar.
///
@@ -77,7 +77,7 @@ pub struct GitPanelSettingsContent {
pub collapse_untracked_diff: Option<bool>,
}
#[derive(Deserialize, Debug, Clone, PartialEq, SettingsUi)]
#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct GitPanelSettings {
pub button: bool,
pub dock: DockPosition,
+5 -5
View File
@@ -293,7 +293,7 @@ impl StatusItemView for CursorPosition {
}
}
#[derive(Clone, Copy, Default, PartialEq, JsonSchema, Deserialize, Serialize, SettingsUi)]
#[derive(Clone, Copy, Default, PartialEq, JsonSchema, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum LineIndicatorFormat {
Short,
@@ -301,14 +301,14 @@ pub(crate) enum LineIndicatorFormat {
Long,
}
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize, SettingsUi)]
#[serde(transparent)]
pub(crate) struct LineIndicatorFormatContent(LineIndicatorFormat);
impl Settings for LineIndicatorFormat {
const KEY: Option<&'static str> = Some("line_indicator_format");
type FileContent = Option<LineIndicatorFormatContent>;
type FileContent = LineIndicatorFormatContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
let format = [
@@ -317,8 +317,8 @@ impl Settings for LineIndicatorFormat {
sources.user,
]
.into_iter()
.find_map(|value| value.copied().flatten())
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
.find_map(|value| value.copied())
.unwrap_or(*sources.default);
Ok(format.0)
}
+2 -2
View File
@@ -55,7 +55,7 @@ pub fn all_language_settings<'a>(
}
/// The settings for all languages.
#[derive(Debug, Clone, SettingsUi)]
#[derive(Debug, Clone)]
pub struct AllLanguageSettings {
/// The edit prediction settings.
pub edit_predictions: EditPredictionSettings,
@@ -292,7 +292,7 @@ pub struct CopilotSettings {
}
/// The settings for all languages.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct AllLanguageSettingsContent {
/// The settings for enabling/disabling features.
#[serde(default)]
+2 -2
View File
@@ -29,7 +29,7 @@ pub fn init_settings(cx: &mut App) {
AllLanguageModelSettings::register(cx);
}
#[derive(Default, SettingsUi)]
#[derive(Default)]
pub struct AllLanguageModelSettings {
pub anthropic: AnthropicSettings,
pub bedrock: AmazonBedrockSettings,
@@ -46,7 +46,7 @@ pub struct AllLanguageModelSettings {
pub zed_dot_dev: ZedDotDevSettings,
}
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, SettingsUi)]
pub struct AllLanguageModelSettingsContent {
pub anthropic: Option<AnthropicSettingsContent>,
pub bedrock: Option<AmazonBedrockSettingsContent>,
+1 -1
View File
@@ -187,7 +187,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
);
update_settings_file::<BaseKeymap>(self.fs.clone(), cx, move |setting, _| {
*setting = Some(base_keymap)
setting.base_keymap = Some(base_keymap)
});
}
+1 -1
View File
@@ -325,7 +325,7 @@ fn render_base_keymap_section(tab_index: &mut isize, cx: &mut App) -> impl IntoE
let fs = <dyn Fs>::global(cx);
update_settings_file::<BaseKeymap>(fs, cx, move |setting, _| {
*setting = Some(keymap_base);
setting.base_keymap = Some(keymap_base);
});
}
}
@@ -18,7 +18,7 @@ pub enum ShowIndentGuides {
Never,
}
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, SettingsUi)]
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct OutlinePanelSettings {
pub button: bool,
pub default_width: Pixels,
@@ -61,7 +61,7 @@ pub struct IndentGuidesSettingsContent {
pub show: Option<ShowIndentGuides>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct OutlinePanelSettingsContent {
/// Whether to show the outline panel button in the status bar.
///
@@ -28,7 +28,7 @@ pub enum EntrySpacing {
Standard,
}
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, SettingsUi)]
#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
pub struct ProjectPanelSettings {
pub button: bool,
pub hide_gitignore: bool,
@@ -92,7 +92,7 @@ pub enum ShowDiagnostics {
All,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct ProjectPanelSettingsContent {
/// Whether to show the project panel button in the status bar.
///
@@ -30,7 +30,7 @@ use ui::{
use util::serde::default_true;
use workspace::{AppState, ModalView, Workspace};
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct SshSettings {
pub ssh_connections: Option<Vec<SshConnection>>,
/// Whether to read ~/.ssh/config for ssh connection sources.
@@ -121,7 +121,7 @@ pub struct SshProject {
pub paths: Vec<String>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct RemoteSettingsContent {
pub ssh_connections: Option<Vec<SshConnection>>,
pub read_ssh_config: Option<bool>,
+2 -2
View File
@@ -6,7 +6,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Debug, Default, SettingsUi)]
#[derive(Debug, Default)]
pub struct JupyterSettings {
pub kernel_selections: HashMap<String, String>,
}
@@ -20,7 +20,7 @@ impl JupyterSettings {
}
}
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
pub struct JupyterSettingsContent {
/// Default kernels to select for each language.
///
+18 -7
View File
@@ -100,25 +100,36 @@ impl BaseKeymap {
}
}
impl Settings for BaseKeymap {
const KEY: Option<&'static str> = Some("base_keymap");
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default, SettingsUi,
)]
// extracted so that it can be an option, and still work with derive(SettingsUi)
pub struct BaseKeymapSetting {
pub base_keymap: Option<BaseKeymap>,
}
type FileContent = Option<Self>;
impl Settings for BaseKeymap {
const KEY: Option<&'static str> = None;
type FileContent = BaseKeymapSetting;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::App,
) -> anyhow::Result<Self> {
if let Some(Some(user_value)) = sources.user.copied() {
if let Some(Some(user_value)) = sources.user.map(|setting| setting.base_keymap) {
return Ok(user_value);
}
if let Some(Some(server_value)) = sources.server.copied() {
if let Some(Some(server_value)) = sources.server.map(|setting| setting.base_keymap) {
return Ok(server_value);
}
sources.default.ok_or_else(Self::missing_default)
sources
.default
.base_keymap
.ok_or_else(Self::missing_default)
}
fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut Self::FileContent) {
*current = Some(BaseKeymap::VSCode);
current.base_keymap = Some(BaseKeymap::VSCode);
}
}
+9 -9
View File
@@ -39,7 +39,7 @@ use crate::{
/// A value that can be defined as a user setting.
///
/// Settings can be loaded from a combination of multiple JSON files.
pub trait Settings: SettingsUi + 'static + Send + Sync {
pub trait Settings: 'static + Send + Sync {
/// The name of a key within the JSON file from which this setting should
/// be deserialized. If this is `None`, then the setting will be deserialized
/// from the root object.
@@ -57,7 +57,7 @@ pub trait Settings: SettingsUi + 'static + Send + Sync {
const PRESERVED_KEYS: Option<&'static [&'static str]> = None;
/// The type that is stored in an individual JSON file.
type FileContent: Clone + Default + Serialize + DeserializeOwned + JsonSchema;
type FileContent: Clone + Default + Serialize + DeserializeOwned + JsonSchema + SettingsUi;
/// The logic for combining together values from one or more JSON files into the
/// final value for this setting.
@@ -1565,7 +1565,7 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
}
fn settings_ui_item(&self) -> SettingsUiEntry {
<T as SettingsUi>::settings_ui_entry()
<<T as Settings>::FileContent as SettingsUi>::settings_ui_entry()
}
}
@@ -2147,12 +2147,12 @@ mod tests {
}
}
#[derive(Debug, Deserialize, PartialEq, SettingsUi)]
#[derive(Debug, Deserialize, PartialEq)]
struct TurboSetting(bool);
impl Settings for TurboSetting {
const KEY: Option<&'static str> = Some("turbo");
type FileContent = Option<bool>;
type FileContent = bool;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
sources.json_merge()
@@ -2161,7 +2161,7 @@ mod tests {
fn import_from_vscode(_vscode: &VsCodeSettings, _current: &mut Self::FileContent) {}
}
#[derive(Clone, Debug, PartialEq, Deserialize, SettingsUi)]
#[derive(Clone, Debug, PartialEq, Deserialize)]
struct MultiKeySettings {
#[serde(default)]
key1: String,
@@ -2169,7 +2169,7 @@ mod tests {
key2: String,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
struct MultiKeySettingsJson {
key1: Option<String>,
key2: Option<String>,
@@ -2194,7 +2194,7 @@ mod tests {
}
}
#[derive(Debug, Deserialize, SettingsUi)]
#[derive(Debug, Deserialize)]
struct JournalSettings {
pub path: String,
pub hour_format: HourFormat,
@@ -2207,7 +2207,7 @@ mod tests {
Hour24,
}
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, SettingsUi)]
struct JournalSettingsJson {
pub path: Option<String>,
pub hour_format: Option<HourFormat>,
+12 -11
View File
@@ -7,9 +7,16 @@ use crate::SettingsStore;
pub trait SettingsUi {
fn settings_ui_item() -> SettingsUiItem {
// todo(settings_ui): remove this default impl, only entry should have a default impl
// because it's expected that the macro or custom impl use the item and the known paths to create the entry
SettingsUiItem::None
}
fn settings_ui_entry() -> SettingsUiEntry;
fn settings_ui_entry() -> SettingsUiEntry {
SettingsUiEntry {
item: SettingsUiEntryVariant::None,
}
}
}
pub struct SettingsUiEntry {
@@ -106,11 +113,11 @@ impl SettingsUi for bool {
fn settings_ui_item() -> SettingsUiItem {
SettingsUiItem::Single(SettingsUiItemSingle::SwitchField)
}
}
fn settings_ui_entry() -> SettingsUiEntry {
SettingsUiEntry {
item: SettingsUiEntryVariant::None,
}
impl SettingsUi for Option<bool> {
fn settings_ui_item() -> SettingsUiItem {
SettingsUiItem::Single(SettingsUiItemSingle::SwitchField)
}
}
@@ -118,10 +125,4 @@ impl SettingsUi for u64 {
fn settings_ui_item() -> SettingsUiItem {
SettingsUiItem::Single(SettingsUiItemSingle::NumericStepper)
}
fn settings_ui_entry() -> SettingsUiEntry {
SettingsUiEntry {
item: SettingsUiEntryVariant::None,
}
}
}
@@ -88,7 +88,34 @@ pub fn derive_settings_ui(input: proc_macro::TokenStream) -> proc_macro::TokenSt
proc_macro::TokenStream::from(expanded)
}
fn extract_type_from_option(ty: TokenStream) -> TokenStream {
match option_inner_type(ty.clone()) {
Some(inner_type) => inner_type,
None => ty,
}
}
fn option_inner_type(ty: TokenStream) -> Option<TokenStream> {
let ty = syn::parse2::<syn::Type>(ty).ok()?;
let syn::Type::Path(path) = ty else {
return None;
};
let segment = path.path.segments.last()?;
if segment.ident != "Option" {
return None;
}
let syn::PathArguments::AngleBracketed(args) = &segment.arguments else {
return None;
};
let arg = args.args.first()?;
let syn::GenericArgument::Type(ty) = arg else {
return None;
};
return Some(ty.to_token_stream());
}
fn map_ui_item_to_render(path: &str, ty: TokenStream) -> TokenStream {
let ty = extract_type_from_option(ty);
quote! {
settings::SettingsUiEntry {
item: match #ty::settings_ui_item() {
+2 -2
View File
@@ -24,7 +24,7 @@ pub struct Toolbar {
pub breadcrumbs: bool,
}
#[derive(Clone, Debug, Deserialize, SettingsUi)]
#[derive(Clone, Debug, Deserialize)]
pub struct TerminalSettings {
pub shell: Shell,
pub working_directory: WorkingDirectory,
@@ -135,7 +135,7 @@ pub enum ActivateScript {
Pyenv,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct TerminalSettingsContent {
/// What shell to use when opening a terminal.
///
+2 -2
View File
@@ -87,7 +87,7 @@ impl From<UiDensity> for String {
}
/// Customizable settings for the UI and theme system.
#[derive(Clone, PartialEq, SettingsUi)]
#[derive(Clone, PartialEq)]
pub struct ThemeSettings {
/// The UI font size. Determines the size of text in the UI,
/// as well as the size of a [gpui::Rems] unit.
@@ -365,7 +365,7 @@ impl IconThemeSelection {
}
/// Settings for rendering text in UI and text buffers.
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct ThemeSettingsContent {
/// The default font size for text in the UI.
#[serde(default)]
+3 -3
View File
@@ -3,8 +3,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Copy, Clone, Deserialize, Debug, SettingsUi)]
#[settings_ui(group = "Title Bar", path = "title_bar")]
#[derive(Copy, Clone, Deserialize, Debug)]
pub struct TitleBarSettings {
pub show_branch_icon: bool,
pub show_onboarding_banner: bool,
@@ -15,7 +14,8 @@ pub struct TitleBarSettings {
pub show_menus: bool,
}
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
#[settings_ui(group = "Title Bar", path = "title_bar")]
pub struct TitleBarSettingsContent {
/// Whether to show the branch icon beside branch switcher in the title bar.
///
+2 -2
View File
@@ -1774,7 +1774,7 @@ struct CursorShapeSettings {
pub insert: Option<CursorShape>,
}
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
struct VimSettings {
pub default_mode: Mode,
pub toggle_relative_line_numbers: bool,
@@ -1785,7 +1785,7 @@ struct VimSettings {
pub cursor_shape: CursorShapeSettings,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
struct VimSettingsContent {
pub default_mode: Option<ModeContent>,
pub toggle_relative_line_numbers: Option<bool>,
+4 -4
View File
@@ -49,7 +49,7 @@ impl Default for SaveOptions {
}
}
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct ItemSettings {
pub git_status: bool,
pub close_position: ClosePosition,
@@ -59,7 +59,7 @@ pub struct ItemSettings {
pub show_close_button: ShowCloseButton,
}
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct PreviewTabsSettings {
pub enabled: bool,
pub enable_preview_from_file_finder: bool,
@@ -101,7 +101,7 @@ pub enum ActivateOnClose {
LeftNeighbour,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct ItemSettingsContent {
/// Whether to show the Git file status on a tab item.
///
@@ -130,7 +130,7 @@ pub struct ItemSettingsContent {
show_close_button: Option<ShowCloseButton>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct PreviewTabsSettingsContent {
/// Whether to show opened editors as preview tabs.
/// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.
+5 -5
View File
@@ -8,7 +8,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct WorkspaceSettings {
pub active_pane_modifiers: ActivePanelModifiers,
pub bottom_dock_layout: BottomDockLayout,
@@ -118,7 +118,7 @@ pub enum RestoreOnStartupBehavior {
LastSession,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct WorkspaceSettingsContent {
/// Active pane styling settings.
pub active_pane_modifiers: Option<ActivePanelModifiers>,
@@ -216,14 +216,14 @@ pub struct WorkspaceSettingsContent {
pub zoomed_padding: Option<bool>,
}
#[derive(Deserialize, SettingsUi)]
#[derive(Deserialize)]
pub struct TabBarSettings {
pub show: bool,
pub show_nav_history_buttons: bool,
pub show_tab_bar_buttons: bool,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct TabBarSettingsContent {
/// Whether or not to show the tab bar in the editor.
///
@@ -266,7 +266,7 @@ pub enum PaneSplitDirectionVertical {
Right,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, SettingsUi)]
#[serde(rename_all = "snake_case")]
pub struct CenteredLayoutSettings {
/// The relative width of the left padding of the central pane from the
+2 -2
View File
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsUi};
use util::paths::PathMatcher;
#[derive(Clone, PartialEq, Eq, SettingsUi)]
#[derive(Clone, PartialEq, Eq)]
pub struct WorktreeSettings {
pub file_scan_inclusions: PathMatcher,
pub file_scan_exclusions: PathMatcher,
@@ -31,7 +31,7 @@ impl WorktreeSettings {
}
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi)]
pub struct WorktreeSettingsContent {
/// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
/// `file_scan_inclusions`.