Support better inlay cache parallelization
This commit is contained in:
parent
890b164278
commit
83b3a914bc
2 changed files with 198 additions and 203 deletions
|
@ -7891,11 +7891,11 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
editor_a.update(cx_a, |_, cx| cx.focus(&editor_a));
|
editor_a.update(cx_a, |_, cx| cx.focus(&editor_a));
|
||||||
cx_a.foreground().run_until_parked();
|
cx_a.foreground().run_until_parked();
|
||||||
editor_a.update(cx_a, |editor, _| {
|
editor_a.update(cx_a, |editor, _| {
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
|
||||||
assert!(
|
assert!(
|
||||||
inlay_cache.hints.is_empty(),
|
extract_hint_labels(editor).is_empty(),
|
||||||
"No inlays should be in the new cache"
|
"No inlays should be in the new cache"
|
||||||
);
|
);
|
||||||
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
||||||
"Cache should use editor settings to get the allowed hint kinds"
|
"Cache should use editor settings to get the allowed hint kinds"
|
||||||
|
@ -7918,11 +7918,11 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
editor_b.update(cx_b, |_, cx| cx.focus(&editor_b));
|
editor_b.update(cx_b, |_, cx| cx.focus(&editor_b));
|
||||||
cx_b.foreground().run_until_parked();
|
cx_b.foreground().run_until_parked();
|
||||||
editor_b.update(cx_b, |editor, _| {
|
editor_b.update(cx_b, |editor, _| {
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
|
||||||
assert!(
|
assert!(
|
||||||
inlay_cache.hints.is_empty(),
|
extract_hint_labels(editor).is_empty(),
|
||||||
"No inlays should be in the new cache"
|
"No inlays should be in the new cache"
|
||||||
);
|
);
|
||||||
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
||||||
"Cache should use editor settings to get the allowed hint kinds"
|
"Cache should use editor settings to get the allowed hint kinds"
|
||||||
|
@ -7978,32 +7978,27 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
cx_a.foreground().finish_waiting();
|
cx_a.foreground().finish_waiting();
|
||||||
cx_a.foreground().run_until_parked();
|
cx_a.foreground().run_until_parked();
|
||||||
|
|
||||||
fn extract_hint_labels(editor: &Editor) -> Vec<&str> {
|
fn extract_hint_labels(editor: &Editor) -> Vec<String> {
|
||||||
editor
|
let mut labels = Vec::new();
|
||||||
.inlay_hint_cache()
|
for (_, excerpt_hints) in &editor.inlay_hint_cache().hints {
|
||||||
.snapshot()
|
let excerpt_hints = excerpt_hints.read();
|
||||||
.hints
|
for (_, inlay) in excerpt_hints.hints.iter() {
|
||||||
.iter()
|
match &inlay.label {
|
||||||
.map(|(_, excerpt_hints)| {
|
project::InlayHintLabel::String(s) => labels.push(s.to_string()),
|
||||||
excerpt_hints
|
|
||||||
.hints
|
|
||||||
.iter()
|
|
||||||
.map(|(_, inlay)| match &inlay.label {
|
|
||||||
project::InlayHintLabel::String(s) => s.as_str(),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
}
|
||||||
})
|
}
|
||||||
.flatten()
|
}
|
||||||
.collect::<Vec<_>>()
|
labels
|
||||||
}
|
}
|
||||||
|
|
||||||
editor_a.update(cx_a, |editor, _| {
|
editor_a.update(cx_a, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0"],
|
vec!["0".to_string()],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Host should get hints from the 1st edit and 1st LSP query"
|
"Host should get hints from the 1st edit and 1st LSP query"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.version, edits_made,
|
inlay_cache.version, edits_made,
|
||||||
|
@ -8012,11 +8007,11 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
});
|
});
|
||||||
editor_b.update(cx_b, |editor, _| {
|
editor_b.update(cx_b, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0", "1"],
|
vec!["0".to_string(), "1".to_string()],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Guest should get hints the 1st edit and 2nd LSP query"
|
"Guest should get hints the 1st edit and 2nd LSP query"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.version, edits_made,
|
inlay_cache.version, edits_made,
|
||||||
|
@ -8034,12 +8029,12 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
cx_b.foreground().run_until_parked();
|
cx_b.foreground().run_until_parked();
|
||||||
editor_a.update(cx_a, |editor, _| {
|
editor_a.update(cx_a, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0", "1", "2"],
|
vec!["0".to_string(), "1".to_string(), "2".to_string()],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Host should get hints from 3rd edit, 5th LSP query: \
|
"Host should get hints from 3rd edit, 5th LSP query: \
|
||||||
4th query was made by guest (but not applied) due to cache invalidation logic"
|
4th query was made by guest (but not applied) due to cache invalidation logic"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds, "Inlay kinds settings never change during the test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.version, edits_made,
|
inlay_cache.version, edits_made,
|
||||||
|
@ -8048,11 +8043,16 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
});
|
});
|
||||||
editor_b.update(cx_b, |editor, _| {
|
editor_b.update(cx_b, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0", "1", "2", "3"],
|
vec![
|
||||||
|
"0".to_string(),
|
||||||
|
"1".to_string(),
|
||||||
|
"2".to_string(),
|
||||||
|
"3".to_string()
|
||||||
|
],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Guest should get hints from 3rd edit, 6th LSP query"
|
"Guest should get hints from 3rd edit, 6th LSP query"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
||||||
"Inlay kinds settings never change during the test"
|
"Inlay kinds settings never change during the test"
|
||||||
|
@ -8072,11 +8072,17 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
cx_b.foreground().run_until_parked();
|
cx_b.foreground().run_until_parked();
|
||||||
editor_a.update(cx_a, |editor, _| {
|
editor_a.update(cx_a, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0", "1", "2", "3", "4"],
|
vec![
|
||||||
|
"0".to_string(),
|
||||||
|
"1".to_string(),
|
||||||
|
"2".to_string(),
|
||||||
|
"3".to_string(),
|
||||||
|
"4".to_string()
|
||||||
|
],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Host should react to /refresh LSP request and get new hints from 7th LSP query"
|
"Host should react to /refresh LSP request and get new hints from 7th LSP query"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
||||||
"Inlay kinds settings never change during the test"
|
"Inlay kinds settings never change during the test"
|
||||||
|
@ -8088,11 +8094,11 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||||
});
|
});
|
||||||
editor_b.update(cx_b, |editor, _| {
|
editor_b.update(cx_b, |editor, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec!["0", "1", "2", "3", "4", "5"],
|
vec!["0".to_string(), "1".to_string(), "2".to_string(), "3".to_string(), "4".to_string(), "5".to_string()],
|
||||||
extract_hint_labels(editor),
|
extract_hint_labels(editor),
|
||||||
"Guest should get a /refresh LSP request propagated by host and get new hints from 8th LSP query"
|
"Guest should get a /refresh LSP request propagated by host and get new hints from 8th LSP query"
|
||||||
);
|
);
|
||||||
let inlay_cache = editor.inlay_hint_cache().snapshot();
|
let inlay_cache = editor.inlay_hint_cache();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
|
||||||
"Inlay kinds settings never change during the test"
|
"Inlay kinds settings never change during the test"
|
||||||
|
|
|
@ -9,13 +9,16 @@ use clock::Global;
|
||||||
use gpui::{ModelHandle, Task, ViewContext};
|
use gpui::{ModelHandle, Task, ViewContext};
|
||||||
use language::{Buffer, BufferSnapshot};
|
use language::{Buffer, BufferSnapshot};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use parking_lot::RwLock;
|
||||||
use project::{InlayHint, InlayHintKind};
|
use project::{InlayHint, InlayHintKind};
|
||||||
|
|
||||||
use collections::{hash_map, HashMap, HashSet};
|
use collections::{hash_map, HashMap, HashSet};
|
||||||
use util::post_inc;
|
use util::post_inc;
|
||||||
|
|
||||||
pub struct InlayHintCache {
|
pub struct InlayHintCache {
|
||||||
snapshot: CacheSnapshot,
|
pub hints: HashMap<ExcerptId, Arc<RwLock<CachedExcerptHints>>>,
|
||||||
|
pub allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
|
||||||
|
pub version: usize,
|
||||||
update_tasks: HashMap<ExcerptId, InlayHintUpdateTask>,
|
update_tasks: HashMap<ExcerptId, InlayHintUpdateTask>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +27,6 @@ struct InlayHintUpdateTask {
|
||||||
_task: Task<()>,
|
_task: Task<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CacheSnapshot {
|
|
||||||
pub hints: HashMap<ExcerptId, Arc<CachedExcerptHints>>,
|
|
||||||
pub allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
|
|
||||||
pub version: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CachedExcerptHints {
|
pub struct CachedExcerptHints {
|
||||||
version: usize,
|
version: usize,
|
||||||
|
@ -84,19 +80,13 @@ struct ExcerptHintsUpdate {
|
||||||
impl InlayHintCache {
|
impl InlayHintCache {
|
||||||
pub fn new(inlay_hint_settings: editor_settings::InlayHints) -> Self {
|
pub fn new(inlay_hint_settings: editor_settings::InlayHints) -> Self {
|
||||||
Self {
|
Self {
|
||||||
snapshot: CacheSnapshot {
|
|
||||||
allowed_hint_kinds: allowed_hint_types(inlay_hint_settings),
|
allowed_hint_kinds: allowed_hint_types(inlay_hint_settings),
|
||||||
hints: HashMap::default(),
|
hints: HashMap::default(),
|
||||||
version: 0,
|
|
||||||
},
|
|
||||||
update_tasks: HashMap::default(),
|
update_tasks: HashMap::default(),
|
||||||
|
version: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self) -> &CacheSnapshot {
|
|
||||||
&self.snapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_settings(
|
pub fn update_settings(
|
||||||
&mut self,
|
&mut self,
|
||||||
multi_buffer: &ModelHandle<MultiBuffer>,
|
multi_buffer: &ModelHandle<MultiBuffer>,
|
||||||
|
@ -106,38 +96,34 @@ impl InlayHintCache {
|
||||||
) -> Option<InlaySplice> {
|
) -> Option<InlaySplice> {
|
||||||
let new_allowed_hint_kinds = allowed_hint_types(inlay_hint_settings);
|
let new_allowed_hint_kinds = allowed_hint_types(inlay_hint_settings);
|
||||||
if !inlay_hint_settings.enabled {
|
if !inlay_hint_settings.enabled {
|
||||||
if self.snapshot.hints.is_empty() {
|
if self.hints.is_empty() {
|
||||||
self.snapshot.allowed_hint_kinds = new_allowed_hint_kinds;
|
self.allowed_hint_kinds = new_allowed_hint_kinds;
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
self.clear();
|
self.clear();
|
||||||
self.snapshot.allowed_hint_kinds = new_allowed_hint_kinds;
|
self.allowed_hint_kinds = new_allowed_hint_kinds;
|
||||||
return Some(InlaySplice {
|
Some(InlaySplice {
|
||||||
to_remove: visible_hints.iter().map(|inlay| inlay.id).collect(),
|
to_remove: visible_hints.iter().map(|inlay| inlay.id).collect(),
|
||||||
to_insert: Vec::new(),
|
to_insert: Vec::new(),
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
} else if new_allowed_hint_kinds == self.allowed_hint_kinds {
|
||||||
return None;
|
None
|
||||||
}
|
} else {
|
||||||
|
let new_splice = self.new_allowed_hint_kinds_splice(
|
||||||
if new_allowed_hint_kinds == self.snapshot.allowed_hint_kinds {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_splice = new_allowed_hint_kinds_splice(
|
|
||||||
&self.snapshot,
|
|
||||||
multi_buffer,
|
multi_buffer,
|
||||||
&visible_hints,
|
&visible_hints,
|
||||||
&new_allowed_hint_kinds,
|
&new_allowed_hint_kinds,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
if new_splice.is_some() {
|
if new_splice.is_some() {
|
||||||
self.snapshot.version += 1;
|
self.version += 1;
|
||||||
self.update_tasks.clear();
|
self.update_tasks.clear();
|
||||||
self.snapshot.allowed_hint_kinds = new_allowed_hint_kinds;
|
self.allowed_hint_kinds = new_allowed_hint_kinds;
|
||||||
}
|
}
|
||||||
new_splice
|
new_splice
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn_hints_update(
|
pub fn spawn_hints_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -154,9 +140,10 @@ impl InlayHintCache {
|
||||||
update_tasks
|
update_tasks
|
||||||
.retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
|
.retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
|
||||||
}
|
}
|
||||||
|
let cache_version = self.version;
|
||||||
excerpts_to_query.retain(|visible_excerpt_id, _| {
|
excerpts_to_query.retain(|visible_excerpt_id, _| {
|
||||||
match update_tasks.entry(*visible_excerpt_id) {
|
match update_tasks.entry(*visible_excerpt_id) {
|
||||||
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&self.snapshot.version) {
|
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&cache_version) {
|
||||||
cmp::Ordering::Less => true,
|
cmp::Ordering::Less => true,
|
||||||
cmp::Ordering::Equal => invalidate_cache,
|
cmp::Ordering::Equal => invalidate_cache,
|
||||||
cmp::Ordering::Greater => false,
|
cmp::Ordering::Greater => false,
|
||||||
|
@ -169,7 +156,6 @@ impl InlayHintCache {
|
||||||
update_tasks
|
update_tasks
|
||||||
.retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
|
.retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
|
||||||
}
|
}
|
||||||
let cache_version = self.snapshot.version;
|
|
||||||
excerpts_to_query.retain(|visible_excerpt_id, _| {
|
excerpts_to_query.retain(|visible_excerpt_id, _| {
|
||||||
match update_tasks.entry(*visible_excerpt_id) {
|
match update_tasks.entry(*visible_excerpt_id) {
|
||||||
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&cache_version) {
|
hash_map::Entry::Occupied(o) => match o.get().version.cmp(&cache_version) {
|
||||||
|
@ -211,15 +197,12 @@ impl InlayHintCache {
|
||||||
cache_version,
|
cache_version,
|
||||||
invalidate,
|
invalidate,
|
||||||
};
|
};
|
||||||
let cached_excxerpt_hints = editor
|
let cached_excxerpt_hints =
|
||||||
.inlay_hint_cache
|
editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
|
||||||
.snapshot
|
|
||||||
.hints
|
|
||||||
.get(&excerpt_id)
|
|
||||||
.cloned();
|
|
||||||
|
|
||||||
if let Some(cached_excerpt_hints) = &cached_excxerpt_hints {
|
if let Some(cached_excerpt_hints) = &cached_excxerpt_hints {
|
||||||
let new_task_buffer_version = buffer_snapshot.version();
|
let new_task_buffer_version = buffer_snapshot.version();
|
||||||
|
let cached_excerpt_hints = cached_excerpt_hints.read();
|
||||||
let cached_buffer_version = &cached_excerpt_hints.buffer_version;
|
let cached_buffer_version = &cached_excerpt_hints.buffer_version;
|
||||||
if cached_buffer_version.changed_since(new_task_buffer_version) {
|
if cached_buffer_version.changed_since(new_task_buffer_version) {
|
||||||
return;
|
return;
|
||||||
|
@ -250,132 +233,14 @@ impl InlayHintCache {
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn new_allowed_hint_kinds_splice(
|
||||||
self.snapshot.version += 1;
|
&self,
|
||||||
self.update_tasks.clear();
|
|
||||||
self.snapshot.hints.clear();
|
|
||||||
self.snapshot.allowed_hint_kinds.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_update_task(
|
|
||||||
query: ExcerptQuery,
|
|
||||||
multi_buffer_snapshot: MultiBufferSnapshot,
|
|
||||||
buffer_snapshot: BufferSnapshot,
|
|
||||||
visible_hints: Arc<Vec<Inlay>>,
|
|
||||||
cached_excerpt_hints: Option<Arc<CachedExcerptHints>>,
|
|
||||||
cx: &mut ViewContext<'_, '_, Editor>,
|
|
||||||
) -> InlayHintUpdateTask {
|
|
||||||
let hints_fetch_task = hints_fetch_task(query, cx);
|
|
||||||
InlayHintUpdateTask {
|
|
||||||
version: query.cache_version,
|
|
||||||
_task: cx.spawn(|editor, mut cx| async move {
|
|
||||||
match hints_fetch_task.await {
|
|
||||||
Ok(Some(new_hints)) => {
|
|
||||||
let task_buffer_snapshot = buffer_snapshot.clone();
|
|
||||||
if let Some(new_update) = cx
|
|
||||||
.background()
|
|
||||||
.spawn(async move {
|
|
||||||
new_excerpt_hints_update_result(
|
|
||||||
query,
|
|
||||||
new_hints,
|
|
||||||
&task_buffer_snapshot,
|
|
||||||
cached_excerpt_hints,
|
|
||||||
&visible_hints,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
editor
|
|
||||||
.update(&mut cx, |editor, cx| {
|
|
||||||
let cached_excerpt_hints = editor
|
|
||||||
.inlay_hint_cache
|
|
||||||
.snapshot
|
|
||||||
.hints
|
|
||||||
.entry(new_update.excerpt_id)
|
|
||||||
.or_insert_with(|| {
|
|
||||||
Arc::new(CachedExcerptHints {
|
|
||||||
version: new_update.cache_version,
|
|
||||||
buffer_version: buffer_snapshot.version().clone(),
|
|
||||||
hints: Vec::new(),
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let cached_excerpt_hints = Arc::get_mut(cached_excerpt_hints)
|
|
||||||
.expect("Cached excerpt hints were dropped with the task");
|
|
||||||
|
|
||||||
match new_update.cache_version.cmp(&cached_excerpt_hints.version) {
|
|
||||||
cmp::Ordering::Less => return,
|
|
||||||
cmp::Ordering::Greater | cmp::Ordering::Equal => {
|
|
||||||
cached_excerpt_hints.version = new_update.cache_version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cached_excerpt_hints.hints.retain(|(hint_id, _)| {
|
|
||||||
!new_update.remove_from_cache.contains(hint_id)
|
|
||||||
});
|
|
||||||
cached_excerpt_hints.buffer_version =
|
|
||||||
buffer_snapshot.version().clone();
|
|
||||||
editor.inlay_hint_cache.snapshot.version += 1;
|
|
||||||
|
|
||||||
let mut splice = InlaySplice {
|
|
||||||
to_remove: new_update.remove_from_visible,
|
|
||||||
to_insert: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
for new_hint in new_update.add_to_cache {
|
|
||||||
let new_hint_position = multi_buffer_snapshot
|
|
||||||
.anchor_in_excerpt(query.excerpt_id, new_hint.position);
|
|
||||||
let new_inlay_id = InlayId(post_inc(&mut editor.next_inlay_id));
|
|
||||||
if editor
|
|
||||||
.inlay_hint_cache
|
|
||||||
.snapshot
|
|
||||||
.allowed_hint_kinds
|
|
||||||
.contains(&new_hint.kind)
|
|
||||||
{
|
|
||||||
splice.to_insert.push((
|
|
||||||
new_hint_position,
|
|
||||||
new_inlay_id,
|
|
||||||
new_hint.clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
cached_excerpt_hints.hints.push((new_inlay_id, new_hint));
|
|
||||||
}
|
|
||||||
|
|
||||||
cached_excerpt_hints
|
|
||||||
.hints
|
|
||||||
.sort_by(|(_, hint_a), (_, hint_b)| {
|
|
||||||
hint_a.position.cmp(&hint_b.position, &buffer_snapshot)
|
|
||||||
});
|
|
||||||
|
|
||||||
let InlaySplice {
|
|
||||||
to_remove,
|
|
||||||
to_insert,
|
|
||||||
} = splice;
|
|
||||||
if !to_remove.is_empty() || !to_insert.is_empty() {
|
|
||||||
editor.splice_inlay_hints(to_remove, to_insert, cx)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None) => {}
|
|
||||||
Err(e) => error!(
|
|
||||||
"Failed to fecth hints for excerpt {:?} in buffer {} : {}",
|
|
||||||
query.excerpt_id, query.buffer_id, e
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_allowed_hint_kinds_splice(
|
|
||||||
cache: &CacheSnapshot,
|
|
||||||
multi_buffer: &ModelHandle<MultiBuffer>,
|
multi_buffer: &ModelHandle<MultiBuffer>,
|
||||||
visible_hints: &[Inlay],
|
visible_hints: &[Inlay],
|
||||||
new_kinds: &HashSet<Option<InlayHintKind>>,
|
new_kinds: &HashSet<Option<InlayHintKind>>,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Option<InlaySplice> {
|
) -> Option<InlaySplice> {
|
||||||
let old_kinds = &cache.allowed_hint_kinds;
|
let old_kinds = &self.allowed_hint_kinds;
|
||||||
if new_kinds == old_kinds {
|
if new_kinds == old_kinds {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -396,8 +261,10 @@ fn new_allowed_hint_kinds_splice(
|
||||||
let multi_buffer = multi_buffer.read(cx);
|
let multi_buffer = multi_buffer.read(cx);
|
||||||
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
|
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
|
||||||
|
|
||||||
for (excerpt_id, excerpt_cached_hints) in &cache.hints {
|
for (excerpt_id, excerpt_cached_hints) in &self.hints {
|
||||||
let shown_excerpt_hints_to_remove = shown_hints_to_remove.entry(*excerpt_id).or_default();
|
let shown_excerpt_hints_to_remove =
|
||||||
|
shown_hints_to_remove.entry(*excerpt_id).or_default();
|
||||||
|
let excerpt_cached_hints = excerpt_cached_hints.read();
|
||||||
let mut excerpt_cache = excerpt_cached_hints.hints.iter().fuse().peekable();
|
let mut excerpt_cache = excerpt_cached_hints.hints.iter().fuse().peekable();
|
||||||
shown_excerpt_hints_to_remove.retain(|(shown_anchor, shown_hint_id)| {
|
shown_excerpt_hints_to_remove.retain(|(shown_anchor, shown_hint_id)| {
|
||||||
let Some(buffer) = shown_anchor
|
let Some(buffer) = shown_anchor
|
||||||
|
@ -421,8 +288,10 @@ fn new_allowed_hint_kinds_splice(
|
||||||
&& new_kinds.contains(&cached_hint.kind)
|
&& new_kinds.contains(&cached_hint.kind)
|
||||||
{
|
{
|
||||||
to_insert.push((
|
to_insert.push((
|
||||||
multi_buffer_snapshot
|
multi_buffer_snapshot.anchor_in_excerpt(
|
||||||
.anchor_in_excerpt(*excerpt_id, cached_hint.position),
|
*excerpt_id,
|
||||||
|
cached_hint.position,
|
||||||
|
),
|
||||||
*cached_hint_id,
|
*cached_hint_id,
|
||||||
cached_hint.clone(),
|
cached_hint.clone(),
|
||||||
));
|
));
|
||||||
|
@ -464,13 +333,128 @@ fn new_allowed_hint_kinds_splice(
|
||||||
to_insert,
|
to_insert,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.version += 1;
|
||||||
|
self.update_tasks.clear();
|
||||||
|
self.hints.clear();
|
||||||
|
self.allowed_hint_kinds.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_update_task(
|
||||||
|
query: ExcerptQuery,
|
||||||
|
multi_buffer_snapshot: MultiBufferSnapshot,
|
||||||
|
buffer_snapshot: BufferSnapshot,
|
||||||
|
visible_hints: Arc<Vec<Inlay>>,
|
||||||
|
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
|
||||||
|
cx: &mut ViewContext<'_, '_, Editor>,
|
||||||
|
) -> InlayHintUpdateTask {
|
||||||
|
let hints_fetch_task = hints_fetch_task(query, cx);
|
||||||
|
InlayHintUpdateTask {
|
||||||
|
version: query.cache_version,
|
||||||
|
_task: cx.spawn(|editor, mut cx| async move {
|
||||||
|
match hints_fetch_task.await {
|
||||||
|
Ok(Some(new_hints)) => {
|
||||||
|
let task_buffer_snapshot = buffer_snapshot.clone();
|
||||||
|
if let Some(new_update) = cx
|
||||||
|
.background()
|
||||||
|
.spawn(async move {
|
||||||
|
new_excerpt_hints_update_result(
|
||||||
|
query,
|
||||||
|
new_hints,
|
||||||
|
&task_buffer_snapshot,
|
||||||
|
cached_excerpt_hints,
|
||||||
|
&visible_hints,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
editor
|
||||||
|
.update(&mut cx, |editor, cx| {
|
||||||
|
let cached_excerpt_hints = editor
|
||||||
|
.inlay_hint_cache
|
||||||
|
.hints
|
||||||
|
.entry(new_update.excerpt_id)
|
||||||
|
.or_insert_with(|| {
|
||||||
|
Arc::new(RwLock::new(CachedExcerptHints {
|
||||||
|
version: new_update.cache_version,
|
||||||
|
buffer_version: buffer_snapshot.version().clone(),
|
||||||
|
hints: Vec::new(),
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
let mut cached_excerpt_hints = cached_excerpt_hints.write();
|
||||||
|
match new_update.cache_version.cmp(&cached_excerpt_hints.version) {
|
||||||
|
cmp::Ordering::Less => return,
|
||||||
|
cmp::Ordering::Greater | cmp::Ordering::Equal => {
|
||||||
|
cached_excerpt_hints.version = new_update.cache_version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cached_excerpt_hints.hints.retain(|(hint_id, _)| {
|
||||||
|
!new_update.remove_from_cache.contains(hint_id)
|
||||||
|
});
|
||||||
|
cached_excerpt_hints.buffer_version =
|
||||||
|
buffer_snapshot.version().clone();
|
||||||
|
editor.inlay_hint_cache.version += 1;
|
||||||
|
|
||||||
|
let mut splice = InlaySplice {
|
||||||
|
to_remove: new_update.remove_from_visible,
|
||||||
|
to_insert: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for new_hint in new_update.add_to_cache {
|
||||||
|
let new_hint_position = multi_buffer_snapshot
|
||||||
|
.anchor_in_excerpt(query.excerpt_id, new_hint.position);
|
||||||
|
let new_inlay_id = InlayId(post_inc(&mut editor.next_inlay_id));
|
||||||
|
if editor
|
||||||
|
.inlay_hint_cache
|
||||||
|
.allowed_hint_kinds
|
||||||
|
.contains(&new_hint.kind)
|
||||||
|
{
|
||||||
|
splice.to_insert.push((
|
||||||
|
new_hint_position,
|
||||||
|
new_inlay_id,
|
||||||
|
new_hint.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_excerpt_hints.hints.push((new_inlay_id, new_hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_excerpt_hints
|
||||||
|
.hints
|
||||||
|
.sort_by(|(_, hint_a), (_, hint_b)| {
|
||||||
|
hint_a.position.cmp(&hint_b.position, &buffer_snapshot)
|
||||||
|
});
|
||||||
|
drop(cached_excerpt_hints);
|
||||||
|
|
||||||
|
let InlaySplice {
|
||||||
|
to_remove,
|
||||||
|
to_insert,
|
||||||
|
} = splice;
|
||||||
|
if !to_remove.is_empty() || !to_insert.is_empty() {
|
||||||
|
editor.splice_inlay_hints(to_remove, to_insert, cx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(e) => error!(
|
||||||
|
"Failed to fecth hints for excerpt {:?} in buffer {} : {}",
|
||||||
|
query.excerpt_id, query.buffer_id, e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_excerpt_hints_update_result(
|
fn new_excerpt_hints_update_result(
|
||||||
query: ExcerptQuery,
|
query: ExcerptQuery,
|
||||||
new_excerpt_hints: Vec<InlayHint>,
|
new_excerpt_hints: Vec<InlayHint>,
|
||||||
buffer_snapshot: &BufferSnapshot,
|
buffer_snapshot: &BufferSnapshot,
|
||||||
cached_excerpt_hints: Option<Arc<CachedExcerptHints>>,
|
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
|
||||||
visible_hints: &[Inlay],
|
visible_hints: &[Inlay],
|
||||||
) -> Option<ExcerptHintsUpdate> {
|
) -> Option<ExcerptHintsUpdate> {
|
||||||
let mut add_to_cache: Vec<InlayHint> = Vec::new();
|
let mut add_to_cache: Vec<InlayHint> = Vec::new();
|
||||||
|
@ -482,6 +466,7 @@ fn new_excerpt_hints_update_result(
|
||||||
}
|
}
|
||||||
let missing_from_cache = match &cached_excerpt_hints {
|
let missing_from_cache = match &cached_excerpt_hints {
|
||||||
Some(cached_excerpt_hints) => {
|
Some(cached_excerpt_hints) => {
|
||||||
|
let cached_excerpt_hints = cached_excerpt_hints.read();
|
||||||
match cached_excerpt_hints.hints.binary_search_by(|probe| {
|
match cached_excerpt_hints.hints.binary_search_by(|probe| {
|
||||||
probe.1.position.cmp(&new_hint.position, buffer_snapshot)
|
probe.1.position.cmp(&new_hint.position, buffer_snapshot)
|
||||||
}) {
|
}) {
|
||||||
|
@ -518,16 +503,20 @@ fn new_excerpt_hints_update_result(
|
||||||
.map(|inlay_hint| inlay_hint.id)
|
.map(|inlay_hint| inlay_hint.id)
|
||||||
.filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)),
|
.filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
|
||||||
|
let cached_excerpt_hints = cached_excerpt_hints.read();
|
||||||
remove_from_cache.extend(
|
remove_from_cache.extend(
|
||||||
cached_excerpt_hints
|
cached_excerpt_hints
|
||||||
|
.hints
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|excerpt_hints| excerpt_hints.hints.iter())
|
|
||||||
.filter(|(cached_inlay_id, _)| {
|
.filter(|(cached_inlay_id, _)| {
|
||||||
!excerpt_hints_to_persist.contains_key(cached_inlay_id)
|
!excerpt_hints_to_persist.contains_key(cached_inlay_id)
|
||||||
})
|
})
|
||||||
.map(|(cached_inlay_id, _)| *cached_inlay_id),
|
.map(|(cached_inlay_id, _)| *cached_inlay_id),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if remove_from_visible.is_empty() && remove_from_cache.is_empty() && add_to_cache.is_empty() {
|
if remove_from_visible.is_empty() && remove_from_cache.is_empty() && add_to_cache.is_empty() {
|
||||||
None
|
None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue