1use core::num;
  2
  3use gpui::App;
  4use language::CursorShape;
  5use project::project_settings::DiagnosticSeverity;
  6use settings::Settings;
  7pub use settings::{
  8    CurrentLineHighlight, DelayMs, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer,
  9    GoToDefinitionFallback, HideMouseMode, MinimapThumb, MinimapThumbBorder, MultiCursorModifier,
 10    ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
 11};
 12use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
 13
 14/// Imports from the VSCode settings at
 15/// https://code.visualstudio.com/docs/reference/default-settings
 16#[derive(Clone)]
 17pub struct EditorSettings {
 18    pub cursor_blink: bool,
 19    pub cursor_shape: Option<CursorShape>,
 20    pub current_line_highlight: CurrentLineHighlight,
 21    pub selection_highlight: bool,
 22    pub rounded_selection: bool,
 23    pub lsp_highlight_debounce: DelayMs,
 24    pub hover_popover_enabled: bool,
 25    pub hover_popover_delay: DelayMs,
 26    pub toolbar: Toolbar,
 27    pub scrollbar: Scrollbar,
 28    pub minimap: Minimap,
 29    pub gutter: Gutter,
 30    pub scroll_beyond_last_line: ScrollBeyondLastLine,
 31    pub vertical_scroll_margin: f64,
 32    pub autoscroll_on_clicks: bool,
 33    pub horizontal_scroll_margin: f32,
 34    pub scroll_sensitivity: f32,
 35    pub fast_scroll_sensitivity: f32,
 36    pub relative_line_numbers: bool,
 37    pub seed_search_query_from_cursor: SeedQuerySetting,
 38    pub use_smartcase_search: bool,
 39    pub multi_cursor_modifier: MultiCursorModifier,
 40    pub redact_private_values: bool,
 41    pub expand_excerpt_lines: u32,
 42    pub excerpt_context_lines: u32,
 43    pub middle_click_paste: bool,
 44    pub double_click_in_multibuffer: DoubleClickInMultibuffer,
 45    pub search_wrap: bool,
 46    pub search: SearchSettings,
 47    pub auto_signature_help: bool,
 48    pub show_signature_help_after_edits: bool,
 49    pub go_to_definition_fallback: GoToDefinitionFallback,
 50    pub jupyter: Jupyter,
 51    pub hide_mouse: Option<HideMouseMode>,
 52    pub snippet_sort_order: SnippetSortOrder,
 53    pub diagnostics_max_severity: Option<DiagnosticSeverity>,
 54    pub inline_code_actions: bool,
 55    pub drag_and_drop_selection: DragAndDropSelection,
 56    pub lsp_document_colors: DocumentColorsRenderMode,
 57    pub minimum_contrast_for_highlights: f32,
 58    pub completion_menu_scrollbar: ShowScrollbar,
 59}
 60#[derive(Debug, Clone)]
 61pub struct Jupyter {
 62    /// Whether the Jupyter feature is enabled.
 63    ///
 64    /// Default: true
 65    pub enabled: bool,
 66}
 67
 68#[derive(Clone, Debug, PartialEq, Eq)]
 69pub struct Toolbar {
 70    pub breadcrumbs: bool,
 71    pub quick_actions: bool,
 72    pub selections_menu: bool,
 73    pub agent_review: bool,
 74    pub code_actions: bool,
 75}
 76
 77#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 78pub struct Scrollbar {
 79    pub show: ShowScrollbar,
 80    pub git_diff: bool,
 81    pub selected_text: bool,
 82    pub selected_symbol: bool,
 83    pub search_results: bool,
 84    pub diagnostics: ScrollbarDiagnostics,
 85    pub cursors: bool,
 86    pub axes: ScrollbarAxes,
 87}
 88
 89#[derive(Copy, Clone, Debug, PartialEq)]
 90pub struct Minimap {
 91    pub show: ShowMinimap,
 92    pub display_in: DisplayIn,
 93    pub thumb: MinimapThumb,
 94    pub thumb_border: MinimapThumbBorder,
 95    pub current_line_highlight: Option<CurrentLineHighlight>,
 96    pub max_width_columns: num::NonZeroU32,
 97}
 98
 99impl Minimap {
100    pub fn minimap_enabled(&self) -> bool {
101        self.show != ShowMinimap::Never
102    }
103
104    #[inline]
105    pub fn on_active_editor(&self) -> bool {
106        self.display_in == DisplayIn::ActiveEditor
107    }
108
109    pub fn with_show_override(self) -> Self {
110        Self {
111            show: ShowMinimap::Always,
112            ..self
113        }
114    }
115}
116
117#[derive(Copy, Clone, Debug, PartialEq, Eq)]
118pub struct Gutter {
119    pub min_line_number_digits: usize,
120    pub line_numbers: bool,
121    pub runnables: bool,
122    pub breakpoints: bool,
123    pub folds: bool,
124}
125
126/// Forcefully enable or disable the scrollbar for each axis
127#[derive(Copy, Clone, Debug, PartialEq, Eq)]
128pub struct ScrollbarAxes {
129    /// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
130    ///
131    /// Default: true
132    pub horizontal: bool,
133
134    /// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
135    ///
136    /// Default: true
137    pub vertical: bool,
138}
139
140/// Whether to allow drag and drop text selection in buffer.
141#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
142pub struct DragAndDropSelection {
143    /// When true, enables drag and drop text selection in buffer.
144    ///
145    /// Default: true
146    pub enabled: bool,
147
148    /// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
149    ///
150    /// Default: 300
151    pub delay: DelayMs,
152}
153
154/// Default options for buffer and project search items.
155#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
156pub struct SearchSettings {
157    /// Whether to show the project search button in the status bar.
158    pub button: bool,
159    pub whole_word: bool,
160    pub case_sensitive: bool,
161    pub include_ignored: bool,
162    pub regex: bool,
163    pub center_on_match: bool,
164}
165
166impl EditorSettings {
167    pub fn jupyter_enabled(cx: &App) -> bool {
168        EditorSettings::get_global(cx).jupyter.enabled
169    }
170}
171
172impl ScrollbarVisibility for EditorSettings {
173    fn visibility(&self, _cx: &App) -> ShowScrollbar {
174        self.scrollbar.show
175    }
176}
177
178impl Settings for EditorSettings {
179    fn from_settings(content: &settings::SettingsContent) -> Self {
180        let editor = content.editor.clone();
181        let scrollbar = editor.scrollbar.unwrap();
182        let minimap = editor.minimap.unwrap();
183        let gutter = editor.gutter.unwrap();
184        let axes = scrollbar.axes.unwrap();
185        let toolbar = editor.toolbar.unwrap();
186        let search = editor.search.unwrap();
187        let drag_and_drop_selection = editor.drag_and_drop_selection.unwrap();
188        Self {
189            cursor_blink: editor.cursor_blink.unwrap(),
190            cursor_shape: editor.cursor_shape.map(Into::into),
191            current_line_highlight: editor.current_line_highlight.unwrap(),
192            selection_highlight: editor.selection_highlight.unwrap(),
193            rounded_selection: editor.rounded_selection.unwrap(),
194            lsp_highlight_debounce: editor.lsp_highlight_debounce.unwrap(),
195            hover_popover_enabled: editor.hover_popover_enabled.unwrap(),
196            hover_popover_delay: editor.hover_popover_delay.unwrap(),
197            toolbar: Toolbar {
198                breadcrumbs: toolbar.breadcrumbs.unwrap(),
199                quick_actions: toolbar.quick_actions.unwrap(),
200                selections_menu: toolbar.selections_menu.unwrap(),
201                agent_review: toolbar.agent_review.unwrap(),
202                code_actions: toolbar.code_actions.unwrap(),
203            },
204            scrollbar: Scrollbar {
205                show: scrollbar.show.map(Into::into).unwrap(),
206                git_diff: scrollbar.git_diff.unwrap(),
207                selected_text: scrollbar.selected_text.unwrap(),
208                selected_symbol: scrollbar.selected_symbol.unwrap(),
209                search_results: scrollbar.search_results.unwrap(),
210                diagnostics: scrollbar.diagnostics.unwrap(),
211                cursors: scrollbar.cursors.unwrap(),
212                axes: ScrollbarAxes {
213                    horizontal: axes.horizontal.unwrap(),
214                    vertical: axes.vertical.unwrap(),
215                },
216            },
217            minimap: Minimap {
218                show: minimap.show.unwrap(),
219                display_in: minimap.display_in.unwrap(),
220                thumb: minimap.thumb.unwrap(),
221                thumb_border: minimap.thumb_border.unwrap(),
222                current_line_highlight: minimap.current_line_highlight,
223                max_width_columns: minimap.max_width_columns.unwrap(),
224            },
225            gutter: Gutter {
226                min_line_number_digits: gutter.min_line_number_digits.unwrap(),
227                line_numbers: gutter.line_numbers.unwrap(),
228                runnables: gutter.runnables.unwrap(),
229                breakpoints: gutter.breakpoints.unwrap(),
230                folds: gutter.folds.unwrap(),
231            },
232            scroll_beyond_last_line: editor.scroll_beyond_last_line.unwrap(),
233            vertical_scroll_margin: editor.vertical_scroll_margin.unwrap() as f64,
234            autoscroll_on_clicks: editor.autoscroll_on_clicks.unwrap(),
235            horizontal_scroll_margin: editor.horizontal_scroll_margin.unwrap(),
236            scroll_sensitivity: editor.scroll_sensitivity.unwrap(),
237            fast_scroll_sensitivity: editor.fast_scroll_sensitivity.unwrap(),
238            relative_line_numbers: editor.relative_line_numbers.unwrap(),
239            seed_search_query_from_cursor: editor.seed_search_query_from_cursor.unwrap(),
240            use_smartcase_search: editor.use_smartcase_search.unwrap(),
241            multi_cursor_modifier: editor.multi_cursor_modifier.unwrap(),
242            redact_private_values: editor.redact_private_values.unwrap(),
243            expand_excerpt_lines: editor.expand_excerpt_lines.unwrap(),
244            excerpt_context_lines: editor.excerpt_context_lines.unwrap(),
245            middle_click_paste: editor.middle_click_paste.unwrap(),
246            double_click_in_multibuffer: editor.double_click_in_multibuffer.unwrap(),
247            search_wrap: editor.search_wrap.unwrap(),
248            search: SearchSettings {
249                button: search.button.unwrap(),
250                whole_word: search.whole_word.unwrap(),
251                case_sensitive: search.case_sensitive.unwrap(),
252                include_ignored: search.include_ignored.unwrap(),
253                regex: search.regex.unwrap(),
254                center_on_match: search.center_on_match.unwrap(),
255            },
256            auto_signature_help: editor.auto_signature_help.unwrap(),
257            show_signature_help_after_edits: editor.show_signature_help_after_edits.unwrap(),
258            go_to_definition_fallback: editor.go_to_definition_fallback.unwrap(),
259            jupyter: Jupyter {
260                enabled: editor.jupyter.unwrap().enabled.unwrap(),
261            },
262            hide_mouse: editor.hide_mouse,
263            snippet_sort_order: editor.snippet_sort_order.unwrap(),
264            diagnostics_max_severity: editor.diagnostics_max_severity.map(Into::into),
265            inline_code_actions: editor.inline_code_actions.unwrap(),
266            drag_and_drop_selection: DragAndDropSelection {
267                enabled: drag_and_drop_selection.enabled.unwrap(),
268                delay: drag_and_drop_selection.delay.unwrap(),
269            },
270            lsp_document_colors: editor.lsp_document_colors.unwrap(),
271            minimum_contrast_for_highlights: editor.minimum_contrast_for_highlights.unwrap().0,
272            completion_menu_scrollbar: editor.completion_menu_scrollbar.map(Into::into).unwrap(),
273        }
274    }
275}