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