Merged
Conversation
In order to have an extensible architecture that will allow us to do things like provide client capabilities that the upstream client does not provide, we need a way to insert lspx into the conversation between client and servers. An example of this is fixing the gap in the conversation between `eglot` and `vscode-eslint-language-server`. This applies the middleware pattern to all communication between client and server so that a single middleware can intercept whichever messages it needs to carry out its job. Because connections are stateful and support both notification and request, there are four components to each middleware: client to N servers: - notify - request 1 of N servers to client: - notify - request Because the middleware contains not only the request/notification params, but also the lsp agents that are sending and receiving, it can make decisions about filtering agents before forwarding on, or it can ever respond directly without consulting the other end of the connection. As part of this, the lifecycle that captures capabilities has been re-written as the very first middleware at the top of the stack, and it actually makes it quite a bit cleaner. The lifecycle of the LSPX server is a middleware that delegates to a "State" middleware. This change limits itself to the minimum required to insert the middleware into each piece of communication, but in the future we should look to extracting out the special case "completion" handler in the `defaultRequest` and implement it as middleware
Also: add logging of stderr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
In order to have an extensible architecture that will allow us to do things like provide client capabilities that the upstream client does not provide, we need a way to insert lspx into the conversation between client and servers. An example of this is fixing the gap in the conversation between
eglotandvscode-eslint-language-server. (see #3)Approach
This applies the middleware pattern to all communication between client and server so that a single middleware can intercept whichever messages it needs to carry out its job. Because connections are stateful and support both notification and request, there are four components to each middleware:
client to N servers:
1 of N servers to client:
Because the middleware contains not only the request/notification params, but also the lsp agents that are sending and receiving, it can make decisions about filtering agents before forwarding on, or it can ever respond directly without consulting the other end of the connection.
As part of this, the lifecycle that captures capabilities has been re-written as the very first middleware at the top of the stack, and it actually makes it quite a bit cleaner. The lifecycle of the LSPX server is a middleware that delegates to a "State" middleware.
Possible Drawbacks or Risks
A hypothetical risk is that it could lead to performance problems if there is too much delegation bouncing around in the system. Another concern that could be raised is that the delegation itself makes the codebase more difficult to understand, however while that might be nominally true at the level of baseline request routing. However, the clarity it brings to actually defining the behavior of the system far outweighs that.
TODOs and Open Questions
defaultRequestand implement it as middleware.