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