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