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