project.rs

  1use std::{path::PathBuf, sync::Arc};
  2
  3use collections::{BTreeMap, HashMap};
  4use schemars::JsonSchema;
  5use serde::{Deserialize, Serialize};
  6use serde_with::skip_serializing_none;
  7use settings_macros::MergeFrom;
  8use util::serde::default_true;
  9
 10use crate::{AllLanguageSettingsContent, ExtendingVec, SlashCommandSettings};
 11
 12#[skip_serializing_none]
 13#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
 14pub struct ProjectSettingsContent {
 15    #[serde(flatten)]
 16    pub all_languages: AllLanguageSettingsContent,
 17
 18    #[serde(flatten)]
 19    pub worktree: WorktreeSettingsContent,
 20
 21    /// Configuration for language servers.
 22    ///
 23    /// The following settings can be overridden for specific language servers:
 24    /// - initialization_options
 25    ///
 26    /// To override settings for a language, add an entry for that language server's
 27    /// name to the lsp value.
 28    /// Default: null
 29    #[serde(default)]
 30    pub lsp: HashMap<Arc<str>, LspSettings>,
 31
 32    /// Configuration for Debugger-related features
 33    #[serde(default)]
 34    pub dap: HashMap<Arc<str>, DapSettingsContent>,
 35
 36    /// Settings for context servers used for AI-related features.
 37    #[serde(default)]
 38    pub context_servers: HashMap<Arc<str>, ContextServerSettingsContent>,
 39
 40    /// Configuration for how direnv configuration should be loaded
 41    pub load_direnv: Option<DirenvSettings>,
 42
 43    /// Settings for slash commands.
 44    pub slash_commands: Option<SlashCommandSettings>,
 45
 46    /// The list of custom Git hosting providers.
 47    pub git_hosting_providers: Option<ExtendingVec<GitHostingProviderConfig>>,
 48}
 49
 50#[skip_serializing_none]
 51#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
 52pub struct WorktreeSettingsContent {
 53    /// The displayed name of this project. If not set or empty, the root directory name
 54    /// will be displayed.
 55    ///
 56    /// Default: ""
 57    pub project_name: Option<String>,
 58
 59    /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
 60    /// `file_scan_inclusions`.
 61    ///
 62    /// Default: [
 63    ///   "**/.git",
 64    ///   "**/.svn",
 65    ///   "**/.hg",
 66    ///   "**/.jj",
 67    ///   "**/CVS",
 68    ///   "**/.DS_Store",
 69    ///   "**/Thumbs.db",
 70    ///   "**/.classpath",
 71    ///   "**/.settings"
 72    /// ]
 73    pub file_scan_exclusions: Option<Vec<String>>,
 74
 75    /// Always include files that match these globs when scanning for files, even if they're
 76    /// ignored by git. This setting is overridden by `file_scan_exclusions`.
 77    /// Default: [
 78    ///  ".env*",
 79    ///  "docker-compose.*.yml",
 80    /// ]
 81    pub file_scan_inclusions: Option<Vec<String>>,
 82
 83    /// Treat the files matching these globs as `.env` files.
 84    /// Default: ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"]
 85    pub private_files: Option<ExtendingVec<String>>,
 86}
 87
 88#[skip_serializing_none]
 89#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash)]
 90#[serde(rename_all = "snake_case")]
 91pub struct LspSettings {
 92    pub binary: Option<BinarySettings>,
 93    pub initialization_options: Option<serde_json::Value>,
 94    pub settings: Option<serde_json::Value>,
 95    /// If the server supports sending tasks over LSP extensions,
 96    /// this setting can be used to enable or disable them in Zed.
 97    /// Default: true
 98    #[serde(default = "default_true")]
 99    pub enable_lsp_tasks: bool,
100    pub fetch: Option<FetchSettings>,
101}
102
103impl Default for LspSettings {
104    fn default() -> Self {
105        Self {
106            binary: None,
107            initialization_options: None,
108            settings: None,
109            enable_lsp_tasks: true,
110            fetch: None,
111        }
112    }
113}
114
115#[skip_serializing_none]
116#[derive(
117    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
118)]
119pub struct BinarySettings {
120    pub path: Option<String>,
121    pub arguments: Option<Vec<String>>,
122    pub env: Option<BTreeMap<String, String>>,
123    pub ignore_system_version: Option<bool>,
124}
125
126#[skip_serializing_none]
127#[derive(
128    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
129)]
130pub struct FetchSettings {
131    // Whether to consider pre-releases for fetching
132    pub pre_release: Option<bool>,
133}
134
135/// Common language server settings.
136#[skip_serializing_none]
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
138pub struct GlobalLspSettingsContent {
139    /// Whether to show the LSP servers button in the status bar.
140    ///
141    /// Default: `true`
142    pub button: Option<bool>,
143}
144
145#[skip_serializing_none]
146#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
147#[serde(rename_all = "snake_case")]
148pub struct DapSettingsContent {
149    pub binary: Option<String>,
150    #[serde(default)]
151    pub args: Option<Vec<String>>,
152}
153
154#[skip_serializing_none]
155#[derive(
156    Default, Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, JsonSchema, MergeFrom,
157)]
158pub struct SessionSettingsContent {
159    /// Whether or not to restore unsaved buffers on restart.
160    ///
161    /// If this is true, user won't be prompted whether to save/discard
162    /// dirty files when closing the application.
163    ///
164    /// Default: true
165    pub restore_unsaved_buffers: Option<bool>,
166}
167
168#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom, Debug)]
169#[serde(tag = "source", rename_all = "snake_case")]
170pub enum ContextServerSettingsContent {
171    Custom {
172        /// Whether the context server is enabled.
173        #[serde(default = "default_true")]
174        enabled: bool,
175
176        #[serde(flatten)]
177        command: ContextServerCommand,
178    },
179    Extension {
180        /// Whether the context server is enabled.
181        #[serde(default = "default_true")]
182        enabled: bool,
183        /// The settings for this context server specified by the extension.
184        ///
185        /// Consult the documentation for the context server to see what settings
186        /// are supported.
187        settings: serde_json::Value,
188    },
189}
190impl ContextServerSettingsContent {
191    pub fn set_enabled(&mut self, enabled: bool) {
192        match self {
193            ContextServerSettingsContent::Custom {
194                enabled: custom_enabled,
195                command: _,
196            } => {
197                *custom_enabled = enabled;
198            }
199            ContextServerSettingsContent::Extension {
200                enabled: ext_enabled,
201                settings: _,
202            } => *ext_enabled = enabled,
203        }
204    }
205}
206
207#[skip_serializing_none]
208#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom)]
209pub struct ContextServerCommand {
210    #[serde(rename = "command")]
211    pub path: PathBuf,
212    pub args: Vec<String>,
213    pub env: Option<HashMap<String, String>>,
214    /// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
215    pub timeout: Option<u64>,
216}
217
218impl std::fmt::Debug for ContextServerCommand {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        let filtered_env = self.env.as_ref().map(|env| {
221            env.iter()
222                .map(|(k, v)| {
223                    (
224                        k,
225                        if util::redact::should_redact(k) {
226                            "[REDACTED]"
227                        } else {
228                            v
229                        },
230                    )
231                })
232                .collect::<Vec<_>>()
233        });
234
235        f.debug_struct("ContextServerCommand")
236            .field("path", &self.path)
237            .field("args", &self.args)
238            .field("env", &filtered_env)
239            .finish()
240    }
241}
242
243#[skip_serializing_none]
244#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
245pub struct GitSettings {
246    /// Whether or not to show the git gutter.
247    ///
248    /// Default: tracked_files
249    pub git_gutter: Option<GitGutterSetting>,
250    /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
251    ///
252    /// Default: null
253    pub gutter_debounce: Option<u64>,
254    /// Whether or not to show git blame data inline in
255    /// the currently focused line.
256    ///
257    /// Default: on
258    pub inline_blame: Option<InlineBlameSettings>,
259    /// Git blame settings.
260    pub blame: Option<BlameSettings>,
261    /// Which information to show in the branch picker.
262    ///
263    /// Default: on
264    pub branch_picker: Option<BranchPickerSettingsContent>,
265    /// How hunks are displayed visually in the editor.
266    ///
267    /// Default: staged_hollow
268    pub hunk_style: Option<GitHunkStyleSetting>,
269}
270
271#[derive(
272    Clone,
273    Copy,
274    Debug,
275    PartialEq,
276    Default,
277    Serialize,
278    Deserialize,
279    JsonSchema,
280    MergeFrom,
281    strum::VariantArray,
282    strum::VariantNames,
283)]
284#[serde(rename_all = "snake_case")]
285pub enum GitGutterSetting {
286    /// Show git gutter in tracked files.
287    #[default]
288    TrackedFiles,
289    /// Hide git gutter
290    Hide,
291}
292
293#[skip_serializing_none]
294#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
295#[serde(rename_all = "snake_case")]
296pub struct InlineBlameSettings {
297    /// Whether or not to show git blame data inline in
298    /// the currently focused line.
299    ///
300    /// Default: true
301    pub enabled: Option<bool>,
302    /// Whether to only show the inline blame information
303    /// after a delay once the cursor stops moving.
304    ///
305    /// Default: 0
306    pub delay_ms: Option<u64>,
307    /// The amount of padding between the end of the source line and the start
308    /// of the inline blame in units of columns.
309    ///
310    /// Default: 7
311    pub padding: Option<u32>,
312    /// The minimum column number to show the inline blame information at
313    ///
314    /// Default: 0
315    pub min_column: Option<u32>,
316    /// Whether to show commit summary as part of the inline blame.
317    ///
318    /// Default: false
319    pub show_commit_summary: Option<bool>,
320}
321
322#[skip_serializing_none]
323#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
324#[serde(rename_all = "snake_case")]
325pub struct BlameSettings {
326    /// Whether to show the avatar of the author of the commit.
327    ///
328    /// Default: true
329    pub show_avatar: Option<bool>,
330}
331
332#[skip_serializing_none]
333#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
334#[serde(rename_all = "snake_case")]
335pub struct BranchPickerSettingsContent {
336    /// Whether to show author name as part of the commit information.
337    ///
338    /// Default: false
339    pub show_author_name: Option<bool>,
340}
341
342#[derive(
343    Clone,
344    Copy,
345    PartialEq,
346    Debug,
347    Default,
348    Serialize,
349    Deserialize,
350    JsonSchema,
351    MergeFrom,
352    strum::VariantArray,
353    strum::VariantNames,
354)]
355#[serde(rename_all = "snake_case")]
356pub enum GitHunkStyleSetting {
357    /// Show unstaged hunks with a filled background and staged hunks hollow.
358    #[default]
359    StagedHollow,
360    /// Show unstaged hunks hollow and staged hunks with a filled background.
361    UnstagedHollow,
362}
363
364#[skip_serializing_none]
365#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
366pub struct DiagnosticsSettingsContent {
367    /// Whether to show the project diagnostics button in the status bar.
368    pub button: Option<bool>,
369
370    /// Whether or not to include warning diagnostics.
371    pub include_warnings: Option<bool>,
372
373    /// Settings for using LSP pull diagnostics mechanism in Zed.
374    pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
375
376    /// Settings for showing inline diagnostics.
377    pub inline: Option<InlineDiagnosticsSettingsContent>,
378}
379
380#[skip_serializing_none]
381#[derive(
382    Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
383)]
384pub struct LspPullDiagnosticsSettingsContent {
385    /// Whether to pull for diagnostics or not.
386    ///
387    /// Default: true
388    pub enabled: Option<bool>,
389    /// Minimum time to wait before pulling diagnostics from the language server(s).
390    /// 0 turns the debounce off.
391    ///
392    /// Default: 50
393    pub debounce_ms: Option<u64>,
394}
395
396#[skip_serializing_none]
397#[derive(
398    Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Eq,
399)]
400pub struct InlineDiagnosticsSettingsContent {
401    /// Whether or not to show inline diagnostics
402    ///
403    /// Default: false
404    pub enabled: Option<bool>,
405    /// Whether to only show the inline diagnostics after a delay after the
406    /// last editor event.
407    ///
408    /// Default: 150
409    pub update_debounce_ms: Option<u64>,
410    /// The amount of padding between the end of the source line and the start
411    /// of the inline diagnostic in units of columns.
412    ///
413    /// Default: 4
414    pub padding: Option<u32>,
415    /// The minimum column to display inline diagnostics. This setting can be
416    /// used to horizontally align inline diagnostics at some position. Lines
417    /// longer than this value will still push diagnostics further to the right.
418    ///
419    /// Default: 0
420    pub min_column: Option<u32>,
421
422    pub max_severity: Option<DiagnosticSeverityContent>,
423}
424
425#[skip_serializing_none]
426#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
427pub struct NodeBinarySettings {
428    /// The path to the Node binary.
429    pub path: Option<String>,
430    /// The path to the npm binary Zed should use (defaults to `.path/../npm`).
431    pub npm_path: Option<String>,
432    /// If enabled, Zed will download its own copy of Node.
433    pub ignore_system_version: Option<bool>,
434}
435
436#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
437#[serde(rename_all = "snake_case")]
438pub enum DirenvSettings {
439    /// Load direnv configuration through a shell hook
440    ShellHook,
441    /// Load direnv configuration directly using `direnv export json`
442    #[default]
443    Direct,
444}
445
446#[derive(
447    Clone,
448    Copy,
449    Debug,
450    Eq,
451    PartialEq,
452    Ord,
453    PartialOrd,
454    Serialize,
455    Deserialize,
456    JsonSchema,
457    MergeFrom,
458    strum::VariantArray,
459    strum::VariantNames,
460)]
461#[serde(rename_all = "snake_case")]
462pub enum DiagnosticSeverityContent {
463    // No diagnostics are shown.
464    Off,
465    Error,
466    Warning,
467    Info,
468    #[serde(alias = "all")]
469    Hint,
470}
471
472/// A custom Git hosting provider.
473#[skip_serializing_none]
474#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
475pub struct GitHostingProviderConfig {
476    /// The type of the provider.
477    ///
478    /// Must be one of `github`, `gitlab`, or `bitbucket`.
479    pub provider: GitHostingProviderKind,
480
481    /// The base URL for the provider (e.g., "https://code.corp.big.com").
482    pub base_url: String,
483
484    /// The display name for the provider (e.g., "BigCorp GitHub").
485    pub name: String,
486}
487
488#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
489#[serde(rename_all = "snake_case")]
490pub enum GitHostingProviderKind {
491    Github,
492    Gitlab,
493    Bitbucket,
494}