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