diff --git a/assets/settings/default.json b/assets/settings/default.json index 4c4732ccb0..a5be294a22 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -154,6 +154,10 @@ // 4. Highlight the full line (default): // "all" "current_line_highlight": "all", + // Whether to highlight all occurrences of the selected text in an editor. + "selection_highlight": true, + // The debounce delay before querying highlights based on the selected text. + "selection_highlight_debounce": 50, // The debounce delay before querying highlights from the language // server based on the current cursor location. "lsp_highlight_debounce": 75, @@ -259,6 +263,8 @@ "git_diff": true, // Whether to show buffer search results in the scrollbar. "search_results": true, + // Whether to show selected text occurrences in the scrollbar. + "selected_text": true, // Whether to show selected symbol occurrences in the scrollbar. "selected_symbol": true, // Which diagnostic indicators to show in the scrollbar: diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 3f6c1b154c..c927b16948 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -283,6 +283,7 @@ impl InlayId { enum DocumentHighlightRead {} enum DocumentHighlightWrite {} enum InputComposition {} +enum SelectedTextHighlight {} #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Navigated { @@ -681,6 +682,7 @@ pub struct Editor { next_completion_id: CompletionId, available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>, code_actions_task: Option>>, + selection_highlight_task: Option>, document_highlights_task: Option>, linked_editing_range_task: Option>>, linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges, @@ -1384,6 +1386,7 @@ impl Editor { code_action_providers, available_code_actions: Default::default(), code_actions_task: Default::default(), + selection_highlight_task: Default::default(), document_highlights_task: Default::default(), linked_editing_range_task: Default::default(), pending_rename: Default::default(), @@ -2165,6 +2168,7 @@ impl Editor { } self.refresh_code_actions(window, cx); self.refresh_document_highlights(cx); + self.refresh_selected_text_highlights(window, cx); refresh_matching_bracket_highlights(self, window, cx); self.update_visible_inline_completion(window, cx); self.edit_prediction_requires_modifier_in_leading_space = true; @@ -4722,6 +4726,93 @@ impl Editor { None } + pub fn refresh_selected_text_highlights( + &mut self, + window: &mut Window, + cx: &mut Context, + ) { + self.selection_highlight_task.take(); + if !EditorSettings::get_global(cx).selection_highlight { + self.clear_background_highlights::(cx); + return; + } + if self.selections.count() != 1 || self.selections.line_mode { + self.clear_background_highlights::(cx); + return; + } + let selection = self.selections.newest::(cx); + if selection.is_empty() || selection.start.row != selection.end.row { + self.clear_background_highlights::(cx); + return; + } + let debounce = EditorSettings::get_global(cx).selection_highlight_debounce; + self.selection_highlight_task = Some(cx.spawn_in(window, |editor, mut cx| async move { + cx.background_executor() + .timer(Duration::from_millis(debounce)) + .await; + let Some(matches_task) = editor + .read_with(&mut cx, |editor, cx| { + let buffer = editor.buffer().read(cx).snapshot(cx); + cx.background_executor().spawn(async move { + let mut ranges = Vec::new(); + let buffer_ranges = + vec![buffer.anchor_before(0)..buffer.anchor_after(buffer.len())]; + let query = buffer.text_for_range(selection.range()).collect::(); + for range in buffer_ranges { + for (search_buffer, search_range, excerpt_id) in + buffer.range_to_buffer_ranges(range) + { + ranges.extend( + project::search::SearchQuery::text( + query.clone(), + false, + false, + false, + Default::default(), + Default::default(), + None, + ) + .unwrap() + .search(search_buffer, Some(search_range.clone())) + .await + .into_iter() + .map(|match_range| { + let start = search_buffer + .anchor_after(search_range.start + match_range.start); + let end = search_buffer + .anchor_before(search_range.start + match_range.end); + Anchor::range_in_buffer( + excerpt_id, + search_buffer.remote_id(), + start..end, + ) + }), + ); + } + } + ranges + }) + }) + .log_err() + else { + return; + }; + let matches = matches_task.await; + editor + .update_in(&mut cx, |editor, _, cx| { + editor.clear_background_highlights::(cx); + if !matches.is_empty() { + editor.highlight_background::( + &matches, + |theme| theme.editor_document_highlight_bracket_background, + cx, + ) + } + }) + .log_err(); + })); + } + pub fn refresh_inline_completion( &mut self, debounce: bool, diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 73966f4452..dbf0bb5cd0 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -9,6 +9,8 @@ pub struct EditorSettings { pub cursor_blink: bool, pub cursor_shape: Option, pub current_line_highlight: CurrentLineHighlight, + pub selection_highlight: bool, + pub selection_highlight_debounce: u64, pub lsp_highlight_debounce: u64, pub hover_popover_enabled: bool, pub hover_popover_delay: u64, @@ -102,6 +104,7 @@ pub struct Toolbar { pub struct Scrollbar { pub show: ShowScrollbar, pub git_diff: bool, + pub selected_text: bool, pub selected_symbol: bool, pub search_results: bool, pub diagnostics: ScrollbarDiagnostics, @@ -271,6 +274,14 @@ pub struct EditorSettingsContent { /// /// Default: all pub current_line_highlight: Option, + /// Whether to highlight all occurrences of the selected text in an editor. + /// + /// Default: true + pub selection_highlight: Option, + /// The debounce delay before querying highlights based on the selected text. + /// + /// Default: 75 + pub selection_highlight_debounce: Option, /// The debounce delay before querying highlights from the language /// server based on the current cursor location. /// @@ -404,6 +415,10 @@ pub struct ScrollbarContent { /// /// Default: true pub search_results: Option, + /// Whether to show selected text occurrences in the scrollbar. + /// + /// Default: true + pub selected_text: Option, /// Whether to show selected symbol occurrences in the scrollbar. /// /// Default: true diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 52c937f2c7..805ce47ef2 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -20,8 +20,8 @@ use crate::{ EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, InlineCompletion, JumpData, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RevertSelectedHunks, RowExt, - RowRangeExt, SelectPhase, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, - ToggleStagedSelectedDiffHunks, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, + RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt, + ToPoint, ToggleFold, ToggleStagedSelectedDiffHunks, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, }; use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus}; @@ -1296,6 +1296,9 @@ impl EditorElement { // Buffer Search Results (is_singleton && scrollbar_settings.search_results && editor.has_background_highlights::()) || + // Selected Text Occurrences + (is_singleton && scrollbar_settings.selected_text && editor.has_background_highlights::()) + || // Selected Symbol Occurrences (is_singleton && scrollbar_settings.selected_symbol && (editor.has_background_highlights::() || editor.has_background_highlights::())) || @@ -5439,11 +5442,14 @@ impl EditorElement { { let is_search_highlights = *background_highlight_id == TypeId::of::(); + let is_text_highlights = *background_highlight_id + == TypeId::of::(); let is_symbol_occurrences = *background_highlight_id == TypeId::of::() || *background_highlight_id == TypeId::of::(); if (is_search_highlights && scrollbar_settings.search_results) + || (is_text_highlights && scrollbar_settings.selected_text) || (is_symbol_occurrences && scrollbar_settings.selected_symbol) { let mut color = theme.status().info; diff --git a/docs/src/configuring-zed.md b/docs/src/configuring-zed.md index e1817cca02..aecdb92198 100644 --- a/docs/src/configuring-zed.md +++ b/docs/src/configuring-zed.md @@ -472,6 +472,19 @@ List of `string` values "current_line_highlight": "all" ``` +## Selection Highlight + +- Description: Whether to highlight all occurrences of the selected text in an editor. +- Setting: `selection_highlight` +- Default: `true` + +## Selection Highlight Debounce + +- Description: The debounce delay before querying highlights based on the selected text. + +- Setting: `selection_highlight_debounce` +- Default: `75` + ## LSP Highlight Debounce - Description: The debounce delay before querying highlights from the language server based on the current cursor location. @@ -532,6 +545,7 @@ List of `string` values "cursors": true, "git_diff": true, "search_results": true, + "selected_text": true, "selected_symbol": true, "diagnostics": "all", "axes": { @@ -611,6 +625,16 @@ List of `string` values `boolean` values +### Selected Text Indicators + +- Description: Whether to show selected text occurrences in the scrollbar. +- Setting: `selected_text` +- Default: `true` + +**Options** + +`boolean` values + ### Selected Symbols Indicators - Description: Whether to show selected symbol occurrences in the scrollbar.