use lsp_types::{Hover, HoverContents, MarkedString};
use crate::App;
pub trait HoverProvider {
fn hover(
&self,
text: &ropey::Rope,
offset: usize,
window: &mut crate::Window,
cx: &mut App,
) -> crate::Task<anyhow::Result<Option<HoverResponse>>>;
}
#[derive(Debug, Clone)]
pub struct HoverResponse {
pub range: std::ops::Range<usize>,
pub contents: Vec<HoverContent>,
}
#[derive(Debug, Clone)]
pub enum HoverContent {
Text(String),
Markdown(String),
CodeBlock {
language: String,
code: String,
},
}
impl HoverResponse {
pub fn from_lsp(hover: Hover, offset: usize) -> Self {
let range = hover
.range
.map(|r| {
let start = r.start.line as usize * 100 + r.start.character as usize;
let end = r.end.line as usize * 100 + r.end.character as usize;
start..end
})
.unwrap_or(offset..offset);
let contents = match hover.contents {
HoverContents::Scalar(MarkedString::String(s)) => {
vec![HoverContent::Markdown(s)]
}
HoverContents::Scalar(MarkedString::LanguageString(block)) => {
vec![HoverContent::CodeBlock {
language: block.language,
code: block.value,
}]
}
HoverContents::Array(items) => items
.into_iter()
.map(|item| match item {
MarkedString::String(s) => HoverContent::Markdown(s),
MarkedString::LanguageString(block) => HoverContent::CodeBlock {
language: block.language,
code: block.value,
},
})
.collect(),
HoverContents::Markup(content) => {
vec![HoverContent::Markdown(content.value)]
}
};
Self { range, contents }
}
}
#[derive(Default)]
pub struct HoverState {
pub response: Option<HoverResponse>,
pub offset: Option<usize>,
pub visible: bool,
}
impl HoverState {
pub fn clear(&mut self) {
self.response = None;
self.offset = None;
self.visible = false;
}
}