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