Settings refactor (#38367)

Co-Authored-By: Ben K <ben@zed.dev>
Co-Authored-By: Anthony <anthony@zed.dev>
Co-Authored-By: Mikayla <mikayla@zed.dev>

Release Notes:

- settings: Major internal changes to settings. The primary user-facing
effect is that some settings which did not make sense in project
settings files are no-longer read from there. (For example the inline
blame settings)

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Conrad Irwin
2025-09-18 16:47:23 +00:00
committed by GitHub
co-authored by Ben Kunkle Mikayla Maki Anthony
parent 0a9023bce0
commit fcdab160f9
219 changed files with 11697 additions and 11894 deletions
+47 -20
View File
@@ -1,9 +1,14 @@
use std::fmt::{Display, Formatter};
use crate::{self as settings};
use crate::{
self as settings,
settings_content::{self, BaseKeymapContent, SettingsContent},
};
use gpui::App;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, VsCodeSettings};
use serde_with::skip_serializing_none;
use settings::{Settings, VsCodeSettings};
use settings_ui_macros::{SettingsKey, SettingsUi};
/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
@@ -24,6 +29,35 @@ pub enum BaseKeymap {
None,
}
impl From<BaseKeymapContent> for BaseKeymap {
fn from(value: BaseKeymapContent) -> Self {
match value {
BaseKeymapContent::VSCode => Self::VSCode,
BaseKeymapContent::JetBrains => Self::JetBrains,
BaseKeymapContent::SublimeText => Self::SublimeText,
BaseKeymapContent::Atom => Self::Atom,
BaseKeymapContent::TextMate => Self::TextMate,
BaseKeymapContent::Emacs => Self::Emacs,
BaseKeymapContent::Cursor => Self::Cursor,
BaseKeymapContent::None => Self::None,
}
}
}
impl Into<BaseKeymapContent> for BaseKeymap {
fn into(self) -> BaseKeymapContent {
match self {
BaseKeymap::VSCode => BaseKeymapContent::VSCode,
BaseKeymap::JetBrains => BaseKeymapContent::JetBrains,
BaseKeymap::SublimeText => BaseKeymapContent::SublimeText,
BaseKeymap::Atom => BaseKeymapContent::Atom,
BaseKeymap::TextMate => BaseKeymapContent::TextMate,
BaseKeymap::Emacs => BaseKeymapContent::Emacs,
BaseKeymap::Cursor => BaseKeymapContent::Cursor,
BaseKeymap::None => BaseKeymapContent::None,
}
}
}
impl Display for BaseKeymap {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@@ -115,30 +149,23 @@ impl BaseKeymap {
)]
// extracted so that it can be an option, and still work with derive(SettingsUi)
#[settings_key(None)]
#[skip_serializing_none]
pub struct BaseKeymapSetting {
pub base_keymap: Option<BaseKeymap>,
}
impl Settings for BaseKeymap {
type FileContent = BaseKeymapSetting;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::App,
) -> anyhow::Result<Self> {
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.map(|setting| setting.base_keymap) {
return Ok(server_value);
}
sources
.default
.base_keymap
.ok_or_else(Self::missing_default)
fn from_defaults(s: &crate::settings_content::SettingsContent, _cx: &mut App) -> Self {
s.base_keymap.unwrap().into()
}
fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut Self::FileContent) {
current.base_keymap = Some(BaseKeymap::VSCode);
fn refine(&mut self, s: &settings_content::SettingsContent, _cx: &mut App) {
if let Some(base_keymap) = s.base_keymap {
*self = base_keymap.into();
};
}
fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut SettingsContent) {
current.base_keymap = Some(BaseKeymapContent::VSCode);
}
}
@@ -1,16 +1,13 @@
use fs::Fs;
use gpui::{App, RenderOnce, SharedString};
use crate::{Settings, update_settings_file};
use crate::{settings_content::SettingsContent, update_settings_file};
/// A UI control that can be used to edit a setting.
pub trait EditableSettingControl: RenderOnce {
/// The type of the setting value.
type Value: Send;
/// The settings type to which this setting belongs.
type Settings: Settings;
/// Returns the name of this setting.
fn name(&self) -> SharedString;
@@ -20,17 +17,13 @@ pub trait EditableSettingControl: RenderOnce {
/// Applies the given setting file to the settings file contents.
///
/// This will be called when writing the setting value back to the settings file.
fn apply(
settings: &mut <Self::Settings as Settings>::FileContent,
value: Self::Value,
cx: &App,
);
fn apply(settings: &mut SettingsContent, value: Self::Value, cx: &App);
/// Writes the given setting value to the settings files.
fn write(value: Self::Value, cx: &App) {
let fs = <dyn Fs>::global(cx);
update_settings_file::<Self::Settings>(fs, cx, move |settings, cx| {
update_settings_file(fs, cx, move |settings, cx| {
Self::apply(settings, value, cx);
});
}
+5 -6
View File
@@ -1,12 +1,15 @@
mod base_keymap_setting;
mod editable_setting_control;
mod keymap_file;
mod settings_content;
mod settings_file;
mod settings_json;
mod settings_store;
mod settings_ui_core;
mod vscode_import;
pub use settings_content::*;
use gpui::{App, Global};
use rust_embed::RustEmbed;
use std::{borrow::Cow, fmt, str};
@@ -21,8 +24,7 @@ pub use keymap_file::{
pub use settings_file::*;
pub use settings_json::*;
pub use settings_store::{
InvalidSettingsError, LocalSettingsKind, Settings, SettingsKey, SettingsLocation,
SettingsSources, SettingsStore,
InvalidSettingsError, LocalSettingsKind, Settings, SettingsKey, SettingsLocation, SettingsStore,
};
pub use settings_ui_core::*;
// Re-export the derive macro
@@ -75,10 +77,7 @@ impl fmt::Display for WorktreeId {
pub struct SettingsAssets;
pub fn init(cx: &mut App) {
let mut settings = SettingsStore::new(cx);
settings
.set_default_settings(&default_settings(), cx)
.unwrap();
let settings = SettingsStore::new(cx, &default_settings());
cx.set_global(settings);
BaseKeymap::register(cx);
SettingsStore::observe_active_settings_profile_name(cx).detach();
+818
View File
@@ -0,0 +1,818 @@
mod agent;
mod editor;
mod language;
mod language_model;
mod project;
mod terminal;
mod theme;
mod workspace;
pub use agent::*;
pub use editor::*;
pub use language::*;
pub use language_model::*;
pub use project::*;
pub use terminal::*;
pub use theme::*;
pub use workspace::*;
use collections::HashMap;
use gpui::{App, SharedString};
use release_channel::ReleaseChannel;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::collections::BTreeSet;
use std::env;
use std::sync::Arc;
pub use util::serde::default_true;
use crate::ActiveSettingsProfileName;
#[skip_serializing_none]
#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize, JsonSchema)]
pub struct SettingsContent {
#[serde(flatten)]
pub project: ProjectSettingsContent,
#[serde(flatten)]
pub theme: Box<ThemeSettingsContent>,
#[serde(flatten)]
pub extension: ExtensionSettingsContent,
#[serde(flatten)]
pub workspace: WorkspaceSettingsContent,
#[serde(flatten)]
pub editor: EditorSettingsContent,
#[serde(flatten)]
pub remote: RemoteSettingsContent,
/// Settings related to the file finder.
pub file_finder: Option<FileFinderSettingsContent>,
pub git_panel: Option<GitPanelSettingsContent>,
pub tabs: Option<ItemSettingsContent>,
pub tab_bar: Option<TabBarSettingsContent>,
pub preview_tabs: Option<PreviewTabsSettingsContent>,
pub agent: Option<AgentSettingsContent>,
pub agent_servers: Option<AllAgentServersSettings>,
/// Configuration of audio in Zed.
pub audio: Option<AudioSettingsContent>,
/// Whether or not to automatically check for updates.
///
/// Default: true
pub auto_update: Option<bool>,
/// This base keymap settings adjusts the default keybindings in Zed to be similar
/// to other common code editors. By default, Zed's keymap closely follows VSCode's
/// keymap, with minor adjustments, this corresponds to the "VSCode" setting.
///
/// Default: VSCode
pub base_keymap: Option<BaseKeymapContent>,
/// Configuration for the collab panel visual settings.
pub collaboration_panel: Option<PanelSettingsContent>,
pub debugger: Option<DebuggerSettingsContent>,
/// Configuration for Diagnostics-related features.
pub diagnostics: Option<DiagnosticsSettingsContent>,
/// Configuration for Git-related features
pub git: Option<GitSettings>,
/// Common language server settings.
pub global_lsp_settings: Option<GlobalLspSettingsContent>,
/// The settings for the image viewer.
pub image_viewer: Option<ImageViewerSettingsContent>,
pub repl: Option<ReplSettingsContent>,
/// Whether or not to enable Helix mode.
///
/// Default: false
pub helix_mode: Option<bool>,
pub journal: Option<JournalSettingsContent>,
/// A map of log scopes to the desired log level.
/// Useful for filtering out noisy logs or enabling more verbose logging.
///
/// Example: {"log": {"client": "warn"}}
pub log: Option<HashMap<String, String>>,
pub line_indicator_format: Option<LineIndicatorFormat>,
pub language_models: Option<AllLanguageModelSettingsContent>,
pub outline_panel: Option<OutlinePanelSettingsContent>,
pub project_panel: Option<ProjectPanelSettingsContent>,
/// Configuration for the Message Editor
pub message_editor: Option<MessageEditorSettings>,
/// Configuration for Node-related features
pub node: Option<NodeBinarySettings>,
/// Configuration for the Notification Panel
pub notification_panel: Option<NotificationPanelSettingsContent>,
pub proxy: Option<String>,
/// The URL of the Zed server to connect to.
pub server_url: Option<String>,
/// Configuration for session-related features
pub session: Option<SessionSettingsContent>,
/// Control what info is collected by Zed.
pub telemetry: Option<TelemetrySettingsContent>,
/// Configuration of the terminal in Zed.
pub terminal: Option<TerminalSettingsContent>,
pub title_bar: Option<TitleBarSettingsContent>,
/// Whether or not to enable Vim mode.
///
/// Default: false
pub vim_mode: Option<bool>,
// Settings related to calls in Zed
pub calls: Option<CallSettingsContent>,
/// Whether to disable all AI features in Zed.
///
/// Default: false
pub disable_ai: Option<bool>,
/// Settings related to Vim mode in Zed.
pub vim: Option<VimSettingsContent>,
}
impl SettingsContent {
pub fn languages_mut(&mut self) -> &mut HashMap<SharedString, LanguageSettingsContent> {
&mut self.project.all_languages.languages.0
}
}
#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct ServerSettingsContent {
#[serde(flatten)]
pub project: ProjectSettingsContent,
}
#[skip_serializing_none]
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct UserSettingsContent {
#[serde(flatten)]
pub content: Box<SettingsContent>,
pub dev: Option<Box<SettingsContent>>,
pub nightly: Option<Box<SettingsContent>>,
pub preview: Option<Box<SettingsContent>>,
pub stable: Option<Box<SettingsContent>>,
pub macos: Option<Box<SettingsContent>>,
pub windows: Option<Box<SettingsContent>>,
pub linux: Option<Box<SettingsContent>>,
#[serde(default)]
pub profiles: HashMap<String, SettingsContent>,
}
pub struct ExtensionsSettingsContent {
pub all_languages: AllLanguageSettingsContent,
}
impl UserSettingsContent {
pub fn for_release_channel(&self) -> Option<&SettingsContent> {
match *release_channel::RELEASE_CHANNEL {
ReleaseChannel::Dev => self.dev.as_deref(),
ReleaseChannel::Nightly => self.nightly.as_deref(),
ReleaseChannel::Preview => self.preview.as_deref(),
ReleaseChannel::Stable => self.stable.as_deref(),
}
}
pub fn for_os(&self) -> Option<&SettingsContent> {
match env::consts::OS {
"macos" => self.macos.as_deref(),
"linux" => self.linux.as_deref(),
"windows" => self.windows.as_deref(),
_ => None,
}
}
pub fn for_profile(&self, cx: &App) -> Option<&SettingsContent> {
let Some(active_profile) = cx.try_global::<ActiveSettingsProfileName>() else {
return None;
};
self.profiles.get(&active_profile.0)
}
}
/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
///
/// Default: VSCode
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
pub enum BaseKeymapContent {
#[default]
VSCode,
JetBrains,
SublimeText,
Atom,
TextMate,
Emacs,
Cursor,
None,
}
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct TitleBarSettingsContent {
/// Controls when the title bar is visible: "always" | "never" | "hide_in_full_screen".
///
/// Default: "always"
pub show: Option<TitleBarVisibility>,
/// Whether to show the branch icon beside branch switcher in the title bar.
///
/// Default: false
pub show_branch_icon: Option<bool>,
/// Whether to show onboarding banners in the title bar.
///
/// Default: true
pub show_onboarding_banner: Option<bool>,
/// Whether to show user avatar in the title bar.
///
/// Default: true
pub show_user_picture: Option<bool>,
/// Whether to show the branch name button in the titlebar.
///
/// Default: true
pub show_branch_name: Option<bool>,
/// Whether to show the project host and name in the titlebar.
///
/// Default: true
pub show_project_items: Option<bool>,
/// Whether to show the sign in button in the title bar.
///
/// Default: true
pub show_sign_in: Option<bool>,
/// Whether to show the menus in the title bar.
///
/// Default: false
pub show_menus: Option<bool>,
}
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum TitleBarVisibility {
Always,
Never,
HideInFullScreen,
}
/// Configuration of audio in Zed.
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct AudioSettingsContent {
/// Opt into the new audio system.
#[serde(rename = "experimental.rodio_audio", default)]
pub rodio_audio: Option<bool>,
/// Requires 'rodio_audio: true'
///
/// Use the new audio systems automatic gain control for your microphone.
/// This affects how loud you sound to others.
#[serde(rename = "experimental.control_input_volume", default)]
pub control_input_volume: Option<bool>,
/// Requires 'rodio_audio: true'
///
/// Use the new audio systems automatic gain control on everyone in the
/// call. This makes call members who are too quite louder and those who are
/// too loud quieter. This only affects how things sound for you.
#[serde(rename = "experimental.control_output_volume", default)]
pub control_output_volume: Option<bool>,
}
/// Control what info is collected by Zed.
#[skip_serializing_none]
#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Debug)]
pub struct TelemetrySettingsContent {
/// Send debug info like crash reports.
///
/// Default: true
pub diagnostics: Option<bool>,
/// Send anonymized usage data like what languages you're using Zed with.
///
/// Default: true
pub metrics: Option<bool>,
}
#[skip_serializing_none]
#[derive(Default, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Clone)]
pub struct DebuggerSettingsContent {
/// Determines the stepping granularity.
///
/// Default: line
pub stepping_granularity: Option<SteppingGranularity>,
/// Whether the breakpoints should be reused across Zed sessions.
///
/// Default: true
pub save_breakpoints: Option<bool>,
/// Whether to show the debug button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Time in milliseconds until timeout error when connecting to a TCP debug adapter
///
/// Default: 2000ms
pub timeout: Option<u64>,
/// Whether to log messages between active debug adapters and Zed
///
/// Default: true
pub log_dap_communications: Option<bool>,
/// Whether to format dap messages in when adding them to debug adapter logger
///
/// Default: true
pub format_dap_log_messages: Option<bool>,
/// The dock position of the debug panel
///
/// Default: Bottom
pub dock: Option<DockPosition>,
}
/// The granularity of one 'step' in the stepping requests `next`, `stepIn`, `stepOut`, and `stepBack`.
#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SteppingGranularity {
/// The step should allow the program to run until the current statement has finished executing.
/// The meaning of a statement is determined by the adapter and it may be considered equivalent to a line.
/// For example 'for(int i = 0; i < 10; i++)' could be considered to have 3 statements 'int i = 0', 'i < 10', and 'i++'.
Statement,
/// The step should allow the program to run until the current source line has executed.
Line,
/// The step should allow one instruction to execute (e.g. one x86 instruction).
Instruction,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DockPosition {
Left,
Bottom,
Right,
}
/// Settings for slash commands.
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, PartialEq, Eq)]
pub struct SlashCommandSettings {
/// Settings for the `/cargo-workspace` slash command.
pub cargo_workspace: Option<CargoWorkspaceCommandSettings>,
}
/// Settings for the `/cargo-workspace` slash command.
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, PartialEq, Eq)]
pub struct CargoWorkspaceCommandSettings {
/// Whether `/cargo-workspace` is enabled.
pub enabled: Option<bool>,
}
/// Configuration of voice calls in Zed.
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct CallSettingsContent {
/// Whether the microphone should be muted when joining a channel or a call.
///
/// Default: false
pub mute_on_join: Option<bool>,
/// Whether your current project should be shared when joining an empty channel.
///
/// Default: false
pub share_on_join: Option<bool>,
}
#[skip_serializing_none]
#[derive(Deserialize, Serialize, PartialEq, Debug, Default, Clone, JsonSchema)]
pub struct ExtensionSettingsContent {
/// The extensions that should be automatically installed by Zed.
///
/// This is used to make functionality provided by extensions (e.g., language support)
/// available out-of-the-box.
///
/// Default: { "html": true }
#[serde(default)]
pub auto_install_extensions: HashMap<Arc<str>, bool>,
#[serde(default)]
pub auto_update_extensions: HashMap<Arc<str>, bool>,
}
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct GitPanelSettingsContent {
/// Whether to show the panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Where to dock the panel.
///
/// Default: left
pub dock: Option<DockPosition>,
/// Default width of the panel in pixels.
///
/// Default: 360
pub default_width: Option<f32>,
/// How entry statuses are displayed.
///
/// Default: icon
pub status_style: Option<StatusStyle>,
/// How and when the scrollbar should be displayed.
///
/// Default: inherits editor scrollbar settings
pub scrollbar: Option<ScrollbarSettings>,
/// What the default branch name should be when
/// `init.defaultBranch` is not set in git
///
/// Default: main
pub fallback_branch_name: Option<String>,
/// Whether to sort entries in the panel by path
/// or by status (the default).
///
/// Default: false
pub sort_by_path: Option<bool>,
/// Whether to collapse untracked files in the diff panel.
///
/// Default: false
pub collapse_untracked_diff: Option<bool>,
}
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum StatusStyle {
#[default]
Icon,
LabelColor,
}
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ScrollbarSettings {
pub show: Option<ShowScrollbar>,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct NotificationPanelSettingsContent {
/// Whether to show the panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Where to dock the panel.
///
/// Default: right
pub dock: Option<DockPosition>,
/// Default width of the panel in pixels.
///
/// Default: 300
pub default_width: Option<f32>,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct PanelSettingsContent {
/// Whether to show the panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Where to dock the panel.
///
/// Default: left
pub dock: Option<DockPosition>,
/// Default width of the panel in pixels.
///
/// Default: 240
pub default_width: Option<f32>,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct MessageEditorSettings {
/// Whether to automatically replace emoji shortcodes with emoji characters.
/// For example: typing `:wave:` gets replaced with `👋`.
///
/// Default: false
pub auto_replace_emoji_shortcode: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct FileFinderSettingsContent {
/// Whether to show file icons in the file finder.
///
/// Default: true
pub file_icons: Option<bool>,
/// Determines how much space the file finder can take up in relation to the available window width.
///
/// Default: small
pub modal_max_width: Option<FileFinderWidthContent>,
/// Determines whether the file finder should skip focus for the active file in search results.
///
/// Default: true
pub skip_focus_for_active_in_search: Option<bool>,
/// Determines whether to show the git status in the file finder
///
/// Default: true
pub git_status: Option<bool>,
/// Whether to use gitignored files when searching.
/// Only the file Zed had indexed will be used, not necessary all the gitignored files.
///
/// Can accept 3 values:
/// * `Some(true)`: Use all gitignored files
/// * `Some(false)`: Use only the files Zed had indexed
/// * `None`: Be smart and search for ignored when called from a gitignored worktree
///
/// Default: None
/// todo() -> Change this type to an enum
pub include_ignored: Option<Option<bool>>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum FileFinderWidthContent {
#[default]
Small,
Medium,
Large,
XLarge,
Full,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Debug, JsonSchema)]
pub struct VimSettingsContent {
pub default_mode: Option<ModeContent>,
pub toggle_relative_line_numbers: Option<bool>,
pub use_system_clipboard: Option<UseSystemClipboard>,
pub use_smartcase_find: Option<bool>,
pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
pub highlight_on_yank_duration: Option<u64>,
pub cursor_shape: Option<CursorShapeSettings>,
}
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ModeContent {
#[default]
Normal,
Insert,
HelixNormal,
}
/// Controls when to use system clipboard.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum UseSystemClipboard {
/// Don't use system clipboard.
Never,
/// Use system clipboard.
Always,
/// Use system clipboard for yank operations.
OnYank,
}
/// The settings for cursor shape.
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct CursorShapeSettings {
/// Cursor shape for the normal mode.
///
/// Default: block
pub normal: Option<CursorShape>,
/// Cursor shape for the replace mode.
///
/// Default: underline
pub replace: Option<CursorShape>,
/// Cursor shape for the visual mode.
///
/// Default: block
pub visual: Option<CursorShape>,
/// Cursor shape for the insert mode.
///
/// The default value follows the primary cursor_shape.
pub insert: Option<CursorShape>,
}
/// Settings specific to journaling
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct JournalSettingsContent {
/// The path of the directory where journal entries are stored.
///
/// Default: `~`
pub path: Option<String>,
/// What format to display the hours in.
///
/// Default: hour12
pub hour_format: Option<HourFormat>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum HourFormat {
#[default]
Hour12,
Hour24,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct OutlinePanelSettingsContent {
/// Whether to show the outline panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Customize default width (in pixels) taken by outline panel
///
/// Default: 240
pub default_width: Option<f32>,
/// The position of outline panel
///
/// Default: left
pub dock: Option<DockSide>,
/// Whether to show file icons in the outline panel.
///
/// Default: true
pub file_icons: Option<bool>,
/// Whether to show folder icons or chevrons for directories in the outline panel.
///
/// Default: true
pub folder_icons: Option<bool>,
/// Whether to show the git status in the outline panel.
///
/// Default: true
pub git_status: Option<bool>,
/// Amount of indentation (in pixels) for nested items.
///
/// Default: 20
pub indent_size: Option<f32>,
/// Whether to reveal it in the outline panel automatically,
/// when a corresponding project entry becomes active.
/// Gitignored entries are never auto revealed.
///
/// Default: true
pub auto_reveal_entries: Option<bool>,
/// Whether to fold directories automatically
/// when directory has only one directory inside.
///
/// Default: true
pub auto_fold_dirs: Option<bool>,
/// Settings related to indent guides in the outline panel.
pub indent_guides: Option<IndentGuidesSettingsContent>,
/// Scrollbar-related settings
pub scrollbar: Option<ScrollbarSettingsContent>,
/// Default depth to expand outline items in the current file.
/// The default depth to which outline entries are expanded on reveal.
/// - Set to 0 to collapse all items that have children
/// - Set to 1 or higher to collapse items at that depth or deeper
///
/// Default: 100
pub expand_outlines_with_depth: Option<usize>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Copy, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum DockSide {
Left,
Right,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ShowIndentGuides {
Always,
Never,
}
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct IndentGuidesSettingsContent {
/// When to show the scrollbar in the outline panel.
pub show: Option<ShowIndentGuides>,
}
#[derive(Clone, Copy, Default, PartialEq, Debug, JsonSchema, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum LineIndicatorFormat {
Short,
#[default]
Long,
}
/// The settings for the image viewer.
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Default, PartialEq)]
pub struct ImageViewerSettingsContent {
/// The unit to use for displaying image file sizes.
///
/// Default: "binary"
pub unit: Option<ImageFileSizeUnit>,
}
#[skip_serializing_none]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, Default, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ImageFileSizeUnit {
/// Displays file size in binary units (e.g., KiB, MiB).
#[default]
Binary,
/// Displays file size in decimal units (e.g., KB, MB).
Decimal,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct RemoteSettingsContent {
pub ssh_connections: Option<Vec<SshConnection>>,
pub wsl_connections: Option<Vec<WslConnection>>,
pub read_ssh_config: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct SshConnection {
pub host: SharedString,
pub username: Option<String>,
pub port: Option<u16>,
#[serde(default)]
pub args: Vec<String>,
#[serde(default)]
pub projects: collections::BTreeSet<SshProject>,
/// Name to use for this server in UI.
pub nickname: Option<String>,
// By default Zed will download the binary to the host directly.
// If this is set to true, Zed will download the binary to your local machine,
// and then upload it over the SSH connection. Useful if your SSH server has
// limited outbound internet access.
pub upload_binary_over_ssh: Option<bool>,
pub port_forwards: Option<Vec<SshPortForwardOption>>,
}
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema, Debug)]
pub struct WslConnection {
pub distro_name: SharedString,
pub user: Option<String>,
#[serde(default)]
pub projects: BTreeSet<SshProject>,
}
#[skip_serializing_none]
#[derive(
Clone, Debug, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize, JsonSchema,
)]
pub struct SshProject {
pub paths: Vec<String>,
}
#[skip_serializing_none]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, JsonSchema)]
pub struct SshPortForwardOption {
#[serde(skip_serializing_if = "Option::is_none")]
pub local_host: Option<String>,
pub local_port: u16,
#[serde(skip_serializing_if = "Option::is_none")]
pub remote_host: Option<String>,
pub remote_port: u16,
}
/// Settings for configuring REPL display and behavior.
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ReplSettingsContent {
/// Maximum number of lines to keep in REPL's scrollback buffer.
/// Clamped with [4, 256] range.
///
/// Default: 32
pub max_lines: Option<usize>,
/// Maximum number of columns to keep in REPL's scrollback buffer.
/// Clamped with [20, 512] range.
///
/// Default: 128
pub max_columns: Option<usize>,
}
@@ -0,0 +1,336 @@
use collections::{HashMap, IndexMap};
use gpui::SharedString;
use schemars::{JsonSchema, json_schema};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::{borrow::Cow, path::PathBuf, sync::Arc};
use crate::DockPosition;
#[skip_serializing_none]
#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, Debug, Default)]
pub struct AgentSettingsContent {
/// Whether the Agent is enabled.
///
/// Default: true
pub enabled: Option<bool>,
/// Whether to show the agent panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Where to dock the agent panel.
///
/// Default: right
pub dock: Option<DockPosition>,
/// Default width in pixels when the agent panel is docked to the left or right.
///
/// Default: 640
pub default_width: Option<f32>,
/// Default height in pixels when the agent panel is docked to the bottom.
///
/// Default: 320
pub default_height: Option<f32>,
/// The default model to use when creating new chats and for other features when a specific model is not specified.
pub default_model: Option<LanguageModelSelection>,
/// Model to use for the inline assistant. Defaults to default_model when not specified.
pub inline_assistant_model: Option<LanguageModelSelection>,
/// Model to use for generating git commit messages. Defaults to default_model when not specified.
pub commit_message_model: Option<LanguageModelSelection>,
/// Model to use for generating thread summaries. Defaults to default_model when not specified.
pub thread_summary_model: Option<LanguageModelSelection>,
/// Additional models with which to generate alternatives when performing inline assists.
pub inline_alternatives: Option<Vec<LanguageModelSelection>>,
/// The default profile to use in the Agent.
///
/// Default: write
pub default_profile: Option<Arc<str>>,
/// Which view type to show by default in the agent panel.
///
/// Default: "thread"
pub default_view: Option<DefaultAgentView>,
/// The available agent profiles.
pub profiles: Option<IndexMap<Arc<str>, AgentProfileContent>>,
/// Whenever a tool action would normally wait for your confirmation
/// that you allow it, always choose to allow it.
///
/// This setting has no effect on external agents that support permission modes, such as Claude Code.
///
/// Set `agent_servers.claude.default_mode` to `bypassPermissions`, to disable all permission requests when using Claude Code.
///
/// Default: false
pub always_allow_tool_actions: Option<bool>,
/// Where to show a popup notification when the agent is waiting for user input.
///
/// Default: "primary_screen"
pub notify_when_agent_waiting: Option<NotifyWhenAgentWaiting>,
/// Whether to play a sound when the agent has either completed its response, or needs user input.
///
/// Default: false
pub play_sound_when_agent_done: Option<bool>,
/// Whether to stream edits from the agent as they are received.
///
/// Default: false
pub stream_edits: Option<bool>,
/// Whether to display agent edits in single-file editors in addition to the review multibuffer pane.
///
/// Default: true
pub single_file_review: Option<bool>,
/// Additional parameters for language model requests. When making a request
/// to a model, parameters will be taken from the last entry in this list
/// that matches the model's provider and name. In each entry, both provider
/// and model are optional, so that you can specify parameters for either
/// one.
///
/// Default: []
#[serde(default)]
pub model_parameters: Vec<LanguageModelParameters>,
/// What completion mode to enable for new threads
///
/// Default: normal
pub preferred_completion_mode: Option<CompletionMode>,
/// Whether to show thumb buttons for feedback in the agent panel.
///
/// Default: true
pub enable_feedback: Option<bool>,
/// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
///
/// Default: true
pub expand_edit_card: Option<bool>,
/// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
///
/// Default: true
pub expand_terminal_card: Option<bool>,
/// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
///
/// Default: false
pub use_modifier_to_send: Option<bool>,
/// Minimum number of lines of height the agent message editor should have.
///
/// Default: 4
pub message_editor_min_lines: Option<usize>,
}
impl AgentSettingsContent {
pub fn set_dock(&mut self, dock: DockPosition) {
self.dock = Some(dock);
}
pub fn set_model(&mut self, language_model: LanguageModelSelection) {
// let model = language_model.id().0.to_string();
// let provider = language_model.provider_id().0.to_string();
// self.default_model = Some(LanguageModelSelection {
// provider: provider.into(),
// model,
// });
self.default_model = Some(language_model)
}
pub fn set_inline_assistant_model(&mut self, provider: String, model: String) {
self.inline_assistant_model = Some(LanguageModelSelection {
provider: provider.into(),
model,
});
}
pub fn set_commit_message_model(&mut self, provider: String, model: String) {
self.commit_message_model = Some(LanguageModelSelection {
provider: provider.into(),
model,
});
}
pub fn set_thread_summary_model(&mut self, provider: String, model: String) {
self.thread_summary_model = Some(LanguageModelSelection {
provider: provider.into(),
model,
});
}
pub fn set_always_allow_tool_actions(&mut self, allow: bool) {
self.always_allow_tool_actions = Some(allow);
}
pub fn set_play_sound_when_agent_done(&mut self, allow: bool) {
self.play_sound_when_agent_done = Some(allow);
}
pub fn set_single_file_review(&mut self, allow: bool) {
self.single_file_review = Some(allow);
}
pub fn set_use_modifier_to_send(&mut self, always_use: bool) {
self.use_modifier_to_send = Some(always_use);
}
pub fn set_profile(&mut self, profile_id: Arc<str>) {
self.default_profile = Some(profile_id);
}
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct AgentProfileContent {
pub name: Arc<str>,
#[serde(default)]
pub tools: IndexMap<Arc<str>, bool>,
/// Whether all context servers are enabled by default.
pub enable_all_context_servers: Option<bool>,
#[serde(default)]
pub context_servers: IndexMap<Arc<str>, ContextServerPresetContent>,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ContextServerPresetContent {
pub tools: IndexMap<Arc<str>, bool>,
}
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DefaultAgentView {
#[default]
Thread,
TextThread,
}
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum NotifyWhenAgentWaiting {
#[default]
PrimaryScreen,
AllScreens,
Never,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct LanguageModelSelection {
pub provider: LanguageModelProviderSetting,
pub model: String,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
#[serde(rename_all = "snake_case")]
pub enum CompletionMode {
#[default]
Normal,
#[serde(alias = "max")]
Burn,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct LanguageModelParameters {
pub provider: Option<LanguageModelProviderSetting>,
pub model: Option<SharedString>,
pub temperature: Option<f32>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct LanguageModelProviderSetting(pub String);
impl JsonSchema for LanguageModelProviderSetting {
fn schema_name() -> Cow<'static, str> {
"LanguageModelProviderSetting".into()
}
fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
// list the builtin providers as a subset so that we still auto complete them in the settings
json_schema!({
"anyOf": [
{
"type": "string",
"enum": [
"amazon-bedrock",
"anthropic",
"copilot_chat",
"deepseek",
"google",
"lmstudio",
"mistral",
"ollama",
"openai",
"openrouter",
"vercel",
"x_ai",
"zed.dev"
]
},
{
"type": "string",
}
]
})
}
}
impl From<String> for LanguageModelProviderSetting {
fn from(provider: String) -> Self {
Self(provider)
}
}
impl From<&str> for LanguageModelProviderSetting {
fn from(provider: &str) -> Self {
Self(provider.to_string())
}
}
#[skip_serializing_none]
#[derive(Default, PartialEq, Deserialize, Serialize, Clone, JsonSchema, Debug)]
pub struct AllAgentServersSettings {
pub gemini: Option<BuiltinAgentServerSettings>,
pub claude: Option<BuiltinAgentServerSettings>,
/// Custom agent servers configured by the user
#[serde(flatten)]
pub custom: HashMap<SharedString, CustomAgentServerSettings>,
}
#[skip_serializing_none]
#[derive(Default, Deserialize, Serialize, Clone, JsonSchema, Debug, PartialEq)]
pub struct BuiltinAgentServerSettings {
/// Absolute path to a binary to be used when launching this agent.
///
/// This can be used to run a specific binary without automatic downloads or searching `$PATH`.
#[serde(rename = "command")]
pub path: Option<PathBuf>,
/// If a binary is specified in `command`, it will be passed these arguments.
pub args: Option<Vec<String>>,
/// If a binary is specified in `command`, it will be passed these environment variables.
pub env: Option<HashMap<String, String>>,
/// Whether to skip searching `$PATH` for an agent server binary when
/// launching this agent.
///
/// This has no effect if a `command` is specified. Otherwise, when this is
/// `false`, Zed will search `$PATH` for an agent server binary and, if one
/// is found, use it for threads with this agent. If no agent binary is
/// found on `$PATH`, Zed will automatically install and use its own binary.
/// When this is `true`, Zed will not search `$PATH`, and will always use
/// its own binary.
///
/// Default: true
pub ignore_system_version: Option<bool>,
/// The default mode to use for this agent.
///
/// Note: Not only all agents support modes.
///
/// Default: None
pub default_mode: Option<String>,
}
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Clone, JsonSchema, Debug, PartialEq)]
pub struct CustomAgentServerSettings {
#[serde(rename = "command")]
pub path: PathBuf,
#[serde(default)]
pub args: Vec<String>,
pub env: Option<HashMap<String, String>>,
/// The default mode to use for this agent.
///
/// Note: Not only all agents support modes.
///
/// Default: None
pub default_mode: Option<String>,
}
@@ -0,0 +1,603 @@
use std::num;
use collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::{DiagnosticSeverityContent, ShowScrollbar};
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct EditorSettingsContent {
/// Whether the cursor blinks in the editor.
///
/// Default: true
pub cursor_blink: Option<bool>,
/// Cursor shape for the default editor.
/// Can be "bar", "block", "underline", or "hollow".
///
/// Default: bar
pub cursor_shape: Option<CursorShape>,
/// Determines when the mouse cursor should be hidden in an editor or input box.
///
/// Default: on_typing_and_movement
pub hide_mouse: Option<HideMouseMode>,
/// Determines how snippets are sorted relative to other completion items.
///
/// Default: inline
pub snippet_sort_order: Option<SnippetSortOrder>,
/// How to highlight the current line in the editor.
///
/// Default: all
pub current_line_highlight: Option<CurrentLineHighlight>,
/// Whether to highlight all occurrences of the selected text in an editor.
///
/// Default: true
pub selection_highlight: Option<bool>,
/// Whether the text selection should have rounded corners.
///
/// Default: true
pub rounded_selection: Option<bool>,
/// The debounce delay before querying highlights from the language
/// server based on the current cursor location.
///
/// Default: 75
pub lsp_highlight_debounce: Option<u64>,
/// Whether to show the informational hover box when moving the mouse
/// over symbols in the editor.
///
/// Default: true
pub hover_popover_enabled: Option<bool>,
/// Time to wait in milliseconds before showing the informational hover box.
///
/// Default: 300
pub hover_popover_delay: Option<u64>,
/// Status bar related settings
pub status_bar: Option<StatusBarContent>,
/// Toolbar related settings
pub toolbar: Option<ToolbarContent>,
/// Scrollbar related settings
pub scrollbar: Option<ScrollbarContent>,
/// Minimap related settings
pub minimap: Option<MinimapContent>,
/// Gutter related settings
pub gutter: Option<GutterContent>,
/// Whether the editor will scroll beyond the last line.
///
/// Default: one_page
pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
/// The number of lines to keep above/below the cursor when auto-scrolling.
///
/// Default: 3.
pub vertical_scroll_margin: Option<f32>,
/// Whether to scroll when clicking near the edge of the visible text area.
///
/// Default: false
pub autoscroll_on_clicks: Option<bool>,
/// The number of characters to keep on either side when scrolling with the mouse.
///
/// Default: 5.
pub horizontal_scroll_margin: Option<f32>,
/// Scroll sensitivity multiplier. This multiplier is applied
/// to both the horizontal and vertical delta values while scrolling.
///
/// Default: 1.0
pub scroll_sensitivity: Option<f32>,
/// Scroll sensitivity multiplier for fast scrolling. This multiplier is applied
/// to both the horizontal and vertical delta values while scrolling. Fast scrolling
/// happens when a user holds the alt or option key while scrolling.
///
/// Default: 4.0
pub fast_scroll_sensitivity: Option<f32>,
/// Whether the line numbers on editors gutter are relative or not.
///
/// Default: false
pub relative_line_numbers: Option<bool>,
/// When to populate a new search's query based on the text under the cursor.
///
/// Default: always
pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
pub use_smartcase_search: Option<bool>,
/// Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier.
///
/// Default: alt
pub multi_cursor_modifier: Option<MultiCursorModifier>,
/// Hide the values of variables in `private` files, as defined by the
/// private_files setting. This only changes the visual representation,
/// the values are still present in the file and can be selected / copied / pasted
///
/// Default: false
pub redact_private_values: Option<bool>,
/// How many lines to expand the multibuffer excerpts by default
///
/// Default: 3
pub expand_excerpt_lines: Option<u32>,
/// How many lines of context to provide in multibuffer excerpts by default
///
/// Default: 2
pub excerpt_context_lines: Option<u32>,
/// Whether to enable middle-click paste on Linux
///
/// Default: true
pub middle_click_paste: Option<bool>,
/// What to do when multibuffer is double clicked in some of its excerpts
/// (parts of singleton buffers).
///
/// Default: select
pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
/// Whether the editor search results will loop
///
/// Default: true
pub search_wrap: Option<bool>,
/// Defaults to use when opening a new buffer and project search items.
///
/// Default: nothing is enabled
pub search: Option<SearchSettingsContent>,
/// Whether to automatically show a signature help pop-up or not.
///
/// Default: false
pub auto_signature_help: Option<bool>,
/// Whether to show the signature help pop-up after completions or bracket pairs inserted.
///
/// Default: false
pub show_signature_help_after_edits: Option<bool>,
/// The minimum APCA perceptual contrast to maintain when
/// rendering text over highlight backgrounds in the editor.
///
/// Values range from 0 to 106. Set to 0 to disable adjustments.
/// Default: 45
pub minimum_contrast_for_highlights: Option<f32>,
/// Whether to follow-up empty go to definition responses from the language server or not.
/// `FindAllReferences` allows to look up references of the same symbol instead.
/// `None` disables the fallback.
///
/// Default: FindAllReferences
pub go_to_definition_fallback: Option<GoToDefinitionFallback>,
/// Jupyter REPL settings.
pub jupyter: Option<JupyterContent>,
/// Which level to use to filter out diagnostics displayed in the editor.
///
/// Affects the editor rendering only, and does not interrupt
/// the functionality of diagnostics fetching and project diagnostics editor.
/// Which files containing diagnostic errors/warnings to mark in the tabs.
/// Diagnostics are only shown when file icons are also active.
///
/// Shows all diagnostics if not specified.
///
/// Default: warning
pub diagnostics_max_severity: Option<DiagnosticSeverityContent>,
/// Whether to show code action button at start of buffer line.
///
/// Default: true
pub inline_code_actions: Option<bool>,
/// Drag and drop related settings
pub drag_and_drop_selection: Option<DragAndDropSelectionContent>,
/// How to render LSP `textDocument/documentColor` colors in the editor.
///
/// Default: [`DocumentColorsRenderMode::Inlay`]
pub lsp_document_colors: Option<DocumentColorsRenderMode>,
}
// Status bar related settings
#[skip_serializing_none]
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct StatusBarContent {
/// Whether to display the active language button in the status bar.
///
/// Default: true
pub active_language_button: Option<bool>,
/// Whether to show the cursor position button in the status bar.
///
/// Default: true
pub cursor_position_button: Option<bool>,
}
// Toolbar related settings
#[skip_serializing_none]
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ToolbarContent {
/// Whether to display breadcrumbs in the editor toolbar.
///
/// Default: true
pub breadcrumbs: Option<bool>,
/// Whether to display quick action buttons in the editor toolbar.
///
/// Default: true
pub quick_actions: Option<bool>,
/// Whether to show the selections menu in the editor toolbar.
///
/// Default: true
pub selections_menu: Option<bool>,
/// Whether to display Agent review buttons in the editor toolbar.
/// Only applicable while reviewing a file edited by the Agent.
///
/// Default: true
pub agent_review: Option<bool>,
/// Whether to display code action buttons in the editor toolbar.
///
/// Default: false
pub code_actions: Option<bool>,
}
/// Scrollbar related settings
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
pub struct ScrollbarContent {
/// When to show the scrollbar in the editor.
///
/// Default: auto
pub show: Option<ShowScrollbar>,
/// Whether to show git diff indicators in the scrollbar.
///
/// Default: true
pub git_diff: Option<bool>,
/// Whether to show buffer search result indicators in the scrollbar.
///
/// Default: true
pub search_results: Option<bool>,
/// Whether to show selected text occurrences in the scrollbar.
///
/// Default: true
pub selected_text: Option<bool>,
/// Whether to show selected symbol occurrences in the scrollbar.
///
/// Default: true
pub selected_symbol: Option<bool>,
/// Which diagnostic indicators to show in the scrollbar:
///
/// Default: all
pub diagnostics: Option<ScrollbarDiagnostics>,
/// Whether to show cursor positions in the scrollbar.
///
/// Default: true
pub cursors: Option<bool>,
/// Forcefully enable or disable the scrollbar for each axis
pub axes: Option<ScrollbarAxesContent>,
}
/// Minimap related settings
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct MinimapContent {
/// When to show the minimap in the editor.
///
/// Default: never
pub show: Option<ShowMinimap>,
/// Where to show the minimap in the editor.
///
/// Default: [`DisplayIn::ActiveEditor`]
pub display_in: Option<DisplayIn>,
/// When to show the minimap thumb.
///
/// Default: always
pub thumb: Option<MinimapThumb>,
/// Defines the border style for the minimap's scrollbar thumb.
///
/// Default: left_open
pub thumb_border: Option<MinimapThumbBorder>,
/// How to highlight the current line in the minimap.
///
/// Default: inherits editor line highlights setting
pub current_line_highlight: Option<Option<CurrentLineHighlight>>,
/// Maximum number of columns to display in the minimap.
///
/// Default: 80
pub max_width_columns: Option<num::NonZeroU32>,
}
/// Forcefully enable or disable the scrollbar for each axis
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
pub struct ScrollbarAxesContent {
/// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
///
/// Default: true
pub horizontal: Option<bool>,
/// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
///
/// Default: true
pub vertical: Option<bool>,
}
/// Gutter related settings
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct GutterContent {
/// Whether to show line numbers in the gutter.
///
/// Default: true
pub line_numbers: Option<bool>,
/// Minimum number of characters to reserve space for in the gutter.
///
/// Default: 4
pub min_line_number_digits: Option<usize>,
/// Whether to show runnable buttons in the gutter.
///
/// Default: true
pub runnables: Option<bool>,
/// Whether to show breakpoints in the gutter.
///
/// Default: true
pub breakpoints: Option<bool>,
/// Whether to show fold buttons in the gutter.
///
/// Default: true
pub folds: Option<bool>,
}
/// How to render LSP `textDocument/documentColor` colors in the editor.
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DocumentColorsRenderMode {
/// Do not query and render document colors.
None,
/// Render document colors as inlay hints near the color text.
#[default]
Inlay,
/// Draw a border around the color text.
Border,
/// Draw a background behind the color text.
Background,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CurrentLineHighlight {
// Don't highlight the current line.
None,
// Highlight the gutter area.
Gutter,
// Highlight the editor area.
Line,
// Highlight the full line.
All,
}
/// When to populate a new search's query based on the text under the cursor.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SeedQuerySetting {
/// Always populate the search query with the word under the cursor.
Always,
/// Only populate the search query when there is text selected.
Selection,
/// Never populate the search query
Never,
}
/// What to do when multibuffer is double clicked in some of its excerpts (parts of singleton buffers).
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DoubleClickInMultibuffer {
/// Behave as a regular buffer and select the whole word.
#[default]
Select,
/// Open the excerpt clicked as a new buffer in the new tab, if no `alt` modifier was pressed during double click.
/// Otherwise, behave as a regular buffer and select the whole word.
Open,
}
/// When to show the minimap thumb.
///
/// Default: always
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MinimapThumb {
/// Show the minimap thumb only when the mouse is hovering over the minimap.
Hover,
/// Always show the minimap thumb.
#[default]
Always,
}
/// Defines the border style for the minimap's scrollbar thumb.
///
/// Default: left_open
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MinimapThumbBorder {
/// Displays a border on all sides of the thumb.
Full,
/// Displays a border on all sides except the left side of the thumb.
#[default]
LeftOpen,
/// Displays a border on all sides except the right side of the thumb.
RightOpen,
/// Displays a border only on the left side of the thumb.
LeftOnly,
/// Displays the thumb without any border.
None,
}
/// Which diagnostic indicators to show in the scrollbar.
///
/// Default: all
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ScrollbarDiagnostics {
/// Show all diagnostic levels: hint, information, warnings, error.
All,
/// Show only the following diagnostic levels: information, warning, error.
Information,
/// Show only the following diagnostic levels: warning, error.
Warning,
/// Show only the following diagnostic level: error.
Error,
/// Do not show diagnostics.
None,
}
/// The key to use for adding multiple cursors
///
/// Default: alt
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MultiCursorModifier {
Alt,
#[serde(alias = "cmd", alias = "ctrl")]
CmdOrCtrl,
}
/// Whether the editor will scroll beyond the last line.
///
/// Default: one_page
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ScrollBeyondLastLine {
/// The editor will not scroll beyond the last line.
Off,
/// The editor will scroll beyond the last line by one page.
OnePage,
/// The editor will scroll beyond the last line by the same number of lines as vertical_scroll_margin.
VerticalScrollMargin,
}
/// The shape of a selection cursor.
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CursorShape {
/// A vertical bar
#[default]
Bar,
/// A block that surrounds the following character
Block,
/// An underline that runs along the following character
Underline,
/// A box drawn around the following character
Hollow,
}
/// What to do when go to definition yields no results.
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GoToDefinitionFallback {
/// Disables the fallback.
None,
/// Looks up references of the same symbol instead.
#[default]
FindAllReferences,
}
/// Determines when the mouse cursor should be hidden in an editor or input box.
///
/// Default: on_typing_and_movement
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum HideMouseMode {
/// Never hide the mouse cursor
Never,
/// Hide only when typing
OnTyping,
/// Hide on both typing and cursor movement
#[default]
OnTypingAndMovement,
}
/// Determines how snippets are sorted relative to other completion items.
///
/// Default: inline
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SnippetSortOrder {
/// Place snippets at the top of the completion list
Top,
/// Sort snippets normally using the default comparison logic
#[default]
Inline,
/// Place snippets at the bottom of the completion list
Bottom,
/// Do not show snippets in the completion list
None,
}
/// Default options for buffer and project search items.
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct SearchSettingsContent {
/// Whether to show the project search button in the status bar.
pub button: Option<bool>,
pub whole_word: Option<bool>,
pub case_sensitive: Option<bool>,
pub include_ignored: Option<bool>,
pub regex: Option<bool>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct JupyterContent {
/// Whether the Jupyter feature is enabled.
///
/// Default: true
pub enabled: Option<bool>,
/// Default kernels to select for each language.
///
/// Default: `{}`
pub kernel_selections: Option<HashMap<String, String>>,
}
/// Whether to allow drag and drop text selection in buffer.
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct DragAndDropSelectionContent {
/// When true, enables drag and drop text selection in buffer.
///
/// Default: true
pub enabled: Option<bool>,
/// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
///
/// Default: 300
pub delay: Option<u64>,
}
/// When to show the minimap in the editor.
///
/// Default: never
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ShowMinimap {
/// Follow the visibility of the scrollbar.
Auto,
/// Always show the minimap.
Always,
/// Never show the minimap.
#[default]
Never,
}
/// Where to show the minimap in the editor.
///
/// Default: all_editors
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DisplayIn {
/// Show on all open editors.
AllEditors,
/// Show the minimap on the active editor only.
#[default]
ActiveEditor,
}
@@ -0,0 +1,894 @@
use std::{borrow::Cow, num::NonZeroU32};
use collections::{HashMap, HashSet};
use gpui::{Modifiers, SharedString};
use schemars::{JsonSchema, json_schema};
use serde::{
Deserialize, Deserializer, Serialize,
de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor},
};
use serde_with::skip_serializing_none;
use std::sync::Arc;
use util::schemars::replace_subschema;
use crate::ParameterizedJsonSchema;
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AllLanguageSettingsContent {
/// The settings for enabling/disabling features.
#[serde(default)]
pub features: Option<FeaturesContent>,
/// The edit prediction settings.
#[serde(default)]
pub edit_predictions: Option<EditPredictionSettingsContent>,
/// The default language settings.
#[serde(flatten)]
pub defaults: LanguageSettingsContent,
/// The settings for individual languages.
#[serde(default)]
pub languages: LanguageToSettingsMap,
/// Settings for associating file extensions and filenames
/// with languages.
#[serde(default)]
pub file_types: HashMap<Arc<str>, Vec<String>>,
}
/// The settings for enabling/disabling features.
#[skip_serializing_none]
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct FeaturesContent {
/// Determines which edit prediction provider to use.
pub edit_prediction_provider: Option<EditPredictionProvider>,
}
/// The provider that supplies edit predictions.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum EditPredictionProvider {
None,
#[default]
Copilot,
Supermaven,
Zed,
}
/// The contents of the edit prediction settings.
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct EditPredictionSettingsContent {
/// A list of globs representing files that edit predictions should be disabled for.
/// This list adds to a pre-existing, sensible default set of globs.
/// Any additional ones you add are combined with them.
pub disabled_globs: Option<Vec<String>>,
/// The mode used to display edit predictions in the buffer.
/// Provider support required.
pub mode: Option<EditPredictionsMode>,
/// Settings specific to GitHub Copilot.
pub copilot: Option<CopilotSettingsContent>,
/// Whether edit predictions are enabled in the assistant prompt editor.
/// This has no effect if globally disabled.
pub enabled_in_text_threads: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct CopilotSettingsContent {
/// HTTP/HTTPS proxy to use for Copilot.
///
/// Default: none
pub proxy: Option<String>,
/// Disable certificate verification for the proxy (not recommended).
///
/// Default: false
pub proxy_no_verify: Option<bool>,
/// Enterprise URI for Copilot.
///
/// Default: none
pub enterprise_uri: Option<String>,
}
/// The mode in which edit predictions should be displayed.
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum EditPredictionsMode {
/// If provider supports it, display inline when holding modifier key (e.g., alt).
/// Otherwise, eager preview is used.
#[serde(alias = "auto")]
Subtle,
/// Display inline when there are no language server completions available.
#[default]
#[serde(alias = "eager_preview")]
Eager,
}
/// Controls the soft-wrapping behavior in the editor.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum SoftWrap {
/// Prefer a single line generally, unless an overly long line is encountered.
None,
/// Deprecated: use None instead. Left to avoid breaking existing users' configs.
/// Prefer a single line generally, unless an overly long line is encountered.
PreferLine,
/// Soft wrap lines that exceed the editor width.
EditorWidth,
/// Soft wrap lines at the preferred line length.
PreferredLineLength,
/// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
Bounded,
}
/// The settings for a particular language.
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LanguageSettingsContent {
/// How many columns a tab should occupy.
///
/// Default: 4
pub tab_size: Option<NonZeroU32>,
/// Whether to indent lines using tab characters, as opposed to multiple
/// spaces.
///
/// Default: false
pub hard_tabs: Option<bool>,
/// How to soft-wrap long lines of text.
///
/// Default: none
pub soft_wrap: Option<SoftWrap>,
/// The column at which to soft-wrap lines, for buffers where soft-wrap
/// is enabled.
///
/// Default: 80
pub preferred_line_length: Option<u32>,
/// Whether to show wrap guides in the editor. Setting this to true will
/// show a guide at the 'preferred_line_length' value if softwrap is set to
/// 'preferred_line_length', and will show any additional guides as specified
/// by the 'wrap_guides' setting.
///
/// Default: true
pub show_wrap_guides: Option<bool>,
/// Character counts at which to show wrap guides in the editor.
///
/// Default: []
pub wrap_guides: Option<Vec<usize>>,
/// Indent guide related settings.
pub indent_guides: Option<IndentGuideSettingsContent>,
/// Whether or not to perform a buffer format before saving.
///
/// Default: on
pub format_on_save: Option<FormatOnSave>,
/// Whether or not to remove any trailing whitespace from lines of a buffer
/// before saving it.
///
/// Default: true
pub remove_trailing_whitespace_on_save: Option<bool>,
/// Whether or not to ensure there's a single newline at the end of a buffer
/// when saving it.
///
/// Default: true
pub ensure_final_newline_on_save: Option<bool>,
/// How to perform a buffer format.
///
/// Default: auto
pub formatter: Option<SelectedFormatter>,
/// Zed's Prettier integration settings.
/// Allows to enable/disable formatting with Prettier
/// and configure default Prettier, used when no project-level Prettier installation is found.
///
/// Default: off
pub prettier: Option<PrettierSettingsContent>,
/// Whether to automatically close JSX tags.
pub jsx_tag_auto_close: Option<JsxTagAutoCloseSettingsContent>,
/// Whether to use language servers to provide code intelligence.
///
/// Default: true
pub enable_language_server: Option<bool>,
/// The list of language servers to use (or disable) for this language.
///
/// This array should consist of language server IDs, as well as the following
/// special tokens:
/// - `"!<language_server_id>"` - A language server ID prefixed with a `!` will be disabled.
/// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language.
///
/// Default: ["..."]
pub language_servers: Option<Vec<String>>,
/// Controls where the `editor::Rewrap` action is allowed for this language.
///
/// Note: This setting has no effect in Vim mode, as rewrap is already
/// allowed everywhere.
///
/// Default: "in_comments"
pub allow_rewrap: Option<RewrapBehavior>,
/// Controls whether edit predictions are shown immediately (true)
/// or manually by triggering `editor::ShowEditPrediction` (false).
///
/// Default: true
pub show_edit_predictions: Option<bool>,
/// Controls whether edit predictions are shown in the given language
/// scopes.
///
/// Example: ["string", "comment"]
///
/// Default: []
pub edit_predictions_disabled_in: Option<Vec<String>>,
/// Whether to show tabs and spaces in the editor.
pub show_whitespaces: Option<ShowWhitespaceSetting>,
/// Visible characters used to render whitespace when show_whitespaces is enabled.
///
/// Default: "•" for spaces, "→" for tabs.
pub whitespace_map: Option<WhitespaceMap>,
/// Whether to start a new line with a comment when a previous line is a comment as well.
///
/// Default: true
pub extend_comment_on_newline: Option<bool>,
/// Inlay hint related settings.
pub inlay_hints: Option<InlayHintSettingsContent>,
/// Whether to automatically type closing characters for you. For example,
/// when you type (, Zed will automatically add a closing ) at the correct position.
///
/// Default: true
pub use_autoclose: Option<bool>,
/// Whether to automatically surround text with characters for you. For example,
/// when you select text and type (, Zed will automatically surround text with ().
///
/// Default: true
pub use_auto_surround: Option<bool>,
/// Controls how the editor handles the autoclosed characters.
/// When set to `false`(default), skipping over and auto-removing of the closing characters
/// happen only for auto-inserted characters.
/// Otherwise(when `true`), the closing characters are always skipped over and auto-removed
/// no matter how they were inserted.
///
/// Default: false
pub always_treat_brackets_as_autoclosed: Option<bool>,
/// Whether to use additional LSP queries to format (and amend) the code after
/// every "trigger" symbol input, defined by LSP server capabilities.
///
/// Default: true
pub use_on_type_format: Option<bool>,
/// Which code actions to run on save after the formatter.
/// These are not run if formatting is off.
///
/// Default: {} (or {"source.organizeImports": true} for Go).
pub code_actions_on_format: Option<HashMap<String, bool>>,
/// Whether to perform linked edits of associated ranges, if the language server supports it.
/// For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well.
///
/// Default: true
pub linked_edits: Option<bool>,
/// Whether indentation should be adjusted based on the context whilst typing.
///
/// Default: true
pub auto_indent: Option<bool>,
/// Whether indentation of pasted content should be adjusted based on the context.
///
/// Default: true
pub auto_indent_on_paste: Option<bool>,
/// Task configuration for this language.
///
/// Default: {}
pub tasks: Option<LanguageTaskSettingsContent>,
/// Whether to pop the completions menu while typing in an editor without
/// explicitly requesting it.
///
/// Default: true
pub show_completions_on_input: Option<bool>,
/// Whether to display inline and alongside documentation for items in the
/// completions menu.
///
/// Default: true
pub show_completion_documentation: Option<bool>,
/// Controls how completions are processed for this language.
pub completions: Option<CompletionSettingsContent>,
/// Preferred debuggers for this language.
///
/// Default: []
pub debuggers: Option<Vec<String>>,
}
/// Controls how whitespace should be displayedin the editor.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ShowWhitespaceSetting {
/// Draw whitespace only for the selected text.
Selection,
/// Do not draw any tabs or spaces.
None,
/// Draw all invisible symbols.
All,
/// Draw whitespaces at boundaries only.
///
/// For a whitespace to be on a boundary, any of the following conditions need to be met:
/// - It is a tab
/// - It is adjacent to an edge (start or end)
/// - It is adjacent to a whitespace (left or right)
Boundary,
/// Draw whitespaces only after non-whitespace characters.
Trailing,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
pub struct WhitespaceMap {
pub space: Option<String>,
pub tab: Option<String>,
}
impl WhitespaceMap {
pub fn space(&self) -> SharedString {
self.space
.as_ref()
.map_or_else(|| SharedString::from("•"), |s| SharedString::from(s))
}
pub fn tab(&self) -> SharedString {
self.tab
.as_ref()
.map_or_else(|| SharedString::from("→"), |s| SharedString::from(s))
}
}
/// The behavior of `editor::Rewrap`.
#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum RewrapBehavior {
/// Only rewrap within comments.
#[default]
InComments,
/// Only rewrap within the current selection(s).
InSelections,
/// Allow rewrapping anywhere.
Anywhere,
}
#[skip_serializing_none]
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct JsxTagAutoCloseSettingsContent {
/// Enables or disables auto-closing of JSX tags.
pub enabled: Option<bool>,
}
/// The settings for inlay hints.
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct InlayHintSettingsContent {
/// Global switch to toggle hints on and off.
///
/// Default: false
pub enabled: Option<bool>,
/// Global switch to toggle inline values on and off when debugging.
///
/// Default: true
pub show_value_hints: Option<bool>,
/// Whether type hints should be shown.
///
/// Default: true
pub show_type_hints: Option<bool>,
/// Whether parameter hints should be shown.
///
/// Default: true
pub show_parameter_hints: Option<bool>,
/// Whether other hints should be shown.
///
/// Default: true
pub show_other_hints: Option<bool>,
/// Whether to show a background for inlay hints.
///
/// If set to `true`, the background will use the `hint.background` color
/// from the current theme.
///
/// Default: false
pub show_background: Option<bool>,
/// Whether or not to debounce inlay hints updates after buffer edits.
///
/// Set to 0 to disable debouncing.
///
/// Default: 700
pub edit_debounce_ms: Option<u64>,
/// Whether or not to debounce inlay hints updates after buffer scrolls.
///
/// Set to 0 to disable debouncing.
///
/// Default: 50
pub scroll_debounce_ms: Option<u64>,
/// Toggles inlay hints (hides or shows) when the user presses the modifiers specified.
/// If only a subset of the modifiers specified is pressed, hints are not toggled.
/// If no modifiers are specified, this is equivalent to `null`.
///
/// Default: null
pub toggle_on_modifiers_press: Option<Modifiers>,
}
/// The kind of an inlay hint.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InlayHintKind {
/// An inlay hint for a type.
Type,
/// An inlay hint for a parameter.
Parameter,
}
impl InlayHintKind {
/// Returns the [`InlayHintKind`]fromthe given name.
///
/// Returns `None` if `name` does not match any of the expected
/// string representations.
pub fn from_name(name: &str) -> Option<Self> {
match name {
"type" => Some(InlayHintKind::Type),
"parameter" => Some(InlayHintKind::Parameter),
_ => None,
}
}
/// Returns the name of this [`InlayHintKind`].
pub fn name(&self) -> &'static str {
match self {
InlayHintKind::Type => "type",
InlayHintKind::Parameter => "parameter",
}
}
}
/// Controls how completions are processed for this language.
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
pub struct CompletionSettingsContent {
/// Controls how words are completed.
/// For large documents, not all words may be fetched for completion.
///
/// Default: `fallback`
pub words: Option<WordsCompletionMode>,
/// How many characters has to be in the completions query to automatically show the words-based completions.
/// Before that value, it's still possible to trigger the words-based completion manually with the corresponding editor command.
///
/// Default: 3
pub words_min_length: Option<usize>,
/// Whether to fetch LSP completions or not.
///
/// Default: true
pub lsp: Option<bool>,
/// When fetching LSP completions, determines how long to wait for a response of a particular server.
/// When set to 0, waits indefinitely.
///
/// Default: 0
pub lsp_fetch_timeout_ms: Option<u64>,
/// Controls how LSP completions are inserted.
///
/// Default: "replace_suffix"
pub lsp_insert_mode: Option<LspInsertMode>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum LspInsertMode {
/// Replaces text before the cursor, using the `insert` range described in the LSP specification.
Insert,
/// Replaces text before and after the cursor, using the `replace` range described in the LSP specification.
Replace,
/// Behaves like `"replace"` if the text that would be replaced is a subsequence of the completion text,
/// and like `"insert"` otherwise.
ReplaceSubsequence,
/// Behaves like `"replace"` if the text after the cursor is a suffix of the completion, and like
/// `"insert"` otherwise.
ReplaceSuffix,
}
/// Controls how document's words are completed.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WordsCompletionMode {
/// Always fetch document's words for completions along with LSP completions.
Enabled,
/// Only if LSP response errors or times out,
/// use document's words to show completions.
Fallback,
/// Never fetch or complete document's words for completions.
/// (Word-based completions can still be queried via a separate action)
Disabled,
}
/// Allows to enable/disable formatting with Prettier
/// and configure default Prettier, used when no project-level Prettier installation is found.
/// Prettier formatting is disabled by default.
#[skip_serializing_none]
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct PrettierSettingsContent {
/// Enables or disables formatting with Prettier for a given language.
pub allowed: Option<bool>,
/// Forces Prettier integration to use a specific parser name when formatting files with the language.
pub parser: Option<String>,
/// Forces Prettier integration to use specific plugins when formatting files with the language.
/// The default Prettier will be installed with these plugins.
#[serde(default)]
pub plugins: HashSet<String>,
/// Default Prettier options, in the format as in package.json section for Prettier.
/// If project installs Prettier via its package.json, these options will be ignored.
#[serde(flatten)]
pub options: HashMap<String, serde_json::Value>,
}
/// Controls the behavior of formatting files when they are saved.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FormatOnSave {
/// Files should be formatted on save.
On,
/// Files should not be formatted on save.
Off,
List(FormatterList),
}
impl JsonSchema for FormatOnSave {
fn schema_name() -> Cow<'static, str> {
"OnSaveFormatter".into()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let formatter_schema = Formatter::json_schema(generator);
json_schema!({
"oneOf": [
{
"type": "array",
"items": formatter_schema
},
{
"type": "string",
"enum": ["on", "off", "language_server"]
},
formatter_schema
]
})
}
}
impl Serialize for FormatOnSave {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Self::On => serializer.serialize_str("on"),
Self::Off => serializer.serialize_str("off"),
Self::List(list) => list.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for FormatOnSave {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FormatDeserializer;
impl<'d> Visitor<'d> for FormatDeserializer {
type Value = FormatOnSave;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid on-save formatter kind")
}
fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
where
E: serde::de::Error,
{
if v == "on" {
Ok(Self::Value::On)
} else if v == "off" {
Ok(Self::Value::Off)
} else if v == "language_server" {
Ok(Self::Value::List(FormatterList::Single(
Formatter::LanguageServer { name: None },
)))
} else {
let ret: Result<FormatterList, _> =
Deserialize::deserialize(v.into_deserializer());
ret.map(Self::Value::List)
}
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'d>,
{
let ret: Result<FormatterList, _> =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
ret.map(Self::Value::List)
}
fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'d>,
{
let ret: Result<FormatterList, _> =
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
ret.map(Self::Value::List)
}
}
deserializer.deserialize_any(FormatDeserializer)
}
}
/// Controls which formatter should be used when formatting code.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum SelectedFormatter {
/// Format files using Zed's Prettier integration (if applicable),
/// or falling back to formatting via language server.
#[default]
Auto,
List(FormatterList),
}
impl JsonSchema for SelectedFormatter {
fn schema_name() -> Cow<'static, str> {
"Formatter".into()
}
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let formatter_schema = Formatter::json_schema(generator);
json_schema!({
"oneOf": [
{
"type": "array",
"items": formatter_schema
},
{
"type": "string",
"enum": ["auto", "language_server"]
},
formatter_schema
]
})
}
}
impl Serialize for SelectedFormatter {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
SelectedFormatter::Auto => serializer.serialize_str("auto"),
SelectedFormatter::List(list) => list.serialize(serializer),
}
}
}
impl<'de> Deserialize<'de> for SelectedFormatter {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FormatDeserializer;
impl<'d> Visitor<'d> for FormatDeserializer {
type Value = SelectedFormatter;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid formatter kind")
}
fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
where
E: serde::de::Error,
{
if v == "auto" {
Ok(Self::Value::Auto)
} else if v == "language_server" {
Ok(Self::Value::List(FormatterList::Single(
Formatter::LanguageServer { name: None },
)))
} else {
let ret: Result<FormatterList, _> =
Deserialize::deserialize(v.into_deserializer());
ret.map(SelectedFormatter::List)
}
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'d>,
{
let ret: Result<FormatterList, _> =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
ret.map(SelectedFormatter::List)
}
fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'d>,
{
let ret: Result<FormatterList, _> =
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
ret.map(SelectedFormatter::List)
}
}
deserializer.deserialize_any(FormatDeserializer)
}
}
/// Controls which formatters should be used when formatting code.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(untagged)]
pub enum FormatterList {
Single(Formatter),
Vec(Vec<Formatter>),
}
impl Default for FormatterList {
fn default() -> Self {
Self::Single(Formatter::default())
}
}
impl AsRef<[Formatter]> for FormatterList {
fn as_ref(&self) -> &[Formatter] {
match &self {
Self::Single(single) => std::slice::from_ref(single),
Self::Vec(v) => v,
}
}
}
/// Controls which formatter should be used when formatting code. If there are multiple formatters, they are executed in the order of declaration.
#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Formatter {
/// Format code using the current language server.
LanguageServer { name: Option<String> },
/// Format code using Zed's Prettier integration.
#[default]
Prettier,
/// Format code using an external command.
External {
/// The external program to run.
command: Arc<str>,
/// The arguments to pass to the program.
arguments: Option<Arc<[String]>>,
},
/// Files should be formatted using code actions executed by language servers.
CodeActions(HashMap<String, bool>),
}
/// The settings for indent guides.
#[skip_serializing_none]
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct IndentGuideSettingsContent {
/// Whether to display indent guides in the editor.
///
/// Default: true
pub enabled: Option<bool>,
/// The width of the indent guides in pixels, between 1 and 10.
///
/// Default: 1
pub line_width: Option<u32>,
/// The width of the active indent guide in pixels, between 1 and 10.
///
/// Default: 1
pub active_line_width: Option<u32>,
/// Determines how indent guides are colored.
///
/// Default: Fixed
pub coloring: Option<IndentGuideColoring>,
/// Determines how indent guide backgrounds are colored.
///
/// Default: Disabled
pub background_coloring: Option<IndentGuideBackgroundColoring>,
}
/// The task settings for a particular language.
#[skip_serializing_none]
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct LanguageTaskSettingsContent {
/// Extra task variables to set for a particular language.
#[serde(default)]
pub variables: HashMap<String, String>,
pub enabled: Option<bool>,
/// Use LSP tasks over Zed language extension ones.
/// If no LSP tasks are returned due to error/timeout or regular execution,
/// Zed language extension tasks will be used instead.
///
/// Other Zed tasks will still be shown:
/// * Zed task from either of the task config file
/// * Zed task from history (e.g. one-off task was spawned before)
pub prefer_lsp: Option<bool>,
}
/// Map from language name to settings. Its `ParameterizedJsonSchema` allows only known language
/// names in the keys.
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LanguageToSettingsMap(pub HashMap<SharedString, LanguageSettingsContent>);
inventory::submit! {
ParameterizedJsonSchema {
add_and_get_ref: |generator, params, _cx| {
let language_settings_content_ref = generator
.subschema_for::<LanguageSettingsContent>()
.to_value();
replace_subschema::<LanguageToSettingsMap>(generator, || json_schema!({
"type": "object",
"properties": params
.language_names
.iter()
.map(|name| {
(
name.clone(),
language_settings_content_ref.clone(),
)
})
.collect::<serde_json::Map<_, _>>()
}))
}
}
}
/// Determines how indent guides are colored.
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IndentGuideColoring {
/// Do not render any lines for indent guides.
Disabled,
/// Use the same color for all indentation levels.
#[default]
Fixed,
/// Use a different color for each indentation level.
IndentAware,
}
/// Determines how indent guide backgrounds are colored.
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IndentGuideBackgroundColoring {
/// Do not render any background for indent guides.
#[default]
Disabled,
/// Use a different color for each indentation level.
IndentAware,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_formatter_deserialization() {
let raw_auto = "{\"formatter\": \"auto\"}";
let settings: LanguageSettingsContent = serde_json::from_str(raw_auto).unwrap();
assert_eq!(settings.formatter, Some(SelectedFormatter::Auto));
let raw = "{\"formatter\": \"language_server\"}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
Some(SelectedFormatter::List(FormatterList::Single(
Formatter::LanguageServer { name: None }
)))
);
let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}]}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
Some(SelectedFormatter::List(FormatterList::Vec(vec![
Formatter::LanguageServer { name: None }
])))
);
let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"prettier\"]}";
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
assert_eq!(
settings.formatter,
Some(SelectedFormatter::List(FormatterList::Vec(vec![
Formatter::LanguageServer { name: None },
Formatter::Prettier
])))
);
}
#[test]
fn test_formatter_deserialization_invalid() {
let raw_auto = "{\"formatter\": {}}";
let result: Result<LanguageSettingsContent, _> = serde_json::from_str(raw_auto);
assert!(result.is_err());
}
}
@@ -0,0 +1,419 @@
use collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::sync::Arc;
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct AllLanguageModelSettingsContent {
pub anthropic: Option<AnthropicSettingsContent>,
pub bedrock: Option<AmazonBedrockSettingsContent>,
pub deepseek: Option<DeepseekSettingsContent>,
pub google: Option<GoogleSettingsContent>,
pub lmstudio: Option<LmStudioSettingsContent>,
pub mistral: Option<MistralSettingsContent>,
pub ollama: Option<OllamaSettingsContent>,
pub open_router: Option<OpenRouterSettingsContent>,
pub openai: Option<OpenAiSettingsContent>,
pub openai_compatible: Option<HashMap<Arc<str>, OpenAiCompatibleSettingsContent>>,
pub vercel: Option<VercelSettingsContent>,
pub x_ai: Option<XAiSettingsContent>,
#[serde(rename = "zed.dev")]
pub zed_dot_dev: Option<ZedDotDevSettingsContent>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct AnthropicSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<AnthropicAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AnthropicAvailableModel {
/// The model's name in the Anthropic API. e.g. claude-3-5-sonnet-latest, claude-3-opus-20240229, etc
pub name: String,
/// The model's name in Zed's UI, such as in the model selector dropdown menu in the assistant panel.
pub display_name: Option<String>,
/// The model's context window size.
pub max_tokens: u64,
/// A model `name` to substitute when calling tools, in case the primary model doesn't support tool calling.
pub tool_override: Option<String>,
/// Configuration of Anthropic's caching API.
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
pub max_output_tokens: Option<u64>,
pub default_temperature: Option<f32>,
#[serde(default)]
pub extra_beta_headers: Vec<String>,
/// The model's mode (e.g. thinking)
pub mode: Option<ModelMode>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct AmazonBedrockSettingsContent {
pub available_models: Option<Vec<BedrockAvailableModel>>,
pub endpoint_url: Option<String>,
pub region: Option<String>,
pub profile: Option<String>,
pub authentication_method: Option<BedrockAuthMethodContent>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct BedrockAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
pub max_output_tokens: Option<u64>,
pub default_temperature: Option<f32>,
pub mode: Option<ModelMode>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub enum BedrockAuthMethodContent {
#[serde(rename = "named_profile")]
NamedProfile,
#[serde(rename = "sso")]
SingleSignOn,
/// IMDSv2, PodIdentity, env vars, etc.
#[serde(rename = "default")]
Automatic,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct OllamaSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<OllamaAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OllamaAvailableModel {
/// The model name in the Ollama API (e.g. "llama3.2:latest")
pub name: String,
/// The model's name in Zed's UI, such as in the model selector dropdown menu in the assistant panel.
pub display_name: Option<String>,
/// The Context Length parameter to the model (aka num_ctx or n_ctx)
pub max_tokens: u64,
/// The number of seconds to keep the connection open after the last request
pub keep_alive: Option<KeepAlive>,
/// Whether the model supports tools
pub supports_tools: Option<bool>,
/// Whether the model supports vision
pub supports_images: Option<bool>,
/// Whether to enable think mode
pub supports_thinking: Option<bool>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, JsonSchema)]
#[serde(untagged)]
pub enum KeepAlive {
/// Keep model alive for N seconds
Seconds(isize),
/// Keep model alive for a fixed duration. Accepts durations like "5m", "10m", "1h", "1d", etc.
Duration(String),
}
impl KeepAlive {
/// Keep model alive until a new model is loaded or until Ollama shuts down
pub fn indefinite() -> Self {
Self::Seconds(-1)
}
}
impl Default for KeepAlive {
fn default() -> Self {
Self::indefinite()
}
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct LmStudioSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<LmStudioAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LmStudioAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub supports_tool_calls: bool,
pub supports_images: bool,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct DeepseekSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<DeepseekAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct DeepseekAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct MistralSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<MistralAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct MistralAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
pub supports_tools: Option<bool>,
pub supports_images: Option<bool>,
pub supports_thinking: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct OpenAiSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<OpenAiAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OpenAiAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
pub reasoning_effort: Option<OpenAiReasoningEffort>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum OpenAiReasoningEffort {
Minimal,
Low,
Medium,
High,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct OpenAiCompatibleSettingsContent {
pub api_url: String,
pub available_models: Vec<OpenAiCompatibleAvailableModel>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OpenAiCompatibleAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
#[serde(default)]
pub capabilities: OpenAiCompatibleModelCapabilities,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OpenAiCompatibleModelCapabilities {
pub tools: bool,
pub images: bool,
pub parallel_tool_calls: bool,
pub prompt_cache_key: bool,
}
impl Default for OpenAiCompatibleModelCapabilities {
fn default() -> Self {
Self {
tools: true,
images: false,
parallel_tool_calls: false,
prompt_cache_key: false,
}
}
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct VercelSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<VercelAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct VercelAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct GoogleSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<GoogleAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct GoogleAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub mode: Option<ModelMode>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct XAiSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<XaiAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct XaiAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct ZedDotDevSettingsContent {
pub available_models: Option<Vec<ZedDotDevAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ZedDotDevAvailableModel {
/// The provider of the language model.
pub provider: ZedDotDevAvailableProvider,
/// The model's name in the provider's API. e.g. claude-3-5-sonnet-20240620
pub name: String,
/// The name displayed in the UI, such as in the assistant panel model dropdown menu.
pub display_name: Option<String>,
/// The size of the context window, indicating the maximum number of tokens the model can process.
pub max_tokens: usize,
/// The maximum number of output tokens allowed by the model.
pub max_output_tokens: Option<u64>,
/// The maximum number of completion tokens allowed by the model (o1-* only)
pub max_completion_tokens: Option<u64>,
/// Override this model with a different Anthropic model for tool calls.
pub tool_override: Option<String>,
/// Indicates whether this custom model supports caching.
pub cache_configuration: Option<LanguageModelCacheConfiguration>,
/// The default temperature to use for this model.
pub default_temperature: Option<f32>,
/// Any extra beta headers to provide when using the model.
#[serde(default)]
pub extra_beta_headers: Vec<String>,
/// The model's mode (e.g. thinking)
pub mode: Option<ModelMode>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ZedDotDevAvailableProvider {
Anthropic,
OpenAi,
Google,
}
#[skip_serializing_none]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)]
pub struct OpenRouterSettingsContent {
pub api_url: Option<String>,
pub available_models: Option<Vec<OpenRouterAvailableModel>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OpenRouterAvailableModel {
pub name: String,
pub display_name: Option<String>,
pub max_tokens: u64,
pub max_output_tokens: Option<u64>,
pub max_completion_tokens: Option<u64>,
pub supports_tools: Option<bool>,
pub supports_images: Option<bool>,
pub mode: Option<ModelMode>,
pub provider: Option<OpenRouterProvider>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct OpenRouterProvider {
order: Option<Vec<String>>,
#[serde(default = "default_true")]
allow_fallbacks: bool,
#[serde(default)]
require_parameters: bool,
#[serde(default)]
data_collection: DataCollection,
only: Option<Vec<String>>,
ignore: Option<Vec<String>>,
quantizations: Option<Vec<String>>,
sort: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum DataCollection {
Allow,
Disallow,
}
impl Default for DataCollection {
fn default() -> Self {
Self::Allow
}
}
fn default_true() -> bool {
true
}
/// Configuration for caching language model messages.
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LanguageModelCacheConfiguration {
pub max_cache_anchors: usize,
pub should_speculate: bool,
pub min_total_token: u64,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum ModelMode {
#[default]
Default,
Thinking {
/// The maximum number of tokens to use for reasoning. Must be lower than the model's `max_output_tokens`.
budget_tokens: Option<u32>,
},
}
@@ -0,0 +1,435 @@
use std::{path::PathBuf, sync::Arc};
use collections::{BTreeMap, HashMap};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use util::serde::default_true;
use crate::{AllLanguageSettingsContent, SlashCommandSettings};
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ProjectSettingsContent {
#[serde(flatten)]
pub all_languages: AllLanguageSettingsContent,
#[serde(flatten)]
pub worktree: WorktreeSettingsContent,
/// Configuration for language servers.
///
/// The following settings can be overridden for specific language servers:
/// - initialization_options
///
/// To override settings for a language, add an entry for that language server's
/// name to the lsp value.
/// Default: null
#[serde(default)]
pub lsp: HashMap<Arc<str>, LspSettings>,
/// Configuration for Debugger-related features
#[serde(default)]
pub dap: HashMap<Arc<str>, DapSettingsContent>,
/// Settings for context servers used for AI-related features.
#[serde(default)]
pub context_servers: HashMap<Arc<str>, ContextServerSettingsContent>,
/// Configuration for how direnv configuration should be loaded
pub load_direnv: Option<DirenvSettings>,
/// Settings for slash commands.
pub slash_commands: Option<SlashCommandSettings>,
/// The list of custom Git hosting providers.
pub git_hosting_providers: Option<Vec<GitHostingProviderConfig>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct WorktreeSettingsContent {
/// The displayed name of this project. If not set, the root directory name
/// will be displayed.
///
/// Default: none
pub project_name: Option<String>,
/// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
/// `file_scan_inclusions`.
///
/// Default: [
/// "**/.git",
/// "**/.svn",
/// "**/.hg",
/// "**/.jj",
/// "**/CVS",
/// "**/.DS_Store",
/// "**/Thumbs.db",
/// "**/.classpath",
/// "**/.settings"
/// ]
pub file_scan_exclusions: Option<Vec<String>>,
/// Always include files that match these globs when scanning for files, even if they're
/// ignored by git. This setting is overridden by `file_scan_exclusions`.
/// Default: [
/// ".env*",
/// "docker-compose.*.yml",
/// ]
pub file_scan_inclusions: Option<Vec<String>>,
/// Treat the files matching these globs as `.env` files.
/// Default: ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"]
pub private_files: Option<Vec<String>>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
#[serde(rename_all = "snake_case")]
pub struct LspSettings {
pub binary: Option<BinarySettings>,
pub initialization_options: Option<serde_json::Value>,
pub settings: Option<serde_json::Value>,
/// If the server supports sending tasks over LSP extensions,
/// this setting can be used to enable or disable them in Zed.
/// Default: true
#[serde(default = "default_true")]
pub enable_lsp_tasks: bool,
pub fetch: Option<FetchSettings>,
}
impl Default for LspSettings {
fn default() -> Self {
Self {
binary: None,
initialization_options: None,
settings: None,
enable_lsp_tasks: true,
fetch: None,
}
}
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
pub struct BinarySettings {
pub path: Option<String>,
pub arguments: Option<Vec<String>>,
pub env: Option<BTreeMap<String, String>>,
pub ignore_system_version: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
pub struct FetchSettings {
// Whether to consider pre-releases for fetching
pub pre_release: Option<bool>,
}
/// Common language server settings.
#[skip_serializing_none]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct GlobalLspSettingsContent {
/// Whether to show the LSP servers button in the status bar.
///
/// Default: `true`
pub button: Option<bool>,
}
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct DapSettingsContent {
pub binary: Option<String>,
#[serde(default)]
pub args: Option<Vec<String>>,
}
#[skip_serializing_none]
#[derive(Default, Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, JsonSchema)]
pub struct SessionSettingsContent {
/// Whether or not to restore unsaved buffers on restart.
///
/// If this is true, user won't be prompted whether to save/discard
/// dirty files when closing the application.
///
/// Default: true
pub restore_unsaved_buffers: Option<bool>,
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
#[serde(tag = "source", rename_all = "snake_case")]
pub enum ContextServerSettingsContent {
Custom {
/// Whether the context server is enabled.
#[serde(default = "default_true")]
enabled: bool,
#[serde(flatten)]
command: ContextServerCommand,
},
Extension {
/// Whether the context server is enabled.
#[serde(default = "default_true")]
enabled: bool,
/// The settings for this context server specified by the extension.
///
/// Consult the documentation for the context server to see what settings
/// are supported.
settings: serde_json::Value,
},
}
impl ContextServerSettingsContent {
pub fn set_enabled(&mut self, enabled: bool) {
match self {
ContextServerSettingsContent::Custom {
enabled: custom_enabled,
command: _,
} => {
*custom_enabled = enabled;
}
ContextServerSettingsContent::Extension {
enabled: ext_enabled,
settings: _,
} => *ext_enabled = enabled,
}
}
}
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)]
pub struct ContextServerCommand {
#[serde(rename = "command")]
pub path: PathBuf,
pub args: Vec<String>,
pub env: Option<HashMap<String, String>>,
/// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
pub timeout: Option<u64>,
}
impl std::fmt::Debug for ContextServerCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let filtered_env = self.env.as_ref().map(|env| {
env.iter()
.map(|(k, v)| {
(
k,
if util::redact::should_redact(k) {
"[REDACTED]"
} else {
v
},
)
})
.collect::<Vec<_>>()
});
f.debug_struct("ContextServerCommand")
.field("path", &self.path)
.field("args", &self.args)
.field("env", &filtered_env)
.finish()
}
}
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct GitSettings {
/// Whether or not to show the git gutter.
///
/// Default: tracked_files
pub git_gutter: Option<GitGutterSetting>,
/// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
///
/// Default: null
pub gutter_debounce: Option<u64>,
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: on
pub inline_blame: Option<InlineBlameSettings>,
/// Which information to show in the branch picker.
///
/// Default: on
pub branch_picker: Option<BranchPickerSettingsContent>,
/// How hunks are displayed visually in the editor.
///
/// Default: staged_hollow
pub hunk_style: Option<GitHunkStyleSetting>,
}
#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitGutterSetting {
/// Show git gutter in tracked files.
#[default]
TrackedFiles,
/// Hide git gutter
Hide,
}
#[skip_serializing_none]
#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct InlineBlameSettings {
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: true
pub enabled: Option<bool>,
/// Whether to only show the inline blame information
/// after a delay once the cursor stops moving.
///
/// Default: 0
pub delay_ms: Option<u64>,
/// The amount of padding between the end of the source line and the start
/// of the inline blame in units of columns.
///
/// Default: 7
pub padding: Option<u32>,
/// The minimum column number to show the inline blame information at
///
/// Default: 0
pub min_column: Option<u32>,
/// Whether to show commit summary as part of the inline blame.
///
/// Default: false
pub show_commit_summary: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct BranchPickerSettingsContent {
/// Whether to show author name as part of the commit information.
///
/// Default: false
pub show_author_name: Option<bool>,
}
#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitHunkStyleSetting {
/// Show unstaged hunks with a filled background and staged hunks hollow.
#[default]
StagedHollow,
/// Show unstaged hunks hollow and staged hunks with a filled background.
UnstagedHollow,
}
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct DiagnosticsSettingsContent {
/// Whether to show the project diagnostics button in the status bar.
pub button: Option<bool>,
/// Whether or not to include warning diagnostics.
pub include_warnings: Option<bool>,
/// Settings for using LSP pull diagnostics mechanism in Zed.
pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
/// Settings for showing inline diagnostics.
pub inline: Option<InlineDiagnosticsSettingsContent>,
}
#[skip_serializing_none]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct LspPullDiagnosticsSettingsContent {
/// Whether to pull for diagnostics or not.
///
/// Default: true
pub enabled: Option<bool>,
/// Minimum time to wait before pulling diagnostics from the language server(s).
/// 0 turns the debounce off.
///
/// Default: 50
pub debounce_ms: Option<u64>,
}
#[skip_serializing_none]
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, JsonSchema, Eq)]
pub struct InlineDiagnosticsSettingsContent {
/// Whether or not to show inline diagnostics
///
/// Default: false
pub enabled: Option<bool>,
/// Whether to only show the inline diagnostics after a delay after the
/// last editor event.
///
/// Default: 150
pub update_debounce_ms: Option<u64>,
/// The amount of padding between the end of the source line and the start
/// of the inline diagnostic in units of columns.
///
/// Default: 4
pub padding: Option<u32>,
/// The minimum column to display inline diagnostics. This setting can be
/// used to horizontally align inline diagnostics at some position. Lines
/// longer than this value will still push diagnostics further to the right.
///
/// Default: 0
pub min_column: Option<u32>,
pub max_severity: Option<DiagnosticSeverityContent>,
}
#[skip_serializing_none]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct NodeBinarySettings {
/// The path to the Node binary.
pub path: Option<String>,
/// The path to the npm binary Zed should use (defaults to `.path/../npm`).
pub npm_path: Option<String>,
/// If enabled, Zed will download its own copy of Node.
pub ignore_system_version: Option<bool>,
}
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DirenvSettings {
/// Load direnv configuration through a shell hook
ShellHook,
/// Load direnv configuration directly using `direnv export json`
#[default]
Direct,
}
#[derive(
Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum DiagnosticSeverityContent {
// No diagnostics are shown.
Off,
Error,
Warning,
Info,
#[serde(alias = "all")]
Hint,
}
/// A custom Git hosting provider.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct GitHostingProviderConfig {
/// The type of the provider.
///
/// Must be one of `github`, `gitlab`, or `bitbucket`.
pub provider: GitHostingProviderKind,
/// The base URL for the provider (e.g., "https://code.corp.big.com").
pub base_url: String,
/// The display name for the provider (e.g., "BigCorp GitHub").
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitHostingProviderKind {
Github,
Gitlab,
Bitbucket,
}
@@ -0,0 +1,318 @@
use std::path::PathBuf;
use collections::HashMap;
use gpui::{AbsoluteLength, FontFeatures, SharedString, px};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::FontFamilyName;
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct TerminalSettingsContent {
/// What shell to use when opening a terminal.
///
/// Default: system
pub shell: Option<Shell>,
/// What working directory to use when launching the terminal
///
/// Default: current_project_directory
pub working_directory: Option<WorkingDirectory>,
/// Sets the terminal's font size.
///
/// If this option is not included,
/// the terminal will default to matching the buffer's font size.
pub font_size: Option<f32>,
/// Sets the terminal's font family.
///
/// If this option is not included,
/// the terminal will default to matching the buffer's font family.
pub font_family: Option<FontFamilyName>,
/// Sets the terminal's font fallbacks.
///
/// If this option is not included,
/// the terminal will default to matching the buffer's font fallbacks.
#[schemars(extend("uniqueItems" = true))]
pub font_fallbacks: Option<Vec<FontFamilyName>>,
/// Sets the terminal's line height.
///
/// Default: comfortable
pub line_height: Option<TerminalLineHeight>,
pub font_features: Option<FontFeatures>,
/// Sets the terminal's font weight in CSS weight units 0-900.
pub font_weight: Option<f32>,
/// Any key-value pairs added to this list will be added to the terminal's
/// environment. Use `:` to separate multiple values.
///
/// Default: {}
pub env: Option<HashMap<String, String>>,
/// Default cursor shape for the terminal.
/// Can be "bar", "block", "underline", or "hollow".
///
/// Default: None
pub cursor_shape: Option<CursorShapeContent>,
/// Sets the cursor blinking behavior in the terminal.
///
/// Default: terminal_controlled
pub blinking: Option<TerminalBlink>,
/// Sets whether Alternate Scroll mode (code: ?1007) is active by default.
/// Alternate Scroll mode converts mouse scroll events into up / down key
/// presses when in the alternate screen (e.g. when running applications
/// like vim or less). The terminal can still set and unset this mode.
///
/// Default: on
pub alternate_scroll: Option<AlternateScroll>,
/// Sets whether the option key behaves as the meta key.
///
/// Default: false
pub option_as_meta: Option<bool>,
/// Whether or not selecting text in the terminal will automatically
/// copy to the system clipboard.
///
/// Default: false
pub copy_on_select: Option<bool>,
/// Whether to keep the text selection after copying it to the clipboard.
///
/// Default: false
pub keep_selection_on_copy: Option<bool>,
/// Whether to show the terminal button in the status bar.
///
/// Default: true
pub button: Option<bool>,
pub dock: Option<TerminalDockPosition>,
/// Default width when the terminal is docked to the left or right.
///
/// Default: 640
pub default_width: Option<f32>,
/// Default height when the terminal is docked to the bottom.
///
/// Default: 320
pub default_height: Option<f32>,
/// Activates the python virtual environment, if one is found, in the
/// terminal's working directory (as resolved by the working_directory
/// setting). Set this to "off" to disable this behavior.
///
/// Default: on
pub detect_venv: Option<VenvSettings>,
/// The maximum number of lines to keep in the scrollback history.
/// Maximum allowed value is 100_000, all values above that will be treated as 100_000.
/// 0 disables the scrolling.
/// Existing terminals will not pick up this change until they are recreated.
/// See <a href="https://github.com/alacritty/alacritty/blob/cb3a79dbf6472740daca8440d5166c1d4af5029e/extra/man/alacritty.5.scd?plain=1#L207-L213">Alacritty documentation</a> for more information.
///
/// Default: 10_000
pub max_scroll_history_lines: Option<usize>,
/// Toolbar related settings
pub toolbar: Option<TerminalToolbarContent>,
/// Scrollbar-related settings
pub scrollbar: Option<ScrollbarSettingsContent>,
/// The minimum APCA perceptual contrast between foreground and background colors.
///
/// APCA (Accessible Perceptual Contrast Algorithm) is more accurate than WCAG 2.x,
/// especially for dark mode. Values range from 0 to 106.
///
/// Based on APCA Readability Criterion (ARC) Bronze Simple Mode:
/// https://readtech.org/ARC/tests/bronze-simple-mode/
/// - 0: No contrast adjustment
/// - 45: Minimum for large fluent text (36px+)
/// - 60: Minimum for other content text
/// - 75: Minimum for body text
/// - 90: Preferred for body text
///
/// Default: 45
pub minimum_contrast: Option<f32>,
}
/// Shell configuration to open the terminal with.
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Shell {
/// Use the system's default terminal configuration in /etc/passwd
#[default]
System,
/// Use a specific program with no arguments.
Program(String),
/// Use a specific program with arguments.
WithArguments {
/// The program to run.
program: String,
/// The arguments to pass to the program.
args: Vec<String>,
/// An optional string to override the title of the terminal tab
title_override: Option<SharedString>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WorkingDirectory {
/// Use the current file's project directory. Will Fallback to the
/// first project directory strategy if unsuccessful.
CurrentProjectDirectory,
/// Use the first project in this workspace's directory.
FirstProjectDirectory,
/// Always use this platform's home directory (if it can be found).
AlwaysHome,
/// Always use a specific directory. This value will be shell expanded.
/// If this path is not a valid directory the terminal will default to
/// this platform's home directory (if it can be found).
Always { directory: String },
}
#[skip_serializing_none]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ScrollbarSettingsContent {
/// When to show the scrollbar in the terminal.
///
/// Default: inherits editor scrollbar settings
pub show: Option<Option<ShowScrollbar>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)]
#[serde(rename_all = "snake_case")]
pub enum TerminalLineHeight {
/// Use a line height that's comfortable for reading, 1.618
#[default]
Comfortable,
/// Use a standard line height, 1.3. This option is useful for TUIs,
/// particularly if they use box characters
Standard,
/// Use a custom line height.
Custom(f32),
}
impl TerminalLineHeight {
pub fn value(&self) -> AbsoluteLength {
let value = match self {
TerminalLineHeight::Comfortable => 1.618,
TerminalLineHeight::Standard => 1.3,
TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.),
};
px(value).into()
}
}
/// When to show the scrollbar.
///
/// Default: auto
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ShowScrollbar {
/// Show the scrollbar if there's important information or
/// follow the system's configured behavior.
Auto,
/// Match the system's configured behavior.
System,
/// Always show the scrollbar.
Always,
/// Never show the scrollbar.
Never,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CursorShapeContent {
/// Cursor is a block like `█`.
#[default]
Block,
/// Cursor is an underscore like `_`.
Underline,
/// Cursor is a vertical bar like `⎸`.
Bar,
/// Cursor is a hollow box like `▯`.
Hollow,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum TerminalBlink {
/// Never blink the cursor, ignoring the terminal mode.
Off,
/// Default the cursor blink to off, but allow the terminal to
/// set blinking.
TerminalControlled,
/// Always blink the cursor, ignoring the terminal mode.
On,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AlternateScroll {
On,
Off,
}
// Toolbar related settings
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct TerminalToolbarContent {
/// Whether to display the terminal title in breadcrumbs inside the terminal pane.
/// Only shown if the terminal title is not empty.
///
/// The shell running in the terminal needs to be configured to emit the title.
/// Example: `echo -e "\e]2;New Title\007";`
///
/// Default: true
pub breadcrumbs: Option<bool>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VenvSettings {
#[default]
Off,
On {
/// Default directories to search for virtual environments, relative
/// to the current working directory. We recommend overriding this
/// in your project's settings, rather than globally.
activate_script: Option<ActivateScript>,
venv_name: Option<String>,
directories: Option<Vec<PathBuf>>,
},
}
#[skip_serializing_none]
pub struct VenvSettingsContent<'a> {
pub activate_script: ActivateScript,
pub venv_name: &'a str,
pub directories: &'a [PathBuf],
}
impl VenvSettings {
pub fn as_option(&self) -> Option<VenvSettingsContent<'_>> {
match self {
VenvSettings::Off => None,
VenvSettings::On {
activate_script,
venv_name,
directories,
} => Some(VenvSettingsContent {
activate_script: activate_script.unwrap_or(ActivateScript::Default),
venv_name: venv_name.as_deref().unwrap_or(""),
directories: directories.as_deref().unwrap_or(&[]),
}),
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum TerminalDockPosition {
Left,
Bottom,
Right,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ActivateScript {
#[default]
Default,
Csh,
Fish,
Nushell,
PowerShell,
Pyenv,
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,440 @@
use std::num::NonZeroUsize;
use collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::{DockPosition, DockSide, ScrollbarSettingsContent, ShowIndentGuides};
#[skip_serializing_none]
#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct WorkspaceSettingsContent {
/// Active pane styling settings.
pub active_pane_modifiers: Option<ActivePanelModifiers>,
/// Layout mode for the bottom dock
///
/// Default: contained
pub bottom_dock_layout: Option<BottomDockLayout>,
/// Direction to split horizontally.
///
/// Default: "up"
pub pane_split_direction_horizontal: Option<PaneSplitDirectionHorizontal>,
/// Direction to split vertically.
///
/// Default: "left"
pub pane_split_direction_vertical: Option<PaneSplitDirectionVertical>,
/// Centered layout related settings.
pub centered_layout: Option<CenteredLayoutSettings>,
/// Whether or not to prompt the user to confirm before closing the application.
///
/// Default: false
pub confirm_quit: Option<bool>,
/// Whether or not to show the call status icon in the status bar.
///
/// Default: true
pub show_call_status_icon: Option<bool>,
/// When to automatically save edited buffers.
///
/// Default: off
pub autosave: Option<AutosaveSetting>,
/// Controls previous session restoration in freshly launched Zed instance.
/// Values: none, last_workspace, last_session
/// Default: last_session
pub restore_on_startup: Option<RestoreOnStartupBehavior>,
/// Whether to attempt to restore previous file's state when opening it again.
/// The state is stored per pane.
/// When disabled, defaults are applied instead of the state restoration.
///
/// E.g. for editors, selections, folds and scroll positions are restored, if the same file is closed and, later, opened again in the same pane.
/// When disabled, a single selection in the very beginning of the file, zero scroll position and no folds state is used as a default.
///
/// Default: true
pub restore_on_file_reopen: Option<bool>,
/// The size of the workspace split drop targets on the outer edges.
/// Given as a fraction that will be multiplied by the smaller dimension of the workspace.
///
/// Default: `0.2` (20% of the smaller dimension of the workspace)
pub drop_target_size: Option<f32>,
/// Whether to close the window when using 'close active item' on a workspace with no tabs
///
/// Default: auto ("on" on macOS, "off" otherwise)
pub when_closing_with_no_tabs: Option<CloseWindowWhenNoItems>,
/// Whether to use the system provided dialogs for Open and Save As.
/// When set to false, Zed will use the built-in keyboard-first pickers.
///
/// Default: true
pub use_system_path_prompts: Option<bool>,
/// Whether to use the system provided prompts.
/// When set to false, Zed will use the built-in prompts.
/// Note that this setting has no effect on Linux, where Zed will always
/// use the built-in prompts.
///
/// Default: true
pub use_system_prompts: Option<bool>,
/// Aliases for the command palette. When you type a key in this map,
/// it will be assumed to equal the value.
///
/// Default: true
#[serde(default)]
pub command_aliases: HashMap<String, String>,
/// Maximum open tabs in a pane. Will not close an unsaved
/// tab. Set to `None` for unlimited tabs.
///
/// Default: none
pub max_tabs: Option<NonZeroUsize>,
/// What to do when the last window is closed
///
/// Default: auto (nothing on macOS, "app quit" otherwise)
pub on_last_window_closed: Option<OnLastWindowClosed>,
/// Whether to resize all the panels in a dock when resizing the dock.
///
/// Default: ["left"]
pub resize_all_panels_in_dock: Option<Vec<DockPosition>>,
/// Whether to automatically close files that have been deleted on disk.
///
/// Default: false
pub close_on_file_delete: Option<bool>,
/// Whether to allow windows to tab together based on the user’s tabbing preference (macOS only).
///
/// Default: false
pub use_system_window_tabs: Option<bool>,
/// Whether to show padding for zoomed panels.
/// When enabled, zoomed bottom panels will have some top padding,
/// while zoomed left/right panels will have padding to the right/left (respectively).
///
/// Default: true
pub zoomed_padding: Option<bool>,
}
#[skip_serializing_none]
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ItemSettingsContent {
/// Whether to show the Git file status on a tab item.
///
/// Default: false
pub git_status: Option<bool>,
/// Position of the close button in a tab.
///
/// Default: right
pub close_position: Option<ClosePosition>,
/// Whether to show the file icon for a tab.
///
/// Default: false
pub file_icons: Option<bool>,
/// What to do after closing the current tab.
///
/// Default: history
pub activate_on_close: Option<ActivateOnClose>,
/// Which files containing diagnostic errors/warnings to mark in the tabs.
/// This setting can take the following three values:
///
/// Default: off
pub show_diagnostics: Option<ShowDiagnostics>,
/// Whether to always show the close button on tabs.
///
/// Default: false
pub show_close_button: Option<ShowCloseButton>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
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.
///
/// Default: true
pub enabled: Option<bool>,
/// Whether to open tabs in preview mode when selected from the file finder.
///
/// Default: false
pub enable_preview_from_file_finder: Option<bool>,
/// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
///
/// Default: false
pub enable_preview_from_code_navigation: Option<bool>,
}
#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ClosePosition {
Left,
#[default]
Right,
}
#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ShowCloseButton {
Always,
#[default]
Hover,
Hidden,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ShowDiagnostics {
#[default]
Off,
Errors,
All,
}
#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ActivateOnClose {
#[default]
History,
Neighbour,
LeftNeighbour,
}
#[skip_serializing_none]
#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct ActivePanelModifiers {
/// Size of the border surrounding the active pane.
/// When set to 0, the active pane doesn't have any border.
/// The border is drawn inset.
///
/// Default: `0.0`
pub border_size: Option<f32>,
/// Opacity of inactive panels.
/// When set to 1.0, the inactive panes have the same opacity as the active one.
/// If set to 0, the inactive panes content will not be visible at all.
/// Values are clamped to the [0.0, 1.0] range.
///
/// Default: `1.0`
pub inactive_opacity: Option<f32>,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum BottomDockLayout {
/// Contained between the left and right docks
#[default]
Contained,
/// Takes up the full width of the window
Full,
/// Extends under the left dock while snapping to the right dock
LeftAligned,
/// Extends under the right dock while snapping to the left dock
RightAligned,
}
#[derive(Copy, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum CloseWindowWhenNoItems {
/// Match platform conventions by default, so "on" on macOS and "off" everywhere else
#[default]
PlatformDefault,
/// Close the window when there are no tabs
CloseWindow,
/// Leave the window open when there are no tabs
KeepWindowOpen,
}
impl CloseWindowWhenNoItems {
pub fn should_close(&self) -> bool {
match self {
CloseWindowWhenNoItems::PlatformDefault => cfg!(target_os = "macos"),
CloseWindowWhenNoItems::CloseWindow => true,
CloseWindowWhenNoItems::KeepWindowOpen => false,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum RestoreOnStartupBehavior {
/// Always start with an empty editor
None,
/// Restore the workspace that was closed last.
LastWorkspace,
/// Restore all workspaces that were open when quitting Zed.
#[default]
LastSession,
}
#[skip_serializing_none]
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
pub struct TabBarSettingsContent {
/// Whether or not to show the tab bar in the editor.
///
/// Default: true
pub show: Option<bool>,
/// Whether or not to show the navigation history buttons in the tab bar.
///
/// Default: true
pub show_nav_history_buttons: Option<bool>,
/// Whether or not to show the tab bar buttons.
///
/// Default: true
pub show_tab_bar_buttons: Option<bool>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AutosaveSetting {
/// Disable autosave.
Off,
/// Save after inactivity period of `milliseconds`.
AfterDelay { milliseconds: u64 },
/// Autosave when focus changes.
OnFocusChange,
/// Autosave when the active window changes.
OnWindowChange,
}
impl AutosaveSetting {
pub fn should_save_on_close(&self) -> bool {
matches!(
&self,
AutosaveSetting::OnFocusChange
| AutosaveSetting::OnWindowChange
| AutosaveSetting::AfterDelay { .. }
)
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PaneSplitDirectionHorizontal {
Up,
Down,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PaneSplitDirectionVertical {
Left,
Right,
}
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct CenteredLayoutSettings {
/// The relative width of the left padding of the central pane from the
/// workspace when the centered layout is used.
///
/// Default: 0.2
pub left_padding: Option<f32>,
// The relative width of the right padding of the central pane from the
// workspace when the centered layout is used.
///
/// Default: 0.2
pub right_padding: Option<f32>,
}
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Debug)]
#[serde(rename_all = "snake_case")]
pub enum OnLastWindowClosed {
/// Match platform conventions by default, so don't quit on macOS, and quit on other platforms
#[default]
PlatformDefault,
/// Quit the application the last window is closed
QuitApp,
}
impl OnLastWindowClosed {
pub fn is_quit_app(&self) -> bool {
match self {
OnLastWindowClosed::PlatformDefault => false,
OnLastWindowClosed::QuitApp => true,
}
}
}
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct ProjectPanelSettingsContent {
/// Whether to show the project panel button in the status bar.
///
/// Default: true
pub button: Option<bool>,
/// Whether to hide gitignore files in the project panel.
///
/// Default: false
pub hide_gitignore: Option<bool>,
/// Customize default width (in pixels) taken by project panel
///
/// Default: 240
pub default_width: Option<f32>,
/// The position of project panel
///
/// Default: left
pub dock: Option<DockSide>,
/// Spacing between worktree entries in the project panel.
///
/// Default: comfortable
pub entry_spacing: Option<ProjectPanelEntrySpacing>,
/// Whether to show file icons in the project panel.
///
/// Default: true
pub file_icons: Option<bool>,
/// Whether to show folder icons or chevrons for directories in the project panel.
///
/// Default: true
pub folder_icons: Option<bool>,
/// Whether to show the git status in the project panel.
///
/// Default: true
pub git_status: Option<bool>,
/// Amount of indentation (in pixels) for nested items.
///
/// Default: 20
pub indent_size: Option<f32>,
/// Whether to reveal it in the project panel automatically,
/// when a corresponding project entry becomes active.
/// Gitignored entries are never auto revealed.
///
/// Default: true
pub auto_reveal_entries: Option<bool>,
/// Whether to fold directories automatically
/// when directory has only one directory inside.
///
/// Default: true
pub auto_fold_dirs: Option<bool>,
/// Whether the project panel should open on startup.
///
/// Default: true
pub starts_open: Option<bool>,
/// Scrollbar-related settings
pub scrollbar: Option<ScrollbarSettingsContent>,
/// Which files containing diagnostic errors/warnings to mark in the project panel.
///
/// Default: all
pub show_diagnostics: Option<ShowDiagnostics>,
/// Settings related to indent guides in the project panel.
pub indent_guides: Option<ProjectPanelIndentGuidesSettings>,
/// Whether to hide the root entry when only one folder is open in the window.
///
/// Default: false
pub hide_root: Option<bool>,
/// Whether to stick parent directories at top of the project panel.
///
/// Default: true
pub sticky_scroll: Option<bool>,
/// Whether to enable drag-and-drop operations in the project panel.
///
/// Default: true
pub drag_and_drop: Option<bool>,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ProjectPanelEntrySpacing {
/// Comfortable spacing of entries.
#[default]
Comfortable,
/// The standard spacing of entries.
Standard,
}
#[skip_serializing_none]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ProjectPanelIndentGuidesSettings {
pub show: Option<ShowIndentGuides>,
}
+4 -4
View File
@@ -1,4 +1,4 @@
use crate::{Settings, settings_store::SettingsStore};
use crate::{settings_content::SettingsContent, settings_store::SettingsStore};
use collections::HashSet;
use fs::{Fs, PathEventKind};
use futures::{StreamExt, channel::mpsc};
@@ -126,10 +126,10 @@ pub fn watch_config_dir(
rx
}
pub fn update_settings_file<T: Settings>(
pub fn update_settings_file(
fs: Arc<dyn Fs>,
cx: &App,
update: impl 'static + Send + FnOnce(&mut T::FileContent, &App),
update: impl 'static + Send + FnOnce(&mut SettingsContent, &App),
) {
SettingsStore::global(cx).update_settings_file::<T>(fs, update);
SettingsStore::global(cx).update_settings_file(fs, update);
}
+1 -8
View File
@@ -26,7 +26,6 @@ pub fn update_value_in_json_text<'a>(
tab_size: usize,
old_value: &'a Value,
new_value: &'a Value,
preserved_keys: &[&str],
edits: &mut Vec<(Range<usize>, String)>,
) {
// If the old and new values are both objects, then compare them key by key,
@@ -43,7 +42,6 @@ pub fn update_value_in_json_text<'a>(
tab_size,
old_sub_value,
new_sub_value,
preserved_keys,
edits,
);
} else {
@@ -64,17 +62,12 @@ pub fn update_value_in_json_text<'a>(
tab_size,
&Value::Null,
new_sub_value,
preserved_keys,
edits,
);
}
key_path.pop();
}
} else if key_path
.last()
.is_some_and(|key| preserved_keys.contains(key))
|| old_value != new_value
{
} else if old_value != new_value {
let mut new_value = new_value.clone();
if let Some(new_object) = new_value.as_object_mut() {
new_object.retain(|_, v| !v.is_null());
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -78,12 +78,7 @@ impl VsCodeSettings {
}
pub fn read_value(&self, setting: &str) -> Option<&Value> {
if let Some(value) = self.content.get(setting) {
return Some(value);
}
// TODO: maybe check if it's in [platform] settings for current platform as a fallback
// TODO: deal with language specific settings
None
self.content.get(setting)
}
pub fn read_string(&self, setting: &str) -> Option<&str> {
@@ -140,4 +135,8 @@ impl VsCodeSettings {
*setting = Some(s)
}
}
pub fn read_enum<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
self.content.get(key).and_then(Value::as_str).and_then(f)
}
}