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