src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md
CLaSP was created to ease the creation and maintenance of Language Server implementations by sharing our hard-won knowledge, while leaving you the flexiblity to create the server you need.
Currently CLaSP is not recommended or supported for use outside of specific teams/projects. We hope to make it more broadly available in the future.
You can find a simple example implementation of a CLaSP-based LanguageServer here.
To get started with CLaSP you may follow the following steps
Microsoft.CommonLanguageServerProtocol.Framework in your LSP server project.ILspLogger. This allows CLaSP to log information however you would like.ILspServices. This interface will serve as a wrapper around whatever DI system you choose to use to make sure that your services implemented elsewhere are available to CLaSP.
SupportsGetRegisteredServices return false and GetRegisteredServices throw NotImplementedException.AbstractLanguageServer. This is the core of your Language Server implementation, which will manage your lifecycle and host the rest of the components.
Initialize is called (preferably from the constructor) to start the server.ConstructLspServices will be called once to construct your implementation of ILspServices. When this exits all your services should be registerd, including your IMethodHandlers. The following Services are mandatory for proper function:
ILspLogger.IRequestContextFactory.InitializeHandler and InitializedHandler, either the ones included in CLaSP or your own implementations. If you use the included handlers you will need an IInitializeManager (which handles your Client and Server Capabilities) too.AbstractLanguageServer itself.IRequestContextFactory<TRequestContext>. Constructs the RequestContext for each request. To maintain good performance you need to minimize the work being done in CreateRequestContextAsync since it blocks the queue from receiving mutating requests.
INotificationHandler and IRequestHandler interfaces (and the ITextDocumeentIdentifierhandler<TRequest,TTextDocumentIdentifier> interface if the request relates to a specific document), being sure to include them in your ILspServices object (as constructed by ConstructLspServices) as IMethodHandler services. This automatically registers them on the JsonRpc object.
MutatesSolutionState should be true for Handlers like textDocument/didChange which change solution state because this affects the queuing behavior required in order to ensure that the correct document version is being operated on.HandleNotificationAsync and HandleRequestAsync. These implement your actual handler behavior but it's very important that if they require access to the current state of a TextDocument that this information be gathered by IRequestContextFactory and put on the RequestContext object rather than retrieved here. If you fail to follow this stipulation you may run into document sync issues because requests which mutate document state are not guaranteed to happen in a particular order. This means that document state might change while your HandleRequestAsync request is executing, but the IRequestContextFactory is guaranteed to operate in a thread-safe manner.AbstractLanguageServer. Note that Roslyn overrides ConstructRequestExecutionQueue, allowing it to change the override some default behavior.ILSPLogger. Logs to LogHub.ILSPServices. Note: Roslyns ILSPServices implementation is a product of their specific history and needs and ends up being a combination of MEF and explicitly constructed services. We don't recommend using it to guide your creation of an ILSPServices implementation unless you have similarly complicated needs.IRequestContextFactory. Provides a good example of how to get the TextDocumentIdentifier (URI) off of the requestParam object.
RequestContext.CreateAsync is called by IRequestContextFactory.CreateRequestContextAsync we maintain synchronization safety.IRequestHandler or INotificationHandler. Note that this example mutates solution state and has document context.ILSPServices) but relies on multiple other language servers (C#, HTML) for information on its contained languages.
AbstractLanguageServer.
ConstructLspServices. Razor has a simple implementation of ILSPServices which wraps Microsoft.Extensions.DependencyInjection and explicitly adds each service that it depends on.ILSPLogger. Razor's ILSPLogger implementation simply notifies the client so that it can do whatever is needed.ILSPServices. A simple wrapper which may serve as a good reference for implementations.IRequestContextFactory. Note again the retrieval of document information.IRequestHandler or INotificationHandler. Note that this example mutates solution state and has document context.