Extract get docs and show actual hover into function

This commit is contained in:
David Kleingeld 2025-08-25 17:39:52 +02:00
parent 78ca73e0b9
commit 1a31961dac

View file

@ -444,6 +444,56 @@ pub fn update_inlay_link_and_hover_points(
let hint_value = hovered_hint_part.value.clone(); let hint_value = hovered_hint_part.value.clone();
let location = location.clone(); let location = location.clone();
get_docs_then_show_hover(
window, cx, highlight, hint_value, location,
project,
);
}
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 => {}
};
}
}
}
if !go_to_definition_updated {
editor.hide_hovered_link(cx)
}
if !hover_updated {
hover_popover::hover_at(editor, None, window, cx);
}
}
fn get_docs_then_show_hover(
window: &mut Window,
cx: &mut Context<'_, Editor>,
highlight: InlayHighlight,
hint_value: String,
location: lsp::Location,
project: Entity<Project>,
) {
cx.spawn_in(window, async move |editor, cx| { cx.spawn_in(window, async move |editor, cx| {
async move { async move {
// Small delay to show the loading message first // Small delay to show the loading message first
@ -452,55 +502,41 @@ pub fn update_inlay_link_and_hover_points(
.await; .await;
// Convert LSP URL to file path // Convert LSP URL to file path
let file_path = let file_path = location
location.uri.to_file_path().map_err( .uri
|_| anyhow::anyhow!("Invalid file URL"), .to_file_path()
)?; .map_err(|_| anyhow::anyhow!("Invalid file URL"))?;
// Open the definition file // Open the definition file
let definition_buffer = project let definition_buffer = project
.update(cx, |project, cx| { .update(cx, |project, cx| project.open_local_buffer(file_path, cx))?
project.open_local_buffer(file_path, cx)
})?
.await?; .await?;
// Extract documentation directly from the source // Extract documentation directly from the source
let documentation = definition_buffer.update( let documentation = definition_buffer.update(cx, |buffer, _| {
cx, let line_number = location.range.start.line as usize;
|buffer, _| {
let line_number =
location.range.start.line as usize;
// Get the text of the buffer // Get the text of the buffer
let text = buffer.text(); let text = buffer.text();
let lines: Vec<&str> = let lines: Vec<&str> = text.lines().collect();
text.lines().collect();
// Look backwards from the definition line to find doc comments // Look backwards from the definition line to find doc comments
let mut doc_lines = Vec::new(); let mut doc_lines = Vec::new();
let mut current_line = let mut current_line = line_number.saturating_sub(1);
line_number.saturating_sub(1);
// Skip any attributes like #[derive(...)] // Skip any attributes like #[derive(...)]
while current_line > 0 while current_line > 0
&& lines.get(current_line).map_or( && lines.get(current_line).map_or(false, |line| {
false,
|line| {
let trimmed = line.trim(); let trimmed = line.trim();
trimmed.starts_with("#[") trimmed.starts_with("#[") || trimmed.is_empty()
|| trimmed.is_empty() })
},
)
{ {
current_line = current_line = current_line.saturating_sub(1);
current_line.saturating_sub(1);
} }
// Collect doc comments // Collect doc comments
while current_line > 0 { while current_line > 0 {
if let Some(line) = if let Some(line) = lines.get(current_line) {
lines.get(current_line)
{
let trimmed = line.trim(); let trimmed = line.trim();
if trimmed.starts_with("///") { if trimmed.starts_with("///") {
// Remove the /// and any leading space // Remove the /// and any leading space
@ -508,23 +544,14 @@ pub fn update_inlay_link_and_hover_points(
.strip_prefix("///") .strip_prefix("///")
.unwrap_or("") .unwrap_or("")
.strip_prefix(" ") .strip_prefix(" ")
.unwrap_or_else(|| { .unwrap_or_else(|| trimmed.strip_prefix("///").unwrap_or(""));
trimmed doc_lines.push(doc_text.to_string());
.strip_prefix(
"///",
)
.unwrap_or("")
});
doc_lines.push(
doc_text.to_string(),
);
} else if !trimmed.is_empty() { } else if !trimmed.is_empty() {
// Stop at the first non-doc, non-empty line // Stop at the first non-doc, non-empty line
break; break;
} }
} }
current_line = current_line = current_line.saturating_sub(1);
current_line.saturating_sub(1);
} }
// Reverse to get correct order // Reverse to get correct order
@ -534,9 +561,7 @@ pub fn update_inlay_link_and_hover_points(
let definition = lines let definition = lines
.get(line_number) .get(line_number)
.map(|s| s.trim().to_string()) .map(|s| s.trim().to_string())
.unwrap_or_else(|| { .unwrap_or_else(|| hint_value.clone());
hint_value.clone()
});
if doc_lines.is_empty() { if doc_lines.is_empty() {
None None
@ -544,16 +569,11 @@ pub fn update_inlay_link_and_hover_points(
let docs = doc_lines.join("\n"); let docs = doc_lines.join("\n");
Some((definition, docs)) Some((definition, docs))
} }
}, })?;
)?;
if let Some((definition, docs)) = documentation if let Some((definition, docs)) = documentation {
{
// Format as markdown with the definition as a code block // Format as markdown with the definition as a code block
let formatted_docs = format!( let formatted_docs = format!("```rust\n{}\n```\n\n{}", definition, docs);
"```rust\n{}\n```\n\n{}",
definition, docs
);
editor editor
.update_in(cx, |editor, window, cx| { .update_in(cx, |editor, window, cx| {
@ -605,42 +625,6 @@ pub fn update_inlay_link_and_hover_points(
.detach(); .detach();
} }
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 => {}
};
}
}
}
if !go_to_definition_updated {
editor.hide_hovered_link(cx)
}
if !hover_updated {
hover_popover::hover_at(editor, None, window, cx);
}
}
pub fn show_link_definition( pub fn show_link_definition(
shift_held: bool, shift_held: bool,
editor: &mut Editor, editor: &mut Editor,