pull/12208/merge
Nik Revenco 2025-06-16 10:51:21 -05:00 committed by GitHub
commit 7ab7bfcf9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 72 additions and 19 deletions

View File

@ -208,6 +208,7 @@
| `remove_primary_selection` | Remove primary selection | normal: `` <A-,> ``, select: `` <A-,> `` |
| `completion` | Invoke completion popup | insert: `` <C-x> `` |
| `hover` | Show docs for item under cursor | normal: `` <space>k ``, select: `` <space>k `` |
| `hover_dump` | Show docs for item under cursor in a new buffer | normal: `` <space>K ``, select: `` <space>K `` |
| `toggle_comments` | Comment/uncomment selections | normal: `` <C-c> ``, `` <space>c ``, select: `` <C-c> ``, `` <space>c `` |
| `toggle_line_comments` | Line comment/uncomment selections | normal: `` <space><A-c> ``, select: `` <space><A-c> `` |
| `toggle_block_comments` | Block comment/uncomment selections | normal: `` <space>C ``, select: `` <space>C `` |

View File

@ -291,6 +291,7 @@ This layer is a kludge of mappings, mostly pickers.
| `g` | Open changed file picker | `changed_file_picker` |
| `G` | Debug (experimental) | N/A |
| `k` | Show documentation for item under cursor in a [popup](#popup) (**LSP**) | `hover` |
| `K` | Go to documentation for item under cursor in a new buffer (**LSP**) | `goto_hover` |
| `s` | Open document symbol picker (**LSP**) | `symbol_picker` |
| `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` |
| `d` | Open document diagnostics picker (**LSP**) | `diagnostics_picker` |

View File

@ -506,6 +506,7 @@ impl MappableCommand {
remove_primary_selection, "Remove primary selection",
completion, "Invoke completion popup",
hover, "Show docs for item under cursor",
goto_hover, "Show docs for item under cursor in a new buffer",
toggle_comments, "Comment/uncomment selections",
toggle_line_comments, "Line comment/uncomment selections",
toggle_block_comments, "Block comment/uncomment selections",

View File

@ -15,7 +15,7 @@ use super::{align_view, push_jump, Align, Context, Editor};
use helix_core::{
diagnostic::DiagnosticProvider, syntax::config::LanguageServerFeature,
text_annotations::InlineAnnotation, Selection, Uri,
text_annotations::InlineAnnotation, Rope, Selection, Uri,
};
use helix_stdx::path;
use helix_view::{
@ -32,7 +32,9 @@ use crate::{
ui::{self, overlay::overlaid, FileLocation, Picker, Popup, PromptEvent},
};
use std::{cmp::Ordering, collections::HashSet, fmt::Display, future::Future, path::Path};
use std::{
cmp::Ordering, collections::HashSet, fmt::Display, future::Future, path::Path, sync::Arc,
};
/// Gets the first language server that is attached to a document which supports a specific feature.
/// If there is no configured language server that supports the feature, this displays a status message.
@ -1015,7 +1017,12 @@ pub fn signature_help(cx: &mut Context) {
.trigger_signature_help(SignatureHelpInvoked::Manual, cx.editor)
}
pub fn hover(cx: &mut Context) {
enum HoverDisplay {
Popup,
File,
}
fn hover_impl(cx: &mut Context, hover_action: HoverDisplay) {
use ui::lsp::hover::Hover;
let (view, doc) = current!(cx.editor);
@ -1062,15 +1069,42 @@ pub fn hover(cx: &mut Context) {
return;
}
// create new popup
let contents = Hover::new(hovers, editor.syn_loader.clone());
let popup = Popup::new(Hover::ID, contents).auto_close(true);
compositor.replace_or_push(Hover::ID, popup);
let hover = Hover::new(hovers, editor.syn_loader.clone());
match hover_action {
HoverDisplay::Popup => {
let popup = Popup::new(Hover::ID, hover).auto_close(true);
compositor.replace_or_push(Hover::ID, popup);
}
HoverDisplay::File => {
editor.new_file_from_document(
Action::Replace,
Document::from(
Rope::from(hover.content_string()),
None,
Arc::clone(&editor.config),
Arc::clone(&editor.syn_loader),
),
);
let hover_doc = doc_mut!(editor);
let _ = hover_doc
.set_language_by_language_id("markdown", &editor.syn_loader.load());
}
}
};
Ok(Callback::EditorCompositor(Box::new(call)))
});
}
pub fn hover(cx: &mut Context) {
hover_impl(cx, HoverDisplay::Popup)
}
pub fn goto_hover(cx: &mut Context) {
hover_impl(cx, HoverDisplay::File)
}
pub fn rename_symbol(cx: &mut Context) {
fn get_prefill_from_word_boundary(editor: &Editor) -> String {
let (view, doc) = current_ref!(editor);

View File

@ -284,6 +284,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
"R" => replace_selections_with_clipboard,
"/" => global_search,
"k" => hover,
"K" => goto_hover,
"r" => rename_symbol,
"h" => select_references_to_symbol_under_cursor,
"c" => toggle_comments,

View File

@ -30,16 +30,15 @@ impl Hover {
.into_iter()
.enumerate()
.map(|(idx, (server_name, hover))| {
let header = (n_hovers > 1).then(|| {
Markdown::new(
format!("**[{}/{}] {}**", idx + 1, n_hovers, server_name),
config_loader.clone(),
)
});
let header = (n_hovers > 1)
.then(|| format!("**[{}/{}] {}**\n", idx + 1, n_hovers, server_name))
.map(|h| Markdown::new(h, Arc::clone(&config_loader)));
let body = Markdown::new(
hover_contents_to_string(hover.contents),
config_loader.clone(),
Arc::clone(&config_loader),
);
(header, body)
})
.collect();
@ -54,10 +53,26 @@ impl Hover {
self.contents.len() > 1
}
fn content(&self) -> &(Option<Markdown>, Markdown) {
fn content_markdown(&self) -> &(Option<Markdown>, Markdown) {
&self.contents[self.active_index]
}
pub fn content_string(&self) -> String {
self.contents
.iter()
.map(|(header, body)| {
let header: String = header
.iter()
.map(|header| header.contents.clone())
.collect();
format!("{}{}", header, body.contents)
})
.collect::<Vec<String>>()
.join("\n\n---\n\n")
+ "\n"
}
fn set_index(&mut self, index: usize) {
assert!((0..self.contents.len()).contains(&index));
self.active_index = index;
@ -75,7 +90,7 @@ impl Component for Hover {
let margin = Margin::all(1);
let area = area.inner(margin);
let (header, contents) = self.content();
let (header, contents) = self.content_markdown();
// show header and border only when more than one results
if let Some(header) = header {
@ -110,7 +125,7 @@ impl Component for Hover {
fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
let max_text_width = viewport.0.saturating_sub(PADDING_HORIZONTAL).clamp(10, 120);
let (header, contents) = self.content();
let (header, contents) = self.content_markdown();
let header_width = header
.as_ref()

View File

@ -132,7 +132,7 @@ pub fn highlighted_code_block<'a>(
}
pub struct Markdown {
contents: String,
pub contents: String,
config_loader: Arc<ArcSwap<syntax::Loader>>,
}

View File

@ -1744,7 +1744,7 @@ impl Editor {
id
}
fn new_file_from_document(&mut self, action: Action, doc: Document) -> DocumentId {
pub fn new_file_from_document(&mut self, action: Action, doc: Document) -> DocumentId {
let id = self.new_document(doc);
self.switch(id, action);
id