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