editor_settings.rs

  1use gpui::AppContext;
  2use language::CursorShape;
  3use schemars::JsonSchema;
  4use serde::{Deserialize, Serialize};
  5use settings::{Settings, SettingsSources};
  6
  7#[derive(Deserialize, Clone)]
  8pub struct EditorSettings {
  9    pub cursor_blink: bool,
 10    pub cursor_shape: Option<CursorShape>,
 11    pub current_line_highlight: CurrentLineHighlight,
 12    pub hover_popover_enabled: bool,
 13    pub toolbar: Toolbar,
 14    pub scrollbar: Scrollbar,
 15    pub gutter: Gutter,
 16    pub scroll_beyond_last_line: ScrollBeyondLastLine,
 17    pub vertical_scroll_margin: f32,
 18    pub autoscroll_on_clicks: bool,
 19    pub scroll_sensitivity: f32,
 20    pub relative_line_numbers: bool,
 21    pub seed_search_query_from_cursor: SeedQuerySetting,
 22    pub use_smartcase_search: bool,
 23    pub multi_cursor_modifier: MultiCursorModifier,
 24    pub redact_private_values: bool,
 25    pub expand_excerpt_lines: u32,
 26    pub middle_click_paste: bool,
 27    #[serde(default)]
 28    pub double_click_in_multibuffer: DoubleClickInMultibuffer,
 29    pub search_wrap: bool,
 30    #[serde(default)]
 31    pub search: SearchSettings,
 32    pub auto_signature_help: bool,
 33    pub show_signature_help_after_edits: bool,
 34    pub jupyter: Jupyter,
 35}
 36
 37#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 38#[serde(rename_all = "snake_case")]
 39pub enum CurrentLineHighlight {
 40    // Don't highlight the current line.
 41    None,
 42    // Highlight the gutter area.
 43    Gutter,
 44    // Highlight the editor area.
 45    Line,
 46    // Highlight the full line.
 47    All,
 48}
 49
 50/// When to populate a new search's query based on the text under the cursor.
 51#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 52#[serde(rename_all = "snake_case")]
 53pub enum SeedQuerySetting {
 54    /// Always populate the search query with the word under the cursor.
 55    Always,
 56    /// Only populate the search query when there is text selected.
 57    Selection,
 58    /// Never populate the search query
 59    Never,
 60}
 61
 62/// What to do when multibuffer is double clicked in some of its excerpts (parts of singleton buffers).
 63#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 64#[serde(rename_all = "snake_case")]
 65pub enum DoubleClickInMultibuffer {
 66    /// Behave as a regular buffer and select the whole word.
 67    #[default]
 68    Select,
 69    /// Open the excerpt clicked as a new buffer in the new tab, if no `alt` modifier was pressed during double click.
 70    /// Otherwise, behave as a regular buffer and select the whole word.
 71    Open,
 72}
 73
 74#[derive(Debug, Clone, Deserialize)]
 75pub struct Jupyter {
 76    /// Whether the Jupyter feature is enabled.
 77    ///
 78    /// Default: true
 79    pub enabled: bool,
 80}
 81
 82#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 83#[serde(rename_all = "snake_case")]
 84pub struct JupyterContent {
 85    /// Whether the Jupyter feature is enabled.
 86    ///
 87    /// Default: true
 88    pub enabled: Option<bool>,
 89}
 90
 91#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
 92pub struct Toolbar {
 93    pub breadcrumbs: bool,
 94    pub quick_actions: bool,
 95    pub selections_menu: bool,
 96}
 97
 98#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
 99pub struct Scrollbar {
100    pub show: ShowScrollbar,
101    pub git_diff: bool,
102    pub selected_symbol: bool,
103    pub search_results: bool,
104    pub diagnostics: bool,
105    pub cursors: bool,
106}
107
108#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
109pub struct Gutter {
110    pub line_numbers: bool,
111    pub code_actions: bool,
112    pub runnables: bool,
113    pub folds: bool,
114}
115
116/// When to show the scrollbar in the editor.
117///
118/// Default: auto
119#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
120#[serde(rename_all = "snake_case")]
121pub enum ShowScrollbar {
122    /// Show the scrollbar if there's important information or
123    /// follow the system's configured behavior.
124    Auto,
125    /// Match the system's configured behavior.
126    System,
127    /// Always show the scrollbar.
128    Always,
129    /// Never show the scrollbar.
130    Never,
131}
132
133/// The key to use for adding multiple cursors
134///
135/// Default: alt
136#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
137#[serde(rename_all = "snake_case")]
138pub enum MultiCursorModifier {
139    Alt,
140    #[serde(alias = "cmd", alias = "ctrl")]
141    CmdOrCtrl,
142}
143
144/// Whether the editor will scroll beyond the last line.
145///
146/// Default: one_page
147#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
148#[serde(rename_all = "snake_case")]
149pub enum ScrollBeyondLastLine {
150    /// The editor will not scroll beyond the last line.
151    Off,
152
153    /// The editor will scroll beyond the last line by one page.
154    OnePage,
155
156    /// The editor will scroll beyond the last line by the same number of lines as vertical_scroll_margin.
157    VerticalScrollMargin,
158}
159
160/// Default options for buffer and project search items.
161#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
162pub struct SearchSettings {
163    #[serde(default)]
164    pub whole_word: bool,
165    #[serde(default)]
166    pub case_sensitive: bool,
167    #[serde(default)]
168    pub include_ignored: bool,
169    #[serde(default)]
170    pub regex: bool,
171}
172
173#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
174pub struct EditorSettingsContent {
175    /// Whether the cursor blinks in the editor.
176    ///
177    /// Default: true
178    pub cursor_blink: Option<bool>,
179    /// Cursor shape for the default editor.
180    /// Can be "bar", "block", "underline", or "hollow".
181    ///
182    /// Default: None
183    pub cursor_shape: Option<CursorShape>,
184    /// How to highlight the current line in the editor.
185    ///
186    /// Default: all
187    pub current_line_highlight: Option<CurrentLineHighlight>,
188    /// Whether to show the informational hover box when moving the mouse
189    /// over symbols in the editor.
190    ///
191    /// Default: true
192    pub hover_popover_enabled: Option<bool>,
193
194    /// Toolbar related settings
195    pub toolbar: Option<ToolbarContent>,
196    /// Scrollbar related settings
197    pub scrollbar: Option<ScrollbarContent>,
198    /// Gutter related settings
199    pub gutter: Option<GutterContent>,
200    /// Whether the editor will scroll beyond the last line.
201    ///
202    /// Default: one_page
203    pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
204    /// The number of lines to keep above/below the cursor when auto-scrolling.
205    ///
206    /// Default: 3.
207    pub vertical_scroll_margin: Option<f32>,
208    /// Whether to scroll when clicking near the edge of the visible text area.
209    ///
210    /// Default: false
211    pub autoscroll_on_clicks: Option<bool>,
212    /// Scroll sensitivity multiplier. This multiplier is applied
213    /// to both the horizontal and vertical delta values while scrolling.
214    ///
215    /// Default: 1.0
216    pub scroll_sensitivity: Option<f32>,
217    /// Whether the line numbers on editors gutter are relative or not.
218    ///
219    /// Default: false
220    pub relative_line_numbers: Option<bool>,
221    /// When to populate a new search's query based on the text under the cursor.
222    ///
223    /// Default: always
224    pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
225    pub use_smartcase_search: Option<bool>,
226    /// The key to use for adding multiple cursors
227    ///
228    /// Default: alt
229    pub multi_cursor_modifier: Option<MultiCursorModifier>,
230    /// Hide the values of variables in `private` files, as defined by the
231    /// private_files setting. This only changes the visual representation,
232    /// the values are still present in the file and can be selected / copied / pasted
233    ///
234    /// Default: false
235    pub redact_private_values: Option<bool>,
236
237    /// How many lines to expand the multibuffer excerpts by default
238    ///
239    /// Default: 3
240    pub expand_excerpt_lines: Option<u32>,
241
242    /// Whether to enable middle-click paste on Linux
243    ///
244    /// Default: true
245    pub middle_click_paste: Option<bool>,
246
247    /// What to do when multibuffer is double clicked in some of its excerpts
248    /// (parts of singleton buffers).
249    ///
250    /// Default: select
251    pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
252    /// Whether the editor search results will loop
253    ///
254    /// Default: true
255    pub search_wrap: Option<bool>,
256
257    /// Defaults to use when opening a new buffer and project search items.
258    ///
259    /// Default: nothing is enabled
260    pub search: Option<SearchSettings>,
261
262    /// Whether to automatically show a signature help pop-up or not.
263    ///
264    /// Default: false
265    pub auto_signature_help: Option<bool>,
266
267    /// Whether to show the signature help pop-up after completions or bracket pairs inserted.
268    ///
269    /// Default: false
270    pub show_signature_help_after_edits: Option<bool>,
271
272    /// Jupyter REPL settings.
273    pub jupyter: Option<JupyterContent>,
274}
275
276// Toolbar related settings
277#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
278pub struct ToolbarContent {
279    /// Whether to display breadcrumbs in the editor toolbar.
280    ///
281    /// Default: true
282    pub breadcrumbs: Option<bool>,
283    /// Whether to display quick action buttons in the editor toolbar.
284    ///
285    /// Default: true
286    pub quick_actions: Option<bool>,
287
288    /// Whether to show the selections menu in the editor toolbar
289    ///
290    /// Default: true
291    pub selections_menu: Option<bool>,
292}
293
294/// Scrollbar related settings
295#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
296pub struct ScrollbarContent {
297    /// When to show the scrollbar in the editor.
298    ///
299    /// Default: auto
300    pub show: Option<ShowScrollbar>,
301    /// Whether to show git diff indicators in the scrollbar.
302    ///
303    /// Default: true
304    pub git_diff: Option<bool>,
305    /// Whether to show buffer search result indicators in the scrollbar.
306    ///
307    /// Default: true
308    pub search_results: Option<bool>,
309    /// Whether to show selected symbol occurrences in the scrollbar.
310    ///
311    /// Default: true
312    pub selected_symbol: Option<bool>,
313    /// Whether to show diagnostic indicators in the scrollbar.
314    ///
315    /// Default: true
316    pub diagnostics: Option<bool>,
317    /// Whether to show cursor positions in the scrollbar.
318    ///
319    /// Default: true
320    pub cursors: Option<bool>,
321}
322
323/// Gutter related settings
324#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
325pub struct GutterContent {
326    /// Whether to show line numbers in the gutter.
327    ///
328    /// Default: true
329    pub line_numbers: Option<bool>,
330    /// Whether to show code action buttons in the gutter.
331    ///
332    /// Default: true
333    pub code_actions: Option<bool>,
334    /// Whether to show runnable buttons in the gutter.
335    ///
336    /// Default: true
337    pub runnables: Option<bool>,
338    /// Whether to show fold buttons in the gutter.
339    ///
340    /// Default: true
341    pub folds: Option<bool>,
342}
343
344impl EditorSettings {
345    pub fn jupyter_enabled(cx: &AppContext) -> bool {
346        EditorSettings::get_global(cx).jupyter.enabled
347    }
348}
349
350impl Settings for EditorSettings {
351    const KEY: Option<&'static str> = None;
352
353    type FileContent = EditorSettingsContent;
354
355    fn load(
356        sources: SettingsSources<Self::FileContent>,
357        _: &mut AppContext,
358    ) -> anyhow::Result<Self> {
359        sources.json_merge()
360    }
361}