@@ -6,8 +6,8 @@ mod tab_map;
mod wrap_map;
use crate::{
- display_map::inlay_map::InlayProperties, Anchor, AnchorRangeExt, InlayHintLocation,
- MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
+ display_map::inlay_map::InlayProperties, Anchor, AnchorRangeExt, MultiBuffer,
+ MultiBufferSnapshot, ToOffset, ToPoint,
};
pub use block_map::{BlockMap, BlockPoint};
use collections::{HashMap, HashSet};
@@ -287,7 +287,7 @@ impl DisplayMap {
pub fn splice_inlays(
&mut self,
- new_hints: &HashMap<InlayHintLocation, Vec<project::InlayHint>>,
+ new_hints: Vec<(Anchor, project::InlayHint)>,
cx: &mut ModelContext<Self>,
) {
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
@@ -302,18 +302,13 @@ impl DisplayMap {
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
self.block_map.read(snapshot, edits);
- let mut new_inlays = Vec::new();
- for (&location, hints) in new_hints {
- for hint in hints {
- let hint_anchor =
- buffer_snapshot.anchor_in_excerpt(location.excerpt_id, hint.position);
- new_inlays.push(InlayProperties {
- position: hint_anchor.bias_left(&buffer_snapshot),
- text: hint.text(),
- });
- }
- }
-
+ let new_inlays = new_hints
+ .into_iter()
+ .map(|(hint_anchor, hint)| InlayProperties {
+ position: hint_anchor.bias_left(&buffer_snapshot),
+ text: hint.text(),
+ })
+ .collect();
let (snapshot, edits, _) = self.inlay_map.splice(
// TODO kb this is wrong, calc diffs in the editor instead.
self.inlay_map.inlays.keys().copied().collect(),
@@ -2,6 +2,7 @@ mod blink_manager;
pub mod display_map;
mod editor_settings;
mod element;
+mod inlay_hint_storage;
mod git;
mod highlight_matching_bracket;
@@ -25,7 +26,7 @@ use aho_corasick::AhoCorasick;
use anyhow::{anyhow, Context, Result};
use blink_manager::BlinkManager;
use client::{ClickhouseEvent, TelemetrySettings};
-use clock::{Global, ReplicaId};
+use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
use copilot::Copilot;
pub use display_map::DisplayPoint;
@@ -52,6 +53,7 @@ use gpui::{
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
+use inlay_hint_storage::InlayHintStorage;
pub use items::MAX_TAB_TITLE_LEN;
use itertools::Itertools;
pub use language::{char_kind, CharKind};
@@ -71,7 +73,9 @@ pub use multi_buffer::{
};
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
use ordered_float::OrderedFloat;
-use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
+use project::{
+ FormatTrigger, InlayHint, Location, LocationLink, Project, ProjectPath, ProjectTransaction,
+};
use scroll::{
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
};
@@ -536,7 +540,7 @@ pub struct Editor {
gutter_hovered: bool,
link_go_to_definition_state: LinkGoToDefinitionState,
copilot_state: CopilotState,
- inlay_hint_versions: InlayHintVersions,
+ inlay_hint_storage: InlayHintStorage,
_subscriptions: Vec<Subscription>,
}
@@ -1153,37 +1157,6 @@ impl CopilotState {
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct InlayHintLocation {
- pub buffer_id: u64,
- pub excerpt_id: ExcerptId,
-}
-
-// TODO kb
-#[derive(Debug, Default, Clone)]
-struct InlayHintVersions {
- last_buffer_versions_with_hints: HashMap<InlayHintLocation, Global>,
-}
-
-impl InlayHintVersions {
- fn absent_or_newer(&self, location: &InlayHintLocation, new_version: &Global) -> bool {
- self.last_buffer_versions_with_hints
- .get(location)
- .map(|last_version_with_hints| new_version.changed_since(&last_version_with_hints))
- .unwrap_or(true)
- }
-
- fn insert(&mut self, location: InlayHintLocation, new_version: Global) -> bool {
- if self.absent_or_newer(&location, &new_version) {
- self.last_buffer_versions_with_hints
- .insert(location, new_version);
- true
- } else {
- false
- }
- }
-}
-
#[derive(Debug)]
struct ActiveDiagnosticGroup {
primary_range: Range<Anchor>,
@@ -1324,7 +1297,7 @@ impl Editor {
project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
match event {
project::Event::ReloadInlayHints => {
- editor.try_update_inlay_hints(cx);
+ editor.reload_inlay_hints(cx);
}
_ => {}
};
@@ -1382,7 +1355,7 @@ impl Editor {
hover_state: Default::default(),
link_go_to_definition_state: Default::default(),
copilot_state: Default::default(),
- inlay_hint_versions: InlayHintVersions::default(),
+ inlay_hint_storage: InlayHintStorage::default(),
gutter_hovered: false,
_subscriptions: vec![
cx.observe(&buffer, Self::on_buffer_changed),
@@ -2618,44 +2591,44 @@ impl Editor {
}
}
- fn try_update_inlay_hints(&self, cx: &mut ViewContext<Self>) {
+ fn reload_inlay_hints(&self, cx: &mut ViewContext<Self>) {
if self.mode != EditorMode::Full {
return;
}
- let multi_buffer = self.buffer().read(cx);
- let buffer_snapshot = multi_buffer.snapshot(cx);
- let hint_fetch_tasks = buffer_snapshot
- .excerpts()
- .map(|(excerpt_id, excerpt_buffer_snapshot, _)| {
- (excerpt_id, excerpt_buffer_snapshot.clone())
- })
- .map(|(excerpt_id, excerpt_buffer_snapshot)| {
+ let multi_buffer = self.buffer();
+ let hint_fetch_tasks = multi_buffer
+ .read(cx)
+ .all_buffers()
+ .into_iter()
+ .map(|buffer_handle| {
+ let buffer = buffer_handle.read(cx);
+ // TODO kb every time I reopen the same buffer, it's different.
+ // Find a way to understand it's the same buffer. Use paths?
+ dbg!(buffer_handle.id());
+ let buffer_id = dbg!(buffer.remote_id());
+ let buffer_len = buffer.len();
+
cx.spawn(|editor, mut cx| async move {
let task = editor
.update(&mut cx, |editor, cx| {
- editor.project.as_ref().and_then(|project| {
+ editor.project.as_ref().map(|project| {
project.update(cx, |project, cx| {
- Some(
- project.inlay_hints_for_buffer(
- editor
- .buffer()
- .read(cx)
- .buffer(excerpt_buffer_snapshot.remote_id())?,
- 0..excerpt_buffer_snapshot.len(),
- cx,
- ),
- )
+ project.inlay_hints_for_buffer(buffer_handle, 0..buffer_len, cx)
})
})
})
.context("inlay hints fecth task spawn")?;
anyhow::Ok((
- excerpt_id,
- excerpt_buffer_snapshot,
+ buffer_id,
match task {
- Some(task) => task.await.context("inlay hints for buffer task")?,
+ Some(task) => {
+ let mut buffer_hints =
+ task.await.context("inlay hints for buffer task")?;
+ buffer_hints.sort_unstable_by_key(|hint| hint.position.offset);
+ buffer_hints
+ }
None => Vec::new(),
},
))
@@ -2664,52 +2637,57 @@ impl Editor {
.collect::<Vec<_>>();
cx.spawn(|editor, mut cx| async move {
- let mut new_hints: HashMap<InlayHintLocation, Vec<project::InlayHint>> =
- HashMap::default();
+ let mut hints_to_draw: Vec<(Anchor, InlayHint)> = Vec::new();
+ let (multi_buffer, multi_buffer_snapshot) = editor.read_with(&cx, |editor, cx| {
+ let multi_buffer = editor.buffer().clone();
+ let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
+ (multi_buffer, multi_buffer_snapshot)
+ })?;
+
for task_result in futures::future::join_all(hint_fetch_tasks).await {
match task_result {
- Ok((excerpt_id, excerpt_buffer_snapshot, excerpt_hints)) => {
- let buffer_id = excerpt_buffer_snapshot.remote_id();
- let should_update_hints = editor
- .update(&mut cx, |editor, _| {
- // TODO kb wrong: need to query hints per buffer, not per excerpt
- // need to store the previous state and calculate the diff between them, and calculate anchors here too.
- editor.inlay_hint_versions.insert(
- InlayHintLocation {
- buffer_id,
- excerpt_id,
- },
- excerpt_buffer_snapshot.version().clone(),
- )
- })
- .log_err()
- .unwrap_or(false);
- if should_update_hints {
- new_hints
- .entry(InlayHintLocation {
- buffer_id,
- excerpt_id,
+ Ok((buffer_id, sorted_buffer_hints)) => {
+ let Some(buffer_excerpts) = cx.read(|cx| {
+ let multi_buffer = multi_buffer.read(cx);
+ multi_buffer.buffer(buffer_id).map(|buffer| multi_buffer.excerpts_for_buffer(&buffer, cx))
+ }) else { continue };
+ for (excerpt_id, excerpt_range) in buffer_excerpts {
+ let excerpt_hints = sorted_buffer_hints
+ .iter()
+ .cloned()
+ .skip_while(|hint| {
+ hint.position.offset < excerpt_range.context.start.offset
+ })
+ .take_while(|hint| {
+ hint.position.offset <= excerpt_range.context.end.offset
})
- .or_default()
- .extend(excerpt_hints);
+ .collect::<Vec<_>>();
+
+ if !excerpt_hints.is_empty() {
+ hints_to_draw.extend(excerpt_hints.into_iter().map(|hint| {
+ let anchor = multi_buffer_snapshot
+ .anchor_in_excerpt(excerpt_id, hint.position);
+ (anchor, hint)
+ }));
+ }
}
}
Err(e) => error!("Failed to update hints for buffer: {e:#}"),
}
}
- if !new_hints.is_empty() {
- editor
- .update(&mut cx, |editor, cx| {
- editor.display_map.update(cx, |display_map, cx| {
- display_map.splice_inlays(&new_hints, cx);
- });
- })
- .log_err()
- .unwrap_or(())
+ // TODO kb calculate diffs using the storage instead
+ if !hints_to_draw.is_empty() {
+ editor.update(&mut cx, |editor, cx| {
+ editor.display_map.update(cx, |display_map, cx| {
+ display_map.splice_inlays(hints_to_draw, cx);
+ });
+ })?;
}
+
+ anyhow::Ok(())
})
- .detach();
+ .detach_and_log_err(cx);
}
fn trigger_on_type_formatting(
@@ -7292,7 +7270,7 @@ impl Editor {
};
if update_inlay_hints {
- self.try_update_inlay_hints(cx);
+ self.reload_inlay_hints(cx);
}
}