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