Skip to content

Commit

Permalink
implement incomplete completion requests
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalkuthe committed Dec 8, 2024
1 parent fc9968b commit 06539ac
Show file tree
Hide file tree
Showing 14 changed files with 835 additions and 494 deletions.
14 changes: 14 additions & 0 deletions helix-core/src/completion.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::borrow::Cow;

use crate::diagnostic::LanguageServerId;
use crate::Transaction;

#[derive(Debug, PartialEq, Clone)]
Expand All @@ -9,4 +10,17 @@ pub struct CompletionItem {
pub kind: Cow<'static, str>,
/// Containing Markdown
pub documentation: String,
pub provider: CompletionProvider,
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum CompletionProvider {
Lsp(LanguageServerId),
PathCompletions,
}

impl From<LanguageServerId> for CompletionProvider {
fn from(id: LanguageServerId) -> Self {
CompletionProvider::Lsp(id)
}
}
106 changes: 57 additions & 49 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,29 +426,32 @@ impl Client {
let server_tx = self.server_tx.clone();
let id = self.next_request_id();

let params = serde_json::to_value(params);
// it' important this is not part of the future so that it gets
// executed right away so that the request order stays concisents
let rx = serde_json::to_value(params)
.map_err(Error::from)
.and_then(|params| {
let request = jsonrpc::MethodCall {
jsonrpc: Some(jsonrpc::Version::V2),
id: id.clone(),
method: R::METHOD.to_string(),
params: Self::value_into_params(params),
};
let (tx, rx) = channel::<Result<Value>>(1);
server_tx
.send(Payload::Request {
chan: tx,
value: request,
})
.map_err(|e| Error::Other(e.into()))?;
Ok(rx)
});

async move {
use std::time::Duration;
use tokio::time::timeout;

let request = jsonrpc::MethodCall {
jsonrpc: Some(jsonrpc::Version::V2),
id: id.clone(),
method: R::METHOD.to_string(),
params: Self::value_into_params(params?),
};

let (tx, mut rx) = channel::<Result<Value>>(1);

server_tx
.send(Payload::Request {
chan: tx,
value: request,
})
.map_err(|e| Error::Other(e.into()))?;

// TODO: delay other calls until initialize success
timeout(Duration::from_secs(timeout_secs), rx.recv())
timeout(Duration::from_secs(timeout_secs), rx?.recv())
.await
.map_err(|_| Error::Timeout(id))? // return Timeout
.ok_or(Error::StreamClosed)?
Expand All @@ -465,21 +468,25 @@ impl Client {
{
let server_tx = self.server_tx.clone();

async move {
let params = serde_json::to_value(params)?;

let notification = jsonrpc::Notification {
jsonrpc: Some(jsonrpc::Version::V2),
method: R::METHOD.to_string(),
params: Self::value_into_params(params),
};

server_tx
.send(Payload::Notification(notification))
.map_err(|e| Error::Other(e.into()))?;

Ok(())
}
// it' important this is not part of the future so that it gets
// executed right away so that the request order stays consisents
let res = serde_json::to_value(params)
.map_err(Error::from)
.and_then(|params| {
let params = serde_json::to_value(params)?;

let notification = jsonrpc::Notification {
jsonrpc: Some(jsonrpc::Version::V2),
method: R::METHOD.to_string(),
params: Self::value_into_params(params),
};
server_tx
.send(Payload::Notification(notification))
.map_err(|e| Error::Other(e.into()))
});
// TODO: this function is not async and never should have been
// but turning it into non-async function is a big refactor
async move { res }
}

/// Reply to a language server RPC call.
Expand All @@ -492,26 +499,27 @@ impl Client {

let server_tx = self.server_tx.clone();

async move {
let output = match result {
Ok(result) => Output::Success(Success {
jsonrpc: Some(Version::V2),
id,
result: serde_json::to_value(result)?,
}),
Err(error) => Output::Failure(Failure {
let output = match result {
Ok(result) => serde_json::to_value(result).map(|result| {
Output::Success(Success {
jsonrpc: Some(Version::V2),
id,
error,
}),
};
result,
})
}),
Err(error) => Ok(Output::Failure(Failure {
jsonrpc: Some(Version::V2),
id,
error,
})),
};

let res = output.map_err(Error::from).and_then(|output| {
server_tx
.send(Payload::Response(output))
.map_err(|e| Error::Other(e.into()))?;

Ok(())
}
.map_err(|e| Error::Other(e.into()))
});
async move { res }
}

// -------------------------------------------------------------------------------------------
Expand Down
6 changes: 2 additions & 4 deletions helix-term/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ use helix_event::AsyncHook;
use crate::config::Config;
use crate::events;
use crate::handlers::auto_save::AutoSaveHandler;
use crate::handlers::completion::CompletionHandler;
use crate::handlers::signature_help::SignatureHelpHandler;

pub use completion::trigger_auto_completion;
pub use helix_view::handlers::Handlers;

mod auto_save;
Expand All @@ -20,12 +18,12 @@ mod signature_help;
pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
events::register();

let completions = CompletionHandler::new(config).spawn();
let event_tx = completion::CompletionHandler::new(config).spawn();
let signature_hints = SignatureHelpHandler::new().spawn();
let auto_save = AutoSaveHandler::new().spawn();

let handlers = Handlers {
completions,
completions: helix_view::handlers::lsp::CompletionHandler::new(event_tx),
signature_hints,
auto_save,
};
Expand Down
Loading

0 comments on commit 06539ac

Please sign in to comment.