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