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