public async Task GetLatestOptionsAsync_ReturnsExpectedOptions() { // Arrange var expectedOptions = new RazorLSPOptions(Trace.Messages, enableFormatting: false, autoClosingTags: false); var razorJsonString = @" { ""trace"": ""Messages"", ""format"": { ""enable"": ""false"" } } ".Trim(); var htmlJsonString = @" { ""format"": ""true"", ""autoClosingTags"": ""false"" } ".Trim(); var result = new JObject[] { JObject.Parse(razorJsonString), JObject.Parse(htmlJsonString) }; var languageServer = GetLanguageServer(new ResponseRouterReturns(result)); var configurationService = new DefaultRazorConfigurationService(languageServer, LoggerFactory); // Act var options = await configurationService.GetLatestOptionsAsync(CancellationToken.None); // Assert Assert.Equal(expectedOptions, options); }
public async Task UpdateAsync_DoesNotInvoke_OnChangeRegistration_AfterDispose() { // Arrange var expectedOptions = new RazorLSPOptions(Trace.Messages, enableFormatting: false, autoClosingTags: true); var configService = Mock.Of <RazorConfigurationService>(f => f.GetLatestOptionsAsync(CancellationToken.None) == Task.FromResult(expectedOptions)); var optionsMonitor = new RazorLSPOptionsMonitor(configService, Cache); var called = false; var onChangeToken = optionsMonitor.OnChange(options => { called = true; }); // Act 1 await optionsMonitor.UpdateAsync(CancellationToken.None); // Assert 1 Assert.True(called, "Registered callback was not called."); // Act 2 called = false; onChangeToken.Dispose(); await optionsMonitor.UpdateAsync(CancellationToken.None); // Assert 2 Assert.False(called, "Registered callback called even after dispose."); }
public void BuildOptions_ReturnsExpectedOptions() { // Arrange - purposely choosing options opposite of default var expectedOptions = new RazorLSPOptions( Trace.Verbose, enableFormatting: false, autoClosingTags: false, insertSpaces: false, tabSize: 8); var razorJsonString = @" { ""trace"": ""Verbose"", ""format"": { ""enable"": ""false"" } } ".Trim(); var htmlJsonString = @" { ""format"": ""true"", ""autoClosingTags"": ""false"" } ".Trim(); var vsEditorJsonString = @" { ""IndentSize"": 8, ""IndentWithTabs"": ""true"" } ".Trim(); // Act var result = new JObject[] { JObject.Parse(razorJsonString), JObject.Parse(htmlJsonString), JObject.Parse(vsEditorJsonString) }; var languageServer = GetLanguageServer(new ResponseRouterReturns(result)); var configurationService = new DefaultRazorConfigurationService(languageServer, LoggerFactory); var options = configurationService.BuildOptions(result); // Assert Assert.Equal(expectedOptions, options); }
public async Task UpdateAsync_Invokes_OnChangeRegistration() { // Arrange var expectedOptions = new RazorLSPOptions(Trace.Messages, enableFormatting: false, autoClosingTags: true, insertSpaces: true, tabSize: 4); var configService = Mock.Of <RazorConfigurationService>(f => f.GetLatestOptionsAsync(CancellationToken.None) == Task.FromResult(expectedOptions), MockBehavior.Strict); var optionsMonitor = new RazorLSPOptionsMonitor(configService, Cache); var called = false; // Act & Assert optionsMonitor.OnChange(options => { called = true; Assert.Same(expectedOptions, options); }); await optionsMonitor.UpdateAsync(CancellationToken.None); Assert.True(called, "Registered callback was not called."); }
public void BuildOptions_MalformedOptions() { // This test is purely to ensure we don't crash if the user provides malformed options. // Arrange var defaultOptions = RazorLSPOptions.Default; var expectedOptions = new RazorLSPOptions( defaultOptions.Trace, defaultOptions.EnableFormatting, defaultOptions.AutoClosingTags, insertSpaces: false, defaultOptions.TabSize); var razorJsonString = @" { ""trace"": 0, ""format"": { ""enable"": ""fals"" } } ".Trim(); var htmlJsonString = @" { ""format"": """", } ".Trim(); var vsEditorJsonString = @" { ""IndentSize"": ""supposedToBeAnInt"", ""IndentWithTabs"": 4 } ".Trim(); // Act var result = new JObject[] { JObject.Parse(razorJsonString), JObject.Parse(htmlJsonString), JObject.Parse(vsEditorJsonString) }; var languageServer = GetLanguageServer(new ResponseRouterReturns(result)); var configurationService = new DefaultRazorConfigurationService(languageServer, LoggerFactory); var options = configurationService.BuildOptions(result); // Assert Assert.Equal(expectedOptions, options); }
public void OnChange(RazorLSPOptions options, string name) => _listener.Invoke(options, name);
public static Task <RazorLanguageServer> CreateAsync(Stream input, Stream output, Trace trace, Action <RazorLanguageServerBuilder> configure = 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) { // 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>() .WithHandler <RazorCompletionEndpoint>() .WithHandler <RazorCompletionResolveEndpoint>() .WithHandler <RazorHoverEndpoint>() .WithHandler <RazorLanguageEndpoint>() .WithHandler <RazorDiagnosticsEndpoint>() .WithHandler <RazorConfigurationEndpoint>() .WithHandler <RazorFormattingEndpoint>() .WithHandler <RazorSemanticTokensEndpoint>() .WithHandler <SemanticTokensRefreshEndpoint>() .WithHandler <OnAutoInsertEndpoint>() .WithHandler <CodeActionEndpoint>() .WithHandler <CodeActionResolutionEndpoint>() .WithHandler <MonitorProjectConfigurationFilePathEndpoint>() .WithHandler <RazorComponentRenameEndpoint>() .WithHandler <RazorDefinitionEndpoint>() .WithHandler <LinkedEditingRangeEndpoint>() .WithHandler <WrapWithTagEndpoint>() .WithHandler <InlineCompletionEndpoint>() .WithHandler <RazorBreakpointSpanEndpoint>() .WithHandler <RazorProximityExpressionsEndpoint>() .WithHandler <DocumentColorEndpoint>() .WithHandler <FoldingRangeEndpoint>() .WithHandler <TextDocumentTextPresentationEndpoint>() .WithHandler <TextDocumentUriPresentationEndpoint>() .WithServices(services => { services.AddLogging(builder => builder .SetMinimumLevel(logLevel) .AddLanguageProtocolLogging()); services.AddSingleton <ErrorReporter, LanguageServerErrorReporter>(); services.AddSingleton <RequestInvoker, RazorOmniSharpRequestInvoker>(); 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 <GeneratedDocumentContainerStore, DefaultGeneratedDocumentContainerStore>(); services.AddSingleton <ProjectSnapshotChangeTrigger>((services) => services.GetRequiredService <GeneratedDocumentContainerStore>()); 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, UnsynchronizableContentDocumentProcessedListener>(); services.AddSingleton <HostDocumentFactory, DefaultHostDocumentFactory>(); services.AddSingleton <ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>(); services.AddSingleton <TagHelperFactsService, DefaultTagHelperFactsService>(); services.AddSingleton <LSPTagHelperTooltipFactory, DefaultLSPTagHelperTooltipFactory>(); services.AddSingleton <VSLSPTagHelperTooltipFactory, DefaultVSLSPTagHelperTooltipFactory>(); // Completion services.AddSingleton <CompletionListCache>(); 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 <LanguageServerFeatureOptions, DefaultLanguageServerFeatureOptions>(); // 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 " + 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)); }
public static Task <ILanguageServer> CreateAsync(Stream input, Stream output, Trace trace) { Serializer.Instance.JsonSerializer.Converters.RegisterRazorConverters(); ILanguageServer server = null; server = OmniSharp.Extensions.LanguageServer.Server.LanguageServer.PreInit(options => options .WithInput(input) .WithOutput(output) .ConfigureLogging(builder => builder .AddLanguageServer() .SetMinimumLevel(RazorLSPOptions.GetLogLevelForTrace(trace))) .OnInitialized(async(s, request, response) => { var fileChangeDetectorManager = s.Services.GetRequiredService <RazorFileChangeDetectorManager>(); await fileChangeDetectorManager.InitializedAsync(s); // 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) { // Initialize our options for the first time. var optionsMonitor = languageServer.Services.GetRequiredService <RazorLSPOptionsMonitor>(); _ = Task.Delay(TimeSpan.FromSeconds(3)).ContinueWith(async(_) => await optionsMonitor.UpdateAsync()); } }) .WithHandler <RazorDocumentSynchronizationEndpoint>() .WithHandler <RazorCompletionEndpoint>() .WithHandler <RazorHoverEndpoint>() .WithHandler <RazorLanguageEndpoint>() .WithHandler <RazorConfigurationEndpoint>() .WithHandler <RazorFormattingEndpoint>() .WithHandler <RazorOnTypeFormattingEndpoint>() .WithHandler <RazorSemanticTokenEndpoint>() .WithHandler <RazorSemanticTokenLegendEndpoint>() .WithServices(services => { var filePathNormalizer = new FilePathNormalizer(); services.AddSingleton <FilePathNormalizer>(filePathNormalizer); var foregroundDispatcher = new DefaultForegroundDispatcher(); services.AddSingleton <ForegroundDispatcher>(foregroundDispatcher); var generatedDocumentPublisher = new DefaultGeneratedDocumentPublisher(foregroundDispatcher, new Lazy <OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>(() => server)); services.AddSingleton <ProjectSnapshotChangeTrigger>(generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentPublisher>(generatedDocumentPublisher); var documentVersionCache = new DefaultDocumentVersionCache(foregroundDispatcher); services.AddSingleton <DocumentVersionCache>(documentVersionCache); services.AddSingleton <ProjectSnapshotChangeTrigger>(documentVersionCache); var containerStore = new DefaultGeneratedDocumentContainerStore( foregroundDispatcher, documentVersionCache, generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentContainerStore>(containerStore); services.AddSingleton <ProjectSnapshotChangeTrigger>(containerStore); services.AddSingleton <RemoteTextLoaderFactory, DefaultRemoteTextLoaderFactory>(); services.AddSingleton <ProjectResolver, DefaultProjectResolver>(); services.AddSingleton <DocumentResolver, DefaultDocumentResolver>(); services.AddSingleton <RazorProjectService, DefaultRazorProjectService>(); services.AddSingleton <ProjectSnapshotChangeTrigger, BackgroundDocumentGenerator>(); services.AddSingleton <RazorDocumentMappingService, DefaultRazorDocumentMappingService>(); services.AddSingleton <RazorFileChangeDetectorManager>(); // 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, UnsynchronizableContentDocumentProcessedListener>(); services.AddSingleton <HostDocumentFactory, DefaultHostDocumentFactory>(); services.AddSingleton <ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>(); services.AddSingleton <TagHelperFactsService, DefaultTagHelperFactsService>(); services.AddSingleton <VisualStudio.Editor.Razor.TagHelperCompletionService, VisualStudio.Editor.Razor.DefaultTagHelperCompletionService>(); services.AddSingleton <TagHelperDescriptionFactory, DefaultTagHelperDescriptionFactory>(); // Completion services.AddSingleton <Completion.TagHelperCompletionService, Completion.DefaultTagHelperCompletionService>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>(); // Formatting services.AddSingleton <RazorFormatOnTypeProvider, HtmlSmartIndentFormatOnTypeProvider>(); services.AddSingleton <RazorFormatOnTypeProvider, CloseRazorCommentFormatOnTypeProvider>(); services.AddSingleton <RazorFormatOnTypeProvider, CloseTextTagFormatOnTypeProvider>(); services.AddSingleton <RazorFormattingService, DefaultRazorFormattingService>(); services.AddSingleton <RazorCompletionFactsService, DefaultRazorCompletionFactsService>(); services.AddSingleton <RazorSemanticTokenInfoService, DefaultRazorSemanticTokenInfoService>(); services.AddSingleton <RazorHoverInfoService, DefaultRazorHoverInfoService>(); services.AddSingleton <HtmlFactsService, DefaultHtmlFactsService>(); })); server.OnShutdown(() => { TempDirectory.Instance.Dispose(); return(Unit.Task); }); try { var factory = new LoggerFactory(); var logger = factory.CreateLogger <RazorLanguageServer>(); var assemblyInformationAttribute = typeof(RazorLanguageServer).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>(); logger.LogInformation("Razor Language Server version " + assemblyInformationAttribute.InformationalVersion); } catch { // Swallow exceptions from determining assembly information. } return(Task.FromResult(server)); }
public static Task <RazorLanguageServer> CreateAsync(Stream input, Stream output, Trace trace, Action <RazorLanguageServerBuilder> configure = null) { Serializer.Instance.Settings.Converters.Add(SemanticTokensOrSemanticTokensEditsConverter.Instance); Serializer.Instance.JsonSerializer.Converters.RegisterRazorConverters(); // Custom ClientCapabilities deserializer to extract experimental capabilities Serializer.Instance.JsonSerializer.Converters.Add(ExtendableClientCapabilitiesJsonConverter.Instance); ILanguageServer server = null; server = OmniSharp.Extensions.LanguageServer.Server.LanguageServer.PreInit(options => options .WithInput(input) .WithOutput(output) .ConfigureLogging(builder => builder .AddLanguageServer(RazorLSPOptions.GetLogLevelForTrace(trace)) .SetMinimumLevel(LogLevel.Trace)) // We set the minimum level here to "Trace" to ensure that other providers still get the opportunity to act on logs if they prefer. .OnInitialized(async(s, request, response) => { var jsonRpcHandlers = s.Services.GetServices <IJsonRpcHandler>(); var registrationExtensions = jsonRpcHandlers.OfType <IRegistrationExtension>(); if (registrationExtensions.Any()) { var capabilities = new ExtendableServerCapabilities(response.Capabilities, registrationExtensions); response.Capabilities = 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) { // Initialize our options for the first time. var optionsMonitor = languageServer.Services.GetRequiredService <RazorLSPOptionsMonitor>(); _ = Task.Delay(TimeSpan.FromSeconds(3)).ContinueWith(async(_) => await optionsMonitor.UpdateAsync()); } }) .WithHandler <RazorDocumentSynchronizationEndpoint>() .WithHandler <RazorCompletionEndpoint>() .WithHandler <RazorHoverEndpoint>() .WithHandler <RazorLanguageEndpoint>() .WithHandler <RazorConfigurationEndpoint>() .WithHandler <RazorFormattingEndpoint>() .WithHandler <RazorSemanticTokensEndpoint>() .WithHandler <RazorSemanticTokensLegendEndpoint>() .WithHandler <OnAutoInsertEndpoint>() .WithHandler <CodeActionEndpoint>() .WithHandler <CodeActionResolutionEndpoint>() .WithHandler <MonitorProjectConfigurationFilePathEndpoint>() .WithHandler <RazorComponentRenameEndpoint>() .WithHandler <RazorDefinitionEndpoint>() .WithServices(services => { if (configure != null) { var builder = new RazorLanguageServerBuilder(services); configure(builder); } var filePathNormalizer = new FilePathNormalizer(); services.AddSingleton <FilePathNormalizer>(filePathNormalizer); var foregroundDispatcher = new DefaultForegroundDispatcher(); services.AddSingleton <ForegroundDispatcher>(foregroundDispatcher); var generatedDocumentPublisher = new DefaultGeneratedDocumentPublisher(foregroundDispatcher, new Lazy <OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>(() => server)); services.AddSingleton <ProjectSnapshotChangeTrigger>(generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentPublisher>(generatedDocumentPublisher); var documentVersionCache = new DefaultDocumentVersionCache(foregroundDispatcher); services.AddSingleton <DocumentVersionCache>(documentVersionCache); services.AddSingleton <ProjectSnapshotChangeTrigger>(documentVersionCache); var containerStore = new DefaultGeneratedDocumentContainerStore( foregroundDispatcher, documentVersionCache, generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentContainerStore>(containerStore); services.AddSingleton <ProjectSnapshotChangeTrigger>(containerStore); services.AddSingleton <RemoteTextLoaderFactory, DefaultRemoteTextLoaderFactory>(); services.AddSingleton <ProjectResolver, DefaultProjectResolver>(); services.AddSingleton <DocumentResolver, DefaultDocumentResolver>(); services.AddSingleton <RazorProjectService, DefaultRazorProjectService>(); services.AddSingleton <ProjectSnapshotChangeTrigger, BackgroundDocumentGenerator>(); services.AddSingleton <RazorDocumentMappingService, DefaultRazorDocumentMappingService>(); services.AddSingleton <RazorFileChangeDetectorManager>(); // 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, UnsynchronizableContentDocumentProcessedListener>(); services.AddSingleton <HostDocumentFactory, DefaultHostDocumentFactory>(); services.AddSingleton <ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>(); services.AddSingleton <TagHelperFactsService, DefaultTagHelperFactsService>(); services.AddSingleton <VisualStudio.Editor.Razor.TagHelperCompletionService, VisualStudio.Editor.Razor.DefaultTagHelperCompletionService>(); services.AddSingleton <TagHelperDescriptionFactory, DefaultTagHelperDescriptionFactory>(); // Completion services.AddSingleton <Completion.TagHelperCompletionService, Completion.DefaultTagHelperCompletionService>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>(); // Auto insert services.AddSingleton <RazorOnAutoInsertProvider, HtmlSmartIndentOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, CloseRazorCommentOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, CloseTextTagOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, AttributeSnippetOnAutoInsertProvider>(); // Formatting services.AddSingleton <RazorFormattingService, DefaultRazorFormattingService>(); // Formatting Passes services.AddSingleton <IFormattingPass, CodeBlockDirectiveFormattingPass>(); services.AddSingleton <IFormattingPass, CSharpOnTypeFormattingPass>(); services.AddSingleton <IFormattingPass, FormattingStructureValidationPass>(); services.AddSingleton <IFormattingPass, FormattingContentValidationPass>(); // Code actions services.AddSingleton <RazorCodeActionProvider, ExtractToCodeBehindCodeActionProvider>(); services.AddSingleton <RazorCodeActionResolver, ExtractToCodeBehindCodeActionResolver>(); services.AddSingleton <RazorCodeActionProvider, ComponentAccessibilityCodeActionProvider>(); services.AddSingleton <RazorCodeActionResolver, CreateComponentCodeActionResolver>(); services.AddSingleton <RazorCodeActionResolver, AddUsingsCodeActionResolver>(); // Other services.AddSingleton <RazorCompletionFactsService, DefaultRazorCompletionFactsService>(); services.AddSingleton <RazorSemanticTokensInfoService, DefaultRazorSemanticTokensInfoService>(); services.AddSingleton <RazorHoverInfoService, DefaultRazorHoverInfoService>(); services.AddSingleton <HtmlFactsService, DefaultHtmlFactsService>(); services.AddSingleton <WorkspaceDirectoryPathResolver, DefaultWorkspaceDirectoryPathResolver>(); services.AddSingleton <RazorComponentSearchEngine, DefaultRazorComponentSearchEngine>(); })); try { var factory = new LoggerFactory(); var logger = factory.CreateLogger <RazorLanguageServer>(); var assemblyInformationAttribute = typeof(RazorLanguageServer).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>(); logger.LogInformation("Razor Language Server version " + 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)); }
public static Task <RazorLanguageServer> CreateAsync(Stream input, Stream output, Trace trace, Action <RazorLanguageServerBuilder> configure = null) { Serializer.Instance.JsonSerializer.Converters.RegisterRazorConverters(); // Custom ClientCapabilities deserializer to extract experimental capabilities Serializer.Instance.JsonSerializer.Converters.Add(ExtendableClientCapabilitiesJsonConverter.Instance); ILanguageServer server = null; var logLevel = RazorLSPOptions.GetLogLevelForTrace(trace); 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/_ms_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.Instance) .ConfigureLogging(builder => builder .SetMinimumLevel(logLevel) .AddLanguageProtocolLogging(logLevel)) .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(); if (registrationExtensions.Any()) { var capabilities = new ExtendableServerCapabilities(response.Capabilities, registrationExtensions); response.Capabilities = 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) { // Initialize our options for the first time. var optionsMonitor = languageServer.Services.GetRequiredService <RazorLSPOptionsMonitor>(); _ = Task.Delay(TimeSpan.FromSeconds(3)).ContinueWith(async(_) => await optionsMonitor.UpdateAsync(cancellationToken)); } }) .WithHandler <RazorDocumentSynchronizationEndpoint>() .WithHandler <RazorCompletionEndpoint>() .WithHandler <RazorHoverEndpoint>() .WithHandler <RazorLanguageEndpoint>() .WithHandler <RazorConfigurationEndpoint>() .WithHandler <RazorFormattingEndpoint>() .WithHandler <RazorSemanticTokensEndpoint>() .AddHandlerLink(LanguageServerConstants.RazorSemanticTokensEditEndpoint, LanguageServerConstants.LegacyRazorSemanticTokensEditEndpoint) .AddHandlerLink(LanguageServerConstants.RazorSemanticTokensEndpoint, LanguageServerConstants.LegacyRazorSemanticTokensEndpoint) .WithHandler <RazorSemanticTokensLegendEndpoint>() .WithHandler <OnAutoInsertEndpoint>() .WithHandler <CodeActionEndpoint>() .WithHandler <CodeActionResolutionEndpoint>() .WithHandler <MonitorProjectConfigurationFilePathEndpoint>() .WithHandler <RazorComponentRenameEndpoint>() .WithHandler <RazorDefinitionEndpoint>() .WithServices(services => { if (configure != null) { var builder = new RazorLanguageServerBuilder(services); configure(builder); } var filePathNormalizer = new FilePathNormalizer(); services.AddSingleton <FilePathNormalizer>(filePathNormalizer); var foregroundDispatcher = new DefaultForegroundDispatcher(); services.AddSingleton <ForegroundDispatcher>(foregroundDispatcher); var generatedDocumentPublisher = new DefaultGeneratedDocumentPublisher(foregroundDispatcher, new Lazy <OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServer>(() => server)); services.AddSingleton <ProjectSnapshotChangeTrigger>(generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentPublisher>(generatedDocumentPublisher); var documentVersionCache = new DefaultDocumentVersionCache(foregroundDispatcher); services.AddSingleton <DocumentVersionCache>(documentVersionCache); services.AddSingleton <ProjectSnapshotChangeTrigger>(documentVersionCache); var containerStore = new DefaultGeneratedDocumentContainerStore( foregroundDispatcher, documentVersionCache, generatedDocumentPublisher); services.AddSingleton <GeneratedDocumentContainerStore>(containerStore); services.AddSingleton <ProjectSnapshotChangeTrigger>(containerStore); services.AddSingleton <RemoteTextLoaderFactory, DefaultRemoteTextLoaderFactory>(); services.AddSingleton <ProjectResolver, DefaultProjectResolver>(); services.AddSingleton <DocumentResolver, DefaultDocumentResolver>(); services.AddSingleton <RazorProjectService, DefaultRazorProjectService>(); services.AddSingleton <ProjectSnapshotChangeTrigger, BackgroundDocumentGenerator>(); services.AddSingleton <RazorDocumentMappingService, DefaultRazorDocumentMappingService>(); services.AddSingleton <RazorFileChangeDetectorManager>(); // 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, UnsynchronizableContentDocumentProcessedListener>(); services.AddSingleton <HostDocumentFactory, DefaultHostDocumentFactory>(); services.AddSingleton <ProjectSnapshotManagerAccessor, DefaultProjectSnapshotManagerAccessor>(); services.AddSingleton <TagHelperFactsService, DefaultTagHelperFactsService>(); services.AddSingleton <VisualStudio.Editor.Razor.TagHelperCompletionService, VisualStudio.Editor.Razor.DefaultTagHelperCompletionService>(); services.AddSingleton <TagHelperDescriptionFactory, DefaultTagHelperDescriptionFactory>(); // Completion services.AddSingleton <Completion.TagHelperCompletionService, Completion.DefaultTagHelperCompletionService>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeParameterCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, DirectiveAttributeTransitionCompletionItemProvider>(); services.AddSingleton <RazorCompletionItemProvider, MarkupTransitionCompletionItemProvider>(); // Auto insert services.AddSingleton <RazorOnAutoInsertProvider, HtmlSmartIndentOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, CloseRazorCommentOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, CloseTextTagOnAutoInsertProvider>(); services.AddSingleton <RazorOnAutoInsertProvider, AttributeSnippetOnAutoInsertProvider>(); // Formatting services.AddSingleton <RazorFormattingService, DefaultRazorFormattingService>(); // Formatting Passes services.AddSingleton <IFormattingPass, HtmlFormattingPass>(); services.AddSingleton <IFormattingPass, CSharpFormattingPass>(); services.AddSingleton <IFormattingPass, CSharpOnTypeFormattingPass>(); services.AddSingleton <IFormattingPass, OnTypeFormattingStructureValidationPass>(); services.AddSingleton <IFormattingPass, FormattingDiagnosticValidationPass>(); services.AddSingleton <IFormattingPass, FormattingContentValidationPass>(); // 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>(); // Other services.AddSingleton <RazorCompletionFactsService, DefaultRazorCompletionFactsService>(); services.AddSingleton <RazorSemanticTokensInfoService, DefaultRazorSemanticTokensInfoService>(); services.AddSingleton <RazorHoverInfoService, DefaultRazorHoverInfoService>(); services.AddSingleton <HtmlFactsService, DefaultHtmlFactsService>(); services.AddSingleton <WorkspaceDirectoryPathResolver, DefaultWorkspaceDirectoryPathResolver>(); services.AddSingleton <RazorComponentSearchEngine, DefaultRazorComponentSearchEngine>(); // Defaults: For when the caller hasn't provided them through the `configure` action. services.TryAddSingleton <LanguageServerFeatureOptions, DefaultLanguageServerFeatureOptions>(); })); try { var factory = new LoggerFactory(); var logger = factory.CreateLogger <RazorLanguageServer>(); var assemblyInformationAttribute = typeof(RazorLanguageServer).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>(); logger.LogInformation("Razor Language Server version " + 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)); }