From 60a6af1fea64381e66ec935d61ff9250491823a5 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Sat, 18 Mar 2023 23:13:58 +0100 Subject: [PATCH] Remove boilerplate in the goto methods by generically composing functions --- helix-term/src/commands/lsp.rs | 189 +++++++++++---------------------- helix-view/src/document.rs | 19 +++- 2 files changed, 82 insertions(+), 126 deletions(-) diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 6553ce167..9eaead951 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -6,7 +6,7 @@ use helix_lsp::{ NumberOrString, }, util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range}, - OffsetEncoding, + Client, OffsetEncoding, }; use serde_json::Value; use tokio_stream::StreamExt; @@ -1028,151 +1028,90 @@ fn to_locations(definitions: Option) -> Vec(cx: &mut Context, feature: LanguageServerFeature, request_provider: P) +where + P: Fn(&Client, lsp::Position, lsp::TextDocumentIdentifier) -> Option, + F: Future> + 'static + Send, +{ let (view, doc) = current!(cx.editor); - let future_offset_encoding = doc - .language_servers_with_feature(LanguageServerFeature::GotoDeclaration) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_declaration(doc.identifier(), pos, None)?; - Some((future, offset_encoding)) - }); - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No language server supports goto-declaration"); - return; - } - }; + if let Some((future, offset_encoding)) = + doc.run_on_first_supported_language_server(view.id, feature, |ls, encoding, pos, doc_id| { + Some((request_provider(ls, pos, doc_id)?, encoding)) + }) + { + cx.callback( + future, + move |editor, compositor, response: Option| { + let items = to_locations(response); + goto_impl(editor, compositor, items, offset_encoding); + }, + ); + } else { + cx.editor.set_error("No language server supports {feature}"); + } +} - cx.callback( - future, - move |editor, compositor, response: Option| { - let items = to_locations(response); - goto_impl(editor, compositor, items, offset_encoding); - }, +pub fn goto_declaration(cx: &mut Context) { + goto_single_impl( + cx, + LanguageServerFeature::GotoDeclaration, + |ls, pos, doc_id| ls.goto_declaration(doc_id, pos, None), ); } pub fn goto_definition(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - let future_offset_encoding = doc - .language_servers_with_feature(LanguageServerFeature::GotoDefinition) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_definition(doc.identifier(), pos, None)?; - Some((future, offset_encoding)) - }); - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No language server supports goto-definition"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option| { - let items = to_locations(response); - goto_impl(editor, compositor, items, offset_encoding); - }, + goto_single_impl( + cx, + LanguageServerFeature::GotoDefinition, + |ls, pos, doc_id| ls.goto_definition(doc_id, pos, None), ); } pub fn goto_type_definition(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - let future_offset_encoding = doc - .language_servers_with_feature(LanguageServerFeature::GotoTypeDefinition) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_type_definition(doc.identifier(), pos, None)?; - Some((future, offset_encoding)) - }); - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No language server supports goto-type-definition"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option| { - let items = to_locations(response); - goto_impl(editor, compositor, items, offset_encoding); - }, + goto_single_impl( + cx, + LanguageServerFeature::GotoTypeDefinition, + |ls, pos, doc_id| ls.goto_type_definition(doc_id, pos, None), ); } pub fn goto_implementation(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - let future_offset_encoding = doc - .language_servers_with_feature(LanguageServerFeature::GotoImplementation) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_implementation(doc.identifier(), pos, None)?; - Some((future, offset_encoding)) - }); - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No language server supports goto-implementation"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option| { - let items = to_locations(response); - goto_impl(editor, compositor, items, offset_encoding); - }, + goto_single_impl( + cx, + LanguageServerFeature::GotoImplementation, + |ls, pos, doc_id| ls.goto_implementation(doc_id, pos, None), ); } pub fn goto_reference(cx: &mut Context) { let config = cx.editor.config(); let (view, doc) = current!(cx.editor); - let future_offset_encoding = doc - .language_servers_with_feature(LanguageServerFeature::GotoReference) - .find_map(|language_server| { - let offset_encoding = language_server.offset_encoding(); - let pos = doc.position(view.id, offset_encoding); - let future = language_server.goto_reference( - doc.identifier(), - pos, - config.lsp.goto_reference_include_declaration, - None, - )?; - Some((future, offset_encoding)) - }); - let (future, offset_encoding) = match future_offset_encoding { - Some(future_offset_encoding) => future_offset_encoding, - None => { - cx.editor - .set_error("No language server supports goto-reference"); - return; - } - }; - - cx.callback( - future, - move |editor, compositor, response: Option>| { - let items = response.unwrap_or_default(); - goto_impl(editor, compositor, items, offset_encoding); + if let Some((future, offset_encoding)) = doc.run_on_first_supported_language_server( + view.id, + LanguageServerFeature::GotoReference, + |ls, encoding, pos, doc_id| { + Some(( + ls.goto_reference( + doc_id, + pos, + config.lsp.goto_reference_include_declaration, + None, + )?, + encoding, + )) }, - ); + ) { + cx.callback( + future, + move |editor, compositor, response: Option>| { + let items = response.unwrap_or_default(); + goto_impl(editor, compositor, items, offset_encoding); + }, + ); + } else { + cx.editor + .set_error("No language server supports goto-reference"); + } } #[derive(PartialEq, Eq, Clone, Copy)] diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 0f8002093..3fd271eb9 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -580,7 +580,7 @@ where *mut_ref = f(mem::take(mut_ref)); } -use helix_lsp::lsp; +use helix_lsp::{lsp, Client, OffsetEncoding}; use url::Url; impl Document { @@ -1460,6 +1460,23 @@ impl Document { self.language_servers().any(|l| l.id() == id) } + pub fn run_on_first_supported_language_server( + &self, + view_id: ViewId, + feature: LanguageServerFeature, + request_provider: P, + ) -> Option + where + P: Fn(&Client, OffsetEncoding, lsp::Position, lsp::TextDocumentIdentifier) -> Option, + { + self.language_servers_with_feature(feature) + .find_map(|language_server| { + let offset_encoding = language_server.offset_encoding(); + let pos = self.position(view_id, offset_encoding); + request_provider(language_server, offset_encoding, pos, self.identifier()) + }) + } + pub fn diff_handle(&self) -> Option<&DiffHandle> { self.diff_handle.as_ref() }