Skip to content

Commit

Permalink
feat: consult all LSPs for goto-definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
Desdaemon committed Dec 2, 2023
1 parent 19fa20f commit f57bb80
Showing 1 changed file with 56 additions and 8 deletions.
64 changes: 56 additions & 8 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use futures_util::{
future::{join_all, BoxFuture},
stream::FuturesUnordered,
FutureExt,
FutureExt, TryFutureExt,
};
use helix_lsp::{
block_on,
Expand Down Expand Up @@ -47,6 +47,7 @@ use std::{
future::Future,
path::PathBuf,
sync::Arc,
task::Poll,
};

/// Gets the first language server that is attached to a document which supports a specific feature.
Expand Down Expand Up @@ -1064,16 +1065,63 @@ where
{
let (view, doc) = current!(cx.editor);

let language_server = language_server_with_feature!(cx.editor, doc, feature);
let offset_encoding = language_server.offset_encoding();
let pos = doc.position(view.id, offset_encoding);
let future = request_provider(language_server, pos, doc.identifier()).unwrap();
let language_servers = doc.language_servers_with_feature(feature);
let mut futures = vec![];
for server in language_servers {
let offset_encoding = server.offset_encoding();
let pos = doc.position(view.id, offset_encoding);
let fut = request_provider(server, pos, doc.identifier()).unwrap();
let fut = fut.map(move |res| {
res.map(|mut resp| {
if !resp.is_null() {
resp = serde_json::json!([offset_encoding as usize, resp]);
}
resp
})
});
futures.push(Box::pin(fut));
}

let future =
futures_util::future::poll_fn(move |ctx| {
if futures.is_empty() {
return Poll::Ready(Ok(Value::Null));
}
loop {
// .. select the next ready future
let Some((idx, res)) = futures.iter_mut().enumerate().find_map(|(idx, fut)| {
match fut.try_poll_unpin(ctx) {
Poll::Pending => None,
Poll::Ready(res) => Some((idx, res)),
}
}) else {
return Poll::Pending;
};

_ = futures.swap_remove(idx);
match res {
// .. that succeeds AND is not null
Ok(res) if !res.is_null() => return Poll::Ready(Ok(res)),
// .. or go back to polling immediately
_ => continue,
}
}
});

cx.callback(
future,
move |editor, compositor, response: Option<lsp::GotoDefinitionResponse>| {
let items = to_locations(response);
goto_impl(editor, compositor, items, offset_encoding);
move |editor, compositor, response: Option<(usize, lsp::GotoDefinitionResponse)>| {
let encoding = response
.as_ref()
.map(|(encoding, _)| match encoding {
0 => OffsetEncoding::Utf8,
1 => OffsetEncoding::Utf32,
2 => OffsetEncoding::Utf16,
_ => unreachable!(),
})
.unwrap_or_default();
let items = to_locations(response.map(|(_, resp)| resp));
goto_impl(editor, compositor, items, encoding);
},
);
}
Expand Down

0 comments on commit f57bb80

Please sign in to comment.