Compare commits

...
Sign in to create a new pull request.

14 commits

Author SHA1 Message Date
Piotr Osiewicz
575e193ea3 WIP
Co-authored-by: Kirill <kirill@zed.dev>
2023-11-02 10:59:10 +01:00
Piotr Osiewicz
a9e3d8c9a4 Make editor's ContextMenu no longer depend on project in it's api 2023-11-01 00:44:29 +01:00
Piotr Osiewicz
b11d1e2db8 Fix up tests.
Fix circular reference in CodeActions.
2023-11-01 00:26:12 +01:00
Piotr Osiewicz
e6448d7f71 Merge branch 'main' into editor_teardown 2023-10-31 21:55:01 +01:00
Piotr Osiewicz
8996ef9d20 Add FormatProvider 2023-10-31 21:26:51 +01:00
Piotr Osiewicz
c0f6075302 touchup, rename a variable 2023-10-31 15:58:35 +01:00
Piotr Osiewicz
f93b23cfc4 fixup! Add RenameProvider 2023-10-31 11:27:21 +01:00
Piotr Osiewicz
9e60c836e0 Add RenameProvider 2023-10-31 11:25:58 +01:00
Piotr Osiewicz
1a5897e264 Another batch of warning fixes 2023-10-30 21:49:38 +01:00
Piotr Osiewicz
1724d5dde2 Fix warnings 2023-10-30 21:47:07 +01:00
Piotr Osiewicz
ebe8e7d4a0 Add GoToDefinition2 2023-10-30 21:46:57 +01:00
Piotr Osiewicz
722a508c2e Add CodeActionsProvider 2023-10-26 15:37:05 +02:00
Piotr Osiewicz
840309a6b7 editor: extract code completions provider 2023-10-26 14:07:32 +02:00
Piotr Osiewicz
c961a1cd2b Mark a bunch of fns in editor as non-pub 2023-10-26 00:29:31 +02:00
7 changed files with 1555 additions and 1189 deletions

View file

@ -5796,7 +5796,7 @@ async fn test_collaborating_with_renames(
prepare_rename.await.unwrap(); prepare_rename.await.unwrap();
editor_b.update(cx_b, |editor, cx| { editor_b.update(cx_b, |editor, cx| {
use editor::ToOffset; use editor::ToOffset;
let rename = editor.pending_rename().unwrap(); let rename = editor.pending_rename(cx).unwrap();
let buffer = editor.buffer().read(cx).snapshot(cx); let buffer = editor.buffer().read(cx).snapshot(cx);
assert_eq!( assert_eq!(
rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer), rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,9 @@ use super::*;
use crate::{ use crate::{
scroll::scroll_amount::ScrollAmount, scroll::scroll_amount::ScrollAmount,
test::{ test::{
assert_text_with_selections, build_editor, editor_lsp_test_context::EditorLspTestContext, assert_text_with_selections, build_editor, build_editor_with_project,
editor_test_context::EditorTestContext, select_ranges, editor_lsp_test_context::EditorLspTestContext, editor_test_context::EditorTestContext,
select_ranges,
}, },
JoinLines, JoinLines,
}; };
@ -4895,7 +4896,9 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
let fake_server = fake_servers.next().await.unwrap(); let fake_server = fake_servers.next().await.unwrap();
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); let editor = cx
.add_window(|cx| build_editor_with_project(project.clone(), buffer, cx))
.root(cx);
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
assert!(cx.read(|cx| editor.is_dirty(cx))); assert!(cx.read(|cx| editor.is_dirty(cx)));
@ -5007,7 +5010,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
let fake_server = fake_servers.next().await.unwrap(); let fake_server = fake_servers.next().await.unwrap();
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); let editor = cx
.add_window(|cx| build_editor_with_project(project.clone(), buffer, cx))
.root(cx);
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
assert!(cx.read(|cx| editor.is_dirty(cx))); assert!(cx.read(|cx| editor.is_dirty(cx)));
@ -5128,11 +5133,13 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
let fake_server = fake_servers.next().await.unwrap(); let fake_server = fake_servers.next().await.unwrap();
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); let editor = cx
.add_window(|cx| build_editor_with_project(project, buffer, cx))
.root(cx);
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
let format = editor.update(cx, |editor, cx| { let format = editor.update(cx, |editor, cx| {
editor.perform_format(project.clone(), FormatTrigger::Manual, cx) editor.perform_format(FormatTrigger::Manual, cx)
}); });
fake_server fake_server
.handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move { .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
@ -5149,7 +5156,7 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
.next() .next()
.await; .await;
cx.foreground().start_waiting(); cx.foreground().start_waiting();
format.await.unwrap(); format.unwrap().await.unwrap();
assert_eq!( assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)), editor.read_with(cx, |editor, cx| editor.text(cx)),
"one, two\nthree\n" "one, two\nthree\n"
@ -5166,11 +5173,11 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
unreachable!() unreachable!()
}); });
let format = editor.update(cx, |editor, cx| { let format = editor.update(cx, |editor, cx| {
editor.perform_format(project, FormatTrigger::Manual, cx) editor.perform_format(FormatTrigger::Manual, cx)
}); });
cx.foreground().advance_clock(super::FORMAT_TIMEOUT); cx.foreground().advance_clock(super::FORMAT_TIMEOUT);
cx.foreground().start_waiting(); cx.foreground().start_waiting();
format.await.unwrap(); format.unwrap().await.unwrap();
assert_eq!( assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)), editor.read_with(cx, |editor, cx| editor.text(cx)),
"one\ntwo\nthree\n" "one\ntwo\nthree\n"
@ -8010,13 +8017,15 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
let buffer_text = "one\ntwo\nthree\n"; let buffer_text = "one\ntwo\nthree\n";
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx); let editor = cx
.add_window(|cx| build_editor_with_project(project.clone(), buffer, cx))
.root(cx);
editor.update(cx, |editor, cx| editor.set_text(buffer_text, cx)); editor.update(cx, |editor, cx| editor.set_text(buffer_text, cx));
let format = editor.update(cx, |editor, cx| { let format = editor.update(cx, |editor, cx| {
editor.perform_format(project.clone(), FormatTrigger::Manual, cx) editor.perform_format(FormatTrigger::Manual, cx)
}); });
format.await.unwrap(); format.unwrap().await.unwrap();
assert_eq!( assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)), editor.read_with(cx, |editor, cx| editor.text(cx)),
buffer_text.to_string() + prettier_format_suffix, buffer_text.to_string() + prettier_format_suffix,
@ -8027,9 +8036,9 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
settings.defaults.formatter = Some(language_settings::Formatter::Auto) settings.defaults.formatter = Some(language_settings::Formatter::Auto)
}); });
let format = editor.update(cx, |editor, cx| { let format = editor.update(cx, |editor, cx| {
editor.perform_format(project.clone(), FormatTrigger::Manual, cx) editor.perform_format(FormatTrigger::Manual, cx)
}); });
format.await.unwrap(); format.unwrap().await.unwrap();
assert_eq!( assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)), editor.read_with(cx, |editor, cx| editor.text(cx)),
buffer_text.to_string() + prettier_format_suffix + "\n" + prettier_format_suffix, buffer_text.to_string() + prettier_format_suffix + "\n" + prettier_format_suffix,

View file

@ -80,7 +80,7 @@ pub fn find_hovered_hint_part(
pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut ViewContext<Editor>) { pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut ViewContext<Editor>) {
if settings::get::<EditorSettings>(cx).hover_popover_enabled { if settings::get::<EditorSettings>(cx).hover_popover_enabled {
if editor.pending_rename.is_some() { if editor.has_pending_rename(cx) {
return; return;
} }
@ -166,7 +166,7 @@ fn show_hover(
ignore_timeout: bool, ignore_timeout: bool,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
if editor.pending_rename.is_some() { if editor.has_pending_rename(cx) {
return; return;
} }

View file

@ -11,10 +11,10 @@ use crate::{
use anyhow::Context; use anyhow::Context;
use clock::Global; use clock::Global;
use futures::future; use futures::future;
use gpui::{ModelContext, ModelHandle, Task, ViewContext}; use gpui::{Entity, ModelContext, ModelHandle, Task, ViewContext};
use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot}; use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
use parking_lot::RwLock; use parking_lot::RwLock;
use project::{InlayHint, ResolveState}; use project::{InlayHint, Project, ResolveState};
use collections::{hash_map, HashMap, HashSet}; use collections::{hash_map, HashMap, HashSet};
use language::language_settings::InlayHintSettings; use language::language_settings::InlayHintSettings;
@ -24,9 +24,11 @@ use text::{ToOffset, ToPoint};
use util::post_inc; use util::post_inc;
pub struct InlayHintCache { pub struct InlayHintCache {
hints: HashMap<ExcerptId, Arc<RwLock<CachedExcerptHints>>>, // TODO kb consider weak handles
project: ModelHandle<Project>,
pub(super) hints: HashMap<ExcerptId, Arc<RwLock<CachedExcerptHints>>>,
allowed_hint_kinds: HashSet<Option<InlayHintKind>>, allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
version: usize, pub(super) version: usize,
pub(super) enabled: bool, pub(super) enabled: bool,
update_tasks: HashMap<ExcerptId, TasksForRanges>, update_tasks: HashMap<ExcerptId, TasksForRanges>,
lsp_request_limiter: Arc<Semaphore>, lsp_request_limiter: Arc<Semaphore>,
@ -236,9 +238,13 @@ impl TasksForRanges {
} }
} }
impl Entity for InlayHintCache {
type Event = ();
}
impl InlayHintCache { impl InlayHintCache {
pub fn new(inlay_hint_settings: InlayHintSettings) -> Self { pub fn new(project: ModelHandle<Project>, inlay_hint_settings: InlayHintSettings) -> Self {
Self { Self {
project,
allowed_hint_kinds: inlay_hint_settings.enabled_inlay_hint_kinds(), allowed_hint_kinds: inlay_hint_settings.enabled_inlay_hint_kinds(),
enabled: inlay_hint_settings.enabled, enabled: inlay_hint_settings.enabled,
hints: HashMap::default(), hints: HashMap::default(),
@ -304,6 +310,7 @@ impl InlayHintCache {
reason: &'static str, reason: &'static str,
excerpts_to_query: HashMap<ExcerptId, (ModelHandle<Buffer>, Global, Range<usize>)>, excerpts_to_query: HashMap<ExcerptId, (ModelHandle<Buffer>, Global, Range<usize>)>,
invalidate: InvalidationStrategy, invalidate: InvalidationStrategy,
cache: ModelHandle<Self>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> Option<InlaySplice> { ) -> Option<InlaySplice> {
if !self.enabled { if !self.enabled {
@ -336,6 +343,7 @@ impl InlayHintCache {
excerpts_to_query, excerpts_to_query,
invalidate, invalidate,
cache_version, cache_version,
cache,
cx, cx,
) )
}) })
@ -538,7 +546,7 @@ impl InlayHintCache {
.read(cx) .read(cx)
.buffer(buffer_id) .buffer(buffer_id)
.and_then(|buffer| { .and_then(|buffer| {
let project = editor.project.as_ref()?; let project = self.project;
Some(project.update(cx, |project, cx| { Some(project.update(cx, |project, cx| {
project.resolve_inlay_hint( project.resolve_inlay_hint(
hint_to_resolve, hint_to_resolve,
@ -582,6 +590,7 @@ fn spawn_new_update_tasks(
excerpts_to_query: HashMap<ExcerptId, (ModelHandle<Buffer>, Global, Range<usize>)>, excerpts_to_query: HashMap<ExcerptId, (ModelHandle<Buffer>, Global, Range<usize>)>,
invalidate: InvalidationStrategy, invalidate: InvalidationStrategy,
update_cache_version: usize, update_cache_version: usize,
cache: ModelHandle<InlayHintCache>,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) { ) {
let visible_hints = Arc::new(editor.visible_inlay_hints(cx)); let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
@ -601,7 +610,8 @@ fn spawn_new_update_tasks(
continue; continue;
} }
let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned(); let cached_excerpt_hints =
cache.update(cx, |cache, _| cache.hints.get(&excerpt_id).cloned());
if let Some(cached_excerpt_hints) = &cached_excerpt_hints { if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
let cached_excerpt_hints = cached_excerpt_hints.read(); let cached_excerpt_hints = cached_excerpt_hints.read();
let cached_buffer_version = &cached_excerpt_hints.buffer_version; let cached_buffer_version = &cached_excerpt_hints.buffer_version;
@ -636,35 +646,39 @@ fn spawn_new_update_tasks(
reason, reason,
}; };
let new_update_task = |query_ranges| { let cache_handle = cache.clone();
new_update_task( cache.update(cx, |cache, _| {
query, let new_update_task = |query_ranges| {
query_ranges, new_update_task(
multi_buffer_snapshot, query,
buffer_snapshot.clone(),
Arc::clone(&visible_hints),
cached_excerpt_hints,
Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
cx,
)
};
match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
hash_map::Entry::Occupied(mut o) => {
o.get_mut().update_cached_tasks(
&buffer_snapshot,
query_ranges, query_ranges,
invalidate, multi_buffer_snapshot,
new_update_task, buffer_snapshot.clone(),
); Arc::clone(&visible_hints),
cached_excerpt_hints,
Arc::clone(&cache.lsp_request_limiter),
cache_handle,
cx,
)
};
match cache.update_tasks.entry(excerpt_id) {
hash_map::Entry::Occupied(mut o) => {
o.get_mut().update_cached_tasks(
&buffer_snapshot,
query_ranges,
invalidate,
new_update_task,
);
}
hash_map::Entry::Vacant(v) => {
v.insert(TasksForRanges::new(
query_ranges.clone(),
new_update_task(query_ranges),
));
}
} }
hash_map::Entry::Vacant(v) => { })
v.insert(TasksForRanges::new(
query_ranges.clone(),
new_update_task(query_ranges),
));
}
}
} }
} }
@ -760,6 +774,7 @@ fn new_update_task(
visible_hints: Arc<Vec<Inlay>>, visible_hints: Arc<Vec<Inlay>>,
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>, cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
lsp_request_limiter: Arc<Semaphore>, lsp_request_limiter: Arc<Semaphore>,
cache: ModelHandle<InlayHintCache>,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) -> Task<()> { ) -> Task<()> {
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
@ -775,6 +790,7 @@ fn new_update_task(
invalidate, invalidate,
range, range,
Arc::clone(&lsp_request_limiter), Arc::clone(&lsp_request_limiter),
cache,
closure_cx.clone(), closure_cx.clone(),
) )
}; };
@ -795,13 +811,9 @@ fn new_update_task(
let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| { let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
log::error!("inlay hint update task for range {range:?} failed: {e:#}"); log::error!("inlay hint update task for range {range:?} failed: {e:#}");
editor cache
.update(&mut cx, |editor, _| { .update(&mut cx, |cache, _| {
if let Some(task_ranges) = editor if let Some(task_ranges) = cache.update_tasks.get_mut(&query.excerpt_id) {
.inlay_hint_cache
.update_tasks
.get_mut(&query.excerpt_id)
{
task_ranges.invalidate_range(&buffer_snapshot, &range); task_ranges.invalidate_range(&buffer_snapshot, &range);
} }
}) })
@ -846,6 +858,7 @@ async fn fetch_and_update_hints(
invalidate: bool, invalidate: bool,
fetch_range: Range<language::Anchor>, fetch_range: Range<language::Anchor>,
lsp_request_limiter: Arc<Semaphore>, lsp_request_limiter: Arc<Semaphore>,
cache: ModelHandle<InlayHintCache>,
mut cx: gpui::AsyncAppContext, mut cx: gpui::AsyncAppContext,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() { let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
@ -880,13 +893,14 @@ async fn fetch_and_update_hints(
}; };
if query_not_around_visible_range { if query_not_around_visible_range {
log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping."); log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
if let Some(task_ranges) = editor cache.update(cx, |cache, _| {
.inlay_hint_cache if let Some(task_ranges) = cache
.update_tasks .update_tasks
.get_mut(&query.excerpt_id) .get_mut(&query.excerpt_id)
{ {
task_ranges.invalidate_range(&buffer_snapshot, &fetch_range); task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
} }
});
return None; return None;
} }
} }
@ -895,7 +909,7 @@ async fn fetch_and_update_hints(
.read(cx) .read(cx)
.buffer(query.buffer_id) .buffer(query.buffer_id)
.and_then(|buffer| { .and_then(|buffer| {
let project = editor.project.as_ref()?; let project = cache.read(cx).project;
Some(project.update(cx, |project, cx| { Some(project.update(cx, |project, cx| {
project.inlay_hints(buffer, fetch_range.clone(), cx) project.inlay_hints(buffer, fetch_range.clone(), cx)
})) }))
@ -957,6 +971,7 @@ async fn fetch_and_update_hints(
invalidate, invalidate,
buffer_snapshot, buffer_snapshot,
multi_buffer_snapshot, multi_buffer_snapshot,
cache,
cx, cx,
); );
}) })
@ -1071,13 +1086,11 @@ fn apply_hint_update(
invalidate: bool, invalidate: bool,
buffer_snapshot: BufferSnapshot, buffer_snapshot: BufferSnapshot,
multi_buffer_snapshot: MultiBufferSnapshot, multi_buffer_snapshot: MultiBufferSnapshot,
cache: ModelHandle<InlayHintsCache>,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) { ) {
let cached_excerpt_hints = editor cache.update(cx, |cache, cx| {
.inlay_hint_cache let cached_excerpt_hints = cache.hints.entry(new_update.excerpt_id).or_insert_with(|| {
.hints
.entry(new_update.excerpt_id)
.or_insert_with(|| {
Arc::new(RwLock::new(CachedExcerptHints { Arc::new(RwLock::new(CachedExcerptHints {
version: query.cache_version, version: query.cache_version,
buffer_version: buffer_snapshot.version().clone(), buffer_version: buffer_snapshot.version().clone(),
@ -1086,112 +1099,111 @@ fn apply_hint_update(
hints_by_id: HashMap::default(), hints_by_id: HashMap::default(),
})) }))
}); });
let mut cached_excerpt_hints = cached_excerpt_hints.write(); let mut cached_excerpt_hints = cached_excerpt_hints.write();
match query.cache_version.cmp(&cached_excerpt_hints.version) { match query.cache_version.cmp(&cached_excerpt_hints.version) {
cmp::Ordering::Less => return, cmp::Ordering::Less => return,
cmp::Ordering::Greater | cmp::Ordering::Equal => { cmp::Ordering::Greater | cmp::Ordering::Equal => {
cached_excerpt_hints.version = query.cache_version; cached_excerpt_hints.version = query.cache_version;
}
} }
}
let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty(); let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
cached_excerpt_hints cached_excerpt_hints
.ordered_hints
.retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
cached_excerpt_hints
.hints_by_id
.retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
let mut splice = InlaySplice {
to_remove: new_update.remove_from_visible,
to_insert: Vec::new(),
};
for new_hint in new_update.add_to_cache {
let insert_position = match cached_excerpt_hints
.ordered_hints .ordered_hints
.binary_search_by(|probe| { .retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
cached_excerpt_hints.hints_by_id[probe] cached_excerpt_hints
.position .hints_by_id
.cmp(&new_hint.position, &buffer_snapshot) .retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
}) { let mut splice = InlaySplice {
Ok(i) => { to_remove: new_update.remove_from_visible,
let mut insert_position = Some(i); to_insert: Vec::new(),
for id in &cached_excerpt_hints.ordered_hints[i..] {
let cached_hint = &cached_excerpt_hints.hints_by_id[id];
if new_hint
.position
.cmp(&cached_hint.position, &buffer_snapshot)
.is_gt()
{
break;
}
if cached_hint.text() == new_hint.text() {
insert_position = None;
break;
}
}
insert_position
}
Err(i) => Some(i),
}; };
for new_hint in new_update.add_to_cache {
let insert_position =
match cached_excerpt_hints
.ordered_hints
.binary_search_by(|probe| {
cached_excerpt_hints.hints_by_id[probe]
.position
.cmp(&new_hint.position, &buffer_snapshot)
}) {
Ok(i) => {
let mut insert_position = Some(i);
for id in &cached_excerpt_hints.ordered_hints[i..] {
let cached_hint = &cached_excerpt_hints.hints_by_id[id];
if new_hint
.position
.cmp(&cached_hint.position, &buffer_snapshot)
.is_gt()
{
break;
}
if cached_hint.text() == new_hint.text() {
insert_position = None;
break;
}
}
insert_position
}
Err(i) => Some(i),
};
if let Some(insert_position) = insert_position { if let Some(insert_position) = insert_position {
let new_inlay_id = post_inc(&mut editor.next_inlay_id); let new_inlay_id = post_inc(&mut editor.next_inlay_id);
if editor if cache.allowed_hint_kinds.contains(&new_hint.kind) {
.inlay_hint_cache let new_hint_position = multi_buffer_snapshot
.allowed_hint_kinds .anchor_in_excerpt(query.excerpt_id, new_hint.position);
.contains(&new_hint.kind) splice
{ .to_insert
let new_hint_position = .push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position); }
splice let new_id = InlayId::Hint(new_inlay_id);
.to_insert cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
.push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint)); cached_excerpt_hints
} .ordered_hints
let new_id = InlayId::Hint(new_inlay_id); .insert(insert_position, new_id);
cached_excerpt_hints.hints_by_id.insert(new_id, new_hint); cached_inlays_changed = true;
cached_excerpt_hints
.ordered_hints
.insert(insert_position, new_id);
cached_inlays_changed = true;
}
}
cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
drop(cached_excerpt_hints);
if invalidate {
let mut outdated_excerpt_caches = HashSet::default();
for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
let excerpt_hints = excerpt_hints.read();
if excerpt_hints.buffer_id == query.buffer_id
&& excerpt_id != &query.excerpt_id
&& buffer_snapshot
.version()
.changed_since(&excerpt_hints.buffer_version)
{
outdated_excerpt_caches.insert(*excerpt_id);
splice
.to_remove
.extend(excerpt_hints.ordered_hints.iter().copied());
} }
} }
cached_inlays_changed |= !outdated_excerpt_caches.is_empty(); cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
editor drop(cached_excerpt_hints);
.inlay_hint_cache });
.hints
.retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
}
let InlaySplice { cache.update(cx, |cache, _| {
to_remove, if invalidate {
to_insert, let mut outdated_excerpt_caches = HashSet::default();
} = splice; for (excerpt_id, excerpt_hints) in &cache.hints {
let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty(); let excerpt_hints = excerpt_hints.read();
if cached_inlays_changed || displayed_inlays_changed { if excerpt_hints.buffer_id == query.buffer_id
editor.inlay_hint_cache.version += 1; && excerpt_id != &query.excerpt_id
} && buffer_snapshot
if displayed_inlays_changed { .version()
editor.splice_inlay_hints(to_remove, to_insert, cx) .changed_since(&excerpt_hints.buffer_version)
} {
outdated_excerpt_caches.insert(*excerpt_id);
splice
.to_remove
.extend(excerpt_hints.ordered_hints.iter().copied());
}
}
cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
cache
.hints
.retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
}
let InlaySplice {
to_remove,
to_insert,
} = splice;
let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
if cached_inlays_changed || displayed_inlays_changed {
cache.version += 1;
}
if displayed_inlays_changed {
editor.splice_inlay_hints(to_remove, to_insert, cx)
}
})
} }
#[cfg(test)] #[cfg(test)]
@ -1287,7 +1299,8 @@ pub mod tests {
"Cache should use editor settings to get the allowed hint kinds" "Cache should use editor settings to get the allowed hint kinds"
); );
assert_eq!( assert_eq!(
inlay_cache.version, edits_made, editor.inlay_hint_cache_version(),
edits_made,
"The editor update the cache version after every cache/view change" "The editor update the cache version after every cache/view change"
); );
}); });
@ -1312,7 +1325,8 @@ pub mod tests {
"Cache should use editor settings to get the allowed hint kinds" "Cache should use editor settings to get the allowed hint kinds"
); );
assert_eq!( assert_eq!(
inlay_cache.version, edits_made, editor.inlay_hint_cache_version(),
edits_made,
"The editor update the cache version after every cache/view change" "The editor update the cache version after every cache/view change"
); );
}); });
@ -1392,7 +1406,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
edits_made, edits_made,
"The editor update the cache version after every cache/view change" "The editor update the cache version after every cache/view change"
); );
@ -1423,7 +1437,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
edits_made, edits_made,
"Should not update the cache while the work task is running" "Should not update the cache while the work task is running"
); );
@ -1447,7 +1461,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
edits_made, edits_made,
"Cache version should udpate once after the work task is done" "Cache version should udpate once after the work task is done"
); );
@ -1566,7 +1580,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
1, 1,
"Rust editor update the cache version after every cache/view change" "Rust editor update the cache version after every cache/view change"
); );
@ -1623,7 +1637,7 @@ pub mod tests {
"Markdown editor should have a separate verison, repeating Rust editor rules" "Markdown editor should have a separate verison, repeating Rust editor rules"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 1); assert_eq!(editor.inlay_hint_cache_version(), 1);
}); });
rs_editor.update(cx, |editor, cx| { rs_editor.update(cx, |editor, cx| {
@ -1640,7 +1654,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
2, 2,
"Every time hint cache changes, cache version should be incremented" "Every time hint cache changes, cache version should be incremented"
); );
@ -1653,7 +1667,7 @@ pub mod tests {
"Markdown editor should not be affected by Rust editor changes" "Markdown editor should not be affected by Rust editor changes"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 1); assert_eq!(editor.inlay_hint_cache_version(), 1);
}); });
md_editor.update(cx, |editor, cx| { md_editor.update(cx, |editor, cx| {
@ -1669,7 +1683,7 @@ pub mod tests {
"Rust editor should not be affected by Markdown editor changes" "Rust editor should not be affected by Markdown editor changes"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 2); assert_eq!(editor.inlay_hint_cache_version(), 2);
}); });
rs_editor.update(cx, |editor, cx| { rs_editor.update(cx, |editor, cx| {
let expected_hints = vec!["1".to_string()]; let expected_hints = vec!["1".to_string()];
@ -1679,7 +1693,7 @@ pub mod tests {
"Markdown editor should also change independently" "Markdown editor should also change independently"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 2); assert_eq!(editor.inlay_hint_cache_version(), 2);
}); });
} }
@ -1801,7 +1815,7 @@ pub mod tests {
visible_hint_labels(editor, cx) visible_hint_labels(editor, cx)
); );
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
edits_made, edits_made,
"Should not update cache version due to new loaded hints being the same" "Should not update cache version due to new loaded hints being the same"
); );
@ -1936,7 +1950,7 @@ pub mod tests {
assert!(cached_hint_labels(editor).is_empty()); assert!(cached_hint_labels(editor).is_empty());
assert!(visible_hint_labels(editor, cx).is_empty()); assert!(visible_hint_labels(editor, cx).is_empty());
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, edits_made, editor.inlay_hint_cache_version(), edits_made,
"The editor should not update the cache version after /refresh query without updates" "The editor should not update the cache version after /refresh query without updates"
); );
}); });
@ -2007,7 +2021,7 @@ pub mod tests {
vec!["parameter hint".to_string()], vec!["parameter hint".to_string()],
visible_hint_labels(editor, cx), visible_hint_labels(editor, cx),
); );
assert_eq!(editor.inlay_hint_cache().version, edits_made); assert_eq!(editor.inlay_hint_cache_version(), edits_made);
}); });
} }
@ -2086,7 +2100,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, 1, editor.inlay_hint_cache_version(), 1,
"Only one update should be registered in the cache after all cancellations" "Only one update should be registered in the cache after all cancellations"
); );
}); });
@ -2131,7 +2145,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
2, 2,
"Should update the cache version once more, for the new change" "Should update the cache version once more, for the new change"
); );
@ -2301,7 +2315,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx), "Should display only hints from the visible range"); assert_eq!(expected_hints, visible_hint_labels(editor, cx), "Should display only hints from the visible range");
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, requests_count, editor.inlay_hint_cache_version(), requests_count,
"LSP queries should've bumped the cache version" "LSP queries should've bumped the cache version"
); );
}); });
@ -2363,7 +2377,7 @@ pub mod tests {
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
lsp_requests, lsp_requests,
"Should update the cache for every LSP response with hints added" "Should update the cache for every LSP response with hints added"
); );
@ -2427,7 +2441,7 @@ pub mod tests {
assert_eq!(expected_hints, cached_hint_labels(editor), assert_eq!(expected_hints, cached_hint_labels(editor),
"Should have hints from the new LSP response after the edit"); "Should have hints from the new LSP response after the edit");
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, lsp_requests, "Should update the cache for every LSP response with hints added"); assert_eq!(editor.inlay_hint_cache_version(), lsp_requests, "Should update the cache for every LSP response with hints added");
}); });
} }
@ -2650,7 +2664,7 @@ pub mod tests {
"When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints" "When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison"); assert_eq!(editor.inlay_hint_cache_version(), expected_hints.len(), "Every visible excerpt hints should bump the verison");
}); });
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -2680,7 +2694,7 @@ pub mod tests {
assert_eq!(expected_hints, cached_hint_labels(editor), assert_eq!(expected_hints, cached_hint_labels(editor),
"With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits"); "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), assert_eq!(editor.inlay_hint_cache_version(), expected_hints.len(),
"Due to every excerpt having one hint, we update cache per new excerpt scrolled"); "Due to every excerpt having one hint, we update cache per new excerpt scrolled");
}); });
@ -2711,7 +2725,7 @@ pub mod tests {
assert_eq!(expected_hints, cached_hint_labels(editor), assert_eq!(expected_hints, cached_hint_labels(editor),
"After multibuffer was scrolled to the end, all hints for all excerpts should be fetched"); "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, expected_hints.len()); assert_eq!(editor.inlay_hint_cache_version(), expected_hints.len());
expected_hints.len() expected_hints.len()
}); });
@ -2739,7 +2753,7 @@ pub mod tests {
assert_eq!(expected_hints, cached_hint_labels(editor), assert_eq!(expected_hints, cached_hint_labels(editor),
"After multibuffer was scrolled to the end, further scrolls up should not bring more hints"); "After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer"); assert_eq!(editor.inlay_hint_cache_version(), last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
}); });
editor_edited.store(true, Ordering::Release); editor_edited.store(true, Ordering::Release);
@ -2769,7 +2783,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
let current_cache_version = editor.inlay_hint_cache().version; let current_cache_version = editor.inlay_hint_cache_version();
let minimum_expected_version = last_scroll_update_version + expected_hints.len(); let minimum_expected_version = last_scroll_update_version + expected_hints.len();
assert!( assert!(
current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1, current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
@ -2953,7 +2967,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"All hints are disabled and should not be shown despite being present in the cache" "All hints are disabled and should not be shown despite being present in the cache"
); );
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
2, 2,
"Cache should update once per excerpt query" "Cache should update once per excerpt query"
); );
@ -2976,7 +2990,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"All hints are disabled and should not be shown despite being present in the cache" "All hints are disabled and should not be shown despite being present in the cache"
); );
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
3, 3,
"Excerpt removal should trigger a cache update" "Excerpt removal should trigger a cache update"
); );
@ -3004,7 +3018,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"Settings change should make cached hints visible" "Settings change should make cached hints visible"
); );
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
4, 4,
"Settings change should trigger a cache update" "Settings change should trigger a cache update"
); );
@ -3114,7 +3128,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
let expected_hints = vec!["1".to_string()]; let expected_hints = vec!["1".to_string()];
assert_eq!(expected_hints, cached_hint_labels(editor)); assert_eq!(expected_hints, cached_hint_labels(editor));
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 1); assert_eq!(editor.inlay_hint_cache_version(), 1);
}); });
} }
@ -3171,7 +3185,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!( assert_eq!(
editor.inlay_hint_cache().version, editor.inlay_hint_cache_version(),
1, 1,
"First toggle should be cache's first update" "First toggle should be cache's first update"
); );
@ -3187,7 +3201,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"Should clear hints after 2nd toggle" "Should clear hints after 2nd toggle"
); );
assert!(visible_hint_labels(editor, cx).is_empty()); assert!(visible_hint_labels(editor, cx).is_empty());
assert_eq!(editor.inlay_hint_cache().version, 2); assert_eq!(editor.inlay_hint_cache_version(), 2);
}); });
update_test_language_settings(cx, |settings| { update_test_language_settings(cx, |settings| {
@ -3207,7 +3221,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"Should query LSP hints for the 2nd time after enabling hints in settings" "Should query LSP hints for the 2nd time after enabling hints in settings"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 3); assert_eq!(editor.inlay_hint_cache_version(), 3);
}); });
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -3220,7 +3234,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"Should clear hints after enabling in settings and a 3rd toggle" "Should clear hints after enabling in settings and a 3rd toggle"
); );
assert!(visible_hint_labels(editor, cx).is_empty()); assert!(visible_hint_labels(editor, cx).is_empty());
assert_eq!(editor.inlay_hint_cache().version, 4); assert_eq!(editor.inlay_hint_cache_version(), 4);
}); });
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -3235,7 +3249,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
"Should query LSP hints for the 3rd time after enabling hints in settings and toggling them back on" "Should query LSP hints for the 3rd time after enabling hints in settings and toggling them back on"
); );
assert_eq!(expected_hints, visible_hint_labels(editor, cx)); assert_eq!(expected_hints, visible_hint_labels(editor, cx));
assert_eq!(editor.inlay_hint_cache().version, 5); assert_eq!(editor.inlay_hint_cache_version(), 5);
}); });
} }
@ -3318,7 +3332,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
assert!(cached_hint_labels(editor).is_empty()); assert!(cached_hint_labels(editor).is_empty());
assert!(visible_hint_labels(editor, cx).is_empty()); assert!(visible_hint_labels(editor, cx).is_empty());
assert_eq!(editor.inlay_hint_cache().version, 0); assert_eq!(editor.inlay_hint_cache_version(), 0);
}); });
("/a/main.rs", editor, fake_server) ("/a/main.rs", editor, fake_server)

View file

@ -3,7 +3,7 @@ use crate::{
movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor, movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor,
Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _, Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,
}; };
use anyhow::{Context, Result}; use anyhow::{anyhow, Context, Result};
use collections::HashSet; use collections::HashSet;
use futures::future::try_join_all; use futures::future::try_join_all;
use gpui::{ use gpui::{
@ -652,7 +652,9 @@ impl Item for Editor {
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
self.report_editor_event("save", None, cx); self.report_editor_event("save", None, cx);
let format = self.perform_format(project.clone(), FormatTrigger::Save, cx); let Some(format) = self.perform_format(FormatTrigger::Save, cx) else {
return Task::ready(Err(anyhow!("Editor does not have a formatter attached")));
};
let buffers = self.buffer().clone().read(cx).all_buffers(); let buffers = self.buffer().clone().read(cx).all_buffers();
cx.spawn(|_, mut cx| async move { cx.spawn(|_, mut cx| async move {
format.await?; format.await?;

View file

@ -178,6 +178,9 @@ pub fn update_inlay_link_and_hover_points(
let mut go_to_definition_updated = false; let mut go_to_definition_updated = false;
let mut hover_updated = false; let mut hover_updated = false;
if let Some(hovered_offset) = hovered_offset { if let Some(hovered_offset) = hovered_offset {
let Some(inlay_hint_cache) = editor.inlay_hints.clone() else {
return;
};
let buffer_snapshot = editor.buffer().read(cx).snapshot(cx); let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
let previous_valid_anchor = buffer_snapshot.anchor_at( let previous_valid_anchor = buffer_snapshot.anchor_at(
point_for_position.previous_valid.to_point(snapshot), point_for_position.previous_valid.to_point(snapshot),
@ -202,82 +205,84 @@ pub fn update_inlay_link_and_hover_points(
}) })
.max_by_key(|hint| hint.id) .max_by_key(|hint| hint.id)
{ {
let inlay_hint_cache = editor.inlay_hint_cache();
let excerpt_id = previous_valid_anchor.excerpt_id; let excerpt_id = previous_valid_anchor.excerpt_id;
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) { inlay_hint_cache.update(cx, |inlay_hint_cache, cx| {
match cached_hint.resolve_state { if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id)
ResolveState::CanResolve(_, _) => { {
if let Some(buffer_id) = previous_valid_anchor.buffer_id { match cached_hint.resolve_state {
inlay_hint_cache.spawn_hint_resolve( ResolveState::CanResolve(_, _) => {
buffer_id, if let Some(buffer_id) = previous_valid_anchor.buffer_id {
excerpt_id, inlay_hint_cache.spawn_hint_resolve(
hovered_hint.id, buffer_id,
cx, excerpt_id,
); hovered_hint.id,
} cx,
} );
ResolveState::Resolved => {
let mut extra_shift_left = 0;
let mut extra_shift_right = 0;
if cached_hint.padding_left {
extra_shift_left += 1;
extra_shift_right += 1;
}
if cached_hint.padding_right {
extra_shift_right += 1;
}
match cached_hint.label {
project::InlayHintLabel::String(_) => {
if let Some(tooltip) = cached_hint.tooltip {
hover_popover::hover_at_inlay(
editor,
InlayHover {
excerpt: excerpt_id,
tooltip: match tooltip {
InlayHintTooltip::String(text) => HoverBlock {
text,
kind: HoverBlockKind::PlainText,
},
InlayHintTooltip::MarkupContent(content) => {
HoverBlock {
text: content.value,
kind: content.kind,
}
}
},
range: InlayHighlight {
inlay: hovered_hint.id,
inlay_position: hovered_hint.position,
range: extra_shift_left
..hovered_hint.text.len() + extra_shift_right,
},
},
cx,
);
hover_updated = true;
}
} }
project::InlayHintLabel::LabelParts(label_parts) => { }
let hint_start = ResolveState::Resolved => {
snapshot.anchor_to_inlay_offset(hovered_hint.position); let mut extra_shift_left = 0;
if let Some((hovered_hint_part, part_range)) = let mut extra_shift_right = 0;
hover_popover::find_hovered_hint_part( if cached_hint.padding_left {
label_parts, extra_shift_left += 1;
hint_start, extra_shift_right += 1;
hovered_offset, }
) if cached_hint.padding_right {
{ extra_shift_right += 1;
let highlight_start = }
(part_range.start - hint_start).0 + extra_shift_left; match cached_hint.label {
let highlight_end = project::InlayHintLabel::String(_) => {
(part_range.end - hint_start).0 + extra_shift_right; if let Some(tooltip) = cached_hint.tooltip {
let highlight = InlayHighlight {
inlay: hovered_hint.id,
inlay_position: hovered_hint.position,
range: highlight_start..highlight_end,
};
if let Some(tooltip) = hovered_hint_part.tooltip {
hover_popover::hover_at_inlay( hover_popover::hover_at_inlay(
editor,
InlayHover {
excerpt: excerpt_id,
tooltip: match tooltip {
InlayHintTooltip::String(text) => HoverBlock {
text,
kind: HoverBlockKind::PlainText,
},
InlayHintTooltip::MarkupContent(content) => {
HoverBlock {
text: content.value,
kind: content.kind,
}
}
},
range: InlayHighlight {
inlay: hovered_hint.id,
inlay_position: hovered_hint.position,
range: extra_shift_left
..hovered_hint.text.len()
+ extra_shift_right,
},
},
cx,
);
hover_updated = true;
}
}
project::InlayHintLabel::LabelParts(label_parts) => {
let hint_start =
snapshot.anchor_to_inlay_offset(hovered_hint.position);
if let Some((hovered_hint_part, part_range)) =
hover_popover::find_hovered_hint_part(
label_parts,
hint_start,
hovered_offset,
)
{
let highlight_start =
(part_range.start - hint_start).0 + extra_shift_left;
let highlight_end =
(part_range.end - hint_start).0 + extra_shift_right;
let highlight = InlayHighlight {
inlay: hovered_hint.id,
inlay_position: hovered_hint.position,
range: highlight_start..highlight_end,
};
if let Some(tooltip) = hovered_hint_part.tooltip {
hover_popover::hover_at_inlay(
editor, editor,
InlayHover { InlayHover {
excerpt: excerpt_id, excerpt: excerpt_id,
@ -299,31 +304,32 @@ pub fn update_inlay_link_and_hover_points(
}, },
cx, cx,
); );
hover_updated = true; hover_updated = true;
} }
if let Some((language_server_id, location)) = if let Some((language_server_id, location)) =
hovered_hint_part.location hovered_hint_part.location
{ {
go_to_definition_updated = true; go_to_definition_updated = true;
update_go_to_definition_link( update_go_to_definition_link(
editor, editor,
Some(GoToDefinitionTrigger::InlayHint( Some(GoToDefinitionTrigger::InlayHint(
highlight, highlight,
location, location,
language_server_id, language_server_id,
)), )),
cmd_held, cmd_held,
shift_held, shift_held,
cx, cx,
); );
}
} }
} }
} };
}; }
ResolveState::Resolving => {}
} }
ResolveState::Resolving => {}
} }
} })
} }
} }
@ -353,7 +359,7 @@ pub fn show_link_definition(
hide_link_definition(editor, cx); hide_link_definition(editor, cx);
} }
if editor.pending_rename.is_some() { if editor.has_pending_rename(cx) {
return; return;
} }