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