diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 91a1a1d86a..69b9158c31 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1061,11 +1061,10 @@ pub struct Editor { read_only: bool, leader_id: Option, remote_id: Option, - hover_state: HoverState, + pub hover_state: HoverState, pending_mouse_down: Option>>>, gutter_hovered: bool, hovered_link_state: Option, - resolved_inlay_hints_pending_hover: HashSet, edit_prediction_provider: Option, code_action_providers: Vec>, active_inline_completion: Option, @@ -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, - ) -> 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, diff --git a/crates/editor/src/hover_links.rs b/crates/editor/src/hover_links.rs index f26c0261c2..02f93e6829 100644 --- a/crates/editor/src/hover_links.rs +++ b/crates/editor/src/hover_links.rs @@ -121,22 +121,6 @@ impl Editor { cx: &mut Context, ) { 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 => {} } } } diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 2f70754c18..cae4789535 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -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::(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::(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. - } } diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index a7debbab12..db01cc7ad1 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -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, - ) -> Task> { - 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 { diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index a4e70a2f10..f2b04b9b21 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -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::( 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::( - &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::(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::>() - .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::( - &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) }) }