@@ -11,7 +11,7 @@ use helix_core::{
11use once_cell::sync::Lazy;
11use once_cell::sync::Lazy;
13use crate::compositor::Compositor;
13use crate::compositor::Compositor;
14−use crate::ui::{self, Prompt, PromptEvent};
14+use crate::ui::{self, Popup, Prompt, PromptEvent};
16use helix_view::{
16use helix_view::{
17 document::Mode,
17 document::Mode,
@@ -1000,6 +1000,63 @@ pub fn completion(cx: &mut Context) {
1003+pub fn hover(cx: &mut Context) {
1004+ use helix_lsp::lsp;
1006+ let doc = cx.doc();
1008+ let language_server = match doc.language_server.as_ref() {
1009+ Some(language_server) => language_server,
1013+ // TODO: factor out a doc.position_identifier() that returns lsp::TextDocumentPositionIdentifier
1015+ // TODO: blocking here is not ideal, make commands async fn?
1016+ // not like we can process additional input meanwhile though
1017+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
1019+ // TODO: handle fails
1020+ let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
1021+ .unwrap_or_default();
1023+ if let Some(hover) = res {
1024+ // hover.contents / .range <- used for visualizing
1025+ let contents = match hover.contents {
1026+ lsp::HoverContents::Scalar(contents) => {
1027+ // markedstring(string/languagestring to be highlighted)
1029+ unimplemented!("{:?}", contents)
1031+ lsp::HoverContents::Array(contents) => {
1032+ unimplemented!("{:?}", contents)
1034+ // TODO: render markdown
1035+ lsp::HoverContents::Markup(contents) => contents.value,
1038+ // skip if contents empty
1040+ // Popup: box frame + Box<Component> for internal content.
1041+ // it will use the contents.size_hint/required size to figure out sizing & positioning
1042+ // can also use render_buffer to render the content.
1043+ // render_buffer(highlights/scopes, text, surface, theme)
1045+ let mut popup = Popup::new(contents);
1047+ cx.callback = Some(Box::new(
1048+ move |compositor: &mut Compositor, editor: &mut Editor| {
1049+ let area = tui::layout::Rect::default(); // TODO: unused remove from cursor_position
1050+ let mut pos = compositor.cursor_position(area, editor);
1051+ pos.row += 1; // shift down by one row
1052+ popup.set_position(pos);
1054+ compositor.push(Box::new(popup));
1003// view movements
1060// view movements
1004pub fn next_view(cx: &mut Context) {
1061pub fn next_view(cx: &mut Context) {
1005 cx.editor.tree.focus_next()
1062 cx.editor.tree.focus_next()