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 /// Configuration for how direnv configuration should be loaded
45 pub load_direnv: Option<DirenvSettings>,
46
47 /// Settings for slash commands.
48 pub slash_commands: Option<SlashCommandSettings>,
49
50 /// The list of custom Git hosting providers.
51 pub git_hosting_providers: Option<ExtendingVec<GitHostingProviderConfig>>,
52}
53
54#[with_fallible_options]
55#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
56pub struct WorktreeSettingsContent {
57 /// The displayed name of this project. If not set or null, the root directory name
58 /// will be displayed.
59 ///
60 /// Default: null
61 pub project_name: Option<String>,
62
63 /// Whether to prevent this project from being shared in public channels.
64 ///
65 /// Default: false
66 #[serde(default)]
67 pub prevent_sharing_in_public_channels: bool,
68
69 /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
70 /// `file_scan_inclusions`.
71 ///
72 /// Default: [
73 /// "**/.git",
74 /// "**/.svn",
75 /// "**/.hg",
76 /// "**/.jj",
77 /// "**/CVS",
78 /// "**/.DS_Store",
79 /// "**/Thumbs.db",
80 /// "**/.classpath",
81 /// "**/.settings"
82 /// ]
83 pub file_scan_exclusions: Option<Vec<String>>,
84
85 /// Always include files that match these globs when scanning for files, even if they're
86 /// ignored by git. This setting is overridden by `file_scan_exclusions`.
87 /// Default: [
88 /// ".env*",
89 /// "docker-compose.*.yml",
90 /// ]
91 pub file_scan_inclusions: Option<Vec<String>>,
92
93 /// Treat the files matching these globs as `.env` files.
94 /// Default: ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"]
95 pub private_files: Option<ExtendingVec<String>>,
96
97 /// Treat the files matching these globs as hidden files. You can hide hidden files in the project panel.
98 /// Default: ["**/.*"]
99 pub hidden_files: Option<Vec<String>>,
100
101 /// Treat the files matching these globs as read-only. These files can be opened and viewed,
102 /// but cannot be edited. This is useful for generated files, build outputs, or files from
103 /// external dependencies that should not be modified directly.
104 /// Default: []
105 pub read_only_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 },
225 Extension {
226 /// Whether the context server is enabled.
227 #[serde(default = "default_true")]
228 enabled: bool,
229 /// The settings for this context server specified by the extension.
230 ///
231 /// Consult the documentation for the context server to see what settings
232 /// are supported.
233 settings: serde_json::Value,
234 },
235}
236
237impl ContextServerSettingsContent {
238 pub fn set_enabled(&mut self, enabled: bool) {
239 match self {
240 ContextServerSettingsContent::Stdio {
241 enabled: custom_enabled,
242 ..
243 } => {
244 *custom_enabled = enabled;
245 }
246 ContextServerSettingsContent::Extension {
247 enabled: ext_enabled,
248 ..
249 } => *ext_enabled = enabled,
250 ContextServerSettingsContent::Http {
251 enabled: remote_enabled,
252 ..
253 } => *remote_enabled = enabled,
254 }
255 }
256}
257
258#[with_fallible_options]
259#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, MergeFrom)]
260pub struct ContextServerCommand {
261 #[serde(rename = "command")]
262 pub path: PathBuf,
263 pub args: Vec<String>,
264 pub env: Option<HashMap<String, String>>,
265 /// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
266 pub timeout: Option<u64>,
267}
268
269impl std::fmt::Debug for ContextServerCommand {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 let filtered_env = self.env.as_ref().map(|env| {
272 env.iter()
273 .map(|(k, v)| {
274 (
275 k,
276 if util::redact::should_redact(k) {
277 "[REDACTED]"
278 } else {
279 v
280 },
281 )
282 })
283 .collect::<Vec<_>>()
284 });
285
286 f.debug_struct("ContextServerCommand")
287 .field("path", &self.path)
288 .field("args", &self.args)
289 .field("env", &filtered_env)
290 .finish()
291 }
292}
293
294#[with_fallible_options]
295#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
296pub struct GitSettings {
297 /// Whether or not to enable git integration.
298 ///
299 /// Default: true
300 #[serde(flatten)]
301 pub enabled: Option<GitEnabledSettings>,
302 /// Whether or not to show the git gutter.
303 ///
304 /// Default: tracked_files
305 pub git_gutter: Option<GitGutterSetting>,
306 /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
307 ///
308 /// Default: 0
309 pub gutter_debounce: Option<u64>,
310 /// Whether or not to show git blame data inline in
311 /// the currently focused line.
312 ///
313 /// Default: on
314 pub inline_blame: Option<InlineBlameSettings>,
315 /// Git blame settings.
316 pub blame: Option<BlameSettings>,
317 /// Which information to show in the branch picker.
318 ///
319 /// Default: on
320 pub branch_picker: Option<BranchPickerSettingsContent>,
321 /// How hunks are displayed visually in the editor.
322 ///
323 /// Default: staged_hollow
324 pub hunk_style: Option<GitHunkStyleSetting>,
325 /// How file paths are displayed in the git gutter.
326 ///
327 /// Default: file_name_first
328 pub path_style: Option<GitPathStyle>,
329}
330
331#[with_fallible_options]
332#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
333#[serde(rename_all = "snake_case")]
334pub struct GitEnabledSettings {
335 pub disable_git: Option<bool>,
336 pub enable_status: Option<bool>,
337 pub enable_diff: Option<bool>,
338}
339
340impl GitEnabledSettings {
341 pub fn is_git_status_enabled(&self) -> bool {
342 !self.disable_git.unwrap_or(false) && self.enable_status.unwrap_or(true)
343 }
344
345 pub fn is_git_diff_enabled(&self) -> bool {
346 !self.disable_git.unwrap_or(false) && self.enable_diff.unwrap_or(true)
347 }
348}
349
350#[derive(
351 Clone,
352 Copy,
353 Debug,
354 PartialEq,
355 Default,
356 Serialize,
357 Deserialize,
358 JsonSchema,
359 MergeFrom,
360 strum::VariantArray,
361 strum::VariantNames,
362)]
363#[serde(rename_all = "snake_case")]
364pub enum GitGutterSetting {
365 /// Show git gutter in tracked files.
366 #[default]
367 TrackedFiles,
368 /// Hide git gutter
369 Hide,
370}
371
372#[with_fallible_options]
373#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
374#[serde(rename_all = "snake_case")]
375pub struct InlineBlameSettings {
376 /// Whether or not to show git blame data inline in
377 /// the currently focused line.
378 ///
379 /// Default: true
380 pub enabled: Option<bool>,
381 /// Whether to only show the inline blame information
382 /// after a delay once the cursor stops moving.
383 ///
384 /// Default: 0
385 pub delay_ms: Option<DelayMs>,
386 /// The amount of padding between the end of the source line and the start
387 /// of the inline blame in units of columns.
388 ///
389 /// Default: 7
390 pub padding: Option<u32>,
391 /// The minimum column number to show the inline blame information at
392 ///
393 /// Default: 0
394 pub min_column: Option<u32>,
395 /// Whether to show commit summary as part of the inline blame.
396 ///
397 /// Default: false
398 pub show_commit_summary: Option<bool>,
399}
400
401#[with_fallible_options]
402#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
403#[serde(rename_all = "snake_case")]
404pub struct BlameSettings {
405 /// Whether to show the avatar of the author of the commit.
406 ///
407 /// Default: true
408 pub show_avatar: Option<bool>,
409}
410
411#[with_fallible_options]
412#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
413#[serde(rename_all = "snake_case")]
414pub struct BranchPickerSettingsContent {
415 /// Whether to show author name as part of the commit information.
416 ///
417 /// Default: false
418 pub show_author_name: Option<bool>,
419}
420
421#[derive(
422 Clone,
423 Copy,
424 PartialEq,
425 Debug,
426 Default,
427 Serialize,
428 Deserialize,
429 JsonSchema,
430 MergeFrom,
431 strum::VariantArray,
432 strum::VariantNames,
433)]
434#[serde(rename_all = "snake_case")]
435pub enum GitHunkStyleSetting {
436 /// Show unstaged hunks with a filled background and staged hunks hollow.
437 #[default]
438 StagedHollow,
439 /// Show unstaged hunks hollow and staged hunks with a filled background.
440 UnstagedHollow,
441}
442
443#[with_fallible_options]
444#[derive(
445 Copy,
446 Clone,
447 Debug,
448 PartialEq,
449 Default,
450 Serialize,
451 Deserialize,
452 JsonSchema,
453 MergeFrom,
454 strum::VariantArray,
455 strum::VariantNames,
456)]
457#[serde(rename_all = "snake_case")]
458pub enum GitPathStyle {
459 /// Show file name first, then path
460 #[default]
461 FileNameFirst,
462 /// Show full path first
463 FilePathFirst,
464}
465
466#[with_fallible_options]
467#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
468pub struct DiagnosticsSettingsContent {
469 /// Whether to show the project diagnostics button in the status bar.
470 pub button: Option<bool>,
471
472 /// Whether or not to include warning diagnostics.
473 pub include_warnings: Option<bool>,
474
475 /// Settings for using LSP pull diagnostics mechanism in Zed.
476 pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
477
478 /// Settings for showing inline diagnostics.
479 pub inline: Option<InlineDiagnosticsSettingsContent>,
480}
481
482#[with_fallible_options]
483#[derive(
484 Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
485)]
486pub struct LspPullDiagnosticsSettingsContent {
487 /// Whether to pull for diagnostics or not.
488 ///
489 /// Default: true
490 pub enabled: Option<bool>,
491 /// Minimum time to wait before pulling diagnostics from the language server(s).
492 /// 0 turns the debounce off.
493 ///
494 /// Default: 50
495 pub debounce_ms: Option<DelayMs>,
496}
497
498#[with_fallible_options]
499#[derive(
500 Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Eq,
501)]
502pub struct InlineDiagnosticsSettingsContent {
503 /// Whether or not to show inline diagnostics
504 ///
505 /// Default: false
506 pub enabled: Option<bool>,
507 /// Whether to only show the inline diagnostics after a delay after the
508 /// last editor event.
509 ///
510 /// Default: 150
511 pub update_debounce_ms: Option<DelayMs>,
512 /// The amount of padding between the end of the source line and the start
513 /// of the inline diagnostic in units of columns.
514 ///
515 /// Default: 4
516 pub padding: Option<u32>,
517 /// The minimum column to display inline diagnostics. This setting can be
518 /// used to horizontally align inline diagnostics at some position. Lines
519 /// longer than this value will still push diagnostics further to the right.
520 ///
521 /// Default: 0
522 pub min_column: Option<u32>,
523
524 pub max_severity: Option<DiagnosticSeverityContent>,
525}
526
527#[with_fallible_options]
528#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, MergeFrom)]
529pub struct NodeBinarySettings {
530 /// The path to the Node binary.
531 pub path: Option<String>,
532 /// The path to the npm binary Zed should use (defaults to `.path/../npm`).
533 pub npm_path: Option<String>,
534 /// If enabled, Zed will download its own copy of Node.
535 pub ignore_system_version: Option<bool>,
536}
537
538#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)]
539#[serde(rename_all = "snake_case")]
540pub enum DirenvSettings {
541 /// Load direnv configuration through a shell hook
542 ShellHook,
543 /// Load direnv configuration directly using `direnv export json`
544 #[default]
545 Direct,
546 /// Do not load direnv configuration
547 Disabled,
548}
549
550#[derive(
551 Clone,
552 Copy,
553 Debug,
554 Eq,
555 PartialEq,
556 Ord,
557 PartialOrd,
558 Serialize,
559 Deserialize,
560 JsonSchema,
561 MergeFrom,
562 strum::VariantArray,
563 strum::VariantNames,
564)]
565#[serde(rename_all = "snake_case")]
566pub enum DiagnosticSeverityContent {
567 // No diagnostics are shown.
568 Off,
569 Error,
570 Warning,
571 Info,
572 Hint,
573 All,
574}
575
576/// A custom Git hosting provider.
577#[with_fallible_options]
578#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
579pub struct GitHostingProviderConfig {
580 /// The type of the provider.
581 ///
582 /// Must be one of `github`, `gitlab`, `bitbucket`, `gitea`, `forgejo`, or `source_hut`.
583 pub provider: GitHostingProviderKind,
584
585 /// The base URL for the provider (e.g., "https://code.corp.big.com").
586 pub base_url: String,
587
588 /// The display name for the provider (e.g., "BigCorp GitHub").
589 pub name: String,
590}
591
592#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
593#[serde(rename_all = "snake_case")]
594pub enum GitHostingProviderKind {
595 Github,
596 Gitlab,
597 Bitbucket,
598 Gitea,
599 Forgejo,
600 SourceHut,
601}