Display excerpt-ranged hints only
This commit is contained in:
parent
addb62c1fc
commit
271cd25a1d
3 changed files with 126 additions and 110 deletions
|
@ -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 =
|
position: hint_anchor.bias_left(&buffer_snapshot),
|
||||||
buffer_snapshot.anchor_in_excerpt(location.excerpt_id, hint.position);
|
text: hint.text(),
|
||||||
new_inlays.push(InlayProperties {
|
})
|
||||||
position: hint_anchor.bias_left(&buffer_snapshot),
|
.collect();
|
||||||
text: hint.text(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(),
|
||||||
|
|
|
@ -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()
|
|
||||||
.unwrap_or(false);
|
|
||||||
if should_update_hints {
|
|
||||||
new_hints
|
|
||||||
.entry(InlayHintLocation {
|
|
||||||
buffer_id,
|
|
||||||
excerpt_id,
|
|
||||||
})
|
})
|
||||||
.or_default()
|
.take_while(|hint| {
|
||||||
.extend(excerpt_hints);
|
hint.position.offset <= excerpt_range.context.end.offset
|
||||||
|
})
|
||||||
|
.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:#}"),
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
43
crates/editor/src/inlay_hint_storage.rs
Normal file
43
crates/editor/src/inlay_hint_storage.rs
Normal 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
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
Loading…
Add table
Add a link
Reference in a new issue