Improve on inlya locations

This commit is contained in:
Kirill Bulatov 2023-06-08 15:44:20 +03:00
parent b193d62a5d
commit 3028767d12
3 changed files with 75 additions and 67 deletions

View file

@ -5,7 +5,9 @@ mod suggestion_map;
mod tab_map; mod tab_map;
mod wrap_map; mod wrap_map;
use crate::{Anchor, AnchorRangeExt, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint}; use crate::{
Anchor, AnchorRangeExt, InlayHintLocation, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
};
pub use block_map::{BlockMap, BlockPoint}; pub use block_map::{BlockMap, BlockPoint};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use fold_map::{FoldMap, FoldOffset}; use fold_map::{FoldMap, FoldOffset};
@ -284,19 +286,12 @@ impl DisplayMap {
pub fn set_inlay_hints( pub fn set_inlay_hints(
&mut self, &mut self,
new_hints: &[project::InlayHint], new_hints: &HashMap<InlayHintLocation, Vec<project::InlayHint>>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
// TODO kb map this to Anchor and set to the map
let multi_buffer = self.buffer.read(cx); let multi_buffer = self.buffer.read(cx);
// TODO kb carry both remote and local ids of the buffer?
// now, `.buffer` requires remote id, hence this map.
let buffers_to_local_id = multi_buffer
.all_buffers()
.into_iter()
.map(|buffer_handle| (buffer_handle.id(), buffer_handle))
.collect::<HashMap<_, _>>();
// multi_buffer.anchor_in_excerpt(excerpt_id, hint.position); // multi_buffer.anchor_in_excerpt(excerpt_id, hint.position);
// TODO kb !!! rework things from buffer_id to excerpt_id // TODO kb !!! rework things from buffer_id to excerpt_id
// let hint_anchor = multi_buffer // let hint_anchor = multi_buffer

View file

@ -7,7 +7,7 @@ use std::{
sync::atomic::{self, AtomicUsize}, sync::atomic::{self, AtomicUsize},
}; };
use crate::{Anchor, MultiBufferSnapshot, ToOffset, ToPoint}; use crate::{Anchor, ExcerptId, InlayHintLocation, MultiBufferSnapshot, ToOffset, ToPoint};
use super::{ use super::{
suggestion_map::{ suggestion_map::{
@ -31,7 +31,7 @@ pub struct InlayId(usize);
pub struct InlayMap { pub struct InlayMap {
snapshot: Mutex<InlaySnapshot>, snapshot: Mutex<InlaySnapshot>,
next_inlay_id: usize, next_inlay_id: usize,
inlays: HashMap<InlayId, Inlay>, inlays: HashMap<InlayId, (InlayHintLocation, Inlay)>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -224,18 +224,18 @@ impl InlayMap {
pub fn splice( pub fn splice(
&mut self, &mut self,
to_remove: HashSet<InlayId>, to_remove: HashSet<InlayId>,
to_insert: Vec<InlayProperties>, to_insert: Vec<(InlayHintLocation, InlayProperties)>,
) -> (InlaySnapshot, Vec<InlayEdit>, Vec<InlayId>) { ) -> (InlaySnapshot, Vec<InlayEdit>, Vec<InlayId>) {
let mut snapshot = self.snapshot.lock(); let mut snapshot = self.snapshot.lock();
let mut inlays = BTreeMap::new(); let mut inlays = BTreeMap::new();
let mut new_ids = Vec::new(); let mut new_ids = Vec::new();
for properties in to_insert { for (location, properties) in to_insert {
let inlay = Inlay { let inlay = Inlay {
id: InlayId(post_inc(&mut self.next_inlay_id)), id: InlayId(post_inc(&mut self.next_inlay_id)),
properties, properties,
}; };
self.inlays.insert(inlay.id, inlay.clone()); self.inlays.insert(inlay.id, (location, inlay.clone()));
new_ids.push(inlay.id); new_ids.push(inlay.id);
let buffer_point = inlay let buffer_point = inlay
@ -253,7 +253,7 @@ impl InlayMap {
} }
for inlay_id in to_remove { for inlay_id in to_remove {
if let Some(inlay) = self.inlays.remove(&inlay_id) { if let Some((_, inlay)) = self.inlays.remove(&inlay_id) {
let buffer_point = inlay let buffer_point = inlay
.properties .properties
.position .position
@ -448,10 +448,16 @@ mod tests {
let (inlay_snapshot, _, inlay_ids) = inlay_map.splice( let (inlay_snapshot, _, inlay_ids) = inlay_map.splice(
HashSet::default(), HashSet::default(),
vec![InlayProperties { vec![(
InlayHintLocation {
buffer_id: 0,
excerpt_id: ExcerptId::default(),
},
InlayProperties {
position: buffer.read(cx).read(cx).anchor_before(3), position: buffer.read(cx).read(cx).anchor_before(3),
text: "|123|".into(), text: "|123|".into(),
}], },
)],
); );
assert_eq!(inlay_snapshot.text(), "abc|123|defghi"); assert_eq!(inlay_snapshot.text(), "abc|123|defghi");

View file

@ -1153,24 +1153,30 @@ impl CopilotState {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InlayHintLocation {
pub buffer_id: u64,
pub excerpt_id: ExcerptId,
}
// TODO kb // TODO kb
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
struct InlayHintVersions { struct InlayHintVersions {
last_buffer_versions_with_hints: HashMap<usize, Global>, last_buffer_versions_with_hints: HashMap<InlayHintLocation, Global>,
} }
impl InlayHintVersions { impl InlayHintVersions {
fn absent_or_newer(&self, buffer_id: usize, new_version: &Global) -> bool { fn absent_or_newer(&self, location: &InlayHintLocation, new_version: &Global) -> bool {
self.last_buffer_versions_with_hints self.last_buffer_versions_with_hints
.get(&buffer_id) .get(location)
.map(|last_version_with_hints| new_version.changed_since(&last_version_with_hints)) .map(|last_version_with_hints| new_version.changed_since(&last_version_with_hints))
.unwrap_or(true) .unwrap_or(true)
} }
fn insert(&mut self, buffer_id: usize, new_version: Global) -> bool { fn insert(&mut self, location: InlayHintLocation, new_version: Global) -> bool {
if self.absent_or_newer(buffer_id, &new_version) { if self.absent_or_newer(&location, &new_version) {
self.last_buffer_versions_with_hints self.last_buffer_versions_with_hints
.insert(buffer_id, new_version); .insert(location, new_version);
true true
} else { } else {
false false
@ -2617,50 +2623,40 @@ impl Editor {
return; return;
} }
let hint_fetch_tasks = self let multi_buffer = self.buffer().read(cx);
.buffer() let buffer_snapshot = multi_buffer.snapshot(cx);
.read(cx) let hint_fetch_tasks = buffer_snapshot
.all_buffers() .excerpts()
.into_iter() .map(|(excerpt_id, excerpt_buffer_snapshot, _)| {
.map(|buffer_handle| { (excerpt_id, excerpt_buffer_snapshot.clone())
let buffer_id = buffer_handle.id(); })
.map(|(excerpt_id, excerpt_buffer_snapshot)| {
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
let task_data = editor let task = editor
.update(&mut cx, |editor, cx| { .update(&mut cx, |editor, cx| {
editor.project.as_ref().and_then(|project| { editor.project.as_ref().and_then(|project| {
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
let buffer = buffer_handle.read(cx); Some(
let end = buffer.len();
let version = buffer.version();
if editor
.inlay_hint_versions
.absent_or_newer(buffer_id, &version)
{
Some((
version,
project.inlay_hints_for_buffer( project.inlay_hints_for_buffer(
buffer_handle, editor
0..end, .buffer()
.read(cx)
.buffer(excerpt_buffer_snapshot.remote_id())?,
0..excerpt_buffer_snapshot.len(),
cx, cx,
), ),
)) )
} else {
None
}
}) })
}) })
}) })
.context("inlay hints fecth task spawn")?; .context("inlay hints fecth task spawn")?;
anyhow::Ok(( anyhow::Ok((
buffer_id, excerpt_id,
match task_data { excerpt_buffer_snapshot,
Some((buffer_version, task)) => Some(( match task {
buffer_version, Some(task) => task.await.context("inlay hints for buffer task")?,
task.await.context("inlay hints for buffer task")?, None => Vec::new(),
)),
None => None,
}, },
)) ))
}) })
@ -2668,21 +2664,32 @@ impl Editor {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
let mut new_hints = Vec::new(); let mut new_hints: HashMap<InlayHintLocation, Vec<project::InlayHint>> =
HashMap::default();
for task_result in futures::future::join_all(hint_fetch_tasks).await { for task_result in futures::future::join_all(hint_fetch_tasks).await {
match task_result { match task_result {
Ok((_buffer_id, None)) => {} Ok((excerpt_id, excerpt_buffer_snapshot, excerpt_hints)) => {
Ok((buffer_id, Some((buffer_with_hints_version, buffer_hints)))) => { let buffer_id = excerpt_buffer_snapshot.remote_id();
let should_update_hints = editor let should_update_hints = editor
.update(&mut cx, |editor, _| { .update(&mut cx, |editor, _| {
editor editor.inlay_hint_versions.insert(
.inlay_hint_versions InlayHintLocation {
.insert(buffer_id, buffer_with_hints_version) buffer_id,
excerpt_id,
},
excerpt_buffer_snapshot.version().clone(),
)
}) })
.log_err() .log_err()
.unwrap_or(false); .unwrap_or(false);
if should_update_hints { if should_update_hints {
new_hints.extend(buffer_hints); new_hints
.entry(InlayHintLocation {
buffer_id,
excerpt_id,
})
.or_default()
.extend(excerpt_hints);
} }
} }
Err(e) => error!("Failed to update hints for buffer: {e:#}"), Err(e) => error!("Failed to update hints for buffer: {e:#}"),