Move away heavy inlay computations into background tasks

This commit is contained in:
Kirill Bulatov 2023-06-21 22:17:47 +03:00
parent 31f0f9f7b1
commit 7fddc223cd
4 changed files with 395 additions and 825 deletions

View file

@ -54,7 +54,7 @@ use gpui::{
}; };
use highlight_matching_bracket::refresh_matching_bracket_highlights; use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState}; use hover_popover::{hide_hover, HoverState};
use inlay_hint_cache::{InlayHintCache, InlayHintQuery}; use inlay_hint_cache::{get_update_state, InlayHintCache, InlaySplice};
pub use items::MAX_TAB_TITLE_LEN; pub use items::MAX_TAB_TITLE_LEN;
use itertools::Itertools; use itertools::Itertools;
pub use language::{char_kind, CharKind}; pub use language::{char_kind, CharKind};
@ -1196,7 +1196,7 @@ enum GotoDefinitionKind {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum InlayRefreshReason { enum InlayRefreshReason {
SettingsChange(editor_settings::InlayHints), SettingsChange(editor_settings::InlayHints),
Scroll(ScrollAnchor), Scroll,
VisibleExcerptsChange, VisibleExcerptsChange,
} }
@ -1367,10 +1367,7 @@ impl Editor {
hover_state: Default::default(), hover_state: Default::default(),
link_go_to_definition_state: Default::default(), link_go_to_definition_state: Default::default(),
copilot_state: Default::default(), copilot_state: Default::default(),
inlay_hint_cache: InlayHintCache::new( inlay_hint_cache: InlayHintCache::new(settings::get::<EditorSettings>(cx).inlay_hints),
settings::get::<EditorSettings>(cx).inlay_hints,
cx,
),
gutter_hovered: false, gutter_hovered: false,
_subscriptions: vec![ _subscriptions: vec![
cx.observe(&buffer, Self::on_buffer_changed), cx.observe(&buffer, Self::on_buffer_changed),
@ -2612,67 +2609,23 @@ impl Editor {
{ {
return; return;
} }
let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
let current_inlays = self
.display_map
.read(cx)
.current_inlays()
.cloned()
.filter(|inlay| Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id))
.collect();
match reason { match reason {
InlayRefreshReason::SettingsChange(new_settings) => self InlayRefreshReason::SettingsChange(new_settings) => {
.inlay_hint_cache let update_state = get_update_state(self, cx);
.spawn_settings_update(multi_buffer_snapshot, new_settings, current_inlays), let new_splice = self
InlayRefreshReason::Scroll(scrolled_to) => { .inlay_hint_cache
if let Some(new_query) = self.excerpt_visible_offsets(cx).into_iter().find_map( .update_settings(new_settings, update_state);
|(buffer, _, excerpt_id)| { if let Some(InlaySplice {
let buffer_id = scrolled_to.anchor.buffer_id?; to_remove,
if buffer_id == buffer.read(cx).remote_id() to_insert,
&& scrolled_to.anchor.excerpt_id == excerpt_id }) = new_splice
{ {
Some(InlayHintQuery { self.splice_inlay_hints(to_remove, to_insert, cx);
buffer_id,
buffer_version: buffer.read(cx).version(),
cache_version: self.inlay_hint_cache.version(),
excerpt_id,
})
} else {
None
}
},
) {
self.inlay_hint_cache.spawn_hints_update(
multi_buffer_snapshot,
vec![new_query],
current_inlays,
false,
cx,
)
} }
} }
InlayRefreshReason::Scroll => self.inlay_hint_cache.spawn_hints_update(false, cx),
InlayRefreshReason::VisibleExcerptsChange => { InlayRefreshReason::VisibleExcerptsChange => {
let replacement_queries = self self.inlay_hint_cache.spawn_hints_update(true, cx)
.excerpt_visible_offsets(cx)
.into_iter()
.map(|(buffer, _, excerpt_id)| {
let buffer = buffer.read(cx);
InlayHintQuery {
buffer_id: buffer.remote_id(),
buffer_version: buffer.version(),
cache_version: self.inlay_hint_cache.version(),
excerpt_id,
}
})
.collect::<Vec<_>>();
self.inlay_hint_cache.spawn_hints_update(
multi_buffer_snapshot,
replacement_queries,
current_inlays,
true,
cx,
)
} }
}; };
} }
@ -2701,13 +2654,13 @@ impl Editor {
fn splice_inlay_hints( fn splice_inlay_hints(
&self, &self,
to_remove: Vec<InlayId>, to_remove: Vec<InlayId>,
to_insert: Vec<(InlayId, Anchor, project::InlayHint)>, to_insert: Vec<(Anchor, InlayId, project::InlayHint)>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
let buffer = self.buffer.read(cx).read(cx); let buffer = self.buffer.read(cx).read(cx);
let new_inlays = to_insert let new_inlays = to_insert
.into_iter() .into_iter()
.map(|(id, position, hint)| { .map(|(position, id, hint)| {
let mut text = hint.text(); let mut text = hint.text();
// TODO kb styling instead? // TODO kb styling instead?
if hint.padding_right { if hint.padding_right {
@ -7298,7 +7251,7 @@ impl Editor {
} }
multi_buffer::Event::ExcerptsRemoved { ids } => { multi_buffer::Event::ExcerptsRemoved { ids } => {
cx.emit(Event::ExcerptsRemoved { ids: ids.clone() }); cx.emit(Event::ExcerptsRemoved { ids: ids.clone() });
true false
} }
multi_buffer::Event::Reparsed => { multi_buffer::Event::Reparsed => {
cx.emit(Event::Reparsed); cx.emit(Event::Reparsed);
@ -7336,7 +7289,11 @@ impl Editor {
}; };
if refresh_inlays { if refresh_inlays {
self.refresh_inlays(InlayRefreshReason::VisibleExcerptsChange, cx); if let Some(_project) = self.project.as_ref() {
// TODO kb non-rust buffer can be edited (e.g. settings) and trigger rust updates
// let zz = project.read(cx).language_servers_for_buffer(buffer, cx);
self.refresh_inlays(InlayRefreshReason::VisibleExcerptsChange, cx);
}
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -176,7 +176,7 @@ impl ScrollManager {
autoscroll: bool, autoscroll: bool,
workspace_id: Option<i64>, workspace_id: Option<i64>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> ScrollAnchor { ) {
let (new_anchor, top_row) = if scroll_position.y() <= 0. { let (new_anchor, top_row) = if scroll_position.y() <= 0. {
( (
ScrollAnchor { ScrollAnchor {
@ -205,7 +205,6 @@ impl ScrollManager {
}; };
self.set_anchor(new_anchor, top_row, local, autoscroll, workspace_id, cx); self.set_anchor(new_anchor, top_row, local, autoscroll, workspace_id, cx);
new_anchor
} }
fn set_anchor( fn set_anchor(
@ -313,7 +312,7 @@ impl Editor {
hide_hover(self, cx); hide_hover(self, cx);
let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1); let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
let scroll_anchor = self.scroll_manager.set_scroll_position( self.scroll_manager.set_scroll_position(
scroll_position, scroll_position,
&map, &map,
local, local,
@ -323,7 +322,7 @@ impl Editor {
); );
if !self.is_singleton(cx) { if !self.is_singleton(cx) {
self.refresh_inlays(crate::InlayRefreshReason::Scroll(scroll_anchor), cx); self.refresh_inlays(crate::InlayRefreshReason::Scroll, cx);
} }
} }

View file

@ -4929,7 +4929,7 @@ impl Project {
) )
} }
pub fn query_inlay_hints_for_buffer<T: ToOffset>( pub fn inlay_hints<T: ToOffset>(
&self, &self,
buffer_handle: ModelHandle<Buffer>, buffer_handle: ModelHandle<Buffer>,
range: Range<T>, range: Range<T>,
@ -6768,7 +6768,7 @@ impl Project {
.update(&mut cx, |project, cx| { .update(&mut cx, |project, cx| {
let buffer_end = buffer.read(cx).len(); let buffer_end = buffer.read(cx).len();
// TODO kb use cache before querying? // TODO kb use cache before querying?
project.query_inlay_hints_for_buffer( project.inlay_hints(
buffer, buffer,
envelope envelope
.payload .payload