-
Notifications
You must be signed in to change notification settings - Fork 62
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
Receive a custom request from client #256
Comments
Good question, @IWANABETHATGUY! There isn't currently a way to do this, but we should be able to easily expose a |
Thank you! |
Actually, I think I might've initially misunderstood your comment. I now realize that you're referring to custom requests sent from the client to the server, rather than custom requests sent from the server to the client. That's actually a totally separate concern from #230, which is something that we also should do regardless (update: just merged #275). Sorry for conflating the two. 😄 I think this task is a bit trickier to achieve while also keeping the API ergonomic and difficult to misuse. The easy way to implement this would be to expose a fall-through handler in the This works well enough, but it feels somewhat brittle to me. It would mean that the catch-all error handling logic in The real question becomes, then, how to make the closure registration approach more ergonomic to the user. Prior to our switch away from let (service, messages) = LspService::with_custom(|client| MyServer { client, ... })
.request("custom/request", |server, params| server.my_custom_request(params))
.notification("custom/notification", |server, params| server.my_custom_notification(params))
.build(); The signature for custom request handlers would probably be something like: async fn(Arc<MyServer>, Option<serde_json::Value>) -> tower_lsp::Result<Option<Value>> and the signature for notification handlers could then be: async fn(Arc<MyServer>, Option<serde_json::Value>) I think there exist ways to reduce boilerplate even further while reducing the potential for bugs. There may also be other viable approaches out there that haven't yet been explored. In any case, hopefully we can eventually arrive at a solid failure-proof solution! Any thoughts on this, @IWANABETHATGUY? |
So, I've implemented a basic working version of this API, which looks like this: struct Backend {
client: Client,
}
impl LanguageServer for Backend {
// ...
}
impl Backend {
async fn custom_request(&self, params: SomethingDeserializable) -> jsonrpc::Result<SomethingSerializable> {
Ok(...)
}
async fn custom_notification(&self, params: SomethingDeserializable) {
// Lack of return value indicates that this is a notification.
}
async fn no_params_works_too(&self) -> jsonrpc::Result<()> {
Ok(())
}
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, messages) = LspService::builder(|client| Backend { client })
.with_method("custom/request", Backend::custom_request)
.with_method("custom/notification", Backend::custom_notification)
.with_method("custom/noParamsWorksToo", Backend::no_params_works_too)
.finish();
Server::new(stdin, stdout)
.interleave(messages)
.serve(service)
.await;
} Underpinning this new API is a In the process of designing this, though, I've encountered and reported dtolnay/async-trait#167, which appears to be caused by a known compiler bug. As a result, the builder currently cannot accept I'm inclined toward releasing this solution as-is, provided that this limitation is clearly documented. Once the |
@ebkalderon This works for me, thank you for your work! |
I'm in the process of transplanting the quick-and-dirty prototype I created into the codebase and making it more robust. The current work is in the support-custom-server-requests branch, if you'd like to have a look. The public |
Is there any way to receive a custom request from client to server?
The text was updated successfully, but these errors were encountered: