Skip to content

Commit

Permalink
multiple lsp groundwork for hover component
Browse files Browse the repository at this point in the history
  • Loading branch information
kyfanc committed Apr 3, 2024
1 parent fca4fde commit 31f872c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 39 deletions.
9 changes: 4 additions & 5 deletions helix-term/src/handlers/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ pub fn request_hover(editor: &mut Editor, cancel: CancelRx) {
match cancelable_future(future, cancel).await {
Some(Ok(response)) => {
job::dispatch(move |editor, compositor| {
if let Some((lsp_name, hover)) = response.first() {
show_hover(editor, compositor, lsp_name.clone(), hover.clone())
if !response.is_empty() {
show_hover(editor, compositor, response)
}
})
.await
Expand All @@ -147,15 +147,14 @@ pub fn request_hover(editor: &mut Editor, cancel: CancelRx) {
pub fn show_hover(
editor: &mut Editor,
compositor: &mut Compositor,
lsp_name: String,
hover: lsp::Hover,
hovers: Vec<(String, lsp::Hover)>,
) {
send_blocking(
&editor.handlers.hovers,
HoverEvent::RequestComplete { open: true },
);

let contents = ui::lsp::hover::Hover::new(hover, lsp_name, editor.syn_loader.clone());
let contents = ui::lsp::hover::Hover::new(hovers, editor.syn_loader.clone());
let popup = Popup::new(ui::lsp::hover::Hover::ID, contents).auto_close(true);
compositor.replace_or_push(ui::lsp::hover::Hover::ID, popup);
}
Expand Down
110 changes: 76 additions & 34 deletions helix-term/src/ui/lsp/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,76 @@ use crate::ui::Markdown;
use crate::ui::Popup;

pub struct Hover {
lsp_name: String,
hover: lsp::Hover,

/// Part of hover text
active_param_range: Option<(usize, usize)>,

hovers: Vec<(String, lsp::Hover)>,
active_index: usize,
config_loader: Arc<ArcSwap<syntax::Loader>>,

header: Option<Markdown>,
contents: Option<Markdown>,
}

impl Hover {
pub const ID: &'static str = "hover";

pub fn new(
hover: lsp::Hover,
lsp_name: String,
hovers: Vec<(String, lsp::Hover)>,
config_loader: Arc<ArcSwap<syntax::Loader>>,
) -> Self {
Self {
hover,
lsp_name,
active_param_range: None,
let mut hover = Self {
hovers,
active_index: usize::default(),
config_loader,
}
header: None,
contents: None,
};
hover.set_index(hover.active_index);
hover
}

pub fn set_hover(&mut self, hover: lsp::Hover, lsp_name: String) {
self.hover = hover;
self.lsp_name = lsp_name;
fn prepare_markdowns(&mut self) {
let Some((lsp_name, hover)) = self.hovers.get(self.active_index) else {
log::info!("prepare_markdowns: failed \nindex:{}\ncount:{}", self.active_index, self.hovers.len());
return
};
self.header = Some(Markdown::new(
format!(
"**[{}/{}] {}**",
self.active_index + 1,
self.hovers.len(),
lsp_name
),
self.config_loader.clone(),
));
let contents = hover_contents_to_string(&hover.contents);
self.contents = Some(Markdown::new(contents, self.config_loader.clone()));
}

pub fn set_active_param_range(&mut self, offset: Option<(usize, usize)>) {
self.active_param_range = offset;
pub fn set_hover(&mut self, hovers: Vec<(String, lsp::Hover)>) {
self.hovers = hovers;
self.set_index(usize::default());
}

fn set_index(&mut self, index: usize) {
self.active_index = index;
self.prepare_markdowns();
}

pub fn next_hover(&mut self) {
let index = if self.active_index < self.hovers.len() - 1 {
self.active_index + 1
} else {
usize::default()
};
self.set_index(index);
}

pub fn previous_hover(&mut self) {
let index = if self.active_index > 1 {
self.active_index - 1
} else {
self.hovers.len() - 1
};
self.set_index(index);
}

pub fn visible_popup(compositor: &mut Compositor) -> Option<&mut Popup<Self>> {
Expand All @@ -62,8 +100,12 @@ impl Component for Hover {
let margin = Margin::horizontal(1);
let area = area.inner(&margin);

let (Some(header), Some(contents)) = (self.header.as_ref(), self.contents.as_ref()) else {
log::info!("markdown not ready");
return;
};

// header LSP Name
let header = Markdown::new(self.lsp_name.clone(), self.config_loader.clone());
let header = header.parse(Some(&cx.editor.theme));
let header = Paragraph::new(&header);
header.render(area.with_height(HEADER_HEIGHT), surface);
Expand All @@ -78,16 +120,14 @@ impl Component for Hover {
}

// hover content
let contents = hover_contents_to_string(self.hover.contents.clone());
let hover = Markdown::new(contents, self.config_loader.clone());
let hover = hover.parse(Some(&cx.editor.theme));
let hover_area = area
let contents = contents.parse(Some(&cx.editor.theme));
let contents_area = area
.clip_top(2)
.clip_bottom(u16::from(cx.editor.popup_border()));
let hover_para = Paragraph::new(&hover)
let contents_para = Paragraph::new(&contents)
.wrap(Wrap { trim: false })
.scroll((cx.scroll.unwrap_or_default() as u16, 0));
hover_para.render(hover_area, surface);
contents_para.render(contents_area, surface);
}

fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
Expand All @@ -96,13 +136,15 @@ impl Component for Hover {
}
let max_text_width = (viewport.0 - PADDING).min(120);

let header = Markdown::new(format!("**{}**", self.lsp_name), self.config_loader.clone());
let (Some(header), Some(contents)) = (self.header.as_ref(), self.contents.as_ref()) else {
log::info!("markdown not ready");
return None;
};

let header = header.parse(None);
let (header_width, _header_height) =
crate::ui::text::required_size(&header, max_text_width);

let contents = hover_contents_to_string(self.hover.contents.clone());
let contents = Markdown::new(contents, Arc::clone(&self.config_loader));
let contents = contents.parse(None);
let (content_width, content_height) =
crate::ui::text::required_size(&contents, max_text_width);
Expand All @@ -116,13 +158,13 @@ impl Component for Hover {
}
}

fn hover_contents_to_string(contents: lsp::HoverContents) -> String {
fn marked_string_to_markdown(contents: lsp::MarkedString) -> String {
fn hover_contents_to_string(contents: &lsp::HoverContents) -> String {
fn marked_string_to_markdown(contents: &lsp::MarkedString) -> String {
match contents {
lsp::MarkedString::String(contents) => contents,
lsp::MarkedString::String(contents) => contents.clone(),
lsp::MarkedString::LanguageString(string) => {
if string.language == "markdown" {
string.value
string.value.clone()
} else {
format!("```{}\n{}\n```", string.language, string.value)
}
Expand All @@ -132,10 +174,10 @@ fn hover_contents_to_string(contents: lsp::HoverContents) -> String {
match contents {
lsp::HoverContents::Scalar(contents) => marked_string_to_markdown(contents),
lsp::HoverContents::Array(contents) => contents
.into_iter()
.iter()
.map(marked_string_to_markdown)
.collect::<Vec<_>>()
.join("\n\n"),
lsp::HoverContents::Markup(contents) => contents.value,
lsp::HoverContents::Markup(contents) => contents.value.clone(),
}
}

0 comments on commit 31f872c

Please sign in to comment.