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