@@ -6,7 +6,7 @@ use helix_lsp::{
6 NumberOrString,
6 NumberOrString,
8 util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range},
8 util::{diagnostic_to_lsp_diagnostic, lsp_range_to_range, range_to_lsp_range},
9− OffsetEncoding,
9+ Client, OffsetEncoding,
11use serde_json::Value;
11use serde_json::Value;
12use tokio_stream::StreamExt;
12use tokio_stream::StreamExt;
@@ -1028,151 +1028,90 @@ fn to_locations(definitions: Option<lsp::GotoDefinitionResponse>) -> Vec<lsp::Lo
1031−// TODO find a way to reduce boilerplate of all the goto functions, without unnecessary complexity...
1031+fn goto_single_impl<P, F>(cx: &mut Context, feature: LanguageServerFeature, request_provider: P)
1032−pub fn goto_declaration(cx: &mut Context) {
1032+where
1033+ P: Fn(&Client, lsp::Position, lsp::TextDocumentIdentifier) -> Option<F>,
1034+ F: Future<Output = helix_lsp::Result<serde_json::Value>> + 'static + Send,
1033 let (view, doc) = current!(cx.editor);
1036 let (view, doc) = current!(cx.editor);
1034− let future_offset_encoding = doc
1037+ if let Some((future, offset_encoding)) =
1035− .language_servers_with_feature(LanguageServerFeature::GotoDeclaration)
1038+ doc.run_on_first_supported_language_server(view.id, feature, |ls, encoding, pos, doc_id| {
1036− .find_map(|language_server| {
1039+ Some((request_provider(ls, pos, doc_id)?, encoding))
1037− let offset_encoding = language_server.offset_encoding();
1038− let pos = doc.position(view.id, offset_encoding);
1039− let future = language_server.goto_declaration(doc.identifier(), pos, None)?;
1040− Some((future, offset_encoding))
1042− let (future, offset_encoding) = match future_offset_encoding {
1041+ {
1043− Some(future_offset_encoding) => future_offset_encoding,
1042+ cx.callback(
1044− None => {
1043+ future,
1045− cx.editor
1044+ move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
1045+ let items = to_locations(response);
1046+ goto_impl(editor, compositor, items, offset_encoding);
1046− .set_error("No language server supports goto-declaration");
1050+ cx.editor.set_error("No language server supports {feature}");
1051− cx.callback(
1054+pub fn goto_declaration(cx: &mut Context) {
1052− future,
1055+ goto_single_impl(
1053− move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
1056+ cx,
1054− let items = to_locations(response);
1057+ LanguageServerFeature::GotoDeclaration,
1055− goto_impl(editor, compositor, items, offset_encoding);
1058+ |ls, pos, doc_id| ls.goto_declaration(doc_id, pos, None),
1060pub fn goto_definition(cx: &mut Context) {
1062pub fn goto_definition(cx: &mut Context) {
1061− let (view, doc) = current!(cx.editor);
1063+ goto_single_impl(
1062− let future_offset_encoding = doc
1064+ cx,
1063− .language_servers_with_feature(LanguageServerFeature::GotoDefinition)
1065+ LanguageServerFeature::GotoDefinition,
1064− .find_map(|language_server| {
1065− let offset_encoding = language_server.offset_encoding();
1066− let pos = doc.position(view.id, offset_encoding);
1067− let future = language_server.goto_definition(doc.identifier(), pos, None)?;
1066+ |ls, pos, doc_id| ls.goto_definition(doc_id, pos, None),
1068− Some((future, offset_encoding))
1070− let (future, offset_encoding) = match future_offset_encoding {
1071− Some(future_offset_encoding) => future_offset_encoding,
1074− .set_error("No language server supports goto-definition");
1081− move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
1082− let items = to_locations(response);
1083− goto_impl(editor, compositor, items, offset_encoding);
1088pub fn goto_type_definition(cx: &mut Context) {
1070pub fn goto_type_definition(cx: &mut Context) {
1089− let (view, doc) = current!(cx.editor);
1071+ goto_single_impl(
1090− let future_offset_encoding = doc
1072+ cx,
1091− .language_servers_with_feature(LanguageServerFeature::GotoTypeDefinition)
1073+ LanguageServerFeature::GotoTypeDefinition,
1092− .find_map(|language_server| {
1093− let offset_encoding = language_server.offset_encoding();
1094− let pos = doc.position(view.id, offset_encoding);
1095− let future = language_server.goto_type_definition(doc.identifier(), pos, None)?;
1074+ |ls, pos, doc_id| ls.goto_type_definition(doc_id, pos, None),
1096− Some((future, offset_encoding))
1098− let (future, offset_encoding) = match future_offset_encoding {
1099− Some(future_offset_encoding) => future_offset_encoding,
1102− .set_error("No language server supports goto-type-definition");
1109− move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
1110− let items = to_locations(response);
1111− goto_impl(editor, compositor, items, offset_encoding);
1116pub fn goto_implementation(cx: &mut Context) {
1078pub fn goto_implementation(cx: &mut Context) {
1117− let (view, doc) = current!(cx.editor);
1079+ goto_single_impl(
1118− let future_offset_encoding = doc
1080+ cx,
1119− .language_servers_with_feature(LanguageServerFeature::GotoImplementation)
1081+ LanguageServerFeature::GotoImplementation,
1120− .find_map(|language_server| {
1121− let offset_encoding = language_server.offset_encoding();
1122− let pos = doc.position(view.id, offset_encoding);
1123− let future = language_server.goto_implementation(doc.identifier(), pos, None)?;
1082+ |ls, pos, doc_id| ls.goto_implementation(doc_id, pos, None),
1124− Some((future, offset_encoding))
1126− let (future, offset_encoding) = match future_offset_encoding {
1127− Some(future_offset_encoding) => future_offset_encoding,
1130− .set_error("No language server supports goto-implementation");
1137− move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
1138− let items = to_locations(response);
1139− goto_impl(editor, compositor, items, offset_encoding);
1144pub fn goto_reference(cx: &mut Context) {
1086pub fn goto_reference(cx: &mut Context) {
1145 let config = cx.editor.config();
1087 let config = cx.editor.config();
1146 let (view, doc) = current!(cx.editor);
1088 let (view, doc) = current!(cx.editor);
1147− let future_offset_encoding = doc
1089+ if let Some((future, offset_encoding)) = doc.run_on_first_supported_language_server(
1148− .language_servers_with_feature(LanguageServerFeature::GotoReference)
1091+ LanguageServerFeature::GotoReference,
1149− .find_map(|language_server| {
1092+ |ls, encoding, pos, doc_id| {
1150− let offset_encoding = language_server.offset_encoding();
1093+ Some((
1151− let pos = doc.position(view.id, offset_encoding);
1152− let future = language_server.goto_reference(
1094+ ls.goto_reference(
1153− doc.identifier(),
1095+ doc_id,
1155− config.lsp.goto_reference_include_declaration,
1097+ config.lsp.goto_reference_include_declaration,
1158− Some((future, offset_encoding))
1100+ encoding,
1160− let (future, offset_encoding) = match future_offset_encoding {
1161− Some(future_offset_encoding) => future_offset_encoding,
1164− .set_error("No language server supports goto-reference");
1171− move |editor, compositor, response: Option<Vec<lsp::Location>>| {
1172− let items = response.unwrap_or_default();
1173− goto_impl(editor, compositor, items, offset_encoding);
1106+ move |editor, compositor, response: Option<Vec<lsp::Location>>| {
1107+ let items = response.unwrap_or_default();
1108+ goto_impl(editor, compositor, items, offset_encoding);
1113+ .set_error("No language server supports goto-reference");
1178#[derive(PartialEq, Eq, Clone, Copy)]
1117#[derive(PartialEq, Eq, Clone, Copy)]