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