File: Services\ClientOptionProviders.cs
Web Access
Project: ..\..\..\src\Workspaces\Remote\ServiceHub\Microsoft.CodeAnalysis.Remote.ServiceHub.csproj (Microsoft.CodeAnalysis.Remote.ServiceHub)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.AddImport;
using Microsoft.CodeAnalysis.CodeCleanup;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Remote;
 
// TODO: Use generic IRemoteOptionsCallback<TOptions> once https://github.com/microsoft/vs-streamjsonrpc/issues/789 is fixed
 
internal sealed class RemoteOptionsProviderCache<TOptions>
{
    private readonly Func<RemoteServiceCallbackId, string, CancellationToken, ValueTask<TOptions>> _callback;
    private readonly RemoteServiceCallbackId _callbackId;
 
    private ImmutableDictionary<string, AsyncLazy<TOptions>> _cache = ImmutableDictionary<string, AsyncLazy<TOptions>>.Empty;
 
    public RemoteOptionsProviderCache(Func<RemoteServiceCallbackId, string, CancellationToken, ValueTask<TOptions>> callback, RemoteServiceCallbackId callbackId)
    {
        _callback = callback;
        _callbackId = callbackId;
    }
 
    public async ValueTask<TOptions> GetOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken)
    {
        var lazyOptions = ImmutableInterlocked.GetOrAdd(ref _cache, languageServices.Language, _ => new AsyncLazy<TOptions>(GetRemoteOptions, cacheResult: true));
        return await lazyOptions.GetValueAsync(cancellationToken).ConfigureAwait(false);
 
        Task<TOptions> GetRemoteOptions(CancellationToken cancellationToken)
            => _callback(_callbackId, languageServices.Language, cancellationToken).AsTask();
    }
}
 
internal sealed class ClientCleanCodeGenerationOptionsProvider : AbstractCleanCodeGenerationOptionsProvider
{
    private readonly RemoteOptionsProviderCache<CleanCodeGenerationOptions> _cache;
 
    public ClientCleanCodeGenerationOptionsProvider(Func<RemoteServiceCallbackId, string, CancellationToken, ValueTask<CleanCodeGenerationOptions>> callback, RemoteServiceCallbackId callbackId)
        => _cache = new RemoteOptionsProviderCache<CleanCodeGenerationOptions>(callback, callbackId);
 
    public override ValueTask<CleanCodeGenerationOptions> GetCleanCodeGenerationOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken)
        => _cache.GetOptionsAsync(languageServices, cancellationToken);
}
 
internal sealed class ClientCodeCleanupOptionsProvider : AbstractCodeCleanupOptionsProvider
{
    private readonly RemoteOptionsProviderCache<CodeCleanupOptions> _cache;
 
    public ClientCodeCleanupOptionsProvider(Func<RemoteServiceCallbackId, string, CancellationToken, ValueTask<CodeCleanupOptions>> callback, RemoteServiceCallbackId callbackId)
        => _cache = new RemoteOptionsProviderCache<CodeCleanupOptions>(callback, callbackId);
 
    public override ValueTask<CodeCleanupOptions> GetCodeCleanupOptionsAsync(LanguageServices languageServices, CancellationToken cancellationToken)
        => _cache.GetOptionsAsync(languageServices, cancellationToken);
}