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