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