Merge pull request #6829 from ryanbrandenburg/CLaSPBase

First CLaSP classes
This commit is contained in:
Ryan Brandenburg 2022-09-14 14:16:31 -07:00 коммит произвёл GitHub
Родитель 61cc048d36 21a4a44d0a
Коммит 06c485ccd5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
27 изменённых файлов: 774 добавлений и 817 удалений

Просмотреть файл

@ -1,27 +1,29 @@
# Creating a C# Language Server Framework
# Background
## Background
The [language server protocol](https://microsoft.github.io/language-server-protocol/specification) is a standard that IDE's can implement in order to provide language service functionality for any number of languages. Because of this, on the official LSP specification site there exists a [list of implementations](https://microsoft.github.io/language-server-protocol/implementors/servers/) for each language. This list contains the list of language servers for languages while simultaneously indicating their "implementation language". The implementation language is where things get interesting (was it written in C#, JS, C++ etc.). Each implementation language typically has a standard framework / library to make writing language servers easy. For instance there's a [JavaScript framework](https://github.com/microsoft/vscode-languageserver-node) and even a [C# framework](https://github.com/omniSharp/csharp-language-server-protocol/) to ease in the writing of language servers. Having a framework is appealing because language servers don't exist for there to be only a single language server for a single language; they exist so that many can be created to provide ever-extending language services for features and are language agnostic (fun fact: Python language server used to be written in C#).
# Problem
## Problem
As mentioned in the [Background](#background) section there exists many language server frameworks, one of which is C# which we'll call from here on out the **C# LSP framework**. The C# LSP framework was written by the creators of [OmniSharp](http://www.omnisharp.net/), is open source and today maintained by a single individual (David Driscoll). The framework originated with the intent to make writing C# language servers easy and quickly became a catch-all for every problem in the language server ecosystem. Effectively it saw all the problems that could possible exist and tried to solve them. While attempting to solve every problem was a noble cause it became its biggest weakness. Solving every problem for every C# language server has led to heaps of dependencies, fragile request handling, arcane service resolution, lengthy startup times, awkward end-user APIs and a highly coupled internal system that's difficult to reason about. In addition to the above given the lack of investment in modernizing the O# framework from the community it has also collected significant technical debt preventing those who depend on it to evolve with the times.
As it stands today the Razor language server currently depends on the C# LSP framework and because of this it encounters the following problems:
- Slower startup time
- High dependency count
- Unstructured logging / tracing
- Race conditions in request handling
- Replication of Visual Studio LSP++ concepts
# Proposal
## Proposal
Being the creators of the Razor, Roslyn, and WebTools language servers we can take what we've learned and build a simplistic C# framework that Razor, C#, HTML, CSS and any other partner can sit ontop of to simplify language server development. Future improvements to the framework would translate across server boundaries, implementations would be consistent and any LSP++ implementations would be readily available for all to consume. Similarly I could envision a world where IntelliCode and other third parties may be able to use this tech to better extend Visual Studio in a reasonable way.
The new framework would opt-for simplicity. This means we wouldn't add bells and whistles to automatically understand configuration or automatically include various services in handlers. In a lot of ways we'd modernize what the Roslyn C# server has already done and lift or add bits of functionality that is unequivocally required.
This simplistic approach would mean building a core piece of infrastructure that could consume and respond to requests in an LSP centric way. Some of the things we can tackle:
- Build request handling that is `textDocument/didX` aware (things that typically mutate state) and optimize when certain requests are run to prevent races while allowing high parallelizability
- Create LSP++ APIs / handler abstractions to ease in implementation
- Do less work on startup to allow for instantaneous startup

Просмотреть файл

@ -127,8 +127,6 @@
<NewtonsoftJsonPackageVersion>13.0.1</NewtonsoftJsonPackageVersion>
<NerdbankStreamsPackageVersion>2.8.57</NerdbankStreamsPackageVersion>
<NuGetSolutionRestoreManagerInteropVersion>4.8.0</NuGetSolutionRestoreManagerInteropVersion>
<OmniSharpExtensionsLanguageServerPackageVersion>0.19.5</OmniSharpExtensionsLanguageServerPackageVersion>
<OmniSharpExtensionsLanguageProtocolPackageVersion>$(OmniSharpExtensionsLanguageServerPackageVersion)</OmniSharpExtensionsLanguageProtocolPackageVersion>
<OmniSharpMSBuildPackageVersion>1.39.1</OmniSharpMSBuildPackageVersion>
<StreamJsonRpcPackageVersion>2.12.7-alpha</StreamJsonRpcPackageVersion>
<SystemRuntimeInteropServicesRuntimePackageVersion>4.3.0</SystemRuntimeInteropServicesRuntimePackageVersion>

Просмотреть файл

@ -45,8 +45,6 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions.Tooling.Internal" Version="$(MicrosoftAspNetCoreMvcRazorExtensionsToolingInternalPackageVersion)" />
<PackageReference Include="OmniSharp.Extensions.LanguageProtocol" Version="$(OmniSharpExtensionsLanguageProtocolPackageVersion)" />
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="$(OmniSharpExtensionsLanguageServerPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageReference Include="System.Private.Uri" Version="$(SystemPrivateUriPackageVersion)" ExcludeAssets="true" PrivateAssets="true" />

Просмотреть файл

@ -0,0 +1,61 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal class CapabilitiesManager : IInitializeManager<InitializeParams, InitializeResult>
{
private InitializeParams? _initializeParams;
private readonly ILspServices _lspServices;
public CapabilitiesManager(ILspServices lspServices)
{
_lspServices = lspServices;
}
public InitializeParams GetInitializeParams()
{
if (_initializeParams is null)
{
throw new InvalidOperationException($"{nameof(GetInitializeParams)} was called before '{Methods.InitializeName}'");
}
return _initializeParams;
}
public InitializeResult GetInitializeResult()
{
var initializeParams = GetInitializeParams();
var clientCapabilities = initializeParams.Capabilities;
var vsClientCapabilities = clientCapabilities.ToVSInternalClientCapabilities();
var serverCapabilities = new VSInternalServerCapabilities();
var registrationExtensions = _lspServices.GetRequiredServices<IRegistrationExtension>();
foreach (var registrationExtension in registrationExtensions)
{
var registrationResult = registrationExtension.GetRegistration(vsClientCapabilities);
if (registrationResult is not null)
{
serverCapabilities.ApplyRegistrationResult(registrationResult);
}
}
var initializeResult = new InitializeResult
{
Capabilities = serverCapabilities,
};
return initializeResult;
}
public void SetInitializeParams(InitializeParams request)
{
_initializeParams = request;
}
}

Просмотреть файл

@ -3,9 +3,6 @@
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
@ -13,14 +10,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
// because of this we need to wait until everthing is initialized to make some client requests like
// razor\serverReady. This class takes a TCS which will complete when everything is initialized
// ensuring that no requests are sent before the client is ready.
internal abstract class ClientNotifierServiceBase: IOnLanguageServerStarted
internal abstract class ClientNotifierServiceBase : IOnInitialized
{
public abstract Task<IResponseRouterReturns> SendRequestAsync(string method);
public abstract Task<TResponse> SendRequestAsync<TParams, TResponse>(string method, TParams @params, CancellationToken cancellationToken);
public abstract Task<IResponseRouterReturns> SendRequestAsync<T>(string method, T @params);
public abstract Task SendNotificationAsync<TParams>(string method, TParams @params, CancellationToken cancellationToken);
public abstract Task SendNotificationAsync(string method, CancellationToken cancellationToken);
public abstract Task OnStarted(ILanguageServer server, CancellationToken cancellationToken);
public abstract InitializeParams ClientSettings { get; }
public abstract Task OnInitializedAsync(CancellationToken cancellationToken);
}
}

Просмотреть файл

@ -4,9 +4,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
@ -17,45 +14,50 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
internal class DefaultClientNotifierService : ClientNotifierServiceBase
{
private readonly TaskCompletionSource<bool> _initializedCompletionSource;
private readonly IClientLanguageServer _languageServer;
private readonly StreamJsonRpc.JsonRpc _jsonRpc;
public DefaultClientNotifierService(IClientLanguageServer languageServer)
public DefaultClientNotifierService(StreamJsonRpc.JsonRpc jsonRpc)
{
if (languageServer is null)
if (jsonRpc is null)
{
throw new ArgumentNullException(nameof(languageServer));
throw new ArgumentNullException(nameof(jsonRpc));
}
_languageServer = languageServer;
_jsonRpc = jsonRpc;
_initializedCompletionSource = new TaskCompletionSource<bool>();
}
public override async Task<IResponseRouterReturns> SendRequestAsync(string method)
public override async Task<TResponse> SendRequestAsync<TParams, TResponse>(string method, TParams @params, CancellationToken cancellationToken)
{
await _initializedCompletionSource.Task;
var result = await _jsonRpc.InvokeAsync<TResponse>(method, @params);
return _languageServer.SendRequest(method);
return result;
}
public override async Task<IResponseRouterReturns> SendRequestAsync<T>(string method, T @params)
public override async Task SendNotificationAsync<TParams>(string method, TParams @params, CancellationToken cancellationToken)
{
await _initializedCompletionSource.Task;
return _languageServer.SendRequest(method, @params);
await _jsonRpc.NotifyAsync(method, @params);
}
public override async Task SendNotificationAsync(string method, CancellationToken cancellationToken)
{
await _initializedCompletionSource.Task;
await _jsonRpc.NotifyAsync(method);
}
/// <summary>
/// Fires when the language server is set to "Started".
/// </summary>
/// <param name="server"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task OnStarted(ILanguageServer server, CancellationToken cancellationToken)
public override Task OnInitializedAsync(CancellationToken cancellationToken)
{
_initializedCompletionSource.TrySetResult(true);
return Task.CompletedTask;
}
public override InitializeParams ClientSettings => _languageServer.ClientSettings;
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CommonLanguageServerProtocol.Framework;
namespace Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts
{
internal interface IRazorNotificationHandler<TRequestType> : INotificationHandler<TRequestType, RazorRequestContext>
{
}
internal interface IRazorNotificationHandler : INotificationHandler<RazorRequestContext>
{
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts
{
internal interface IRazorRequestHandler<TRequestType, TResponseType> : IRequestHandler<TRequestType, TResponseType, RazorRequestContext>, ITextDocumentIdentifierHandler<TRequestType, TextDocumentIdentifier>
{
}
internal interface IRazorDocumentlessRequestHandler<TRequestType, TResponseType> : IRequestHandler<TRequestType, TResponseType, RazorRequestContext>
{
}
}

Просмотреть файл

@ -0,0 +1,46 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
internal readonly struct RazorRequestContext
{
private readonly DocumentContext? _documentContext;
public readonly ILspLogger LspLogger;
public readonly ILogger Logger;
public readonly ILspServices LspServices;
public RazorRequestContext(
DocumentContext? documentContext,
ILspLogger lspLoger,
ILogger logger,
ILspServices lspServices)
{
_documentContext = documentContext;
LspLogger = lspLoger;
LspServices = lspServices;
Logger = logger;
}
public DocumentContext GetRequiredDocumentContext()
{
if (_documentContext is null)
{
throw new ArgumentNullException(nameof(DocumentContext));
}
return _documentContext;
}
public T GetRequiredService<T>() where T : class
{
return LspServices.GetRequiredService<T>();
}
}

Просмотреть файл

@ -1,31 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.LanguageServer.Serialization;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
using OmniSharpClientCapabilities = OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities.ClientCapabilities;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Extensions
{
internal static class ClientCapabilitiesExtensions
{
public static VSInternalClientCapabilities ToVSClientCapabilities(this OmniSharpClientCapabilities? omniSharpClientCapabilities, LspSerializer serializer)
{
var jsonCapturingCapabilities = omniSharpClientCapabilities as ICaptureJson;
if (jsonCapturingCapabilities is null)
{
throw new InvalidOperationException("Client capability deserializers not registered, failed to convert to " + nameof(ICaptureJson));
}
var vsClientCapabilities = jsonCapturingCapabilities.Json.ToObject<VSInternalClientCapabilities>(serializer.JsonSerializer);
if (vsClientCapabilities is null)
{
throw new InvalidOperationException("Failed to convert client capabilities");
}
return vsClientCapabilities;
}
}
}

Просмотреть файл

@ -0,0 +1,214 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation;
using Microsoft.AspNetCore.Razor.LanguageServer.Completion;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
using Microsoft.Extensions.Options;
using Microsoft.CommonLanguageServerProtocol.Framework;
using System;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.AspNetCore.Razor.LanguageServer.Hover;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.CommonLanguageServerProtocol.Framework.Handlers;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation;
using StreamJsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
internal static class IServiceCollectionExtensions
{
public static void AddLifeCycleServices(this IServiceCollection services, RazorLanguageServer razorLanguageServer, JsonRpc jsonRpc)
{
services.AddHandler<RazorInitializeEndpoint>();
services.AddHandler<RazorInitializedEndpoint>();
services.AddHandler<ExitHandler<RazorRequestContext>>();
services.AddHandler<ShutdownHandler<RazorRequestContext>>();
services.AddSingleton<ILifeCycleManager>(razorLanguageServer);
services.AddSingleton<IInitializeManager<InitializeParams, InitializeResult>, CapabilitiesManager>();
services.AddSingleton<IRequestContextFactory<RazorRequestContext>, RazorRequestContextFactory>();
var serverManager = new DefaultClientNotifierService(jsonRpc);
services.AddSingleton<ClientNotifierServiceBase>(serverManager);
services.AddSingleton<IOnInitialized>(serverManager);
}
public static void AddFormattingServices(this IServiceCollection services)
{
// Formatting
services.AddSingleton<RazorFormattingService, DefaultRazorFormattingService>();
// Formatting Passes
services.AddSingleton<IFormattingPass, HtmlFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpOnTypeFormattingPass>();
services.AddSingleton<IFormattingPass, FormattingDiagnosticValidationPass>();
services.AddSingleton<IFormattingPass, FormattingContentValidationPass>();
services.AddSingleton<IFormattingPass, RazorFormattingPass>();
services.AddRegisteringHandler<RazorDocumentFormattingEndpoint>();
services.AddRegisteringHandler<RazorDocumentOnTypeFormattingEndpoint>();
services.AddRegisteringHandler<RazorDocumentRangeFormattingEndpoint>();
}
public static void AddCompletionServices(this IServiceCollection services, LanguageServerFeatureOptions featureOptions)
{
services.AddRegisteringHandler<InlineCompletionEndpoint>();
if (featureOptions.SingleServerCompletionSupport)
{
services.AddRegisteringHandler<RazorCompletionEndpoint>();
services.AddRegisteringHandler<RazorCompletionResolveEndpoint>();
}
else
{
services.AddRegisteringHandler<LegacyRazorCompletionEndpoint>();
services.AddHandler<LegacyRazorCompletionResolveEndpoint>();
}
services.AddSingleton<CompletionListCache>();
services.AddSingleton<AggregateCompletionListProvider>();
services.AddSingleton<CompletionListProvider, DelegatedCompletionListProvider>();
services.AddSingleton<CompletionListProvider, RazorCompletionListProvider>();
services.AddSingleton<DelegatedCompletionResponseRewriter, TextEditResponseRewriter>();
services.AddSingleton<DelegatedCompletionResponseRewriter, DesignTimeHelperResponseRewriter>();
services.AddSingleton<AggregateCompletionItemResolver>();
services.AddSingleton<CompletionItemResolver, RazorCompletionItemResolver>();
services.AddSingleton<CompletionItemResolver, DelegatedCompletionItemResolver>();
services.AddSingleton<TagHelperCompletionService, LanguageServerTagHelperCompletionService>();
services.AddSingleton<RazorCompletionFactsService, DefaultRazorCompletionFactsService>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, TagHelperCompletionProvider>();
}
public static void AddHoverServices(this IServiceCollection services)
{
services.AddRegisteringHandler<RazorHoverEndpoint>();
services.AddSingleton<RazorHoverInfoService, DefaultRazorHoverInfoService>();
}
public static void AddSemanticTokensServices(this IServiceCollection services)
{
services.AddRegisteringHandler<RazorSemanticTokensEndpoint>();
services.AddRegisteringHandler<SemanticTokensRefreshEndpoint>();
services.AddSingleton<WorkspaceSemanticTokensRefreshPublisher, DefaultWorkspaceSemanticTokensRefreshPublisher>();
services.AddSingleton<ProjectSnapshotChangeTrigger, DefaultWorkspaceSemanticTokensRefreshTrigger>();
services.AddSingleton<RazorSemanticTokensInfoService, DefaultRazorSemanticTokensInfoService>();
}
public static void AddCodeActionsServices(this IServiceCollection services)
{
services.AddRegisteringHandler<CodeActionEndpoint>();
services.AddHandler<CodeActionResolutionEndpoint>();
// CSharp Code actions
services.AddSingleton<CSharpCodeActionProvider, TypeAccessibilityCodeActionProvider>();
services.AddSingleton<CSharpCodeActionProvider, DefaultCSharpCodeActionProvider>();
services.AddSingleton<CSharpCodeActionResolver, DefaultCSharpCodeActionResolver>();
services.AddSingleton<CSharpCodeActionResolver, AddUsingsCSharpCodeActionResolver>();
services.AddSingleton<CSharpCodeActionResolver, UnformattedRemappingCSharpCodeActionResolver>();
// Razor Code actions
services.AddSingleton<RazorCodeActionProvider, ExtractToCodeBehindCodeActionProvider>();
services.AddSingleton<RazorCodeActionResolver, ExtractToCodeBehindCodeActionResolver>();
services.AddSingleton<RazorCodeActionProvider, ComponentAccessibilityCodeActionProvider>();
services.AddSingleton<RazorCodeActionResolver, CreateComponentCodeActionResolver>();
services.AddSingleton<RazorCodeActionResolver, AddUsingsCodeActionResolver>();
}
public static void AddTextDocumentServices(this IServiceCollection services)
{
services.AddRegisteringHandler<TextDocumentTextPresentationEndpoint>();
services.AddRegisteringHandler<TextDocumentUriPresentationEndpoint>();
services.AddRegisteringHandler<RazorDidChangeTextDocumentEndpoint>();
services.AddHandler<RazorDidCloseTextDocumentEndpoint>();
services.AddHandler<RazorDidOpenTextDocumentEndpoint>();
services.AddHandler<RazorMapToDocumentRangesEndpoint>();
}
public static void AddOptionsServices(this IServiceCollection services)
{
services.AddSingleton<RazorConfigurationService, DefaultRazorConfigurationService>();
services.AddSingleton<RazorLSPOptionsMonitor>();
services.AddSingleton<IOptionsMonitor<RazorLSPOptions>, RazorLSPOptionsMonitor>();
}
public static void AddDocumentManagmentServices(this IServiceCollection services)
{
services.AddSingleton<GeneratedDocumentPublisher, DefaultGeneratedDocumentPublisher>();
services.AddSingleton<ProjectSnapshotChangeTrigger>((services) => services.GetRequiredService<GeneratedDocumentPublisher>());
services.AddSingleton<DocumentContextFactory, DefaultDocumentContextFactory>();
services.AddSingleton<FilePathNormalizer>();
services.AddSingleton<DocumentVersionCache, DefaultDocumentVersionCache>();
services.AddSingleton<ProjectSnapshotChangeTrigger>((services) => services.GetRequiredService<DocumentVersionCache>());
services.AddSingleton<RemoteTextLoaderFactory, DefaultRemoteTextLoaderFactory>();
services.AddSingleton<ProjectResolver, DefaultProjectResolver>();
services.AddSingleton<DocumentResolver, DefaultDocumentResolver>();
services.AddSingleton<RazorProjectService, DefaultRazorProjectService>();
services.AddSingleton<ProjectSnapshotChangeTrigger, OpenDocumentGenerator>();
services.AddSingleton<RazorDocumentMappingService, DefaultRazorDocumentMappingService>();
services.AddSingleton<RazorFileChangeDetectorManager>();
// File change listeners
services.AddSingleton<IProjectConfigurationFileChangeListener, ProjectConfigurationStateSynchronizer>();
services.AddSingleton<IProjectFileChangeListener, ProjectFileSynchronizer>();
services.AddSingleton<IRazorFileChangeListener, RazorFileSynchronizer>();
// File Change detectors
services.AddSingleton<IFileChangeDetector, ProjectConfigurationFileChangeDetector>();
services.AddSingleton<IFileChangeDetector, ProjectFileChangeDetector>();
services.AddSingleton<IFileChangeDetector, RazorFileChangeDetector>();
// Document processed listeners
services.AddSingleton<DocumentProcessedListener, RazorDiagnosticsPublisher>();
services.AddSingleton<DocumentProcessedListener, GeneratedDocumentSynchronizer>();
services.AddSingleton<DocumentProcessedListener, CodeDocumentReferenceHolder>();
services.AddSingleton<ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>();
services.AddSingleton<TagHelperFactsService, DefaultTagHelperFactsService>();
services.AddSingleton<LSPTagHelperTooltipFactory, DefaultLSPTagHelperTooltipFactory>();
services.AddSingleton<VSLSPTagHelperTooltipFactory, DefaultVSLSPTagHelperTooltipFactory>();
}
public static void AddRegisteringHandler<T>(this IServiceCollection services)
where T : class, IMethodHandler, IRegistrationExtension
{
services.AddSingleton<T>();
services.AddSingleton<IMethodHandler, T>(s => s.GetRequiredService<T>());
// Transient because it should only be used once and I'm hoping it doesn't stick around.
services.AddTransient<IRegistrationExtension, T>(s => s.GetRequiredService<T>());
}
public static void AddHandler<T>(this IServiceCollection services)
where T : class, IMethodHandler
{
if (typeof(IRegistrationExtension).IsAssignableFrom(typeof(T)))
{
throw new NotImplementedException($"{nameof(T)} is not using {nameof(AddRegisteringHandler)} when it implements {nameof(IRegistrationExtension)}");
}
services.AddSingleton<IMethodHandler, T>();
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
internal static class VSInternalClientCapabilitiesExtensions
{
internal static VSInternalClientCapabilities ToVSInternalClientCapabilities(this ClientCapabilities clientCapabilities)
{
if (clientCapabilities is VSInternalClientCapabilities vSInternalClientCapabilities)
{
return vSInternalClientCapabilities;
}
return new VSInternalClientCapabilities()
{
TextDocument = clientCapabilities.TextDocument,
SupportsVisualStudioExtensions = false,
Experimental = clientCapabilities.Experimental,
Workspace = clientCapabilities.Workspace,
};
}
}

Просмотреть файл

@ -1,14 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.VisualStudio.Editor.Razor
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
internal abstract class RazorUIContextManager
internal interface IOnInitialized
{
public abstract Task SetUIContextAsync(Guid guid, bool isActive, CancellationToken cancellationToken);
Task OnInitializedAsync(CancellationToken cancellationToken);
}
}

Просмотреть файл

@ -1,100 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Threading;
using OmniSharp.Extensions.JsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer.JsonRpc
{
internal class JsonRpcRequestScheduler : IDisposable
{
private readonly Task _processingQueueTask;
private readonly AsyncQueue<QueueItem> _queue;
private readonly CancellationTokenSource _disposedCancellationTokenSource;
private readonly ILogger<JsonRpcRequestScheduler> _logger;
public JsonRpcRequestScheduler(ILoggerFactory loggerFactory)
{
_disposedCancellationTokenSource = new CancellationTokenSource();
_logger = loggerFactory.CreateLogger<JsonRpcRequestScheduler>();
_queue = new AsyncQueue<QueueItem>();
// Start the queue processing
_processingQueueTask = ProcessQueueAsync();
}
public bool Schedule(RequestProcessType type, string identifier, ProcessSchedulerDelegate processAsync)
{
var queueItem = new QueueItem(type, identifier, processAsync);
// Try and enqueue item, if this fails it means we're tearing down.
var enqueued = _queue.TryEnqueue(queueItem);
return enqueued;
}
public void Dispose()
{
if (_disposedCancellationTokenSource.IsCancellationRequested)
{
return;
}
_disposedCancellationTokenSource.Cancel();
}
private async Task ProcessQueueAsync()
{
try
{
while (!_disposedCancellationTokenSource.Token.IsCancellationRequested)
{
var work = await _queue.DequeueAsync(_disposedCancellationTokenSource.Token).ConfigureAwait(false);
_logger.LogDebug("Queueing {Type} {Identifier} request for processing", work.Type, work.Identifier);
if (work.Type == RequestProcessType.Serial)
{
// Serial requests block other requests from starting to ensure up-to-date state is used.
await work.ProcessAsync(_disposedCancellationTokenSource.Token).ConfigureAwait(false);
}
else
{
_ = Task.Run(() => work.ProcessAsync(_disposedCancellationTokenSource.Token), _disposedCancellationTokenSource.Token);
}
}
}
catch (OperationCanceledException)
{
// We're shutting down
}
catch (Exception e)
{
_logger.LogCritical("Work queue threw an uncaught exception. Stopping processing: {exceptionMessage}", e.Message);
}
}
private record QueueItem(RequestProcessType Type, string Identifier, ProcessSchedulerDelegate ProcessAsync);
public delegate Task ProcessSchedulerDelegate(CancellationToken cancellationToken);
public TestAccessor GetTestAccessor() => new TestAccessor(this);
public class TestAccessor
{
private readonly JsonRpcRequestScheduler _requestScheduler;
public TestAccessor(JsonRpcRequestScheduler requestScheduler)
{
_requestScheduler = requestScheduler;
}
#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
public Task CompleteWorkAsync() => _requestScheduler._processingQueueTask;
#pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
}
}
}

Просмотреть файл

@ -1,154 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.JsonRpc.Server;
using OmniSharp.Extensions.JsonRpc.Server.Messages;
using static Microsoft.AspNetCore.Razor.LanguageServer.JsonRpc.JsonRpcRequestScheduler;
namespace Microsoft.AspNetCore.Razor.LanguageServer.JsonRpc
{
internal class RazorOmniSharpRequestInvoker : RequestInvoker
{
private readonly TimeSpan _requestTimeout;
private readonly IOutputHandler _outputHandler;
private readonly IRequestRouter<IHandlerDescriptor?> _requestRouter;
private readonly IRequestProcessIdentifier _requestProcessIdentifier;
private readonly JsonRpcRequestScheduler _requestScheduler;
private readonly ILogger<RazorOmniSharpRequestInvoker> _logger;
public RazorOmniSharpRequestInvoker(
RequestInvokerOptions options,
IOutputHandler outputHandler,
IRequestRouter<IHandlerDescriptor?> requestRouter,
IRequestProcessIdentifier requestProcessIdentifier,
ILoggerFactory loggerFactory)
{
_requestTimeout = options.RequestTimeout;
_outputHandler = outputHandler;
_requestRouter = requestRouter;
_requestProcessIdentifier = requestProcessIdentifier;
_requestScheduler = new JsonRpcRequestScheduler(loggerFactory);
_logger = loggerFactory.CreateLogger<RazorOmniSharpRequestInvoker>();
}
public override RequestInvocationHandle InvokeRequest(IRequestDescriptor<IHandlerDescriptor?> descriptor, Request request)
{
if (descriptor.Default is null)
{
throw new ArgumentNullException(nameof(descriptor.Default));
}
var handle = new RequestInvocationHandle(request);
var type = _requestProcessIdentifier.Identify(descriptor.Default);
var schedulerDelegate = BuildRequestDelegate(descriptor, request, handle);
_requestScheduler.Schedule(type, $"{request.Method}:{request.Id}", schedulerDelegate);
return handle;
}
public override void InvokeNotification(IRequestDescriptor<IHandlerDescriptor?> descriptor, Notification notification)
{
if (descriptor.Default is null)
{
throw new ArgumentNullException(nameof(descriptor.Default));
}
var type = _requestProcessIdentifier.Identify(descriptor.Default);
var schedulerDelegate = BuildNotificationDelegate(descriptor, notification);
_requestScheduler.Schedule(type, notification.Method, schedulerDelegate);
}
public override void Dispose()
{
_requestScheduler.Dispose();
}
private ProcessSchedulerDelegate BuildRequestDelegate(IRequestDescriptor<IHandlerDescriptor?> descriptors, Request request, RequestInvocationHandle handle)
{
return async (cancellationToken) =>
{
try
{
var result = await InvokeRequestAsync(cancellationToken).ConfigureAwait(false);
_outputHandler.Send(result.Value);
}
finally
{
handle.Dispose();
}
};
async Task<ErrorResponse> InvokeRequestAsync(CancellationToken cancellationToken)
{
using var timeoutCts = new CancellationTokenSource(_requestTimeout);
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(handle.CancellationTokenSource.Token, timeoutCts.Token, cancellationToken);
using var timer = _logger.TimeDebug("Processing request {Method}:{Id}", request.Method, request.Id);
try
{
var result = await _requestRouter.RouteRequest(descriptors, request, combinedCts.Token).ConfigureAwait(false);
return result;
}
catch (OperationCanceledException)
{
if (timeoutCts.IsCancellationRequested)
{
_logger.LogTrace("Request {Method}:{Id} was cancelled, due to timeout", request.Method, request.Id);
return new RequestCancelled(request.Id, request.Method);
}
_logger.LogTrace("Request {Method}:{Id} was cancelled", request.Method, request.Id);
return new RequestCancelled(request.Id, request.Method);
}
catch (RpcErrorException e)
{
_logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}", request.Method, request.Id);
return new RpcError(
request.Id,
request.Method,
new ErrorMessage(e.Code, e.Message, e.Error));
}
catch (Exception e)
{
_logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle request {Method}:{Id}. Unhandled exception", request.Method, request.Id);
return new InternalError(request.Id, request.Method, e.ToString());
}
}
}
private ProcessSchedulerDelegate BuildNotificationDelegate(IRequestDescriptor<IHandlerDescriptor?> descriptors, Notification notification)
{
return async (cancellationToken) =>
{
using var timeoutCts = new CancellationTokenSource(_requestTimeout);
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken);
using var timer = _logger.TimeDebug("Processing notification {Method}", notification.Method);
try
{
await _requestRouter.RouteNotification(descriptors, notification, combinedCts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
if (timeoutCts.IsCancellationRequested)
{
_logger.LogTrace("Notification {Method} was cancelled due to timeout", notification.Method);
return;
}
_logger.LogTrace("Notification {Method} was cancelled", notification.Method);
}
catch (Exception e)
{
_logger.LogCritical(Events.UnhandledRequest, e, "Failed to handle notification {Method}", notification.Method);
}
};
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal class LspServices : ILspServices
{
private readonly IServiceProvider _serviceProvider;
public LspServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<ILspServices>(this);
_serviceProvider = serviceCollection.BuildServiceProvider();
}
public ImmutableArray<Type> GetRegisteredServices()
{
throw new NotImplementedException();
}
public T GetRequiredService<T>() where T : notnull
{
return _serviceProvider.GetRequiredService<T>();
}
public IEnumerable<T> GetRequiredServices<T>()
{
var services = _serviceProvider.GetServices<T>();
if (services is null)
{
throw new ArgumentNullException($"Missing services {nameof(T)}");
}
return services;
}
public object? TryGetService(Type type)
{
var service = _serviceProvider.GetService(type);
return service;
}
public bool SupportsGetRegisteredServices()
{
return false;
}
public void Dispose()
{
}
}

Просмотреть файл

@ -14,10 +14,9 @@
<ItemGroup>
<!-- Need this reference to avoid 'The C# language is not supported' error during formatting. -->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(Tooling_MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion)" />
<PackageReference Include="OmniSharp.Extensions.LanguageProtocol" Version="$(OmniSharpExtensionsLanguageProtocolPackageVersion)" />
<PackageReference Include="Microsoft.CommonLanguageServerProtocol.Framework" Version="$(RoslynPackageVersion)" />
<!-- We hide these dependencies from consumers because they're implementation details and aren't required to interact with the language server. -->
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="$(OmniSharpExtensionsLanguageServerPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsPackageVersion)" PrivateAssets="All" />

Просмотреть файл

@ -2,363 +2,141 @@
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert;
using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.LanguageServer.Completion;
using Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation;
using Microsoft.AspNetCore.Razor.LanguageServer.Debugging;
using Microsoft.AspNetCore.Razor.LanguageServer.Definition;
using Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics;
using Microsoft.AspNetCore.Razor.LanguageServer.DocumentColor;
using Microsoft.AspNetCore.Razor.LanguageServer.DocumentHighlighting;
using Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.LanguageServer.Folding;
using Microsoft.AspNetCore.Razor.LanguageServer.Formatting;
using Microsoft.AspNetCore.Razor.LanguageServer.Hover;
using Microsoft.AspNetCore.Razor.LanguageServer.Implementation;
using Microsoft.AspNetCore.Razor.LanguageServer.JsonRpc;
using Microsoft.AspNetCore.Razor.LanguageServer.LinkedEditingRange;
using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem;
using Microsoft.AspNetCore.Razor.LanguageServer.Refactoring;
using Microsoft.AspNetCore.Razor.LanguageServer.Semantic;
using Microsoft.AspNetCore.Razor.LanguageServer.Serialization;
using Microsoft.AspNetCore.Razor.LanguageServer.SignatureHelp;
using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip;
using Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Completion;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.Editor.Razor;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Server;
using StreamJsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal class RazorLanguageServer : AbstractLanguageServer<RazorRequestContext>
{
internal sealed class RazorLanguageServer : IDisposable
private readonly JsonRpc _jsonRpc;
private readonly LanguageServerFeatureOptions? _featureOptions;
private readonly ProjectSnapshotManagerDispatcher? _projectSnapshotManagerDispatcher;
private readonly Action<IServiceCollection>? _configureServer;
private readonly TaskCompletionSource<int> _tcs = new();
public RazorLanguageServer(
JsonRpc jsonRpc,
ILspLogger logger,
ProjectSnapshotManagerDispatcher? projectSnapshotManagerDispatcher,
LanguageServerFeatureOptions? featureOptions,
Action<IServiceCollection>? configureServer)
: base(jsonRpc, logger)
{
private readonly ILanguageServer _innerServer;
private readonly object _disposeLock;
private bool _disposed;
_jsonRpc = jsonRpc;
_featureOptions = featureOptions;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_configureServer = configureServer;
}
private RazorLanguageServer(ILanguageServer innerServer)
protected override ILspServices ConstructLspServices()
{
var services = new ServiceCollection()
.AddOptions()
.AddLogging();
if (_configureServer is not null)
{
if (innerServer is null)
{
throw new ArgumentNullException(nameof(innerServer));
}
_innerServer = innerServer;
_disposeLock = new object();
_configureServer(services);
}
public IObservable<bool> OnShutdown => _innerServer.Shutdown;
services.AddSingleton<ILspLogger>(RazorLspLogger.Instance);
services.AddSingleton<ErrorReporter, LanguageServerErrorReporter>();
public Task WaitForExit => _innerServer.WaitForExit;
public Task InitializedAsync(CancellationToken token) => _innerServer.Initialize(token);
public static Task<RazorLanguageServer> CreateAsync(Stream input, Stream output, Trace trace, LanguageServerFeatureOptions? featureOptions = null, Action<RazorLanguageServerBuilder>? configure = null)
if (_projectSnapshotManagerDispatcher is null)
{
var serializer = new LspSerializer();
serializer.RegisterRazorConverters();
serializer.RegisterVSInternalExtensionConverters();
ILanguageServer? server = null;
var logLevel = RazorLSPOptions.GetLogLevelForTrace(trace);
var initializedCompletionSource = new TaskCompletionSource<bool>();
server = OmniSharp.Extensions.LanguageServer.Server.LanguageServer.PreInit(options =>
options
.WithInput(input)
.WithOutput(output)
// StreamJsonRpc has both Serial and Parallel requests. With WithContentModifiedSupport(true) (which is default) when a Serial
// request is made any Parallel requests will be cancelled because the assumption is that Serial requests modify state, and that
// therefore any Parallel request is now invalid and should just try again. A specific instance of this can be seen when you
// hover over a TagHelper while the switch is set to true. Hover is parallel, and a lot of our endpoints like
// textDocument/_vs_onAutoInsert, and razor/languageQuery are Serial. I BELIEVE that specifically what happened is the serial
// languageQuery event gets fired by our semantic tokens endpoint (which fires constantly), cancelling the hover, which red-bars.
// We can prevent that behavior entirely by doing WithContentModifiedSupport, at the possible expense of some delays due doing all requests in serial.
//
// I recommend that we attempt to resolve this and switch back to WithContentModifiedSupport(true) in the future,
// I think that would mean either having 0 Serial Handlers in the whole LS, or making VSLanguageServerClient handle this more gracefully.
.WithContentModifiedSupport(false)
.WithSerializer(serializer)
.OnInitialized(async (s, request, response, cancellationToken) =>
{
var handlersManager = s.GetRequiredService<IHandlersManager>();
var jsonRpcHandlers = handlersManager.Descriptors.Select(d => d.Handler);
var registrationExtensions = jsonRpcHandlers.OfType<IRegistrationExtension>().Distinct();
var vsCapabilities = s.ClientSettings.Capabilities.ToVSClientCapabilities(serializer);
foreach (var registrationExtension in registrationExtensions)
{
var optionsResult = registrationExtension.GetRegistration(vsCapabilities);
if (optionsResult != null)
{
response.Capabilities.ExtensionData[optionsResult.ServerCapability] = JToken.FromObject(optionsResult.Options);
}
}
RazorLanguageServerCapability.AddTo(response.Capabilities);
var fileChangeDetectorManager = s.Services.GetRequiredService<RazorFileChangeDetectorManager>();
await fileChangeDetectorManager.InitializedAsync();
// Workaround for https://github.com/OmniSharp/csharp-language-server-protocol/issues/106
var languageServer = (OmniSharp.Extensions.LanguageServer.Server.LanguageServer)server!;
if (request.Capabilities?.Workspace?.Configuration.IsSupported == true)
{
// Initialize our options for the first time.
var optionsMonitor = languageServer.Services.GetRequiredService<RazorLSPOptionsMonitor>();
// Explicitly not passing in the same CancellationToken as that might get cancelled before the update happens.
_ = Task.Delay(TimeSpan.FromSeconds(3), CancellationToken.None)
.ContinueWith(async (_) => await optionsMonitor.UpdateAsync(), TaskScheduler.Default);
}
})
.WithHandler<RazorDocumentSynchronizationEndpoint>()
// These two are specifically commented out / manually added in the services below based on feature options (for now)
//.WithHandler<RazorCompletionEndpoint>()
//.WithHandler<RazorCompletionResolveEndpoint>()
.WithHandler<RazorHoverEndpoint>()
.WithHandler<RazorLanguageEndpoint>()
.WithHandler<RazorDiagnosticsEndpoint>()
.WithHandler<RazorConfigurationEndpoint>()
.WithHandler<RazorDocumentFormattingEndpoint>()
.WithHandler<RazorDocumentOnTypeFormattingEndpoint>()
.WithHandler<RazorDocumentRangeFormattingEndpoint>()
.WithHandler<RazorSemanticTokensEndpoint>()
.WithHandler<SemanticTokensRefreshEndpoint>()
.WithHandler<OnAutoInsertEndpoint>()
.WithHandler<CodeActionEndpoint>()
.WithHandler<CodeActionResolutionEndpoint>()
.WithHandler<MonitorProjectConfigurationFilePathEndpoint>()
.WithHandler<RenameEndpoint>()
.WithHandler<RazorDefinitionEndpoint>()
.WithHandler<LinkedEditingRangeEndpoint>()
.WithHandler<WrapWithTagEndpoint>()
.WithHandler<InlineCompletionEndpoint>()
.WithHandler<RazorBreakpointSpanEndpoint>()
.WithHandler<RazorProximityExpressionsEndpoint>()
.WithHandler<DocumentColorEndpoint>()
.WithHandler<FoldingRangeEndpoint>()
.WithHandler<TextDocumentTextPresentationEndpoint>()
.WithHandler<TextDocumentUriPresentationEndpoint>()
.WithHandler<DocumentHighlightEndpoint>()
.WithHandler<SignatureHelpEndpoint>()
.WithHandler<ImplementationEndpoint>()
.WithServices(services =>
{
featureOptions ??= new DefaultLanguageServerFeatureOptions();
services.AddSingleton(featureOptions);
if (featureOptions.SingleServerCompletionSupport)
{
options.WithHandler<RazorCompletionEndpoint>();
options.WithHandler<RazorCompletionResolveEndpoint>();
}
else
{
options.WithHandler<LegacyRazorCompletionEndpoint>();
options.WithHandler<LegacyRazorCompletionResolveEndpoint>();
}
services.AddLogging(builder => builder
.SetMinimumLevel(logLevel)
.AddLanguageProtocolLogging());
services.AddSingleton<ErrorReporter, LanguageServerErrorReporter>();
services.AddSingleton<RequestInvoker, RazorOmniSharpRequestInvoker>();
services.AddSingleton<DocumentContextFactory, DefaultDocumentContextFactory>();
services.AddSingleton<FilePathNormalizer>();
services.AddSingleton<ProjectSnapshotManagerDispatcher, LSPProjectSnapshotManagerDispatcher>();
services.AddSingleton<GeneratedDocumentPublisher, DefaultGeneratedDocumentPublisher>();
services.AddSingleton<AdhocWorkspaceFactory, DefaultAdhocWorkspaceFactory>();
services.AddSingleton<ProjectSnapshotChangeTrigger>((services) => services.GetRequiredService<GeneratedDocumentPublisher>());
services.AddSingleton<WorkspaceSemanticTokensRefreshPublisher, DefaultWorkspaceSemanticTokensRefreshPublisher>();
services.AddSingleton<ProjectSnapshotChangeTrigger, DefaultWorkspaceSemanticTokensRefreshTrigger>();
services.AddSingleton<DocumentVersionCache, DefaultDocumentVersionCache>();
services.AddSingleton<ProjectSnapshotChangeTrigger>((services) => services.GetRequiredService<DocumentVersionCache>());
services.AddSingleton<RemoteTextLoaderFactory, DefaultRemoteTextLoaderFactory>();
services.AddSingleton<ProjectResolver, DefaultProjectResolver>();
services.AddSingleton<DocumentResolver, DefaultDocumentResolver>();
services.AddSingleton<RazorProjectService, DefaultRazorProjectService>();
services.AddSingleton<ProjectSnapshotChangeTrigger, OpenDocumentGenerator>();
services.AddSingleton<RazorDocumentMappingService, DefaultRazorDocumentMappingService>();
services.AddSingleton<RazorFileChangeDetectorManager>();
services.AddSingleton<ProjectSnapshotChangeTrigger, RazorServerReadyPublisher>();
services.AddSingleton<ClientNotifierServiceBase, DefaultClientNotifierService>();
services.AddSingleton<IOnLanguageServerStarted, DefaultClientNotifierService>();
// Options
services.AddSingleton<RazorConfigurationService, DefaultRazorConfigurationService>();
services.AddSingleton<RazorLSPOptionsMonitor>();
services.AddSingleton<IOptionsMonitor<RazorLSPOptions>, RazorLSPOptionsMonitor>();
// File change listeners
services.AddSingleton<IProjectConfigurationFileChangeListener, ProjectConfigurationStateSynchronizer>();
services.AddSingleton<IProjectFileChangeListener, ProjectFileSynchronizer>();
services.AddSingleton<IRazorFileChangeListener, RazorFileSynchronizer>();
// File Change detectors
services.AddSingleton<IFileChangeDetector, ProjectConfigurationFileChangeDetector>();
services.AddSingleton<IFileChangeDetector, ProjectFileChangeDetector>();
services.AddSingleton<IFileChangeDetector, RazorFileChangeDetector>();
// Document processed listeners
services.AddSingleton<DocumentProcessedListener, RazorDiagnosticsPublisher>();
services.AddSingleton<DocumentProcessedListener, GeneratedDocumentSynchronizer>();
services.AddSingleton<DocumentProcessedListener, CodeDocumentReferenceHolder>();
services.AddSingleton<ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>();
services.AddSingleton<TagHelperFactsService, DefaultTagHelperFactsService>();
services.AddSingleton<LSPTagHelperTooltipFactory, DefaultLSPTagHelperTooltipFactory>();
services.AddSingleton<VSLSPTagHelperTooltipFactory, DefaultVSLSPTagHelperTooltipFactory>();
// Completion
services.AddSingleton<CompletionListCache>();
services.AddSingleton<AggregateCompletionListProvider>();
services.AddSingleton<CompletionListProvider, DelegatedCompletionListProvider>();
services.AddSingleton<CompletionListProvider, RazorCompletionListProvider>();
services.AddSingleton<DelegatedCompletionResponseRewriter, TextEditResponseRewriter>();
services.AddSingleton<DelegatedCompletionResponseRewriter, DesignTimeHelperResponseRewriter>();
services.AddSingleton<AggregateCompletionItemResolver>();
services.AddSingleton<CompletionItemResolver, RazorCompletionItemResolver>();
services.AddSingleton<CompletionItemResolver, DelegatedCompletionItemResolver>();
services.AddSingleton<TagHelperCompletionService, LanguageServerTagHelperCompletionService>();
services.AddSingleton<RazorCompletionFactsService, DefaultRazorCompletionFactsService>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>();
services.AddSingleton<RazorCompletionItemProvider, TagHelperCompletionProvider>();
// Auto insert
services.AddSingleton<RazorOnAutoInsertProvider, CloseTextTagOnAutoInsertProvider>();
services.AddSingleton<RazorOnAutoInsertProvider, AutoClosingTagOnAutoInsertProvider>();
// Folding Range Providers
services.AddSingleton<RazorFoldingRangeProvider, RazorCodeBlockFoldingProvider>();
// Formatting
services.AddSingleton<RazorFormattingService, DefaultRazorFormattingService>();
// Formatting Passes
services.AddSingleton<IFormattingPass, HtmlFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpFormattingPass>();
services.AddSingleton<IFormattingPass, CSharpOnTypeFormattingPass>();
services.AddSingleton<IFormattingPass, FormattingDiagnosticValidationPass>();
services.AddSingleton<IFormattingPass, FormattingContentValidationPass>();
services.AddSingleton<IFormattingPass, RazorFormattingPass>();
// Razor Code actions
services.AddSingleton<RazorCodeActionProvider, ExtractToCodeBehindCodeActionProvider>();
services.AddSingleton<RazorCodeActionResolver, ExtractToCodeBehindCodeActionResolver>();
services.AddSingleton<RazorCodeActionProvider, ComponentAccessibilityCodeActionProvider>();
services.AddSingleton<RazorCodeActionResolver, CreateComponentCodeActionResolver>();
services.AddSingleton<RazorCodeActionResolver, AddUsingsCodeActionResolver>();
// CSharp Code actions
services.AddSingleton<CSharpCodeActionProvider, TypeAccessibilityCodeActionProvider>();
services.AddSingleton<CSharpCodeActionProvider, DefaultCSharpCodeActionProvider>();
services.AddSingleton<CSharpCodeActionResolver, DefaultCSharpCodeActionResolver>();
services.AddSingleton<CSharpCodeActionResolver, AddUsingsCSharpCodeActionResolver>();
services.AddSingleton<CSharpCodeActionResolver, UnformattedRemappingCSharpCodeActionResolver>();
// Other
services.AddSingleton<RazorSemanticTokensInfoService, DefaultRazorSemanticTokensInfoService>();
services.AddSingleton<RazorHoverInfoService, DefaultRazorHoverInfoService>();
services.AddSingleton<HtmlFactsService, DefaultHtmlFactsService>();
services.AddSingleton<WorkspaceDirectoryPathResolver, DefaultWorkspaceDirectoryPathResolver>();
services.AddSingleton<RazorComponentSearchEngine, DefaultRazorComponentSearchEngine>();
if (configure != null)
{
var builder = new RazorLanguageServerBuilder(services);
configure(builder);
}
// Defaults: For when the caller hasn't provided them through the `configure` action.
services.TryAddSingleton<HostServicesProvider, DefaultHostServicesProvider>();
}));
try
{
var factory = new LoggerFactory();
var logger = factory.CreateLogger<RazorLanguageServer>();
var assemblyInformationAttribute = typeof(RazorLanguageServer).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
logger.LogInformation("Razor Language Server version {RazorVersion}", assemblyInformationAttribute.InformationalVersion);
factory.Dispose();
}
catch
{
// Swallow exceptions from determining assembly information.
}
var razorLanguageServer = new RazorLanguageServer(server);
IDisposable? exitSubscription = null;
exitSubscription = server.Exit.Subscribe((_) =>
{
exitSubscription!.Dispose();
razorLanguageServer.Dispose();
});
return Task.FromResult(razorLanguageServer);
services.AddSingleton<ProjectSnapshotManagerDispatcher, LSPProjectSnapshotManagerDispatcher>();
}
else
{
services.AddSingleton<ProjectSnapshotManagerDispatcher>(_projectSnapshotManagerDispatcher);
}
public void Dispose()
services.AddSingleton<AdhocWorkspaceFactory, DefaultAdhocWorkspaceFactory>();
var featureOptions = _featureOptions ?? new DefaultLanguageServerFeatureOptions();
services.AddSingleton(featureOptions);
services.AddLifeCycleServices(this, _jsonRpc);
services.AddSemanticTokensServices();
services.AddDocumentManagmentServices();
services.AddCompletionServices(featureOptions);
services.AddFormattingServices();
services.AddCodeActionsServices();
services.AddOptionsServices();
services.AddHoverServices();
services.AddTextDocumentServices();
// Auto insert
services.AddSingleton<RazorOnAutoInsertProvider, CloseTextTagOnAutoInsertProvider>();
services.AddSingleton<RazorOnAutoInsertProvider, AutoClosingTagOnAutoInsertProvider>();
// Folding Range Providers
services.AddSingleton<RazorFoldingRangeProvider, RazorCodeBlockFoldingProvider>();
// Other
services.AddSingleton<HtmlFactsService, DefaultHtmlFactsService>();
services.AddSingleton<WorkspaceDirectoryPathResolver, DefaultWorkspaceDirectoryPathResolver>();
services.AddSingleton<RazorComponentSearchEngine, DefaultRazorComponentSearchEngine>();
// Folding Range Providers
services.AddSingleton<RazorFoldingRangeProvider, RazorCodeBlockFoldingProvider>();
AddHandlers(services, _featureOptions);
var lspServices = new LspServices(services);
return lspServices;
static void AddHandlers(IServiceCollection services, LanguageServerFeatureOptions? featureOptions)
{
lock (_disposeLock)
{
if (_disposed)
{
// Already disposed
return;
}
_disposed = true;
TempDirectory.Instance.Dispose();
_innerServer.Dispose();
// Disposing the server doesn't actually dispose the servers Services for whatever reason. We cast the services collection
// to IDisposable and try to dispose it ourselves to account for this.
var disposableServices = _innerServer.Services as IDisposable;
disposableServices?.Dispose();
}
}
// For testing purposes only.
internal ILanguageServer GetInnerLanguageServerForTesting()
{
return _innerServer;
services.AddHandler<RazorDiagnosticsEndpoint>();
services.AddHandler<RazorConfigurationEndpoint>();
services.AddRegisteringHandler<OnAutoInsertEndpoint>();
services.AddHandler<MonitorProjectConfigurationFilePathEndpoint>();
services.AddRegisteringHandler<RenameEndpoint>();
services.AddRegisteringHandler<RazorDefinitionEndpoint>();
services.AddRegisteringHandler<LinkedEditingRangeEndpoint>();
services.AddHandler<WrapWithTagEndpoint>();
services.AddHandler<RazorBreakpointSpanEndpoint>();
services.AddHandler<RazorProximityExpressionsEndpoint>();
services.AddRegisteringHandler<DocumentColorEndpoint>();
services.AddRegisteringHandler<FoldingRangeEndpoint>();
}
}
internal T GetRequiredService<T>() where T : notnull
{
var lspServices = GetLspServices();
return lspServices.GetRequiredService<T>();
}
public override Task ExitAsync()
{
var exit = base.ExitAsync();
_tcs.TrySetResult(0);
return exit;
}
internal Task WaitForExit => _tcs.Task;
}

Просмотреть файл

@ -0,0 +1,96 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Common.Extensions;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using StreamJsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
internal sealed class RazorLanguageServerWrapper : IAsyncDisposable
{
private readonly RazorLanguageServer _innerServer;
private readonly object _disposeLock;
private bool _disposed;
private RazorLanguageServerWrapper(RazorLanguageServer innerServer)
{
if (innerServer is null)
{
throw new ArgumentNullException(nameof(innerServer));
}
_innerServer = innerServer;
_disposeLock = new object();
}
public static async Task<RazorLanguageServerWrapper> CreateAsync(
Stream input,
Stream output,
Trace trace,
ProjectSnapshotManagerDispatcher? projectSnapshotManagerDispatcher = null,
Action<IServiceCollection>? configure = null,
LanguageServerFeatureOptions? featureOptions = null)
{
var logLevel = RazorLSPOptions.GetLogLevelForTrace(trace);
var logger = new RazorLspLogger();
var jsonRpc = CreateJsonRpc(input, output);
var server = new RazorLanguageServer(
jsonRpc,
logger,
projectSnapshotManagerDispatcher,
featureOptions,
configure);
var razorLanguageServer = new RazorLanguageServerWrapper(server);
await server.InitializeAsync();
jsonRpc.StartListening();
return razorLanguageServer;
}
private static JsonRpc CreateJsonRpc(Stream input, Stream output)
{
var messageFormatter = new JsonMessageFormatter();
messageFormatter.JsonSerializer.AddVSInternalExtensionConverters();
messageFormatter.JsonSerializer.Converters.RegisterRazorConverters();
var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(output, input, messageFormatter));
return jsonRpc;
}
internal T GetRequiredService<T>() where T : notnull
{
return _innerServer.GetRequiredService<T>();
}
public async ValueTask DisposeAsync()
{
await _innerServer.DisposeAsync();
lock (_disposeLock)
{
if (!_disposed)
{
_disposed = true;
TempDirectory.Instance.Dispose();
}
}
}
internal RazorLanguageServer GetInnerLanguageServerForTesting()
{
return _innerServer;
}
internal Task WaitForExit => _innerServer.WaitForExit;
}

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
internal class RazorRequestContextFactory : IRequestContextFactory<RazorRequestContext>
{
private readonly ILspServices _lspServices;
public RazorRequestContextFactory(ILspServices lspServices)
{
_lspServices = lspServices;
}
public async Task<RazorRequestContext> CreateRequestContextAsync<TRequestParams>(IQueueItem<RazorRequestContext> queueItem, TRequestParams @params, CancellationToken cancellationToken)
{
DocumentContext? documentContext = null;
var textDocumentHandler = queueItem.MethodHandler as ITextDocumentIdentifierHandler;
TextDocumentIdentifier? textDocumentIdentifier = null;
if (textDocumentHandler is not null)
{
if (textDocumentHandler is ITextDocumentIdentifierHandler<TRequestParams, TextDocumentIdentifier> tdiHandler)
{
textDocumentIdentifier = tdiHandler.GetTextDocumentIdentifier(@params);
}
else
{
throw new NotImplementedException();
}
}
if (textDocumentIdentifier is not null)
{
var documentContextFactory = _lspServices.GetRequiredService<DocumentContextFactory>();
documentContext = await documentContextFactory.TryCreateAsync(textDocumentIdentifier.Uri, cancellationToken);
}
var lspLogger = _lspServices.GetRequiredService<ILspLogger>();
var loggerFactory = _lspServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger(queueItem.MethodName);
var requestContext = new RazorRequestContext(documentContext, lspLogger, logger, _lspServices);
return requestContext;
}
}
}

Просмотреть файл

@ -1,84 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
internal class RazorServerReadyPublisher : ProjectSnapshotChangeTrigger
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private ProjectSnapshotManagerBase? _projectManager;
private readonly ClientNotifierServiceBase _clientNotifierService;
private bool _hasNotified = false;
public RazorServerReadyPublisher(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ClientNotifierServiceBase clientNotifierService)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (clientNotifierService is null)
{
throw new ArgumentNullException(nameof(clientNotifierService));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_clientNotifierService = clientNotifierService;
}
public override void Initialize(ProjectSnapshotManagerBase projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
_projectManager.Changed += ProjectSnapshotManager_Changed;
}
private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args)
{
_ = ProjectSnapshotManager_ChangedAsync(args, CancellationToken.None);
}
private async Task ProjectSnapshotManager_ChangedAsync(ProjectChangeEventArgs args, CancellationToken cancellationToken)
{
try
{
// Don't do any work if the solution is closing
if (args.SolutionIsClosing)
{
return;
}
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
var projectSnapshot = args.Newer;
if (projectSnapshot?.ProjectWorkspaceState != null && !_hasNotified)
{
// Un-register this method, we only need to send this once.
_projectManager!.Changed -= ProjectSnapshotManager_Changed;
var response = await _clientNotifierService.SendRequestAsync(RazorLanguageServerCustomMessageTargets.RazorServerReadyEndpoint);
await response.ReturningVoid(cancellationToken);
_hasNotified = true;
}
}
catch (Exception ex)
{
_projectManager?.ReportError(ex);
}
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.AspNetCore.Razor.LanguageServer;
public static class ServerCapabilitiesExtensions
{
private static readonly IReadOnlyDictionary<string, PropertyInfo> s_propertyMappings;
static ServerCapabilitiesExtensions()
{
var propertyInfos = typeof(VSInternalServerCapabilities).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var dictionary = new Dictionary<string, PropertyInfo>();
foreach (var propertyInfo in propertyInfos)
{
var dataMemeberAttribute = propertyInfo.GetCustomAttribute<DataMemberAttribute>();
var serverCapability = dataMemeberAttribute.Name;
dictionary[serverCapability] = propertyInfo;
}
s_propertyMappings = dictionary;
}
internal static void ApplyRegistrationResult(this VSInternalServerCapabilities serverCapabilities, RegistrationExtensionResult registrationExtensionResult)
{
var serverCapability = registrationExtensionResult.ServerCapability;
if (s_propertyMappings.ContainsKey(serverCapability))
{
var propertyInfo = s_propertyMappings[serverCapability];
propertyInfo.SetValue(serverCapabilities, registrationExtensionResult.Options);
}
else
{
serverCapabilities.Experimental ??= new Dictionary<string, object>();
var dict = (Dictionary<string, object>)serverCapabilities.Experimental;
dict[registrationExtensionResult.ServerCapability] = registrationExtensionResult.Options;
}
}
}

Просмотреть файл

@ -1,51 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Composition;
using System.Threading;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Threading;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
[Export(typeof(RazorUIContextManager))]
internal class VisualStudioWindowsRazorUIContextManager : RazorUIContextManager
{
private readonly IServiceProvider _serviceProvider;
private readonly JoinableTaskFactory _joinableTaskFactory;
[ImportingConstructor]
public VisualStudioWindowsRazorUIContextManager(SVsServiceProvider serviceProvider, JoinableTaskContext joinableTaskContext)
{
if (serviceProvider is null)
{
throw new ArgumentNullException(nameof(serviceProvider));
}
if (joinableTaskContext is null)
{
throw new ArgumentNullException(nameof(joinableTaskContext));
}
_serviceProvider = serviceProvider;
_joinableTaskFactory = joinableTaskContext.Factory;
}
public override async Task SetUIContextAsync(Guid uiContextGuid, bool isActive, CancellationToken cancellationToken)
{
await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
var monitorSelection = _serviceProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
Assumes.Present(monitorSelection);
var cookieResult = monitorSelection.GetCmdUIContextCookie(uiContextGuid, out var cookie);
ErrorHandler.ThrowOnFailure(cookieResult);
var setContextResult = monitorSelection.SetCmdUIContext(cookie, isActive ? 1 : 0);
ErrorHandler.ThrowOnFailure(setContextResult);
}
}
}

Просмотреть файл

@ -1,21 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Editor.Razor;
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
[Export(typeof(RazorUIContextManager))]
internal class VisualStudioMacRazorUIContextManager : RazorUIContextManager
{
public override Task SetUIContextAsync(Guid uiContextGuid, bool isActive, CancellationToken cancellationToken)
{
// UIContext's aren't a thing in VS4Mac.
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -58,9 +58,6 @@
<PackageReference Include="Microsoft.AspNetCore.Razor.Symbols.Transport" Version="$(MicrosoftAspNetCoreRazorSymbolsTransportPackageVersion)" GeneratePathProperty="true"/>
<PackageReference Include="Microsoft.CodeAnalysis.Razor.Tooling.Internal" Version="$(MicrosoftCodeAnalysisRazorToolingInternalPackageVersion)" GeneratePathProperty="true"/>
<PackageReference Include="Mono.Addins" Version="$(MonoAddinsPackageVersion)" />
<!-- We need to directly reference the O# language server here because we mark it as PrivateAssets="All" in our language server itself -->
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="$(OmniSharpExtensionsLanguageServerPackageVersion)" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -226,9 +226,6 @@
<PackageReference Include="System.Resources.Extensions" Version="$(SystemResourcesExtensionsPackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="$(MicrosoftVisualStudioShell150PackageVersion)" />
<!-- We need to directly reference the O# language server here because we mark it as PrivateAssets="All" in our language server itself -->
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="$(OmniSharpExtensionsLanguageServerPackageVersion)" />
<!--
Pinning packages to avoid misaligned reference CI failures.
CI builds here: https://github.com/dotnet/razor-tooling/issues/4327

Просмотреть файл

@ -46,8 +46,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftExtensionsPackageVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsPackageVersion)" PrivateAssets="All" />
<!-- We need to directly reference the O# language server here because we mark it as PrivateAssets="All" in our language server itself -->
<PackageReference Include="OmniSharp.Extensions.LanguageServer" Version="$(OmniSharpExtensionsLanguageServerPackageVersion)" />
<PackageReference Include="System.Private.Uri" Version="$(SystemPrivateUriPackageVersion)" ExcludeAssets="true" PrivateAssets="true" />
</ItemGroup>