editor_settings.rs

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