use crate::error::Result;
use crate::lsp::LanguageServerManager;
use crate::tools::{ensure_document_open, make_position};
use lsp_types::{Hover, HoverContents, MarkedString, MarkupContent};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct HoverResult {
pub contents: String,
pub range: Option<RangeInfo>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RangeInfo {
pub start_line: u32,
pub start_character: u32,
pub end_line: u32,
pub end_character: u32,
}
pub fn hover(
manager: &LanguageServerManager,
file_path: &str,
line: u32,
character: u32,
) -> Result<Option<HoverResult>> {
let path = PathBuf::from(file_path);
let (client, uri) = ensure_document_open(manager, &path)?;
let position = make_position(line, character);
let hover = client.hover(&uri, position)?;
Ok(hover.map(|h| convert_hover(h)))
}
fn convert_hover(hover: Hover) -> HoverResult {
let contents = extract_hover_contents(&hover.contents);
let range = hover.range.map(|r| RangeInfo {
start_line: r.start.line,
start_character: r.start.character,
end_line: r.end.line,
end_character: r.end.character,
});
HoverResult { contents, range }
}
fn extract_hover_contents(contents: &HoverContents) -> String {
match contents {
HoverContents::Scalar(marked) => extract_marked_string(marked),
HoverContents::Array(arr) => arr
.iter()
.map(extract_marked_string)
.collect::<Vec<_>>()
.join("\n\n"),
HoverContents::Markup(markup) => extract_markup_content(markup),
}
}
fn extract_marked_string(marked: &MarkedString) -> String {
match marked {
MarkedString::String(s) => s.clone(),
MarkedString::LanguageString(ls) => {
format!("```{}\n{}\n```", ls.language, ls.value)
}
}
}
fn extract_markup_content(markup: &MarkupContent) -> String {
markup.value.clone()
}