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