aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/commands
diff options
context:
space:
mode:
authorPascal Kuthe2023-11-30 23:03:27 +0000
committerBlaž Hrastnik2024-01-23 02:20:19 +0000
commit8e592a151fe7adfbf3fb35ae134b7f2a70700f09 (patch)
tree603a94042068620e52f50cb26cf881d5461d1c8d /helix-term/src/commands
parent13ed4f6c4748019787d24c2b686d417b71604242 (diff)
refactor completion and signature help using hooks
Diffstat (limited to 'helix-term/src/commands')
-rw-r--r--helix-term/src/commands/lsp.rs156
1 files changed, 8 insertions, 148 deletions
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 051cdcd3..de2f0e5e 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -1,4 +1,4 @@
-use futures_util::{future::BoxFuture, stream::FuturesUnordered, FutureExt};
+use futures_util::{stream::FuturesUnordered, FutureExt};
use helix_lsp::{
block_on,
lsp::{
@@ -8,21 +8,21 @@ use helix_lsp::{
util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range},
Client, OffsetEncoding,
};
-use serde_json::Value;
use tokio_stream::StreamExt;
use tui::{
text::{Span, Spans},
widgets::Row,
};
-use super::{align_view, push_jump, Align, Context, Editor, Open};
+use super::{align_view, push_jump, Align, Context, Editor};
use helix_core::{syntax::LanguageServerFeature, text_annotations::InlineAnnotation, Selection};
use helix_stdx::path;
use helix_view::{
- document::{DocumentInlayHints, DocumentInlayHintsId, Mode},
+ document::{DocumentInlayHints, DocumentInlayHintsId},
editor::Action,
graphics::Margin,
+ handlers::lsp::SignatureHelpInvoked,
theme::Style,
Document, View,
};
@@ -30,10 +30,7 @@ use helix_view::{
use crate::{
compositor::{self, Compositor},
job::Callback,
- ui::{
- self, lsp::SignatureHelp, overlay::overlaid, DynamicPicker, FileLocation, Picker, Popup,
- PromptEvent,
- },
+ ui::{self, overlay::overlaid, DynamicPicker, FileLocation, Picker, Popup, PromptEvent},
};
use std::{
@@ -42,7 +39,6 @@ use std::{
fmt::Write,
future::Future,
path::PathBuf,
- sync::Arc,
};
/// Gets the first language server that is attached to a document which supports a specific feature.
@@ -1132,146 +1128,10 @@ pub fn goto_reference(cx: &mut Context) {
);
}
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub enum SignatureHelpInvoked {
- Manual,
- Automatic,
-}
-
pub fn signature_help(cx: &mut Context) {
- signature_help_impl(cx, SignatureHelpInvoked::Manual)
-}
-
-pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) {
- let (view, doc) = current!(cx.editor);
-
- // TODO merge multiple language server signature help into one instead of just taking the first language server that supports it
- let future = doc
- .language_servers_with_feature(LanguageServerFeature::SignatureHelp)
- .find_map(|language_server| {
- let pos = doc.position(view.id, language_server.offset_encoding());
- language_server.text_document_signature_help(doc.identifier(), pos, None)
- });
-
- let Some(future) = future else {
- // Do not show the message if signature help was invoked
- // automatically on backspace, trigger characters, etc.
- if invoked == SignatureHelpInvoked::Manual {
- cx.editor
- .set_error("No configured language server supports signature-help");
- }
- return;
- };
- signature_help_impl_with_future(cx, future.boxed(), invoked);
-}
-
-pub fn signature_help_impl_with_future(
- cx: &mut Context,
- future: BoxFuture<'static, helix_lsp::Result<Value>>,
- invoked: SignatureHelpInvoked,
-) {
- cx.callback(
- future,
- move |editor, compositor, response: Option<lsp::SignatureHelp>| {
- let config = &editor.config();
-
- if !(config.lsp.auto_signature_help
- || SignatureHelp::visible_popup(compositor).is_some()
- || invoked == SignatureHelpInvoked::Manual)
- {
- return;
- }
-
- // If the signature help invocation is automatic, don't show it outside of Insert Mode:
- // it very probably means the server was a little slow to respond and the user has
- // already moved on to something else, making a signature help popup will just be an
- // annoyance, see https://github.com/helix-editor/helix/issues/3112
- if invoked == SignatureHelpInvoked::Automatic && editor.mode != Mode::Insert {
- return;
- }
-
- let response = match response {
- // According to the spec the response should be None if there
- // are no signatures, but some servers don't follow this.
- Some(s) if !s.signatures.is_empty() => s,
- _ => {
- compositor.remove(SignatureHelp::ID);
- return;
- }
- };
- let doc = doc!(editor);
- let language = doc.language_name().unwrap_or("");
-
- let signature = match response
- .signatures
- .get(response.active_signature.unwrap_or(0) as usize)
- {
- Some(s) => s,
- None => return,
- };
- let mut contents = SignatureHelp::new(
- signature.label.clone(),
- language.to_string(),
- Arc::clone(&editor.syn_loader),
- );
-
- let signature_doc = if config.lsp.display_signature_help_docs {
- signature.documentation.as_ref().map(|doc| match doc {
- lsp::Documentation::String(s) => s.clone(),
- lsp::Documentation::MarkupContent(markup) => markup.value.clone(),
- })
- } else {
- None
- };
-
- contents.set_signature_doc(signature_doc);
-
- let active_param_range = || -> Option<(usize, usize)> {
- let param_idx = signature
- .active_parameter
- .or(response.active_parameter)
- .unwrap_or(0) as usize;
- let param = signature.parameters.as_ref()?.get(param_idx)?;
- match &param.label {
- lsp::ParameterLabel::Simple(string) => {
- let start = signature.label.find(string.as_str())?;
- Some((start, start + string.len()))
- }
- lsp::ParameterLabel::LabelOffsets([start, end]) => {
- // LS sends offsets based on utf-16 based string representation
- // but highlighting in helix is done using byte offset.
- use helix_core::str_utils::char_to_byte_idx;
- let from = char_to_byte_idx(&signature.label, *start as usize);
- let to = char_to_byte_idx(&signature.label, *end as usize);
- Some((from, to))
- }
- }
- };
- contents.set_active_param_range(active_param_range());
-
- let old_popup = compositor.find_id::<Popup<SignatureHelp>>(SignatureHelp::ID);
- let mut popup = Popup::new(SignatureHelp::ID, contents)
- .position(old_popup.and_then(|p| p.get_position()))
- .position_bias(Open::Above)
- .ignore_escape_key(true);
-
- // Don't create a popup if it intersects the auto-complete menu.
- let size = compositor.size();
- if compositor
- .find::<ui::EditorView>()
- .unwrap()
- .completion
- .as_mut()
- .map(|completion| completion.area(size, editor))
- .filter(|area| area.intersects(popup.area(size, editor)))
- .is_some()
- {
- return;
- }
-
- compositor.replace_or_push(SignatureHelp::ID, popup);
- },
- );
+ cx.editor
+ .handlers
+ .trigger_signature_help(SignatureHelpInvoked::Manual, cx.editor)
}
pub fn hover(cx: &mut Context) {