Detailed changes
@@ -1061,11 +1061,10 @@ pub struct Editor {
read_only: bool,
leader_id: Option<CollaboratorId>,
remote_id: Option<ViewId>,
- hover_state: HoverState,
+ pub hover_state: HoverState,
pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
gutter_hovered: bool,
hovered_link_state: Option<HoveredLinkState>,
- resolved_inlay_hints_pending_hover: HashSet<InlayId>,
edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
active_inline_completion: Option<InlineCompletionState>,
@@ -2080,7 +2079,6 @@ impl Editor {
hover_state: HoverState::default(),
pending_mouse_down: None,
hovered_link_state: None,
- resolved_inlay_hints_pending_hover: HashSet::default(),
edit_prediction_provider: None,
active_inline_completion: None,
stale_inline_completion_in_menu: None,
@@ -20354,99 +20352,6 @@ impl Editor {
&self.inlay_hint_cache
}
- pub fn check_resolved_inlay_hint_hover(
- &mut self,
- inlay_id: InlayId,
- excerpt_id: ExcerptId,
- window: &mut Window,
- cx: &mut Context<Self>,
- ) -> bool {
- if !self.resolved_inlay_hints_pending_hover.remove(&inlay_id) {
- return false;
- }
- // Get the resolved hint from the cache
- if let Some(cached_hint) = self.inlay_hint_cache.hint_by_id(excerpt_id, inlay_id) {
- // Check if we have tooltip data to display
- let mut hover_to_show = None;
-
- // Check main tooltip
- if let Some(tooltip) = &cached_hint.tooltip {
- let inlay_hint = self
- .visible_inlay_hints(cx)
- .into_iter()
- .find(|hint| hint.id == inlay_id);
-
- if let Some(inlay_hint) = inlay_hint {
- let range = crate::InlayHighlight {
- inlay: inlay_id,
- inlay_position: inlay_hint.position,
- range: 0..inlay_hint.text.len(),
- };
- hover_to_show = Some((tooltip.clone(), range));
- }
- } else if let project::InlayHintLabel::LabelParts(parts) = &cached_hint.label {
- // Check label parts for tooltips
- let inlay_hint = self
- .visible_inlay_hints(cx)
- .into_iter()
- .find(|hint| hint.id == inlay_id);
-
- if let Some(inlay_hint) = inlay_hint {
- let mut offset = 0;
- for part in parts {
- if let Some(part_tooltip) = &part.tooltip {
- let range = crate::InlayHighlight {
- inlay: inlay_id,
- inlay_position: inlay_hint.position,
- range: offset..offset + part.value.len(),
- };
- // Convert InlayHintLabelPartTooltip to InlayHintTooltip
- let tooltip = match part_tooltip {
- project::InlayHintLabelPartTooltip::String(text) => {
- project::InlayHintTooltip::String(text.clone())
- }
- project::InlayHintLabelPartTooltip::MarkupContent(content) => {
- project::InlayHintTooltip::MarkupContent(content.clone())
- }
- };
- hover_to_show = Some((tooltip, range));
- break;
- }
- offset += part.value.len();
- }
- }
- }
-
- // Show the hover if we have tooltip data
- if let Some((tooltip, range)) = hover_to_show {
- use crate::hover_popover::{InlayHover, hover_at_inlay};
- use project::{HoverBlock, HoverBlockKind, InlayHintTooltip};
-
- let hover_block = match tooltip {
- InlayHintTooltip::String(text) => HoverBlock {
- text,
- kind: HoverBlockKind::PlainText,
- },
- InlayHintTooltip::MarkupContent(content) => HoverBlock {
- text: content.value,
- kind: content.kind,
- },
- };
-
- hover_at_inlay(
- self,
- InlayHover {
- tooltip: hover_block,
- range,
- },
- window,
- cx,
- );
- }
- }
- true
- }
-
pub fn replay_insert_event(
&mut self,
text: &str,
@@ -121,22 +121,6 @@ impl Editor {
cx: &mut Context<Self>,
) {
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() {
self.hide_hovered_link(cx);
return;
@@ -153,7 +137,15 @@ impl Editor {
show_link_definition(modifiers.shift, self, trigger_point, snapshot, window, cx);
}
None => {
- // This case is now handled above
+ update_inlay_link_and_hover_points(
+ snapshot,
+ point_for_position,
+ self,
+ hovered_link_modifier,
+ modifiers.shift,
+ window,
+ cx,
+ );
}
}
}
@@ -327,164 +319,129 @@ pub fn update_inlay_link_and_hover_points(
let inlay_hint_cache = editor.inlay_hint_cache();
let excerpt_id = previous_valid_anchor.excerpt_id;
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
- // Check if we should process this hint for hover
- let should_process_hint = match cached_hint.resolve_state {
+ match cached_hint.resolve_state {
ResolveState::CanResolve(_, _) => {
- // Check if the hint already has the data we need (tooltip in label parts)
- if let project::InlayHintLabel::LabelParts(label_parts) = &cached_hint.label
- {
- let has_tooltip_parts =
- label_parts.iter().any(|part| part.tooltip.is_some());
- if has_tooltip_parts {
- 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
+ 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,
+ );
}
}
ResolveState::Resolved => {
- true // Process the hint
- }
- ResolveState::Resolving => {
- // Check if this hint was just resolved and needs hover
- if editor.check_resolved_inlay_hint_hover(
- hovered_hint.id,
- excerpt_id,
- window,
- cx,
- ) {
- return; // Hover was shown by check_resolved_inlay_hint_hover
+ 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;
}
- false // Don't process yet
- }
- };
-
- 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 {
+ extra_shift_right += 1;
}
- 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 {
+ match cached_hint.label {
+ project::InlayHintLabel::String(_) => {
+ if let Some(tooltip) = cached_hint.tooltip {
hover_popover::hover_at_inlay(
editor,
InlayHover {
tooltip: match tooltip {
- InlayHintLabelPartTooltip::String(text) => {
+ InlayHintTooltip::String(text) => HoverBlock {
+ text,
+ kind: HoverBlockKind::PlainText,
+ },
+ InlayHintTooltip::MarkupContent(content) => {
HoverBlock {
- text,
- kind: HoverBlockKind::PlainText,
+ text: content.value,
+ kind: content.kind,
}
}
- InlayHintLabelPartTooltip::MarkupContent(
- content,
- ) => HoverBlock {
- text: content.value,
- kind: content.kind,
- },
},
- range: highlight.clone(),
+ 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 let Some((language_server_id, location)) =
- hovered_hint_part.location
+ }
+ 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,
+ )
{
- if secondary_held && !editor.has_pending_nonempty_selection() {
- go_to_definition_updated = true;
- show_link_definition(
- shift_held,
+ 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,
- TriggerPoint::InlayHint(
- highlight,
- location,
- language_server_id,
- ),
- snapshot,
+ InlayHover {
+ tooltip: match tooltip {
+ InlayHintLabelPartTooltip::String(text) => {
+ HoverBlock {
+ text,
+ kind: HoverBlockKind::PlainText,
+ }
+ }
+ InlayHintLabelPartTooltip::MarkupContent(
+ content,
+ ) => HoverBlock {
+ text: content.value,
+ kind: content.kind,
+ },
+ },
+ range: highlight.clone(),
+ },
window,
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 => {}
}
}
}
@@ -55,15 +55,7 @@ pub fn hover_at(
if let Some(anchor) = anchor {
show_hover(editor, anchor, false, window, cx);
} else {
- // Don't hide hover if there's an active inlay hover
- let has_inlay_hover = editor
- .hover_state
- .info_popovers
- .iter()
- .any(|popover| matches!(popover.symbol_range, RangeInEditor::Inlay(_)));
- if !has_inlay_hover {
- hide_hover(editor, cx);
- }
+ hide_hover(editor, cx);
}
}
}
@@ -159,12 +151,7 @@ pub fn hover_at_inlay(
false
})
{
- return;
- }
-
- // Check if we have an in-progress hover task for a different location
- if editor.hover_state.info_task.is_some() {
- editor.hover_state.info_task = None;
+ hide_hover(editor, cx);
}
let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
@@ -214,9 +201,7 @@ pub fn hover_at_inlay(
anyhow::Ok(())
}
.log_err()
- .await;
-
- Some(())
+ .await
});
editor.hover_state.info_task = Some(task);
@@ -1898,236 +1883,4 @@ mod tests {
);
});
}
-
- #[gpui::test]
- async fn test_hover_on_inlay_hint_types(cx: &mut gpui::TestAppContext) {
- use crate::{DisplayPoint, PointForPosition};
-
- init_test(cx, |settings| {
- settings.defaults.inlay_hints = Some(InlayHintSettings {
- enabled: true,
- show_type_hints: true,
- show_value_hints: true,
- show_parameter_hints: true,
- show_other_hints: true,
- edit_debounce_ms: 0,
- scroll_debounce_ms: 0,
- show_background: false,
- toggle_on_modifiers_press: None,
- });
- });
-
- let mut cx = EditorLspTestContext::new_rust(
- lsp::ServerCapabilities {
- hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
- inlay_hint_provider: Some(lsp::OneOf::Right(
- lsp::InlayHintServerCapabilities::Options(lsp::InlayHintOptions {
- resolve_provider: Some(true),
- ..Default::default()
- }),
- )),
- ..Default::default()
- },
- cx,
- )
- .await;
-
- cx.set_state(indoc! {r#"
- struct String;
-
- fn main() {
- let foo = "foo".to_string();
- let bar: String = "bar".to_string();ˇ
- }
- "#});
-
- // Set up inlay hint handler with proper label parts that include locations
- let buffer_text = cx.buffer_text();
- let hint_position = cx.to_lsp(buffer_text.find("foo =").unwrap() + 3);
- let string_type_range = cx.lsp_range(indoc! {r#"
- struct «String»;
-
- fn main() {
- let foo = "foo".to_string();
- let bar: String = "bar".to_string();
- }
- "#});
- let uri = cx.buffer_lsp_url.clone();
-
- cx.set_request_handler::<lsp::request::InlayHintRequest, _, _>(move |_, _params, _| {
- let uri = uri.clone();
- async move {
- Ok(Some(vec![lsp::InlayHint {
- position: hint_position,
- label: lsp::InlayHintLabel::LabelParts(vec![
- lsp::InlayHintLabelPart {
- value: ": ".to_string(),
- location: None,
- tooltip: None,
- command: None,
- },
- lsp::InlayHintLabelPart {
- value: "String".to_string(),
- location: Some(lsp::Location {
- uri: uri.clone(),
- range: string_type_range,
- }),
- tooltip: Some(lsp::InlayHintLabelPartTooltip::MarkupContent(
- lsp::MarkupContent {
- kind: lsp::MarkupKind::Markdown,
- value: "```rust\nstruct String\n```\n\nA UTF-8 encoded, growable string.".to_string(),
- }
- )),
- command: None,
- },
- ]),
- kind: Some(lsp::InlayHintKind::TYPE),
- text_edits: None,
- tooltip: None,
- padding_left: Some(false),
- padding_right: Some(false),
- data: None,
- }]))
- }
- })
- .next()
- .await;
-
- cx.background_executor.run_until_parked();
-
- // Verify inlay hint is displayed
- cx.update_editor(|editor, _, cx| {
- let expected_layers = vec![": String".to_string()];
- assert_eq!(expected_layers, cached_hint_labels(editor));
- assert_eq!(expected_layers, visible_hint_labels(editor, cx));
- });
-
- // Set up hover handler for explicit type hover
- let mut hover_requests =
- cx.set_request_handler::<lsp::request::HoverRequest, _, _>(move |_, _params, _| {
- async move {
- // Return hover info for any hover request (both line 0 and line 4 have String types)
- Ok(Some(lsp::Hover {
- contents: lsp::HoverContents::Markup(lsp::MarkupContent {
- kind: lsp::MarkupKind::Markdown,
- value:
- "```rust\nstruct String\n```\n\nA UTF-8 encoded, growable string."
- .to_string(),
- }),
- range: None,
- }))
- }
- });
-
- // Test hovering over the inlay hint type
- // Get the position where the inlay hint is displayed
- let inlay_range = cx
- .ranges(indoc! {r#"
- struct String;
-
- fn main() {
- let foo« »= "foo".to_string();
- let bar: String = "bar".to_string();
- }
- "#})
- .first()
- .cloned()
- .unwrap();
-
- // Create a PointForPosition that simulates hovering over the "String" part of the inlay hint
- let point_for_position = cx.update_editor(|editor, window, cx| {
- let snapshot = editor.snapshot(window, cx);
- let previous_valid = inlay_range.start.to_display_point(&snapshot);
- let next_valid = inlay_range.end.to_display_point(&snapshot);
- // The hint text is ": String", we want to hover over "String" which starts at index 2
- // Add a bit more to ensure we're well within "String" (e.g., over the 'r')
- let exact_unclipped = DisplayPoint::new(
- previous_valid.row(),
- previous_valid.column() + 4, // Position over 'r' in "String"
- );
- PointForPosition {
- previous_valid,
- next_valid,
- exact_unclipped,
- column_overshoot_after_line_end: 0,
- }
- });
-
- // Update hovered link to trigger hover logic for inlay hints
- cx.update_editor(|editor, window, cx| {
- let snapshot = editor.snapshot(window, cx);
- update_inlay_link_and_hover_points(
- &snapshot,
- point_for_position,
- editor,
- false, // secondary_held
- false, // shift_held
- window,
- cx,
- );
- });
-
- // Wait for the popover to appear
- cx.background_executor
- .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
- cx.background_executor.run_until_parked();
-
- // Check if hover popover is shown for inlay hint
- let has_inlay_hover = cx.editor(|editor, _, _| editor.hover_state.info_popovers.len() > 0);
-
- // Clear hover state
- cx.update_editor(|editor, _, cx| {
- hide_hover(editor, cx);
- });
-
- // Test hovering over the explicit type
- let explicit_string_point = cx.display_point(indoc! {r#"
- struct String;
-
- fn main() {
- let foo = "foo".to_string();
- let bar: Sˇtring = "bar".to_string();
- }
- "#});
-
- // Use hover_at to trigger hover on explicit type
- cx.update_editor(|editor, window, cx| {
- let snapshot = editor.snapshot(window, cx);
- let anchor = snapshot
- .buffer_snapshot
- .anchor_before(explicit_string_point.to_offset(&snapshot, Bias::Left));
- hover_at(editor, Some(anchor), window, cx);
- });
-
- // Wait for hover request and give time for the popover to appear
- hover_requests.next().await;
- cx.background_executor
- .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
- cx.background_executor.run_until_parked();
-
- // Check if hover popover is shown for explicit type
- let has_explicit_hover =
- cx.editor(|editor, _, _| editor.hover_state.info_popovers.len() > 0);
-
- // Both should show hover popovers
- assert!(
- has_explicit_hover,
- "Hover popover should be shown when hovering over explicit type"
- );
-
- assert!(
- has_inlay_hover,
- "Hover popover should be shown when hovering over inlay hint type"
- );
-
- // NOTE: This test demonstrates the proper fix for issue #33715:
- // Language servers should provide inlay hints with label parts that include
- // tooltip information. When users hover over a type in an inlay hint,
- // they see the tooltip content, which should contain the same information
- // as hovering over an actual type annotation.
- //
- // The issue occurs when language servers provide inlay hints as plain strings
- // (e.g., ": String") without any tooltip information. In that case, there's
- // no way for Zed to know what documentation to show when hovering.
- }
}
@@ -21,7 +21,6 @@ use clock::Global;
use futures::future;
use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
use language::{Buffer, BufferSnapshot, language_settings::InlayHintKind};
-use lsp::LanguageServerId;
use parking_lot::RwLock;
use project::{InlayHint, ResolveState};
@@ -623,67 +622,45 @@ impl InlayHintCache {
let mut guard = excerpt_hints.write();
if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
if let ResolveState::CanResolve(server_id, _) = &cached_hint.resolve_state {
- let server_id = *server_id;
let hint_to_resolve = cached_hint.clone();
+ let server_id = *server_id;
cached_hint.resolve_state = ResolveState::Resolving;
drop(guard);
- self.resolve_hint(
- server_id,
- buffer_id,
- excerpt_id,
- id,
- hint_to_resolve,
- window,
- cx,
- )
+ 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.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,
- excerpt_id: ExcerptId,
- inlay_id: InlayId,
- 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(&inlay_id) {
- if cached_hint.resolve_state == ResolveState::Resolving {
- resolved_hint.resolve_state = ResolveState::Resolved;
- *cached_hint = resolved_hint;
- }
- }
- }
-
- // Mark the hint as resolved and needing hover check
- editor.resolved_inlay_hints_pending_hover.insert(inlay_id);
- cx.notify();
- })?;
- }
-
- anyhow::Ok(())
- })
- }
}
fn debounce_value(debounce_ms: u64) -> Option<Duration> {
@@ -4965,10 +4965,7 @@ impl LspStore {
return Task::ready(Ok(hint));
}
let buffer_snapshot = buffer_handle.read(cx).snapshot();
- // Preserve the original hint data before resolution
- let original_hint = hint.clone();
-
- cx.spawn(async move |_this, cx| {
+ cx.spawn(async move |_, cx| {
let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
);
@@ -4976,139 +4973,7 @@ impl LspStore {
.await
.into_response()
.context("inlay hint resolve LSP request")?;
-
- // Check if we need to fetch hover info as a fallback
- let needs_fallback = match &resolved_hint.label {
- lsp::InlayHintLabel::String(_) => resolved_hint.tooltip.is_none(),
- lsp::InlayHintLabel::LabelParts(parts) => {
- resolved_hint.tooltip.is_none()
- && parts
- .iter()
- .any(|p| p.tooltip.is_none() && p.location.is_some())
- }
- };
-
- let mut resolved_hint = resolved_hint;
-
- if let lsp::InlayHintLabel::LabelParts(parts) = &resolved_hint.label {
- for (i, part) in parts.iter().enumerate() {
- " Part {}: value='{}', tooltip={:?}, location={:?}",
- i, part.value, part.tooltip, part.location
- );
- }
- }
-
- if needs_fallback {
- // For label parts with locations but no tooltips, fetch hover info
- if let lsp::InlayHintLabel::LabelParts(parts) = &mut resolved_hint.label {
- for part in parts.iter_mut() {
- if part.tooltip.is_none() {
- if let Some(location) = &part.location {
-
- // Open the document
- let did_open_params = lsp::DidOpenTextDocumentParams {
- text_document: lsp::TextDocumentItem {
- uri: location.uri.clone(),
- language_id: "rust".to_string(), // TODO: Detect language
- version: 0,
- text: std::fs::read_to_string(location.uri.path())
- .unwrap_or_else(|_| String::new()),
- },
- };
-
- lang_server.notify::<lsp::notification::DidOpenTextDocument>(
- &did_open_params,
- )?;
-
- // Request hover at the location
- let hover_params = lsp::HoverParams {
- text_document_position_params:
- lsp::TextDocumentPositionParams {
- text_document: lsp::TextDocumentIdentifier {
- uri: location.uri.clone(),
- },
- position: location.range.start,
- },
- work_done_progress_params: Default::default(),
- };
-
- if let Ok(hover_response) = lang_server
- .request::<lsp::request::HoverRequest>(hover_params)
- .await
- .into_response()
- {
-
- if let Some(hover) = hover_response {
- // Convert hover contents to tooltip
- part.tooltip = Some(match hover.contents {
- lsp::HoverContents::Scalar(content) => {
- lsp::InlayHintLabelPartTooltip::String(
- match content {
- lsp::MarkedString::String(s) => s,
- lsp::MarkedString::LanguageString(
- ls,
- ) => ls.value,
- },
- )
- }
- lsp::HoverContents::Array(contents) => {
- let combined = contents
- .into_iter()
- .map(|c| match c {
- lsp::MarkedString::String(s) => s,
- lsp::MarkedString::LanguageString(
- ls,
- ) => ls.value,
- })
- .collect::<Vec<_>>()
- .join("\n\n");
- lsp::InlayHintLabelPartTooltip::String(combined)
- }
- lsp::HoverContents::Markup(markup) => {
- lsp::InlayHintLabelPartTooltip::MarkupContent(
- markup,
- )
- }
- });
- }
- }
-
- // Close the document
- let did_close_params = lsp::DidCloseTextDocumentParams {
- text_document: lsp::TextDocumentIdentifier {
- uri: location.uri.clone(),
- },
- };
-
- lang_server.notify::<lsp::notification::DidCloseTextDocument>(
- &did_close_params,
- )?;
- }
- }
- }
- }
- }
-
- // Check if we need to restore location data from the original hint
- let mut resolved_hint = resolved_hint;
- if let (
- lsp::InlayHintLabel::LabelParts(resolved_parts),
- crate::InlayHintLabel::LabelParts(original_parts),
- ) = (&mut resolved_hint.label, &original_hint.label)
- {
- for (resolved_part, original_part) in
- resolved_parts.iter_mut().zip(original_parts.iter())
- {
- if resolved_part.location.is_none() && original_part.location.is_some() {
- // Restore location from original hint
- if let Some((_server_id, location)) = &original_part.location {
- resolved_part.location = Some(location.clone());
- }
- }
- }
- }
-
- let mut resolved_hint = InlayHints::lsp_to_project_hint(
+ let resolved_hint = InlayHints::lsp_to_project_hint(
resolved_hint,
&buffer_handle,
server_id,
@@ -5117,28 +4982,6 @@ impl LspStore {
cx,
)
.await?;
-
- // Final check: if resolved hint still has no tooltip but original had location,
- // preserve the original hint's data
- if resolved_hint.tooltip.is_none() {
- if let (
- crate::InlayHintLabel::LabelParts(resolved_parts),
- crate::InlayHintLabel::LabelParts(original_parts),
- ) = (&mut resolved_hint.label, &original_hint.label)
- {
- for (resolved_part, original_part) in
- resolved_parts.iter_mut().zip(original_parts.iter())
- {
- if resolved_part.tooltip.is_none()
- && resolved_part.location.is_none()
- && original_part.location.is_some()
- {
- resolved_part.location = original_part.location.clone();
- }
- }
- }
- }
-
Ok(resolved_hint)
})
}