Simplify inlay hint version handling
This commit is contained in:
parent
d506522eef
commit
7397b8028c
5 changed files with 111 additions and 136 deletions
|
@ -1181,8 +1181,7 @@ mod tests {
|
||||||
fold_map.read(buffer_snapshot, subscription.consume().into_inner());
|
fold_map.read(buffer_snapshot, subscription.consume().into_inner());
|
||||||
let (suggestion_snapshot, suggestion_edits) =
|
let (suggestion_snapshot, suggestion_edits) =
|
||||||
suggestion_map.sync(fold_snapshot, fold_edits);
|
suggestion_map.sync(fold_snapshot, fold_edits);
|
||||||
let (inlay_snapshot, inlay_edits) =
|
let (inlay_snapshot, inlay_edits) = inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
||||||
inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
|
||||||
let (tab_snapshot, tab_edits) =
|
let (tab_snapshot, tab_edits) =
|
||||||
tab_map.sync(inlay_snapshot, inlay_edits, 4.try_into().unwrap());
|
tab_map.sync(inlay_snapshot, inlay_edits, 4.try_into().unwrap());
|
||||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
|
@ -1396,8 +1395,7 @@ mod tests {
|
||||||
suggestion_map.sync(fold_snapshot, fold_edits);
|
suggestion_map.sync(fold_snapshot, fold_edits);
|
||||||
let (inlay_snapshot, inlay_edits) =
|
let (inlay_snapshot, inlay_edits) =
|
||||||
inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
||||||
let (tab_snapshot, tab_edits) =
|
let (tab_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
|
||||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||||
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,9 +44,7 @@ impl TabMap {
|
||||||
version: old_snapshot.version,
|
version: old_snapshot.version,
|
||||||
};
|
};
|
||||||
|
|
||||||
if old_snapshot.inlay_snapshot.version
|
if old_snapshot.inlay_snapshot.version != new_snapshot.inlay_snapshot.version {
|
||||||
!= new_snapshot.inlay_snapshot.version
|
|
||||||
{
|
|
||||||
new_snapshot.version += 1;
|
new_snapshot.version += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +58,10 @@ impl TabMap {
|
||||||
let old_end = old_snapshot
|
let old_end = old_snapshot
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
.to_point(suggestion_edit.old.end);
|
.to_point(suggestion_edit.old.end);
|
||||||
let old_end_row_successor_offset =
|
let old_end_row_successor_offset = old_snapshot.inlay_snapshot.to_offset(cmp::min(
|
||||||
old_snapshot.inlay_snapshot.to_offset(cmp::min(
|
InlayPoint::new(old_end.row() + 1, 0),
|
||||||
InlayPoint::new(old_end.row() + 1, 0),
|
old_snapshot.inlay_snapshot.max_point(),
|
||||||
old_snapshot.inlay_snapshot.max_point(),
|
));
|
||||||
));
|
|
||||||
let new_end = new_snapshot
|
let new_end = new_snapshot
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
.to_point(suggestion_edit.new.end);
|
.to_point(suggestion_edit.new.end);
|
||||||
|
@ -171,12 +168,9 @@ impl TabSnapshot {
|
||||||
pub fn line_len(&self, row: u32) -> u32 {
|
pub fn line_len(&self, row: u32) -> u32 {
|
||||||
let max_point = self.max_point();
|
let max_point = self.max_point();
|
||||||
if row < max_point.row() {
|
if row < max_point.row() {
|
||||||
self.to_tab_point(InlayPoint::new(
|
self.to_tab_point(InlayPoint::new(row, self.inlay_snapshot.line_len(row)))
|
||||||
row,
|
.0
|
||||||
self.inlay_snapshot.line_len(row),
|
.column
|
||||||
))
|
|
||||||
.0
|
|
||||||
.column
|
|
||||||
} else {
|
} else {
|
||||||
max_point.column()
|
max_point.column()
|
||||||
}
|
}
|
||||||
|
@ -331,27 +325,18 @@ impl TabSnapshot {
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
.suggestion_snapshot
|
.suggestion_snapshot
|
||||||
.to_suggestion_point(fold_point);
|
.to_suggestion_point(fold_point);
|
||||||
let inlay_point = self
|
let inlay_point = self.inlay_snapshot.to_inlay_point(suggestion_point);
|
||||||
.inlay_snapshot
|
|
||||||
.to_inlay_point(suggestion_point);
|
|
||||||
self.to_tab_point(inlay_point)
|
self.to_tab_point(inlay_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point {
|
pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point {
|
||||||
let inlay_point = self.to_inlay_point(point, bias).0;
|
let inlay_point = self.to_inlay_point(point, bias).0;
|
||||||
let suggestion_point = self
|
let suggestion_point = self.inlay_snapshot.to_suggestion_point(inlay_point, bias);
|
||||||
.inlay_snapshot
|
|
||||||
.to_suggestion_point(inlay_point, bias);
|
|
||||||
let fold_point = self
|
let fold_point = self
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
.suggestion_snapshot
|
.suggestion_snapshot
|
||||||
.to_fold_point(suggestion_point);
|
.to_fold_point(suggestion_point);
|
||||||
fold_point.to_buffer_point(
|
fold_point.to_buffer_point(&self.inlay_snapshot.suggestion_snapshot.fold_snapshot)
|
||||||
&self
|
|
||||||
.inlay_snapshot
|
|
||||||
.suggestion_snapshot
|
|
||||||
.fold_snapshot,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_tabs(&self, chars: impl Iterator<Item = char>, column: u32) -> u32 {
|
fn expand_tabs(&self, chars: impl Iterator<Item = char>, column: u32) -> u32 {
|
||||||
|
|
|
@ -762,10 +762,7 @@ impl WrapSnapshot {
|
||||||
let mut prev_fold_row = 0;
|
let mut prev_fold_row = 0;
|
||||||
for display_row in 0..=self.max_point().row() {
|
for display_row in 0..=self.max_point().row() {
|
||||||
let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
|
let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
|
||||||
let inlay_point = self
|
let inlay_point = self.tab_snapshot.to_inlay_point(tab_point, Bias::Left).0;
|
||||||
.tab_snapshot
|
|
||||||
.to_inlay_point(tab_point, Bias::Left)
|
|
||||||
.0;
|
|
||||||
let suggestion_point = self
|
let suggestion_point = self
|
||||||
.tab_snapshot
|
.tab_snapshot
|
||||||
.inlay_snapshot
|
.inlay_snapshot
|
||||||
|
@ -1198,8 +1195,7 @@ mod tests {
|
||||||
log::info!("SuggestionMap text: {:?}", suggestion_snapshot.text());
|
log::info!("SuggestionMap text: {:?}", suggestion_snapshot.text());
|
||||||
let (inlay_snapshot, inlay_edits) =
|
let (inlay_snapshot, inlay_edits) =
|
||||||
inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
inlay_map.sync(suggestion_snapshot, suggestion_edits);
|
||||||
let (tabs_snapshot, tab_edits) =
|
let (tabs_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
|
||||||
log::info!("TabMap text: {:?}", tabs_snapshot.text());
|
log::info!("TabMap text: {:?}", tabs_snapshot.text());
|
||||||
|
|
||||||
let unwrapped_text = tabs_snapshot.text();
|
let unwrapped_text = tabs_snapshot.text();
|
||||||
|
|
|
@ -26,7 +26,7 @@ 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::{Global, ReplicaId};
|
||||||
use collections::{hash_map, 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;
|
||||||
use display_map::*;
|
use display_map::*;
|
||||||
|
@ -71,7 +71,6 @@ pub use multi_buffer::{
|
||||||
};
|
};
|
||||||
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
|
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use parking_lot::RwLock;
|
|
||||||
use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
|
use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
|
||||||
use scroll::{
|
use scroll::{
|
||||||
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
||||||
|
@ -537,7 +536,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_hints_version: InlayHintVersion,
|
inlay_hint_versions: InlayHintVersions,
|
||||||
_subscriptions: Vec<Subscription>,
|
_subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,54 +1153,29 @@ impl CopilotState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO kb
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
struct InlayHintVersion(Arc<RwLock<HashMap<usize, Global>>>);
|
struct InlayHintVersions {
|
||||||
|
last_buffer_versions_with_hints: HashMap<usize, Global>,
|
||||||
|
}
|
||||||
|
|
||||||
impl InlayHintVersion {
|
impl InlayHintVersions {
|
||||||
fn is_newer(&self, timestamp: &HashMap<usize, Global>) -> bool {
|
fn absent_or_newer(&self, buffer_id: usize, new_version: &Global) -> bool {
|
||||||
let current_timestamp = self.0.read();
|
self.last_buffer_versions_with_hints
|
||||||
Self::first_timestamp_newer(timestamp, ¤t_timestamp)
|
.get(&buffer_id)
|
||||||
|
.map(|last_version_with_hints| new_version.changed_since(&last_version_with_hints))
|
||||||
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_if_newer(&self, new_timestamp: HashMap<usize, Global>) -> bool {
|
fn insert(&mut self, buffer_id: usize, new_version: Global) -> bool {
|
||||||
let mut guard = self.0.write();
|
if self.absent_or_newer(buffer_id, &new_version) {
|
||||||
if Self::first_timestamp_newer(&new_timestamp, &guard) {
|
self.last_buffer_versions_with_hints
|
||||||
*guard = new_timestamp;
|
.insert(buffer_id, new_version);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_timestamp_newer(
|
|
||||||
first: &HashMap<usize, Global>,
|
|
||||||
second: &HashMap<usize, Global>,
|
|
||||||
) -> bool {
|
|
||||||
if first.is_empty() {
|
|
||||||
false
|
|
||||||
} else if second.is_empty() {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
let mut first_newer = false;
|
|
||||||
let mut second_has_extra_buffers = false;
|
|
||||||
for (buffer_id, first_version) in first {
|
|
||||||
match second.get(buffer_id) {
|
|
||||||
None => {
|
|
||||||
second_has_extra_buffers = true;
|
|
||||||
}
|
|
||||||
Some(second_version) => {
|
|
||||||
if second_version.changed_since(&first_version) {
|
|
||||||
return false;
|
|
||||||
} else if first_version.changed_since(&second_version) {
|
|
||||||
first_newer = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
first_newer || !second_has_extra_buffers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1402,7 +1376,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_hints_version: InlayHintVersion::default(),
|
inlay_hint_versions: InlayHintVersions::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),
|
||||||
|
@ -2643,69 +2617,91 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut hint_fetch_tasks = Vec::new();
|
let hint_fetch_tasks = self
|
||||||
let new_timestamp = self.buffer().read(cx).all_buffers().into_iter().fold(
|
.buffer()
|
||||||
HashMap::default(),
|
.read(cx)
|
||||||
|mut buffer_versions, new_buffer| {
|
.all_buffers()
|
||||||
let new_buffer_version = new_buffer.read(cx).version();
|
.into_iter()
|
||||||
match buffer_versions.entry(new_buffer.id()) {
|
.map(|buffer_handle| {
|
||||||
hash_map::Entry::Occupied(mut entry) => {
|
let buffer_id = buffer_handle.id();
|
||||||
let entry_version = entry.get();
|
cx.spawn(|editor, mut cx| async move {
|
||||||
if new_buffer_version.changed_since(&entry_version) {
|
let task_data = editor
|
||||||
entry.insert(new_buffer_version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hash_map::Entry::Vacant(v) => {
|
|
||||||
v.insert(new_buffer_version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hint_fetch_tasks.push(cx.spawn(|editor, mut cx| async move {
|
|
||||||
let task = editor
|
|
||||||
.update(&mut cx, |editor, cx| {
|
.update(&mut cx, |editor, cx| {
|
||||||
editor.project.as_ref().map(|project| {
|
editor.project.as_ref().and_then(|project| {
|
||||||
project.update(cx, |project, cx| {
|
project.update(cx, |project, cx| {
|
||||||
let end = new_buffer.read(cx).len();
|
let buffer = buffer_handle.read(cx);
|
||||||
project.inlay_hints(new_buffer, 0..end, cx)
|
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(
|
||||||
|
buffer_handle,
|
||||||
|
0..end,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.context("inlay hints fecth task spawn")?;
|
.context("inlay hints fecth task spawn")?;
|
||||||
|
|
||||||
match task {
|
anyhow::Ok((
|
||||||
Some(task) => Ok(task.await.context("inlay hints fetch task await")?),
|
buffer_id,
|
||||||
None => anyhow::Ok(Vec::new()),
|
match task_data {
|
||||||
}
|
Some((buffer_version, task)) => Some((
|
||||||
}));
|
buffer_version,
|
||||||
|
task.await.context("inlay hints for buffer task")?,
|
||||||
buffer_versions
|
)),
|
||||||
},
|
None => None,
|
||||||
);
|
},
|
||||||
|
))
|
||||||
let current_hints_version = self.inlay_hints_version.clone();
|
})
|
||||||
if current_hints_version.is_newer(&new_timestamp) {
|
|
||||||
cx.spawn(|editor, mut cx| async move {
|
|
||||||
let mut new_hints = Vec::new();
|
|
||||||
for task_result in futures::future::join_all(hint_fetch_tasks).await {
|
|
||||||
match task_result {
|
|
||||||
Ok(task_hints) => new_hints.extend(task_hints),
|
|
||||||
Err(e) => error!("Failed to update hints for buffer: {e:#}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_hints_version.update_if_newer(new_timestamp) {
|
|
||||||
editor
|
|
||||||
.update(&mut cx, |editor, cx| {
|
|
||||||
editor.display_map.update(cx, |display_map, cx| {
|
|
||||||
display_map.set_inlay_hints(&new_hints, cx)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.log_err()
|
|
||||||
.unwrap_or(())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.detach();
|
.collect::<Vec<_>>();
|
||||||
}
|
|
||||||
|
cx.spawn(|editor, mut cx| async move {
|
||||||
|
let mut new_hints = Vec::new();
|
||||||
|
for task_result in futures::future::join_all(hint_fetch_tasks).await {
|
||||||
|
match task_result {
|
||||||
|
Ok((_buffer_id, None)) => {}
|
||||||
|
Ok((buffer_id, Some((buffer_with_hints_version, buffer_hints)))) => {
|
||||||
|
let should_update_hints = editor
|
||||||
|
.update(&mut cx, |editor, _| {
|
||||||
|
editor
|
||||||
|
.inlay_hint_versions
|
||||||
|
.insert(buffer_id, buffer_with_hints_version)
|
||||||
|
})
|
||||||
|
.log_err()
|
||||||
|
.unwrap_or(false);
|
||||||
|
if should_update_hints {
|
||||||
|
new_hints.extend(buffer_hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => error!("Failed to update hints for buffer: {e:#}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO kb wrong, need a splice here instead
|
||||||
|
if !new_hints.is_empty() {
|
||||||
|
editor
|
||||||
|
.update(&mut cx, |editor, cx| {
|
||||||
|
editor.display_map.update(cx, |display_map, cx| {
|
||||||
|
display_map.set_inlay_hints(&new_hints, cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.log_err()
|
||||||
|
.unwrap_or(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trigger_on_type_formatting(
|
fn trigger_on_type_formatting(
|
||||||
|
|
|
@ -4904,7 +4904,7 @@ impl Project {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inlay_hints<T: ToOffset>(
|
pub fn inlay_hints_for_buffer<T: ToOffset>(
|
||||||
&self,
|
&self,
|
||||||
buffer_handle: ModelHandle<Buffer>,
|
buffer_handle: ModelHandle<Buffer>,
|
||||||
range: Range<T>,
|
range: Range<T>,
|
||||||
|
@ -6688,7 +6688,7 @@ impl Project {
|
||||||
let buffer_hints = this
|
let buffer_hints = this
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
let end = buffer.read(cx).len();
|
let end = buffer.read(cx).len();
|
||||||
project.inlay_hints(buffer, 0..end, cx)
|
project.inlay_hints_for_buffer(buffer, 0..end, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.context("inlay hints fetch")?;
|
.context("inlay hints fetch")?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue