editor_settings.rs

  1use core::num;
  2use std::num::NonZeroU32;
  3
  4use gpui::App;
  5use language::CursorShape;
  6use project::project_settings::DiagnosticSeverity;
  7use schemars::JsonSchema;
  8use serde::{Deserialize, Serialize};
  9use settings::{Settings, SettingsSources, VsCodeSettings};
 10use util::serde::default_true;
 11
 12/// Imports from the VSCode settings at
 13/// https://code.visualstudio.com/docs/reference/default-settings
 14#[derive(Deserialize, Clone)]
 15pub struct EditorSettings {
 16    pub cursor_blink: bool,
 17    pub cursor_shape: Option<CursorShape>,
 18    pub current_line_highlight: CurrentLineHighlight,
 19    pub selection_highlight: bool,
 20    pub lsp_highlight_debounce: u64,
 21    pub hover_popover_enabled: bool,
 22    pub hover_popover_delay: u64,
 23    pub status_bar: StatusBar,
 24    pub toolbar: Toolbar,
 25    pub scrollbar: Scrollbar,
 26    pub minimap: Minimap,
 27    pub gutter: Gutter,
 28    pub scroll_beyond_last_line: ScrollBeyondLastLine,
 29    pub vertical_scroll_margin: f32,
 30    pub autoscroll_on_clicks: bool,
 31    pub horizontal_scroll_margin: f32,
 32    pub scroll_sensitivity: f32,
 33    pub fast_scroll_sensitivity: f32,
 34    pub relative_line_numbers: bool,
 35    pub seed_search_query_from_cursor: SeedQuerySetting,
 36    pub use_smartcase_search: bool,
 37    pub multi_cursor_modifier: MultiCursorModifier,
 38    pub redact_private_values: bool,
 39    pub expand_excerpt_lines: u32,
 40    pub excerpt_context_lines: u32,
 41    pub middle_click_paste: bool,
 42    #[serde(default)]
 43    pub double_click_in_multibuffer: DoubleClickInMultibuffer,
 44    pub search_wrap: bool,
 45    #[serde(default)]
 46    pub search: SearchSettings,
 47    pub auto_signature_help: bool,
 48    pub show_signature_help_after_edits: bool,
 49    #[serde(default)]
 50    pub go_to_definition_fallback: GoToDefinitionFallback,
 51    pub jupyter: Jupyter,
 52    pub hide_mouse: Option<HideMouseMode>,
 53    pub snippet_sort_order: SnippetSortOrder,
 54    #[serde(default)]
 55    pub diagnostics_max_severity: Option<DiagnosticSeverity>,
 56    pub inline_code_actions: bool,
 57    pub drag_and_drop_selection: DragAndDropSelection,
 58    pub lsp_document_colors: DocumentColorsRenderMode,
 59}
 60
 61/// How to render LSP `textDocument/documentColor` colors in the editor.
 62#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 63#[serde(rename_all = "snake_case")]
 64pub enum DocumentColorsRenderMode {
 65    /// Do not query and render document colors.
 66    None,
 67    /// Render document colors as inlay hints near the color text.
 68    #[default]
 69    Inlay,
 70    /// Draw a border around the color text.
 71    Border,
 72    /// Draw a background behind the color text.
 73    Background,
 74}
 75
 76#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 77#[serde(rename_all = "snake_case")]
 78pub enum CurrentLineHighlight {
 79    // Don't highlight the current line.
 80    None,
 81    // Highlight the gutter area.
 82    Gutter,
 83    // Highlight the editor area.
 84    Line,
 85    // Highlight the full line.
 86    All,
 87}
 88
 89/// When to populate a new search's query based on the text under the cursor.
 90#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 91#[serde(rename_all = "snake_case")]
 92pub enum SeedQuerySetting {
 93    /// Always populate the search query with the word under the cursor.
 94    Always,
 95    /// Only populate the search query when there is text selected.
 96    Selection,
 97    /// Never populate the search query
 98    Never,
 99}
100
101/// What to do when multibuffer is double clicked in some of its excerpts (parts of singleton buffers).
102#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
103#[serde(rename_all = "snake_case")]
104pub enum DoubleClickInMultibuffer {
105    /// Behave as a regular buffer and select the whole word.
106    #[default]
107    Select,
108    /// Open the excerpt clicked as a new buffer in the new tab, if no `alt` modifier was pressed during double click.
109    /// Otherwise, behave as a regular buffer and select the whole word.
110    Open,
111}
112
113#[derive(Debug, Clone, Deserialize)]
114pub struct Jupyter {
115    /// Whether the Jupyter feature is enabled.
116    ///
117    /// Default: true
118    pub enabled: bool,
119}
120
121#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
122#[serde(rename_all = "snake_case")]
123pub struct JupyterContent {
124    /// Whether the Jupyter feature is enabled.
125    ///
126    /// Default: true
127    pub enabled: Option<bool>,
128}
129
130#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
131pub struct StatusBar {
132    /// Whether to display the active language button in the status bar.
133    ///
134    /// Default: true
135    pub active_language_button: bool,
136    /// Whether to show the cursor position button in the status bar.
137    ///
138    /// Default: true
139    pub cursor_position_button: bool,
140}
141
142#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
143pub struct Toolbar {
144    pub breadcrumbs: bool,
145    pub quick_actions: bool,
146    pub selections_menu: bool,
147    pub agent_review: bool,
148    pub code_actions: bool,
149}
150
151#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
152pub struct Scrollbar {
153    pub show: ShowScrollbar,
154    pub git_diff: bool,
155    pub selected_text: bool,
156    pub selected_symbol: bool,
157    pub search_results: bool,
158    pub diagnostics: ScrollbarDiagnostics,
159    pub cursors: bool,
160    pub axes: ScrollbarAxes,
161}
162
163#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
164pub struct Minimap {
165    pub show: ShowMinimap,
166    pub display_in: DisplayIn,
167    pub thumb: MinimapThumb,
168    pub thumb_border: MinimapThumbBorder,
169    pub current_line_highlight: Option<CurrentLineHighlight>,
170    pub max_width_columns: num::NonZeroU32,
171}
172
173impl Minimap {
174    pub fn minimap_enabled(&self) -> bool {
175        self.show != ShowMinimap::Never
176    }
177
178    #[inline]
179    pub fn on_active_editor(&self) -> bool {
180        self.display_in == DisplayIn::ActiveEditor
181    }
182
183    pub fn with_show_override(self) -> Self {
184        Self {
185            show: ShowMinimap::Always,
186            ..self
187        }
188    }
189}
190
191#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
192pub struct Gutter {
193    pub min_line_number_digits: usize,
194    pub line_numbers: bool,
195    pub runnables: bool,
196    pub breakpoints: bool,
197    pub folds: bool,
198}
199
200/// When to show the scrollbar in the editor.
201///
202/// Default: auto
203#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
204#[serde(rename_all = "snake_case")]
205pub enum ShowScrollbar {
206    /// Show the scrollbar if there's important information or
207    /// follow the system's configured behavior.
208    Auto,
209    /// Match the system's configured behavior.
210    System,
211    /// Always show the scrollbar.
212    Always,
213    /// Never show the scrollbar.
214    Never,
215}
216
217/// When to show the minimap in the editor.
218///
219/// Default: never
220#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
221#[serde(rename_all = "snake_case")]
222pub enum ShowMinimap {
223    /// Follow the visibility of the scrollbar.
224    Auto,
225    /// Always show the minimap.
226    Always,
227    /// Never show the minimap.
228    #[default]
229    Never,
230}
231
232/// Where to show the minimap in the editor.
233///
234/// Default: all_editors
235#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
236#[serde(rename_all = "snake_case")]
237pub enum DisplayIn {
238    /// Show on all open editors.
239    AllEditors,
240    /// Show the minimap on the active editor only.
241    #[default]
242    ActiveEditor,
243}
244
245/// When to show the minimap thumb.
246///
247/// Default: always
248#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
249#[serde(rename_all = "snake_case")]
250pub enum MinimapThumb {
251    /// Show the minimap thumb only when the mouse is hovering over the minimap.
252    Hover,
253    /// Always show the minimap thumb.
254    #[default]
255    Always,
256}
257
258/// Defines the border style for the minimap's scrollbar thumb.
259///
260/// Default: left_open
261#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
262#[serde(rename_all = "snake_case")]
263pub enum MinimapThumbBorder {
264    /// Displays a border on all sides of the thumb.
265    Full,
266    /// Displays a border on all sides except the left side of the thumb.
267    #[default]
268    LeftOpen,
269    /// Displays a border on all sides except the right side of the thumb.
270    RightOpen,
271    /// Displays a border only on the left side of the thumb.
272    LeftOnly,
273    /// Displays the thumb without any border.
274    None,
275}
276
277/// Forcefully enable or disable the scrollbar for each axis
278#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
279#[serde(rename_all = "lowercase")]
280pub struct ScrollbarAxes {
281    /// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
282    ///
283    /// Default: true
284    pub horizontal: bool,
285
286    /// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
287    ///
288    /// Default: true
289    pub vertical: bool,
290}
291
292/// Whether to allow drag and drop text selection in buffer.
293#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
294pub struct DragAndDropSelection {
295    /// When true, enables drag and drop text selection in buffer.
296    ///
297    /// Default: true
298    #[serde(default = "default_true")]
299    pub enabled: bool,
300
301    /// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
302    ///
303    /// Default: 300
304    #[serde(default = "default_drag_and_drop_selection_delay_ms")]
305    pub delay: u64,
306}
307
308fn default_drag_and_drop_selection_delay_ms() -> u64 {
309    300
310}
311
312/// Which diagnostic indicators to show in the scrollbar.
313///
314/// Default: all
315#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
316#[serde(rename_all = "lowercase")]
317pub enum ScrollbarDiagnostics {
318    /// Show all diagnostic levels: hint, information, warnings, error.
319    All,
320    /// Show only the following diagnostic levels: information, warning, error.
321    Information,
322    /// Show only the following diagnostic levels: warning, error.
323    Warning,
324    /// Show only the following diagnostic level: error.
325    Error,
326    /// Do not show diagnostics.
327    None,
328}
329
330/// The key to use for adding multiple cursors
331///
332/// Default: alt
333#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
334#[serde(rename_all = "snake_case")]
335pub enum MultiCursorModifier {
336    Alt,
337    #[serde(alias = "cmd", alias = "ctrl")]
338    CmdOrCtrl,
339}
340
341/// Whether the editor will scroll beyond the last line.
342///
343/// Default: one_page
344#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
345#[serde(rename_all = "snake_case")]
346pub enum ScrollBeyondLastLine {
347    /// The editor will not scroll beyond the last line.
348    Off,
349
350    /// The editor will scroll beyond the last line by one page.
351    OnePage,
352
353    /// The editor will scroll beyond the last line by the same number of lines as vertical_scroll_margin.
354    VerticalScrollMargin,
355}
356
357/// Default options for buffer and project search items.
358#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
359pub struct SearchSettings {
360    /// Whether to show the project search button in the status bar.
361    #[serde(default = "default_true")]
362    pub button: bool,
363    #[serde(default)]
364    pub whole_word: bool,
365    #[serde(default)]
366    pub case_sensitive: bool,
367    #[serde(default)]
368    pub include_ignored: bool,
369    #[serde(default)]
370    pub regex: bool,
371}
372
373/// What to do when go to definition yields no results.
374#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
375#[serde(rename_all = "snake_case")]
376pub enum GoToDefinitionFallback {
377    /// Disables the fallback.
378    None,
379    /// Looks up references of the same symbol instead.
380    #[default]
381    FindAllReferences,
382}
383
384/// Determines when the mouse cursor should be hidden in an editor or input box.
385///
386/// Default: on_typing_and_movement
387#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
388#[serde(rename_all = "snake_case")]
389pub enum HideMouseMode {
390    /// Never hide the mouse cursor
391    Never,
392    /// Hide only when typing
393    OnTyping,
394    /// Hide on both typing and cursor movement
395    #[default]
396    OnTypingAndMovement,
397}
398
399/// Determines how snippets are sorted relative to other completion items.
400///
401/// Default: inline
402#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
403#[serde(rename_all = "snake_case")]
404pub enum SnippetSortOrder {
405    /// Place snippets at the top of the completion list
406    Top,
407    /// Sort snippets normally using the default comparison logic
408    #[default]
409    Inline,
410    /// Place snippets at the bottom of the completion list
411    Bottom,
412    /// Do not show snippets in the completion list
413    None,
414}
415
416#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
417pub struct EditorSettingsContent {
418    /// Whether the cursor blinks in the editor.
419    ///
420    /// Default: true
421    pub cursor_blink: Option<bool>,
422    /// Cursor shape for the default editor.
423    /// Can be "bar", "block", "underline", or "hollow".
424    ///
425    /// Default: None
426    pub cursor_shape: Option<CursorShape>,
427    /// Determines when the mouse cursor should be hidden in an editor or input box.
428    ///
429    /// Default: on_typing_and_movement
430    pub hide_mouse: Option<HideMouseMode>,
431    /// Determines how snippets are sorted relative to other completion items.
432    ///
433    /// Default: inline
434    pub snippet_sort_order: Option<SnippetSortOrder>,
435    /// How to highlight the current line in the editor.
436    ///
437    /// Default: all
438    pub current_line_highlight: Option<CurrentLineHighlight>,
439    /// Whether to highlight all occurrences of the selected text in an editor.
440    ///
441    /// Default: true
442    pub selection_highlight: Option<bool>,
443    /// The debounce delay before querying highlights from the language
444    /// server based on the current cursor location.
445    ///
446    /// Default: 75
447    pub lsp_highlight_debounce: Option<u64>,
448    /// Whether to show the informational hover box when moving the mouse
449    /// over symbols in the editor.
450    ///
451    /// Default: true
452    pub hover_popover_enabled: Option<bool>,
453    /// Time to wait in milliseconds before showing the informational hover box.
454    ///
455    /// Default: 300
456    pub hover_popover_delay: Option<u64>,
457    /// Status bar related settings
458    pub status_bar: Option<StatusBarContent>,
459    /// Toolbar related settings
460    pub toolbar: Option<ToolbarContent>,
461    /// Scrollbar related settings
462    pub scrollbar: Option<ScrollbarContent>,
463    /// Minimap related settings
464    pub minimap: Option<MinimapContent>,
465    /// Gutter related settings
466    pub gutter: Option<GutterContent>,
467    /// Whether the editor will scroll beyond the last line.
468    ///
469    /// Default: one_page
470    pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
471    /// The number of lines to keep above/below the cursor when auto-scrolling.
472    ///
473    /// Default: 3.
474    pub vertical_scroll_margin: Option<f32>,
475    /// Whether to scroll when clicking near the edge of the visible text area.
476    ///
477    /// Default: false
478    pub autoscroll_on_clicks: Option<bool>,
479    /// The number of characters to keep on either side when scrolling with the mouse.
480    ///
481    /// Default: 5.
482    pub horizontal_scroll_margin: Option<f32>,
483    /// Scroll sensitivity multiplier. This multiplier is applied
484    /// to both the horizontal and vertical delta values while scrolling.
485    ///
486    /// Default: 1.0
487    pub scroll_sensitivity: Option<f32>,
488    /// Scroll sensitivity multiplier for fast scrolling. This multiplier is applied
489    /// to both the horizontal and vertical delta values while scrolling. Fast scrolling
490    /// happens when a user holds the alt or option key while scrolling.
491    ///
492    /// Default: 4.0
493    pub fast_scroll_sensitivity: Option<f32>,
494    /// Whether the line numbers on editors gutter are relative or not.
495    ///
496    /// Default: false
497    pub relative_line_numbers: Option<bool>,
498    /// When to populate a new search's query based on the text under the cursor.
499    ///
500    /// Default: always
501    pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
502    pub use_smartcase_search: Option<bool>,
503    /// Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier.
504    ///
505    /// Default: alt
506    pub multi_cursor_modifier: Option<MultiCursorModifier>,
507    /// Hide the values of variables in `private` files, as defined by the
508    /// private_files setting. This only changes the visual representation,
509    /// the values are still present in the file and can be selected / copied / pasted
510    ///
511    /// Default: false
512    pub redact_private_values: Option<bool>,
513
514    /// How many lines to expand the multibuffer excerpts by default
515    ///
516    /// Default: 3
517    pub expand_excerpt_lines: Option<u32>,
518
519    /// How many lines of context to provide in multibuffer excerpts by default
520    ///
521    /// Default: 2
522    pub excerpt_context_lines: Option<u32>,
523
524    /// Whether to enable middle-click paste on Linux
525    ///
526    /// Default: true
527    pub middle_click_paste: Option<bool>,
528
529    /// What to do when multibuffer is double clicked in some of its excerpts
530    /// (parts of singleton buffers).
531    ///
532    /// Default: select
533    pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
534    /// Whether the editor search results will loop
535    ///
536    /// Default: true
537    pub search_wrap: Option<bool>,
538
539    /// Defaults to use when opening a new buffer and project search items.
540    ///
541    /// Default: nothing is enabled
542    pub search: Option<SearchSettings>,
543
544    /// Whether to automatically show a signature help pop-up or not.
545    ///
546    /// Default: false
547    pub auto_signature_help: Option<bool>,
548
549    /// Whether to show the signature help pop-up after completions or bracket pairs inserted.
550    ///
551    /// Default: false
552    pub show_signature_help_after_edits: Option<bool>,
553
554    /// Whether to follow-up empty go to definition responses from the language server or not.
555    /// `FindAllReferences` allows to look up references of the same symbol instead.
556    /// `None` disables the fallback.
557    ///
558    /// Default: FindAllReferences
559    pub go_to_definition_fallback: Option<GoToDefinitionFallback>,
560
561    /// Jupyter REPL settings.
562    pub jupyter: Option<JupyterContent>,
563
564    /// Which level to use to filter out diagnostics displayed in the editor.
565    ///
566    /// Affects the editor rendering only, and does not interrupt
567    /// the functionality of diagnostics fetching and project diagnostics editor.
568    /// Which files containing diagnostic errors/warnings to mark in the tabs.
569    /// Diagnostics are only shown when file icons are also active.
570    ///
571    /// Shows all diagnostics if not specified.
572    ///
573    /// Default: warning
574    #[serde(default)]
575    pub diagnostics_max_severity: Option<DiagnosticSeverity>,
576
577    /// Whether to show code action button at start of buffer line.
578    ///
579    /// Default: true
580    pub inline_code_actions: Option<bool>,
581
582    /// Drag and drop related settings
583    pub drag_and_drop_selection: Option<DragAndDropSelection>,
584
585    /// How to render LSP `textDocument/documentColor` colors in the editor.
586    ///
587    /// Default: [`DocumentColorsRenderMode::Inlay`]
588    pub lsp_document_colors: Option<DocumentColorsRenderMode>,
589}
590
591// Status bar related settings
592#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
593pub struct StatusBarContent {
594    /// Whether to display the active language button in the status bar.
595    ///
596    /// Default: true
597    pub active_language_button: Option<bool>,
598    /// Whether to show the cursor position button in the status bar.
599    ///
600    /// Default: true
601    pub cursor_position_button: Option<bool>,
602}
603
604// Toolbar related settings
605#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
606pub struct ToolbarContent {
607    /// Whether to display breadcrumbs in the editor toolbar.
608    ///
609    /// Default: true
610    pub breadcrumbs: Option<bool>,
611    /// Whether to display quick action buttons in the editor toolbar.
612    ///
613    /// Default: true
614    pub quick_actions: Option<bool>,
615    /// Whether to show the selections menu in the editor toolbar.
616    ///
617    /// Default: true
618    pub selections_menu: Option<bool>,
619    /// Whether to display Agent review buttons in the editor toolbar.
620    /// Only applicable while reviewing a file edited by the Agent.
621    ///
622    /// Default: true
623    pub agent_review: Option<bool>,
624    /// Whether to display code action buttons in the editor toolbar.
625    ///
626    /// Default: false
627    pub code_actions: Option<bool>,
628}
629
630/// Scrollbar related settings
631#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
632pub struct ScrollbarContent {
633    /// When to show the scrollbar in the editor.
634    ///
635    /// Default: auto
636    pub show: Option<ShowScrollbar>,
637    /// Whether to show git diff indicators in the scrollbar.
638    ///
639    /// Default: true
640    pub git_diff: Option<bool>,
641    /// Whether to show buffer search result indicators in the scrollbar.
642    ///
643    /// Default: true
644    pub search_results: Option<bool>,
645    /// Whether to show selected text occurrences in the scrollbar.
646    ///
647    /// Default: true
648    pub selected_text: Option<bool>,
649    /// Whether to show selected symbol occurrences in the scrollbar.
650    ///
651    /// Default: true
652    pub selected_symbol: Option<bool>,
653    /// Which diagnostic indicators to show in the scrollbar:
654    ///
655    /// Default: all
656    pub diagnostics: Option<ScrollbarDiagnostics>,
657    /// Whether to show cursor positions in the scrollbar.
658    ///
659    /// Default: true
660    pub cursors: Option<bool>,
661    /// Forcefully enable or disable the scrollbar for each axis
662    pub axes: Option<ScrollbarAxesContent>,
663}
664
665/// Minimap related settings
666#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
667pub struct MinimapContent {
668    /// When to show the minimap in the editor.
669    ///
670    /// Default: never
671    pub show: Option<ShowMinimap>,
672
673    /// Where to show the minimap in the editor.
674    ///
675    /// Default: [`DisplayIn::ActiveEditor`]
676    pub display_in: Option<DisplayIn>,
677
678    /// When to show the minimap thumb.
679    ///
680    /// Default: always
681    pub thumb: Option<MinimapThumb>,
682
683    /// Defines the border style for the minimap's scrollbar thumb.
684    ///
685    /// Default: left_open
686    pub thumb_border: Option<MinimapThumbBorder>,
687
688    /// How to highlight the current line in the minimap.
689    ///
690    /// Default: inherits editor line highlights setting
691    pub current_line_highlight: Option<Option<CurrentLineHighlight>>,
692
693    /// Maximum number of columns to display in the minimap.
694    ///
695    /// Default: 80
696    pub max_width_columns: Option<num::NonZeroU32>,
697}
698
699/// Forcefully enable or disable the scrollbar for each axis
700#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
701pub struct ScrollbarAxesContent {
702    /// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
703    ///
704    /// Default: true
705    horizontal: Option<bool>,
706
707    /// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
708    ///
709    /// Default: true
710    vertical: Option<bool>,
711}
712
713/// Gutter related settings
714#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
715pub struct GutterContent {
716    /// Whether to show line numbers in the gutter.
717    ///
718    /// Default: true
719    pub line_numbers: Option<bool>,
720    /// Minimum number of characters to reserve space for in the gutter.
721    ///
722    /// Default: 4
723    pub min_line_number_digits: Option<usize>,
724    /// Whether to show runnable buttons in the gutter.
725    ///
726    /// Default: true
727    pub runnables: Option<bool>,
728    /// Whether to show breakpoints in the gutter.
729    ///
730    /// Default: true
731    pub breakpoints: Option<bool>,
732    /// Whether to show fold buttons in the gutter.
733    ///
734    /// Default: true
735    pub folds: Option<bool>,
736}
737
738impl EditorSettings {
739    pub fn jupyter_enabled(cx: &App) -> bool {
740        EditorSettings::get_global(cx).jupyter.enabled
741    }
742}
743
744impl Settings for EditorSettings {
745    const KEY: Option<&'static str> = None;
746
747    type FileContent = EditorSettingsContent;
748
749    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
750        sources.json_merge()
751    }
752
753    fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
754        vscode.enum_setting(
755            "editor.cursorBlinking",
756            &mut current.cursor_blink,
757            |s| match s {
758                "blink" | "phase" | "expand" | "smooth" => Some(true),
759                "solid" => Some(false),
760                _ => None,
761            },
762        );
763        vscode.enum_setting(
764            "editor.cursorStyle",
765            &mut current.cursor_shape,
766            |s| match s {
767                "block" => Some(CursorShape::Block),
768                "block-outline" => Some(CursorShape::Hollow),
769                "line" | "line-thin" => Some(CursorShape::Bar),
770                "underline" | "underline-thin" => Some(CursorShape::Underline),
771                _ => None,
772            },
773        );
774
775        vscode.enum_setting(
776            "editor.renderLineHighlight",
777            &mut current.current_line_highlight,
778            |s| match s {
779                "gutter" => Some(CurrentLineHighlight::Gutter),
780                "line" => Some(CurrentLineHighlight::Line),
781                "all" => Some(CurrentLineHighlight::All),
782                _ => None,
783            },
784        );
785
786        vscode.bool_setting(
787            "editor.selectionHighlight",
788            &mut current.selection_highlight,
789        );
790        vscode.bool_setting("editor.hover.enabled", &mut current.hover_popover_enabled);
791        vscode.u64_setting("editor.hover.delay", &mut current.hover_popover_delay);
792
793        let mut gutter = GutterContent::default();
794        vscode.enum_setting(
795            "editor.showFoldingControls",
796            &mut gutter.folds,
797            |s| match s {
798                "always" | "mouseover" => Some(true),
799                "never" => Some(false),
800                _ => None,
801            },
802        );
803        vscode.enum_setting(
804            "editor.lineNumbers",
805            &mut gutter.line_numbers,
806            |s| match s {
807                "on" | "relative" => Some(true),
808                "off" => Some(false),
809                _ => None,
810            },
811        );
812        if let Some(old_gutter) = current.gutter.as_mut() {
813            if gutter.folds.is_some() {
814                old_gutter.folds = gutter.folds
815            }
816            if gutter.line_numbers.is_some() {
817                old_gutter.line_numbers = gutter.line_numbers
818            }
819        } else if gutter != GutterContent::default() {
820            current.gutter = Some(gutter)
821        }
822        if let Some(b) = vscode.read_bool("editor.scrollBeyondLastLine") {
823            current.scroll_beyond_last_line = Some(if b {
824                ScrollBeyondLastLine::OnePage
825            } else {
826                ScrollBeyondLastLine::Off
827            })
828        }
829
830        let mut scrollbar_axes = ScrollbarAxesContent::default();
831        vscode.enum_setting(
832            "editor.scrollbar.horizontal",
833            &mut scrollbar_axes.horizontal,
834            |s| match s {
835                "auto" | "visible" => Some(true),
836                "hidden" => Some(false),
837                _ => None,
838            },
839        );
840        vscode.enum_setting(
841            "editor.scrollbar.vertical",
842            &mut scrollbar_axes.horizontal,
843            |s| match s {
844                "auto" | "visible" => Some(true),
845                "hidden" => Some(false),
846                _ => None,
847            },
848        );
849
850        if scrollbar_axes != ScrollbarAxesContent::default() {
851            let scrollbar_settings = current.scrollbar.get_or_insert_default();
852            let axes_settings = scrollbar_settings.axes.get_or_insert_default();
853
854            if let Some(vertical) = scrollbar_axes.vertical {
855                axes_settings.vertical = Some(vertical);
856            }
857            if let Some(horizontal) = scrollbar_axes.horizontal {
858                axes_settings.horizontal = Some(horizontal);
859            }
860        }
861
862        // TODO: check if this does the int->float conversion?
863        vscode.f32_setting(
864            "editor.cursorSurroundingLines",
865            &mut current.vertical_scroll_margin,
866        );
867        vscode.f32_setting(
868            "editor.mouseWheelScrollSensitivity",
869            &mut current.scroll_sensitivity,
870        );
871        vscode.f32_setting(
872            "editor.fastScrollSensitivity",
873            &mut current.fast_scroll_sensitivity,
874        );
875        if Some("relative") == vscode.read_string("editor.lineNumbers") {
876            current.relative_line_numbers = Some(true);
877        }
878
879        vscode.enum_setting(
880            "editor.find.seedSearchStringFromSelection",
881            &mut current.seed_search_query_from_cursor,
882            |s| match s {
883                "always" => Some(SeedQuerySetting::Always),
884                "selection" => Some(SeedQuerySetting::Selection),
885                "never" => Some(SeedQuerySetting::Never),
886                _ => None,
887            },
888        );
889        vscode.bool_setting("search.smartCase", &mut current.use_smartcase_search);
890        vscode.enum_setting(
891            "editor.multiCursorModifier",
892            &mut current.multi_cursor_modifier,
893            |s| match s {
894                "ctrlCmd" => Some(MultiCursorModifier::CmdOrCtrl),
895                "alt" => Some(MultiCursorModifier::Alt),
896                _ => None,
897            },
898        );
899
900        vscode.bool_setting(
901            "editor.parameterHints.enabled",
902            &mut current.auto_signature_help,
903        );
904        vscode.bool_setting(
905            "editor.parameterHints.enabled",
906            &mut current.show_signature_help_after_edits,
907        );
908
909        if let Some(use_ignored) = vscode.read_bool("search.useIgnoreFiles") {
910            let search = current.search.get_or_insert_default();
911            search.include_ignored = use_ignored;
912        }
913
914        let mut minimap = MinimapContent::default();
915        let minimap_enabled = vscode.read_bool("editor.minimap.enabled").unwrap_or(true);
916        let autohide = vscode.read_bool("editor.minimap.autohide");
917        let mut max_width_columns: Option<u32> = None;
918        vscode.u32_setting("editor.minimap.maxColumn", &mut max_width_columns);
919        if minimap_enabled {
920            if let Some(false) = autohide {
921                minimap.show = Some(ShowMinimap::Always);
922            } else {
923                minimap.show = Some(ShowMinimap::Auto);
924            }
925        } else {
926            minimap.show = Some(ShowMinimap::Never);
927        }
928        if let Some(max_width_columns) = max_width_columns {
929            minimap.max_width_columns = NonZeroU32::new(max_width_columns);
930        }
931
932        vscode.enum_setting(
933            "editor.minimap.showSlider",
934            &mut minimap.thumb,
935            |s| match s {
936                "always" => Some(MinimapThumb::Always),
937                "mouseover" => Some(MinimapThumb::Hover),
938                _ => None,
939            },
940        );
941
942        if minimap != MinimapContent::default() {
943            current.minimap = Some(minimap)
944        }
945    }
946}