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