Extract resolve_hint
Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
parent
a61e478152
commit
17f7312fc0
2 changed files with 182 additions and 137 deletions
|
@ -121,6 +121,22 @@ impl Editor {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
let hovered_link_modifier = Editor::multi_cursor_modifier(false, &modifiers, cx);
|
let hovered_link_modifier = Editor::multi_cursor_modifier(false, &modifiers, cx);
|
||||||
|
|
||||||
|
// Allow inlay hover points to be updated even without modifier key
|
||||||
|
if point_for_position.as_valid().is_none() {
|
||||||
|
// Hovering over inlay - check for hover tooltips
|
||||||
|
update_inlay_link_and_hover_points(
|
||||||
|
snapshot,
|
||||||
|
point_for_position,
|
||||||
|
self,
|
||||||
|
hovered_link_modifier,
|
||||||
|
modifiers.shift,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if !hovered_link_modifier || self.has_pending_selection() {
|
if !hovered_link_modifier || self.has_pending_selection() {
|
||||||
self.hide_hovered_link(cx);
|
self.hide_hovered_link(cx);
|
||||||
return;
|
return;
|
||||||
|
@ -137,15 +153,7 @@ impl Editor {
|
||||||
show_link_definition(modifiers.shift, self, trigger_point, snapshot, window, cx);
|
show_link_definition(modifiers.shift, self, trigger_point, snapshot, window, cx);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
update_inlay_link_and_hover_points(
|
// This case is now handled above
|
||||||
snapshot,
|
|
||||||
point_for_position,
|
|
||||||
self,
|
|
||||||
hovered_link_modifier,
|
|
||||||
modifiers.shift,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,129 +327,155 @@ pub fn update_inlay_link_and_hover_points(
|
||||||
let inlay_hint_cache = editor.inlay_hint_cache();
|
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) {
|
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||||
match cached_hint.resolve_state {
|
// Check if we should process this hint for hover
|
||||||
|
let should_process_hint = match cached_hint.resolve_state {
|
||||||
ResolveState::CanResolve(_, _) => {
|
ResolveState::CanResolve(_, _) => {
|
||||||
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
// Check if the hint already has the data we need (tooltip in label parts)
|
||||||
inlay_hint_cache.spawn_hint_resolve(
|
if let project::InlayHintLabel::LabelParts(label_parts) = &cached_hint.label
|
||||||
buffer_id,
|
{
|
||||||
excerpt_id,
|
let has_tooltip_parts =
|
||||||
hovered_hint.id,
|
label_parts.iter().any(|part| part.tooltip.is_some());
|
||||||
window,
|
if has_tooltip_parts {
|
||||||
cx,
|
true // Process the hint
|
||||||
);
|
} else {
|
||||||
|
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||||
|
inlay_hint_cache.spawn_hint_resolve(
|
||||||
|
buffer_id,
|
||||||
|
excerpt_id,
|
||||||
|
hovered_hint.id,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
false // Don't process further
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||||
|
inlay_hint_cache.spawn_hint_resolve(
|
||||||
|
buffer_id,
|
||||||
|
excerpt_id,
|
||||||
|
hovered_hint.id,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
false // Don't process further
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResolveState::Resolved => {
|
ResolveState::Resolved => {
|
||||||
let mut extra_shift_left = 0;
|
true // Process the hint
|
||||||
let mut extra_shift_right = 0;
|
}
|
||||||
if cached_hint.padding_left {
|
ResolveState::Resolving => {
|
||||||
extra_shift_left += 1;
|
false // Don't process yet
|
||||||
extra_shift_right += 1;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_process_hint {
|
||||||
|
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 {
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
hover_updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cached_hint.padding_right {
|
project::InlayHintLabel::LabelParts(label_parts) => {
|
||||||
extra_shift_right += 1;
|
let hint_start = snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||||
}
|
if let Some((hovered_hint_part, part_range)) =
|
||||||
match cached_hint.label {
|
hover_popover::find_hovered_hint_part(
|
||||||
project::InlayHintLabel::String(_) => {
|
label_parts,
|
||||||
if let Some(tooltip) = cached_hint.tooltip {
|
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(
|
hover_popover::hover_at_inlay(
|
||||||
editor,
|
editor,
|
||||||
InlayHover {
|
InlayHover {
|
||||||
tooltip: match tooltip {
|
tooltip: match tooltip {
|
||||||
InlayHintTooltip::String(text) => HoverBlock {
|
InlayHintLabelPartTooltip::String(text) => {
|
||||||
text,
|
|
||||||
kind: HoverBlockKind::PlainText,
|
|
||||||
},
|
|
||||||
InlayHintTooltip::MarkupContent(content) => {
|
|
||||||
HoverBlock {
|
HoverBlock {
|
||||||
text: content.value,
|
text,
|
||||||
kind: content.kind,
|
kind: HoverBlockKind::PlainText,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InlayHintLabelPartTooltip::MarkupContent(
|
||||||
|
content,
|
||||||
|
) => HoverBlock {
|
||||||
|
text: content.value,
|
||||||
|
kind: content.kind,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
range: InlayHighlight {
|
range: highlight.clone(),
|
||||||
inlay: hovered_hint.id,
|
|
||||||
inlay_position: hovered_hint.position,
|
|
||||||
range: extra_shift_left
|
|
||||||
..hovered_hint.text.len() + extra_shift_right,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
hover_updated = true;
|
hover_updated = true;
|
||||||
}
|
}
|
||||||
}
|
if let Some((language_server_id, location)) =
|
||||||
project::InlayHintLabel::LabelParts(label_parts) => {
|
hovered_hint_part.location
|
||||||
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 =
|
if secondary_held && !editor.has_pending_nonempty_selection() {
|
||||||
(part_range.start - hint_start).0 + extra_shift_left;
|
go_to_definition_updated = true;
|
||||||
let highlight_end =
|
show_link_definition(
|
||||||
(part_range.end - hint_start).0 + extra_shift_right;
|
shift_held,
|
||||||
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 {
|
TriggerPoint::InlayHint(
|
||||||
tooltip: match tooltip {
|
highlight,
|
||||||
InlayHintLabelPartTooltip::String(text) => {
|
location,
|
||||||
HoverBlock {
|
language_server_id,
|
||||||
text,
|
),
|
||||||
kind: HoverBlockKind::PlainText,
|
snapshot,
|
||||||
}
|
|
||||||
}
|
|
||||||
InlayHintLabelPartTooltip::MarkupContent(
|
|
||||||
content,
|
|
||||||
) => HoverBlock {
|
|
||||||
text: content.value,
|
|
||||||
kind: content.kind,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
range: highlight.clone(),
|
|
||||||
},
|
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
hover_updated = true;
|
|
||||||
}
|
|
||||||
if let Some((language_server_id, location)) =
|
|
||||||
hovered_hint_part.location
|
|
||||||
{
|
|
||||||
if secondary_held
|
|
||||||
&& !editor.has_pending_nonempty_selection()
|
|
||||||
{
|
|
||||||
go_to_definition_updated = true;
|
|
||||||
show_link_definition(
|
|
||||||
shift_held,
|
|
||||||
editor,
|
|
||||||
TriggerPoint::InlayHint(
|
|
||||||
highlight,
|
|
||||||
location,
|
|
||||||
language_server_id,
|
|
||||||
),
|
|
||||||
snapshot,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
ResolveState::Resolving => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ use clock::Global;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
|
use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
|
||||||
use language::{Buffer, BufferSnapshot, language_settings::InlayHintKind};
|
use language::{Buffer, BufferSnapshot, language_settings::InlayHintKind};
|
||||||
|
use lsp::LanguageServerId;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use project::{InlayHint, ResolveState};
|
use project::{InlayHint, ResolveState};
|
||||||
|
|
||||||
|
@ -622,45 +623,55 @@ impl InlayHintCache {
|
||||||
let mut guard = excerpt_hints.write();
|
let mut guard = excerpt_hints.write();
|
||||||
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
||||||
if let ResolveState::CanResolve(server_id, _) = &cached_hint.resolve_state {
|
if let ResolveState::CanResolve(server_id, _) = &cached_hint.resolve_state {
|
||||||
let hint_to_resolve = cached_hint.clone();
|
|
||||||
let server_id = *server_id;
|
let server_id = *server_id;
|
||||||
|
let mut cached_hint = cached_hint.clone();
|
||||||
cached_hint.resolve_state = ResolveState::Resolving;
|
cached_hint.resolve_state = ResolveState::Resolving;
|
||||||
drop(guard);
|
drop(guard);
|
||||||
cx.spawn_in(window, async move |editor, cx| {
|
self.resolve_hint(server_id, buffer_id, cached_hint, window, cx)
|
||||||
let resolved_hint_task = editor.update(cx, |editor, cx| {
|
.detach_and_log_err(cx);
|
||||||
let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
|
|
||||||
editor.semantics_provider.as_ref()?.resolve_inlay_hint(
|
|
||||||
hint_to_resolve,
|
|
||||||
buffer,
|
|
||||||
server_id,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
if let Some(resolved_hint_task) = resolved_hint_task {
|
|
||||||
let mut resolved_hint =
|
|
||||||
resolved_hint_task.await.context("hint resolve task")?;
|
|
||||||
editor.read_with(cx, |editor, _| {
|
|
||||||
if let Some(excerpt_hints) =
|
|
||||||
editor.inlay_hint_cache.hints.get(&excerpt_id)
|
|
||||||
{
|
|
||||||
let mut guard = excerpt_hints.write();
|
|
||||||
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
|
||||||
if cached_hint.resolve_state == ResolveState::Resolving {
|
|
||||||
resolved_hint.resolve_state = ResolveState::Resolved;
|
|
||||||
*cached_hint = resolved_hint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_hint(
|
||||||
|
&self,
|
||||||
|
server_id: LanguageServerId,
|
||||||
|
buffer_id: BufferId,
|
||||||
|
hint_to_resolve: InlayHint,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Editor>,
|
||||||
|
) -> Task<anyhow::Result<()>> {
|
||||||
|
cx.spawn_in(window, async move |editor, cx| {
|
||||||
|
let resolved_hint_task = editor.update(cx, |editor, cx| {
|
||||||
|
let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
|
||||||
|
editor.semantics_provider.as_ref()?.resolve_inlay_hint(
|
||||||
|
hint_to_resolve,
|
||||||
|
buffer,
|
||||||
|
server_id,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
if let Some(resolved_hint_task) = resolved_hint_task {
|
||||||
|
let mut resolved_hint = resolved_hint_task.await.context("hint resolve task")?;
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
if let Some(excerpt_hints) = editor.inlay_hint_cache.hints.get(&excerpt_id) {
|
||||||
|
let mut guard = excerpt_hints.write();
|
||||||
|
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
|
||||||
|
if cached_hint.resolve_state == ResolveState::Resolving {
|
||||||
|
resolved_hint.resolve_state = ResolveState::Resolved;
|
||||||
|
*cached_hint = resolved_hint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Notify to trigger UI update
|
||||||
|
cx.notify();
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debounce_value(debounce_ms: u64) -> Option<Duration> {
|
fn debounce_value(debounce_ms: u64) -> Option<Duration> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue