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