问题描述
我正在使用LSP4J用Scala编写的语言服务器。我遵循了VS Code和LSP4J的文档,并达到可以在客户端和服务器之间来回发送通知的地步。我还设法使客户端从服务器请求内容,然后与它们一起使用。但是,我还没有完全设法解决其他问题。也就是说,我可以让服务器向客户端发出请求,但这些请求从未完成。
为您提供一些背景信息,这是我所做的:
到目前为止,太好了。我可以跟踪每个步骤,并且知道一切都按预期执行。现在,在服务器端,我应该找回CompletableFuture
。以我对事物的理解,此CompletableFuture
最终应该以请求处理程序(在客户端)返回的值完成。
下面是上述代码的相关部分。
trait IdeLanguageClient extends LanguageClient {
//...
//This is the request sent to the client
@JsonRequest("SomeRequest")
def s2c_request(): CompletableFuture[String]
}
class ExampleLanguageServer() extends LanguageClientAware {
private var client: Option[IdeLanguageClient] = None
//...
//This is the handler for the notification the client sends after clicking on the status bar.
@JsonNotification("sbi")
def c2s_notification(): Unit = {
client match {
case Some(c) =>
val completable_future = c.s2c_request()
while(!fut.isDone){
println("sleepy")
Thread.sleep(1000) // This goes on for ever!!
}
val s = fut.get()
println(s)
}
}
override def connect(client: LanguageClient): Unit = {
println("client is connected")
this.client = Some(client.asInstanceOf[IdeLanguageClient])
}
}
export function activate(context: ExtensionContext) {
//...
// Create the language client.
client = new LanguageClient(
'languageServerExample','Language Server Example',startServer,clientOptions
);
createStatusBarItem();
// Handler for the server's request
client.onReady().then(ready => {
client.onRequest("SomeRequest",() => {
"Some Responce to the request"
});
});
// Start the client. This will also launch the server
client.start();
function createStatusBarItem() {...}
// Invokes the jars of the language server
function startServer(): Promise<StreamInfo> {...}
}
关键部分是while循环c2s_notification
。以我的理解,将来应该最终完成(给予微不足道的任务,几乎立即完成)并产生onRequest
句柄返回的值。相反,循环仅继续每秒打印一次“睡眠”。我误会了什么吗?还是我只是做错了什么?
我希望问题已经足够清楚地陈述,并且包括所有必要的信息。
感谢您的帮助!
解决方法
我发现了问题所在。我认为CompletableFuture
可以像Future
那样对待。显然不是这样。取而代之的是,join
-ing(或get
-ting)来自CompletableFuture
的结果的异步计算必须由Future
包装。
也就是说,用以下内容替换c2sNotification
中while循环周围的关键部分:
client match {
case Some(c) =>
val f: Future[String] = Future {
val cf: CompletableFuture[String] = c.s2c_request()
val s = cf.join()
s
}
f.onComplete({
case Success(s) => println(s)
case Failure(e) => println(e)
})
}