Move InlayId generation back to InlayCache

This commit is contained in:
Kirill Bulatov 2023-06-17 23:10:48 +03:00
parent e82b4d8957
commit 8c03e9e122
7 changed files with 147 additions and 133 deletions

View file

@ -4,7 +4,7 @@ mod inlay_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, InlayId, 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; use fold_map::FoldMap;
@ -28,7 +28,7 @@ pub use block_map::{
BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock, BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
}; };
pub use self::inlay_map::{Inlay, InlayId, InlayProperties}; pub use self::inlay_map::{Inlay, InlayProperties};
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FoldStatus { pub enum FoldStatus {
@ -249,11 +249,11 @@ impl DisplayMap {
pub fn splice_inlays<T: Into<Rope>>( pub fn splice_inlays<T: Into<Rope>>(
&mut self, &mut self,
to_remove: Vec<InlayId>, to_remove: Vec<InlayId>,
to_insert: Vec<(Option<InlayId>, InlayProperties<T>)>, to_insert: Vec<(InlayId, InlayProperties<T>)>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Vec<InlayId> { ) {
if to_remove.is_empty() && to_insert.is_empty() { if to_remove.is_empty() && to_insert.is_empty() {
return Vec::new(); return;
} }
let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
@ -267,14 +267,13 @@ impl DisplayMap {
.update(cx, |map, cx| map.sync(snapshot, edits, cx)); .update(cx, |map, cx| map.sync(snapshot, edits, cx));
self.block_map.read(snapshot, edits); self.block_map.read(snapshot, edits);
let (snapshot, edits, new_inlay_ids) = self.inlay_map.splice(to_remove, to_insert); let (snapshot, edits) = self.inlay_map.splice(to_remove, to_insert);
let (snapshot, edits) = self.fold_map.read(snapshot, edits); let (snapshot, edits) = self.fold_map.read(snapshot, edits);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size); let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
let (snapshot, edits) = self let (snapshot, edits) = self
.wrap_map .wrap_map
.update(cx, |map, cx| map.sync(snapshot, edits, cx)); .update(cx, |map, cx| map.sync(snapshot, edits, cx));
self.block_map.read(snapshot, edits); self.block_map.read(snapshot, edits);
new_inlay_ids
} }
fn tab_size(buffer: &ModelHandle<MultiBuffer>, cx: &mut ModelContext<Self>) -> NonZeroU32 { fn tab_size(buffer: &ModelHandle<MultiBuffer>, cx: &mut ModelContext<Self>) -> NonZeroU32 {

View file

@ -1475,6 +1475,7 @@ mod tests {
Arc::new((HighlightStyle::default(), highlight_ranges)), Arc::new((HighlightStyle::default(), highlight_ranges)),
); );
let mut next_inlay_id = 0;
for _ in 0..operations { for _ in 0..operations {
log::info!("text: {:?}", buffer_snapshot.text()); log::info!("text: {:?}", buffer_snapshot.text());
let mut buffer_edits = Vec::new(); let mut buffer_edits = Vec::new();
@ -1484,7 +1485,7 @@ mod tests {
snapshot_edits.extend(map.randomly_mutate(&mut rng)); snapshot_edits.extend(map.randomly_mutate(&mut rng));
} }
40..=59 => { 40..=59 => {
let (_, edits) = inlay_map.randomly_mutate(&mut rng); let (_, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
inlay_edits = edits; inlay_edits = edits;
} }
_ => buffer.update(cx, |buffer, cx| { _ => buffer.update(cx, |buffer, cx| {

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
multi_buffer::{MultiBufferChunks, MultiBufferRows}, multi_buffer::{MultiBufferChunks, MultiBufferRows},
Anchor, MultiBufferSnapshot, ToOffset, Anchor, InlayId, MultiBufferSnapshot, ToOffset,
}; };
use collections::{BTreeSet, HashMap}; use collections::{BTreeSet, HashMap};
use gpui::fonts::HighlightStyle; use gpui::fonts::HighlightStyle;
@ -12,13 +12,11 @@ use std::{
}; };
use sum_tree::{Bias, Cursor, SumTree}; use sum_tree::{Bias, Cursor, SumTree};
use text::Patch; use text::Patch;
use util::post_inc;
pub struct InlayMap { pub struct InlayMap {
snapshot: Mutex<InlaySnapshot>, snapshot: Mutex<InlaySnapshot>,
inlays_by_id: HashMap<InlayId, Inlay>, inlays_by_id: HashMap<InlayId, Inlay>,
inlays: Vec<Inlay>, inlays: Vec<Inlay>,
next_inlay_id: usize,
} }
#[derive(Clone)] #[derive(Clone)]
@ -34,9 +32,6 @@ enum Transform {
Inlay(Inlay), Inlay(Inlay),
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InlayId(usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Inlay { pub struct Inlay {
pub id: InlayId, pub id: InlayId,
@ -316,7 +311,6 @@ impl InlayMap {
snapshot: Mutex::new(snapshot.clone()), snapshot: Mutex::new(snapshot.clone()),
inlays_by_id: HashMap::default(), inlays_by_id: HashMap::default(),
inlays: Vec::new(), inlays: Vec::new(),
next_inlay_id: 0,
}, },
snapshot, snapshot,
) )
@ -461,8 +455,8 @@ impl InlayMap {
pub fn splice<T: Into<Rope>>( pub fn splice<T: Into<Rope>>(
&mut self, &mut self,
to_remove: Vec<InlayId>, to_remove: Vec<InlayId>,
to_insert: Vec<(Option<InlayId>, InlayProperties<T>)>, to_insert: Vec<(InlayId, InlayProperties<T>)>,
) -> (InlaySnapshot, Vec<InlayEdit>, Vec<InlayId>) { ) -> (InlaySnapshot, Vec<InlayEdit>) {
let snapshot = self.snapshot.lock(); let snapshot = self.snapshot.lock();
let mut edits = BTreeSet::new(); let mut edits = BTreeSet::new();
@ -474,16 +468,12 @@ impl InlayMap {
} }
} }
let mut new_inlay_ids = Vec::with_capacity(to_insert.len());
for (existing_id, properties) in to_insert { for (existing_id, properties) in to_insert {
let inlay = Inlay { let inlay = Inlay {
id: existing_id.unwrap_or_else(|| InlayId(post_inc(&mut self.next_inlay_id))), id: existing_id,
position: properties.position, position: properties.position,
text: properties.text.into(), text: properties.text.into(),
}; };
if existing_id.is_none() {
new_inlay_ids.push(inlay.id);
}
self.inlays_by_id.insert(inlay.id, inlay.clone()); self.inlays_by_id.insert(inlay.id, inlay.clone());
match self match self
.inlays .inlays
@ -508,7 +498,7 @@ impl InlayMap {
let buffer_snapshot = snapshot.buffer.clone(); let buffer_snapshot = snapshot.buffer.clone();
drop(snapshot); drop(snapshot);
let (snapshot, edits) = self.sync(buffer_snapshot, buffer_edits); let (snapshot, edits) = self.sync(buffer_snapshot, buffer_edits);
(snapshot, edits, new_inlay_ids) (snapshot, edits)
} }
pub fn current_inlays(&self) -> impl Iterator<Item = &Inlay> { pub fn current_inlays(&self) -> impl Iterator<Item = &Inlay> {
@ -518,9 +508,11 @@ impl InlayMap {
#[cfg(test)] #[cfg(test)]
pub(crate) fn randomly_mutate( pub(crate) fn randomly_mutate(
&mut self, &mut self,
next_inlay_id: &mut usize,
rng: &mut rand::rngs::StdRng, rng: &mut rand::rngs::StdRng,
) -> (InlaySnapshot, Vec<InlayEdit>) { ) -> (InlaySnapshot, Vec<InlayEdit>) {
use rand::prelude::*; use rand::prelude::*;
use util::post_inc;
let mut to_remove = Vec::new(); let mut to_remove = Vec::new();
let mut to_insert = Vec::new(); let mut to_insert = Vec::new();
@ -541,7 +533,7 @@ impl InlayMap {
text text
); );
to_insert.push(( to_insert.push((
None, InlayId(post_inc(next_inlay_id)),
InlayProperties { InlayProperties {
position: snapshot.buffer.anchor_at(position, bias), position: snapshot.buffer.anchor_at(position, bias),
text, text,
@ -554,7 +546,7 @@ impl InlayMap {
log::info!("removing inlays: {:?}", to_remove); log::info!("removing inlays: {:?}", to_remove);
drop(snapshot); drop(snapshot);
let (snapshot, edits, _) = self.splice(to_remove, to_insert); let (snapshot, edits) = self.splice(to_remove, to_insert);
(snapshot, edits) (snapshot, edits)
} }
} }
@ -860,12 +852,13 @@ fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::MultiBuffer; use crate::{InlayId, MultiBuffer};
use gpui::AppContext; use gpui::AppContext;
use rand::prelude::*; use rand::prelude::*;
use settings::SettingsStore; use settings::SettingsStore;
use std::env; use std::env;
use text::Patch; use text::Patch;
use util::post_inc;
#[gpui::test] #[gpui::test]
fn test_basic_inlays(cx: &mut AppContext) { fn test_basic_inlays(cx: &mut AppContext) {
@ -873,11 +866,12 @@ mod tests {
let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe()); let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx)); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
assert_eq!(inlay_snapshot.text(), "abcdefghi"); assert_eq!(inlay_snapshot.text(), "abcdefghi");
let mut next_inlay_id = 0;
let (inlay_snapshot, _, _) = inlay_map.splice( let (inlay_snapshot, _) = inlay_map.splice(
Vec::new(), Vec::new(),
vec![( vec![(
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_after(3), position: buffer.read(cx).snapshot(cx).anchor_after(3),
text: "|123|", text: "|123|",
@ -952,18 +946,18 @@ mod tests {
); );
assert_eq!(inlay_snapshot.text(), "abxyDzefghi"); assert_eq!(inlay_snapshot.text(), "abxyDzefghi");
let (inlay_snapshot, _, _) = inlay_map.splice( let (inlay_snapshot, _) = inlay_map.splice(
Vec::new(), Vec::new(),
vec![ vec![
( (
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_before(3), position: buffer.read(cx).snapshot(cx).anchor_before(3),
text: "|123|", text: "|123|",
}, },
), ),
( (
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_after(3), position: buffer.read(cx).snapshot(cx).anchor_after(3),
text: "|456|", text: "|456|",
@ -982,7 +976,7 @@ mod tests {
assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi"); assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi");
// The inlays can be manually removed. // The inlays can be manually removed.
let (inlay_snapshot, _, _) = inlay_map let (inlay_snapshot, _) = inlay_map
.splice::<String>(inlay_map.inlays_by_id.keys().copied().collect(), Vec::new()); .splice::<String>(inlay_map.inlays_by_id.keys().copied().collect(), Vec::new());
assert_eq!(inlay_snapshot.text(), "abxJKLyDzefghi"); assert_eq!(inlay_snapshot.text(), "abxJKLyDzefghi");
} }
@ -992,26 +986,27 @@ mod tests {
let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx); let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx);
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx)); let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi"); assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
let mut next_inlay_id = 0;
let (inlay_snapshot, _, _) = inlay_map.splice( let (inlay_snapshot, _) = inlay_map.splice(
Vec::new(), Vec::new(),
vec![ vec![
( (
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_before(0), position: buffer.read(cx).snapshot(cx).anchor_before(0),
text: "|123|\n", text: "|123|\n",
}, },
), ),
( (
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_before(4), position: buffer.read(cx).snapshot(cx).anchor_before(4),
text: "|456|", text: "|456|",
}, },
), ),
( (
None, InlayId(post_inc(&mut next_inlay_id)),
InlayProperties { InlayProperties {
position: buffer.read(cx).snapshot(cx).anchor_before(7), position: buffer.read(cx).snapshot(cx).anchor_before(7),
text: "\n|567|\n", text: "\n|567|\n",
@ -1044,6 +1039,7 @@ mod tests {
MultiBuffer::build_random(&mut rng, cx) MultiBuffer::build_random(&mut rng, cx)
}; };
let mut buffer_snapshot = buffer.read(cx).snapshot(cx); let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
let mut next_inlay_id = 0;
log::info!("buffer text: {:?}", buffer_snapshot.text()); log::info!("buffer text: {:?}", buffer_snapshot.text());
let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
@ -1054,7 +1050,7 @@ mod tests {
let mut buffer_edits = Vec::new(); let mut buffer_edits = Vec::new();
match rng.gen_range(0..=100) { match rng.gen_range(0..=100) {
0..=50 => { 0..=50 => {
let (snapshot, edits) = inlay_map.randomly_mutate(&mut rng); let (snapshot, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
log::info!("mutated text: {:?}", snapshot.text()); log::info!("mutated text: {:?}", snapshot.text());
inlay_edits = Patch::new(edits); inlay_edits = Patch::new(edits);
} }

View file

@ -708,7 +708,7 @@ mod tests {
fold_map.randomly_mutate(&mut rng); fold_map.randomly_mutate(&mut rng);
let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]); let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]);
log::info!("FoldMap text: {:?}", fold_snapshot.text()); log::info!("FoldMap text: {:?}", fold_snapshot.text());
let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut rng); let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut 0, &mut rng);
log::info!("InlayMap text: {:?}", inlay_snapshot.text()); log::info!("InlayMap text: {:?}", inlay_snapshot.text());
let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size); let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);

View file

@ -1119,6 +1119,7 @@ mod tests {
); );
log::info!("Wrapped text: {:?}", actual_text); log::info!("Wrapped text: {:?}", actual_text);
let mut next_inlay_id = 0;
let mut edits = Vec::new(); let mut edits = Vec::new();
for _i in 0..operations { for _i in 0..operations {
log::info!("{} ==============================================", _i); log::info!("{} ==============================================", _i);
@ -1146,7 +1147,8 @@ mod tests {
} }
} }
40..=59 => { 40..=59 => {
let (inlay_snapshot, inlay_edits) = inlay_map.randomly_mutate(&mut rng); let (inlay_snapshot, inlay_edits) =
inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits); let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
let (tabs_snapshot, tab_edits) = let (tabs_snapshot, tab_edits) =
tab_map.sync(fold_snapshot, fold_edits, tab_size); tab_map.sync(fold_snapshot, fold_edits, tab_size);

View file

@ -185,6 +185,9 @@ pub struct GutterHover {
pub hovered: bool, pub hovered: bool,
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InlayId(usize);
actions!( actions!(
editor, editor,
[ [
@ -541,6 +544,7 @@ pub struct Editor {
link_go_to_definition_state: LinkGoToDefinitionState, link_go_to_definition_state: LinkGoToDefinitionState,
copilot_state: CopilotState, copilot_state: CopilotState,
inlay_hint_cache: InlayHintCache, inlay_hint_cache: InlayHintCache,
next_inlay_id: usize,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
@ -1339,6 +1343,7 @@ impl Editor {
.add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)), .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)),
completion_tasks: Default::default(), completion_tasks: Default::default(),
next_completion_id: 0, next_completion_id: 0,
next_inlay_id: 0,
available_code_actions: Default::default(), available_code_actions: Default::default(),
code_actions_task: Default::default(), code_actions_task: Default::default(),
document_highlights_task: Default::default(), document_highlights_task: Default::default(),
@ -2664,7 +2669,7 @@ impl Editor {
to_insert, to_insert,
} = editor } = editor
.update(&mut cx, |editor, cx| { .update(&mut cx, |editor, cx| {
editor.inlay_hint_cache.append_inlays( editor.inlay_hint_cache.append_hints(
multi_buffer_handle, multi_buffer_handle,
std::iter::once(updated_range_query), std::iter::once(updated_range_query),
cx, cx,
@ -2693,7 +2698,7 @@ impl Editor {
to_insert, to_insert,
} = editor } = editor
.update(&mut cx, |editor, cx| { .update(&mut cx, |editor, cx| {
editor.inlay_hint_cache.replace_inlays( editor.inlay_hint_cache.replace_hints(
multi_buffer_handle, multi_buffer_handle,
replacement_queries.into_iter(), replacement_queries.into_iter(),
currently_shown_inlay_hints, currently_shown_inlay_hints,
@ -2738,7 +2743,7 @@ impl Editor {
fn splice_inlay_hints( fn splice_inlay_hints(
&self, &self,
to_remove: Vec<InlayId>, to_remove: Vec<InlayId>,
to_insert: Vec<(Option<InlayId>, Anchor, project::InlayHint)>, to_insert: Vec<(InlayId, Anchor, 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);
@ -3514,23 +3519,19 @@ impl Editor {
to_remove.push(suggestion.id); to_remove.push(suggestion.id);
} }
let suggestion_inlay_id = self.next_inlay_id();
let to_insert = vec![( let to_insert = vec![(
None, suggestion_inlay_id,
InlayProperties { InlayProperties {
position: cursor, position: cursor,
text: text.clone(), text: text.clone(),
}, },
)]; )];
let new_inlay_ids = self.display_map.update(cx, move |map, cx| { self.display_map.update(cx, move |map, cx| {
map.splice_inlays(to_remove, to_insert, cx) map.splice_inlays(to_remove, to_insert, cx)
}); });
assert_eq!(
new_inlay_ids.len(),
1,
"Expecting only copilot suggestion id generated"
);
self.copilot_state.suggestion = Some(Inlay { self.copilot_state.suggestion = Some(Inlay {
id: new_inlay_ids.into_iter().next().unwrap(), id: suggestion_inlay_id,
position: cursor, position: cursor,
text, text,
}); });
@ -7687,6 +7688,10 @@ impl Editor {
let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { return; }; let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { return; };
cx.write_to_clipboard(ClipboardItem::new(lines)); cx.write_to_clipboard(ClipboardItem::new(lines));
} }
pub fn next_inlay_id(&mut self) -> InlayId {
InlayId(post_inc(&mut self.next_inlay_id))
}
} }
fn inlay_hint_query( fn inlay_hint_query(

View file

@ -1,8 +1,7 @@
use std::ops::Range; use std::ops::Range;
use crate::{ use crate::{
display_map::InlayId, editor_settings, scroll::ScrollAnchor, Anchor, Editor, ExcerptId, editor_settings, scroll::ScrollAnchor, Anchor, Editor, ExcerptId, InlayId, MultiBuffer,
MultiBuffer,
}; };
use anyhow::Context; use anyhow::Context;
use clock::Global; use clock::Global;
@ -12,6 +11,7 @@ use log::error;
use project::{InlayHint, InlayHintKind}; use project::{InlayHint, InlayHintKind};
use collections::{hash_map, HashMap, HashSet}; use collections::{hash_map, HashMap, HashSet};
use util::post_inc;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum InlayRefreshReason { pub enum InlayRefreshReason {
@ -20,26 +20,39 @@ pub enum InlayRefreshReason {
VisibleExcerptsChange, VisibleExcerptsChange,
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Default)]
pub struct InlayHintCache { pub struct InlayHintCache {
inlay_hints: HashMap<InlayId, InlayHint>, inlay_hints: HashMap<InlayId, InlayHint>,
inlays_in_buffers: HashMap<u64, BufferInlays<(Anchor, InlayId)>>, hints_in_buffers: HashMap<u64, BufferHints<(Anchor, InlayId)>>,
allowed_hint_kinds: HashSet<Option<InlayHintKind>>, allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug)]
struct BufferInlays<I> { struct BufferHints<I> {
buffer_version: Global, buffer_version: Global,
cached_ranges: HashMap<ExcerptId, Vec<Range<usize>>>, hints_per_excerpt: HashMap<ExcerptId, ExcerptHints<I>>,
excerpt_inlays: HashMap<ExcerptId, Vec<I>>,
} }
impl<I> BufferInlays<I> { #[derive(Clone, Debug)]
struct ExcerptHints<I> {
cached_excerpt_offsets: Vec<Range<usize>>,
hints: Vec<I>,
}
impl<I> Default for ExcerptHints<I> {
fn default() -> Self {
Self {
cached_excerpt_offsets: Vec::new(),
hints: Vec::new(),
}
}
}
impl<I> BufferHints<I> {
fn new(buffer_version: Global) -> Self { fn new(buffer_version: Global) -> Self {
Self { Self {
buffer_version, buffer_version,
excerpt_inlays: HashMap::default(), hints_per_excerpt: HashMap::default(),
cached_ranges: HashMap::default(),
} }
} }
} }
@ -47,7 +60,7 @@ impl<I> BufferInlays<I> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct InlaySplice { pub struct InlaySplice {
pub to_remove: Vec<InlayId>, pub to_remove: Vec<InlayId>,
pub to_insert: Vec<(Option<InlayId>, Anchor, InlayHint)>, pub to_insert: Vec<(InlayId, Anchor, InlayHint)>,
} }
pub struct InlayHintQuery { pub struct InlayHintQuery {
@ -61,7 +74,7 @@ impl InlayHintCache {
pub fn new(inlay_hint_settings: editor_settings::InlayHints) -> Self { pub fn new(inlay_hint_settings: editor_settings::InlayHints) -> Self {
Self { Self {
allowed_hint_kinds: allowed_inlay_hint_types(inlay_hint_settings), allowed_hint_kinds: allowed_inlay_hint_types(inlay_hint_settings),
inlays_in_buffers: HashMap::default(), hints_in_buffers: HashMap::default(),
inlay_hints: HashMap::default(), inlay_hints: HashMap::default(),
} }
} }
@ -117,26 +130,27 @@ impl InlayHintCache {
} }
let reenabled_hints = self let reenabled_hints = self
.inlays_in_buffers .hints_in_buffers
.iter() .iter()
.filter_map(|(cached_buffer_id, cached_hints_per_excerpt)| { .filter_map(|(cached_buffer_id, cached_hints_per_excerpt)| {
let considered_hints_in_excerpts = considered_hints.get(cached_buffer_id)?; let considered_hints_in_excerpts = considered_hints.get(cached_buffer_id)?;
let not_considered_cached_inlays = cached_hints_per_excerpt let not_considered_cached_hints = cached_hints_per_excerpt
.excerpt_inlays .hints_per_excerpt
.iter() .iter()
.filter_map(|(cached_excerpt_id, cached_hints)| { .filter_map(|(cached_excerpt_id, cached_excerpt_hints)| {
let considered_excerpt_hints = let considered_excerpt_hints =
considered_hints_in_excerpts.get(&cached_excerpt_id)?; considered_hints_in_excerpts.get(&cached_excerpt_id)?;
let not_considered_cached_inlays = cached_hints let not_considered_cached_hints = cached_excerpt_hints
.hints
.iter() .iter()
.filter(|(_, cached_hint_id)| { .filter(|(_, cached_hint_id)| {
!considered_excerpt_hints.contains(cached_hint_id) !considered_excerpt_hints.contains(cached_hint_id)
}) })
.copied(); .copied();
Some(not_considered_cached_inlays) Some(not_considered_cached_hints)
}) })
.flatten(); .flatten();
Some(not_considered_cached_inlays) Some(not_considered_cached_hints)
}) })
.flatten() .flatten()
.filter_map(|(cached_anchor, cached_inlay_id)| { .filter_map(|(cached_anchor, cached_inlay_id)| {
@ -148,11 +162,7 @@ impl InlayHintCache {
}) })
.filter(|(_, _, cached_inlay)| self.allowed_hint_kinds.contains(&cached_inlay.kind)) .filter(|(_, _, cached_inlay)| self.allowed_hint_kinds.contains(&cached_inlay.kind))
.map(|(cached_anchor, cached_inlay_id, reenabled_inlay)| { .map(|(cached_anchor, cached_inlay_id, reenabled_inlay)| {
( (cached_inlay_id, cached_anchor, reenabled_inlay.clone())
Some(cached_inlay_id),
cached_anchor,
reenabled_inlay.clone(),
)
}); });
to_insert.extend(reenabled_hints); to_insert.extend(reenabled_hints);
@ -173,25 +183,25 @@ impl InlayHintCache {
pub fn clear(&mut self) -> Vec<InlayId> { pub fn clear(&mut self) -> Vec<InlayId> {
let ids_to_remove = self.inlay_hints.drain().map(|(id, _)| id).collect(); let ids_to_remove = self.inlay_hints.drain().map(|(id, _)| id).collect();
self.inlays_in_buffers.clear(); self.hints_in_buffers.clear();
ids_to_remove ids_to_remove
} }
pub fn append_inlays( pub fn append_hints(
&mut self, &mut self,
multi_buffer: ModelHandle<MultiBuffer>, multi_buffer: ModelHandle<MultiBuffer>,
ranges_to_add: impl Iterator<Item = InlayHintQuery>, ranges_to_add: impl Iterator<Item = InlayHintQuery>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> Task<anyhow::Result<InlaySplice>> { ) -> Task<anyhow::Result<InlaySplice>> {
let queries = ranges_to_add.filter_map(|additive_query| { let queries = ranges_to_add.filter_map(|additive_query| {
let Some(cached_buffer_inlays) = self.inlays_in_buffers.get(&additive_query.buffer_id) let Some(cached_buffer_hints) = self.hints_in_buffers.get(&additive_query.buffer_id)
else { return Some(vec![additive_query]) }; else { return Some(vec![additive_query]) };
if cached_buffer_inlays.buffer_version.changed_since(&additive_query.buffer_version) { if cached_buffer_hints.buffer_version.changed_since(&additive_query.buffer_version) {
return None return None
} }
let Some(excerpt_cached_ranges) = cached_buffer_inlays.cached_ranges.get(&additive_query.excerpt_id) let Some(excerpt_hints) = cached_buffer_hints.hints_per_excerpt.get(&additive_query.excerpt_id)
else { return Some(vec![additive_query]) }; else { return Some(vec![additive_query]) };
let non_cached_ranges = missing_subranges(&excerpt_cached_ranges, &additive_query.excerpt_offset_query_range); let non_cached_ranges = missing_subranges(&excerpt_hints.cached_excerpt_offsets, &additive_query.excerpt_offset_query_range);
if non_cached_ranges.is_empty() { if non_cached_ranges.is_empty() {
None None
} else { } else {
@ -210,55 +220,59 @@ impl InlayHintCache {
let new_hints = fetch_queries_task.await?; let new_hints = fetch_queries_task.await?;
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
let multi_buffer_snapshot = task_multi_buffer.read(cx).snapshot(cx); let multi_buffer_snapshot = task_multi_buffer.read(cx).snapshot(cx);
let inlay_hint_cache = &mut editor.inlay_hint_cache;
let mut to_insert = Vec::new(); let mut to_insert = Vec::new();
for (new_buffer_id, new_hints_per_buffer) in new_hints { for (new_buffer_id, new_hints_per_buffer) in new_hints {
let cached_buffer_inlays = inlay_hint_cache let cached_buffer_hints = editor
.inlays_in_buffers .inlay_hint_cache
.hints_in_buffers
.entry(new_buffer_id) .entry(new_buffer_id)
.or_insert_with(|| { .or_insert_with(|| {
BufferInlays::new(new_hints_per_buffer.buffer_version.clone()) BufferHints::new(new_hints_per_buffer.buffer_version.clone())
}); });
if cached_buffer_inlays if cached_buffer_hints
.buffer_version .buffer_version
.changed_since(&new_hints_per_buffer.buffer_version) .changed_since(&new_hints_per_buffer.buffer_version)
{ {
continue; continue;
} }
for (new_excerpt_id, new_ranges) in new_hints_per_buffer.cached_ranges { for (new_excerpt_id, new_excerpt_hints) in
let cached_ranges = cached_buffer_inlays new_hints_per_buffer.hints_per_excerpt
.cached_ranges {
let cached_excerpt_hints = cached_buffer_hints
.hints_per_excerpt
.entry(new_excerpt_id) .entry(new_excerpt_id)
.or_default(); .or_insert_with(|| ExcerptHints::default());
for new_range in new_ranges { for new_range in new_excerpt_hints.cached_excerpt_offsets {
insert_and_merge_ranges(cached_ranges, &new_range) insert_and_merge_ranges(
&mut cached_excerpt_hints.cached_excerpt_offsets,
&new_range,
)
} }
} for new_inlay_hint in new_excerpt_hints.hints {
for (new_excerpt_id, new_hints) in new_hints_per_buffer.excerpt_inlays {
let cached_inlays = cached_buffer_inlays
.excerpt_inlays
.entry(new_excerpt_id)
.or_default();
for new_inlay_hint in new_hints {
let new_inlay_id = todo!("TODO kb");
let hint_anchor = multi_buffer_snapshot let hint_anchor = multi_buffer_snapshot
.anchor_in_excerpt(new_excerpt_id, new_inlay_hint.position); .anchor_in_excerpt(new_excerpt_id, new_inlay_hint.position);
match cached_inlays.binary_search_by(|probe| { let insert_ix =
match cached_excerpt_hints.hints.binary_search_by(|probe| {
hint_anchor.cmp(&probe.0, &multi_buffer_snapshot) hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
}) { }) {
Ok(ix) | Err(ix) => { Ok(ix) | Err(ix) => ix,
cached_inlays.insert(ix, (hint_anchor, new_inlay_id)) };
}
} let new_inlay_id = InlayId(post_inc(&mut editor.next_inlay_id));
inlay_hint_cache cached_excerpt_hints
.hints
.insert(insert_ix, (hint_anchor, new_inlay_id));
editor
.inlay_hint_cache
.inlay_hints .inlay_hints
.insert(new_inlay_id, new_inlay_hint.clone()); .insert(new_inlay_id, new_inlay_hint.clone());
if inlay_hint_cache if editor
.inlay_hint_cache
.allowed_hint_kinds .allowed_hint_kinds
.contains(&new_inlay_hint.kind) .contains(&new_inlay_hint.kind)
{ {
to_insert.push((Some(new_inlay_id), hint_anchor, new_inlay_hint)); to_insert.push((new_inlay_id, hint_anchor, new_inlay_hint));
} }
} }
} }
@ -272,7 +286,7 @@ impl InlayHintCache {
}) })
} }
pub fn replace_inlays( pub fn replace_hints(
&mut self, &mut self,
multi_buffer: ModelHandle<MultiBuffer>, multi_buffer: ModelHandle<MultiBuffer>,
new_ranges: impl Iterator<Item = InlayHintQuery>, new_ranges: impl Iterator<Item = InlayHintQuery>,
@ -401,7 +415,7 @@ fn fetch_queries<'a, 'b>(
multi_buffer: ModelHandle<MultiBuffer>, multi_buffer: ModelHandle<MultiBuffer>,
queries: impl Iterator<Item = InlayHintQuery>, queries: impl Iterator<Item = InlayHintQuery>,
cx: &mut ViewContext<'a, 'b, Editor>, cx: &mut ViewContext<'a, 'b, Editor>,
) -> Task<anyhow::Result<HashMap<u64, BufferInlays<InlayHint>>>> { ) -> Task<anyhow::Result<HashMap<u64, BufferHints<InlayHint>>>> {
let mut inlay_fetch_tasks = Vec::new(); let mut inlay_fetch_tasks = Vec::new();
for query in queries { for query in queries {
let task_multi_buffer = multi_buffer.clone(); let task_multi_buffer = multi_buffer.clone();
@ -434,33 +448,30 @@ fn fetch_queries<'a, 'b>(
} }
cx.spawn(|editor, cx| async move { cx.spawn(|editor, cx| async move {
let mut inlay_updates: HashMap<u64, BufferInlays<InlayHint>> = HashMap::default(); let mut inlay_updates: HashMap<u64, BufferHints<InlayHint>> = HashMap::default();
for task_result in futures::future::join_all(inlay_fetch_tasks).await { for task_result in futures::future::join_all(inlay_fetch_tasks).await {
match task_result { match task_result {
Ok((query, Some(response_inlays))) => { Ok((query, Some(response_hints))) => {
let Some(buffer_snapshot) = editor.read_with(&cx, |editor, cx| { let Some(buffer_snapshot) = editor.read_with(&cx, |editor, cx| {
editor.buffer().read(cx).buffer(query.buffer_id).map(|buffer| buffer.read(cx).snapshot()) editor.buffer().read(cx).buffer(query.buffer_id).map(|buffer| buffer.read(cx).snapshot())
})? else { continue; }; })? else { continue; };
let buffer_inlays = inlay_updates let buffer_hints = inlay_updates
.entry(query.buffer_id) .entry(query.buffer_id)
.or_insert_with(|| BufferInlays::new(query.buffer_version.clone())); .or_insert_with(|| BufferHints::new(query.buffer_version.clone()));
assert_eq!(buffer_inlays.buffer_version, query.buffer_version); if buffer_snapshot.version().changed_since(&buffer_hints.buffer_version) {
{ continue;
let cached_ranges = buffer_inlays }
.cached_ranges let cached_excerpt_hints = buffer_hints
.hints_per_excerpt
.entry(query.excerpt_id) .entry(query.excerpt_id)
.or_default(); .or_default();
insert_and_merge_ranges(cached_ranges, &query.excerpt_offset_query_range); insert_and_merge_ranges(&mut cached_excerpt_hints.cached_excerpt_offsets, &query.excerpt_offset_query_range);
let excerpt_inlays = buffer_inlays let excerpt_hints = &mut cached_excerpt_hints.hints;
.excerpt_inlays for inlay in response_hints {
.entry(query.excerpt_id) match excerpt_hints.binary_search_by(|probe| {
.or_default();
for inlay in response_inlays {
match excerpt_inlays.binary_search_by(|probe| {
inlay.position.cmp(&probe.position, &buffer_snapshot) inlay.position.cmp(&probe.position, &buffer_snapshot)
}) { }) {
Ok(ix) | Err(ix) => excerpt_inlays.insert(ix, inlay), Ok(ix) | Err(ix) => excerpt_hints.insert(ix, inlay),
}
} }
} }
} }