settings_content.rs

  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}