
Refs #9647 Fixes https://github.com/zed-industries/zed/issues/9792 This pull request moves the computation of scrollbar markers off the main thread, to prevent them from grinding the editor to a halt when we have a lot of them (e.g., when there are lots of search results on a large file). With these changes we also avoid generating multiple quads for adjacent markers, thus fixing an issue where we stop drawing other primitives because we've drawn too many quads in the scrollbar. Release Notes: - Improved editor performance when displaying lots of search results, diagnostics, or symbol highlights in the scrollbar ([#9792](https://github.com/zed-industries/zed/issues/9792)). --------- Co-authored-by: Antonio Scandurra <me@as-cii.com> Co-authored-by: Nathan <nathan@zed.dev>
128 lines
4.1 KiB
Rust
128 lines
4.1 KiB
Rust
use std::time::Duration;
|
|
|
|
use editor::{ClipboardSelection, Editor};
|
|
use gpui::{ClipboardItem, ViewContext};
|
|
use language::{CharKind, Point};
|
|
use settings::Settings;
|
|
|
|
use crate::{state::Mode, UseSystemClipboard, Vim, VimSettings};
|
|
|
|
pub struct HighlightOnYank;
|
|
|
|
pub fn yank_selections_content(
|
|
vim: &mut Vim,
|
|
editor: &mut Editor,
|
|
linewise: bool,
|
|
cx: &mut ViewContext<Editor>,
|
|
) {
|
|
copy_selections_content_internal(vim, editor, linewise, true, cx);
|
|
}
|
|
|
|
pub fn copy_selections_content(
|
|
vim: &mut Vim,
|
|
editor: &mut Editor,
|
|
linewise: bool,
|
|
cx: &mut ViewContext<Editor>,
|
|
) {
|
|
copy_selections_content_internal(vim, editor, linewise, false, cx);
|
|
}
|
|
|
|
fn copy_selections_content_internal(
|
|
vim: &mut Vim,
|
|
editor: &mut Editor,
|
|
linewise: bool,
|
|
is_yank: bool,
|
|
cx: &mut ViewContext<Editor>,
|
|
) {
|
|
let selections = editor.selections.all_adjusted(cx);
|
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
|
let mut text = String::new();
|
|
let mut clipboard_selections = Vec::with_capacity(selections.len());
|
|
let mut ranges_to_highlight = Vec::new();
|
|
{
|
|
let mut is_first = true;
|
|
for selection in selections.iter() {
|
|
let mut start = selection.start;
|
|
let end = selection.end;
|
|
if is_first {
|
|
is_first = false;
|
|
} else {
|
|
text.push_str("\n");
|
|
}
|
|
let initial_len = text.len();
|
|
|
|
// if the file does not end with \n, and our line-mode selection ends on
|
|
// that line, we will have expanded the start of the selection to ensure it
|
|
// contains a newline (so that delete works as expected). We undo that change
|
|
// here.
|
|
let is_last_line = linewise
|
|
&& end.row == buffer.max_buffer_row()
|
|
&& buffer.max_point().column > 0
|
|
&& start.row < buffer.max_buffer_row()
|
|
&& start == Point::new(start.row, buffer.line_len(start.row));
|
|
|
|
if is_last_line {
|
|
start = Point::new(start.row + 1, 0);
|
|
}
|
|
|
|
let start_anchor = buffer.anchor_after(start);
|
|
let end_anchor = buffer.anchor_before(end);
|
|
ranges_to_highlight.push(start_anchor..end_anchor);
|
|
|
|
for chunk in buffer.text_for_range(start..end) {
|
|
text.push_str(chunk);
|
|
}
|
|
if is_last_line {
|
|
text.push_str("\n");
|
|
}
|
|
clipboard_selections.push(ClipboardSelection {
|
|
len: text.len() - initial_len,
|
|
is_entire_line: linewise,
|
|
first_line_indent: buffer.indent_size_for_line(start.row).len,
|
|
});
|
|
}
|
|
}
|
|
|
|
let setting = VimSettings::get_global(cx).use_system_clipboard;
|
|
if setting == UseSystemClipboard::Always || setting == UseSystemClipboard::OnYank && is_yank {
|
|
cx.write_to_clipboard(ClipboardItem::new(text.clone()).with_metadata(clipboard_selections));
|
|
vim.workspace_state
|
|
.registers
|
|
.insert(".system.".to_string(), text.clone());
|
|
} else {
|
|
vim.workspace_state.registers.insert(
|
|
".system.".to_string(),
|
|
cx.read_from_clipboard()
|
|
.map(|item| item.text().clone())
|
|
.unwrap_or_default(),
|
|
);
|
|
}
|
|
vim.workspace_state.registers.insert("\"".to_string(), text);
|
|
if !is_yank || vim.state().mode == Mode::Visual {
|
|
return;
|
|
}
|
|
|
|
editor.highlight_background::<HighlightOnYank>(
|
|
&ranges_to_highlight,
|
|
|colors| colors.editor_document_highlight_read_background,
|
|
cx,
|
|
);
|
|
cx.spawn(|this, mut cx| async move {
|
|
cx.background_executor()
|
|
.timer(Duration::from_millis(200))
|
|
.await;
|
|
this.update(&mut cx, |editor, cx| {
|
|
editor.clear_background_highlights::<HighlightOnYank>(cx)
|
|
})
|
|
.ok();
|
|
})
|
|
.detach();
|
|
}
|
|
|
|
pub fn coerce_punctuation(kind: CharKind, treat_punctuation_as_word: bool) -> CharKind {
|
|
if treat_punctuation_as_word && kind == CharKind::Punctuation {
|
|
CharKind::Word
|
|
} else {
|
|
kind
|
|
}
|
|
}
|