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