Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert to std::future and async/await #101

Merged
merged 9 commits into from
Feb 22, 2020
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
rust-version: [1.36.0, beta, nightly]
rust-version: [1.39.0, beta, nightly]
include:
- rust-version: nightly
continue-on-error: true
Expand Down
31 changes: 16 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ categories = ["asynchronous"]
keywords = ["language-server", "lsp", "tower"]

[dependencies]
bytes = "0.4.12"
futures = "0.1.28"
jsonrpc-core = "14.0.5"
jsonrpc-derive = "14.0.5"
log = "0.4.8"
lsp-types = "0.68.0"
nom = "5.0.1"
serde = { version = "1.0.103", features = ["derive"] }
serde_json = "1.0.40"
tokio-codec = "0.1.1"
tokio-executor = "0.1.9"
tokio-io = "0.1.12"
tower-service = "0.2.0"
async-trait = "0.1"
bytes = "0.5"
futures = { version = "0.3", features = ["compat"] }
jsonrpc-core = "14.0"
jsonrpc-derive = "14.0"
log = "0.4"
lsp-types = "0.68"
nom = "5.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "0.2", features = ["rt-core"] }
tokio-util = { version = "0.2", features = ["codec"] }
tower-service = "0.3"

[dev-dependencies]
env_logger = "0.7.1"
tokio = "0.1.22"
env_logger = "0.7"
tokio = { version = "0.2", features = ["io-std", "macros", "test-util"] }
tower-test = "0.3"
70 changes: 32 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,20 @@ consists of three parts:
* A `Server` which spawns the `LspService` and processes requests and responses
over stdin and stdout.

_NOTE: This library currently relies on `futures` 0.1 and is not async/await
ready. Support for `std::future::Future` and async/await is tracked in [#58]._

[#58]: https://github.com/ebkalderon/tower-lsp/issues/58

## Example

```rust
use futures::future;
use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::Result;
use serde_json::Value;
use tower_lsp::lsp_types::request::GotoDefinitionResponse;
use tower_lsp::lsp_types::request::*;
use tower_lsp::lsp_types::*;
use tower_lsp::{LanguageServer, LspService, Printer, Server};

#[derive(Debug, Default)]
struct Backend;

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
type ShutdownFuture = BoxFuture<()>;
type SymbolFuture = BoxFuture<Option<Vec<SymbolInformation>>>;
type ExecuteFuture = BoxFuture<Option<Value>>;
type CompletionFuture = BoxFuture<Option<CompletionResponse>>;
type HoverFuture = BoxFuture<Option<Hover>>;
type DeclarationFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type DefinitionFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type TypeDefinitionFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type HighlightFuture = BoxFuture<Option<Vec<DocumentHighlight>>>;

fn initialize(&self, _: &Printer, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult::default())
}
Expand All @@ -73,44 +58,53 @@ impl LanguageServer for Backend {
printer.log_message(MessageType::Info, "server initialized!");
}

fn shutdown(&self) -> Self::ShutdownFuture {
Box::new(future::ok(()))
async fn shutdown(&self) -> Result<()> {
Ok(())
}

async fn symbol(&self, _: WorkspaceSymbolParams) -> Result<Option<Vec<SymbolInformation>>> {
Ok(None)
}

async fn execute_command(&self, _: &Printer, _: ExecuteCommandParams) -> Result<Option<Value>> {
Ok(None)
}

fn symbol(&self, _: WorkspaceSymbolParams) -> Self::SymbolFuture {
Box::new(future::ok(None))
async fn completion(&self, _: CompletionParams) -> Result<Option<CompletionResponse>> {
Ok(None)
}

fn execute_command(&self, _: &Printer, _: ExecuteCommandParams) -> Self::ExecuteFuture {
Box::new(future::ok(None))
async fn hover(&self, _: TextDocumentPositionParams) -> Result<Option<Hover>> {
Ok(None)
}

fn completion(&self, _: CompletionParams) -> Self::CompletionFuture {
Box::new(future::ok(None))
async fn signature_help(&self, _: TextDocumentPositionParams) -> Result<Option<SignatureHelp>> {
Ok(None)
}

fn goto_declaration(&self, _: TextDocumentPositionParams) -> Self::DeclarationFuture {
Box::new(future::ok(None))
async fn goto_declaration(&self, _: TextDocumentPositionParams) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn goto_definition(&self, _: TextDocumentPositionParams) -> Self::DefinitionFuture {
Box::new(future::ok(None))
async fn goto_definition(&self, _: TextDocumentPositionParams) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn goto_type_definition(&self, _: TextDocumentPositionParams) -> Self::TypeDefinitionFuture {
Box::new(future::ok(None))
async fn goto_type_definition(&self, _: TextDocumentPositionParams) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn hover(&self, _: TextDocumentPositionParams) -> Self::HoverFuture {
Box::new(future::ok(None))
async fn goto_implementation(&self, _: TextDocumentPositionParams) -> Result<Option<GotoImplementationResponse>> {
Ok(None)
}

fn document_highlight(&self, _: TextDocumentPositionParams) -> Self::HighlightFuture {
Box::new(future::ok(None))
async fn document_highlight(&self, _: TextDocumentPositionParams) -> Result<Option<Vec<DocumentHighlight>>> {
Ok(None)
}
}

fn main() {
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();

Expand All @@ -120,7 +114,7 @@ fn main() {
.interleave(messages)
.serve(service);

tokio::run(handle.run_until_exit(server));
handle.run_until_exit(server).await;
}
```

Expand Down
94 changes: 48 additions & 46 deletions examples/custom_notification.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use futures::future;
use jsonrpc_core::{BoxFuture, Result};
use lsp_types::notification::Notification;
use lsp_types::request::GotoImplementationResponse;
use serde::{Deserialize, Serialize};
use jsonrpc_core::Result;
use serde::Serialize;
use serde_json::Value;
use tower_lsp::lsp_types::request::GotoDefinitionResponse;
use tower_lsp::lsp_types::notification::Notification;
use tower_lsp::lsp_types::request::*;
use tower_lsp::lsp_types::*;
use tower_lsp::{LanguageServer, LspService, Printer, Server};

#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
#[derive(Debug, Serialize)]
struct CustomNotificationParams {
title: String,
message: String,
Expand All @@ -24,7 +22,7 @@ impl CustomNotificationParams {
}

#[derive(Debug)]
struct CustomNotification {}
enum CustomNotification {}

impl Notification for CustomNotification {
type Params = CustomNotificationParams;
Expand All @@ -34,19 +32,8 @@ impl Notification for CustomNotification {
#[derive(Debug, Default)]
struct Backend;

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
type ShutdownFuture = BoxFuture<()>;
type SymbolFuture = BoxFuture<Option<Vec<SymbolInformation>>>;
type ExecuteFuture = BoxFuture<Option<Value>>;
type CompletionFuture = BoxFuture<Option<CompletionResponse>>;
type HoverFuture = BoxFuture<Option<Hover>>;
type SignatureHelpFuture = BoxFuture<Option<SignatureHelp>>;
type DeclarationFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type DefinitionFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type TypeDefinitionFuture = BoxFuture<Option<GotoDefinitionResponse>>;
type ImplementationFuture = BoxFuture<Option<GotoImplementationResponse>>;
type HighlightFuture = BoxFuture<Option<Vec<DocumentHighlight>>>;

fn initialize(&self, _: &Printer, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
server_info: None,
Expand Down Expand Up @@ -87,19 +74,19 @@ impl LanguageServer for Backend {
})
}

fn shutdown(&self) -> Self::ShutdownFuture {
Box::new(future::ok(()))
async fn shutdown(&self) -> Result<()> {
Ok(())
}

fn symbol(&self, _: WorkspaceSymbolParams) -> Self::SymbolFuture {
Box::new(future::ok(None))
async fn symbol(&self, _: WorkspaceSymbolParams) -> Result<Option<Vec<SymbolInformation>>> {
Ok(None)
}

fn execute_command(
async fn execute_command(
&self,
printer: &Printer,
params: ExecuteCommandParams,
) -> Self::ExecuteFuture {
) -> Result<Option<Value>> {
if &params.command == "custom.notification" {
printer.send_notification::<CustomNotification>(CustomNotificationParams::new(
"Hello", "Message",
Expand All @@ -109,44 +96,59 @@ impl LanguageServer for Backend {
MessageType::Info,
format!("command executed!: {:?}", params),
);
printer.apply_edit(WorkspaceEdit::default());
Box::new(future::ok(None))
Ok(None)
}

fn completion(&self, _: CompletionParams) -> Self::CompletionFuture {
Box::new(future::ok(None))
async fn completion(&self, _: CompletionParams) -> Result<Option<CompletionResponse>> {
Ok(None)
}

fn hover(&self, _: TextDocumentPositionParams) -> Self::HoverFuture {
Box::new(future::ok(None))
async fn hover(&self, _: TextDocumentPositionParams) -> Result<Option<Hover>> {
Ok(None)
}

fn signature_help(&self, _: TextDocumentPositionParams) -> Self::SignatureHelpFuture {
Box::new(future::ok(None))
async fn signature_help(&self, _: TextDocumentPositionParams) -> Result<Option<SignatureHelp>> {
Ok(None)
}

fn goto_declaration(&self, _: TextDocumentPositionParams) -> Self::DeclarationFuture {
Box::new(future::ok(None))
async fn goto_declaration(
&self,
_: TextDocumentPositionParams,
) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn goto_definition(&self, _: TextDocumentPositionParams) -> Self::DefinitionFuture {
Box::new(future::ok(None))
async fn goto_definition(
&self,
_: TextDocumentPositionParams,
) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn goto_type_definition(&self, _: TextDocumentPositionParams) -> Self::TypeDefinitionFuture {
Box::new(future::ok(None))
async fn goto_type_definition(
&self,
_: TextDocumentPositionParams,
) -> Result<Option<GotoDefinitionResponse>> {
Ok(None)
}

fn goto_implementation(&self, _: TextDocumentPositionParams) -> Self::ImplementationFuture {
Box::new(future::ok(None))
async fn goto_implementation(
&self,
_: TextDocumentPositionParams,
) -> Result<Option<GotoImplementationResponse>> {
Ok(None)
}

fn document_highlight(&self, _: TextDocumentPositionParams) -> Self::HighlightFuture {
Box::new(future::ok(None))
async fn document_highlight(
&self,
_: TextDocumentPositionParams,
) -> Result<Option<Vec<DocumentHighlight>>> {
Ok(None)
}
}

fn main() {
#[tokio::main]
async fn main() {
env_logger::init();

let stdin = tokio::io::stdin();
Expand All @@ -158,5 +160,5 @@ fn main() {
.interleave(messages)
.serve(service);

tokio::run(handle.run_until_exit(server));
handle.run_until_exit(server).await;
}
Loading