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