Skip to content

[LSP] Allow services to be exported per language server #61002

@dibarbet

Description

@dibarbet

Currently, it is not easy to share types that must be instantiated per server between different IRequestHandler objects from the same server. This is a useful thing to do to share things like caches between completion and completion resolve requests for the same server (but should not be accessible outside of it). Or access information about the current LSP solution via the LSPWorkspaceManager (without passing them along in the request context).

Desired characteristics

  1. Allow services to be simply exported (similar to MEF) and import their non-shared dependencies (e.g. import the shared diagnostics service).
  2. Language server services should be newly instantiated each time a new LSP server is created and disposed of when they shutdown.
  3. Services should be part of the request context so handlers can easily access the services.
  4. Language server services can import other language server services and share the same instance for them in the same server.

Example

Exporting an LSP server service

interface ILspService
{
}

// We should have a single instance of this type per language server.
// All handlers for the same server should get the same instance of this.
[ExportLspService]
public class CompletionCacheService : ILspService
{
    CacheList(CompletionList list)....
    TryGetCachedList(TextDocumentIdentifier textDoc)...
}

public class CompletionHandler : IRequestHandler<...>
{
    async Task<CompletionList> HandleAsync(RequestContext context, ...)
    {
        var completionList = await CalculateListAsync(...);
        context.GetRequiredService<CompletionCacheService>().CacheList(completionList);
        ...
    }
}

public class CompletionResolveHandler : IRequestHandler<...>
{
    async Task<CompletionItem> HandleAsync(RequestContext context, ...)
    {
        // Should retrieve the list that was cached in the completion handler for the same server, but not
        // a list cached by a different server
        var cachedList = context.GetRequiredService<CompletionCacheService>().TryGetCachedList(textDoc);
        ...
    }
}


Notes

  1. this might be possible via non-shared mef exports - during creation of the server we explicitly request the services once and store them.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions