diff options
author | Philipp Mildenberger | 2023-03-20 16:44:04 +0000 |
---|---|---|
committer | Philipp Mildenberger | 2023-05-18 19:58:17 +0000 |
commit | ff262084271492bba239dbc2e5788be3c4d5a4e5 (patch) | |
tree | 0c668cc05e1757377fa3cd418921c9ee575da350 /helix-term/src/commands.rs | |
parent | 9d089c27c77cb2797a0495b46477dfe348d09a91 (diff) |
Filter language servers also by capabilities in `doc.language_servers_with_feature`
* Add `helix_lsp::client::Client::supports_feature(&self, LanguageServerFeature)`
* Extend `doc.language_servers_with_feature` to use this method as filter as well
* Add macro `language_server_with_feature!` to reduce boilerplate for non-mergeable language server requests (like goto-definition)
* Refactored most of the `find_map` code to use the either the macro or filter directly via `doc.language_servers_with_feature`
Diffstat (limited to 'helix-term/src/commands.rs')
-rw-r--r-- | helix-term/src/commands.rs | 145 |
1 files changed, 68 insertions, 77 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d602eaa2..749b0ecf 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3236,10 +3236,8 @@ pub mod insert { let trigger_completion = doc .language_servers_with_feature(LanguageServerFeature::Completion) .any(|ls| { - let capabilities = ls.capabilities(); - // TODO: what if trigger is multiple chars long - matches!(&capabilities.completion_provider, Some(lsp::CompletionOptions { + matches!(&ls.capabilities().completion_provider, Some(lsp::CompletionOptions { trigger_characters: Some(triggers), .. }) if triggers.iter().any(|trigger| trigger.contains(ch))) @@ -3252,51 +3250,39 @@ pub mod insert { } fn signature_help(cx: &mut Context, ch: char) { - use futures_util::FutureExt; use helix_lsp::lsp; // if ch matches signature_help char, trigger - let (view, doc) = current!(cx.editor); - // lsp doesn't tell us when to close the signature help, so we request - // the help information again after common close triggers which should - // return None, which in turn closes the popup. - let close_triggers = &[')', ';', '.']; - // TODO support multiple language servers (not just the first that is found) - let future = doc + let doc = doc_mut!(cx.editor); + // TODO support multiple language servers (not just the first that is found), likely by merging UI somehow + let Some(language_server) = doc .language_servers_with_feature(LanguageServerFeature::SignatureHelp) - .find_map(|ls| { - let capabilities = ls.capabilities(); - - match capabilities { - lsp::ServerCapabilities { - signature_help_provider: - Some(lsp::SignatureHelpOptions { - trigger_characters: Some(triggers), - // TODO: retrigger_characters - .. - }), - .. - } if triggers.iter().any(|trigger| trigger.contains(ch)) - || close_triggers.contains(&ch) => - { - let pos = doc.position(view.id, ls.offset_encoding()); - ls.text_document_signature_help(doc.identifier(), pos, None) - } - _ if close_triggers.contains(&ch) => ls.text_document_signature_help( - doc.identifier(), - doc.position(view.id, ls.offset_encoding()), - None, - ), - // TODO: what if trigger is multiple chars long - _ => None, - } - }); + .next() + else { + return; + }; - if let Some(future) = future { - super::signature_help_impl_with_future( - cx, - future.boxed(), - SignatureHelpInvoked::Automatic, - ) + let capabilities = language_server.capabilities(); + + if let lsp::ServerCapabilities { + signature_help_provider: + Some(lsp::SignatureHelpOptions { + trigger_characters: Some(triggers), + // TODO: retrigger_characters + .. + }), + .. + } = capabilities + { + // TODO: what if trigger is multiple chars long + let is_trigger = triggers.iter().any(|trigger| trigger.contains(ch)); + // lsp doesn't tell us when to close the signature help, so we request + // the help information again after common close triggers which should + // return None, which in turn closes the popup. + let close_triggers = &[')', ';', '.']; + + if is_trigger || close_triggers.contains(&ch) { + super::signature_help_impl(cx, SignatureHelpInvoked::Automatic); + } } } @@ -3310,7 +3296,7 @@ pub mod insert { Some(transaction) } - use helix_core::{auto_pairs, syntax::LanguageServerFeature}; + use helix_core::auto_pairs; pub fn insert_char(cx: &mut Context, c: char) { let (view, doc) = current_ref!(cx.editor); @@ -4065,38 +4051,43 @@ fn format_selections(cx: &mut Context) { .set_error("format_selections only supports a single selection for now"); return; } - let future_offset_encoding = doc + + // TODO extra LanguageServerFeature::FormatSelections? + // maybe such that LanguageServerFeature::Format contains it as well + let Some(language_server) = doc .language_servers_with_feature(LanguageServerFeature::Format) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let ranges: Vec<lsp::Range> = doc - .selection(view_id) - .iter() - .map(|range| range_to_lsp_range(doc.text(), *range, offset_encoding)) - .collect(); + .find(|ls| { + matches!( + ls.capabilities().document_range_formatting_provider, + Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) + ) + }) + else { + cx.editor + .set_error("No configured language server does not support range formatting"); + return; + }; - // TODO: handle fails - // TODO: concurrent map over all ranges + let offset_encoding = language_server.offset_encoding(); + let ranges: Vec<lsp::Range> = doc + .selection(view_id) + .iter() + .map(|range| range_to_lsp_range(doc.text(), *range, offset_encoding)) + .collect(); - let range = ranges[0]; + // TODO: handle fails + // TODO: concurrent map over all ranges - let future = language_server.text_document_range_formatting( - doc.identifier(), - range, - lsp::FormattingOptions::default(), - None, - )?; - Some((future, offset_encoding)) - }); + let range = ranges[0]; - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No configured language server supports range formatting"); - return; - } - }; + let future = language_server + .text_document_range_formatting( + doc.identifier(), + range, + lsp::FormattingOptions::default(), + None, + ) + .unwrap(); let edits = tokio::task::block_in_place(|| helix_lsp::block_on(future)).unwrap_or_default(); @@ -4247,15 +4238,15 @@ pub fn completion(cx: &mut Context) { let mut futures: FuturesUnordered<_> = doc .language_servers_with_feature(LanguageServerFeature::Completion) - // TODO this should probably already been filtered in something like "language_servers_with_feature" .filter(|ls| seen_language_servers.insert(ls.id())) - .filter_map(|language_server| { + .map(|language_server| { let language_server_id = language_server.id(); let offset_encoding = language_server.offset_encoding(); let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding); - let completion_request = language_server.completion(doc.identifier(), pos, None)?; + let doc_id = doc.identifier(); + let completion_request = language_server.completion(doc_id, pos, None).unwrap(); - Some(async move { + async move { let json = completion_request.await?; let response: Option<lsp::CompletionResponse> = serde_json::from_value(json)?; @@ -4277,7 +4268,7 @@ pub fn completion(cx: &mut Context) { .collect(); anyhow::Ok(items) - }) + } }) .collect(); |