Display excerpt-ranged hints only

This commit is contained in:
Kirill Bulatov 2023-06-12 17:16:48 +03:00
parent addb62c1fc
commit 271cd25a1d
3 changed files with 126 additions and 110 deletions

View file

@ -6,8 +6,8 @@ mod tab_map;
mod wrap_map; mod wrap_map;
use crate::{ use crate::{
display_map::inlay_map::InlayProperties, Anchor, AnchorRangeExt, InlayHintLocation, display_map::inlay_map::InlayProperties, Anchor, AnchorRangeExt, MultiBuffer,
MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, MultiBufferSnapshot, ToOffset, ToPoint,
}; };
pub use block_map::{BlockMap, BlockPoint}; pub use block_map::{BlockMap, BlockPoint};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
@ -287,7 +287,7 @@ impl DisplayMap {
pub fn splice_inlays( pub fn splice_inlays(
&mut self, &mut self,
new_hints: &HashMap<InlayHintLocation, Vec<project::InlayHint>>, new_hints: Vec<(Anchor, project::InlayHint)>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
@ -302,18 +302,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 mut new_inlays = Vec::new(); let new_inlays = new_hints
for (&location, hints) in new_hints { .into_iter()
for hint in hints { .map(|(hint_anchor, hint)| InlayProperties {
let hint_anchor =
buffer_snapshot.anchor_in_excerpt(location.excerpt_id, hint.position);
new_inlays.push(InlayProperties {
position: hint_anchor.bias_left(&buffer_snapshot), position: hint_anchor.bias_left(&buffer_snapshot),
text: hint.text(), text: hint.text(),
}); })
} .collect();
}
let (snapshot, edits, _) = self.inlay_map.splice( let (snapshot, edits, _) = self.inlay_map.splice(
// TODO kb this is wrong, calc diffs in the editor instead. // TODO kb this is wrong, calc diffs in the editor instead.
self.inlay_map.inlays.keys().copied().collect(), self.inlay_map.inlays.keys().copied().collect(),

View file

@ -2,6 +2,7 @@ mod blink_manager;
pub mod display_map; pub mod display_map;
mod editor_settings; mod editor_settings;
mod element; mod element;
mod inlay_hint_storage;
mod git; mod git;
mod highlight_matching_bracket; mod highlight_matching_bracket;
@ -25,7 +26,7 @@ use aho_corasick::AhoCorasick;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use blink_manager::BlinkManager; use blink_manager::BlinkManager;
use client::{ClickhouseEvent, TelemetrySettings}; use client::{ClickhouseEvent, TelemetrySettings};
use clock::{Global, ReplicaId}; use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
use copilot::Copilot; use copilot::Copilot;
pub use display_map::DisplayPoint; pub use display_map::DisplayPoint;
@ -52,6 +53,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_storage::InlayHintStorage;
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};
@ -71,7 +73,9 @@ pub use multi_buffer::{
}; };
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16}; use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction}; use project::{
FormatTrigger, InlayHint, Location, LocationLink, Project, ProjectPath, ProjectTransaction,
};
use scroll::{ use scroll::{
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide, autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
}; };
@ -536,7 +540,7 @@ pub struct Editor {
gutter_hovered: bool, gutter_hovered: bool,
link_go_to_definition_state: LinkGoToDefinitionState, link_go_to_definition_state: LinkGoToDefinitionState,
copilot_state: CopilotState, copilot_state: CopilotState,
inlay_hint_versions: InlayHintVersions, inlay_hint_storage: InlayHintStorage,
_subscriptions: Vec<Subscription>, _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)] #[derive(Debug)]
struct ActiveDiagnosticGroup { struct ActiveDiagnosticGroup {
primary_range: Range<Anchor>, primary_range: Range<Anchor>,
@ -1324,7 +1297,7 @@ impl Editor {
project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| { project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
match event { match event {
project::Event::ReloadInlayHints => { project::Event::ReloadInlayHints => {
editor.try_update_inlay_hints(cx); editor.reload_inlay_hints(cx);
} }
_ => {} _ => {}
}; };
@ -1382,7 +1355,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_versions: InlayHintVersions::default(), inlay_hint_storage: InlayHintStorage::default(),
gutter_hovered: false, gutter_hovered: false,
_subscriptions: vec![ _subscriptions: vec![
cx.observe(&buffer, Self::on_buffer_changed), 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 { if self.mode != EditorMode::Full {
return; return;
} }
let multi_buffer = self.buffer().read(cx); let multi_buffer = self.buffer();
let buffer_snapshot = multi_buffer.snapshot(cx); let hint_fetch_tasks = multi_buffer
let hint_fetch_tasks = buffer_snapshot .read(cx)
.excerpts() .all_buffers()
.map(|(excerpt_id, excerpt_buffer_snapshot, _)| { .into_iter()
(excerpt_id, excerpt_buffer_snapshot.clone()) .map(|buffer_handle| {
}) let buffer = buffer_handle.read(cx);
.map(|(excerpt_id, excerpt_buffer_snapshot)| { // 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 { cx.spawn(|editor, mut cx| async move {
let task = 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().map(|project| {
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
Some( project.inlay_hints_for_buffer(buffer_handle, 0..buffer_len, cx)
project.inlay_hints_for_buffer(
editor
.buffer()
.read(cx)
.buffer(excerpt_buffer_snapshot.remote_id())?,
0..excerpt_buffer_snapshot.len(),
cx,
),
)
}) })
}) })
}) })
.context("inlay hints fecth task spawn")?; .context("inlay hints fecth task spawn")?;
anyhow::Ok(( anyhow::Ok((
excerpt_id, buffer_id,
excerpt_buffer_snapshot,
match task { 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(), None => Vec::new(),
}, },
)) ))
@ -2664,52 +2637,57 @@ impl Editor {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
let mut new_hints: HashMap<InlayHintLocation, Vec<project::InlayHint>> = let mut hints_to_draw: Vec<(Anchor, InlayHint)> = Vec::new();
HashMap::default(); 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 { for task_result in futures::future::join_all(hint_fetch_tasks).await {
match task_result { match task_result {
Ok((excerpt_id, excerpt_buffer_snapshot, excerpt_hints)) => { Ok((buffer_id, sorted_buffer_hints)) => {
let buffer_id = excerpt_buffer_snapshot.remote_id(); let Some(buffer_excerpts) = cx.read(|cx| {
let should_update_hints = editor let multi_buffer = multi_buffer.read(cx);
.update(&mut cx, |editor, _| { multi_buffer.buffer(buffer_id).map(|buffer| multi_buffer.excerpts_for_buffer(&buffer, cx))
// TODO kb wrong: need to query hints per buffer, not per excerpt }) else { continue };
// need to store the previous state and calculate the diff between them, and calculate anchors here too. for (excerpt_id, excerpt_range) in buffer_excerpts {
editor.inlay_hint_versions.insert( let excerpt_hints = sorted_buffer_hints
InlayHintLocation { .iter()
buffer_id, .cloned()
excerpt_id, .skip_while(|hint| {
}, hint.position.offset < excerpt_range.context.start.offset
excerpt_buffer_snapshot.version().clone(),
)
}) })
.log_err() .take_while(|hint| {
.unwrap_or(false); hint.position.offset <= excerpt_range.context.end.offset
if should_update_hints {
new_hints
.entry(InlayHintLocation {
buffer_id,
excerpt_id,
}) })
.or_default() .collect::<Vec<_>>();
.extend(excerpt_hints);
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:#}"), Err(e) => error!("Failed to update hints for buffer: {e:#}"),
} }
} }
if !new_hints.is_empty() { // TODO kb calculate diffs using the storage instead
editor if !hints_to_draw.is_empty() {
.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
editor.display_map.update(cx, |display_map, cx| { editor.display_map.update(cx, |display_map, cx| {
display_map.splice_inlays(&new_hints, cx); display_map.splice_inlays(hints_to_draw, cx);
}); });
}) })?;
.log_err()
.unwrap_or(())
} }
anyhow::Ok(())
}) })
.detach(); .detach_and_log_err(cx);
} }
fn trigger_on_type_formatting( fn trigger_on_type_formatting(
@ -7292,7 +7270,7 @@ impl Editor {
}; };
if update_inlay_hints { if update_inlay_hints {
self.try_update_inlay_hints(cx); self.reload_inlay_hints(cx);
} }
} }

View file

@ -0,0 +1,43 @@
use crate::Anchor;
use project::InlayHint;
use collections::BTreeMap;
#[derive(Debug, Default)]
pub struct InlayHintStorage {
hints: BTreeMap<Anchor, InlayHint>,
}
impl InlayHintStorage {
// TODO kb calculate the diff instead
fn insert(&mut self) -> bool {
todo!("TODO kb")
}
}
// let buffer_version =
// cx.read(|cx| buffer.read(cx).version().clone());
// #[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
// }
// }
// }