1use std::borrow::Cow;
2use std::env;
3use std::num::NonZeroU32;
4use std::sync::Arc;
5
6use collections::{HashMap, HashSet};
7use gpui::{App, Modifiers, SharedString};
8use release_channel::ReleaseChannel;
9use schemars::{JsonSchema, json_schema};
10use serde::de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor};
11use serde::{Deserialize, Deserializer, Serialize};
12use util::schemars::replace_subschema;
13use util::serde::default_true;
14
15use crate::{ActiveSettingsProfileName, ParameterizedJsonSchema, Settings};
16
17#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
18pub struct SettingsContent {
19 #[serde(flatten)]
20 pub project: ProjectSettingsContent,
21
22 pub base_keymap: Option<BaseKeymapContent>,
23}
24
25impl SettingsContent {
26 pub fn languages_mut(&mut self) -> &mut HashMap<SharedString, LanguageSettingsContent> {
27 &mut self.project.all_languages.languages.0
28 }
29}
30
31// todo!() what should this be?
32#[derive(Debug, Default, Serialize, Deserialize, JsonSchema)]
33pub struct ServerSettingsContent {
34 #[serde(flatten)]
35 project: ProjectSettingsContent,
36}
37
38#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
39pub(crate) struct UserSettingsContent {
40 #[serde(flatten)]
41 pub(crate) content: SettingsContent,
42
43 pub(crate) dev: Option<SettingsContent>,
44 pub(crate) nightly: Option<SettingsContent>,
45 pub(crate) preview: Option<SettingsContent>,
46 pub(crate) stable: Option<SettingsContent>,
47
48 pub(crate) macos: Option<SettingsContent>,
49 pub(crate) windows: Option<SettingsContent>,
50 pub(crate) linux: Option<SettingsContent>,
51
52 #[serde(default)]
53 pub(crate) profiles: HashMap<String, SettingsContent>,
54}
55
56pub struct ExtensionsSettingsContent {
57 pub(crate) all_languages: AllLanguageSettingsContent,
58}
59
60impl UserSettingsContent {
61 pub(crate) fn for_release_channel(&self) -> Option<&SettingsContent> {
62 match *release_channel::RELEASE_CHANNEL {
63 ReleaseChannel::Dev => self.dev.as_ref(),
64 ReleaseChannel::Nightly => self.nightly.as_ref(),
65 ReleaseChannel::Preview => self.preview.as_ref(),
66 ReleaseChannel::Stable => self.stable.as_ref(),
67 }
68 }
69
70 pub(crate) fn for_os(&self) -> Option<&SettingsContent> {
71 match env::consts::OS {
72 "macos" => self.macos.as_ref(),
73 "linux" => self.linux.as_ref(),
74 "windows" => self.windows.as_ref(),
75 _ => None,
76 }
77 }
78
79 pub(crate) fn for_profile(&self, cx: &App) -> Option<&SettingsContent> {
80 let Some(active_profile) = cx.try_global::<ActiveSettingsProfileName>() else {
81 return None;
82 };
83 self.profiles.get(&active_profile.0)
84 }
85}
86
87/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
88///
89/// Default: VSCode
90#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
91pub enum BaseKeymapContent {
92 #[default]
93 VSCode,
94 JetBrains,
95 SublimeText,
96 Atom,
97 TextMate,
98 Emacs,
99 Cursor,
100 None,
101}
102
103#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
104pub struct ProjectSettingsContent {
105 #[serde(flatten)]
106 pub(crate) all_languages: AllLanguageSettingsContent,
107}
108
109#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
110pub struct AllLanguageSettingsContent {
111 /// The settings for enabling/disabling features.
112 #[serde(default)]
113 pub features: Option<FeaturesContent>,
114 /// The edit prediction settings.
115 #[serde(default)]
116 pub edit_predictions: Option<EditPredictionSettingsContent>,
117 /// The default language settings.
118 #[serde(flatten)]
119 pub defaults: LanguageSettingsContent,
120 /// The settings for individual languages.
121 #[serde(default)]
122 pub languages: LanguageToSettingsMap,
123 /// Settings for associating file extensions and filenames
124 /// with languages.
125 #[serde(default)]
126 pub file_types: HashMap<SharedString, Vec<String>>,
127}
128
129/// The settings for enabling/disabling features.
130#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
131#[serde(rename_all = "snake_case")]
132pub struct FeaturesContent {
133 /// Determines which edit prediction provider to use.
134 pub edit_prediction_provider: Option<EditPredictionProviderContent>,
135}
136
137/// The provider that supplies edit predictions.
138#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
139#[serde(rename_all = "snake_case")]
140pub enum EditPredictionProviderContent {
141 None,
142 #[default]
143 Copilot,
144 Supermaven,
145 Zed,
146}
147
148/// The contents of the edit prediction settings.
149#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
150pub struct EditPredictionSettingsContent {
151 /// A list of globs representing files that edit predictions should be disabled for.
152 /// This list adds to a pre-existing, sensible default set of globs.
153 /// Any additional ones you add are combined with them.
154 #[serde(default)]
155 pub disabled_globs: Option<Vec<String>>,
156 /// The mode used to display edit predictions in the buffer.
157 /// Provider support required.
158 #[serde(default)]
159 pub mode: EditPredictionsModeContent,
160 /// Settings specific to GitHub Copilot.
161 #[serde(default)]
162 pub copilot: CopilotSettingsContent,
163 /// Whether edit predictions are enabled in the assistant prompt editor.
164 /// This has no effect if globally disabled.
165 #[serde(default = "default_true")]
166 pub enabled_in_text_threads: bool,
167}
168
169#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
170pub struct CopilotSettingsContent {
171 /// HTTP/HTTPS proxy to use for Copilot.
172 ///
173 /// Default: none
174 #[serde(default)]
175 pub proxy: Option<String>,
176 /// Disable certificate verification for the proxy (not recommended).
177 ///
178 /// Default: false
179 #[serde(default)]
180 pub proxy_no_verify: Option<bool>,
181 /// Enterprise URI for Copilot.
182 ///
183 /// Default: none
184 #[serde(default)]
185 pub enterprise_uri: Option<String>,
186}
187
188/// The mode in which edit predictions should be displayed.
189#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
190#[serde(rename_all = "snake_case")]
191pub enum EditPredictionsModeContent {
192 /// If provider supports it, display inline when holding modifier key (e.g., alt).
193 /// Otherwise, eager preview is used.
194 #[serde(alias = "auto")]
195 Subtle,
196 /// Display inline when there are no language server completions available.
197 #[default]
198 #[serde(alias = "eager_preview")]
199 Eager,
200}
201
202/// Controls the soft-wrapping behavior in the editor.
203#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
204#[serde(rename_all = "snake_case")]
205pub enum SoftWrapContent {
206 /// Prefer a single line generally, unless an overly long line is encountered.
207 None,
208 /// Deprecated: use None instead. Left to avoid breaking existing users' configs.
209 /// Prefer a single line generally, unless an overly long line is encountered.
210 PreferLine,
211 /// Soft wrap lines that exceed the editor width.
212 EditorWidth,
213 /// Soft wrap lines at the preferred line length.
214 PreferredLineLength,
215 /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
216 Bounded,
217}
218
219/// The settings for a particular language.
220#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
221pub struct LanguageSettingsContent {
222 /// How many columns a tab should occupy.
223 ///
224 /// Default: 4
225 #[serde(default)]
226 pub tab_size: Option<NonZeroU32>,
227 /// Whether to indent lines using tab characters, as opposed to multiple
228 /// spaces.
229 ///
230 /// Default: false
231 #[serde(default)]
232 pub hard_tabs: Option<bool>,
233 /// How to soft-wrap long lines of text.
234 ///
235 /// Default: none
236 #[serde(default)]
237 pub soft_wrap: Option<SoftWrapContent>,
238 /// The column at which to soft-wrap lines, for buffers where soft-wrap
239 /// is enabled.
240 ///
241 /// Default: 80
242 #[serde(default)]
243 pub preferred_line_length: Option<u32>,
244 /// Whether to show wrap guides in the editor. Setting this to true will
245 /// show a guide at the 'preferred_line_length' value if softwrap is set to
246 /// 'preferred_line_length', and will show any additional guides as specified
247 /// by the 'wrap_guides' setting.
248 ///
249 /// Default: true
250 #[serde(default)]
251 pub show_wrap_guides: Option<bool>,
252 /// Character counts at which to show wrap guides in the editor.
253 ///
254 /// Default: []
255 #[serde(default)]
256 pub wrap_guides: Option<Vec<usize>>,
257 /// Indent guide related settings.
258 #[serde(default)]
259 pub indent_guides: Option<IndentGuideSettingsContent>,
260 /// Whether or not to perform a buffer format before saving.
261 ///
262 /// Default: on
263 #[serde(default)]
264 pub format_on_save: Option<FormatOnSave>,
265 /// Whether or not to remove any trailing whitespace from lines of a buffer
266 /// before saving it.
267 ///
268 /// Default: true
269 #[serde(default)]
270 pub remove_trailing_whitespace_on_save: Option<bool>,
271 /// Whether or not to ensure there's a single newline at the end of a buffer
272 /// when saving it.
273 ///
274 /// Default: true
275 #[serde(default)]
276 pub ensure_final_newline_on_save: Option<bool>,
277 /// How to perform a buffer format.
278 ///
279 /// Default: auto
280 #[serde(default)]
281 pub formatter: Option<SelectedFormatter>,
282 /// Zed's Prettier integration settings.
283 /// Allows to enable/disable formatting with Prettier
284 /// and configure default Prettier, used when no project-level Prettier installation is found.
285 ///
286 /// Default: off
287 #[serde(default)]
288 pub prettier: Option<PrettierSettings>,
289 /// Whether to automatically close JSX tags.
290 #[serde(default)]
291 pub jsx_tag_auto_close: Option<JsxTagAutoCloseSettings>,
292 /// Whether to use language servers to provide code intelligence.
293 ///
294 /// Default: true
295 #[serde(default)]
296 pub enable_language_server: Option<bool>,
297 /// The list of language servers to use (or disable) for this language.
298 ///
299 /// This array should consist of language server IDs, as well as the following
300 /// special tokens:
301 /// - `"!<language_server_id>"` - A language server ID prefixed with a `!` will be disabled.
302 /// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language.
303 ///
304 /// Default: ["..."]
305 #[serde(default)]
306 pub language_servers: Option<Vec<String>>,
307 /// Controls where the `editor::Rewrap` action is allowed for this language.
308 ///
309 /// Note: This setting has no effect in Vim mode, as rewrap is already
310 /// allowed everywhere.
311 ///
312 /// Default: "in_comments"
313 #[serde(default)]
314 pub allow_rewrap: Option<RewrapBehavior>,
315 /// Controls whether edit predictions are shown immediately (true)
316 /// or manually by triggering `editor::ShowEditPrediction` (false).
317 ///
318 /// Default: true
319 #[serde(default)]
320 pub show_edit_predictions: Option<bool>,
321 /// Controls whether edit predictions are shown in the given language
322 /// scopes.
323 ///
324 /// Example: ["string", "comment"]
325 ///
326 /// Default: []
327 #[serde(default)]
328 pub edit_predictions_disabled_in: Option<Vec<String>>,
329 /// Whether to show tabs and spaces in the editor.
330 #[serde(default)]
331 pub show_whitespaces: Option<ShowWhitespaceSetting>,
332 /// Visible characters used to render whitespace when show_whitespaces is enabled.
333 ///
334 /// Default: "•" for spaces, "→" for tabs.
335 #[serde(default)]
336 pub whitespace_map: Option<WhitespaceMap>,
337 /// Whether to start a new line with a comment when a previous line is a comment as well.
338 ///
339 /// Default: true
340 #[serde(default)]
341 pub extend_comment_on_newline: Option<bool>,
342 /// Inlay hint related settings.
343 #[serde(default)]
344 pub inlay_hints: Option<InlayHintSettings>,
345 /// Whether to automatically type closing characters for you. For example,
346 /// when you type (, Zed will automatically add a closing ) at the correct position.
347 ///
348 /// Default: true
349 pub use_autoclose: Option<bool>,
350 /// Whether to automatically surround text with characters for you. For example,
351 /// when you select text and type (, Zed will automatically surround text with ().
352 ///
353 /// Default: true
354 pub use_auto_surround: Option<bool>,
355 /// Controls how the editor handles the autoclosed characters.
356 /// When set to `false`(default), skipping over and auto-removing of the closing characters
357 /// happen only for auto-inserted characters.
358 /// Otherwise(when `true`), the closing characters are always skipped over and auto-removed
359 /// no matter how they were inserted.
360 ///
361 /// Default: false
362 pub always_treat_brackets_as_autoclosed: Option<bool>,
363 /// Whether to use additional LSP queries to format (and amend) the code after
364 /// every "trigger" symbol input, defined by LSP server capabilities.
365 ///
366 /// Default: true
367 pub use_on_type_format: Option<bool>,
368 /// Which code actions to run on save after the formatter.
369 /// These are not run if formatting is off.
370 ///
371 /// Default: {} (or {"source.organizeImports": true} for Go).
372 pub code_actions_on_format: Option<HashMap<String, bool>>,
373 /// Whether to perform linked edits of associated ranges, if the language server supports it.
374 /// For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well.
375 ///
376 /// Default: true
377 pub linked_edits: Option<bool>,
378 /// Whether indentation should be adjusted based on the context whilst typing.
379 ///
380 /// Default: true
381 pub auto_indent: Option<bool>,
382 /// Whether indentation of pasted content should be adjusted based on the context.
383 ///
384 /// Default: true
385 pub auto_indent_on_paste: Option<bool>,
386 /// Task configuration for this language.
387 ///
388 /// Default: {}
389 pub tasks: Option<LanguageTaskConfig>,
390 /// Whether to pop the completions menu while typing in an editor without
391 /// explicitly requesting it.
392 ///
393 /// Default: true
394 pub show_completions_on_input: Option<bool>,
395 /// Whether to display inline and alongside documentation for items in the
396 /// completions menu.
397 ///
398 /// Default: true
399 pub show_completion_documentation: Option<bool>,
400 /// Controls how completions are processed for this language.
401 pub completions: Option<CompletionSettings>,
402 /// Preferred debuggers for this language.
403 ///
404 /// Default: []
405 pub debuggers: Option<Vec<String>>,
406}
407
408/// Controls how whitespace should be displayedin the editor.
409#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
410#[serde(rename_all = "snake_case")]
411pub enum ShowWhitespaceSetting {
412 /// Draw whitespace only for the selected text.
413 Selection,
414 /// Do not draw any tabs or spaces.
415 None,
416 /// Draw all invisible symbols.
417 All,
418 /// Draw whitespaces at boundaries only.
419 ///
420 /// For a whitespace to be on a boundary, any of the following conditions need to be met:
421 /// - It is a tab
422 /// - It is adjacent to an edge (start or end)
423 /// - It is adjacent to a whitespace (left or right)
424 Boundary,
425 /// Draw whitespaces only after non-whitespace characters.
426 Trailing,
427}
428
429#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
430pub struct WhitespaceMap {
431 #[serde(default)]
432 pub space: Option<String>,
433 #[serde(default)]
434 pub tab: Option<String>,
435}
436
437impl WhitespaceMap {
438 pub fn space(&self) -> SharedString {
439 self.space
440 .as_ref()
441 .map_or_else(|| SharedString::from("•"), |s| SharedString::from(s))
442 }
443
444 pub fn tab(&self) -> SharedString {
445 self.tab
446 .as_ref()
447 .map_or_else(|| SharedString::from("→"), |s| SharedString::from(s))
448 }
449}
450
451/// The behavior of `editor::Rewrap`.
452#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
453#[serde(rename_all = "snake_case")]
454pub enum RewrapBehavior {
455 /// Only rewrap within comments.
456 #[default]
457 InComments,
458 /// Only rewrap within the current selection(s).
459 InSelections,
460 /// Allow rewrapping anywhere.
461 Anywhere,
462}
463
464#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
465pub struct JsxTagAutoCloseSettings {
466 /// Enables or disables auto-closing of JSX tags.
467 #[serde(default)]
468 pub enabled: bool,
469}
470
471/// The settings for inlay hints.
472#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
473pub struct InlayHintSettings {
474 /// Global switch to toggle hints on and off.
475 ///
476 /// Default: false
477 #[serde(default)]
478 pub enabled: bool,
479 /// Global switch to toggle inline values on and off when debugging.
480 ///
481 /// Default: true
482 #[serde(default = "default_true")]
483 pub show_value_hints: bool,
484 /// Whether type hints should be shown.
485 ///
486 /// Default: true
487 #[serde(default = "default_true")]
488 pub show_type_hints: bool,
489 /// Whether parameter hints should be shown.
490 ///
491 /// Default: true
492 #[serde(default = "default_true")]
493 pub show_parameter_hints: bool,
494 /// Whether other hints should be shown.
495 ///
496 /// Default: true
497 #[serde(default = "default_true")]
498 pub show_other_hints: bool,
499 /// Whether to show a background for inlay hints.
500 ///
501 /// If set to `true`, the background will use the `hint.background` color
502 /// from the current theme.
503 ///
504 /// Default: false
505 #[serde(default)]
506 pub show_background: bool,
507 /// Whether or not to debounce inlay hints updates after buffer edits.
508 ///
509 /// Set to 0 to disable debouncing.
510 ///
511 /// Default: 700
512 #[serde(default = "edit_debounce_ms")]
513 pub edit_debounce_ms: u64,
514 /// Whether or not to debounce inlay hints updates after buffer scrolls.
515 ///
516 /// Set to 0 to disable debouncing.
517 ///
518 /// Default: 50
519 #[serde(default = "scroll_debounce_ms")]
520 pub scroll_debounce_ms: u64,
521 /// Toggles inlay hints (hides or shows) when the user presses the modifiers specified.
522 /// If only a subset of the modifiers specified is pressed, hints are not toggled.
523 /// If no modifiers are specified, this is equivalent to `None`.
524 ///
525 /// Default: None
526 #[serde(default)]
527 pub toggle_on_modifiers_press: Option<Modifiers>,
528}
529
530fn edit_debounce_ms() -> u64 {
531 700
532}
533
534fn scroll_debounce_ms() -> u64 {
535 50
536}
537
538/// Controls how completions are processed for this language.
539#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
540#[serde(rename_all = "snake_case")]
541pub struct CompletionSettings {
542 /// Controls how words are completed.
543 /// For large documents, not all words may be fetched for completion.
544 ///
545 /// Default: `fallback`
546 #[serde(default = "default_words_completion_mode")]
547 pub words: WordsCompletionMode,
548 /// How many characters has to be in the completions query to automatically show the words-based completions.
549 /// Before that value, it's still possible to trigger the words-based completion manually with the corresponding editor command.
550 ///
551 /// Default: 3
552 #[serde(default = "default_3")]
553 pub words_min_length: usize,
554 /// Whether to fetch LSP completions or not.
555 ///
556 /// Default: true
557 #[serde(default = "default_true")]
558 pub lsp: bool,
559 /// When fetching LSP completions, determines how long to wait for a response of a particular server.
560 /// When set to 0, waits indefinitely.
561 ///
562 /// Default: 0
563 #[serde(default)]
564 pub lsp_fetch_timeout_ms: u64,
565 /// Controls how LSP completions are inserted.
566 ///
567 /// Default: "replace_suffix"
568 #[serde(default = "default_lsp_insert_mode")]
569 pub lsp_insert_mode: LspInsertMode,
570}
571
572#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
573#[serde(rename_all = "snake_case")]
574pub enum LspInsertMode {
575 /// Replaces text before the cursor, using the `insert` range described in the LSP specification.
576 Insert,
577 /// Replaces text before and after the cursor, using the `replace` range described in the LSP specification.
578 Replace,
579 /// Behaves like `"replace"` if the text that would be replaced is a subsequence of the completion text,
580 /// and like `"insert"` otherwise.
581 ReplaceSubsequence,
582 /// Behaves like `"replace"` if the text after the cursor is a suffix of the completion, and like
583 /// `"insert"` otherwise.
584 ReplaceSuffix,
585}
586
587/// Controls how document's words are completed.
588#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
589#[serde(rename_all = "snake_case")]
590pub enum WordsCompletionMode {
591 /// Always fetch document's words for completions along with LSP completions.
592 Enabled,
593 /// Only if LSP response errors or times out,
594 /// use document's words to show completions.
595 Fallback,
596 /// Never fetch or complete document's words for completions.
597 /// (Word-based completions can still be queried via a separate action)
598 Disabled,
599}
600
601fn default_words_completion_mode() -> WordsCompletionMode {
602 WordsCompletionMode::Fallback
603}
604
605fn default_lsp_insert_mode() -> LspInsertMode {
606 LspInsertMode::ReplaceSuffix
607}
608
609fn default_3() -> usize {
610 3
611}
612
613/// Allows to enable/disable formatting with Prettier
614/// and configure default Prettier, used when no project-level Prettier installation is found.
615/// Prettier formatting is disabled by default.
616#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
617pub struct PrettierSettings {
618 /// Enables or disables formatting with Prettier for a given language.
619 #[serde(default)]
620 pub allowed: bool,
621
622 /// Forces Prettier integration to use a specific parser name when formatting files with the language.
623 #[serde(default)]
624 pub parser: Option<String>,
625
626 /// Forces Prettier integration to use specific plugins when formatting files with the language.
627 /// The default Prettier will be installed with these plugins.
628 #[serde(default)]
629 pub plugins: HashSet<String>,
630
631 /// Default Prettier options, in the format as in package.json section for Prettier.
632 /// If project installs Prettier via its package.json, these options will be ignored.
633 #[serde(flatten)]
634 pub options: HashMap<String, serde_json::Value>,
635}
636/// Controls the behavior of formatting files when they are saved.
637#[derive(Debug, Clone, PartialEq, Eq)]
638pub enum FormatOnSave {
639 /// Files should be formatted on save.
640 On,
641 /// Files should not be formatted on save.
642 Off,
643 List(FormatterList),
644}
645
646impl JsonSchema for FormatOnSave {
647 fn schema_name() -> Cow<'static, str> {
648 "OnSaveFormatter".into()
649 }
650
651 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
652 let formatter_schema = Formatter::json_schema(generator);
653
654 json_schema!({
655 "oneOf": [
656 {
657 "type": "array",
658 "items": formatter_schema
659 },
660 {
661 "type": "string",
662 "enum": ["on", "off", "language_server"]
663 },
664 formatter_schema
665 ]
666 })
667 }
668}
669
670impl Serialize for FormatOnSave {
671 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
672 where
673 S: serde::Serializer,
674 {
675 match self {
676 Self::On => serializer.serialize_str("on"),
677 Self::Off => serializer.serialize_str("off"),
678 Self::List(list) => list.serialize(serializer),
679 }
680 }
681}
682
683impl<'de> Deserialize<'de> for FormatOnSave {
684 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
685 where
686 D: Deserializer<'de>,
687 {
688 struct FormatDeserializer;
689
690 impl<'d> Visitor<'d> for FormatDeserializer {
691 type Value = FormatOnSave;
692
693 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
694 formatter.write_str("a valid on-save formatter kind")
695 }
696 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
697 where
698 E: serde::de::Error,
699 {
700 if v == "on" {
701 Ok(Self::Value::On)
702 } else if v == "off" {
703 Ok(Self::Value::Off)
704 } else if v == "language_server" {
705 Ok(Self::Value::List(FormatterList::Single(
706 Formatter::LanguageServer { name: None },
707 )))
708 } else {
709 let ret: Result<FormatterList, _> =
710 Deserialize::deserialize(v.into_deserializer());
711 ret.map(Self::Value::List)
712 }
713 }
714 fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
715 where
716 A: MapAccess<'d>,
717 {
718 let ret: Result<FormatterList, _> =
719 Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
720 ret.map(Self::Value::List)
721 }
722 fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
723 where
724 A: SeqAccess<'d>,
725 {
726 let ret: Result<FormatterList, _> =
727 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
728 ret.map(Self::Value::List)
729 }
730 }
731 deserializer.deserialize_any(FormatDeserializer)
732 }
733}
734
735/// Controls which formatter should be used when formatting code.
736#[derive(Clone, Debug, Default, PartialEq, Eq)]
737pub enum SelectedFormatter {
738 /// Format files using Zed's Prettier integration (if applicable),
739 /// or falling back to formatting via language server.
740 #[default]
741 Auto,
742 List(FormatterList),
743}
744
745impl JsonSchema for SelectedFormatter {
746 fn schema_name() -> Cow<'static, str> {
747 "Formatter".into()
748 }
749
750 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
751 let formatter_schema = Formatter::json_schema(generator);
752
753 json_schema!({
754 "oneOf": [
755 {
756 "type": "array",
757 "items": formatter_schema
758 },
759 {
760 "type": "string",
761 "enum": ["auto", "language_server"]
762 },
763 formatter_schema
764 ]
765 })
766 }
767}
768
769impl Serialize for SelectedFormatter {
770 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
771 where
772 S: serde::Serializer,
773 {
774 match self {
775 SelectedFormatter::Auto => serializer.serialize_str("auto"),
776 SelectedFormatter::List(list) => list.serialize(serializer),
777 }
778 }
779}
780
781impl<'de> Deserialize<'de> for SelectedFormatter {
782 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
783 where
784 D: Deserializer<'de>,
785 {
786 struct FormatDeserializer;
787
788 impl<'d> Visitor<'d> for FormatDeserializer {
789 type Value = SelectedFormatter;
790
791 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
792 formatter.write_str("a valid formatter kind")
793 }
794 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
795 where
796 E: serde::de::Error,
797 {
798 if v == "auto" {
799 Ok(Self::Value::Auto)
800 } else if v == "language_server" {
801 Ok(Self::Value::List(FormatterList::Single(
802 Formatter::LanguageServer { name: None },
803 )))
804 } else {
805 let ret: Result<FormatterList, _> =
806 Deserialize::deserialize(v.into_deserializer());
807 ret.map(SelectedFormatter::List)
808 }
809 }
810 fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
811 where
812 A: MapAccess<'d>,
813 {
814 let ret: Result<FormatterList, _> =
815 Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
816 ret.map(SelectedFormatter::List)
817 }
818 fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
819 where
820 A: SeqAccess<'d>,
821 {
822 let ret: Result<FormatterList, _> =
823 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
824 ret.map(SelectedFormatter::List)
825 }
826 }
827 deserializer.deserialize_any(FormatDeserializer)
828 }
829}
830
831/// Controls which formatters should be used when formatting code.
832#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
833#[serde(untagged)]
834pub enum FormatterList {
835 Single(Formatter),
836 Vec(Vec<Formatter>),
837}
838
839impl Default for FormatterList {
840 fn default() -> Self {
841 Self::Single(Formatter::default())
842 }
843}
844
845/// Controls which formatter should be used when formatting code. If there are multiple formatters, they are executed in the order of declaration.
846#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
847#[serde(rename_all = "snake_case")]
848pub enum Formatter {
849 /// Format code using the current language server.
850 LanguageServer { name: Option<String> },
851 /// Format code using Zed's Prettier integration.
852 #[default]
853 Prettier,
854 /// Format code using an external command.
855 External {
856 /// The external program to run.
857 command: Arc<str>,
858 /// The arguments to pass to the program.
859 arguments: Option<Arc<[String]>>,
860 },
861 /// Files should be formatted using code actions executed by language servers.
862 CodeActions(HashMap<String, bool>),
863}
864
865/// The settings for indent guides.
866#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
867pub struct IndentGuideSettingsContent {
868 /// Whether to display indent guides in the editor.
869 ///
870 /// Default: true
871 #[serde(default = "default_true")]
872 pub enabled: bool,
873 /// The width of the indent guides in pixels, between 1 and 10.
874 ///
875 /// Default: 1
876 #[serde(default = "line_width")]
877 pub line_width: u32,
878 /// The width of the active indent guide in pixels, between 1 and 10.
879 ///
880 /// Default: 1
881 #[serde(default = "active_line_width")]
882 pub active_line_width: u32,
883 /// Determines how indent guides are colored.
884 ///
885 /// Default: Fixed
886 #[serde(default)]
887 pub coloring: IndentGuideColoring,
888 /// Determines how indent guide backgrounds are colored.
889 ///
890 /// Default: Disabled
891 #[serde(default)]
892 pub background_coloring: IndentGuideBackgroundColoring,
893}
894
895fn line_width() -> u32 {
896 1
897}
898
899fn active_line_width() -> u32 {
900 line_width()
901}
902
903/// The task settings for a particular language.
904#[derive(Debug, Clone, Deserialize, PartialEq, Serialize, JsonSchema)]
905pub struct LanguageTaskConfig {
906 /// Extra task variables to set for a particular language.
907 #[serde(default)]
908 pub variables: HashMap<String, String>,
909 #[serde(default = "default_true")]
910 pub enabled: bool,
911 /// Use LSP tasks over Zed language extension ones.
912 /// If no LSP tasks are returned due to error/timeout or regular execution,
913 /// Zed language extension tasks will be used instead.
914 ///
915 /// Other Zed tasks will still be shown:
916 /// * Zed task from either of the task config file
917 /// * Zed task from history (e.g. one-off task was spawned before)
918 #[serde(default = "default_true")]
919 pub prefer_lsp: bool,
920}
921
922/// Map from language name to settings. Its `ParameterizedJsonSchema` allows only known language
923/// names in the keys.
924#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
925pub struct LanguageToSettingsMap(pub HashMap<SharedString, LanguageSettingsContent>);
926
927inventory::submit! {
928 ParameterizedJsonSchema {
929 add_and_get_ref: |generator, params, _cx| {
930 let language_settings_content_ref = generator
931 .subschema_for::<LanguageSettingsContent>()
932 .to_value();
933 replace_subschema::<LanguageToSettingsMap>(generator, || json_schema!({
934 "type": "object",
935 "properties": params
936 .language_names
937 .iter()
938 .map(|name| {
939 (
940 name.clone(),
941 language_settings_content_ref.clone(),
942 )
943 })
944 .collect::<serde_json::Map<_, _>>()
945 }))
946 }
947 }
948}
949
950/// Determines how indent guides are colored.
951#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
952#[serde(rename_all = "snake_case")]
953pub enum IndentGuideColoring {
954 /// Do not render any lines for indent guides.
955 Disabled,
956 /// Use the same color for all indentation levels.
957 #[default]
958 Fixed,
959 /// Use a different color for each indentation level.
960 IndentAware,
961}
962
963/// Determines how indent guide backgrounds are colored.
964#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
965#[serde(rename_all = "snake_case")]
966pub enum IndentGuideBackgroundColoring {
967 /// Do not render any background for indent guides.
968 #[default]
969 Disabled,
970 /// Use a different color for each indentation level.
971 IndentAware,
972}