diff --git a/eng/Signing.props b/eng/Signing.props index 3980092891..4a94789f83 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -19,6 +19,7 @@ + diff --git a/eng/Versions.props b/eng/Versions.props index 7d79a417e1..657cd318d1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -91,7 +91,7 @@ 1.0.1-beta1.21103.2 17.0.0-previews-1-31410-258 17.0.35-gdeb9415fdc - 4.0.0-2.21354.7 + 4.0.0-3.21367.2 5.0.0-preview.4.20205.1 @@ -106,7 +106,7 @@ $(MicrosoftVisualStudioPackagesVersion) $(MicrosoftVisualStudioPackagesVersion) $(MicrosoftVisualStudioPackagesVersion) - 17.0.2062-g973d339867 + 17.0.3094-g82ddffa096 0.3.1074 16.10.81-pre $(MicrosoftVisualStudioShellPackagesVersion) @@ -132,6 +132,7 @@ 3.3.2 6.0.0-preview3.21158.1 $(RoslynPackageVersion) + $(RoslynPackageVersion) $(RoslynPackageVersion) $(RoslynPackageVersion) $(RoslynPackageVersion) diff --git a/src/Razor/Razor.sln b/src/Razor/Razor.sln index d32182f13a..6265d851ea 100644 --- a/src/Razor/Razor.sln +++ b/src/Razor/Razor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28410.60 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31415.485 MinimumVisualStudioVersion = 16.0.0.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}" ProjectSection(SolutionItems) = preProject @@ -86,6 +86,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Lang EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Remote.Razor.Test", "test\Microsoft.CodeAnalysis.Remote.Razor.Test\Microsoft.CodeAnalysis.Remote.Razor.Test.csproj", "{39233703-B752-43AC-AD86-E9D3E61B4AD9}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Remote.Razor.CoreComponents", "src\Microsoft.CodeAnalysis.Remote.Razor.CoreComponents\Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj", "{17C4A6DF-3AA5-43FE-8A0E-53DF14340446}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -390,6 +392,14 @@ Global {39233703-B752-43AC-AD86-E9D3E61B4AD9}.Release|Any CPU.Build.0 = Release|Any CPU {39233703-B752-43AC-AD86-E9D3E61B4AD9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU {39233703-B752-43AC-AD86-E9D3E61B4AD9}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.Release|Any CPU.Build.0 = Release|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -432,6 +442,7 @@ Global {0FC409AF-B92B-42D0-9096-1F20360D2672} = {92463391-81BE-462B-AC3C-78C6C760741F} {1C7BBF16-3507-4A23-91B4-9EEA03409C72} = {92463391-81BE-462B-AC3C-78C6C760741F} {39233703-B752-43AC-AD86-E9D3E61B4AD9} = {92463391-81BE-462B-AC3C-78C6C760741F} + {17C4A6DF-3AA5-43FE-8A0E-53DF14340446} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26} diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs index 1ba0900c8a..225ed98945 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer private DocumentSnapshot UpdatedDocumentSnapshot { get; set; } - private ForegroundDispatcher ForegroundDispatcher { get; set; } + private ProjectSnapshotManagerDispatcher ProjectSnapshotManagerDispatcher { get; set; } private string PagesDirectory { get; set; } @@ -76,7 +76,8 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer private async Task UpdateDocumentAsync(int newVersion, DocumentSnapshot documentSnapshot) { - await Task.Factory.StartNew(() => VersionCache.TrackDocumentVersion(documentSnapshot, newVersion), CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + await ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => VersionCache.TrackDocumentVersion(documentSnapshot, newVersion), CancellationToken.None).ConfigureAwait(false); } [GlobalCleanup] @@ -101,7 +102,7 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer var languageServer = RazorLanguageServer.GetInnerLanguageServerForTesting(); RazorSemanticTokenService = languageServer.GetService(typeof(RazorSemanticTokensInfoService)) as TestRazorSemanticTokensInfoService; VersionCache = languageServer.GetService(typeof(DocumentVersionCache)) as DocumentVersionCache; - ForegroundDispatcher = languageServer.GetService(typeof(ForegroundDispatcher)) as ForegroundDispatcher; + ProjectSnapshotManagerDispatcher = languageServer.GetService(typeof(ProjectSnapshotManagerDispatcher)) as ProjectSnapshotManagerDispatcher; } private class TestRazorSemanticTokensInfoService : DefaultRazorSemanticTokensInfoService @@ -109,11 +110,11 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer public TestRazorSemanticTokensInfoService( ClientNotifierServiceBase languageServer, RazorDocumentMappingService documentMappingService, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, LoggerFactory loggerFactory) : - base(languageServer, documentMappingService, foregroundDispatcher, documentResolver, documentVersionCache, loggerFactory) + base(languageServer, documentMappingService, projectSnapshotManagerDispatcher, documentResolver, documentVersionCache, loggerFactory) { } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs index f1dc695b9c..ea35c5b2ef 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/ProjectSystem/ProjectSnapshotManagerBenchmarkBase.cs @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks Array.Empty()); return new DefaultProjectSnapshotManager( - new TestForegroundDispatcher(), + new TestProjectSnapshotManagerDispatcher(), new TestErrorReporter(), Array.Empty(), #pragma warning disable CA2000 // Dispose objects before losing scope @@ -91,13 +91,11 @@ namespace Microsoft.AspNetCore.Razor.Microbenchmarks } } - private class TestForegroundDispatcher : ForegroundDispatcher + private class TestProjectSnapshotManagerDispatcher : ProjectSnapshotManagerDispatcher { - public override bool IsForegroundThread => true; + public override bool IsDispatcherThread => true; - public override TaskScheduler ForegroundScheduler => TaskScheduler.Default; - - public override TaskScheduler BackgroundScheduler => TaskScheduler.Default; + public override TaskScheduler DispatcherScheduler => TaskScheduler.Default; } private class TestErrorReporter : ErrorReporter diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/BackgroundDocumentGenerator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/BackgroundDocumentGenerator.cs index e36abc002a..480b5f8aaf 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/BackgroundDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/BackgroundDocumentGenerator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -13,36 +12,36 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common { internal class BackgroundDocumentGenerator : ProjectSnapshotChangeTrigger { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly IEnumerable _documentProcessedListeners; private readonly Dictionary _work; private ProjectSnapshotManagerBase _projectManager; private Timer _timer; public BackgroundDocumentGenerator( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable documentProcessedListeners) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (documentProcessedListeners == null) + if (documentProcessedListeners is null) { throw new ArgumentNullException(nameof(documentProcessedListeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentProcessedListeners = documentProcessedListeners; _work = new Dictionary(StringComparer.Ordinal); } // For testing only protected BackgroundDocumentGenerator( - ForegroundDispatcher foregroundDispatcher) + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _work = new Dictionary(StringComparer.Ordinal); _documentProcessedListeners = Enumerable.Empty(); } @@ -136,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common // Internal for testing internal void Enqueue(DocumentSnapshot document) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); lock (_work) { @@ -164,8 +163,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common { try { - _foregroundDispatcher.AssertBackgroundThread(); - OnStartingBackgroundWork(); KeyValuePair[] work; @@ -192,11 +189,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common OnCompletingBackgroundWork(); - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => NotifyDocumentsProcessed(work), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); lock (_work) { @@ -237,7 +232,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { @@ -317,11 +312,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common private void ReportError(Exception ex) { - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectManager.ReportError(ex), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/LanguageServerConstants.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/LanguageServerConstants.cs index ca8c78d894..1127babf21 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/LanguageServerConstants.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/LanguageServerConstants.cs @@ -9,14 +9,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common public const string ProjectConfigurationFile = "project.razor.json"; - // Semantic "Legacy" endpoints refer to an old LSP spec version, needed for now until VS reacts. - public const string LegacyRazorSemanticTokensEndpoint = "textDocument/semanticTokens"; - - public const string LegacyRazorSemanticTokensEditEndpoint = "textDocument/semanticTokens/edits"; - - public const string LegacyRazorSemanticTokensRangeEndpoint = "textDocument/semanticTokens/range"; - - public const string RazorSemanticTokensLegendEndpoint = "_ms_/textDocument/semanticTokensLegend"; + public const string RazorSemanticTokensLegendEndpoint = "_vs_/textDocument/semanticTokensLegend"; public const string RazorSemanticTokensEditEndpoint = "textDocument/semanticTokens/full/delta"; @@ -36,8 +29,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common public const string RazorCodeActionRunnerCommand = "razor/runCodeAction"; - public const string RazorCodeActionResolveEndpoint = "textDocument/codeActionResolve"; - // RZLS Custom Message Targets public const string RazorUpdateCSharpBufferEndpoint = "razor/updateCSharpBuffer"; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs index 806f2a187e..ef94f794b1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -288,4 +288,4 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert SelfClosing, } } -} +} \ No newline at end of file diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/IOnAutoInsertHandler.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/IOnAutoInsertHandler.cs index f20d1589fa..24e909928c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/IOnAutoInsertHandler.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/IOnAutoInsertHandler.cs @@ -5,7 +5,7 @@ using OmniSharp.Extensions.JsonRpc; namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert { - [Parallel, Method("textDocument/_ms_onAutoInsert")] + [Parallel, Method("textDocument/_vs_onAutoInsert")] internal interface IOnAutoInsertHandler : IJsonRpcRequestHandler, IRegistrationExtension { } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs index 9e2379109b..60d6ba1d41 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertEndpoint.cs @@ -16,21 +16,21 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert { internal class OnAutoInsertEndpoint : IOnAutoInsertHandler { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly AdhocWorkspaceFactory _workspaceFactory; private readonly IReadOnlyList _onAutoInsertProviders; private readonly Container _onAutoInsertTriggerCharacters; public OnAutoInsertEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, IEnumerable onAutoInsertProvider, AdhocWorkspaceFactory workspaceFactory) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver is null) @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert throw new ArgumentNullException(nameof(workspaceFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _workspaceFactory = workspaceFactory; _onAutoInsertProviders = onAutoInsertProvider.ToList(); @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert public RegistrationExtensionResult GetRegistration() { - const string AssociatedServerCapability = "_ms_onAutoInsertProvider"; + const string AssociatedServerCapability = "_vs_onAutoInsertProvider"; var registrationOptions = new OnAutoInsertRegistrationOptions() { @@ -70,12 +70,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert public async Task Handle(OnAutoInsertParams request, CancellationToken cancellationToken) { - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); if (document is null || cancellationToken.IsCancellationRequested) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertParams.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertParams.cs index 1de0fc8315..100f8775ae 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertParams.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertParams.cs @@ -9,13 +9,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert { internal class OnAutoInsertParams : ITextDocumentIdentifierParams, IRequest, IBaseRequest { + [JsonProperty("_vs_textDocument")] public TextDocumentIdentifier TextDocument { get; set; } + [JsonProperty("_vs_position")] public Position Position { get; set; } - [JsonProperty("ch")] + [JsonProperty("_vs_ch")] public string Character { get; set; } + [JsonProperty("_vs_options")] public FormattingOptions Options { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertRegistrationOptions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertRegistrationOptions.cs index 3bde512e04..866882c9e4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertRegistrationOptions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertRegistrationOptions.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert @@ -9,6 +10,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert { public DocumentSelector DocumentSelector { get; set; } + [JsonProperty("_vs_triggerCharacters")] public Container TriggerCharacters { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertResponse.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertResponse.cs index ce39023b03..c61a497928 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertResponse.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/OnAutoInsertResponse.cs @@ -1,14 +1,17 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert { internal class OnAutoInsertResponse { + [JsonProperty("_vs_textEditFormat")] public InsertTextFormat TextEditFormat { get; set; } + [JsonProperty("_vs_textEdit")] public TextEdit TextEdit { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/AddUsingsCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/AddUsingsCodeActionResolver.cs index 9279ad235f..b5d9701959 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/AddUsingsCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/AddUsingsCodeActionResolver.cs @@ -23,13 +23,25 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { internal class AddUsingsCodeActionResolver : RazorCodeActionResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; - public AddUsingsCodeActionResolver(ForegroundDispatcher foregroundDispatcher, DocumentResolver documentResolver) + public AddUsingsCodeActionResolver( + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + DocumentResolver documentResolver) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); - _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + + if (documentResolver is null) + { + throw new ArgumentNullException(nameof(documentResolver)); + } + + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _documentResolver = documentResolver; } public override string Action => LanguageServerConstants.CodeActions.AddUsing; @@ -49,11 +61,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var path = actionParams.Uri.GetAbsoluteOrUNCPath(); - var documentSnapshot = await Task.Factory.StartNew(() => + var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(path, out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { return null; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/AddUsingsCSharpCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/AddUsingsCSharpCodeActionResolver.cs index b0dfa8fb5b..550a721d70 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/AddUsingsCSharpCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/AddUsingsCSharpCodeActionResolver.cs @@ -19,18 +19,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions /// internal class AddUsingsCSharpCodeActionResolver : CSharpCodeActionResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly DocumentVersionCache _documentVersionCache; public AddUsingsCSharpCodeActionResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, ClientNotifierServiceBase languageServer, DocumentVersionCache documentVersionCache) : base(languageServer) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _documentVersionCache = documentVersionCache ?? throw new ArgumentNullException(nameof(documentVersionCache)); } @@ -87,11 +87,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions return codeAction; } - var documentSnapshot = await Task.Factory.StartNew(() => + var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(csharpParams.RazorFileUri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { return codeAction; @@ -109,11 +109,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions return null; } - var documentVersion = await Task.Factory.StartNew(() => + var documentVersion = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version); return version; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); var codeDocumentIdentifier = new VersionedTextDocumentIdentifier() { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/DefaultCSharpCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/DefaultCSharpCodeActionResolver.cs index b87efb66e9..282f2046fd 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/DefaultCSharpCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/DefaultCSharpCodeActionResolver.cs @@ -28,22 +28,22 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions TrimFinalNewlines = true }; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorFormattingService _razorFormattingService; private readonly DocumentVersionCache _documentVersionCache; public DefaultCSharpCodeActionResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, ClientNotifierServiceBase languageServer, RazorFormattingService razorFormattingService, DocumentVersionCache documentVersionCache) : base(languageServer) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver is null) @@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions throw new ArgumentNullException(nameof(documentVersionCache)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _razorFormattingService = razorFormattingService; _documentVersionCache = documentVersionCache; @@ -99,11 +99,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions cancellationToken.ThrowIfCancellationRequested(); - var documentSnapshot = await Task.Factory.StartNew(() => + var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(csharpParams.RazorFileUri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { @@ -134,11 +134,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions cancellationToken.ThrowIfCancellationRequested(); - var documentVersion = await Task.Factory.StartNew(() => + var documentVersion = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version); return version; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); var codeDocumentIdentifier = new VersionedTextDocumentIdentifier() { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs index 7596bfb5b2..bd5807391b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/UnformattedRemappingCSharpCodeActionResolver.cs @@ -19,20 +19,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions /// internal class UnformattedRemappingCSharpCodeActionResolver : CSharpCodeActionResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly DocumentVersionCache _documentVersionCache; private readonly RazorDocumentMappingService _documentMappingService; public UnformattedRemappingCSharpCodeActionResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, ClientNotifierServiceBase languageServer, DocumentVersionCache documentVersionCache, RazorDocumentMappingService documentMappingService) : base(languageServer) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _documentVersionCache = documentVersionCache ?? throw new ArgumentNullException(nameof(documentVersionCache)); _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); @@ -85,14 +85,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions return codeAction; } - var (documentSnapshot, documentVersion) = await Task.Factory.StartNew(() => + var (documentSnapshot, documentVersion) = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(csharpParams.RazorFileUri.ToUri().GetAbsoluteOrUNCPath(), out var documentSnapshot); _documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version); return (documentSnapshot, version); - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 6174577ab3..f80f3ff3e7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions private readonly RazorDocumentMappingService _documentMappingService; private readonly IEnumerable _razorCodeActionProviders; private readonly IEnumerable _csharpCodeActionProviders; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly LanguageServerFeatureOptions _languageServerFeatureOptions; private readonly ClientNotifierServiceBase _languageServer; @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions RazorDocumentMappingService documentMappingService, IEnumerable razorCodeActionProviders, IEnumerable csharpCodeActionProviders, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, ClientNotifierServiceBase languageServer, LanguageServerFeatureOptions languageServerFeatureOptions) @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); _razorCodeActionProviders = razorCodeActionProviders ?? throw new ArgumentNullException(nameof(razorCodeActionProviders)); _csharpCodeActionProviders = csharpCodeActionProviders ?? throw new ArgumentNullException(nameof(csharpCodeActionProviders)); - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _languageServer = languageServer ?? throw new ArgumentNullException(nameof(languageServer)); _languageServerFeatureOptions = languageServerFeatureOptions ?? throw new ArgumentNullException(nameof(languageServerFeatureOptions)); @@ -65,7 +65,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions CodeActionKind.RefactorExtract, CodeActionKind.QuickFix, CodeActionKind.Refactor - } + }, + ResolveProvider = true, }; } @@ -73,8 +74,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { _capability = capability; - var extendableClientCapabilities = _languageServer.ClientSettings?.Capabilities as PlatformAgnosticClientCapabilities; - _supportsCodeActionResolve = extendableClientCapabilities?.SupportsCodeActionResolve ?? false; + _supportsCodeActionResolve = _capability.ResolveSupport != null; } public async Task Handle(RazorCodeActionParams request, CancellationToken cancellationToken) @@ -121,11 +121,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions // internal for testing internal async Task GenerateRazorCodeActionContextAsync(RazorCodeActionParams request, CancellationToken cancellationToken) { - var documentSnapshot = await Task.Factory.StartNew(() => + var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionResolutionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionResolutionEndpoint.cs index e490e1c735..619cdb07f1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionResolutionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionResolutionEndpoint.cs @@ -16,8 +16,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { internal class CodeActionResolutionEndpoint : IRazorCodeActionResolveHandler { - private const string CodeActionsResolveProviderCapability = "codeActionsResolveProvider"; - private readonly IReadOnlyDictionary _razorCodeActionResolvers; private readonly IReadOnlyDictionary _csharpCodeActionResolvers; private readonly ILogger _logger; @@ -48,9 +46,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions _csharpCodeActionResolvers = CreateResolverMap(csharpCodeActionResolvers); } - // Register VS LSP code action resolution server capability - public RegistrationExtensionResult GetRegistration() => new RegistrationExtensionResult(CodeActionsResolveProviderCapability, true); - public async Task Handle(CodeAction request, CancellationToken cancellationToken) { if (request is null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/IRazorCodeActionResolveHandler.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/IRazorCodeActionResolveHandler.cs index 8e6dfcc8dd..06d3d56d5e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/IRazorCodeActionResolveHandler.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/IRazorCodeActionResolveHandler.cs @@ -1,16 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Razor.LanguageServer.Common; using OmniSharp.Extensions.JsonRpc; +using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { - [Parallel, Method(LanguageServerConstants.RazorCodeActionResolveEndpoint)] + [Parallel, Method(TextDocumentNames.CodeActionResolve, Direction.ClientToServer)] internal interface IRazorCodeActionResolveHandler : - IJsonRpcRequestHandler, - IRegistrationExtension + IJsonRpcRequestHandler { } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Models/ExtendedCodeActionContext.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Models/ExtendedCodeActionContext.cs index 490fa669f3..b5d9a587a5 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Models/ExtendedCodeActionContext.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Models/ExtendedCodeActionContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Serialization; @@ -9,6 +10,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models internal class ExtendedCodeActionContext : CodeActionContext { [Optional] + [JsonProperty("_vs_selectionRange")] public Range SelectionRange { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs index d117bc175f..dfb46814f1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs @@ -20,14 +20,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { internal class CreateComponentCodeActionResolver : RazorCodeActionResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; public CreateComponentCodeActionResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); } @@ -48,11 +48,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var path = actionParams.Uri.GetAbsoluteOrUNCPath(); - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(path, out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (document is null) { return null; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs index 6a5981360c..f63182693d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs @@ -26,18 +26,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { internal class ExtractToCodeBehindCodeActionResolver : RazorCodeActionResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly FilePathNormalizer _filePathNormalizer; private static readonly Range s_startOfDocumentRange = new Range(new Position(0, 0), new Position(0, 0)); public ExtractToCodeBehindCodeActionResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, FilePathNormalizer filePathNormalizer) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _filePathNormalizer = filePathNormalizer ?? throw new ArgumentNullException(nameof(filePathNormalizer)); } @@ -59,11 +59,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var path = _filePathNormalizer.Normalize(actionParams.Uri.GetAbsoluteOrUNCPath()); - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(path, out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (document is null) { return null; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OmniSharpVSCompletionContext.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OmniSharpVSCompletionContext.cs index e4bbb15563..b8b032e318 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OmniSharpVSCompletionContext.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OmniSharpVSCompletionContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion { public static readonly PlatformExtensionConverter JsonConverter = new PlatformExtensionConverter(); - [JsonProperty("_ms_invokeKind")] + [JsonProperty("_vs_invokeKind")] public OmniSharpVSCompletionInvokeKind InvokeKind { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OptimizedVSCompletionList.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OptimizedVSCompletionList.cs index cfbd09fe4b..857acaea8e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OptimizedVSCompletionList.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/OptimizedVSCompletionList.cs @@ -29,13 +29,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion if (vsCompletionList.CommitCharacters != null) { - writer.WritePropertyName("_vsext_commitCharacters"); + writer.WritePropertyName("_vs_commitCharacters"); serializer.Serialize(writer, vsCompletionList.CommitCharacters); } if (vsCompletionList.Data != null) { - writer.WritePropertyName("_vsext_data"); + writer.WritePropertyName("_vs_data"); serializer.Serialize(writer, vsCompletionList.Data); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/PlatformAgnosticCompletionCapability.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/PlatformAgnosticCompletionCapability.cs index a5a06fefef..b2a9202a5d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/PlatformAgnosticCompletionCapability.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/PlatformAgnosticCompletionCapability.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion { public static readonly PlatformExtensionConverter JsonConverter = new PlatformExtensionConverter(); - [JsonProperty("_ms_completionList")] + [JsonProperty("_vs_completionList")] public VSCompletionListCapability VSCompletionList { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs index ed3bf4cd07..40a16bf6e0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion { private PlatformAgnosticCompletionCapability _capability; private readonly ILogger _logger; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorCompletionFactsService _completionFactsService; private readonly LSPTagHelperTooltipFactory _lspTagHelperTooltipFactory; @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion private IReadOnlyList _supportedItemKinds; public RazorCompletionEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorCompletionFactsService completionFactsService, LSPTagHelperTooltipFactory lspTagHelperTooltipFactory, @@ -49,9 +49,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion ClientNotifierServiceBase languageServer, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver == null) @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _completionFactsService = completionFactsService; _lspTagHelperTooltipFactory = lspTagHelperTooltipFactory; @@ -102,14 +102,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion public async Task Handle(CompletionParams request, CancellationToken cancellationToken) { - _foregroundDispatcher.AssertBackgroundThread(); - - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, CancellationToken.None); if (document is null || cancellationToken.IsCancellationRequested) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionItem.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionItem.cs index 13cfcc39d7..a0664ce683 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionItem.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionItem.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.LanguageServer.Tooltip; +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion @@ -11,6 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion /// internal class VSCompletionItem : CompletionItem { + [JsonProperty("_vs_description")] public VSClassifiedTextElement Description { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionList.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionList.cs index 3c0ffbd7c6..b0feac0f08 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionList.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionList.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion @@ -19,11 +20,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion /// /// Gets or sets the default used for completion items. /// + [JsonProperty("_vs_commitCharacters")] public Container CommitCharacters { get; set; } /// /// Gets or sets the default used for completion items. /// + [JsonProperty("_vs_data")] public object Data { get; set; } public static VSCompletionList Convert(CompletionList completionList, VSCompletionListCapability vsCompletionListCapability) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionListCapability.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionListCapability.cs index d97ff4e857..01f5a3711f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionListCapability.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/VSCompletionListCapability.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Newtonsoft.Json; + namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion { internal class VSCompletionListCapability @@ -9,12 +11,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion /// Gets or sets a value indicating whether completion lists can have VSCommitCharacters. These commit characters get propagated /// onto underlying valid completion items unless they have their own commit characters. /// + [JsonProperty("_vs_commitCharacters")] public bool CommitCharacters { get; set; } /// /// Gets or sets a value indicating whether completion lists can have Data bags. These data bags get propagated /// onto underlying completion items unless they have their own data bags. /// + [JsonProperty("_vs_data")] public bool Data { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentVersionCache.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentVersionCache.cs index 0adc0e1c25..e07aa66a09 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentVersionCache.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentVersionCache.cs @@ -14,18 +14,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer // Internal for testing internal readonly Dictionary> DocumentLookup; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private ProjectSnapshotManagerBase _projectSnapshotManager; - public DefaultDocumentVersionCache(ForegroundDispatcher foregroundDispatcher) + public DefaultDocumentVersionCache(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; DocumentLookup = new Dictionary>(FilePathComparer.Instance); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public override void TrackDocumentVersion(DocumentSnapshot documentSnapshot, int version) @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(documentSnapshot)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!DocumentLookup.TryGetValue(documentSnapshot.FilePath, out var documentEntries)) { @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(documentSnapshot)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!DocumentLookup.TryGetValue(documentSnapshot.FilePath, out var documentEntries)) { @@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentContainerStore.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentContainerStore.cs index 650a29af3f..2e56cdf503 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentContainerStore.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentContainerStore.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -13,19 +12,19 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer internal class DefaultGeneratedDocumentContainerStore : GeneratedDocumentContainerStore { private readonly ConcurrentDictionary _store; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentVersionCache _documentVersionCache; private readonly GeneratedDocumentPublisher _generatedDocumentPublisher; private ProjectSnapshotManagerBase _projectSnapshotManager; public DefaultGeneratedDocumentContainerStore( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentVersionCache documentVersionCache, GeneratedDocumentPublisher generatedDocumentPublisher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentVersionCache == null) @@ -38,7 +37,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(generatedDocumentPublisher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentVersionCache = documentVersionCache; _generatedDocumentPublisher = generatedDocumentPublisher; _store = new ConcurrentDictionary(FilePathComparer.Instance); @@ -67,7 +66,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer // Internal for testing internal void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { @@ -95,7 +94,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer var latestDocument = generatedDocumentContainer.LatestDocument; - _ = Task.Factory.StartNew(() => + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { @@ -111,7 +110,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishCSharp(filePath, args.NewText, hostDocumentVersion); - }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, CancellationToken.None); }; documentContainer.GeneratedHtmlChanged += (sender, args) => @@ -120,7 +119,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer var latestDocument = generatedDocumentContainer.LatestDocument; - _ = Task.Factory.StartNew(() => + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { @@ -136,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishHtml(filePath, args.NewText, hostDocumentVersion); - }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, CancellationToken.None); }; return documentContainer; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentPublisher.cs index 4e97ba240a..5b289bd629 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultGeneratedDocumentPublisher.cs @@ -20,17 +20,17 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private readonly Dictionary _publishedHtmlData; private readonly IClientLanguageServer _server; private readonly ILogger _logger; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private ProjectSnapshotManagerBase _projectSnapshotManager; public DefaultGeneratedDocumentPublisher( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IClientLanguageServer server, ILoggerFactory loggerFactory) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (server is null) @@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _server = server; _logger = loggerFactory.CreateLogger(); _publishedCSharpData = new Dictionary(FilePathComparer.Instance); @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(sourceText)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_publishedCSharpData.TryGetValue(filePath, out var previouslyPublishedData)) { @@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(sourceText)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_publishedHtmlData.TryGetValue(filePath, out var previouslyPublishedData)) { @@ -167,7 +167,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { @@ -178,12 +178,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer if (_publishedCSharpData.ContainsKey(args.DocumentFilePath)) { var removed = _publishedCSharpData.Remove(args.DocumentFilePath); - Debug.Assert(removed, "Published data should be protected by the foreground thread and should never fail to remove."); + Debug.Assert(removed, "Published data should be protected by the project snapshot manager's thread and should never fail to remove."); } if (_publishedHtmlData.ContainsKey(args.DocumentFilePath)) { var removed = _publishedHtmlData.Remove(args.DocumentFilePath); - Debug.Assert(removed, "Published data should be protected by the foreground thread and should never fail to remove."); + Debug.Assert(removed, "Published data should be protected by the project snapshot manager's thread and should never fail to remove."); } } break; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultHostDocumentFactory.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultHostDocumentFactory.cs index 40a1501d08..e6378b25c4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultHostDocumentFactory.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultHostDocumentFactory.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; @@ -12,24 +11,15 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class DefaultHostDocumentFactory : HostDocumentFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly GeneratedDocumentContainerStore _generatedDocumentContainerStore; - public DefaultHostDocumentFactory( - ForegroundDispatcher foregroundDispatcher, - GeneratedDocumentContainerStore generatedDocumentContainerStore) + public DefaultHostDocumentFactory(GeneratedDocumentContainerStore generatedDocumentContainerStore) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (generatedDocumentContainerStore == null) + if (generatedDocumentContainerStore is null) { throw new ArgumentNullException(nameof(generatedDocumentContainerStore)); } - _foregroundDispatcher = foregroundDispatcher; _generatedDocumentContainerStore = generatedDocumentContainerStore; } @@ -38,12 +28,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public override HostDocument Create(string filePath, string targetFilePath, string fileKind) { - if (filePath == null) + if (filePath is null) { throw new ArgumentNullException(nameof(filePath)); } - if (targetFilePath == null) + if (targetFilePath is null) { throw new ArgumentNullException(nameof(targetFilePath)); } @@ -64,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer () => sharedContainer.SetOutputAndCaptureReferenceAsync(latestDocument), CancellationToken.None, TaskCreationOptions.None, - _foregroundDispatcher.BackgroundScheduler); + TaskScheduler.Default); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultProjectSnapshotManagerAccessor.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultProjectSnapshotManagerAccessor.cs index a3b5e2ed00..a14bd3624b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultProjectSnapshotManagerAccessor.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultProjectSnapshotManagerAccessor.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class DefaultProjectSnapshotManagerAccessor : ProjectSnapshotManagerAccessor, IDisposable { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly IEnumerable _changeTriggers; private readonly FilePathNormalizer _filePathNormalizer; private readonly IOptionsMonitor _optionsMonitor; @@ -21,15 +21,15 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private bool _disposed; public DefaultProjectSnapshotManagerAccessor( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable changeTriggers, FilePathNormalizer filePathNormalizer, IOptionsMonitor optionsMonitor, AdhocWorkspaceFactory workspaceFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (changeTriggers == null) @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(workspaceFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _changeTriggers = changeTriggers; _filePathNormalizer = filePathNormalizer; _optionsMonitor = optionsMonitor; @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer new RemoteProjectSnapshotProjectEngineFactory(_filePathNormalizer, _optionsMonitor) }); _instance = new DefaultProjectSnapshotManager( - _foregroundDispatcher, + _projectSnapshotManagerDispatcher, new DefaultErrorReporter(), _changeTriggers, workspace); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs index b60d7c19bd..e3a28d4da2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs @@ -15,14 +15,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class DefaultRazorComponentSearchEngine : RazorComponentSearchEngine { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectSnapshotManager _projectSnapshotManager; public DefaultRazorComponentSearchEngine( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _projectSnapshotManager = projectSnapshotManagerAccessor?.Instance ?? throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor)); } @@ -45,11 +45,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.TrySplitNamespaceAndType(tagHelper.Name, out var @namespaceName, out var typeName); var lookupSymbolName = RemoveGenericContent(typeName); - var projects = await Task.Factory.StartNew( + var projects = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectSnapshotManager.Projects.ToArray(), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + CancellationToken.None).ConfigureAwait(false); foreach (var project in projects) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/RazorDefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/RazorDefinitionEndpoint.cs index 14f9a7f4d5..a95033a500 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/RazorDefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/RazorDefinitionEndpoint.cs @@ -21,16 +21,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition { internal class RazorDefinitionEndpoint : IDefinitionHandler { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorComponentSearchEngine _componentSearchEngine; public RazorDefinitionEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorComponentSearchEngine componentSearchEngine) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); } @@ -50,12 +50,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition throw new ArgumentNullException(nameof(request)); } - var documentSnapshot = await Task.Factory.StartNew(() => + var documentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { var path = request.TextDocument.Uri.GetAbsoluteOrUNCPath(); _documentResolver.TryResolveDocument(path, out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnostic.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnostic.cs index b1f2c3791f..f16d082c44 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnostic.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnostic.cs @@ -20,46 +20,46 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics /// /// Gets or sets the project and context (e.g. Win32, MacOS, etc.) in which the diagnostic was generated. /// - [JsonProperty("_ms_projects")] - public OmniSharpVSProjectAndContext[]? Projects { get; set; } + [JsonProperty("_vs_projects")] + public OmniSharpVSDiagnosticProjectInformation[]? Projects { get; set; } /// /// Gets or sets an expanded description of the diagnostic. /// - [JsonProperty("_ms_expandedMessage")] + [JsonProperty("_vs_expandedMessage")] public string? ExpandedMessage { get; set; } /// /// Gets or sets a message shown when the user hovers over an error. If null, then message /// is used (use to prevent a tool tip from being shown). /// - [JsonProperty("_ms_toolTip")] + [JsonProperty("_vs_toolTip")] public string? ToolTip { get; set; } /// /// Gets or sets some non-human readable identifier so that two diagnostics that are /// equivalent (e.g.a syntax error in both a build for Win32 and MacOs) can be consolidated. /// - [JsonProperty("_ms_identifier")] + [JsonProperty("_vs_identifier")] public string? Identifier { get; set; } /// /// Gets or sets a string describing the diagnostic types (e.g. Security, Performance, Style, ...). /// - [JsonProperty("_ms_diagnosticType")] + [JsonProperty("_vs_diagnosticType")] public string? DiagnosticType { get; set; } /// /// Gets or sets a rank associated with this diagnostic, used for the default sort. /// Default == 300 will be used if no rank is specified. /// - [JsonProperty("_ms_diagnosticRank")] + [JsonProperty("_vs_diagnosticRank")] public OmniSharpVSDiagnosticRank? DiagnosticRank { get; set; } /// /// Gets or sets an ID used to associate this diagnostic with a corresponding line in the output window. /// - [JsonProperty("_ms_outputId")] + [JsonProperty("_vs_outputId")] public int? OutputId { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSProjectAndContext.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnosticProjectInformation.cs similarity index 81% rename from src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSProjectAndContext.cs rename to src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnosticProjectInformation.cs index 5bd250b7f2..c4bca4d2c2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSProjectAndContext.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/OmniSharpVSDiagnosticProjectInformation.cs @@ -3,24 +3,29 @@ #nullable enable +using Newtonsoft.Json; + namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics { - internal class OmniSharpVSProjectAndContext + internal class OmniSharpVSDiagnosticProjectInformation { /// /// Gets or sets a human-readable identifier for the project in which the diagnostic was generated. /// + [JsonProperty("_vs_projectName")] public string? ProjectName { get; set; } /// /// Gets or sets a human-readable identifier for the build context (e.g. Win32 or MacOS) /// in which the diagnostic was generated. /// + [JsonProperty("_vs_context")] public string? Context { get; set; } /// /// Gets or sets the unique identifier for the project in which the diagnostic was generated. /// + [JsonProperty("_vs_projectIdentifier")] public string? ProjectIdentifier { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsEndpoint.cs index 2ed88f838f..764fdccb08 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticsEndpoint.cs @@ -30,22 +30,22 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics "IDE0005_gen", // Using directive is unnecessary }; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly DocumentVersionCache _documentVersionCache; private readonly RazorDocumentMappingService _documentMappingService; private readonly ILogger _logger; public RazorDiagnosticsEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, RazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver == null) @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _documentVersionCache = documentVersionCache; _documentMappingService = documentMappingService; @@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics int? documentVersion = null; DocumentSnapshot documentSnapshot = null; - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.RazorDocumentUri.GetAbsoluteOrUNCPath(), out documentSnapshot); @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics { documentVersion = null; } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (documentSnapshot is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ExtendableServerCapabilities.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ExtendableServerCapabilities.cs index 5ac148d77f..b8108f9887 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ExtendableServerCapabilities.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ExtendableServerCapabilities.cs @@ -36,6 +36,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer TextDocumentSync = inner.TextDocumentSync; CodeLensProvider = inner.CodeLensProvider; Workspace = inner.Workspace; +#pragma warning disable CS0618 // Type or member is obsolete + SemanticTokensProvider = inner.SemanticTokensProvider; +#pragma warning restore CS0618 // Type or member is obsolete RazorLanguageServerCapability.AddTo(this); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs index 9ed76cd90d..e0f39a97c8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingEndpoint.cs @@ -22,22 +22,22 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting { internal class RazorFormattingEndpoint : IDocumentFormattingHandler, IDocumentRangeFormattingHandler { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorFormattingService _razorFormattingService; private readonly IOptionsMonitor _optionsMonitor; private readonly ILogger _logger; public RazorFormattingEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorFormattingService razorFormattingService, IOptionsMonitor optionsMonitor, ILoggerFactory loggerFactory) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver is null) @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _razorFormattingService = razorFormattingService; _optionsMonitor = optionsMonitor; @@ -90,12 +90,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting return null; } - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); if (document is null || cancellationToken.IsCancellationRequested) { @@ -124,12 +124,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting return null; } - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); if (document is null || cancellationToken.IsCancellationRequested) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/RazorHoverEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/RazorHoverEndpoint.cs index 405474ee77..7f50eeb938 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/RazorHoverEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/RazorHoverEndpoint.cs @@ -21,21 +21,21 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover { private HoverCapability _capability; private readonly ILogger _logger; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorHoverInfoService _hoverInfoService; private readonly ClientNotifierServiceBase _languageServer; public RazorHoverEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorHoverInfoService hoverInfoService, ClientNotifierServiceBase languageServer, ILoggerFactory loggerFactory) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver is null) @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _hoverInfoService = hoverInfoService; _languageServer = languageServer; @@ -72,12 +72,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover throw new ArgumentNullException(nameof(request)); } - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); if (document is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/VSHover.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/VSHover.cs index 9624b44c46..1be0bf5a6b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/VSHover.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/VSHover.cs @@ -3,12 +3,14 @@ #nullable enable +using Newtonsoft.Json; using HoverModel = OmniSharp.Extensions.LanguageServer.Protocol.Models.Hover; namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover { internal class VSHover : HoverModel { + [JsonProperty("_vs_rawContent")] public object? RawContent { get; set; } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MonitorProjectConfigurationFilePathEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MonitorProjectConfigurationFilePathEndpoint.cs index 4a72999667..5f7a9923bb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MonitorProjectConfigurationFilePathEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MonitorProjectConfigurationFilePathEndpoint.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class MonitorProjectConfigurationFilePathEndpoint : IMonitorProjectConfigurationFilePathHandler, IDisposable { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly FilePathNormalizer _filePathNormalizer; private readonly WorkspaceDirectoryPathResolver _workspaceDirectoryPathResolver; private readonly IEnumerable _listeners; @@ -25,14 +25,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private bool _disposed; public MonitorProjectConfigurationFilePathEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, WorkspaceDirectoryPathResolver workspaceDirectoryPathResolver, IEnumerable listeners) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (filePathNormalizer is null) @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(listeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _filePathNormalizer = filePathNormalizer; _workspaceDirectoryPathResolver = workspaceDirectoryPathResolver; _listeners = listeners; @@ -191,6 +191,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer } // Protected virtual for testing - protected virtual IFileChangeDetector CreateFileChangeDetector() => new ProjectConfigurationFileChangeDetector(_foregroundDispatcher, _filePathNormalizer, _listeners); + protected virtual IFileChangeDetector CreateFileChangeDetector() => new ProjectConfigurationFileChangeDetector(_projectSnapshotManagerDispatcher, _filePathNormalizer, _listeners); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs index 0bd5e11fa7..6c4c448af8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/OpenDocumentGenerator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.Extensions.Internal; @@ -14,35 +13,35 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class OpenDocumentGenerator : ProjectSnapshotChangeTrigger { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly IReadOnlyList _documentProcessedListeners; private readonly Dictionary _work; private ProjectSnapshotManagerBase _projectManager; private Timer _timer; public OpenDocumentGenerator( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable documentProcessedListeners) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (documentProcessedListeners == null) + if (documentProcessedListeners is null) { throw new ArgumentNullException(nameof(documentProcessedListeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentProcessedListeners = documentProcessedListeners.ToArray(); _work = new Dictionary(StringComparer.Ordinal); } // For testing only - protected OpenDocumentGenerator(ForegroundDispatcher foregroundDispatcher) + protected OpenDocumentGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _work = new Dictionary(StringComparer.Ordinal); _documentProcessedListeners = Array.Empty(); } @@ -136,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer // Internal for testing internal void Enqueue(DocumentSnapshot document) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_projectManager.IsDocumentOpen(document.FilePath)) { @@ -170,8 +169,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { try { - _foregroundDispatcher.AssertBackgroundThread(); - OnStartingBackgroundWork(); KeyValuePair[] work; @@ -200,11 +197,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer if (_documentProcessedListeners.Count != 0) { - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => NotifyDocumentsProcessed(work), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + CancellationToken.None).ConfigureAwait(false); } lock (_work) @@ -246,7 +241,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { @@ -308,11 +303,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void ReportError(Exception ex) { - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectManager.ReportError(ex), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PlatformAgnosticClientCapabilities.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PlatformAgnosticClientCapabilities.cs index b2f3e651e3..1c6ec168e6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PlatformAgnosticClientCapabilities.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PlatformAgnosticClientCapabilities.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.LanguageServer.Serialization; +using Newtonsoft.Json; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; namespace Microsoft.AspNetCore.Razor.LanguageServer @@ -13,8 +14,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { public static readonly PlatformExtensionConverter JsonConverter = new PlatformExtensionConverter(); - public bool SupportsCodeActionResolve { get; set; } = false; - + [JsonProperty("_vs_supportsVisualStudioExtensions")] public bool SupportsVisualStudioExtensions { get; set; } = false; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationFileChangeDetector.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationFileChangeDetector.cs index 30dec9439e..a0d959ac61 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationFileChangeDetector.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationFileChangeDetector.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class ProjectConfigurationFileChangeDetector : IFileChangeDetector { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly FilePathNormalizer _filePathNormalizer; private readonly IEnumerable _listeners; private readonly ILogger _logger; @@ -28,14 +28,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer }; public ProjectConfigurationFileChangeDetector( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, IEnumerable listeners, ILoggerFactory loggerFactory = null) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (filePathNormalizer is null) @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(listeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _filePathNormalizer = filePathNormalizer; _listeners = listeners; _logger = loggerFactory?.CreateLogger(); @@ -66,13 +66,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer workspaceDirectory = _filePathNormalizer.Normalize(workspaceDirectory); var existingConfigurationFiles = GetExistingConfigurationFiles(workspaceDirectory); - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { foreach (var configurationFilePath in existingConfigurationFiles) { FileSystemWatcher_ProjectConfigurationFileEvent(configurationFilePath, RazorFileChangeKind.Added); } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); // This is an entry point for testing OnInitializationFinished(); @@ -134,9 +134,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void FileSystemWatcher_ProjectConfigurationFileEvent_Background(string physicalFilePath, RazorFileChangeKind kind) { - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => FileSystemWatcher_ProjectConfigurationFileEvent(physicalFilePath, kind), - CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } private void FileSystemWatcher_ProjectConfigurationFileEvent(string physicalFilePath, RazorFileChangeKind kind) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationStateSynchronizer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationStateSynchronizer.cs index cd6ab0a547..ffbc47d514 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationStateSynchronizer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectConfigurationStateSynchronizer.cs @@ -14,20 +14,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class ProjectConfigurationStateSynchronizer : IProjectConfigurationFileChangeListener { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly RazorProjectService _projectService; private readonly FilePathNormalizer _filePathNormalizer; private readonly Dictionary _configurationToProjectMap; internal readonly Dictionary ProjectInfoMap; public ProjectConfigurationStateSynchronizer( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RazorProjectService projectService, FilePathNormalizer filePathNormalizer) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectService is null) @@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(filePathNormalizer)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectService = projectService; _filePathNormalizer = filePathNormalizer; _configurationToProjectMap = new Dictionary(FilePathComparer.Instance); @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(args)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (args.Kind) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileChangeDetector.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileChangeDetector.cs index 98b947d132..3ec7a8bf5e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileChangeDetector.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileChangeDetector.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { private const string ProjectFileExtension = ".csproj"; private const string ProjectFileExtensionPattern = "*" + ProjectFileExtension; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly FilePathNormalizer _filePathNormalizer; private readonly IEnumerable _listeners; private FileSystemWatcher _watcher; @@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer }; public ProjectFileChangeDetector( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, IEnumerable listeners) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (filePathNormalizer is null) @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(listeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _filePathNormalizer = filePathNormalizer; _listeners = listeners; } @@ -64,13 +64,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer workspaceDirectory = _filePathNormalizer.Normalize(workspaceDirectory); var existingProjectFiles = GetExistingProjectFiles(workspaceDirectory); - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { foreach (var projectFilePath in existingProjectFiles) { FileSystemWatcher_ProjectFileEvent(projectFilePath, RazorFileChangeKind.Added); } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); // This is an entry point for testing OnInitializationFinished(); @@ -134,9 +134,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private void FileSystemWatcher_ProjectFileEvent_Background(string physicalFilePath, RazorFileChangeKind kind) { - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => FileSystemWatcher_ProjectFileEvent(physicalFilePath, kind), - CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } private void FileSystemWatcher_ProjectFileEvent(string physicalFilePath, RazorFileChangeKind kind) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileSynchronizer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileSynchronizer.cs index a75453adf6..9a9ea289f3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileSynchronizer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectFileSynchronizer.cs @@ -10,16 +10,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class ProjectFileSynchronizer : IProjectFileChangeListener { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly RazorProjectService _projectService; public ProjectFileSynchronizer( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RazorProjectService projectService) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectService is null) @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(projectService)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectService = projectService; } @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(filePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (kind) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultDocumentResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultDocumentResolver.cs index 6a9707b2ed..58f79d714c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultDocumentResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultDocumentResolver.cs @@ -10,18 +10,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem { internal class DefaultDocumentResolver : DocumentResolver { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectResolver _projectResolver; private readonly FilePathNormalizer _filePathNormalizer; public DefaultDocumentResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectResolver projectResolver, FilePathNormalizer filePathNormalizer) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectResolver == null) @@ -34,14 +34,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem throw new ArgumentNullException(nameof(filePathNormalizer)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectResolver = projectResolver; _filePathNormalizer = filePathNormalizer; } public override bool TryResolveDocument(string documentFilePath, out DocumentSnapshot document) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var normalizedPath = _filePathNormalizer.Normalize(documentFilePath); if (!_projectResolver.TryResolveProject(normalizedPath, out var project)) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultProjectResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultProjectResolver.cs index 9e9f77bf82..0ace3de1ff 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultProjectResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultProjectResolver.cs @@ -14,18 +14,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem // Internal for testing protected internal readonly HostProject MiscellaneousHostProject; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly FilePathNormalizer _filePathNormalizer; private readonly ProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor; public DefaultProjectResolver( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (filePathNormalizer == null) @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _filePathNormalizer = filePathNormalizer; _projectSnapshotManagerAccessor = projectSnapshotManagerAccessor; @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem throw new ArgumentNullException(nameof(documentFilePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var normalizedDocumentPath = _filePathNormalizer.Normalize(documentFilePath); var projects = _projectSnapshotManagerAccessor.Instance.Projects; @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override ProjectSnapshot GetMiscellaneousProject() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var miscellaneousProject = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(MiscellaneousHostProject.FilePath); if (miscellaneousProject == null) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultRazorProjectService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultRazorProjectService.cs index 41c7f39586..e32028acf4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultRazorProjectService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/ProjectSystem/DefaultRazorProjectService.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem internal class DefaultRazorProjectService : RazorProjectService { private readonly ProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly HostDocumentFactory _hostDocumentFactory; private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory; private readonly ProjectResolver _projectResolver; @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem private readonly ILogger _logger; public DefaultRazorProjectService( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, HostDocumentFactory hostDocumentFactory, RemoteTextLoaderFactory remoteTextLoaderFactory, DocumentResolver documentResolver, @@ -41,9 +41,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (hostDocumentFactory == null) @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _hostDocumentFactory = hostDocumentFactory; _remoteTextLoaderFactory = remoteTextLoaderFactory; _documentResolver = documentResolver; @@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void AddDocument(string filePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var textDocumentPath = _filePathNormalizer.Normalize(filePath); if (_documentResolver.TryResolveDocument(textDocumentPath, out var _)) @@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void OpenDocument(string filePath, SourceText sourceText, int version) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var textDocumentPath = _filePathNormalizer.Normalize(filePath); if (!_documentResolver.TryResolveDocument(textDocumentPath, out _)) @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void CloseDocument(string filePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var textDocumentPath = _filePathNormalizer.Normalize(filePath); if (!_projectResolver.TryResolveProject(textDocumentPath, out var projectSnapshot)) @@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void RemoveDocument(string filePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var textDocumentPath = _filePathNormalizer.Normalize(filePath); if (!_projectResolver.TryResolveProject(textDocumentPath, out var projectSnapshot)) @@ -204,7 +204,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void UpdateDocument(string filePath, SourceText sourceText, int version) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var textDocumentPath = _filePathNormalizer.Normalize(filePath); if (!_projectResolver.TryResolveProject(textDocumentPath, out var projectSnapshot)) @@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void AddProject(string filePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var normalizedPath = _filePathNormalizer.Normalize(filePath); @@ -242,7 +242,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem public override void RemoveProject(string filePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var normalizedPath = _filePathNormalizer.Normalize(filePath); var project = (DefaultProjectSnapshot)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(normalizedPath); @@ -266,7 +266,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem ProjectWorkspaceState projectWorkspaceState, IReadOnlyList documents) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var normalizedPath = _filePathNormalizer.Normalize(filePath); var project = (DefaultProjectSnapshot)_projectSnapshotManagerAccessor.Instance.GetLoadedProject(normalizedPath); @@ -411,7 +411,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem // Internal for testing internal void TryMigrateDocumentsFromRemovedProject(ProjectSnapshot project) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var miscellaneousProject = _projectResolver.GetMiscellaneousProject(); @@ -437,7 +437,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem // Internal for testing internal void TryMigrateMiscellaneousDocumentsToProject() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var miscellaneousProject = _projectResolver.GetMiscellaneousProject(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDiagnosticsPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDiagnosticsPublisher.cs index d00e13321b..56893d9357 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDiagnosticsPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDiagnosticsPublisher.cs @@ -26,20 +26,20 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer internal Timer _documentClosedTimer; private static readonly TimeSpan s_checkForDocumentClosedDelay = TimeSpan.FromSeconds(5); - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ITextDocumentLanguageServer _languageServer; private readonly Dictionary _work; private readonly ILogger _logger; private ProjectSnapshotManager _projectManager; public RazorDiagnosticsPublisher( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ITextDocumentLanguageServer languageServer, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (languageServer == null) @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _languageServer = languageServer; PublishedDiagnostics = new Dictionary>(FilePathComparer.Instance); _work = new Dictionary(FilePathComparer.Instance); @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(document)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); lock (_work) { @@ -114,11 +114,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private async void DocumentClosedTimer_Tick(object state) #pragma warning restore VSTHRD100 // Avoid async void methods { - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( ClearClosedDocuments, - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } // Internal for testing diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentSynchronizationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentSynchronizationEndpoint.cs index d77a30ea50..b231fe0991 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentSynchronizationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorDocumentSynchronizationEndpoint.cs @@ -22,37 +22,37 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { private SynchronizationCapability _capability; private readonly ILogger _logger; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly RazorProjectService _projectService; public RazorDocumentSynchronizationEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorProjectService projectService, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (documentResolver == null) + if (documentResolver is null) { throw new ArgumentNullException(nameof(documentResolver)); } - if (projectService == null) + if (projectService is null) { throw new ArgumentNullException(nameof(projectService)); } - if (loggerFactory == null) + if (loggerFactory is null) { throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _projectService = projectService; _logger = loggerFactory.CreateLogger(); @@ -67,14 +67,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public async Task Handle(DidChangeTextDocumentParams notification, CancellationToken token) { - _foregroundDispatcher.AssertBackgroundThread(); - - var document = await Task.Factory.StartNew(() => + var document = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(notification.TextDocument.Uri.GetAbsoluteOrUNCPath(), out var documentSnapshot); return documentSnapshot; - }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, CancellationToken.None); var sourceText = await document.GetTextAsync(); sourceText = ApplyContentChanges(notification.ContentChanges, sourceText); @@ -84,19 +82,15 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new InvalidOperationException(RazorLS.Resources.Version_Should_Not_Be_Null); } - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectService.UpdateDocument(document.FilePath, sourceText, notification.TextDocument.Version.Value), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); return Unit.Value; } public async Task Handle(DidOpenTextDocumentParams notification, CancellationToken token) { - _foregroundDispatcher.AssertBackgroundThread(); - var sourceText = SourceText.From(notification.TextDocument.Text); if (notification.TextDocument.Version is null) @@ -104,24 +98,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new InvalidOperationException(RazorLS.Resources.Version_Should_Not_Be_Null); } - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectService.OpenDocument(notification.TextDocument.Uri.GetAbsoluteOrUNCPath(), sourceText, notification.TextDocument.Version.Value), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); return Unit.Value; } public async Task Handle(DidCloseTextDocumentParams notification, CancellationToken token) { - _foregroundDispatcher.AssertBackgroundThread(); - - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectService.CloseDocument(notification.TextDocument.Uri.GetAbsoluteOrUNCPath()), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); return Unit.Value; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileChangeDetector.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileChangeDetector.cs index 850336599c..0b81432bc0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileChangeDetector.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileChangeDetector.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer // Internal for testing internal readonly Dictionary PendingNotifications; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly FilePathNormalizer _filePathNormalizer; private readonly IEnumerable _listeners; private readonly List _watchers; @@ -32,13 +32,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer }; public RazorFileChangeDetector( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, IEnumerable listeners) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (filePathNormalizer is null) @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(listeners)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _filePathNormalizer = filePathNormalizer; _listeners = listeners; _watchers = new List(s_razorFileExtensions.Count); @@ -80,13 +80,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer var existingRazorFiles = GetExistingRazorFiles(workspaceDirectory); - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { foreach (var razorFilePath in existingRazorFiles) { FileSystemWatcher_RazorFileEvent(razorFilePath, RazorFileChangeKind.Added); } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); // This is an entry point for testing OnInitializationFinished(); @@ -211,12 +211,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer OnStartingDelayedNotificationWork(); - await Task.Factory.StartNew( - () => NotifyAfterDelay_Foreground(physicalFilePath), - CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => NotifyAfterDelay_ProjectSnapshotManagerDispatcher(physicalFilePath), + CancellationToken.None); } - private void NotifyAfterDelay_Foreground(string physicalFilePath) + private void NotifyAfterDelay_ProjectSnapshotManagerDispatcher(string physicalFilePath) { lock (_pendingNotificationsLock) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileSynchronizer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileSynchronizer.cs index 6afee33451..e91e66e5ed 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileSynchronizer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorFileSynchronizer.cs @@ -10,16 +10,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class RazorFileSynchronizer : IRazorFileChangeListener { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly RazorProjectService _projectService; public RazorFileSynchronizer( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RazorProjectService projectService) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectService is null) @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(projectService)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectService = projectService; } @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(filePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); switch (kind) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageEndpoint.cs index 4397aef4ce..80af7eb585 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageEndpoint.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer IRazorMapToDocumentRangesHandler, IRazorMapToDocumentEditsHandler { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly DocumentVersionCache _documentVersionCache; private readonly RazorDocumentMappingService _documentMappingService; @@ -31,16 +31,16 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private readonly ILogger _logger; public RazorLanguageEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, RazorDocumentMappingService documentMappingService, RazorFormattingService razorFormattingService, ILoggerFactory loggerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentResolver == null) @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentResolver = documentResolver; _documentVersionCache = documentVersionCache; _documentMappingService = documentMappingService; @@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { int? documentVersion = null; DocumentSnapshot documentSnapshot = null; - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.Uri.GetAbsoluteOrUNCPath(), out documentSnapshot); @@ -93,7 +93,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer } return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); var sourceText = await documentSnapshot.GetTextAsync(); @@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer int? documentVersion = null; DocumentSnapshot documentSnapshot = null; - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.RazorDocumentUri.GetAbsoluteOrUNCPath(), out documentSnapshot); @@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { documentVersion = null; } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); if (request.Kind != RazorLanguageKind.CSharp) { @@ -215,7 +215,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer int? documentVersion = null; DocumentSnapshot documentSnapshot = null; - await Task.Factory.StartNew(() => + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.RazorDocumentUri.GetAbsoluteOrUNCPath(), out documentSnapshot); @@ -225,7 +225,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { documentVersion = null; } - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); if (codeDocument.IsUnsupported()) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs index ea6038c9a3..9a99c9c6e9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer // 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 + // 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. // @@ -122,8 +122,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer .WithHandler() .WithHandler() .WithHandler() - .AddHandlerLink(LanguageServerConstants.RazorSemanticTokensEditEndpoint, LanguageServerConstants.LegacyRazorSemanticTokensEditEndpoint) - .AddHandlerLink(LanguageServerConstants.RazorSemanticTokensEndpoint, LanguageServerConstants.LegacyRazorSemanticTokensEndpoint) .WithHandler() .WithHandler() .WithHandler() @@ -138,7 +136,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer .AddLanguageProtocolLogging(logLevel)); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton((services) => services.GetRequiredService()); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorServerReadyPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorServerReadyPublisher.cs index fca66c137e..38b48eaf62 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorServerReadyPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorServerReadyPublisher.cs @@ -11,18 +11,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class RazorServerReadyPublisher : ProjectSnapshotChangeTrigger { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private ProjectSnapshotManagerBase _projectManager; private readonly ClientNotifierServiceBase _clientNotifierService; private bool _hasNotified = false; public RazorServerReadyPublisher( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ClientNotifierServiceBase clientNotifierService) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (clientNotifierService is null) @@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(clientNotifierService)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _clientNotifierService = clientNotifierService; } @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private async void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) #pragma warning restore VSTHRD100 // Avoid async void methods { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var projectSnapshot = args.Newer; if (projectSnapshot?.ProjectWorkspaceState != null && !_hasNotified) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RazorComponentRenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RazorComponentRenameEndpoint.cs index 2a186fbaf0..c3ee45c51d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RazorComponentRenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RazorComponentRenameEndpoint.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring { internal class RazorComponentRenameEndpoint : IRenameHandler { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly ProjectSnapshotManager _projectSnapshotManager; private readonly RazorComponentSearchEngine _componentSearchEngine; @@ -35,13 +35,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring private RenameCapability _capability; public RazorComponentRenameEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, RazorComponentSearchEngine componentSearchEngine, ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor, LanguageServerFeatureOptions languageServerFeatureOptions) { - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _componentSearchEngine = componentSearchEngine ?? throw new ArgumentNullException(nameof(componentSearchEngine)); _projectSnapshotManager = projectSnapshotManagerAccessor?.Instance ?? throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor)); @@ -70,12 +70,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring return null; } - var requestDocumentSnapshot = await Task.Factory.StartNew(() => + var requestDocumentSnapshot = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { var path = request.TextDocument.Uri.GetAbsoluteOrUNCPath(); _documentResolver.TryResolveDocument(path, out var documentSnapshot); return documentSnapshot; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); if (requestDocumentSnapshot is null) { @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring var documentSnapshots = await GetAllDocumentSnapshotsAsync(requestDocumentSnapshot, cancellationToken).ConfigureAwait(false); foreach (var documentSnapshot in documentSnapshots) { - await AddEditsForCodeDocumentAsync(documentChanges, originTagHelpers, request.NewName, documentSnapshot, cancellationToken); + await AddEditsForCodeDocumentAsync(documentChanges, originTagHelpers, request.NewName, documentSnapshot); } return new WorkspaceEdit @@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring private async Task> GetAllDocumentSnapshotsAsync(DocumentSnapshot skipDocumentSnapshot, CancellationToken cancellationToken) { - return await Task.Factory.StartNew(() => + return await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { var documentSnapshots = new List(); var documentPaths = new HashSet(); @@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring } } return documentSnapshots; - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } public void AddFileRenameForComponent(List documentChanges, DocumentSnapshot documentSnapshot, string newPath) @@ -188,12 +188,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring return newPath; } - public async Task AddEditsForCodeDocumentAsync( + private async Task AddEditsForCodeDocumentAsync( List documentChanges, IReadOnlyList originTagHelpers, string newName, - DocumentSnapshot documentSnapshot, - CancellationToken cancellationToken) + DocumentSnapshot documentSnapshot) { if (documentSnapshot is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Models/LegacySemanticTokensOptions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Models/LegacySemanticTokensOptions.cs deleted file mode 100644 index 7adf2e3957..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Models/LegacySemanticTokensOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -#pragma warning disable CS0618 -#nullable enable -using OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals; - -namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models -{ - internal class LegacySemanticTokensOptions - { - public SemanticTokensLegend? Legend { get; set; } - - public bool RangeProvider { get; set; } - - public SemanticTokensDocumentProviderOptions? DocumentProvider { get; set; } - } -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/RazorSemanticTokensEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/RazorSemanticTokensEndpoint.cs index 8a29f556e2..c14e9c99af 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/RazorSemanticTokensEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/RazorSemanticTokensEndpoint.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models; using Microsoft.Extensions.Logging; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -15,7 +14,7 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals; namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic { - internal class RazorSemanticTokensEndpoint : ISemanticTokensHandler, ISemanticTokensRangeHandler, ISemanticTokensDeltaHandler, IRegistrationExtension + internal class RazorSemanticTokensEndpoint : ISemanticTokensHandler, ISemanticTokensRangeHandler, ISemanticTokensDeltaHandler { private SemanticTokensCapability? _capability; @@ -96,19 +95,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic _capability = capability; } - public RegistrationExtensionResult GetRegistration() - { - return new RegistrationExtensionResult(LanguageServerConstants.SemanticTokensProviderName, new LegacySemanticTokensOptions - { - DocumentProvider = new SemanticTokensDocumentProviderOptions - { - Edits = true, - }, - Legend = RazorSemanticTokensLegend.Instance, - RangeProvider = true, - }); - } - private async Task HandleAsync(TextDocumentIdentifier textDocument, CancellationToken cancellationToken, Range? range = null) { var tokens = await _semanticTokensInfoService.GetSemanticTokensAsync(textDocument, range, cancellationToken); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/DefaultRazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/DefaultRazorSemanticTokensInfoService.cs index 6e28c50a61..b60768a775 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/DefaultRazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/DefaultRazorSemanticTokensInfoService.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic private readonly MemoryCache> _csharpGeneratedSemanticTokensCache = new(); // For C# generated docs private readonly ClientNotifierServiceBase _languageServer; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentResolver _documentResolver; private readonly DocumentVersionCache _documentVersionCache; private readonly ILogger _logger; @@ -43,14 +43,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic public DefaultRazorSemanticTokensInfoService( ClientNotifierServiceBase languageServer, RazorDocumentMappingService documentMappingService, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, ILoggerFactory loggerFactory) { _languageServer = languageServer ?? throw new ArgumentNullException(nameof(languageServer)); _documentMappingService = documentMappingService ?? throw new ArgumentNullException(nameof(documentMappingService)); - _foregroundDispatcher = foregroundDispatcher ?? throw new ArgumentNullException(nameof(foregroundDispatcher)); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); _documentResolver = documentResolver ?? throw new ArgumentNullException(nameof(documentResolver)); _documentVersionCache = documentVersionCache ?? throw new ArgumentNullException(nameof(documentVersionCache)); @@ -561,13 +561,13 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic private async Task<(DocumentSnapshot Snapshot, int? Version)> TryGetDocumentInfoAsync(string absolutePath, CancellationToken cancellationToken) { - var documentInfo = await Task.Factory.StartNew(() => + var documentInfo = await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(absolutePath, out var documentSnapshot); _documentVersionCache.TryGetDocumentVersion(documentSnapshot, out var version); return (documentSnapshot, version); - }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + }, cancellationToken); return documentInfo; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextElement.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextElement.cs index cbb429f97f..61a85f525e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextElement.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextElement.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Tooltip /// internal sealed class VSClassifiedTextElement { - [JsonProperty("type")] + [JsonProperty("_vs_type")] public static readonly string Type = "ClassifiedTextElement"; public const string TextClassificationTypeName = "text"; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextRun.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextRun.cs index c8c79e338d..8bde06cc25 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextRun.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSClassifiedTextRun.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Tooltip /// internal sealed class VSClassifiedTextRun { - [JsonProperty("type")] + [JsonProperty("_vs_type")] public static readonly string Type = "ClassifiedTextRun"; public VSClassifiedTextRun(string classificationTypeName, string text) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSContainerElement.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSContainerElement.cs index 588fc90ea0..4acfd60ed7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSContainerElement.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSContainerElement.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Tooltip /// internal sealed class VSContainerElement { - [JsonProperty("type")] + [JsonProperty("_vs_type")] public static readonly string Type = "ContainerElement"; public VSContainerElement(VSContainerElementStyle style, IEnumerable elements) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageElement.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageElement.cs index 1a81928376..ea2c522537 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageElement.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageElement.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Tooltip /// internal class VSImageElement { - [JsonProperty("type")] + [JsonProperty("_vs_type")] public static readonly string Type = "ImageElement"; public static readonly VSImageElement Empty = new(default, string.Empty); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageId.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageId.cs index c202aa23d7..b95638ee16 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageId.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Tooltip/VSImageId.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Tooltip /// internal class VSImageId : IEquatable { - [JsonProperty("type")] + [JsonProperty("_vs_type")] public static readonly string Type = "ImageId"; [JsonProperty("Guid")] diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/UnsynchronizableContentDocumentProcessedListener.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/UnsynchronizableContentDocumentProcessedListener.cs index 15b19d655f..2188f01d39 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/UnsynchronizableContentDocumentProcessedListener.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/UnsynchronizableContentDocumentProcessedListener.cs @@ -9,19 +9,19 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer { internal class UnsynchronizableContentDocumentProcessedListener : DocumentProcessedListener { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly DocumentVersionCache _documentVersionCache; private readonly GeneratedDocumentPublisher _generatedDocumentPublisher; private ProjectSnapshotManager _projectManager; public UnsynchronizableContentDocumentProcessedListener( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentVersionCache documentVersionCache, GeneratedDocumentPublisher generatedDocumentPublisher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (documentVersionCache == null) @@ -34,14 +34,14 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer throw new ArgumentNullException(nameof(generatedDocumentPublisher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _documentVersionCache = documentVersionCache; _generatedDocumentPublisher = generatedDocumentPublisher; } public override void DocumentProcessed(DocumentSnapshot document) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_projectManager.IsDocumentOpen(document.FilePath)) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpForegroundDispatcher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpForegroundDispatcher.cs deleted file mode 100644 index 7e3b71230b..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpForegroundDispatcher.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.LanguageServer.Common; - -namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin -{ - public class DefaultOmniSharpForegroundDispatcher : OmniSharpForegroundDispatcher - { - public DefaultOmniSharpForegroundDispatcher() - { - InternalDispatcher = new DefaultForegroundDispatcher(); - } - - public override bool IsForegroundThread => InternalDispatcher.IsForegroundThread; - public override TaskScheduler ForegroundScheduler => InternalDispatcher.ForegroundScheduler; - public override TaskScheduler BackgroundScheduler => InternalDispatcher.BackgroundScheduler; - - public override void AssertBackgroundThread([CallerMemberName] string caller = null) => InternalDispatcher.AssertBackgroundThread(caller); - public override void AssertForegroundThread([CallerMemberName] string caller = null) => InternalDispatcher.AssertForegroundThread(caller); - } -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerAccessor.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerAccessor.cs index 6f1385db78..506723c5dd 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerAccessor.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerAccessor.cs @@ -15,14 +15,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin { private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory; private readonly IEnumerable _projectChangeTriggers; - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; + private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly Workspace _workspace; private OmniSharpProjectSnapshotManager _instance; public DefaultOmniSharpProjectSnapshotManagerAccessor( RemoteTextLoaderFactory remoteTextLoaderFactory, IEnumerable projectChangeTriggers, - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, Workspace workspace) { if (remoteTextLoaderFactory is null) @@ -35,9 +35,9 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin throw new ArgumentNullException(nameof(projectChangeTriggers)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspace == null) @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin _remoteTextLoaderFactory = remoteTextLoaderFactory; _projectChangeTriggers = projectChangeTriggers; - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _workspace = workspace; } @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin if (_instance == null) { var projectSnapshotManager = new DefaultProjectSnapshotManager( - _foregroundDispatcher.InternalDispatcher, + _projectSnapshotManagerDispatcher.InternalDispatcher, new DefaultErrorReporter(), Enumerable.Empty(), _workspace); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerDispatcher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerDispatcher.cs new file mode 100644 index 0000000000..44bb9109be --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/DefaultOmniSharpProjectSnapshotManagerDispatcher.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Razor.Workspaces; + +namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin +{ + public class DefaultOmniSharpProjectSnapshotManagerDispatcher : OmniSharpProjectSnapshotManagerDispatcher + { + public DefaultOmniSharpProjectSnapshotManagerDispatcher() + { + InternalDispatcher = new DefaultProjectSnapshotManagerDispatcher(); + } + + public override TaskScheduler DispatcherScheduler => InternalDispatcher.DispatcherScheduler; + + public override void AssertDispatcherThread([CallerMemberName] string caller = null) => InternalDispatcher.AssertDispatcherThread(caller); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpBackgroundDocumentGenerator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpBackgroundDocumentGenerator.cs index ecd7d34bd3..0bd7680b47 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpBackgroundDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpBackgroundDocumentGenerator.cs @@ -15,13 +15,13 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed private readonly BackgroundDocumentGenerator _backgroundDocumentGenerator; public OmniSharpBackgroundDocumentGenerator( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RemoteTextLoaderFactory remoteTextLoaderFactory, IEnumerable documentProcessedListeners) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (remoteTextLoaderFactory is null) @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed } var wrappedListeners = documentProcessedListeners.Select(listener => new WrappedDocumentProcessedListener(remoteTextLoaderFactory, listener)); - _backgroundDocumentGenerator = new BackgroundDocumentGenerator(foregroundDispatcher.InternalDispatcher, wrappedListeners); + _backgroundDocumentGenerator = new BackgroundDocumentGenerator(projectSnapshotManagerDispatcher.InternalDispatcher, wrappedListeners); } public void Initialize(OmniSharpProjectSnapshotManagerBase projectManager) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpForegroundDispatcher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpForegroundDispatcher.cs deleted file mode 100644 index 712f78b611..0000000000 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpForegroundDispatcher.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; - -namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin -{ - public abstract class OmniSharpForegroundDispatcher - { - internal ForegroundDispatcher InternalDispatcher { get; private protected set; } - - public abstract bool IsForegroundThread { get; } - - public abstract TaskScheduler ForegroundScheduler { get; } - - public abstract TaskScheduler BackgroundScheduler { get; } - - public abstract void AssertForegroundThread([CallerMemberName] string caller = null); - - public abstract void AssertBackgroundThread([CallerMemberName] string caller = null); - } -} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectSnapshotManagerDispatcher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectSnapshotManagerDispatcher.cs new file mode 100644 index 0000000000..044f5eb11a --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectSnapshotManagerDispatcher.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Razor; + +namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin +{ + public abstract class OmniSharpProjectSnapshotManagerDispatcher + { + internal ProjectSnapshotManagerDispatcher InternalDispatcher { get; private protected set; } + + public abstract TaskScheduler DispatcherScheduler { get; } + + public Task RunOnDispatcherThreadAsync(Action action, CancellationToken cancellationToken) + => InternalDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken); + + public Task RunOnDispatcherThreadAsync(Func action, CancellationToken cancellationToken) + => InternalDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken); + + public abstract void AssertDispatcherThread([CallerMemberName] string caller = null); + } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectWorkspaceStateGenerator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectWorkspaceStateGenerator.cs index 737e9b1914..d3a38724e1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectWorkspaceStateGenerator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpProjectWorkspaceStateGenerator.cs @@ -15,14 +15,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed { } - public OmniSharpProjectWorkspaceStateGenerator(OmniSharpForegroundDispatcher foregroundDispatcher) + public OmniSharpProjectWorkspaceStateGenerator(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - InternalWorkspaceStateGenerator = new DefaultProjectWorkspaceStateGenerator(foregroundDispatcher.InternalDispatcher); + InternalWorkspaceStateGenerator = new DefaultProjectWorkspaceStateGenerator(projectSnapshotManagerDispatcher.InternalDispatcher); } internal DefaultProjectWorkspaceStateGenerator InternalWorkspaceStateGenerator { get; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpWorkspaceProjectStateChangeDetector.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpWorkspaceProjectStateChangeDetector.cs index 2f3667fa11..9b23eba340 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpWorkspaceProjectStateChangeDetector.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed/OmniSharpWorkspaceProjectStateChangeDetector.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; @@ -14,12 +13,12 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed public class OmniSharpWorkspaceProjectStateChangeDetector : IOmniSharpProjectSnapshotManagerChangeTrigger { public OmniSharpWorkspaceProjectStateChangeDetector( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspaceStateGenerator == null) @@ -27,8 +26,8 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed throw new ArgumentNullException(nameof(workspaceStateGenerator)); } - InternalWorkspaceProjectStateChangeDetector = new ForegroundWorkspaceProjectStateChangeDetector( - foregroundDispatcher.InternalDispatcher, + InternalWorkspaceProjectStateChangeDetector = new ProjectSnapshotManagerWorkspaceProjectStateChangeDetector( + projectSnapshotManagerDispatcher.InternalDispatcher, workspaceStateGenerator.InternalWorkspaceStateGenerator); } @@ -39,37 +38,31 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed InternalWorkspaceProjectStateChangeDetector.Initialize(projectManager.InternalProjectSnapshotManager); } - private class ForegroundWorkspaceProjectStateChangeDetector : WorkspaceProjectStateChangeDetector + private class ProjectSnapshotManagerWorkspaceProjectStateChangeDetector : WorkspaceProjectStateChangeDetector { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; - public ForegroundWorkspaceProjectStateChangeDetector( - ForegroundDispatcher foregroundDispatcher, - ProjectWorkspaceStateGenerator workspaceStateGenerator) : base(workspaceStateGenerator) + public ProjectSnapshotManagerWorkspaceProjectStateChangeDetector( + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + ProjectWorkspaceStateGenerator workspaceStateGenerator) : base(workspaceStateGenerator, projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } - // We override the InitializeSolution in order to enforce calls to this to be on the foreground thread. - // OmniSharp currently has an issue where they update the Solution on multiple different threads resulting + // We override the InitializeSolution in order to enforce calls to this to be on the project snapshot manager's + // thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting // in change events dispatching through the Workspace on multiple different threads. This normalizes // that abnormality. #pragma warning disable VSTHRD100 // Avoid async void methods protected override async void InitializeSolution(Solution solution) #pragma warning restore VSTHRD100 // Avoid async void methods { - if (_foregroundDispatcher.IsForegroundThread) - { - base.InitializeSolution(solution); - return; - } - - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => { try @@ -81,25 +74,18 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed Debug.Fail("Unexpected error when initializing solution: " + ex); } }, - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } - // We override Workspace_WorkspaceChanged in order to enforce calls to this to be on the foreground thread. - // OmniSharp currently has an issue where they update the Solution on multiple different threads resulting + // We override Workspace_WorkspaceChanged in order to enforce calls to this to be on the project snapshot manager's + // thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting // in change events dispatching through the Workspace on multiple different threads. This normalizes // that abnormality. #pragma warning disable VSTHRD100 // Avoid async void methods internal override async void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args) #pragma warning restore VSTHRD100 // Avoid async void methods { - if (_foregroundDispatcher.IsForegroundThread) - { - base.Workspace_WorkspaceChanged(sender, args); - return; - } - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => { try @@ -111,9 +97,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin.StrongNamed Debug.Fail("Unexpected error when handling a workspace changed event: " + ex); } }, - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/BackgroundDocumentProcessedPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/BackgroundDocumentProcessedPublisher.cs index 0eb724c5c9..96a69e6e3c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/BackgroundDocumentProcessedPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/BackgroundDocumentProcessedPublisher.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin internal const string ActiveVirtualDocumentSuffix = "__virtual.cs"; internal const string BackgroundVirtualDocumentSuffix = "__bg" + ActiveVirtualDocumentSuffix; - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; + private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly OmniSharpWorkspace _workspace; private readonly ILogger _logger; private OmniSharpProjectSnapshotManager _projectManager; @@ -43,13 +43,13 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin [ImportingConstructor] public BackgroundDocumentProcessedPublisher( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, OmniSharpWorkspace workspace, ILoggerFactory loggerFactory) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspace is null) @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin throw new ArgumentNullException(nameof(loggerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _workspace = workspace; _logger = loggerFactory.CreateLogger(); _workspaceChangedLock = new object(); @@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin throw new ArgumentNullException(nameof(document)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); lock (_workspaceChangedLock) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DefaultProjectInstanceEvaluator.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DefaultProjectInstanceEvaluator.cs index 07f841baea..433b8d7b95 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DefaultProjectInstanceEvaluator.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DefaultProjectInstanceEvaluator.cs @@ -35,31 +35,22 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin private const string RazorGenerateDesignTimeTargetName = "RazorGenerateDesignTime"; private const string RazorGenerateComponentDesignTimeTargetName = "RazorGenerateComponentDesignTime"; private static readonly IEnumerable s_emptyMSBuildLoggers = Enumerable.Empty(); - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; private readonly object _evaluationLock = new object(); [ImportingConstructor] - public DefaultProjectInstanceEvaluator(OmniSharpForegroundDispatcher foregroundDispatcher) + public DefaultProjectInstanceEvaluator() { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - _foregroundDispatcher = foregroundDispatcher; } public override ProjectInstance Evaluate(ProjectInstance projectInstance) { - if (projectInstance == null) + if (projectInstance is null) { throw new ArgumentNullException(nameof(projectInstance)); } lock (_evaluationLock) { - _foregroundDispatcher.AssertBackgroundThread(); - var refreshTargets = new List() { // These are the default targets for the project instance that OmniSharp runs. diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DocumentChangedSynchronizationService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DocumentChangedSynchronizationService.cs index 24a2823952..876abf1d59 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DocumentChangedSynchronizationService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/DocumentChangedSynchronizationService.cs @@ -4,7 +4,6 @@ using System; using System.Composition; using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.OmniSharpPlugin; namespace Microsoft.AspNetCore.Razor.LanguageServer.Common @@ -14,18 +13,18 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common [Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))] internal class DocumentChangedSynchronizationService : IRazorDocumentChangeListener, IOmniSharpProjectSnapshotManagerChangeTrigger { - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; + private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private OmniSharpProjectSnapshotManagerBase _projectManager; [ImportingConstructor] - public DocumentChangedSynchronizationService(OmniSharpForegroundDispatcher foregroundDispatcher) + public DocumentChangedSynchronizationService(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public void Initialize(OmniSharpProjectSnapshotManagerBase projectManager) @@ -53,9 +52,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common var projectFilePath = args.UnevaluatedProjectInstance.ProjectFileLocation.File; var documentFilePath = args.FilePath; - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectManager.DocumentChanged(projectFilePath, documentFilePath), - CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + CancellationToken.None).ConfigureAwait(false); } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/MSBuildProjectManager.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/MSBuildProjectManager.cs index 9520c7689a..282caaee00 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/MSBuildProjectManager.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/MSBuildProjectManager.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin private readonly IEnumerable _projectConfigurationProviders; private readonly ProjectInstanceEvaluator _projectInstanceEvaluator; private readonly ProjectChangePublisher _projectConfigurationPublisher; - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; + private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private OmniSharpProjectSnapshotManagerBase _projectManager; [ImportingConstructor] @@ -42,30 +42,30 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin [ImportMany] IEnumerable projectConfigurationProviders, ProjectInstanceEvaluator projectInstanceEvaluator, ProjectChangePublisher projectConfigurationPublisher, - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ILoggerFactory loggerFactory) { - if (projectConfigurationProviders == null) + if (projectConfigurationProviders is null) { throw new ArgumentNullException(nameof(projectConfigurationProviders)); } - if (projectInstanceEvaluator == null) + if (projectInstanceEvaluator is null) { throw new ArgumentNullException(nameof(projectInstanceEvaluator)); } - if (projectConfigurationPublisher == null) + if (projectConfigurationPublisher is null) { throw new ArgumentNullException(nameof(projectConfigurationPublisher)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (loggerFactory == null) + if (loggerFactory is null) { throw new ArgumentNullException(nameof(loggerFactory)); } @@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin _projectConfigurationProviders = projectConfigurationProviders; _projectInstanceEvaluator = projectInstanceEvaluator; _projectConfigurationPublisher = projectConfigurationPublisher; - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public void Initialize(OmniSharpProjectSnapshotManagerBase projectManager) @@ -103,19 +103,14 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin public void RazorDocumentChanged(RazorFileChangeEventArgs args) { - _foregroundDispatcher.AssertBackgroundThread(); - if (args.Kind == RazorFileChangeKind.Added || args.Kind == RazorFileChangeKind.Removed) { // When documents get added or removed we need to refresh project state to properly reflect the host documents in the project. var evaluatedProjectInstance = _projectInstanceEvaluator.Evaluate(args.UnevaluatedProjectInstance); - _ = Task.Factory.StartNew( - () => UpdateProjectState(evaluatedProjectInstance), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => UpdateProjectState(evaluatedProjectInstance), CancellationToken.None).ConfigureAwait(false); } } @@ -142,13 +137,13 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin // Force project instance evaluation to ensure that all Razor specific targets have run. projectInstance = _projectInstanceEvaluator.Evaluate(projectInstance); - await Task.Factory.StartNew(() => UpdateProjectState(projectInstance), - CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => UpdateProjectState(projectInstance), CancellationToken.None); } private void UpdateProjectState(ProjectInstance projectInstance) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var projectFilePath = projectInstance.GetPropertyValue(MSBuildProjectFullPathPropertyName); if (string.IsNullOrEmpty(projectFilePath)) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.csproj b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.csproj index 8f01686036..1a945de38f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.csproj +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/Microsoft.AspNetCore.Razor.OmniSharpPlugin.csproj @@ -13,9 +13,10 @@ - + + diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/OmniSharpStrongNamedExports.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/OmniSharpStrongNamedExports.cs index da776e7b2c..6bc30e8ca0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/OmniSharpStrongNamedExports.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/OmniSharpStrongNamedExports.cs @@ -21,8 +21,8 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin } [Shared] - [Export(typeof(OmniSharpForegroundDispatcher))] - internal class ExportOmniSharpForegroundDispatcher : DefaultOmniSharpForegroundDispatcher + [Export(typeof(OmniSharpProjectSnapshotManagerDispatcher))] + internal class ExportOmniSharpProjectSnapshotManagerDispatcher : DefaultOmniSharpProjectSnapshotManagerDispatcher { } @@ -44,8 +44,8 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public ExportDefaultOmniSharpProjectSnapshotManagerAccessor( RemoteTextLoaderFactory remoteTextLoaderFactory, [ImportMany] IEnumerable projectChangeTriggers, - OmniSharpForegroundDispatcher foregroundDispatcher, - OmniSharpWorkspace workspace) : base(remoteTextLoaderFactory, projectChangeTriggers, foregroundDispatcher, workspace) + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + OmniSharpWorkspace workspace) : base(remoteTextLoaderFactory, projectChangeTriggers, projectSnapshotManagerDispatcher, workspace) { } } @@ -56,8 +56,8 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin { [ImportingConstructor] public ExportOmniSharpWorkspaceProjectStateChangeDetector( - OmniSharpForegroundDispatcher foregroundDispatcher, - OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator) : base(foregroundDispatcher, workspaceStateGenerator) + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator) : base(projectSnapshotManagerDispatcher, workspaceStateGenerator) { } } @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public class ExportOmniSharpProjectWorkspaceStateGenerator : OmniSharpProjectWorkspaceStateGenerator { [ImportingConstructor] - public ExportOmniSharpProjectWorkspaceStateGenerator(OmniSharpForegroundDispatcher foregroundDispatcher) : base(foregroundDispatcher) + public ExportOmniSharpProjectWorkspaceStateGenerator(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(projectSnapshotManagerDispatcher) { } } @@ -79,9 +79,9 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin { [ImportingConstructor] public ExportOmniSharpBackgroundDocumentGenerator( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RemoteTextLoaderFactory remoteTextLoaderFactory, - [ImportMany] IEnumerable documentProcessedListeners) : base(foregroundDispatcher, remoteTextLoaderFactory, documentProcessedListeners) + [ImportMany] IEnumerable documentProcessedListeners) : base(projectSnapshotManagerDispatcher, remoteTextLoaderFactory, documentProcessedListeners) { } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/TagHelperRefreshTrigger.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/TagHelperRefreshTrigger.cs index fc39558537..a5c52715c4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/TagHelperRefreshTrigger.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.OmniSharpPlugin/TagHelperRefreshTrigger.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin [Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))] internal class TagHelperRefreshTrigger : IMSBuildEventSink, IRazorDocumentOutputChangeListener, IOmniSharpProjectSnapshotManagerChangeTrigger, IRazorDocumentChangeListener { - private readonly OmniSharpForegroundDispatcher _foregroundDispatcher; + private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly Workspace _omniSharpWorkspace; private readonly OmniSharpProjectWorkspaceStateGenerator _workspaceStateGenerator; private readonly Dictionary _deferredUpdates; @@ -30,22 +30,22 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin [ImportingConstructor] public TagHelperRefreshTrigger( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, OmniSharpWorkspace omniSharpWorkspace, OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator) : - this(foregroundDispatcher, (Workspace)omniSharpWorkspace, workspaceStateGenerator) + this(projectSnapshotManagerDispatcher, (Workspace)omniSharpWorkspace, workspaceStateGenerator) { } // Internal for testing internal TagHelperRefreshTrigger( - OmniSharpForegroundDispatcher foregroundDispatcher, + OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, Workspace omniSharpWorkspace, OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (omniSharpWorkspace == null) @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin throw new ArgumentNullException(nameof(workspaceStateGenerator)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _omniSharpWorkspace = omniSharpWorkspace; _workspaceStateGenerator = workspaceStateGenerator; _deferredUpdates = new Dictionary(); @@ -85,11 +85,9 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin // Project file was modified or impacted in a significant way. - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => EnqueueUpdate(args.ProjectInstance.ProjectFileLocation.File), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + CancellationToken.None).ConfigureAwait(false); } public void RazorDocumentChanged(RazorFileChangeEventArgs args) @@ -113,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin }, CancellationToken.None, TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + _projectSnapshotManagerDispatcher.DispatcherScheduler).ConfigureAwait(false); } public void RazorDocumentOutputChanged(RazorFileChangeEventArgs args) @@ -129,7 +127,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin () => EnqueueUpdate(args.UnevaluatedProjectInstance.ProjectFileLocation.File), CancellationToken.None, TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + _projectSnapshotManagerDispatcher.DispatcherScheduler).ConfigureAwait(false); } // Internal for testing @@ -152,7 +150,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin private void EnqueueUpdate(string projectFilePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); // A race is not possible here because we use the main thread to synchronize the updates // by capturing the sync context. @@ -177,7 +175,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin // Internal for testing internal bool IsComponentFile(string relativeDocumentFilePath, string projectFilePath) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var projectSnapshot = _projectManager.GetLoadedProject(projectFilePath); if (projectSnapshot == null) diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultProjectEngineFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectEngineFactory.cs similarity index 90% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultProjectEngineFactory.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectEngineFactory.cs index abe963830a..bdd8b41dc6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultProjectEngineFactory.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectEngineFactory.cs @@ -3,9 +3,8 @@ using System; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { [ExportCustomProjectEngineFactory("Default", SupportsSerialization = true)] internal class DefaultProjectEngineFactory : IProjectEngineFactory diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/DefaultForegroundDispatcher.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectSnapshotManagerDispatcher.cs similarity index 70% rename from src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/DefaultForegroundDispatcher.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectSnapshotManagerDispatcher.cs index 1ffde091a8..9ef41f2eed 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer.Common/DefaultForegroundDispatcher.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectSnapshotManagerDispatcher.cs @@ -5,26 +5,24 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.AspNetCore.Razor.LanguageServer.Common +namespace Microsoft.CodeAnalysis.Razor.Workspaces { - internal class DefaultForegroundDispatcher : ForegroundDispatcher + internal class DefaultProjectSnapshotManagerDispatcher : ProjectSnapshotManagerDispatcher { - public override bool IsForegroundThread => Thread.CurrentThread.ManagedThreadId == ForegroundTaskScheduler.Instance.ForegroundThreadId; + public override bool IsDispatcherThread + => Thread.CurrentThread.ManagedThreadId == ProjectSnapshotManagerTaskScheduler.Instance.ThreadId; - public override TaskScheduler ForegroundScheduler { get; } = ForegroundTaskScheduler.Instance; + public override TaskScheduler DispatcherScheduler { get; } = ProjectSnapshotManagerTaskScheduler.Instance; - public override TaskScheduler BackgroundScheduler { get; } = TaskScheduler.Default; - - internal class ForegroundTaskScheduler : TaskScheduler + internal class ProjectSnapshotManagerTaskScheduler : TaskScheduler { - public static ForegroundTaskScheduler Instance = new ForegroundTaskScheduler(); + public static ProjectSnapshotManagerTaskScheduler Instance = new(); private readonly Thread _thread; - private readonly BlockingCollection _tasks = new BlockingCollection(); + private readonly BlockingCollection _tasks = new(); - private ForegroundTaskScheduler() + private ProjectSnapshotManagerTaskScheduler() { _thread = new Thread(ThreadStart) { @@ -34,7 +32,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common _thread.Start(); } - public int ForegroundThreadId => _thread.ManagedThreadId; + public int ThreadId => _thread.ManagedThreadId; public override int MaximumConcurrencyLevel => 1; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectWorkspaceStateGenerator.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectWorkspaceStateGenerator.cs index af94209ccc..d0ea115ab6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectWorkspaceStateGenerator.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectWorkspaceStateGenerator.cs @@ -20,21 +20,21 @@ namespace Microsoft.CodeAnalysis.Razor // Internal for testing internal readonly Dictionary Updates; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly SemaphoreSlim _semaphore; private ProjectSnapshotManagerBase _projectManager; private TagHelperResolver _tagHelperResolver; private bool _disposed; [ImportingConstructor] - public DefaultProjectWorkspaceStateGenerator(ForegroundDispatcher foregroundDispatcher) + public DefaultProjectWorkspaceStateGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _semaphore = new SemaphoreSlim(initialCount: 1); Updates = new Dictionary(FilePathComparer.Instance); @@ -65,7 +65,7 @@ namespace Microsoft.CodeAnalysis.Razor throw new ArgumentNullException(nameof(projectSnapshot)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_disposed) { @@ -89,7 +89,7 @@ namespace Microsoft.CodeAnalysis.Razor () => UpdateWorkspaceStateAsync(workspaceProject, projectSnapshot, lcts.Token), lcts.Token, TaskCreationOptions.None, - _foregroundDispatcher.BackgroundScheduler).Unwrap(); + TaskScheduler.Default).Unwrap(); updateTask.ConfigureAwait(false); updateItem = new UpdateItem(updateTask, lcts); Updates[projectSnapshot.FilePath] = updateItem; @@ -97,8 +97,6 @@ namespace Microsoft.CodeAnalysis.Razor public void Dispose() { - _foregroundDispatcher.AssertForegroundThread(); - _disposed = true; foreach (var update in Updates) @@ -132,8 +130,6 @@ namespace Microsoft.CodeAnalysis.Razor try { - _foregroundDispatcher.AssertBackgroundThread(); - OnStartingBackgroundWork(); if (cancellationToken.IsCancellationRequested) @@ -168,11 +164,10 @@ namespace Microsoft.CodeAnalysis.Razor } catch (Exception ex) { - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectManager.ReportError(ex, projectSnapshot), - CancellationToken.None, // Don't allow errors to be cancelled - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + // Don't allow errors to be cancelled + CancellationToken.None).ConfigureAwait(false); return; } @@ -182,7 +177,7 @@ namespace Microsoft.CodeAnalysis.Razor return; } - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => { if (cancellationToken.IsCancellationRequested) @@ -192,9 +187,7 @@ namespace Microsoft.CodeAnalysis.Razor ReportWorkspaceStateChange(projectSnapshot.FilePath, workspaceState); }, - cancellationToken, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -204,11 +197,10 @@ namespace Microsoft.CodeAnalysis.Razor catch (Exception ex) { // This is something totally unexpected, let's just send it over to the project manager. - await Task.Factory.StartNew( + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => _projectManager.ReportError(ex), - CancellationToken.None, // Don't allow errors to be cancelled - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + // Don't allow errors to be cancelled + CancellationToken.None).ConfigureAwait(false); } finally { @@ -227,7 +219,7 @@ namespace Microsoft.CodeAnalysis.Razor private void ReportWorkspaceStateChange(string projectFilePath, ProjectWorkspaceState workspaceStateChange) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _projectManager.ProjectWorkspaceStateChanged(projectFilePath, workspaceStateChange); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ForegroundDispatcher.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ForegroundDispatcher.cs deleted file mode 100644 index 39aea4722d..0000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ForegroundDispatcher.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace Microsoft.CodeAnalysis.Razor -{ - internal abstract class ForegroundDispatcher - { - public abstract bool IsForegroundThread { get; } - - public abstract TaskScheduler ForegroundScheduler { get; } - - public abstract TaskScheduler BackgroundScheduler { get; } - - public virtual void AssertForegroundThread([CallerMemberName] string caller = null) - { - if (!IsForegroundThread) - { - caller = caller == null ? Workspaces.Resources.ForegroundDispatcher_NoMethodNamePlaceholder : $"'{caller}'"; - throw new InvalidOperationException(Workspaces.Resources.FormatForegroundDispatcher_AssertForegroundThread(caller)); - } - } - - public virtual void AssertBackgroundThread([CallerMemberName] string caller = null) - { - if (IsForegroundThread) - { - caller = caller == null ? Workspaces.Resources.ForegroundDispatcher_NoMethodNamePlaceholder : $"'{caller}'"; - throw new InvalidOperationException(Workspaces.Resources.FormatForegroundDispatcher_AssertBackgroundThread(caller)); - } - } - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/JoinableTaskContextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/JoinableTaskContextExtensions.cs new file mode 100644 index 0000000000..efc0c35969 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/JoinableTaskContextExtensions.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using Microsoft.VisualStudio.Threading; + +namespace Microsoft.CodeAnalysis.Razor.Workspaces +{ + internal static class JoinableTaskContextExtensions + { + public static void AssertUIThread(this JoinableTaskContext joinableTaskContext, [CallerMemberName] string caller = null) + { + if (!joinableTaskContext.IsOnMainThread) + { + caller = caller is null ? "The method" : $"'{caller}'"; + throw new InvalidOperationException($"{caller} must be called on the UI thread."); + } + } + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_0.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_0.cs similarity index 94% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_0.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_0.cs index 84007ad73f..74b1004091 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_0.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_0.cs @@ -4,9 +4,8 @@ using System; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { [ExportCustomProjectEngineFactory("MVC-1.0", SupportsSerialization = true)] internal class LegacyProjectEngineFactory_1_0 : IProjectEngineFactory diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_1.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_1.cs similarity index 94% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_1.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_1.cs index 2e31c46990..a6781731c4 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_1_1.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_1_1.cs @@ -4,9 +4,8 @@ using System; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { [ExportCustomProjectEngineFactory("MVC-1.1", SupportsSerialization = true)] internal class LegacyProjectEngineFactory_1_1 : IProjectEngineFactory diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_0.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_0.cs similarity index 94% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_0.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_0.cs index 83f217d295..147bb126d0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_0.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_0.cs @@ -4,9 +4,8 @@ using System; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { [ExportCustomProjectEngineFactory("MVC-2.0", SupportsSerialization = true)] internal class LegacyProjectEngineFactory_2_0 : IProjectEngineFactory diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_1.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_1.cs similarity index 94% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_1.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_1.cs index f48989904a..bba9a8bce9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_2_1.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_2_1.cs @@ -4,9 +4,8 @@ using System; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { // Currently we provide a fixed configuration for 2.1, but this is a point-in-time issue. We plan // to make the 2.1 configuration more flexible and less hardcoded. diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_3_0.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_3_0.cs similarity index 94% rename from src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_3_0.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_3_0.cs index 8cc36de057..23d6f77905 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/LegacyProjectEngineFactory_3_0.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LegacyProjectEngineFactory_3_0.cs @@ -4,9 +4,8 @@ using System; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.VisualStudio.Editor.Razor +namespace Microsoft.CodeAnalysis.Razor.Workspaces { [ExportCustomProjectEngineFactory("MVC-3.0", SupportsSerialization = true)] internal class LegacyProjectEngineFactory_3_0 : IProjectEngineFactory diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Microsoft.CodeAnalysis.Razor.Workspaces.csproj b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Microsoft.CodeAnalysis.Razor.Workspaces.csproj index 338fb2b5c1..19e685ea18 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Microsoft.CodeAnalysis.Razor.Workspaces.csproj +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Microsoft.CodeAnalysis.Razor.Workspaces.csproj @@ -14,6 +14,9 @@ + + + diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSnapshotManagerDispatcher.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSnapshotManagerDispatcher.cs new file mode 100644 index 0000000000..035d1e74db --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSnapshotManagerDispatcher.cs @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Razor +{ + internal abstract class ProjectSnapshotManagerDispatcher + { + public abstract bool IsDispatcherThread { get; } + + public abstract TaskScheduler DispatcherScheduler { get; } + + public Task RunOnDispatcherThreadAsync(Action action, CancellationToken cancellationToken) + => Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.None, DispatcherScheduler); + + public Task RunOnDispatcherThreadAsync(Func action, CancellationToken cancellationToken) + => Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.None, DispatcherScheduler); + + public virtual void AssertDispatcherThread([CallerMemberName] string caller = null) + { + if (!IsDispatcherThread) + { + caller = caller is null ? "The method" : $"'{caller}'"; + throw new InvalidOperationException(caller + " must be called on the project snapshot manager's thread."); + } + } + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManager.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManager.cs index d2b3b2e959..9e89e04b7f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManager.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManager.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem public override event EventHandler Changed; private readonly ErrorReporter _errorReporter; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectSnapshotChangeTrigger[] _triggers; // Each entry holds a ProjectState and an optional ProjectSnapshot. ProjectSnapshots are @@ -33,32 +33,32 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private readonly Queue _notificationWork; public DefaultProjectSnapshotManager( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ErrorReporter errorReporter, IEnumerable triggers, Workspace workspace) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (errorReporter == null) + if (errorReporter is null) { throw new ArgumentNullException(nameof(errorReporter)); } - if (triggers == null) + if (triggers is null) { throw new ArgumentNullException(nameof(triggers)); } - if (workspace == null) + if (workspace is null) { throw new ArgumentNullException(nameof(workspace)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _errorReporter = errorReporter; _triggers = triggers.OrderByDescending(trigger => trigger.InitializePriority).ToArray(); Workspace = workspace; @@ -67,9 +67,28 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem _openDocuments = new HashSet(FilePathComparer.Instance); _notificationWork = new Queue(); - for (var i = 0; i < _triggers.Length; i++) + // All methods involving the project snapshot manager need to be run on the + // project snapshot manager's specialized thread. The LSP editor should already + // be on the specialized thread, however the old editor may be calling this + // constructor on the UI thread. + if (_projectSnapshotManagerDispatcher.IsDispatcherThread) { - _triggers[i].Initialize(this); + InitializeTriggers(this, _triggers); + } + else + { + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => InitializeTriggers(this, _triggers), CancellationToken.None); + } + + static void InitializeTriggers( + DefaultProjectSnapshotManager snapshotManager, + ProjectSnapshotChangeTrigger[] triggers) + { + for (var i = 0; i < triggers.Length; i++) + { + triggers[i].Initialize(snapshotManager); + } } } @@ -77,7 +96,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { get { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var i = 0; var projects = new ProjectSnapshot[_projects.Count]; @@ -94,7 +113,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { get { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); return _openDocuments; } @@ -109,7 +128,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(filePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projects.TryGetValue(filePath, out var entry)) { @@ -126,7 +145,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(filePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); return GetLoadedProject(filePath) ?? new EphemeralProjectSnapshot(Workspace.Services, filePath); } @@ -138,7 +157,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(documentFilePath)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); return _openDocuments.Contains(documentFilePath); } @@ -155,7 +174,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(document)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projects.TryGetValue(hostProject.FilePath, out var entry)) { @@ -187,7 +206,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(document)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); + if (_projects.TryGetValue(hostProject.FilePath, out var entry)) { var state = entry.State.WithRemovedHostDocument(document); @@ -220,7 +240,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(sourceText)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); + if (_projects.TryGetValue(projectFilePath, out var entry) && entry.State.Documents.TryGetValue(documentFilePath, out var older)) { @@ -275,7 +296,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(textLoader)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); + if (_projects.TryGetValue(projectFilePath, out var entry) && entry.State.Documents.TryGetValue(documentFilePath, out var older)) { @@ -313,7 +335,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(sourceText)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); + if (_projects.TryGetValue(projectFilePath, out var entry) && entry.State.Documents.TryGetValue(documentFilePath, out var older)) { @@ -366,7 +389,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(textLoader)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); + if (_projects.TryGetValue(projectFilePath, out var entry) && entry.State.Documents.TryGetValue(documentFilePath, out var older)) { @@ -392,7 +416,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(hostProject)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); // We don't expect to see a HostProject initialized multiple times for the same path. Just ignore it. if (_projects.ContainsKey(hostProject.FilePath)) @@ -415,7 +439,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(hostProject)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projects.TryGetValue(hostProject.FilePath, out var entry)) { @@ -444,7 +468,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(projectWorkspaceState)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projects.TryGetValue(projectFilePath, out var entry)) { @@ -468,7 +492,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(hostProject)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projects.TryGetValue(hostProject.FilePath, out var entry)) { @@ -513,7 +537,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem // virtual so it can be overridden in tests protected virtual void NotifyListeners(ProjectChangeEventArgs e) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _notificationWork.Enqueue(e); @@ -536,7 +560,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem } while (_notificationWork.Count > 0); } - } private class Entry diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManagerFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManagerFactory.cs index b092174aa6..312eaaf7f7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManagerFactory.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DefaultProjectSnapshotManagerFactory.cs @@ -14,16 +14,16 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem internal class DefaultProjectSnapshotManagerFactory : ILanguageServiceFactory { private readonly IEnumerable _triggers; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; [ImportingConstructor] public DefaultProjectSnapshotManagerFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, [ImportMany] IEnumerable triggers) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (triggers == null) @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem throw new ArgumentNullException(nameof(triggers)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _triggers = triggers; } @@ -43,7 +43,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem } return new DefaultProjectSnapshotManager( - _foregroundDispatcher, + _projectSnapshotManagerDispatcher, languageServices.WorkspaceServices.GetRequiredService(), _triggers, languageServices.WorkspaceServices.Workspace); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/WorkspaceProjectStateChangeDetector.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/WorkspaceProjectStateChangeDetector.cs index 728e9137e6..53acadaf56 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/WorkspaceProjectStateChangeDetector.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/WorkspaceProjectStateChangeDetector.cs @@ -18,6 +18,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem internal class WorkspaceProjectStateChangeDetector : ProjectSnapshotChangeTrigger { private readonly ProjectWorkspaceStateGenerator _workspaceStateGenerator; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private ProjectSnapshotManagerBase _projectManager; public int EnqueueDelay { get; set; } = 3 * 1000; @@ -29,19 +30,31 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem internal Dictionary _deferredUpdates; [ImportingConstructor] - public WorkspaceProjectStateChangeDetector(ProjectWorkspaceStateGenerator workspaceStateGenerator) + public WorkspaceProjectStateChangeDetector( + ProjectWorkspaceStateGenerator workspaceStateGenerator, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (workspaceStateGenerator == null) + if (workspaceStateGenerator is null) { throw new ArgumentNullException(nameof(workspaceStateGenerator)); } + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + _workspaceStateGenerator = workspaceStateGenerator; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } // Used in unit tests to ensure we can control when background work starts. public ManualResetEventSlim BlockDelayedUpdateWorkEnqueue { get; set; } + public ManualResetEventSlim BlockDelayedUpdateWorkAfterEnqueue { get; set; } + + public ManualResetEventSlim NotifyWorkspaceChangedEventComplete { get; set; } + private void OnStartingDelayedUpdate() { if (BlockDelayedUpdateWorkEnqueue != null) @@ -49,6 +62,11 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem BlockDelayedUpdateWorkEnqueue.Wait(); BlockDelayedUpdateWorkEnqueue.Reset(); } + + if (BlockDelayedUpdateWorkAfterEnqueue != null) + { + BlockDelayedUpdateWorkAfterEnqueue.Set(); + } } public override void Initialize(ProjectSnapshotManagerBase projectManager) @@ -64,107 +82,136 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem } // Internal for testing, virtual for temporary VSCode workaround - internal virtual void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + internal async virtual void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - Project project; - switch (e.Kind) + try { - case WorkspaceChangeKind.ProjectAdded: + // Method needs to be run on the project snapshot manager's specialized thread + // due to project snapshot manager access. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => + { + Project project; + switch (e.Kind) { - project = e.NewSolution.GetProject(e.ProjectId); - - Debug.Assert(project != null); - - if (TryGetProjectSnapshot(project.FilePath, out var projectSnapshot)) - { - _workspaceStateGenerator.Update(project, projectSnapshot, CancellationToken.None); - } - break; - } - - case WorkspaceChangeKind.ProjectChanged: - case WorkspaceChangeKind.ProjectReloaded: - { - project = e.NewSolution.GetProject(e.ProjectId); - - if (TryGetProjectSnapshot(project?.FilePath, out var _)) - { - EnqueueUpdate(e.ProjectId); - } - break; - } - - case WorkspaceChangeKind.ProjectRemoved: - { - project = e.OldSolution.GetProject(e.ProjectId); - Debug.Assert(project != null); - - if (TryGetProjectSnapshot(project?.FilePath, out var projectSnapshot)) - { - _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); - } - - break; - } - - case WorkspaceChangeKind.DocumentChanged: - case WorkspaceChangeKind.DocumentReloaded: - { - // This is the case when a component declaration file changes on disk. We have an MSBuild - // generator configured by the SDK that will poke these files on disk when a component - // is saved, or loses focus in the editor. - project = e.OldSolution.GetProject(e.ProjectId); - var document = project.GetDocument(e.DocumentId); - - if (document.FilePath == null) - { - return; - } - - // Using EndsWith because Path.GetExtension will ignore everything before .cs - // Using Ordinal because the SDK generates these filenames. - // Stll have .cshtml.g.cs and .razor.g.cs for Razor.VSCode scenarios. - if (document.FilePath.EndsWith(".cshtml.g.cs", StringComparison.Ordinal) || - document.FilePath.EndsWith(".razor.g.cs", StringComparison.Ordinal) || - document.FilePath.EndsWith(".razor", StringComparison.Ordinal) || - - // VSCode's background C# document - document.FilePath.EndsWith("__bg__virtual.cs", StringComparison.Ordinal)) - { - EnqueueUpdate(e.ProjectId); - return; - } - - // We now know we're not operating directly on a Razor file. However, it's possible the user is operating on a partial class that is associated with a Razor file. - - if (IsPartialComponentClass(document)) - { - EnqueueUpdate(e.ProjectId); - } - - break; - } - - case WorkspaceChangeKind.SolutionAdded: - case WorkspaceChangeKind.SolutionChanged: - case WorkspaceChangeKind.SolutionCleared: - case WorkspaceChangeKind.SolutionReloaded: - case WorkspaceChangeKind.SolutionRemoved: - - if (e.OldSolution != null) - { - foreach (var p in e.OldSolution.Projects) - { - - if (TryGetProjectSnapshot(p?.FilePath, out var projectSnapshot)) + case WorkspaceChangeKind.ProjectAdded: { - _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); + project = e.NewSolution.GetProject(e.ProjectId); + + Debug.Assert(project != null); + + if (TryGetProjectSnapshot(project.FilePath, out var projectSnapshot)) + { + _workspaceStateGenerator.Update(project, projectSnapshot, CancellationToken.None); + } + + break; } - } + + case WorkspaceChangeKind.ProjectChanged: + case WorkspaceChangeKind.ProjectReloaded: + { + project = e.NewSolution.GetProject(e.ProjectId); + + if (TryGetProjectSnapshot(project?.FilePath, out var _)) + { + EnqueueUpdate(e.ProjectId); + + var dependencyGraph = e.NewSolution.GetProjectDependencyGraph(); + var dependentProjectIds = dependencyGraph.GetProjectsThatTransitivelyDependOnThisProject(e.ProjectId); + foreach (var dependentProjectId in dependentProjectIds) + { + EnqueueUpdate(dependentProjectId); + } + } + break; + } + + case WorkspaceChangeKind.ProjectRemoved: + { + project = e.OldSolution.GetProject(e.ProjectId); + Debug.Assert(project != null); + + if (TryGetProjectSnapshot(project?.FilePath, out var projectSnapshot)) + { + _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); + } + + break; + } + + case WorkspaceChangeKind.DocumentChanged: + case WorkspaceChangeKind.DocumentReloaded: + { + // This is the case when a component declaration file changes on disk. We have an MSBuild + // generator configured by the SDK that will poke these files on disk when a component + // is saved, or loses focus in the editor. + project = e.OldSolution.GetProject(e.ProjectId); + var document = project.GetDocument(e.DocumentId); + + if (document.FilePath == null) + { + break; + } + + // Using EndsWith because Path.GetExtension will ignore everything before .cs + // Using Ordinal because the SDK generates these filenames. + // Stll have .cshtml.g.cs and .razor.g.cs for Razor.VSCode scenarios. + if (document.FilePath.EndsWith(".cshtml.g.cs", StringComparison.Ordinal) || + document.FilePath.EndsWith(".razor.g.cs", StringComparison.Ordinal) || + document.FilePath.EndsWith(".razor", StringComparison.Ordinal) || + + // VSCode's background C# document + document.FilePath.EndsWith("__bg__virtual.cs", StringComparison.Ordinal)) + { + EnqueueUpdate(e.ProjectId); + break; + } + + // We now know we're not operating directly on a Razor file. However, it's possible the user is operating on a partial class that is associated with a Razor file. + + if (IsPartialComponentClass(document)) + { + EnqueueUpdate(e.ProjectId); + } + + break; + } + + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionCleared: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.SolutionRemoved: + + if (e.OldSolution != null) + { + foreach (var p in e.OldSolution.Projects) + { + + if (TryGetProjectSnapshot(p?.FilePath, out var projectSnapshot)) + { + _workspaceStateGenerator.Update(workspaceProject: null, projectSnapshot, CancellationToken.None); + } + } + } + + InitializeSolution(e.NewSolution); + break; } - InitializeSolution(e.NewSolution); - break; + // Let tests know that this event has completed + if (NotifyWorkspaceChangedEventComplete != null) + { + NotifyWorkspaceChangedEventComplete.Set(); + } + }, CancellationToken.None); + } + catch (Exception ex) + { + Debug.Fail("WorkspaceProjectStateChangeDetector.Workspace_WorkspaceChanged threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentServiceProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentServiceProvider.cs index c1f0d58d8e..8cd3ad861a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentServiceProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentServiceProvider.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces private readonly object _lock; private IRazorSpanMappingService _spanMappingService; - private IRazorDocumentExcerptService _excerptService; + private IRazorDocumentExcerptService _documentExcerptService; private IRazorDocumentPropertiesService _documentPropertiesService; public RazorDocumentServiceProvider() @@ -37,7 +37,9 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces return this as TService; } - if (typeof(TService) == typeof(IRazorSpanMappingService)) + var serviceType = typeof(TService); + + if (serviceType == typeof(IRazorSpanMappingService)) { if (_spanMappingService == null) { @@ -53,23 +55,23 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces return (TService)_spanMappingService; } - if (typeof(TService) == typeof(IRazorDocumentExcerptService)) + if (serviceType == typeof(IRazorDocumentExcerptService)) { - if (_excerptService == null) + if (_documentExcerptService == null) { lock (_lock) { - if (_excerptService == null) + if (_documentExcerptService == null) { - _excerptService = _documentContainer.GetExcerptService(); + _documentExcerptService = _documentContainer.GetExcerptService(); } } } - return (TService)_excerptService; + return (TService)_documentExcerptService; } - if (typeof(TService) == typeof(IRazorDocumentPropertiesService)) + if (serviceType == typeof(IRazorDocumentPropertiesService)) { if (_documentPropertiesService == null) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSpanMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSpanMappingService.cs index f10122276a..c04a682ed1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSpanMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorSpanMappingService.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor { - internal class RazorSpanMappingService: IRazorSpanMappingService + internal class RazorSpanMappingService : IRazorSpanMappingService { private readonly DocumentSnapshot _document; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Resources.resx b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Resources.resx index fca5a30e15..55a253ebbe 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Resources.resx +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Resources.resx @@ -120,13 +120,4 @@ Value cannot be null or an empty string. - - {0} must be called on a background thread. - - - {0} must be called on the foreground thread. - - - The method - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.cs.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.cs.xlf index 95de4c5bf5..ab58c337c8 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.cs.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.cs.xlf @@ -7,21 +7,6 @@ Hodnota nesmí být null ani prázdný řetězec. - - {0} must be called on a background thread. - {0} musí být voláno ve vlákně na pozadí. - - - - {0} must be called on the foreground thread. - {0} musí být voláno ve vlákně na popředí. - - - - The method - Metoda - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.de.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.de.xlf index 6ea3276695..3a7a0ae4af 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.de.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.de.xlf @@ -7,21 +7,6 @@ Der Wert darf nicht NULL oder eine leere Zeichenfolge sein. - - {0} must be called on a background thread. - {0} muss für einen Hintergrundthread aufgerufen werden. - - - - {0} must be called on the foreground thread. - {0} muss im Vordergrundthread aufgerufen werden. - - - - The method - Die Methode - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.es.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.es.xlf index ed7b6de894..94946cbda3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.es.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.es.xlf @@ -7,21 +7,6 @@ El valor no puede ser nulo ni una cadena vacía. - - {0} must be called on a background thread. - {0} se debe llamar en un subproceso en segundo plano. - - - - {0} must be called on the foreground thread. - {0} se debe llamar en el subproceso principal. - - - - The method - El método - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.fr.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.fr.xlf index 57fee56bc5..cdc8e29c7f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.fr.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.fr.xlf @@ -7,21 +7,6 @@ La valeur ne peut pas être Null ni être une chaîne vide. - - {0} must be called on a background thread. - {0} doit être appelé sur un thread d’arrière-plan. - - - - {0} must be called on the foreground thread. - {0} doit être appelé sur le thread de premier plan. - - - - The method - La méthode - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.it.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.it.xlf index d63a8a1378..306f0c04a2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.it.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.it.xlf @@ -7,21 +7,6 @@ Il valore non può essere null o una stringa vuota. - - {0} must be called on a background thread. - {0} deve essere chiamato nel thread in background. - - - - {0} must be called on the foreground thread. - {0} deve essere chiamato nel thread in primo piano. - - - - The method - Il metodo - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ja.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ja.xlf index 077c897a18..fa172a25c7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ja.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ja.xlf @@ -7,21 +7,6 @@ 値を null または空の文字列にすることはできません。 - - {0} must be called on a background thread. - {0} をバックグラウンド スレッドで呼び出す必要があります。 - - - - {0} must be called on the foreground thread. - {0} をフォアグラウンド スレッドで呼び出す必要があります。 - - - - The method - メソッド - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ko.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ko.xlf index 4728203a19..ba55d9b4b9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ko.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ko.xlf @@ -7,21 +7,6 @@ 값은 null이거나 빈 문자열일 수 없습니다. - - {0} must be called on a background thread. - {0}(은)는 배경 스레드에서 호출되어야 합니다. - - - - {0} must be called on the foreground thread. - {0}(은)는 전경 스레드에서 호출되어야 합니다. - - - - The method - 메서드 이름 - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pl.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pl.xlf index 8827116b91..0e96041cf2 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pl.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pl.xlf @@ -7,21 +7,6 @@ Wartość nie może być wartością null ani pustym ciągiem. - - {0} must be called on a background thread. - Element {0}musi zostać wywołany w wątku w tle. - - - - {0} must be called on the foreground thread. - Element {0}musi zostać wywołany w wątku na pierwszym planie. - - - - The method - Metoda - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pt-BR.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pt-BR.xlf index 908a0a2ecb..45490e8754 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pt-BR.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.pt-BR.xlf @@ -7,21 +7,6 @@ O valor não pode ser nulo ou uma cadeia de caracteres vazia. - - {0} must be called on a background thread. - {0} deve ser chamado em uma thread em segundo plano. - - - - {0} must be called on the foreground thread. - {0} deve ser chamado na thread de primeiro plano. - - - - The method - O método - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ru.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ru.xlf index c0ddf2668b..f31e4fa6de 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ru.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.ru.xlf @@ -7,21 +7,6 @@ Значение не может быть NULL или пустой строкой. - - {0} must be called on a background thread. - {0} необходимо вызвать в фоновом потоке. - - - - {0} must be called on the foreground thread. - {0} необходимо вызвать в потоке переднего плана. - - - - The method - Метод - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.tr.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.tr.xlf index 459e01d7ea..368352d30f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.tr.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.tr.xlf @@ -7,21 +7,6 @@ Değer null veya boş bir dize olamaz. - - {0} must be called on a background thread. - {0} arka plan iş parçacığında çağrılmalıdır. - - - - {0} must be called on the foreground thread. - {0} ön plan iş parçacığında çağrılmalıdır. - - - - The method - Yöntem - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hans.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hans.xlf index fc47ee881b..597f355d58 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hans.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hans.xlf @@ -7,21 +7,6 @@ 值不能为 null 或空字符串。 - - {0} must be called on a background thread. - 必须在后台线程上调用 {0}。 - - - - {0} must be called on the foreground thread. - 必须在前台线程上调用 {0}。 - - - - The method - 方法 - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hant.xlf b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hant.xlf index 31cab319c6..1dbea8fba1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hant.xlf +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/xlf/Resources.zh-Hant.xlf @@ -7,21 +7,6 @@ 值不能為 Null 或空字串。 - - {0} must be called on a background thread. - {0} 必須在背景執行緒上呼叫。 - - - - {0} must be called on the foreground thread. - {0} 必須在前景執行緒上呼叫。 - - - - The method - 方法 - - \ No newline at end of file diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj new file mode 100644 index 0000000000..01d27be350 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.csproj @@ -0,0 +1,44 @@ + + + + Exe + netcoreapp3.1 + + + false + + + + + + + + + + + + + <_PublishedFiles Include="$(PublishDir)**\*.*" Exclude="$(PublishDir)**\Microsoft.CodeAnalysis.Remote.Razor.CoreComponents.*"/> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Extension)' == '.pdb'" /> + + + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'MessagePack.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'MessagePack.Annotations.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.AnalyzerUtilities.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.CSharp.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.CSharp.Features.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.CSharp.Workspaces.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.Features.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.Remote.Workspaces.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.Scripting.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.Workspaces.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.CodeAnalysis.ExternalAccess.Razor.dll'" /> + <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Filename)%(Extension)' == 'Microsoft.Win32.Registry.dll'" /> + + + <_PublishedFiles Update="@(_PublishedFiles)" TargetPath="%(RecursiveDir)%(Filename)%(Extension)" /> + + + + diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Program.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Program.cs new file mode 100644 index 0000000000..92f9a49e80 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor.CoreComponents/Program.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Remote.Razor.CoreComponents +{ + internal static class Program + { +#pragma warning disable IDE0060 // Remove unused parameter + public static void Main(string[] args) +#pragma warning restore IDE0060 // Remove unused parameter + { + } + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BackgroundDocumentGenerator.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BackgroundDocumentGenerator.cs index 1a9936120b..95bdf0f4f6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BackgroundDocumentGenerator.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BackgroundDocumentGenerator.cs @@ -21,26 +21,26 @@ namespace Microsoft.CodeAnalysis.Razor // Internal for testing internal readonly Dictionary Work; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly RazorDynamicFileInfoProvider _infoProvider; private readonly HashSet _suppressedDocuments; private ProjectSnapshotManagerBase _projectManager; private Timer _timer; [ImportingConstructor] - public BackgroundDocumentGenerator(ForegroundDispatcher foregroundDispatcher, RazorDynamicFileInfoProvider infoProvider) + public BackgroundDocumentGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RazorDynamicFileInfoProvider infoProvider) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (infoProvider == null) + if (infoProvider is null) { throw new ArgumentNullException(nameof(infoProvider)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _infoProvider = infoProvider; _suppressedDocuments = new HashSet(FilePathComparer.Instance); @@ -130,7 +130,7 @@ namespace Microsoft.CodeAnalysis.Razor public override void Initialize(ProjectSnapshotManagerBase projectManager) { - if (projectManager == null) + if (projectManager is null) { throw new ArgumentNullException(nameof(projectManager)); } @@ -148,17 +148,17 @@ namespace Microsoft.CodeAnalysis.Razor public void Enqueue(ProjectSnapshot project, DocumentSnapshot document) { - if (project == null) + if (project is null) { throw new ArgumentNullException(nameof(project)); } - if (document == null) + if (document is null) { throw new ArgumentNullException(nameof(document)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); lock (Work) { @@ -194,8 +194,6 @@ namespace Microsoft.CodeAnalysis.Razor { try { - _foregroundDispatcher.AssertBackgroundThread(); - // Timer is stopped. _timer.Change(Timeout.Infinite, Timeout.Infinite); @@ -252,12 +250,9 @@ namespace Microsoft.CodeAnalysis.Razor catch (Exception ex) { // This is something totally unexpected, let's just send it over to the workspace. - await Task.Factory.StartNew( - (p) => ((ProjectSnapshotManagerBase)p).ReportError(ex), - _projectManager, - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _projectManager.ReportError(ex), + CancellationToken.None).ConfigureAwait(false); } } @@ -265,12 +260,9 @@ namespace Microsoft.CodeAnalysis.Razor { OnErrorBeingReported(); - _ = Task.Factory.StartNew( - (p) => ((ProjectSnapshotManagerBase)p).ReportError(ex, project), - _projectManager, - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _projectManager.ReportError(ex, project), + CancellationToken.None); } private bool Suppressed(ProjectSnapshot project, DocumentSnapshot document) diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BraceSmartIndenter.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BraceSmartIndenter.cs index 1c04b06710..f8fc75568f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BraceSmartIndenter.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/BraceSmartIndenter.cs @@ -6,10 +6,11 @@ using System.Text; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Threading; using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer; namespace Microsoft.VisualStudio.Editor.Razor @@ -28,8 +29,8 @@ namespace Microsoft.VisualStudio.Editor.Razor /// internal class BraceSmartIndenter : IDisposable { - private readonly ForegroundDispatcher _dispatcher; private readonly ITextBuffer _textBuffer; + private readonly JoinableTaskContext _joinableTaskContext; private readonly VisualStudioDocumentTracker _documentTracker; private readonly TextBufferCodeDocumentProvider _codeDocumentProvider; private readonly IEditorOperationsFactoryService _editorOperationsFactory; @@ -42,32 +43,32 @@ namespace Microsoft.VisualStudio.Editor.Razor } public BraceSmartIndenter( - ForegroundDispatcher dispatcher, + JoinableTaskContext joinableTaskContext, VisualStudioDocumentTracker documentTracker, TextBufferCodeDocumentProvider codeDocumentProvider, IEditorOperationsFactoryService editorOperationsFactory) { - if (dispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (documentTracker == null) + if (documentTracker is null) { throw new ArgumentNullException(nameof(documentTracker)); } - if (codeDocumentProvider == null) + if (codeDocumentProvider is null) { throw new ArgumentNullException(nameof(codeDocumentProvider)); } - if (editorOperationsFactory == null) + if (editorOperationsFactory is null) { throw new ArgumentNullException(nameof(editorOperationsFactory)); } - _dispatcher = dispatcher; + _joinableTaskContext = joinableTaskContext; _documentTracker = documentTracker; _codeDocumentProvider = codeDocumentProvider; _editorOperationsFactory = editorOperationsFactory; @@ -78,7 +79,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public void Dispose() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); _textBuffer.Changed -= TextBuffer_OnChanged; _textBuffer.PostChanged -= TextBuffer_OnPostChanged; @@ -96,7 +97,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void TextBuffer_OnChanged(object sender, TextContentChangedEventArgs args) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (!args.TextChangeOccurred(out var changeInformation)) { @@ -119,7 +120,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private void TextBuffer_OnPostChanged(object sender, EventArgs e) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); var context = _context; _context = null; diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSource.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSource.cs index da9fef893c..1d5aeb83ff 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSource.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSource.cs @@ -39,36 +39,36 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion private readonly RazorCompletionFactsService _completionFactsService; private readonly ICompletionBroker _completionBroker; private readonly VisualStudioDescriptionFactory _descriptionFactory; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; public RazorDirectiveAttributeCompletionSource( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, VisualStudioRazorParser parser, RazorCompletionFactsService completionFactsService, ICompletionBroker completionBroker, VisualStudioDescriptionFactory descriptionFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (parser == null) + if (parser is null) { throw new ArgumentNullException(nameof(parser)); } - if (completionFactsService == null) + if (completionFactsService is null) { throw new ArgumentNullException(nameof(completionFactsService)); } - if (descriptionFactory == null) + if (descriptionFactory is null) { throw new ArgumentNullException(nameof(descriptionFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _parser = parser; _completionFactsService = completionFactsService; _completionBroker = completionBroker; @@ -77,8 +77,6 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion public async Task GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token) { - _foregroundDispatcher.AssertBackgroundThread(); - try { var codeDocument = await _parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token); @@ -110,11 +108,9 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion // Legacy completion is also active, we need to dismiss it. - _ = Task.Factory.StartNew( + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( () => activeSession.Dismiss(), - CancellationToken.None, - TaskCreationOptions.None, - _foregroundDispatcher.ForegroundScheduler); + CancellationToken.None); } var completionItems = new List(); diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSourceProvider.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSourceProvider.cs index ced3a8c21e..2dcadef856 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSourceProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveAttributeCompletionSourceProvider.cs @@ -21,22 +21,22 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion [ContentType(RazorConstants.LegacyCoreContentType)] internal class RazorDirectiveAttributeCompletionSourceProvider : IAsyncCompletionSourceProvider { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly RazorCompletionFactsService _completionFactsService; private readonly ICompletionBroker _completionBroker; private readonly VisualStudioDescriptionFactory _descriptionFactory; [ImportingConstructor] public RazorDirectiveAttributeCompletionSourceProvider( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, RazorCompletionFactsService completionFactsService, IAsyncCompletionBroker asyncCoompletionBroker, ICompletionBroker completionBroker, VisualStudioDescriptionFactory descriptionFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (completionFactsService == null) @@ -54,7 +54,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion throw new ArgumentNullException(nameof(descriptionFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _completionFactsService = completionFactsService; _completionBroker = completionBroker; _descriptionFactory = descriptionFactory; @@ -87,7 +87,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion return null; } - var completionSource = new RazorDirectiveAttributeCompletionSource(_foregroundDispatcher, parser, _completionFactsService, _completionBroker, _descriptionFactory); + var completionSource = new RazorDirectiveAttributeCompletionSource(_projectSnapshotManagerDispatcher, parser, _completionFactsService, _completionBroker, _descriptionFactory); return completionSource; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSource.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSource.cs index dd35c211e8..6d0ff1d5a0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSource.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSource.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.VisualStudio.Core.Imaging; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; @@ -34,29 +33,21 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion // Internal for testing internal readonly VisualStudioRazorParser Parser; private readonly RazorCompletionFactsService _completionFactsService; - private readonly ForegroundDispatcher _foregroundDispatcher; public RazorDirectiveCompletionSource( - ForegroundDispatcher foregroundDispatcher, VisualStudioRazorParser parser, RazorCompletionFactsService completionFactsService) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (parser == null) + if (parser is null) { throw new ArgumentNullException(nameof(parser)); } - if (completionFactsService == null) + if (completionFactsService is null) { throw new ArgumentNullException(nameof(completionFactsService)); } - _foregroundDispatcher = foregroundDispatcher; Parser = parser; _completionFactsService = completionFactsService; } @@ -68,8 +59,6 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion SnapshotSpan applicableSpan, CancellationToken token) { - _foregroundDispatcher.AssertBackgroundThread(); - try { var codeDocument = await Parser.GetLatestCodeDocumentAsync(triggerLocation.Snapshot, token); diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSourceProvider.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSourceProvider.cs index 0b79b65004..6fc38ecf12 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSourceProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Completion/RazorDirectiveCompletionSourceProvider.cs @@ -20,31 +20,22 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion [ContentType(RazorConstants.LegacyCoreContentType)] internal class RazorDirectiveCompletionSourceProvider : IAsyncCompletionSourceProvider { - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly RazorCompletionFactsService _completionFactsService; [ImportingConstructor] - public RazorDirectiveCompletionSourceProvider( - ForegroundDispatcher foregroundDispatcher, - RazorCompletionFactsService completionFactsService) + public RazorDirectiveCompletionSourceProvider(RazorCompletionFactsService completionFactsService) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (completionFactsService == null) + if (completionFactsService is null) { throw new ArgumentNullException(nameof(completionFactsService)); } - _foregroundDispatcher = foregroundDispatcher; _completionFactsService = completionFactsService; } public IAsyncCompletionSource GetOrCreate(ITextView textView) { - if (textView == null) + if (textView is null) { throw new ArgumentNullException(nameof(textView)); } @@ -69,7 +60,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion return null; } - var completionSource = new RazorDirectiveCompletionSource(_foregroundDispatcher, parser, _completionFactsService); + var completionSource = new RazorDirectiveCompletionSource(parser, _completionFactsService); return completionSource; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactory.cs index 0b89592c56..57eaaa5078 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactory.cs @@ -2,52 +2,53 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { internal class DefaultBraceSmartIndenterFactory : BraceSmartIndenterFactory { private readonly IEditorOperationsFactoryService _editorOperationsFactory; - private readonly ForegroundDispatcher _dispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly TextBufferCodeDocumentProvider _codeDocumentProvider; public DefaultBraceSmartIndenterFactory( - ForegroundDispatcher dispatcher, + JoinableTaskContext joinableTaskContext, TextBufferCodeDocumentProvider codeDocumentProvider, IEditorOperationsFactoryService editorOperationsFactory) { - if (dispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (codeDocumentProvider == null) + if (codeDocumentProvider is null) { throw new ArgumentNullException(nameof(codeDocumentProvider)); } - if (editorOperationsFactory == null) + if (editorOperationsFactory is null) { throw new ArgumentNullException(nameof(editorOperationsFactory)); } - _dispatcher = dispatcher; + _joinableTaskContext = joinableTaskContext; _codeDocumentProvider = codeDocumentProvider; _editorOperationsFactory = editorOperationsFactory; } public override BraceSmartIndenter Create(VisualStudioDocumentTracker documentTracker) { - if (documentTracker == null) + if (documentTracker is null) { throw new ArgumentNullException(nameof(documentTracker)); } - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); - var braceSmartIndenter = new BraceSmartIndenter(_dispatcher, documentTracker, _codeDocumentProvider, _editorOperationsFactory); + var braceSmartIndenter = new BraceSmartIndenter(_joinableTaskContext, documentTracker, _codeDocumentProvider, _editorOperationsFactory); return braceSmartIndenter; } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactoryFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactoryFactory.cs index 2ca82e3cb5..66c83befeb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactoryFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultBraceSmartIndenterFactoryFactory.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Razor; using Microsoft.VisualStudio.Text.Operations; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { @@ -14,44 +15,44 @@ namespace Microsoft.VisualStudio.Editor.Razor [ExportLanguageServiceFactory(typeof(BraceSmartIndenterFactory), RazorLanguage.Name, ServiceLayer.Default)] internal class DefaultBraceSmartIndenterFactoryFactory : ILanguageServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly TextBufferCodeDocumentProvider _codeDocumentProvider; private readonly IEditorOperationsFactoryService _editorOperationsFactory; [ImportingConstructor] public DefaultBraceSmartIndenterFactoryFactory( - ForegroundDispatcher foregroundDispatcher, + JoinableTaskContext joinableTaskContext, TextBufferCodeDocumentProvider codeDocumentProvider, IEditorOperationsFactoryService editorOperationsFactory) { - if (foregroundDispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (codeDocumentProvider == null) + if (codeDocumentProvider is null) { throw new ArgumentNullException(nameof(codeDocumentProvider)); } - if (editorOperationsFactory == null) + if (editorOperationsFactory is null) { throw new ArgumentNullException(nameof(editorOperationsFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _joinableTaskContext = joinableTaskContext; _codeDocumentProvider = codeDocumentProvider; _editorOperationsFactory = editorOperationsFactory; } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { - if (languageServices == null) + if (languageServices is null) { throw new ArgumentNullException(nameof(languageServices)); } - return new DefaultBraceSmartIndenterFactory(_foregroundDispatcher, _codeDocumentProvider, _editorOperationsFactory); + return new DefaultBraceSmartIndenterFactory(_joinableTaskContext, _codeDocumentProvider, _editorOperationsFactory); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultEditorSettingsManager.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultEditorSettingsManager.cs index 66d9f411dc..ffa57d935c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultEditorSettingsManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultEditorSettingsManager.cs @@ -14,14 +14,14 @@ namespace Microsoft.VisualStudio.Editor.Razor { public override event EventHandler Changed; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly object _settingsAccessorLock = new object(); - private readonly ForegroundDispatcher _foregroundDispatcher; private EditorSettings _settings; [ImportingConstructor] - public DefaultEditorSettingsManager(ForegroundDispatcher foregroundDispatcher) + public DefaultEditorSettingsManager(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _settings = EditorSettings.Default; } @@ -43,7 +43,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(updatedSettings)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); lock (_settingsAccessorLock) { @@ -57,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private void OnChanged() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var args = new EditorSettingsChangedEventArgs(Current); Changed?.Invoke(this, args); diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManager.cs index 3e4ff43714..1a2a54c8e9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManager.cs @@ -14,20 +14,20 @@ namespace Microsoft.VisualStudio.Editor.Razor internal class DefaultImportDocumentManager : ImportDocumentManager { private readonly FileChangeTrackerFactory _fileChangeTrackerFactory; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ErrorReporter _errorReporter; private readonly Dictionary _importTrackerCache; public override event EventHandler Changed; public DefaultImportDocumentManager( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ErrorReporter errorReporter, FileChangeTrackerFactory fileChangeTrackerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (errorReporter == null) @@ -40,7 +40,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(fileChangeTrackerFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _errorReporter = errorReporter; _fileChangeTrackerFactory = fileChangeTrackerFactory; _importTrackerCache = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -53,7 +53,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(tracker)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var imports = GetImportItems(tracker); foreach (var import in imports) @@ -83,7 +83,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(tracker)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var imports = GetImportItems(tracker); foreach (var import in imports) @@ -120,7 +120,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private void OnChanged(ImportTracker importTracker, FileChangeKind changeKind) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (Changed == null) { @@ -133,7 +133,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private void FileChangeTracker_Changed(object sender, FileChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_importTrackerCache.TryGetValue(args.FilePath, out var importTracker)) { diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManagerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManagerFactory.cs index 1a0596d25e..aafa1f0621 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManagerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultImportDocumentManagerFactory.cs @@ -14,17 +14,17 @@ namespace Microsoft.VisualStudio.Editor.Razor [ExportLanguageServiceFactory(typeof(ImportDocumentManager), RazorLanguage.Name, ServiceLayer.Default)] internal class DefaultImportDocumentManagerFactory : ILanguageServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; [ImportingConstructor] - public DefaultImportDocumentManagerFactory(ForegroundDispatcher foregroundDispatcher) + public DefaultImportDocumentManagerFactory(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) @@ -37,7 +37,7 @@ namespace Microsoft.VisualStudio.Editor.Razor var errorReporter = languageServices.WorkspaceServices.GetRequiredService(); var fileChangeTrackerFactory = languageServices.WorkspaceServices.GetRequiredService(); - return new DefaultImportDocumentManager(_foregroundDispatcher, errorReporter, fileChangeTrackerFactory); + return new DefaultImportDocumentManager(_projectSnapshotManagerDispatcher, errorReporter, fileChangeTrackerFactory); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorDocumentManager.cs index f2f040c116..599ec8b5bd 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorDocumentManager.cs @@ -5,9 +5,13 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { @@ -15,41 +19,49 @@ namespace Microsoft.VisualStudio.Editor.Razor [Export(typeof(RazorDocumentManager))] internal class DefaultRazorDocumentManager : RazorDocumentManager { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly RazorEditorFactoryService _editorFactoryService; [ImportingConstructor] public DefaultRazorDocumentManager( - ForegroundDispatcher dispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, RazorEditorFactoryService editorFactoryService) { - if (dispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (editorFactoryService == null) + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + + if (editorFactoryService is null) { throw new ArgumentNullException(nameof(editorFactoryService)); } - _foregroundDispatcher = dispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _editorFactoryService = editorFactoryService; } - public override void OnTextViewOpened(ITextView textView, IEnumerable subjectBuffers) + public async override Task OnTextViewOpenedAsync(ITextView textView, IEnumerable subjectBuffers) { - if (textView == null) + if (textView is null) { throw new ArgumentNullException(nameof(textView)); } - if (subjectBuffers == null) + if (subjectBuffers is null) { throw new ArgumentNullException(nameof(subjectBuffers)); } - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); foreach (var textBuffer in subjectBuffers) { @@ -69,24 +81,26 @@ namespace Microsoft.VisualStudio.Editor.Razor if (documentTracker.TextViews.Count == 1) { - tracker.Subscribe(); + // tracker.Subscribe() accesses the project snapshot manager, which needs to be run on the + // project snapshot manager's specialized thread. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => tracker.Subscribe(), CancellationToken.None); } } } - public override void OnTextViewClosed(ITextView textView, IEnumerable subjectBuffers) + public async override Task OnTextViewClosedAsync(ITextView textView, IEnumerable subjectBuffers) { - if (textView == null) + if (textView is null) { throw new ArgumentNullException(nameof(textView)); } - if (subjectBuffers == null) + if (subjectBuffers is null) { throw new ArgumentNullException(nameof(subjectBuffers)); } - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); // This means a Razor buffer has be detached from this ITextView or the ITextView is closing. Since we keep a // list of all of the open text views for each text buffer, we need to update the tracker. @@ -101,7 +115,9 @@ namespace Microsoft.VisualStudio.Editor.Razor if (documentTracker.TextViews.Count == 0) { - documentTracker.Unsubscribe(); + // tracker.Unsubscribe() should be in sync with tracker.Subscribe(). The latter of needs to be run + // on the project snapshot manager's specialized thread, so we run both on it. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => documentTracker.Unsubscribe(), CancellationToken.None); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorEditorFactoryService.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorEditorFactoryService.cs index 030bb955a9..ca941d0da3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorEditorFactoryService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultRazorEditorFactoryService.cs @@ -29,7 +29,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public override bool TryGetDocumentTracker(ITextBuffer textBuffer, out VisualStudioDocumentTracker documentTracker) { - if (textBuffer == null) + if (textBuffer is null) { throw new ArgumentNullException(nameof(textBuffer)); } @@ -58,7 +58,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public override bool TryGetParser(ITextBuffer textBuffer, out VisualStudioRazorParser parser) { - if (textBuffer == null) + if (textBuffer is null) { throw new ArgumentNullException(nameof(textBuffer)); } @@ -87,7 +87,7 @@ namespace Microsoft.VisualStudio.Editor.Razor internal override bool TryGetSmartIndenter(ITextBuffer textBuffer, out BraceSmartIndenter braceSmartIndenter) { - if (textBuffer == null) + if (textBuffer is null) { throw new ArgumentNullException(nameof(textBuffer)); } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTracker.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTracker.cs index e18a2bd933..1d5397d06e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTracker.cs @@ -9,14 +9,17 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Editor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly string _filePath; private readonly string _projectPath; private readonly ProjectSnapshotManager _projectManager; @@ -32,7 +35,8 @@ namespace Microsoft.VisualStudio.Editor.Razor public override event EventHandler ContextChanged; public DefaultVisualStudioDocumentTracker( - ForegroundDispatcher dispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, string filePath, string projectPath, ProjectSnapshotManager projectManager, @@ -41,9 +45,14 @@ namespace Microsoft.VisualStudio.Editor.Razor ITextBuffer textBuffer, ImportDocumentManager importDocumentManager) { - if (dispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); } if (string.IsNullOrEmpty(filePath)) @@ -51,37 +60,38 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath)); } - if (projectPath == null) + if (projectPath is null) { throw new ArgumentNullException(nameof(projectPath)); } - if (projectManager == null) + if (projectManager is null) { throw new ArgumentNullException(nameof(projectManager)); } - if (workspaceEditorSettings == null) + if (workspaceEditorSettings is null) { throw new ArgumentNullException(nameof(workspaceEditorSettings)); } - if (workspace == null) + if (workspace is null) { throw new ArgumentNullException(nameof(workspace)); } - if (textBuffer == null) + if (textBuffer is null) { throw new ArgumentNullException(nameof(textBuffer)); } - if (importDocumentManager == null) + if (importDocumentManager is null) { throw new ArgumentNullException(nameof(importDocumentManager)); } - _foregroundDispatcher = dispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _filePath = filePath; _projectPath = projectPath; _projectManager = projectManager; @@ -115,12 +125,12 @@ namespace Microsoft.VisualStudio.Editor.Razor internal void AddTextView(ITextView textView) { - if (textView == null) + if (textView is null) { throw new ArgumentNullException(nameof(textView)); } - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (!_textViews.Contains(textView)) { @@ -130,12 +140,12 @@ namespace Microsoft.VisualStudio.Editor.Razor internal void RemoveTextView(ITextView textView) { - if (textView == null) + if (textView is null) { throw new ArgumentNullException(nameof(textView)); } - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (_textViews.Contains(textView)) { @@ -145,7 +155,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public override ITextView GetFocusedTextView() { - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); for (var i = 0; i < TextViews.Count; i++) { @@ -160,7 +170,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public void Subscribe() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_subscribeCount++ > 0) { @@ -181,7 +191,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public void Unsubscribe() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_subscribeCount == 0 || _subscribeCount-- > 1) { @@ -197,20 +207,22 @@ namespace Microsoft.VisualStudio.Editor.Razor // Detached from project. _isSupportedProject = false; _projectSnapshot = null; + OnContextChanged(kind: ContextChangeKind.ProjectChanged); } - private void OnContextChanged(ContextChangeKind kind) +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void OnContextChanged(ContextChangeKind kind) +#pragma warning restore VSTHRD100 // Avoid async void methods { - _foregroundDispatcher.AssertForegroundThread(); - + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); ContextChanged?.Invoke(this, new ContextChangeEventArgs(kind)); } // Internal for testing internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projectPath != null && string.Equals(_projectPath, e.ProjectFilePath, StringComparison.OrdinalIgnoreCase)) @@ -233,7 +245,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Just an update OnContextChanged(ContextChangeKind.ProjectChanged); - if (e.Older == null || + if (e.Older is null || !Enumerable.SequenceEqual(e.Older.TagHelpers, e.Newer.TagHelpers)) { OnContextChanged(ContextChangeKind.TagHelpersChanged); @@ -255,16 +267,12 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void EditorSettingsManager_Changed(object sender, EditorSettingsChangedEventArgs args) - { - _foregroundDispatcher.AssertForegroundThread(); - - OnContextChanged(ContextChangeKind.EditorSettingsChanged); - } + => OnContextChanged(ContextChangeKind.EditorSettingsChanged); // Internal for testing internal void Import_Changed(object sender, ImportChangedEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); foreach (var path in args.AssociatedDocuments) { diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactory.cs index 5d04b9d479..956b535196 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactory.cs @@ -8,21 +8,24 @@ using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Editor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { internal class DefaultVisualStudioDocumentTrackerFactory : VisualStudioDocumentTrackerFactory { + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly ITextDocumentFactoryService _textDocumentFactory; private readonly ProjectPathProvider _projectPathProvider; private readonly Workspace _workspace; private readonly ImportDocumentManager _importDocumentManager; - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly ProjectSnapshotManager _projectManager; private readonly WorkspaceEditorSettings _workspaceEditorSettings; public DefaultVisualStudioDocumentTrackerFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, ProjectSnapshotManager projectManager, WorkspaceEditorSettings workspaceEditorSettings, ProjectPathProvider projectPathProvider, @@ -30,42 +33,43 @@ namespace Microsoft.VisualStudio.Editor.Razor ImportDocumentManager importDocumentManager, Workspace workspace) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (projectManager == null) + if (projectManager is null) { throw new ArgumentNullException(nameof(projectManager)); } - if (workspaceEditorSettings == null) + if (workspaceEditorSettings is null) { throw new ArgumentNullException(nameof(workspaceEditorSettings)); } - if (projectPathProvider == null) + if (projectPathProvider is null) { throw new ArgumentNullException(nameof(projectPathProvider)); } - if (textDocumentFactory == null) + if (textDocumentFactory is null) { throw new ArgumentNullException(nameof(textDocumentFactory)); } - if (importDocumentManager == null) + if (importDocumentManager is null) { throw new ArgumentNullException(nameof(importDocumentManager)); } - if (workspace == null) + if (workspace is null) { throw new ArgumentNullException(nameof(workspace)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _projectManager = projectManager; _workspaceEditorSettings = workspaceEditorSettings; _projectPathProvider = projectPathProvider; @@ -93,7 +97,8 @@ namespace Microsoft.VisualStudio.Editor.Razor } var filePath = textDocument.FilePath; - var tracker = new DefaultVisualStudioDocumentTracker(_foregroundDispatcher, filePath, projectPath, _projectManager, _workspaceEditorSettings, _workspace, textBuffer, _importDocumentManager); + var tracker = new DefaultVisualStudioDocumentTracker( + _projectSnapshotManagerDispatcher, _joinableTaskContext, filePath, projectPath, _projectManager, _workspaceEditorSettings, _workspace, textBuffer, _importDocumentManager); return tracker; } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactoryFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactoryFactory.cs index eed3ca436e..2f1491f1a0 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactoryFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioDocumentTrackerFactoryFactory.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Editor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { @@ -16,25 +17,33 @@ namespace Microsoft.VisualStudio.Editor.Razor [ExportLanguageServiceFactory(typeof(VisualStudioDocumentTrackerFactory), RazorLanguage.Name, ServiceLayer.Default)] internal class DefaultVisualStudioDocumentTrackerFactoryFactory : ILanguageServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly ITextDocumentFactoryService _textDocumentFactory; [ImportingConstructor] public DefaultVisualStudioDocumentTrackerFactoryFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, ITextDocumentFactoryService textDocumentFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (textDocumentFactory == null) + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + + if (textDocumentFactory is null) { throw new ArgumentNullException(nameof(textDocumentFactory)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _textDocumentFactory = textDocumentFactory; } @@ -52,7 +61,8 @@ namespace Microsoft.VisualStudio.Editor.Razor var projectPathProvider = languageServices.WorkspaceServices.GetRequiredService(); return new DefaultVisualStudioDocumentTrackerFactory( - _foregroundDispatcher, + _projectSnapshotManagerDispatcher, + _joinableTaskContext, projectManager, workspaceEditorSettings, projectPathProvider, diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs index f0f2fc3250..bce125f22d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs @@ -11,8 +11,10 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Editor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.Extensions.Internal; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using static Microsoft.VisualStudio.Editor.Razor.BackgroundParser; using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer; using Timer = System.Threading.Timer; @@ -34,10 +36,11 @@ namespace Microsoft.VisualStudio.Editor.Razor private readonly object _updateStateLock = new object(); private readonly VisualStudioCompletionBroker _completionBroker; private readonly VisualStudioDocumentTracker _documentTracker; - private readonly ForegroundDispatcher _dispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly ProjectSnapshotProjectEngineFactory _projectEngineFactory; private readonly ErrorReporter _errorReporter; private readonly List _codeDocumentRequests; + private readonly TaskScheduler _uiThreadScheduler; private RazorProjectEngine _projectEngine; private RazorCodeDocument _codeDocument; private ITextSnapshot _snapshot; @@ -51,38 +54,38 @@ namespace Microsoft.VisualStudio.Editor.Razor } public DefaultVisualStudioRazorParser( - ForegroundDispatcher dispatcher, + JoinableTaskContext joinableTaskContext, VisualStudioDocumentTracker documentTracker, ProjectSnapshotProjectEngineFactory projectEngineFactory, ErrorReporter errorReporter, VisualStudioCompletionBroker completionBroker) { - if (dispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (documentTracker == null) + if (documentTracker is null) { throw new ArgumentNullException(nameof(documentTracker)); } - if (projectEngineFactory == null) + if (projectEngineFactory is null) { throw new ArgumentNullException(nameof(projectEngineFactory)); } - if (errorReporter == null) + if (errorReporter is null) { throw new ArgumentNullException(nameof(errorReporter)); } - if (completionBroker == null) + if (completionBroker is null) { throw new ArgumentNullException(nameof(completionBroker)); } - _dispatcher = dispatcher; + _joinableTaskContext = joinableTaskContext; _projectEngineFactory = projectEngineFactory; _errorReporter = errorReporter; _completionBroker = completionBroker; @@ -90,6 +93,9 @@ namespace Microsoft.VisualStudio.Editor.Razor _codeDocumentRequests = new List(); _documentTracker.ContextChanged += DocumentTracker_ContextChanged; + + _joinableTaskContext.AssertUIThread(); + _uiThreadScheduler = TaskScheduler.FromCurrentSynchronizationContext(); } public override string FilePath => _documentTracker.FilePath; @@ -103,7 +109,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public override bool HasPendingChanges => _latestChangeReference != null; // Used in unit tests to ensure we can be notified when idle starts. - internal ManualResetEventSlim NotifyForegroundIdleStart { get; set; } + internal ManualResetEventSlim NotifyUIIdleStart { get; set; } // Used in unit tests to ensure we can block background idle work. internal ManualResetEventSlim BlockBackgroundIdleWork { get; set; } @@ -143,23 +149,33 @@ namespace Microsoft.VisualStudio.Editor.Razor } } + // WebTools depends on this method. Do not remove until old editor is phased out public override void QueueReparse() { // Can be called from any thread - if (_dispatcher.IsForegroundThread) + try { - ReparseOnForeground(null); + if (_joinableTaskContext.IsOnMainThread) + { + ReparseOnUIThread(); + } + else + { + _ = Task.Factory.StartNew( + () => ReparseOnUIThread(), CancellationToken.None, TaskCreationOptions.None, _uiThreadScheduler); + } } - else + catch (Exception ex) { - _ = Task.Factory.StartNew(ReparseOnForeground, null, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler); + Debug.Fail("DefaultVisualStudioRazorParser.QueueReparse threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } } public void Dispose() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); StopParser(); @@ -180,7 +196,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void DocumentTracker_ContextChanged(object sender, ContextChangeEventArgs args) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (!TryReinitializeParser()) { @@ -189,13 +205,13 @@ namespace Microsoft.VisualStudio.Editor.Razor // We have a new parser, force a reparse to generate new document information. Note that this // only blocks until the reparse change has been queued. - QueueReparse(); + ReparseOnUIThread(); } // Internal for testing internal bool TryReinitializeParser() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); StopParser(); @@ -214,7 +230,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void StartParser() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); // Make sure any tests use the real thing or a good mock. These tests can cause failures // that are hard to understand when this throws. @@ -242,7 +258,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void StopParser() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (_parser != null) { @@ -258,7 +274,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void StartIdleTimer() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); lock (_idleLock) { @@ -287,7 +303,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private void TextBuffer_OnChanged(object sender, TextContentChangedEventArgs args) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (args.Changes.Count > 0) { @@ -341,16 +357,16 @@ namespace Microsoft.VisualStudio.Editor.Razor } // Internal for testing - internal void OnIdle(object state) + internal void OnIdle() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (_disposed) { return; } - OnNotifyForegroundIdle(); + OnNotifyUIIdle(); foreach (var textView in _documentTracker.TextViews) { @@ -362,13 +378,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - QueueReparse(); + ReparseOnUIThread(); } // Internal for testing - internal void ReparseOnForeground(object state) + internal void ReparseOnUIThread() { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (_disposed) { @@ -381,17 +397,17 @@ namespace Microsoft.VisualStudio.Editor.Razor private void QueueChange(SourceChange change, ITextSnapshot snapshot) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); // _parser can be null if we're in the midst of rebuilding the internal parser (TagHelper refresh/solution teardown) _latestChangeReference = _parser?.QueueChange(change, snapshot); } - private void OnNotifyForegroundIdle() + private void OnNotifyUIIdle() { - if (NotifyForegroundIdleStart != null) + if (NotifyUIIdleStart != null) { - NotifyForegroundIdleStart.Set(); + NotifyUIIdleStart.Set(); } } @@ -407,37 +423,49 @@ namespace Microsoft.VisualStudio.Editor.Razor { try { - _dispatcher.AssertBackgroundThread(); - OnStartingBackgroundIdleWork(); - StopIdleTimer(); // We need to get back to the UI thread to properly check if a completion is active. - _ = Task.Factory.StartNew(OnIdle, null, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler); + _ = Task.Factory.StartNew(() => OnIdle_QueueOnUIThread(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } catch (Exception ex) { // This is something totally unexpected, let's just send it over to the workspace. - _ = Task.Factory.StartNew(() => _errorReporter.ReportError(ex), CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler); + _errorReporter.ReportError(ex); + } + + async Task OnIdle_QueueOnUIThread() + { + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); + OnIdle(); } } // Internal for testing - internal void OnResultsReady(object sender, BackgroundParserResultsReadyEventArgs args) +#pragma warning disable VSTHRD100 // Avoid async void methods + internal async void OnResultsReady(object sender, BackgroundParserResultsReadyEventArgs args) +#pragma warning restore VSTHRD100 // Avoid async void methods { - _dispatcher.AssertBackgroundThread(); + try + { + UpdateParserState(args.CodeDocument, args.ChangeReference.Snapshot); - UpdateParserState(args.CodeDocument, args.ChangeReference.Snapshot); - - // Jump back to UI thread to notify structure changes. - _ = Task.Factory.StartNew(OnDocumentStructureChanged, args, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler); + // Jump back to UI thread to notify structure changes. + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); + OnDocumentStructureChanged(args); + } + catch (Exception ex) + { + Debug.Fail("DefaultVisualStudioRazorParser.OnResultsReady threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); + } } // Internal for testing internal void OnDocumentStructureChanged(object state) { - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (_disposed) { @@ -458,7 +486,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // This can happen for a multitude of reasons, usually because of a user auto-completing // C# statements (causes multiple edits in quick succession). This ensures that our latest // parse corresponds to the current snapshot. - QueueReparse(); + ReparseOnUIThread(); return; } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactory.cs index 8807802090..758f90eaef 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactory.cs @@ -3,43 +3,45 @@ using System; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { internal class DefaultVisualStudioRazorParserFactory : VisualStudioRazorParserFactory { - private readonly ForegroundDispatcher _dispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly ProjectSnapshotProjectEngineFactory _projectEngineFactory; private readonly VisualStudioCompletionBroker _completionBroker; private readonly ErrorReporter _errorReporter; public DefaultVisualStudioRazorParserFactory( - ForegroundDispatcher dispatcher, + JoinableTaskContext joinableTaskContext, ErrorReporter errorReporter, VisualStudioCompletionBroker completionBroker, ProjectSnapshotProjectEngineFactory projectEngineFactory) { - if (dispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(dispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (errorReporter == null) + if (errorReporter is null) { throw new ArgumentNullException(nameof(errorReporter)); } - if (completionBroker == null) + if (completionBroker is null) { throw new ArgumentNullException(nameof(completionBroker)); } - if (projectEngineFactory == null) + if (projectEngineFactory is null) { throw new ArgumentNullException(nameof(projectEngineFactory)); } - _dispatcher = dispatcher; + _joinableTaskContext = joinableTaskContext; _errorReporter = errorReporter; _completionBroker = completionBroker; _projectEngineFactory = projectEngineFactory; @@ -52,10 +54,10 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(documentTracker)); } - _dispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); var parser = new DefaultVisualStudioRazorParser( - _dispatcher, + _joinableTaskContext, documentTracker, _projectEngineFactory, _errorReporter, @@ -63,4 +65,4 @@ namespace Microsoft.VisualStudio.Editor.Razor return parser; } } -} \ No newline at end of file +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactoryFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactoryFactory.cs index 4e0ff7406e..a6ff8823e1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactoryFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParserFactoryFactory.cs @@ -6,6 +6,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Razor; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor { @@ -13,17 +14,17 @@ namespace Microsoft.VisualStudio.Editor.Razor [ExportLanguageServiceFactory(typeof(VisualStudioRazorParserFactory), RazorLanguage.Name, ServiceLayer.Default)] internal class DefaultVisualStudioRazorParserFactoryFactory : ILanguageServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; [ImportingConstructor] - public DefaultVisualStudioRazorParserFactoryFactory(ForegroundDispatcher foregroundDispatcher) + public DefaultVisualStudioRazorParserFactoryFactory(JoinableTaskContext joinableTaskContext) { - if (foregroundDispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - _foregroundDispatcher = foregroundDispatcher; + _joinableTaskContext = joinableTaskContext; } public ILanguageService CreateLanguageService(HostLanguageServices languageServices) { @@ -38,10 +39,10 @@ namespace Microsoft.VisualStudio.Editor.Razor var projectEngineFactory = workspaceServices.GetRequiredService(); return new DefaultVisualStudioRazorParserFactory( - _foregroundDispatcher, + _joinableTaskContext, errorReporter, completionBroker, projectEngineFactory); } } -} \ No newline at end of file +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettings.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettings.cs index 1f30f1c8c5..a914a52e53 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettings.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettings.cs @@ -13,14 +13,14 @@ namespace Microsoft.VisualStudio.Editor.Razor private readonly EditorSettingsManager _editorSettingsManager; private readonly EventHandler _onChanged; private EventHandler _changed; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private int _listenerCount = 0; - public DefaultWorkspaceEditorSettings(ForegroundDispatcher foregroundDispatcher, EditorSettingsManager editorSettingsManager) + public DefaultWorkspaceEditorSettings(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, EditorSettingsManager editorSettingsManager) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (editorSettingsManager == null) @@ -28,7 +28,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(editorSettingsManager)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _editorSettingsManager = editorSettingsManager; _onChanged = OnChanged; } @@ -37,7 +37,7 @@ namespace Microsoft.VisualStudio.Editor.Razor { add { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _listenerCount++; _changed += value; @@ -52,7 +52,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } remove { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _listenerCount--; _changed -= value; @@ -83,7 +83,7 @@ namespace Microsoft.VisualStudio.Editor.Razor // Internal for testing internal void OnChanged(object sender, EditorSettingsChangedEventArgs e) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); Debug.Assert(_changed != null, nameof(OnChanged) + " should not be invoked when there are no listeners."); diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettingsFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettingsFactory.cs index 6bc448b43f..af113311ea 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettingsFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/DefaultWorkspaceEditorSettingsFactory.cs @@ -14,15 +14,15 @@ namespace Microsoft.VisualStudio.Editor.Razor [ExportLanguageServiceFactory(typeof(WorkspaceEditorSettings), RazorLanguage.Name)] internal class DefaultWorkspaceEditorSettingsFactory : ILanguageServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly EditorSettingsManager _editorSettingsManager; [ImportingConstructor] - public DefaultWorkspaceEditorSettingsFactory(ForegroundDispatcher foregroundDispatcher, EditorSettingsManager editorSettingsManager) + public DefaultWorkspaceEditorSettingsFactory(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, EditorSettingsManager editorSettingsManager) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (editorSettingsManager == null) @@ -30,7 +30,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(editorSettingsManager)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _editorSettingsManager = editorSettingsManager; } @@ -41,7 +41,7 @@ namespace Microsoft.VisualStudio.Editor.Razor throw new ArgumentNullException(nameof(languageServices)); } - return new DefaultWorkspaceEditorSettings(_foregroundDispatcher, _editorSettingsManager); + return new DefaultWorkspaceEditorSettings(_projectSnapshotManagerDispatcher, _editorSettingsManager); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocument.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocument.cs index d31e8d0085..0fe22349b6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocument.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocument.cs @@ -2,9 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor.Documents { @@ -13,6 +17,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents internal sealed class EditorDocument : IDisposable { private readonly EditorDocumentManager _documentManager; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly FileChangeTracker _fileTracker; private readonly SnapshotChangeTracker _snapshotTracker; private readonly EventHandler _changedOnDisk; @@ -24,6 +30,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public EditorDocument( EditorDocumentManager documentManager, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, string projectFilePath, string documentFilePath, TextLoader textLoader, @@ -34,32 +42,44 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents EventHandler opened, EventHandler closed) { - if (documentManager == null) + if (documentManager is null) { throw new ArgumentNullException(nameof(documentManager)); } - if (projectFilePath == null) + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + + if (projectFilePath is null) { throw new ArgumentNullException(nameof(projectFilePath)); } - if (documentFilePath == null) + if (documentFilePath is null) { throw new ArgumentNullException(nameof(documentFilePath)); } - if (textLoader == null) + if (textLoader is null) { throw new ArgumentNullException(nameof(textLoader)); } - if (fileTracker == null) + if (fileTracker is null) { throw new ArgumentNullException(nameof(fileTracker)); } _documentManager = documentManager; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; ProjectFilePath = projectFilePath; DocumentFilePath = documentFilePath; TextLoader = textLoader; @@ -75,7 +95,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents // Only one of these should be active at a time. if (textBuffer == null) { - _fileTracker.StartListening(); + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _fileTracker.StartListening(), CancellationToken.None); } else { @@ -106,7 +127,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents throw new ArgumentNullException(nameof(textBuffer)); } - _fileTracker.StopListening(); + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _fileTracker.StopListening(), CancellationToken.None); _snapshotTracker.StartTracking(textBuffer); EditorTextBuffer = textBuffer; @@ -125,8 +147,9 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents EditorTextContainer.TextChanged -= TextContainer_Changed; EditorTextContainer = null; EditorTextBuffer = null; - - _fileTracker.StartListening(); + + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _fileTracker.StartListening(), CancellationToken.None); } private void ChangeTracker_Changed(object sender, FileChangeEventArgs e) @@ -144,10 +167,14 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void Dispose() { + _joinableTaskContext.AssertUIThread(); + if (!_disposed) { _fileTracker.Changed -= ChangeTracker_Changed; - _fileTracker.StopListening(); + + _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => _fileTracker.StopListening(), CancellationToken.None); if (EditorTextBuffer != null) { diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerBase.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerBase.cs index 1fe2a783fd..7c3b20e32f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerBase.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerBase.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor.Documents { @@ -17,31 +19,42 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private readonly FileChangeTrackerFactory _fileChangeTrackerFactory; private readonly Dictionary _documents; private readonly Dictionary> _documentsByFilePath; + protected readonly object Lock; public EditorDocumentManagerBase( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, FileChangeTrackerFactory fileChangeTrackerFactory) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (fileChangeTrackerFactory == null) + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + + if (fileChangeTrackerFactory is null) { throw new ArgumentNullException(nameof(fileChangeTrackerFactory)); } - ForegroundDispatcher = foregroundDispatcher; + ProjectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + JoinableTaskContext = joinableTaskContext; _fileChangeTrackerFactory = fileChangeTrackerFactory; _documents = new Dictionary(); _documentsByFilePath = new Dictionary>(FilePathComparer.Instance); + Lock = new object(); } - protected ForegroundDispatcher ForegroundDispatcher { get; } + protected ProjectSnapshotManagerDispatcher ProjectSnapshotManagerDispatcher { get; } + + protected JoinableTaskContext JoinableTaskContext { get; } protected abstract ITextBuffer GetTextBufferForOpenDocument(string filePath); @@ -51,7 +64,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public sealed override bool TryGetDocument(DocumentKey key, out EditorDocument document) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -61,7 +74,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public sealed override bool TryGetMatchingDocuments(string filePath, out EditorDocument[] documents) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -88,13 +101,11 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents EventHandler opened, EventHandler closed) { - ForegroundDispatcher.AssertForegroundThread(); - - EditorDocument document; + JoinableTaskContext.AssertUIThread(); lock (Lock) { - if (TryGetDocument(key, out document)) + if (TryGetDocument(key, out var document)) { return document; } @@ -103,6 +114,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents var textBuffer = GetTextBufferForOpenDocument(key.DocumentFilePath); document = new EditorDocument( this, + ProjectSnapshotManagerDispatcher, + JoinableTaskContext, key.ProjectFilePath, key.DocumentFilePath, new FileTextLoader(key.DocumentFilePath, defaultEncoding: null), @@ -147,7 +160,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents throw new ArgumentNullException(nameof(textBuffer)); } - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -171,7 +184,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents throw new ArgumentNullException(nameof(filePath)); } - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -195,24 +208,27 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents throw new ArgumentNullException(nameof(document)); } - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); - var key = new DocumentKey(document.ProjectFilePath, document.DocumentFilePath); - if (_documentsByFilePath.TryGetValue(document.DocumentFilePath, out var documents)) + lock (Lock) { - documents.Remove(key); - - if (documents.Count == 0) + var key = new DocumentKey(document.ProjectFilePath, document.DocumentFilePath); + if (_documentsByFilePath.TryGetValue(document.DocumentFilePath, out var documents)) { - _documentsByFilePath.Remove(document.DocumentFilePath); + documents.Remove(key); + + if (documents.Count == 0) + { + _documentsByFilePath.Remove(document.DocumentFilePath); + } } - } - _documents.Remove(key); + _documents.Remove(key); - if (document.IsOpenInEditor) - { - OnDocumentClosed(document); + if (document.IsOpenInEditor) + { + OnDocumentClosed(document); + } } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerListener.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerListener.cs index bddb3da02a..a7defcde29 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerListener.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/Documents/EditorDocumentManagerListener.cs @@ -3,8 +3,11 @@ using System; using System.Composition; +using System.Diagnostics; +using System.Threading; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor.Documents { @@ -15,6 +18,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents [Export(typeof(ProjectSnapshotChangeTrigger))] internal class EditorDocumentManagerListener : ProjectSnapshotChangeTrigger { + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly EventHandler _onChangedOnDisk; private readonly EventHandler _onChangedInEditor; private readonly EventHandler _onOpened; @@ -24,8 +29,20 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private ProjectSnapshotManagerBase _projectManager; [ImportingConstructor] - public EditorDocumentManagerListener() + public EditorDocumentManagerListener(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext) { + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _onChangedOnDisk = Document_ChangedOnDisk; _onChangedInEditor = Document_ChangedInEditor; _onOpened = Document_Opened; @@ -33,8 +50,17 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents } // For testing purposes only. - internal EditorDocumentManagerListener(EditorDocumentManager documentManager, EventHandler onChangedOnDisk, EventHandler onChangedInEditor, EventHandler onOpened, EventHandler onClosed) + internal EditorDocumentManagerListener( + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, + EditorDocumentManager documentManager, + EventHandler onChangedOnDisk, + EventHandler onChangedInEditor, + EventHandler onOpened, + EventHandler onClosed) { + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; _documentManager = documentManager; _onChangedOnDisk = onChangedOnDisk; _onChangedInEditor = onChangedInEditor; @@ -61,56 +87,142 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents } // Internal for testing. - internal void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + internal async void ProjectManager_Changed(object sender, ProjectChangeEventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - switch (e.Kind) + try { - case ProjectChangeKind.DocumentAdded: - { - var key = new DocumentKey(e.ProjectFilePath, e.DocumentFilePath); - var document = _documentManager.GetOrCreateDocument(key, _onChangedOnDisk, _onChangedInEditor, _onOpened, _onClosed); - if (document.IsOpenInEditor) + switch (e.Kind) + { + case ProjectChangeKind.DocumentAdded: { - _onOpened(document, EventArgs.Empty); + var key = new DocumentKey(e.ProjectFilePath, e.DocumentFilePath); + + // GetOrCreateDocument needs to be run on the UI thread + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); + + var document = _documentManager.GetOrCreateDocument( + key, _onChangedOnDisk, _onChangedInEditor, _onOpened, _onClosed); + if (document.IsOpenInEditor) + { + _onOpened(document, EventArgs.Empty); + } + + break; } - break; - } - - case ProjectChangeKind.DocumentRemoved: - { - // This class 'owns' the document entry so it's safe for us to dispose it. - if (_documentManager.TryGetDocument(new DocumentKey(e.ProjectFilePath, e.DocumentFilePath), out var document)) + case ProjectChangeKind.DocumentRemoved: { - document.Dispose(); + // TryGetDocument and Dispose need to be run on the UI thread + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); + + var documentFound = _documentManager.TryGetDocument( + new DocumentKey(e.ProjectFilePath, e.DocumentFilePath), out var document); + + // This class 'owns' the document entry so it's safe for us to dispose it. + if (documentFound) + { + document.Dispose(); + } + + break; } - break; - } + } + } + catch (Exception ex) + { + Debug.Fail("EditorDocumentManagerListener.ProjectManager_Changed threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } } - private void Document_ChangedOnDisk(object sender, EventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void Document_ChangedOnDisk(object sender, EventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - var document = (EditorDocument)sender; - _projectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader); + try + { + // This event is called by the EditorDocumentManager, which runs on the UI thread. + // However, due to accessing the project snapshot manager, we need to switch to + // running on the project snapshot manager's specialized thread. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => + { + var document = (EditorDocument)sender; + _projectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader); + }, CancellationToken.None); + } + catch (Exception ex) + { + Debug.Fail("EditorDocumentManagerListener.Document_ChangedOnDisk threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); + } } - private void Document_ChangedInEditor(object sender, EventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void Document_ChangedInEditor(object sender, EventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - var document = (EditorDocument)sender; - _projectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.EditorTextContainer.CurrentText); + try + { + // This event is called by the EditorDocumentManager, which runs on the UI thread. + // However, due to accessing the project snapshot manager, we need to switch to + // running on the project snapshot manager's specialized thread. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => + { + var document = (EditorDocument)sender; + _projectManager.DocumentChanged(document.ProjectFilePath, document.DocumentFilePath, document.EditorTextContainer.CurrentText); + }, CancellationToken.None); + } + catch (Exception ex) + { + Debug.Fail("EditorDocumentManagerListener.Document_ChangedInEditor threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); + } } - private void Document_Opened(object sender, EventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void Document_Opened(object sender, EventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - var document = (EditorDocument)sender; - _projectManager.DocumentOpened(document.ProjectFilePath, document.DocumentFilePath, document.EditorTextContainer.CurrentText); + try + { + // This event is called by the EditorDocumentManager, which runs on the UI thread. + // However, due to accessing the project snapshot manager, we need to switch to + // running on the project snapshot manager's specialized thread. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => + { + var document = (EditorDocument)sender; + _projectManager.DocumentOpened(document.ProjectFilePath, document.DocumentFilePath, document.EditorTextContainer.CurrentText); + }, CancellationToken.None); + } + catch (Exception ex) + { + Debug.Fail("EditorDocumentManagerListener.Document_Opened threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); + } } - private void Document_Closed(object sender, EventArgs e) +#pragma warning disable VSTHRD100 // Avoid async void methods + private async void Document_Closed(object sender, EventArgs e) +#pragma warning restore VSTHRD100 // Avoid async void methods { - var document = (EditorDocument)sender; - _projectManager.DocumentClosed(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader); + try + { + // This event is called by the EditorDocumentManager, which runs on the UI thread. + // However, due to accessing the project snapshot manager, we need to switch to + // running on the project snapshot manager's specialized thread. + await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => + { + var document = (EditorDocument)sender; + _projectManager.DocumentClosed(document.ProjectFilePath, document.DocumentFilePath, document.TextLoader); + }, CancellationToken.None); + } + catch (Exception ex) + { + Debug.Fail("EditorDocumentManagerListener.Document_Closed threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); + } } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorDocumentManager.cs index 2f4dd3c577..ad30e0ec3c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorDocumentManager.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -10,8 +11,8 @@ namespace Microsoft.VisualStudio.Editor.Razor { internal abstract class RazorDocumentManager : ILanguageService { - public abstract void OnTextViewOpened(ITextView textView, IEnumerable subjectBuffers); + public abstract Task OnTextViewOpenedAsync(ITextView textView, IEnumerable subjectBuffers); - public abstract void OnTextViewClosed(ITextView textView, IEnumerable subjectBuffers); + public abstract Task OnTextViewClosedAsync(ITextView textView, IEnumerable subjectBuffers); } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorTextViewConnectionListener.cs b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorTextViewConnectionListener.cs index 2e614a5a70..ddf2817b12 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorTextViewConnectionListener.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Editor.Razor/RazorTextViewConnectionListener.cs @@ -4,9 +4,12 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using System.Diagnostics; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.Editor.Razor @@ -17,58 +20,76 @@ namespace Microsoft.VisualStudio.Editor.Razor [Export(typeof(ITextViewConnectionListener))] internal class RazorTextViewConnectionListener : ITextViewConnectionListener { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; private readonly RazorDocumentManager _documentManager; [ImportingConstructor] - public RazorTextViewConnectionListener(ForegroundDispatcher foregroundDispatcher, RazorDocumentManager documentManager) + public RazorTextViewConnectionListener(JoinableTaskContext joinableTaskContext, RazorDocumentManager documentManager) { - if (foregroundDispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } - if (documentManager == null) + if (documentManager is null) { throw new ArgumentNullException(nameof(documentManager)); } - _foregroundDispatcher = foregroundDispatcher; + _joinableTaskContext = joinableTaskContext; _documentManager = documentManager; } - public void SubjectBuffersConnected(ITextView textView, ConnectionReason reason, IReadOnlyCollection subjectBuffers) +#pragma warning disable VSTHRD100 // Avoid async void methods + public async void SubjectBuffersConnected(ITextView textView, ConnectionReason reason, IReadOnlyCollection subjectBuffers) +#pragma warning restore VSTHRD100 // Avoid async void methods { - if (textView == null) + try { - throw new ArgumentException(nameof(textView)); - } + if (textView is null) + { + throw new ArgumentException(nameof(textView)); + } - if (subjectBuffers == null) + if (subjectBuffers is null) + { + throw new ArgumentNullException(nameof(subjectBuffers)); + } + + _joinableTaskContext.AssertUIThread(); + await _documentManager.OnTextViewOpenedAsync(textView, subjectBuffers); + } + catch (Exception ex) { - throw new ArgumentNullException(nameof(subjectBuffers)); + Debug.Fail("RazorTextViewConnectionListener.SubjectBuffersConnected threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } - - _foregroundDispatcher.AssertForegroundThread(); - - _documentManager.OnTextViewOpened(textView, subjectBuffers); } - public void SubjectBuffersDisconnected(ITextView textView, ConnectionReason reason, IReadOnlyCollection subjectBuffers) +#pragma warning disable VSTHRD100 // Avoid async void methods + public async void SubjectBuffersDisconnected(ITextView textView, ConnectionReason reason, IReadOnlyCollection subjectBuffers) +#pragma warning restore VSTHRD100 // Avoid async void methods { - if (textView == null) + try { - throw new ArgumentException(nameof(textView)); - } + if (textView is null) + { + throw new ArgumentException(nameof(textView)); + } - if (subjectBuffers == null) + if (subjectBuffers is null) + { + throw new ArgumentNullException(nameof(subjectBuffers)); + } + + _joinableTaskContext.AssertUIThread(); + await _documentManager.OnTextViewClosedAsync(textView, subjectBuffers); + } + catch (Exception ex) { - throw new ArgumentNullException(nameof(subjectBuffers)); + Debug.Fail("RazorTextViewConnectionListener.SubjectBuffersDisconnected threw exception:" + + Environment.NewLine + ex.Message + Environment.NewLine + "Stack trace:" + Environment.NewLine + ex.StackTrace); } - - _foregroundDispatcher.AssertForegroundThread(); - - _documentManager.OnTextViewClosed(textView, subjectBuffers); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultFallbackCapabilitiesFilterResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultFallbackCapabilitiesFilterResolver.cs index 650108752f..2f40c09bc1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultFallbackCapabilitiesFilterResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultFallbackCapabilitiesFilterResolver.cs @@ -58,22 +58,24 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage case Methods.TextDocumentDocumentHighlightName: return CheckHighlightCapabilities; case "textDocument/semanticTokens": - case "textDocument/semanticTokens/edits": + case Methods.TextDocumentSemanticTokensFullName: + case Methods.TextDocumentSemanticTokensFullDeltaName: + case Methods.TextDocumentSemanticTokensRangeName: return CheckSemanticTokensCapabilities; + case Methods.TextDocumentLinkedEditingRangeName: + return CheckLinkedEditingRangeCapabilities; + case Methods.CodeActionResolveName: + return CheckCodeActionResolveCapabilities; // VS LSP Expansion capabilities - case MSLSPMethods.DocumentReferencesName: - return CheckMSReferencesCapabilities; - case MSLSPMethods.ProjectContextsName: + case VSMethods.GetProjectContextsName: return CheckProjectContextsCapabilities; - case MSLSPMethods.TextDocumentCodeActionResolveName: - return CheckCodeActionResolveCapabilities; - case MSLSPMethods.OnAutoInsertName: + case VSInternalMethods.DocumentReferencesName: + return CheckMSReferencesCapabilities; + case VSInternalMethods.OnAutoInsertName: return CheckOnAutoInsertCapabilities; - case MSLSPMethods.OnTypeRenameName: - return CheckOnTypeRenameCapabilities; - case MSLSPMethods.DocumentPullDiagnosticName: - case MSLSPMethods.WorkspacePullDiagnosticName: + case VSInternalMethods.DocumentPullDiagnosticName: + case VSInternalMethods.WorkspacePullDiagnosticName: return CheckPullDiagnosticCapabilities; default: @@ -85,9 +87,7 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage { var serverCapabilities = token.ToObject(); - return serverCapabilities?.SemanticTokensOptions?.DocumentProvider?.Match( - boolValue => boolValue, - options => options != null) ?? false; + return serverCapabilities?.SemanticTokensOptions != null; } private static bool CheckImplementationCapabilities(JToken token) @@ -240,42 +240,48 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage private static bool CheckMSReferencesCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); return serverCapabilities?.MSReferencesProvider == true; } private static bool CheckProjectContextsCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); return serverCapabilities?.ProjectContextProvider == true; } private static bool CheckCodeActionResolveCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); - return serverCapabilities?.CodeActionsResolveProvider == true; + var resolvesCodeActions = serverCapabilities?.CodeActionProvider?.Match( + boolValue => false, + options => options.ResolveProvider) ?? false; + + return resolvesCodeActions; } private static bool CheckOnAutoInsertCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); return serverCapabilities?.OnAutoInsertProvider != null; } - private static bool CheckOnTypeRenameCapabilities(JToken token) + private static bool CheckLinkedEditingRangeCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); - return serverCapabilities?.OnTypeRenameProvider != null; + return serverCapabilities?.LinkedEditingRangeProvider?.Match( + boolValue => boolValue, + options => options != null) ?? false; } private static bool CheckPullDiagnosticCapabilities(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); return serverCapabilities?.SupportsDiagnosticRequests == true; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultLSPRequestInvoker.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultLSPRequestInvoker.cs index 8551077993..1f703e46d3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultLSPRequestInvoker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServer.ContainedLanguage/DefaultLSPRequestInvoker.cs @@ -42,7 +42,7 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage // We need these converters so we don't lose information as part of the deserialization. _serializer = new JsonSerializer(); - _serializer.AddVSExtensionConverters(); + _serializer.AddVSInternalExtensionConverters(); } public override Task>> ReinvokeRequestOnMultipleServersAsync(string method, string contentType, TIn parameters, CancellationToken cancellationToken) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultLSPEditorFeatureDetector.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultLSPEditorFeatureDetector.cs index ef35cf2088..8aed0956dd 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultLSPEditorFeatureDetector.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultLSPEditorFeatureDetector.cs @@ -16,7 +16,6 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor internal class DefaultLSPEditorFeatureDetector : LSPEditorFeatureDetector { private const string DotNetCoreCSharpCapability = "CSharp&CPS"; - private const string UseLegacyASPNETCoreEditorSettingTemp = "TextEditor.HTMLX.Specific.UseLegacyASPNETCoreRazorEditor"; private const string UseLegacyASPNETCoreEditorSetting = "TextEditor.HTML.Specific.UseLegacyASPNETCoreRazorEditor"; private static readonly Guid s_liveShareHostUIContextGuid = Guid.Parse("62de1aa5-70b0-4934-9324-680896466fe1"); @@ -49,12 +48,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor Assumes.Present(settingsManager); var useLegacyEditor = settingsManager.GetValueOrDefault(UseLegacyASPNETCoreEditorSetting); - - // WebTools is in the process of renaming HTMLX -> HTML and this Temp setting represents the HTMLX variant of the setting. - // Once they've committed the fix we'll need to "do the right thing" for the point-in-time where things vary. - var useLegacyEditorTemp = settingsManager.GetValueOrDefault(UseLegacyASPNETCoreEditorSettingTemp); - var shouldUseLegacyEditor = useLegacyEditor || useLegacyEditorTemp; - return shouldUseLegacyEditor; + return useLegacyEditor; }); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultRazorLanguageServerCustomMessageTarget.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultRazorLanguageServerCustomMessageTarget.cs index face9e420d..810c8d9458 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultRazorLanguageServerCustomMessageTarget.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/DefaultRazorLanguageServerCustomMessageTarget.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic.Models; using Microsoft.CodeAnalysis.ExternalAccess.Razor; @@ -233,7 +232,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor return response; } - public override async Task ProvideCodeActionsAsync(CodeActionParams codeActionParams, CancellationToken cancellationToken) + public override async Task ProvideCodeActionsAsync(CodeActionParams codeActionParams, CancellationToken cancellationToken) { if (codeActionParams is null) { @@ -252,7 +251,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor codeActionParams.TextDocument.Uri = csharpDoc.Uri; - var results = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( + var results = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( Methods.TextDocumentCodeActionName, LanguageServerKind.CSharp.ToContentType(), SupportsCSharpCodeActions, @@ -262,15 +261,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor return results.SelectMany(l => l.Result).ToArray(); } - public override async Task ResolveCodeActionsAsync(VSCodeAction codeAction, CancellationToken cancellationToken) + public override async Task ResolveCodeActionsAsync(VSInternalCodeAction codeAction, CancellationToken cancellationToken) { if (codeAction is null) { throw new ArgumentNullException(nameof(codeAction)); } - var results = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( - MSLSPMethods.TextDocumentCodeActionResolveName, + var results = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( + Methods.CodeActionResolveName, LanguageServerKind.CSharp.ToContentType(), SupportsCSharpCodeActions, codeAction, @@ -313,7 +312,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor PartialResultToken = semanticTokensParams.PartialResultToken, }; var csharpResults = await _requestInvoker.ReinvokeRequestOnServerAsync( - LanguageServerConstants.LegacyRazorSemanticTokensEndpoint, + Methods.TextDocumentSemanticTokensFullName, RazorLSPConstants.RazorCSharpLanguageServerName, newParams, cancellationToken).ConfigureAwait(false); @@ -347,7 +346,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor return new ProvideSemanticTokensEditsResponse(tokens: null, edits: null, resultId: null, csharpDoc.HostDocumentSyncVersion); } - var newParams = new SemanticTokensEditsParams + var newParams = new SemanticTokensDeltaParams { TextDocument = new TextDocumentIdentifier { @@ -356,8 +355,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor PreviousResultId = semanticTokensEditsParams.PreviousResultId, }; - var csharpResponse = await _requestInvoker.ReinvokeRequestOnServerAsync>( - LanguageServerConstants.LegacyRazorSemanticTokensEditEndpoint, + var csharpResponse = await _requestInvoker.ReinvokeRequestOnServerAsync>( + Methods.TextDocumentSemanticTokensFullDeltaName, RazorLSPConstants.RazorCSharpLanguageServerName, newParams, cancellationToken).ConfigureAwait(false); @@ -369,7 +368,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var response = new ProvideSemanticTokensEditsResponse(tokens.Data, edits: null, tokens.ResultId, semanticTokensEditsParams.RequiredHostDocumentVersion); return response; } - else if (csharpResults.Value is SemanticTokensEdits edits) + else if (csharpResults.Value is SemanticTokensDelta edits) { var results = new RazorSemanticTokensEdit[edits.Edits.Length]; for (var i = 0; i < edits.Edits.Length; i++) @@ -414,13 +413,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor private static bool SupportsCSharpCodeActions(JToken token) { - var serverCapabilities = token.ToObject(); + var serverCapabilities = token.ToObject(); - var providesCodeActions = serverCapabilities?.CodeActionProvider?.Match( - boolValue => boolValue, - options => options != null) ?? false; - - var resolvesCodeActions = serverCapabilities?.CodeActionsResolveProvider == true; + var (providesCodeActions, resolvesCodeActions) = serverCapabilities?.CodeActionProvider?.Match( + boolValue => (boolValue, false), + options => (true, options.ResolveProvider)) ?? (false, false); return providesCodeActions && resolvesCodeActions; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/Feedback/RazorFeedbackDiagnosticFileProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/Feedback/RazorFeedbackDiagnosticFileProvider.cs index ae2014964d..64f6ba0b9b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/Feedback/RazorFeedbackDiagnosticFileProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/Feedback/RazorFeedbackDiagnosticFileProvider.cs @@ -57,9 +57,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Feedback return Array.Empty(); } -#pragma warning disable VSTHRD110 // Observe result of async calls - _joinableTaskFactory.RunAsync(() => ZipLogsAsync(logDirectory, zipFilePath)); -#pragma warning restore VSTHRD110 // Observe result of async calls + _ = _joinableTaskFactory.RunAsync(() => ZipLogsAsync(logDirectory, zipFilePath)); return new[] { zipFilePath }; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/CompletionHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/CompletionHandler.cs index a8de659a2a..e257485e3b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/CompletionHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/CompletionHandler.cs @@ -223,7 +223,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp if (completionList != null) { - completionList = completionList is VSCompletionList vsCompletionList + completionList = completionList is VSInternalCompletionList vsCompletionList ? new OptimizedVSCompletionList(vsCompletionList) : new OptimizedVSCompletionList(completionList); } @@ -456,12 +456,12 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } // Trigger character not associated with the current langauge. Transform the context into an invoked context. - var rewrittenContext = new VSCompletionContext() + var rewrittenContext = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked, }; - var invokeKind = (context as VSCompletionContext)?.InvokeKind; + var invokeKind = (context as VSInternalCompletionContext)?.InvokeKind; if (invokeKind.HasValue) { rewrittenContext.InvokeKind = invokeKind.Value; @@ -471,7 +471,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { // The C# language server will not return any completions for the '@' character unless we // send the completion request explicitly. - rewrittenContext.InvokeKind = VSCompletionInvokeKind.Explicit; + rewrittenContext.InvokeKind = VSInternalCompletionInvokeKind.Explicit; } return rewrittenContext; @@ -662,7 +662,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp internal static void SetResolveData(long resultId, CompletionList completionList) { - if (completionList is VSCompletionList vsCompletionList && vsCompletionList.Data != null) + if (completionList is VSInternalCompletionList vsCompletionList && vsCompletionList.Data != null) { // Provided completion list is already wrapping completion list data, lets wrap that instead of each completion item. diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DefaultLSPDocumentMappingProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DefaultLSPDocumentMappingProvider.cs index e2371e517c..6b7cdd117e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DefaultLSPDocumentMappingProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DefaultLSPDocumentMappingProvider.cs @@ -271,7 +271,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri); remappedDocumentEdits.Add(new TextDocumentEdit() { - TextDocument = new VersionedTextDocumentIdentifier() + TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = razorDocumentUri, Version = documentSnapshot?.Version diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DocumentPullDiagnosticsHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DocumentPullDiagnosticsHandler.cs index ba8929698d..589f24eb4b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DocumentPullDiagnosticsHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/DocumentPullDiagnosticsHandler.cs @@ -15,9 +15,9 @@ using Microsoft.VisualStudio.LanguageServerClient.Razor.Logging; namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { [Shared] - [ExportLspMethod(MSLSPMethods.DocumentPullDiagnosticName)] + [ExportLspMethod(VSInternalMethods.DocumentPullDiagnosticName)] internal class DocumentPullDiagnosticsHandler : - IRequestHandler + IRequestHandler { private readonly LSPRequestInvoker _requestInvoker; private readonly LSPDocumentManager _documentManager; @@ -67,7 +67,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } // Internal for testing - public async Task HandleRequestAsync(DocumentDiagnosticsParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + public async Task HandleRequestAsync(VSInternalDocumentDiagnosticsParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { @@ -102,9 +102,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _logger.LogInformation($"Failed to synchronize document {csharpDoc.Uri}."); // Could not synchronize, report nothing changed - return new DiagnosticReport[] + return new VSInternalDiagnosticReport[] { - new DiagnosticReport() + new VSInternalDiagnosticReport() { ResultId = request.PreviousResultId, Diagnostics = null @@ -112,7 +112,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp }; } - var referenceParams = new DocumentDiagnosticsParams() + var referenceParams = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { @@ -126,8 +126,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp // End goal is to transition this from ReinvokeRequestOnMultipleServersAsync -> ReinvokeRequestOnServerAsync // We can't do this right now as we don't have the ability to specify the language client name we'd like to make the call out to // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1246135 - var resultsFromAllLanguageServers = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( - MSLSPMethods.DocumentPullDiagnosticName, + var resultsFromAllLanguageServers = await _requestInvoker.ReinvokeRequestOnMultipleServersAsync( + VSInternalMethods.DocumentPullDiagnosticName, RazorLSPConstants.CSharpContentTypeName, referenceParams, cancellationToken).ConfigureAwait(false); @@ -153,8 +153,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return processedResults; } - private async Task RemapDocumentDiagnosticsAsync( - DiagnosticReport[] unmappedDiagnosticReports, + private async Task RemapDocumentDiagnosticsAsync( + VSInternalDiagnosticReport[] unmappedDiagnosticReports, Uri razorDocumentUri, CancellationToken cancellationToken) { @@ -163,7 +163,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return unmappedDiagnosticReports; } - var mappedDiagnosticReports = new List(unmappedDiagnosticReports.Length); + var mappedDiagnosticReports = new List(unmappedDiagnosticReports.Length); foreach (var diagnosticReport in unmappedDiagnosticReports) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/FindAllReferencesHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/FindAllReferencesHandler.cs index 9d79c35b75..f0aecc527a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/FindAllReferencesHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/FindAllReferencesHandler.cs @@ -21,8 +21,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp [Shared] [ExportLspMethod(Methods.TextDocumentReferencesName)] internal class FindAllReferencesHandler : - LSPProgressListenerHandlerBase, - IRequestHandler + LSPProgressListenerHandlerBase, + IRequestHandler { private readonly LSPRequestInvoker _requestInvoker; private readonly LSPDocumentManager _documentManager; @@ -80,7 +80,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } // Internal for testing - internal async override Task HandleRequestAsync(ReferenceParams request, ClientCapabilities clientCapabilities, string token, CancellationToken cancellationToken) + internal async override Task HandleRequestAsync(ReferenceParams request, ClientCapabilities clientCapabilities, string token, CancellationToken cancellationToken) { if (request is null) { @@ -137,7 +137,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _logger.LogInformation($"Requesting references for {projectionResult.Uri}."); - var response = await _requestInvoker.ReinvokeRequestOnServerAsync( + var response = await _requestInvoker.ReinvokeRequestOnServerAsync( Methods.TextDocumentReferencesName, projectionResult.LanguageKind.ToContainedLanguageServerName(), referenceParams, @@ -190,7 +190,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp IProgress progress, CancellationToken cancellationToken) { - var result = value.ToObject(); + var result = value.ToObject(); if (result == null || result.Length == 0) { @@ -205,9 +205,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp progress.Report(remappedResults); } - private async Task RemapReferenceItemsAsync(VSReferenceItem[] result, CancellationToken cancellationToken) + private async Task RemapReferenceItemsAsync(VSInternalReferenceItem[] result, CancellationToken cancellationToken) { - var remappedLocations = new List(); + var remappedLocations = new List(); foreach (var referenceItem in result) { @@ -222,7 +222,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp referenceItem.Text = FilterReferenceDisplayText(referenceItem.Text); // Indicates the reference item is directly available in the code - referenceItem.Origin = ItemOrigin.Exact; + referenceItem.Origin = VSInternalItemOrigin.Exact; if (!RazorLSPConventions.IsVirtualCSharpFile(referenceItem.Location.Uri) && !RazorLSPConventions.IsVirtualHtmlFile(referenceItem.Location.Uri)) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/HoverHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/HoverHandler.cs index 65a19acba8..22f91c4e5d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/HoverHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/HoverHandler.cs @@ -147,13 +147,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return CreateHover(result, mappingResult.Ranges[0]); } - private static VSHover CreateHover(Hover originalHover, Range range) + private static VSInternalHover CreateHover(Hover originalHover, Range range) { - return new VSHover + return new VSInternalHover { Contents = originalHover.Contents, Range = range, - RawContent = originalHover is VSHover originalVSHover ? originalVSHover.RawContent : null + RawContent = originalHover is VSInternalHover originalVSHover ? originalVSHover.RawContent : null }; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/InitializeHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/InitializeHandler.cs index de3c4fed1e..43da19df76 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/InitializeHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/InitializeHandler.cs @@ -23,7 +23,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { private static readonly InitializeResult s_initializeResult = new() { - Capabilities = new VSServerCapabilities + Capabilities = new VSInternalServerCapabilities { CompletionProvider = new CompletionOptions() { @@ -31,7 +31,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp ResolveProvider = true, TriggerCharacters = CompletionHandler.AllTriggerCharacters.ToArray() }, - OnAutoInsertProvider = new DocumentOnAutoInsertOptions() + OnAutoInsertProvider = new VSInternalDocumentOnAutoInsertOptions() { TriggerCharacters = new[] { "'", "/", "\n" } }, @@ -53,13 +53,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp }, ImplementationProvider = true, SupportsDiagnosticRequests = true, - OnTypeRenameProvider = new DocumentOnTypeRenameOptions() + LinkedEditingRangeProvider = new LinkedEditingRangeOptions() } }; private readonly JoinableTaskFactory _joinableTaskFactory; private readonly ILanguageClientBroker _languageClientBroker; private readonly ILanguageServiceBroker2 _languageServiceBroker; - private readonly List<(ILanguageClient Client, VSServerCapabilities Capabilities)> _serverCapabilities; + private readonly List<(ILanguageClient Client, VSInternalServerCapabilities Capabilities)> _serverCapabilities; private readonly JsonSerializer _serializer; private readonly ILogger _logger; @@ -96,10 +96,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _logger = loggerProvider.CreateLogger(nameof(InitializeHandler)); - _serverCapabilities = new List<(ILanguageClient, VSServerCapabilities)>(); + _serverCapabilities = new List<(ILanguageClient, VSInternalServerCapabilities)>(); _serializer = new JsonSerializer(); - _serializer.AddVSExtensionConverters(); + _serializer.AddVSInternalExtensionConverters(); } public Task HandleRequestAsync(InitializeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) @@ -138,7 +138,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp }).ConfigureAwait(false); } - private VSServerCapabilities GetMergedServerCapabilities(List relevantLanguageClients) + private VSInternalServerCapabilities GetMergedServerCapabilities(List relevantLanguageClients) { #pragma warning disable CS0618 // Type or member is obsolete foreach (var languageClientInstance in _languageServiceBroker.ActiveLanguageClients) @@ -149,16 +149,16 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var resultToken = languageClientInstance.InitializeResult; var initializeResult = resultToken.ToObject(_serializer); - _serverCapabilities.Add((languageClientInstance.Client, (initializeResult.Capabilities as VSServerCapabilities)!)); + _serverCapabilities.Add((languageClientInstance.Client, (initializeResult.Capabilities as VSInternalServerCapabilities)!)); } } - var serverCapabilities = new VSServerCapabilities + var serverCapabilities = new VSInternalServerCapabilities { CompletionProvider = GetMergedCompletionOptions(), TextDocumentSync = GetMergedTextDocumentSyncOptions(), HoverProvider = GetMergedHoverProvider(), - OnAutoInsertProvider = GetMergedDocumentOnAutoInsertOptions(), + OnAutoInsertProvider = GetMergedVSInternalDocumentOnAutoInsertOptions(), SignatureHelpProvider = GetMergedSignatureHelpOptions(), DefinitionProvider = GetMergedDefinitionProvider(), ReferencesProvider = GetMergedReferencesProvider(), @@ -198,12 +198,12 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return _serverCapabilities.Any(s => s.Capabilities.HoverProvider?.Value is bool isHoverSupported && isHoverSupported); } - private DocumentOnAutoInsertOptions GetMergedDocumentOnAutoInsertOptions() + private VSInternalDocumentOnAutoInsertOptions GetMergedVSInternalDocumentOnAutoInsertOptions() { - var allDocumentOnAutoInsertOptions = _serverCapabilities.Where(s => s.Capabilities.OnAutoInsertProvider != null).Select(s => s.Capabilities.OnAutoInsertProvider!); + var allVSInternalDocumentOnAutoInsertOptions = _serverCapabilities.Where(s => s.Capabilities.OnAutoInsertProvider != null).Select(s => s.Capabilities.OnAutoInsertProvider!); var triggerChars = new HashSet(); - foreach (var documentOnAutoInsertOptions in allDocumentOnAutoInsertOptions) + foreach (var documentOnAutoInsertOptions in allVSInternalDocumentOnAutoInsertOptions) { if (documentOnAutoInsertOptions.TriggerCharacters != null) { @@ -211,7 +211,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } } - return new DocumentOnAutoInsertOptions() + return new VSInternalDocumentOnAutoInsertOptions() { TriggerCharacters = triggerChars.ToArray(), }; @@ -318,7 +318,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return _serverCapabilities.Any(s => s.Capabilities.RenameProvider?.Value is bool isRenameSupported && isRenameSupported); } - private async Task VerifyMergedOnAutoInsertAsync(VSServerCapabilities mergedCapabilities) + private async Task VerifyMergedOnAutoInsertAsync(VSInternalServerCapabilities mergedCapabilities) { var triggerCharEnumeration = mergedCapabilities.OnAutoInsertProvider?.TriggerCharacters ?? Enumerable.Empty(); var purposefullyRemovedTriggerCharacters = new[] diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnTypeRenameHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/LinkedEditingRangeHandler.cs similarity index 79% rename from src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnTypeRenameHandler.cs rename to src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/LinkedEditingRangeHandler.cs index 02522a71cf..52cdd3c503 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnTypeRenameHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/LinkedEditingRangeHandler.cs @@ -13,8 +13,8 @@ using Microsoft.VisualStudio.LanguageServerClient.Razor.Logging; namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { [Shared] - [ExportLspMethod(MSLSPMethods.OnTypeRenameName)] - internal class OnTypeRenameHandler : IRequestHandler + [ExportLspMethod(Methods.TextDocumentLinkedEditingRangeName)] + internal class LinkedEditingRangeHandler : IRequestHandler { private readonly LSPDocumentManager _documentManager; private readonly LSPRequestInvoker _requestInvoker; @@ -23,7 +23,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp private readonly ILogger _logger; [ImportingConstructor] - public OnTypeRenameHandler( + public LinkedEditingRangeHandler( LSPDocumentManager documentManager, LSPRequestInvoker requestInvoker, LSPProjectionProvider projectionProvider, @@ -60,10 +60,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _projectionProvider = projectionProvider; _documentMappingProvider = documentMappingProvider; - _logger = loggerProvider.CreateLogger(nameof(OnTypeRenameHandler)); + _logger = loggerProvider.CreateLogger(nameof(LinkedEditingRangeHandler)); } - public async Task HandleRequestAsync(DocumentOnTypeRenameParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + public async Task HandleRequestAsync(LinkedEditingRangeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { @@ -94,23 +94,23 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return null; } - var onTypeRenameParams = new DocumentOnTypeRenameParams() + var linkedEditingRangeParams = new LinkedEditingRangeParams() { Position = projectionResult.Position, TextDocument = new TextDocumentIdentifier() { Uri = projectionResult.Uri } }; - _logger.LogInformation($"Requesting OnTypeRename for {projectionResult.Uri}."); + _logger.LogInformation($"Requesting LinkedEditingRange for {projectionResult.Uri}."); var languageServerName = projectionResult.LanguageKind.ToContainedLanguageServerName(); - var onTypeResponse = await _requestInvoker.ReinvokeRequestOnServerAsync( - MSLSPMethods.OnTypeRenameName, + var linkedEditingRangeResponse = await _requestInvoker.ReinvokeRequestOnServerAsync( + Methods.TextDocumentLinkedEditingRangeName, languageServerName, - onTypeRenameParams, + linkedEditingRangeParams, cancellationToken).ConfigureAwait(false); - var onTypeResult = onTypeResponse.Result; - if (onTypeResult is null) + var linkedEditingRangeResult = linkedEditingRangeResponse.Result; + if (linkedEditingRangeResult is null) { _logger.LogInformation("Received no results."); return null; @@ -121,7 +121,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var mappingResult = await _documentMappingProvider.MapToDocumentRangesAsync( projectionResult.LanguageKind, request.TextDocument.Uri, - onTypeResult.Ranges, + linkedEditingRangeResult.Ranges, cancellationToken).ConfigureAwait(false); if (mappingResult is null || @@ -133,9 +133,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return null; } - onTypeResult.Ranges = mappingResult.Ranges; + linkedEditingRangeResult.Ranges = mappingResult.Ranges; _logger.LogInformation("Returned remapped result."); - return onTypeResult; + return linkedEditingRangeResult; } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnAutoInsertHandler.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnAutoInsertHandler.cs index 1db3292612..2bfd26a3c8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnAutoInsertHandler.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/OnAutoInsertHandler.cs @@ -15,8 +15,8 @@ using Microsoft.VisualStudio.LanguageServerClient.Razor.Logging; namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { [Shared] - [ExportLspMethod(MSLSPMethods.OnAutoInsertName)] - internal class OnAutoInsertHandler : IRequestHandler + [ExportLspMethod(VSInternalMethods.OnAutoInsertName)] + internal class OnAutoInsertHandler : IRequestHandler { private static readonly HashSet s_htmlAllowedTriggerCharacters = new HashSet(); private static readonly HashSet s_cSharpAllowedTriggerCharacters = new() { "'", "/", "\n" }; @@ -71,7 +71,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _logger = loggerProvider.CreateLogger(nameof(OnAutoInsertHandler)); } - public async Task HandleRequestAsync(DocumentOnAutoInsertParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + public async Task HandleRequestAsync(VSInternalDocumentOnAutoInsertParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { if (request is null) { @@ -115,7 +115,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return null; } - var formattingParams = new DocumentOnAutoInsertParams() + var formattingParams = new VSInternalDocumentOnAutoInsertParams() { Character = request.Character, Options = request.Options, @@ -126,8 +126,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _logger.LogInformation($"Requesting auto-insert for {projectionResult.Uri}."); var languageServerName = projectionResult.LanguageKind.ToContainedLanguageServerName(); - var response = await _requestInvoker.ReinvokeRequestOnServerAsync( - MSLSPMethods.OnAutoInsertName, + var response = await _requestInvoker.ReinvokeRequestOnServerAsync( + VSInternalMethods.OnAutoInsertName, languageServerName, formattingParams, cancellationToken).ConfigureAwait(false); @@ -156,7 +156,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } var remappedEdit = remappedEdits.Single(); - var remappedResponse = new DocumentOnAutoInsertResponseItem() + var remappedResponse = new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = remappedEdit, TextEditFormat = result.TextEditFormat, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServer.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServer.cs index ed32754f0f..cc87774734 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServer.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServer.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServerClient.Razor.Logging; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using StreamJsonRpc; @@ -19,7 +18,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { private readonly JsonRpc _jsonRpc; private readonly ImmutableDictionary> _requestHandlers; - private VSClientCapabilities _clientCapabilities; + private VSInternalClientCapabilities _clientCapabilities; private RazorHtmlCSharpLanguageServer( Stream inputStream, @@ -90,9 +89,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } // InitializeParams only references ClientCapabilities, but the VS LSP client - // sends additional VS specific capabilities, so directly deserialize them into the VSClientCapabilities + // sends additional VS specific capabilities, so directly deserialize them into the VSInternalClientCapabilities // to avoid losing them. - _clientCapabilities = input["capabilities"].ToObject(); + _clientCapabilities = input["capabilities"].ToObject(); var initializeParams = input.ToObject(); return ExecuteRequestAsync(Methods.InitializeName, initializeParams, _clientCapabilities, cancellationToken); } @@ -146,15 +145,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return ExecuteRequestAsync(Methods.TextDocumentCompletionResolveName, request, _clientCapabilities, cancellationToken); } - [JsonRpcMethod(MSLSPMethods.OnAutoInsertName, UseSingleObjectParameterDeserialization = true)] - public Task OnAutoInsertAsync(DocumentOnAutoInsertParams request, CancellationToken cancellationToken) + [JsonRpcMethod(VSInternalMethods.OnAutoInsertName, UseSingleObjectParameterDeserialization = true)] + public Task OnAutoInsertAsync(VSInternalDocumentOnAutoInsertParams request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } - return ExecuteRequestAsync(MSLSPMethods.OnAutoInsertName, request, _clientCapabilities, cancellationToken); + return ExecuteRequestAsync(VSInternalMethods.OnAutoInsertName, request, _clientCapabilities, cancellationToken); } [JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName, UseSingleObjectParameterDeserialization = true)] @@ -168,15 +167,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return ExecuteRequestAsync(Methods.TextDocumentOnTypeFormattingName, request, _clientCapabilities, cancellationToken); } - [JsonRpcMethod(MSLSPMethods.OnTypeRenameName, UseSingleObjectParameterDeserialization = true)] - public Task OnTypeRenameAsync(DocumentOnTypeRenameParams request, CancellationToken cancellationToken) + [JsonRpcMethod(Methods.TextDocumentLinkedEditingRangeName, UseSingleObjectParameterDeserialization = true)] + public Task OnLinkedEditingRangeAsync(LinkedEditingRangeParams request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } - return ExecuteRequestAsync(MSLSPMethods.OnTypeRenameName, request, _clientCapabilities, cancellationToken); + return ExecuteRequestAsync(Methods.TextDocumentLinkedEditingRangeName, request, _clientCapabilities, cancellationToken); } [JsonRpcMethod(Methods.TextDocumentDefinitionName, UseSingleObjectParameterDeserialization = true)] @@ -191,14 +190,14 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } [JsonRpcMethod(Methods.TextDocumentReferencesName, UseSingleObjectParameterDeserialization = true)] - public Task FindAllReferencesAsync(ReferenceParams referenceParams, CancellationToken cancellationToken) + public Task FindAllReferencesAsync(VSInternalReferenceParams referenceParams, CancellationToken cancellationToken) { if (referenceParams is null) { throw new ArgumentNullException(nameof(referenceParams)); } - return ExecuteRequestAsync(Methods.TextDocumentReferencesName, referenceParams, _clientCapabilities, cancellationToken); + return ExecuteRequestAsync(Methods.TextDocumentReferencesName, referenceParams, _clientCapabilities, cancellationToken); } [JsonRpcMethod(Methods.TextDocumentSignatureHelpName, UseSingleObjectParameterDeserialization = true)] @@ -245,15 +244,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return ExecuteRequestAsync(Methods.TextDocumentImplementationName, positionParams, _clientCapabilities, cancellationToken); } - [JsonRpcMethod(MSLSPMethods.DocumentPullDiagnosticName, UseSingleObjectParameterDeserialization = true)] - public Task DocumentPullDiagnosticsAsync(DocumentDiagnosticsParams documentDiagnosticsParams, CancellationToken cancellationToken) + [JsonRpcMethod(VSInternalMethods.DocumentPullDiagnosticName, UseSingleObjectParameterDeserialization = true)] + public Task DocumentPullDiagnosticsAsync(VSInternalDocumentDiagnosticsParams documentDiagnosticsParams, CancellationToken cancellationToken) { if (documentDiagnosticsParams is null) { throw new ArgumentNullException(nameof(documentDiagnosticsParams)); } - return ExecuteRequestAsync(MSLSPMethods.DocumentPullDiagnosticName, documentDiagnosticsParams, _clientCapabilities, cancellationToken); + return ExecuteRequestAsync(VSInternalMethods.DocumentPullDiagnosticName, documentDiagnosticsParams, _clientCapabilities, cancellationToken); } // Razor tooling doesn't utilize workspace pull diagnostics as it doesn't really make sense for our use case. @@ -261,10 +260,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp // triggered. Thus we add the following no-op handler until a server capability is available. // Having a server capability would reduce overhead of sending/receiving the request and the // associated serialization/deserialization. - [JsonRpcMethod(MSLSPMethods.WorkspacePullDiagnosticName, UseSingleObjectParameterDeserialization = true)] - public static Task WorkspacePullDiagnosticsAsync(WorkspaceDocumentDiagnosticsParams workspaceDiagnosticsParams, CancellationToken cancellationToken) + [JsonRpcMethod(VSInternalMethods.WorkspacePullDiagnosticName, UseSingleObjectParameterDeserialization = true)] + public static Task WorkspacePullDiagnosticsAsync(VSInternalWorkspaceDiagnosticsParams workspaceDiagnosticsParams, CancellationToken cancellationToken) { - return Task.FromResult(null); + return Task.FromResult(null); } // Internal for testing @@ -301,7 +300,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp #pragma warning restore CA2000 // Dispose objects before losing scope var serializer = messageFormatter.JsonSerializer; - AddVSExtensionConverters(serializer); + serializer.AddVSInternalExtensionConverters(); #pragma warning disable CA2000 // Dispose objects before losing scope var messageHandler = new HeaderDelimitedMessageHandler(outputStream, inputStream, messageFormatter); @@ -310,24 +309,6 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp // The JsonRpc object owns disposing the message handler which disposes the formatter. var jsonRpc = new JsonRpc(messageHandler, target); return jsonRpc; - - // Can be removed for serializer.AddVSExtensionConverters() once we are able to update to a newer LSP protocol Extensions version. - static void AddVSExtensionConverters(JsonSerializer serializer) - { - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - serializer.Converters.Add(new VSExtensionConverter()); - } } private static ImmutableDictionary> CreateMethodToHandlerMap(IEnumerable> requestHandlers) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServerClient.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServerClient.cs index 1eac58e434..4c5bcba622 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServerClient.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/HtmlCSharp/RazorHtmlCSharpLanguageServerClient.cs @@ -49,6 +49,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp public IEnumerable FilesToWatch => null; + public bool ShowNotificationOnInitializeFailed => true; + public event AsyncEventHandler StartAsync; public event AsyncEventHandler StopAsync @@ -72,11 +74,6 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return StartAsync.InvokeAsync(this, EventArgs.Empty); } - public Task OnServerInitializeFailedAsync(Exception e) - { - return Task.CompletedTask; - } - public Task OnServerInitializedAsync() { return Task.CompletedTask; @@ -86,5 +83,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { _languageServer?.Dispose(); } + + public Task OnServerInitializeFailedAsync(ILanguageClientInitializationInfo initializationState) + { + var initializationFailureContext = new InitializationFailureContext(); + initializationFailureContext.FailureMessage = string.Format(VS.LSClientRazor.Resources.LanguageServer_Initialization_Failed, + Name, initializationState.StatusMessage, initializationState.InitializationException?.ToString()); + return Task.FromResult(initializationFailureContext); + } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorDocumentOptionsService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorDocumentOptionsService.cs new file mode 100644 index 0000000000..cc4c704220 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorDocumentOptionsService.cs @@ -0,0 +1,80 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.ExternalAccess.Razor.Api; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Razor.Editor; + +namespace Microsoft.VisualStudio.LanguageServerClient.Razor +{ + [Export(typeof(IRazorDocumentOptionsService))] + internal sealed class RazorDocumentOptionsService : IRazorDocumentOptionsService + { + private readonly RazorLSPClientOptionsMonitor _optionsMonitor; + + [ImportingConstructor] + public RazorDocumentOptionsService(RazorLSPClientOptionsMonitor optionsMonitor) + { + if (optionsMonitor is null) + { + throw new ArgumentNullException(nameof(optionsMonitor)); + } + + _optionsMonitor = optionsMonitor; + } + + public Task GetOptionsForDocumentAsync(Document document, CancellationToken cancellationToken) + { + if (document is null) + { + throw new ArgumentNullException(nameof(document)); + } + + // TO-DO: We should switch to a per-document implementation once Razor starts supporting .editorconfig. + var editorSettings = _optionsMonitor.EditorSettings; + return Task.FromResult(new RazorDocumentOptions(document, editorSettings)); + } + + private sealed class RazorDocumentOptions : IRazorDocumentOptions + { + private readonly EditorSettings _editorSettings; + private readonly OptionKey _useTabsOptionKey; + private readonly OptionKey _tabSizeOptionKey; + private readonly OptionKey _indentationSizeOptionKey; + + public RazorDocumentOptions(Document document, EditorSettings editorSettings) + { + _editorSettings = editorSettings; + + _useTabsOptionKey = new OptionKey(FormattingOptions.UseTabs, document.Project.Language); + _tabSizeOptionKey = new OptionKey(FormattingOptions.TabSize, document.Project.Language); + _indentationSizeOptionKey = new OptionKey(FormattingOptions.IndentationSize, document.Project.Language); + } + + public bool TryGetDocumentOption(OptionKey option, out object value) + { + if (option == _useTabsOptionKey) + { + value = _editorSettings.IndentWithTabs; + return true; + } + else if (option == _tabSizeOptionKey || option == _indentationSizeOptionKey) + { + value = _editorSettings.IndentSize; + return true; + } + else + { + value = null; + return false; + } + } + } + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorHtmlPublishDiagnosticsInterceptor.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorHtmlPublishDiagnosticsInterceptor.cs index 189d7890bb..1641ba2b3a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorHtmlPublishDiagnosticsInterceptor.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorHtmlPublishDiagnosticsInterceptor.cs @@ -66,13 +66,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor // Consequently, if we don't initialize the logger here, then the logger will be unavailable for logging. await InitializeLogHubLoggerAsync(cancellationToken).ConfigureAwait(false); - var diagnosticParams = token.ToObject(); + var diagnosticParams = token.ToObject(); if (diagnosticParams?.Uri is null) { var exception = new ArgumentException("Conversion of token failed."); - _logger?.LogError(exception, $"Not a {nameof(VSPublishDiagnosticParams)}"); + _logger?.LogError(exception, $"Not a {nameof(PublishDiagnosticParams)}"); throw exception; } @@ -138,13 +138,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor return new(token, changedDocumentUri: false); } - static InterceptionResult CreateEmptyDiagnosticsResponse(VSPublishDiagnosticParams diagnosticParams) + static InterceptionResult CreateEmptyDiagnosticsResponse(PublishDiagnosticParams diagnosticParams) { diagnosticParams.Diagnostics = Array.Empty(); return CreateResponse(diagnosticParams); } - static InterceptionResult CreateResponse(VSPublishDiagnosticParams diagnosticParams) + static InterceptionResult CreateResponse(PublishDiagnosticParams diagnosticParams) { var newToken = JToken.FromObject(diagnosticParams); var interceptionResult = new InterceptionResult(newToken, changedDocumentUri: true); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerClient.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerClient.cs index 1e8b31f04b..4760a56119 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerClient.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerClient.cs @@ -118,6 +118,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor // We set a priority to ensure that our Razor language server is always chosen if there's a conflict for which language server to prefer. public int Priority => 10; + public bool ShowNotificationOnInitializeFailed => true; + public event AsyncEventHandler StartAsync; public event AsyncEventHandler StopAsync { @@ -229,11 +231,6 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor await StartAsync.InvokeAsync(this, EventArgs.Empty).ConfigureAwait(false); } - public Task OnServerInitializeFailedAsync(Exception e) - { - return Task.CompletedTask; - } - public Task OnServerInitializedAsync() { _serverShutdownDisposable = _server.OnShutdown.Subscribe((_) => ServerShutdown()); @@ -307,5 +304,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor } public Task AttachForCustomMessageAsync(JsonRpc rpc) => Task.CompletedTask; + + public Task OnServerInitializeFailedAsync(ILanguageClientInitializationInfo initializationState) + { + var initializationFailureContext = new InitializationFailureContext(); + initializationFailureContext.FailureMessage = string.Format(VS.LSClientRazor.Resources.LanguageServer_Initialization_Failed, + Name, initializationState.StatusMessage, initializationState.InitializationException?.ToString()); + return Task.FromResult(initializationFailureContext); + } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerCustomMessageTarget.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerCustomMessageTarget.cs index 952298bd68..53af24a8c9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerCustomMessageTarget.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/RazorLanguageServerCustomMessageTarget.cs @@ -34,11 +34,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor // Called by the Razor Language Server to provide code actions from the platform. [JsonRpcMethod(LanguageServerConstants.RazorProvideCodeActionsEndpoint, UseSingleObjectParameterDeserialization = true)] - public abstract Task ProvideCodeActionsAsync(CodeActionParams codeActionParams, CancellationToken cancellationToken); + public abstract Task ProvideCodeActionsAsync(CodeActionParams codeActionParams, CancellationToken cancellationToken); // Called by the Razor Language Server to resolve code actions from the platform. [JsonRpcMethod(LanguageServerConstants.RazorResolveCodeActionsEndpoint, UseSingleObjectParameterDeserialization = true)] - public abstract Task ResolveCodeActionsAsync(VSCodeAction codeAction, CancellationToken cancellationToken); + public abstract Task ResolveCodeActionsAsync(VSInternalCodeAction codeAction, CancellationToken cancellationToken); // Called by the Razor Language Server to provide semantic tokens from the platform. [JsonRpcMethod(LanguageServerConstants.RazorProvideSemanticTokensEndpoint, UseSingleObjectParameterDeserialization = true)] diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/VS.LSClientRazor.Resources.resx b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/VS.LSClientRazor.Resources.resx index 23037dc4f5..0182abb90f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/VS.LSClientRazor.Resources.resx +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/VS.LSClientRazor.Resources.resx @@ -117,6 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.cs.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.cs.xlf index 6f68067a68..ce21ec61af 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.cs.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.cs.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Ladicí program Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.de.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.de.xlf index 81093970b3..be5bdef3b3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.de.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.de.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor-Debugger diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.es.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.es.xlf index db3089adaf..01133c6d46 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.es.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.es.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Depurador de Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.fr.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.fr.xlf index b19b4e45c4..e4417d0718 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.fr.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.fr.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Débogueur Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.it.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.it.xlf index ac7ab01789..99bd676cf3 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.it.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.it.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Debugger Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ja.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ja.xlf index d7cdfac0c3..28ace069bf 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ja.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ja.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor デバッガー diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ko.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ko.xlf index e535d2dc35..e03f48257e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ko.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ko.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor 디버거 diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pl.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pl.xlf index 2d55710bb3..8f4cf5da43 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pl.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pl.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Debuger składni Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pt-BR.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pt-BR.xlf index 6049ac6526..4fcbf2bac7 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pt-BR.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.pt-BR.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Depurar Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ru.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ru.xlf index 0ab7729ac6..6639949fc8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ru.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.ru.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Отладчик Razor diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.tr.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.tr.xlf index c05ac34349..2ba9e8a43d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.tr.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.tr.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor Hata Ayıklayıcısı diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hans.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hans.xlf index 7abb47f526..2b6ff36741 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hans.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hans.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor 调试程序 diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hant.xlf b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hant.xlf index 032ee93c0b..66ff0d3b4b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hant.xlf +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServerClient.Razor/xlf/VS.LSClientRazor.Resources.zh-Hant.xlf @@ -2,6 +2,11 @@ + + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} failed to initialize. Please report a problem via Help -> Send Feedback -> Report a Problem. Status = {1}. Exception = {2} + {0} is the language server name. Status is the status of the initialization. Exception is the exception encountered during initialization. + Razor Debugger Razor 偵錯工具 diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RunningDocumentTableEventSink.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RunningDocumentTableEventSink.cs index 76390ba81b..bf03426ea9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RunningDocumentTableEventSink.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/RunningDocumentTableEventSink.cs @@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public RunningDocumentTableEventSink(VisualStudioEditorDocumentManager documentManager) { - if (documentManager == null) + if (documentManager is null) { throw new ArgumentNullException(nameof(documentManager)); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManager.cs index a396d7f098..c2e7dc8d58 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManager.cs @@ -6,9 +6,11 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor.Documents { @@ -25,28 +27,24 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private readonly Dictionary _cookiesByDocument; public VisualStudioEditorDocumentManager( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, FileChangeTrackerFactory fileChangeTrackerFactory, IVsRunningDocumentTable runningDocumentTable, IVsEditorAdaptersFactoryService editorAdaptersFactory) - : base(foregroundDispatcher, fileChangeTrackerFactory) + : base(projectSnapshotManagerDispatcher, joinableTaskContext, fileChangeTrackerFactory) { - if (runningDocumentTable == null) + if (runningDocumentTable is null) { throw new ArgumentNullException(nameof(runningDocumentTable)); } - if (editorAdaptersFactory == null) + if (editorAdaptersFactory is null) { throw new ArgumentNullException(nameof(editorAdaptersFactory)); } - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (fileChangeTrackerFactory == null) + if (fileChangeTrackerFactory is null) { throw new ArgumentNullException(nameof(fileChangeTrackerFactory)); } @@ -63,18 +61,23 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents protected override ITextBuffer GetTextBufferForOpenDocument(string filePath) { - if (filePath == null) + if (filePath is null) { throw new ArgumentNullException(nameof(filePath)); } + JoinableTaskContext.AssertUIThread(); + // Check if the document is already open and initialized, and associate a buffer if possible. uint cookie; if (_runningDocumentTable.IsMonikerValid(filePath) && ((cookie = _runningDocumentTable.GetDocumentCookie(filePath)) != VSConstants.VSCOOKIE_NIL) && (_runningDocumentTable.GetDocumentFlags(cookie) & (uint)_VSRDTFLAGS4.RDT_PendingInitialization) == 0) { - var textBuffer = !(((object)_runningDocumentTable.GetDocumentData(cookie)) is VsTextBuffer vsTextBuffer) + // GetDocumentData requires the UI thread + var documentData = _runningDocumentTable.GetDocumentData(cookie); + + var textBuffer = !(documentData is VsTextBuffer vsTextBuffer) ? null : _editorAdaptersFactory.GetDocumentBuffer(vsTextBuffer); return textBuffer; @@ -85,6 +88,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents protected override void OnDocumentOpened(EditorDocument document) { + JoinableTaskContext.AssertUIThread(); + var cookie = _runningDocumentTable.GetDocumentCookie(document.DocumentFilePath); if (cookie != VSConstants.VSCOOKIE_NIL) { @@ -94,6 +99,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents protected override void OnDocumentClosed(EditorDocument document) { + JoinableTaskContext.AssertUIThread(); + var key = new DocumentKey(document.ProjectFilePath, document.DocumentFilePath); if (_cookiesByDocument.TryGetValue(key, out var cookie)) { @@ -103,7 +110,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void DocumentOpened(uint cookie) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -139,8 +146,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void BufferLoaded(IVsTextBuffer vsTextBuffer, string filePath) { - ForegroundDispatcher.AssertForegroundThread(); - + JoinableTaskContext.AssertUIThread(); + var textBuffer = _editorAdaptersFactory.GetDocumentBuffer(vsTextBuffer); if (textBuffer != null) { @@ -155,7 +162,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void BufferLoaded(ITextBuffer textBuffer, string filePath, EditorDocument[] documents) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -168,7 +175,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void DocumentClosed(uint cookie, string exceptFilePath = null) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -192,7 +199,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public void DocumentRenamed(uint cookie, string fromFilePath, string toFilePath) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); // Ignore changes is casing if (FilePathComparer.Instance.Equals(fromFilePath, toFilePath)) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManagerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManagerFactory.cs index 1fd0f508d3..5035431dc2 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManagerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioEditorDocumentManagerFactory.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Razor; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Editor.Razor.Documents { @@ -17,32 +18,35 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { private readonly SVsServiceProvider _serviceProvider; private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactory; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; [ImportingConstructor] public VisualStudioEditorDocumentManagerFactory( SVsServiceProvider serviceProvider, IVsEditorAdaptersFactoryService editorAdaptersFactory, - ForegroundDispatcher foregroundDispatcher) + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext) { - if (serviceProvider == null) + if (serviceProvider is null) { throw new ArgumentNullException(nameof(serviceProvider)); } - if (editorAdaptersFactory == null) + if (editorAdaptersFactory is null) { throw new ArgumentNullException(nameof(editorAdaptersFactory)); } - if (foregroundDispatcher == null) + if (joinableTaskContext is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(joinableTaskContext)); } _serviceProvider = serviceProvider; _editorAdaptersFactory = editorAdaptersFactory; - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) @@ -54,7 +58,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents var runningDocumentTable = (IVsRunningDocumentTable)_serviceProvider.GetService(typeof(SVsRunningDocumentTable)); var fileChangeTrackerFactory = workspaceServices.GetRequiredService(); - return new VisualStudioEditorDocumentManager(_foregroundDispatcher, fileChangeTrackerFactory, runningDocumentTable, _editorAdaptersFactory); + return new VisualStudioEditorDocumentManager( + _projectSnapshotManagerDispatcher, _joinableTaskContext, fileChangeTrackerFactory, runningDocumentTable, _editorAdaptersFactory); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisaulStudioFileChangeTracker.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTracker.cs similarity index 80% rename from src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisaulStudioFileChangeTracker.cs rename to src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTracker.cs index 219f33584e..9dff5bfcc2 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisaulStudioFileChangeTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTracker.cs @@ -4,6 +4,7 @@ using System; using System.IO; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; @@ -14,10 +15,10 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { private const _VSFILECHANGEFLAGS FileChangeFlags = _VSFILECHANGEFLAGS.VSFILECHG_Time | _VSFILECHANGEFLAGS.VSFILECHG_Size | _VSFILECHANGEFLAGS.VSFILECHG_Del | _VSFILECHANGEFLAGS.VSFILECHG_Add; - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly ErrorReporter _errorReporter; private readonly IVsAsyncFileChangeEx _fileChangeService; - private readonly JoinableTaskFactory _joinableTaskFactory; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; // Internal for testing internal JoinableTask _fileChangeAdviseTask; @@ -28,47 +29,52 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public VisualStudioFileChangeTracker( string filePath, - ForegroundDispatcher foregroundDispatcher, ErrorReporter errorReporter, IVsAsyncFileChangeEx fileChangeService, - JoinableTaskFactory joinableTaskFactory) + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath)); } - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (errorReporter == null) + if (errorReporter is null) { throw new ArgumentNullException(nameof(errorReporter)); } - if (fileChangeService == null) + if (fileChangeService is null) { throw new ArgumentNullException(nameof(fileChangeService)); } + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + + if (joinableTaskContext is null) + { + throw new ArgumentNullException(nameof(joinableTaskContext)); + } + FilePath = filePath; - _foregroundDispatcher = foregroundDispatcher; _errorReporter = errorReporter; _fileChangeService = fileChangeService; - _joinableTaskFactory = joinableTaskFactory ?? throw new ArgumentNullException(); + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; } public override string FilePath { get; } public override void StartListening() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_fileChangeUnadviseTask?.IsCompleted == false) { - // An unadvise operation is still processing, block the foreground thread until it completes. + // An unadvise operation is still processing, block the project snapshot manager's thread until it completes. _fileChangeUnadviseTask.Join(); } @@ -78,7 +84,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents return; } - _fileChangeAdviseTask = _joinableTaskFactory.RunAsync(async () => + _fileChangeAdviseTask = _joinableTaskContext.Factory.RunAsync(async () => { try { @@ -88,9 +94,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { // Don't report PathTooLongExceptions but don't fault either. } -#pragma warning disable CA1031 // Do not catch general exception types catch (Exception exception) -#pragma warning restore CA1031 // Do not catch general exception types { // Don't explode on actual exceptions, just report gracefully. _errorReporter.ReportError(exception); @@ -102,7 +106,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public override void StopListening() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_fileChangeAdviseTask == null || _fileChangeUnadviseTask?.IsCompleted == false) { @@ -110,7 +114,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents return; } - _fileChangeUnadviseTask = _joinableTaskFactory.RunAsync(async () => + _fileChangeUnadviseTask = _joinableTaskContext.Factory.RunAsync(async () => { try { @@ -130,9 +134,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { // Don't report PathTooLongExceptions but don't fault either. } -#pragma warning disable CA1031 // Do not catch general exception types catch (Exception exception) -#pragma warning restore CA1031 // Do not catch general exception types { // Don't explode on actual exceptions, just report gracefully. _errorReporter.ReportError(exception); @@ -143,9 +145,9 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public int FilesChanged(uint fileCount, string[] filePaths, uint[] fileChangeFlags) { // Capturing task for testing purposes - _fileChangedTask = _joinableTaskFactory.RunAsync(async () => + _fileChangedTask = _joinableTaskContext.Factory.RunAsync(async () => { - await _joinableTaskFactory.SwitchToMainThreadAsync(); + await _joinableTaskContext.Factory.SwitchToMainThreadAsync(); foreach (var fileChangeFlag in fileChangeFlags) { @@ -177,7 +179,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private void OnChanged(FileChangeKind changeKind) { - _foregroundDispatcher.AssertForegroundThread(); + _joinableTaskContext.AssertUIThread(); if (Changed == null) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactory.cs index 911278c74f..6b40b353fe 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactory.cs @@ -10,41 +10,41 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { internal class VisualStudioFileChangeTrackerFactory : FileChangeTrackerFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly ErrorReporter _errorReporter; - private readonly JoinableTaskContext _joinableTaskContext; private readonly IVsAsyncFileChangeEx _fileChangeService; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; public VisualStudioFileChangeTrackerFactory( - ForegroundDispatcher foregroundDispatcher, ErrorReporter errorReporter, IVsAsyncFileChangeEx fileChangeService, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (errorReporter == null) + if (errorReporter is null) { throw new ArgumentNullException(nameof(errorReporter)); } - if (fileChangeService == null) + if (fileChangeService is null) { throw new ArgumentNullException(nameof(fileChangeService)); } + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + if (joinableTaskContext is null) { throw new ArgumentNullException(nameof(joinableTaskContext)); } - _foregroundDispatcher = foregroundDispatcher; _errorReporter = errorReporter; - _joinableTaskContext = joinableTaskContext; _fileChangeService = fileChangeService; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; } public override FileChangeTracker Create(string filePath) @@ -54,7 +54,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath)); } - var fileChangeTracker = new VisualStudioFileChangeTracker(filePath, _foregroundDispatcher, _errorReporter, _fileChangeService, _joinableTaskContext.Factory); + var fileChangeTracker = new VisualStudioFileChangeTracker(filePath, _errorReporter, _fileChangeService, _projectSnapshotManagerDispatcher, _joinableTaskContext); return fileChangeTracker; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactoryFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactoryFactory.cs index 68428080d4..706d22cc73 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactoryFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Documents/VisualStudioFileChangeTrackerFactoryFactory.cs @@ -17,30 +17,33 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents internal class VisualStudioFileChangeTrackerFactoryFactory : IWorkspaceServiceFactory { private readonly IVsAsyncFileChangeEx _fileChangeService; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly JoinableTaskContext _joinableTaskContext; [ImportingConstructor] - public VisualStudioFileChangeTrackerFactoryFactory(ForegroundDispatcher foregroundDispatcher, SVsServiceProvider serviceProvider, JoinableTaskContext joinableTaskContext) + public VisualStudioFileChangeTrackerFactoryFactory( + SVsServiceProvider serviceProvider, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (serviceProvider == null) + if (serviceProvider is null) { throw new ArgumentNullException(nameof(serviceProvider)); } + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + if (joinableTaskContext is null) { throw new ArgumentNullException(nameof(joinableTaskContext)); } - _foregroundDispatcher = foregroundDispatcher; - _joinableTaskContext = joinableTaskContext; _fileChangeService = serviceProvider.GetService(typeof(SVsFileChangeEx)) as IVsAsyncFileChangeEx; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { @@ -50,7 +53,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents } var errorReporter = workspaceServices.GetRequiredService(); - return new VisualStudioFileChangeTrackerFactory(_foregroundDispatcher, errorReporter, _fileChangeService, _joinableTaskContext); + return new VisualStudioFileChangeTrackerFactory(errorReporter, _fileChangeService, _projectSnapshotManagerDispatcher, _joinableTaskContext); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs index e69932ddf3..9224f89ce6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs @@ -34,18 +34,20 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem public DefaultRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, [Import(typeof(VisualStudioWorkspace))] Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectConfigurationFilePathStore projectConfigurationFilePathStore) - : base(commonServices, workspace, projectConfigurationFilePathStore) + : base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore) { } // Internal for testing internal DefaultRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, - Workspace workspace, - ProjectConfigurationFilePathStore projectConfigurationFilePathStore, - ProjectSnapshotManagerBase projectManager) - : base(commonServices, workspace, projectConfigurationFilePathStore, projectManager) + Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + ProjectConfigurationFilePathStore projectConfigurationFilePathStore, + ProjectSnapshotManagerBase projectManager) + : base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager) { } @@ -127,13 +129,13 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem for (var i = 0; i < documents.Length; i++) { AddDocumentUnsafe(documents[i]); - } - }).ConfigureAwait(false); + } + }, CancellationToken.None).ConfigureAwait(false); } else { // Ok we can't find a configuration. Let's assume this project isn't using Razor then. - await UpdateAsync(UninitializeProjectUnsafe).ConfigureAwait(false); + await UpdateAsync(UninitializeProjectUnsafe, CancellationToken.None).ConfigureAwait(false); } }).ConfigureAwait(false), registerFaultHandler: true); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs index 809ea7ac89..5498f30b3d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs @@ -38,17 +38,19 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem public FallbackRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, [Import(typeof(VisualStudioWorkspace))] Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectConfigurationFilePathStore projectConfigurationFilePathStore) - : base(commonServices, workspace, projectConfigurationFilePathStore) + : base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore) { } internal FallbackRazorProjectHost( IUnconfiguredProjectCommonServices commonServices, Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectConfigurationFilePathStore projectConfigurationFilePathStore, ProjectSnapshotManagerBase projectManager) - : base(commonServices, workspace, projectConfigurationFilePathStore, projectManager) + : base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager) { } @@ -111,7 +113,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem if (mvcReferenceFullPath == null) { // Ok we can't find an MVC version. Let's assume this project isn't using Razor then. - await UpdateAsync(UninitializeProjectUnsafe).ConfigureAwait(false); + await UpdateAsync(UninitializeProjectUnsafe, CancellationToken.None).ConfigureAwait(false); return; } @@ -119,7 +121,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem if (version == null) { // Ok we can't find an MVC version. Let's assume this project isn't using Razor then. - await UpdateAsync(UninitializeProjectUnsafe).ConfigureAwait(false); + await UpdateAsync(UninitializeProjectUnsafe, CancellationToken.None).ConfigureAwait(false); return; } @@ -155,7 +157,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { AddDocumentUnsafe(documents[i]); } - }).ConfigureAwait(false); + }, CancellationToken.None).ConfigureAwait(false); }).ConfigureAwait(false), registerFaultHandler: true); } @@ -267,9 +269,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var assemblyDefinition = metadataReader.GetAssemblyDefinition(); return assemblyDefinition.Version; } -#pragma warning disable CA1031 // Do not catch general exception types catch -#pragma warning restore CA1031 // Do not catch general exception types { // We're purposely silencing any kinds of I/O exceptions here, just in case something wacky is going on. return null; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs index 2421c11ba3..9e5530746c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs @@ -23,6 +23,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem internal abstract class RazorProjectHostBase : OnceInitializedOnceDisposedAsync, IProjectDynamicLoadComponent { private readonly Workspace _workspace; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly AsyncSemaphore _lock; private ProjectSnapshotManagerBase _projectManager; @@ -42,21 +43,28 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem public RazorProjectHostBase( IUnconfiguredProjectCommonServices commonServices, [Import(typeof(VisualStudioWorkspace))] Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectConfigurationFilePathStore projectConfigurationFilePathStore) : base(commonServices.ThreadingService.JoinableTaskContext) { - if (commonServices == null) + if (commonServices is null) { throw new ArgumentNullException(nameof(commonServices)); } - if (workspace == null) + if (workspace is null) { throw new ArgumentNullException(nameof(workspace)); } + if (projectSnapshotManagerDispatcher is null) + { + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); + } + CommonServices = commonServices; _workspace = workspace; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _lock = new AsyncSemaphore(initialCount: 1); _currentDocuments = new Dictionary(FilePathComparer.Instance); @@ -67,9 +75,10 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem protected RazorProjectHostBase( IUnconfiguredProjectCommonServices commonServices, Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectConfigurationFilePathStore projectConfigurationFilePathStore, ProjectSnapshotManagerBase projectManager) - : this(commonServices, workspace, projectConfigurationFilePathStore) + : this(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore) { if (projectManager == null) { @@ -106,7 +115,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { if (Current != null) { - await UpdateAsync(UninitializeProjectUnsafe).ConfigureAwait(false); + await UpdateAsync(UninitializeProjectUnsafe, CancellationToken.None).ConfigureAwait(false); } }).ConfigureAwait(false); } @@ -127,7 +136,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var old = Current; var oldDocuments = _currentDocuments.Values.ToArray(); - await UpdateAsync(UninitializeProjectUnsafe).ConfigureAwait(false); + await UpdateAsync(UninitializeProjectUnsafe, CancellationToken.None).ConfigureAwait(false); await UpdateAsync(() => { @@ -139,15 +148,15 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { AddDocumentUnsafe(oldDocuments[i]); } - }).ConfigureAwait(false); + }, CancellationToken.None).ConfigureAwait(false); } }).ConfigureAwait(false); } - // Should only be called from the UI thread. + // Should only be called from the project snapshot manager's specialized thread. private ProjectSnapshotManagerBase GetProjectManager() { - CommonServices.ThreadingService.VerifyOnUIThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_projectManager == null) { @@ -157,11 +166,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem return _projectManager; } - protected async Task UpdateAsync(Action action) - { - await CommonServices.ThreadingService.SwitchToUIThread(); - action(); - } + protected Task UpdateAsync(Action action, CancellationToken cancellationToken) + => _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken); protected void UninitializeProjectUnsafe() { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs deleted file mode 100644 index 6b80023b68..0000000000 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.ComponentModel.Composition; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; -using Microsoft.VisualStudio.Shell; - -namespace Microsoft.VisualStudio.LanguageServices.Razor -{ - [System.Composition.Shared] - [Export(typeof(ForegroundDispatcher))] - internal class VisualStudioForegroundDispatcher : ForegroundDispatcher - { - public override TaskScheduler BackgroundScheduler { get; } = TaskScheduler.Default; - - public override TaskScheduler ForegroundScheduler { get; } = TaskScheduler.FromCurrentSynchronizationContext(); - - public override bool IsForegroundThread => ThreadHelper.CheckAccess(); - } -} diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs new file mode 100644 index 0000000000..ea1d607ca2 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; + +namespace Microsoft.VisualStudio.LanguageServices.Razor +{ + [Export(typeof(ProjectSnapshotManagerDispatcher))] + internal class VisualStudioProjectSnapshotManagerDispatcher : DefaultProjectSnapshotManagerDispatcher + { + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Guest/GuestProjectPathProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Guest/GuestProjectPathProvider.cs index a72c37e9f5..36f602c91d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Guest/GuestProjectPathProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Guest/GuestProjectPathProvider.cs @@ -89,7 +89,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Guest { var projectHierarchyProxy = _proxyAccessor.GetProjectHierarchyProxy(); - // We need to block the foreground thread to get a proper project path. However, this is only done once on opening thedocument. + // We need to block the UI thread to get a proper project path. However, this is only done once on opening the document. return projectHierarchyProxy.GetProjectPathAsync(ownerPath, CancellationToken.None); }); diff --git a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxy.cs b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxy.cs index e062a54585..5c4b839b11 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxy.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxy.cs @@ -4,7 +4,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; @@ -14,47 +13,38 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host internal class DefaultProjectHierarchyProxy : IProjectHierarchyProxy, ICollaborationService { private readonly CollaborationSession _session; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly JoinableTaskFactory _joinableTaskFactory; private IVsUIShellOpenDocument _openDocumentShell; public DefaultProjectHierarchyProxy( CollaborationSession session, - ForegroundDispatcher foregroundDispatcher, JoinableTaskFactory joinableTaskFactory) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (joinableTaskFactory == null) + if (joinableTaskFactory is null) { throw new ArgumentNullException(nameof(joinableTaskFactory)); } _session = session; - _foregroundDispatcher = foregroundDispatcher; _joinableTaskFactory = joinableTaskFactory; } public async Task GetProjectPathAsync(Uri documentFilePath, CancellationToken cancellationToken) { - if (documentFilePath == null) + if (documentFilePath is null) { throw new ArgumentNullException(nameof(documentFilePath)); } - _foregroundDispatcher.AssertBackgroundThread(); - await _joinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - if (_openDocumentShell == null) + if (_openDocumentShell is null) { _openDocumentShell = ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument; } diff --git a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxyFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxyFactory.cs index 60d04169df..e41ded0ce6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxyFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectHierarchyProxyFactory.cs @@ -17,36 +17,29 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host Role = ServiceRole.RemoteService)] internal class DefaultProjectHierarchyProxyFactory : ICollaborationServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; private readonly JoinableTaskContext _joinableTaskContext; [ImportingConstructor] public DefaultProjectHierarchyProxyFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext) { - if (foregroundDispatcher == null) - { - throw new ArgumentNullException(nameof(foregroundDispatcher)); - } - - if (joinableTaskContext == null) + if (joinableTaskContext is null) { throw new ArgumentNullException(nameof(joinableTaskContext)); } - _foregroundDispatcher = foregroundDispatcher; _joinableTaskContext = joinableTaskContext; } public Task CreateServiceAsync(CollaborationSession session, CancellationToken cancellationToken) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } - var service = new DefaultProjectHierarchyProxy(session, _foregroundDispatcher, _joinableTaskContext.Factory); + var service = new DefaultProjectHierarchyProxy(session, _joinableTaskContext.Factory); return Task.FromResult(service); } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxy.cs b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxy.cs index e3977e1e13..5b6925ba1a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxy.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxy.cs @@ -15,7 +15,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host internal class DefaultProjectSnapshotManagerProxy : IProjectSnapshotManagerProxy, ICollaborationService, IDisposable { private readonly CollaborationSession _session; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly ProjectSnapshotManager _projectSnapshotManager; private readonly JoinableTaskFactory _joinableTaskFactory; private readonly AsyncSemaphore _latestStateSemaphore; @@ -27,7 +27,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host public DefaultProjectSnapshotManagerProxy( CollaborationSession session, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManager projectSnapshotManager, JoinableTaskFactory joinableTaskFactory) { @@ -36,9 +36,9 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host throw new ArgumentNullException(nameof(session)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectSnapshotManager == null) @@ -52,7 +52,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host } _session = session; - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectSnapshotManager = projectSnapshotManager; _joinableTaskFactory = joinableTaskFactory; @@ -80,7 +80,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host public void Dispose() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _projectSnapshotManager.Changed -= ProjectSnapshotManager_Changed; _latestStateSemaphore.Dispose(); @@ -90,7 +90,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host // Internal for testing internal async Task> GetLatestProjectsAsync() { - if (!_foregroundDispatcher.IsForegroundThread) + if (!_joinableTaskFactory.Context.IsOnMainThread) { await _joinableTaskFactory.SwitchToMainThreadAsync(CancellationToken.None); } @@ -130,7 +130,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host private void ProjectSnapshotManager_Changed(object sender, ProjectChangeEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_disposed) { @@ -161,7 +161,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host private void OnChanged(ProjectChangeEventProxyArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_disposed) { diff --git a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxyFactory.cs b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxyFactory.cs index 9280038f7e..7a17e7ad90 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxyFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LiveShare.Razor/Host/DefaultProjectSnapshotManagerProxyFactory.cs @@ -22,19 +22,19 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host Role = ServiceRole.RemoteService)] internal class DefaultProjectSnapshotManagerProxyFactory : ICollaborationServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly JoinableTaskContext _joinableTaskContext; private readonly Workspace _workspace; [ImportingConstructor] public DefaultProjectSnapshotManagerProxyFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext, [Import(typeof(VisualStudioWorkspace))] Workspace workspace) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (joinableTaskContext == null) @@ -47,7 +47,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host throw new ArgumentNullException(nameof(workspace)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _joinableTaskContext = joinableTaskContext; _workspace = workspace; @@ -66,7 +66,7 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host var razorLanguageServices = _workspace.Services.GetLanguageServices(RazorLanguage.Name); var projectSnapshotManager = razorLanguageServices.GetRequiredService(); - var service = new DefaultProjectSnapshotManagerProxy(session, _foregroundDispatcher, projectSnapshotManager, _joinableTaskContext.Factory); + var service = new DefaultProjectSnapshotManagerProxy(session, _projectSnapshotManagerDispatcher, projectSnapshotManager, _joinableTaskContext.Factory); return Task.FromResult(service); } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectBuildChangeTrigger.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectBuildChangeTrigger.cs index 33593876c6..b166e37c7c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectBuildChangeTrigger.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectBuildChangeTrigger.cs @@ -18,18 +18,18 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { private readonly TextBufferProjectService _projectService; private readonly ProjectWorkspaceStateGenerator _workspaceStateGenerator; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private ProjectSnapshotManagerBase _projectManager; [ImportingConstructor] public ProjectBuildChangeTrigger( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, TextBufferProjectService projectService, ProjectWorkspaceStateGenerator workspaceStateGenerator) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectService == null) @@ -42,21 +42,21 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor throw new ArgumentNullException(nameof(workspaceStateGenerator)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectService = projectService; _workspaceStateGenerator = workspaceStateGenerator; } // Internal for testing internal ProjectBuildChangeTrigger( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, TextBufferProjectService projectService, ProjectWorkspaceStateGenerator workspaceStateGenerator, ProjectSnapshotManagerBase projectManager) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (projectService == null) @@ -74,7 +74,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor throw new ArgumentNullException(nameof(projectManager)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectService = projectService; _projectManager = projectManager; _workspaceStateGenerator = workspaceStateGenerator; @@ -103,7 +103,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor throw new ArgumentNullException(nameof(args)); } - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!args.Success) { diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultDotNetProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultDotNetProjectHost.cs index 571a1821d9..a5467f182e 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultDotNetProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultDotNetProjectHost.cs @@ -14,14 +14,14 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem private const string ExplicitRazorConfigurationCapability = "DotNetCoreRazorConfiguration"; private readonly DotNetProject _project; - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly VisualStudioMacWorkspaceAccessor _workspaceAccessor; private readonly TextBufferProjectService _projectService; private RazorProjectHostBase _razorProjectHost; public DefaultDotNetProjectHost( DotNetProject project, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, VisualStudioMacWorkspaceAccessor workspaceAccessor, TextBufferProjectService projectService) { @@ -30,9 +30,9 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem throw new ArgumentNullException(nameof(project)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspaceAccessor == null) @@ -46,20 +46,20 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem } _project = project; - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _workspaceAccessor = workspaceAccessor; _projectService = projectService; } // Internal for testing internal DefaultDotNetProjectHost( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, VisualStudioMacWorkspaceAccessor workspaceAccessor, TextBufferProjectService projectService) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspaceAccessor == null) @@ -72,7 +72,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem throw new ArgumentNullException(nameof(projectService)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _workspaceAccessor = workspaceAccessor; _projectService = projectService; } @@ -81,7 +81,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem public override void Subscribe() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); UpdateRazorHostProject(); @@ -91,7 +91,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem private void Project_Disposing(object sender, EventArgs e) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); _project.ProjectCapabilitiesChanged -= Project_ProjectCapabilitiesChanged; _project.Disposing -= Project_Disposing; @@ -104,7 +104,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem // Internal for testing internal void UpdateRazorHostProject() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); DetachCurrentRazorProjectHost(); @@ -123,12 +123,12 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem if (_project.IsCapabilityMatch(ExplicitRazorConfigurationCapability)) { // SDK >= 2.1 - _razorProjectHost = new DefaultRazorProjectHost(_project, _foregroundDispatcher, projectSnapshotManager); + _razorProjectHost = new DefaultRazorProjectHost(_project, _projectSnapshotManagerDispatcher, projectSnapshotManager); return; } // We're an older version of Razor at this point, SDK < 2.1 - _razorProjectHost = new FallbackRazorProjectHost(_project, _foregroundDispatcher, projectSnapshotManager); + _razorProjectHost = new FallbackRazorProjectHost(_project, _projectSnapshotManagerDispatcher, projectSnapshotManager); } private bool TryGetProjectSnapshotManager(out ProjectSnapshotManagerBase projectSnapshotManagerBase) diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs index 06347b3682..d71ff08af6 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DefaultRazorProjectHost.cs @@ -30,16 +30,14 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem public DefaultRazorProjectHost( DotNetProject project, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerBase projectSnapshotManager) - : base(project, foregroundDispatcher, projectSnapshotManager) + : base(project, projectSnapshotManagerDispatcher, projectSnapshotManager) { } protected override async Task OnProjectChangedAsync() { - ForegroundDispatcher.AssertBackgroundThread(); - await ExecuteWithLockAsync(async () => { var projectProperties = DotNetProject.MSBuildProject.EvaluatedProperties; @@ -82,7 +80,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem _currentRazorFilePaths = documentFilePaths; - _ = Task.Factory.StartNew(() => + _ = ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { foreach (var document in removedFiles) { @@ -95,9 +93,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem AddDocument(hostProject, document, relativeFilePath); } }, - CancellationToken.None, - TaskCreationOptions.None, - ForegroundDispatcher.ForegroundScheduler); + CancellationToken.None); } // Internal for testing diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DotNetProjectHostFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DotNetProjectHostFactory.cs index 9755b2dc19..9cdc0b1b24 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DotNetProjectHostFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/DotNetProjectHostFactory.cs @@ -13,19 +13,19 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem [Export(typeof(DotNetProjectHostFactory))] internal class DotNetProjectHostFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly VisualStudioMacWorkspaceAccessor _workspaceAccessor; private readonly TextBufferProjectService _projectService; [ImportingConstructor] public DotNetProjectHostFactory( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, VisualStudioMacWorkspaceAccessor workspaceAccessor, TextBufferProjectService projectService) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } if (workspaceAccessor == null) @@ -38,7 +38,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem throw new ArgumentNullException(nameof(projectService)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _workspaceAccessor = workspaceAccessor; _projectService = projectService; } @@ -50,7 +50,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem throw new ArgumentNullException(nameof(project)); } - var projectHost = new DefaultDotNetProjectHost(project, _foregroundDispatcher, _workspaceAccessor, _projectService); + var projectHost = new DefaultDotNetProjectHost(project, _projectSnapshotManagerDispatcher, _workspaceAccessor, _projectService); return projectHost; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs index c019ea4969..0eeac51e65 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/FallbackRazorProjectHost.cs @@ -20,16 +20,14 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem public FallbackRazorProjectHost( DotNetProject project, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerBase projectSnapshotManager) - : base(project, foregroundDispatcher, projectSnapshotManager) + : base(project, projectSnapshotManagerDispatcher, projectSnapshotManager) { } protected override async Task OnProjectChangedAsync() { - ForegroundDispatcher.AssertBackgroundThread(); - await ExecuteWithLockAsync(async () => { var referencedAssemblies = await DotNetProject.GetReferencedAssemblies(ConfigurationSelector.Default); diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs index 1d81b46035..c401caabc1 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/ProjectSystem/RazorProjectHostBase.cs @@ -27,26 +27,26 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem public RazorProjectHostBase( DotNetProject project, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ProjectSnapshotManagerBase projectSnapshotManager) { - if (project == null) + if (project is null) { throw new ArgumentNullException(nameof(project)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - if (projectSnapshotManager == null) + if (projectSnapshotManager is null) { throw new ArgumentNullException(nameof(projectSnapshotManager)); } DotNetProject = project; - ForegroundDispatcher = foregroundDispatcher; + ProjectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; _projectSnapshotManager = projectSnapshotManager; _onProjectChangedInnerSemaphore = new AsyncSemaphore(initialCount: 1); _projectChangedSemaphore = new AsyncSemaphore(initialCount: 1); @@ -59,15 +59,15 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem public HostProject HostProject { get; private set; } - protected ForegroundDispatcher ForegroundDispatcher { get; } + protected ProjectSnapshotManagerDispatcher ProjectSnapshotManagerDispatcher { get; } public void Detach() { - ForegroundDispatcher.AssertForegroundThread(); + ProjectSnapshotManagerDispatcher.AssertDispatcherThread(); DotNetProject.Modified -= DotNetProject_Modified; - UpdateHostProjectForeground(null); + UpdateHostProjectProjectSnapshotManagerDispatcher(null); } protected abstract Task OnProjectChangedAsync(); @@ -75,21 +75,20 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem // Protected virtual for testing protected virtual void AttachToProject() { - ForegroundDispatcher.AssertForegroundThread(); + ProjectSnapshotManagerDispatcher.AssertDispatcherThread(); DotNetProject.Modified += DotNetProject_Modified; // Trigger the initial update to the project. _batchingProjectChanges = true; - _ = Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.BackgroundScheduler); + _ = Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } // Must be called inside the lock. protected async Task UpdateHostProjectUnsafeAsync(HostProject newHostProject) { - ForegroundDispatcher.AssertBackgroundThread(); - - await Task.Factory.StartNew(UpdateHostProjectForeground, newHostProject, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.ForegroundScheduler); + await ProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync( + () => UpdateHostProjectProjectSnapshotManagerDispatcher(newHostProject), CancellationToken.None); } protected async Task ExecuteWithLockAsync(Func func) @@ -102,8 +101,6 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem private async Task ProjectChangedBackgroundAsync(object state) { - ForegroundDispatcher.AssertBackgroundThread(); - _batchingProjectChanges = false; // Ensure ordering, typically we'll only have 1 background thread in flight at a time. However, @@ -122,7 +119,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem throw new ArgumentNullException(nameof(args)); } - ForegroundDispatcher.AssertForegroundThread(); + ProjectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_batchingProjectChanges) { @@ -137,13 +134,13 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem // Therefore, we re-dispatch here to allow any remaining project change events to fire and to then only have 1 host // project change trigger; this way we don't spam our own system with re-configure calls. _batchingProjectChanges = true; - _ = Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, ForegroundDispatcher.BackgroundScheduler); + _ = Task.Factory.StartNew(ProjectChangedBackgroundAsync, null, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } } - private void UpdateHostProjectForeground(object state) + private void UpdateHostProjectProjectSnapshotManagerDispatcher(object state) { - ForegroundDispatcher.AssertForegroundThread(); + ProjectSnapshotManagerDispatcher.AssertDispatcherThread(); var newHostProject = (HostProject)state; @@ -169,7 +166,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem protected void AddDocument(HostProject hostProject, string filePath, string relativeFilePath) { - ForegroundDispatcher.AssertForegroundThread(); + ProjectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_currentDocuments.ContainsKey(filePath)) { @@ -191,4 +188,4 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem } } } -} \ No newline at end of file +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs deleted file mode 100644 index 789171cf05..0000000000 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioForegroundDispatcher.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.ComponentModel.Composition; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Razor; - -namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor -{ - [System.Composition.Shared] - [Export(typeof(ForegroundDispatcher))] - internal class VisualStudioForegroundDispatcher : ForegroundDispatcher - { - public override TaskScheduler BackgroundScheduler { get; } = TaskScheduler.Default; - - public override TaskScheduler ForegroundScheduler { get; } = MonoDevelop.Core.Runtime.MainTaskScheduler; - - public override bool IsForegroundThread => MonoDevelop.Core.Runtime.IsMainThread; - } -} diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManager.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManager.cs index 88cf915d2c..05852ad546 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManager.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManager.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Editor.Razor.Documents; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using MonoDevelop.Ide; namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor @@ -14,9 +16,10 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor internal class VisualStudioMacEditorDocumentManager : EditorDocumentManagerBase { public VisualStudioMacEditorDocumentManager( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext, FileChangeTrackerFactory fileChangeTrackerFactory) - : base(foregroundDispatcher, fileChangeTrackerFactory) + : base(projectSnapshotManagerDispatcher, joinableTaskContext, fileChangeTrackerFactory) { } @@ -41,7 +44,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public void HandleDocumentOpened(string filePath, ITextBuffer textBuffer) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -57,7 +60,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public void HandleDocumentClosed(string filePath) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { @@ -81,7 +84,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public void HandleDocumentRenamed(string fromFilePath, string toFilePath, ITextBuffer textBuffer) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); if (string.Equals(fromFilePath, toFilePath, FilePathComparison.Instance)) { @@ -102,7 +105,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public void BufferLoaded(ITextBuffer textBuffer, string filePath, EditorDocument[] documents) { - ForegroundDispatcher.AssertForegroundThread(); + JoinableTaskContext.AssertUIThread(); lock (Lock) { diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManagerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManagerFactory.cs index 9912d0cff2..7387284e0b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManagerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacEditorDocumentManagerFactory.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Razor; using Microsoft.VisualStudio.Editor.Razor.Documents; +using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { @@ -14,17 +15,21 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor [ExportWorkspaceServiceFactory(typeof(EditorDocumentManager), ServiceLayer.Host)] internal class VisualStudioMacEditorDocumentManagerFactory : IWorkspaceServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; + private readonly JoinableTaskContext _joinableTaskContext; [ImportingConstructor] - public VisualStudioMacEditorDocumentManagerFactory(ForegroundDispatcher foregroundDispatcher) + public VisualStudioMacEditorDocumentManagerFactory( + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + JoinableTaskContext joinableTaskContext) { - if (foregroundDispatcher is null) + if (projectSnapshotManagerDispatcher is null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; + _joinableTaskContext = joinableTaskContext; } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) @@ -35,7 +40,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor } var fileChangeTrackerFactory = workspaceServices.GetRequiredService(); - var editorDocumentManager = new VisualStudioMacEditorDocumentManager(_foregroundDispatcher, fileChangeTrackerFactory); + var editorDocumentManager = new VisualStudioMacEditorDocumentManager(_projectSnapshotManagerDispatcher, _joinableTaskContext, fileChangeTrackerFactory); return editorDocumentManager; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTracker.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTracker.cs index 17f9910514..84f95f3318 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTracker.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTracker.cs @@ -10,7 +10,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { internal class VisualStudioMacFileChangeTracker : FileChangeTracker { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private readonly string _normalizedFilePath; private bool _listening; @@ -18,28 +18,28 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public VisualStudioMacFileChangeTracker( string filePath, - ForegroundDispatcher foregroundDispatcher) + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath)); } - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } FilePath = filePath; _normalizedFilePath = NormalizePath(FilePath); - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public override string FilePath { get; } public override void StartListening() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (_listening) { @@ -53,7 +53,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor public override void StopListening() { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_listening) { @@ -89,7 +89,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor private void HandleFileChangeEvent(FileChangeKind changeKind, FileEventArgs args) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (Changed == null) { @@ -114,7 +114,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor private void OnChanged(FileChangeKind changeKind) { - _foregroundDispatcher.AssertForegroundThread(); + _projectSnapshotManagerDispatcher.AssertDispatcherThread(); var args = new FileChangeEventArgs(FilePath, changeKind); Changed?.Invoke(this, args); diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactory.cs index ec3560afc5..e92fbd116a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactory.cs @@ -9,16 +9,16 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { internal class VisualStudioMacFileChangeTrackerFactory : FileChangeTrackerFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; - public VisualStudioMacFileChangeTrackerFactory(ForegroundDispatcher foregroundDispatcher) + public VisualStudioMacFileChangeTrackerFactory(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public override FileChangeTracker Create(string filePath) @@ -28,7 +28,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath)); } - var fileChangeTracker = new VisualStudioMacFileChangeTracker(filePath, _foregroundDispatcher); + var fileChangeTracker = new VisualStudioMacFileChangeTracker(filePath, _projectSnapshotManagerDispatcher); return fileChangeTracker; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactoryFactory.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactoryFactory.cs index 012084c697..9817a6cb9a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactoryFactory.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioMacFileChangeTrackerFactoryFactory.cs @@ -14,17 +14,17 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor [ExportWorkspaceServiceFactory(typeof(FileChangeTrackerFactory), ServiceLayer.Host)] internal class VisualStudioMacFileChangeTrackerFactoryFactory : IWorkspaceServiceFactory { - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; [ImportingConstructor] - public VisualStudioMacFileChangeTrackerFactoryFactory(ForegroundDispatcher foregroundDispatcher) + public VisualStudioMacFileChangeTrackerFactoryFactory(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) { - if (foregroundDispatcher == null) + if (projectSnapshotManagerDispatcher == null) { - throw new ArgumentNullException(nameof(foregroundDispatcher)); + throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher)); } - _foregroundDispatcher = foregroundDispatcher; + _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher; } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) @@ -34,7 +34,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor throw new ArgumentNullException(nameof(workspaceServices)); } - return new VisualStudioMacFileChangeTrackerFactory(_foregroundDispatcher); + return new VisualStudioMacFileChangeTrackerFactory(_projectSnapshotManagerDispatcher); } } } diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs new file mode 100644 index 0000000000..9f16806fd4 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.LanguageServices.Razor/VisualStudioProjectSnapshotManagerDispatcher.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; + +namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor +{ + [Export(typeof(ProjectSnapshotManagerDispatcher))] + internal class VisualStudioProjectSnapshotManagerDispatcher : DefaultProjectSnapshotManagerDispatcher + { + } +} diff --git a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/RazorProjectExtension.cs b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/RazorProjectExtension.cs index 2ef08073b1..f53058a81b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/RazorProjectExtension.cs +++ b/src/Razor/src/Microsoft.VisualStudio.Mac.RazorAddin/RazorProjectExtension.cs @@ -14,12 +14,12 @@ namespace Microsoft.VisualStudio.Mac.RazorAddin internal class RazorProjectExtension : ProjectExtension { private readonly object _lock = new object(); - private readonly ForegroundDispatcher _foregroundDispatcher; + private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher; private CancellationTokenSource _cancellationTokenSource; public RazorProjectExtension() { - _foregroundDispatcher = CompositionManager.Instance.GetExportedValue(); + _projectSnapshotManagerDispatcher = CompositionManager.Instance.GetExportedValue(); } protected override void OnBoundToSolution() @@ -52,7 +52,7 @@ namespace Microsoft.VisualStudio.Mac.RazorAddin _ = IdeApp.TypeSystemService.GetWorkspaceAsync(Project.ParentSolution, token).ContinueWith(task => projectHost.Subscribe(), token, TaskContinuationOptions.OnlyOnRanToCompletion, // We only want to act if we could properly retrieve the workspace. - _foregroundDispatcher.ForegroundScheduler); + _projectSnapshotManagerDispatcher.DispatcherScheduler); } protected override void OnUnboundFromSolution() diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs index 6241adade5..c20496549a 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/AssemblyCodeBases.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.Shell; [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.VisualStudio.LanguageServer.Protocol.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.VisualStudio.LanguageServer.Protocol.Extensions.dll")] +[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Microsoft.VisualStudio.LanguageServer.Protocol.Internal.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\MediatR.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\OmniSharp.Extensions.JsonRpc.dll")] [assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\OmniSharp.Extensions.LanguageProtocol.dll")] diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj index bf42be9ba8..4f3f0d1e35 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/Microsoft.VisualStudio.RazorExtension.csproj @@ -25,6 +25,7 @@ true neutral + ServiceHubCore @@ -59,6 +60,18 @@ PreserveNewest true + + PreserveNewest + true + + + PreserveNewest + true + + + PreserveNewest + true + PreserveNewest true @@ -130,6 +143,7 @@ + @@ -163,6 +177,20 @@ + + Microsoft.CodeAnalysis.Remote.Razor.CoreComponents + + true + false + PublishProjectOutputGroup + + false + $(ServiceHubCoreSubPath) + + + false + + @@ -219,6 +247,7 @@ + diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/RazorPackage.cs b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/RazorPackage.cs index 92a7a5a0d5..d26f330e03 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/RazorPackage.cs +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/RazorPackage.cs @@ -21,9 +21,11 @@ namespace Microsoft.VisualStudio.RazorExtension [AboutDialogInfo(PackageGuidString, "Razor (ASP.NET Core)", "#110", "#112", IconResourceID = "#400")] [ProvideService(typeof(RazorLanguageService))] [ProvideLanguageService(typeof(RazorLanguageService), RazorLSPConstants.RazorLSPContentTypeName, 110)] - [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider", Audience = Shell.ServiceBroker.ServiceAudience.Local)] - [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider64", Audience = Shell.ServiceBroker.ServiceAudience.Local)] - [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider64S", Audience = Shell.ServiceBroker.ServiceAudience.Local)] + [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider", Audience = ServiceAudience.Local)] + [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider64", Audience = ServiceAudience.Local)] + [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProvider64S", Audience = ServiceAudience.Local)] + [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProviderCore64", ServiceLocation = ProvideBrokeredServiceHubServiceAttribute.DefaultServiceLocation + @"\ServiceHubCore", Audience = ServiceAudience.Local)] + [ProvideBrokeredServiceHubService("Microsoft.VisualStudio.Razor.TagHelperProviderCore64S", ServiceLocation = ProvideBrokeredServiceHubServiceAttribute.DefaultServiceLocation + @"\ServiceHubCore", Audience = ServiceAudience.Local)] [Guid(PackageGuidString)] public sealed class RazorPackage : AsyncPackage { diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProvider.AssemblySearchPathsConfig.json b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProvider.AssemblySearchPathsConfig.json new file mode 100644 index 0000000000..b23dbf2aae --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProvider.AssemblySearchPathsConfig.json @@ -0,0 +1,3 @@ +[ + "..\\..\\managedLanguages\\VBCSharp\\LanguageServices\\Core" +] \ No newline at end of file diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64.servicehub.service.json b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64.servicehub.service.json new file mode 100644 index 0000000000..54faca95a3 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64.servicehub.service.json @@ -0,0 +1,11 @@ +{ + "host": "coreClr", + "hostId": "RoslynCodeAnalysisService", + "hostGroupAllowed": true, + "entryPoint": { + "assemblyPath": "Microsoft.CodeAnalysis.Remote.Razor.dll", + "fullClassName": "Microsoft.CodeAnalysis.Remote.Razor.RemoteTagHelperProviderServiceFactory", + "AssemblySearchPathsConfig": "Microsoft.VisualStudio.Razor.TagHelperProvider.AssemblySearchPathsConfig.json" + }, + "friendServices": [ "roslynRemoteHostCore64" ] +} \ No newline at end of file diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64S.servicehub.service.json b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64S.servicehub.service.json new file mode 100644 index 0000000000..b3be606022 --- /dev/null +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/ServiceHubCore/Microsoft.VisualStudio.Razor.TagHelperProviderCore64S.servicehub.service.json @@ -0,0 +1,11 @@ +{ + "host": "coreClr", + "hostId": "RoslynCodeAnalysisServiceS", + "hostGroupAllowed": true, + "entryPoint": { + "assemblyPath": "Microsoft.CodeAnalysis.Remote.Razor.dll", + "fullClassName": "Microsoft.CodeAnalysis.Remote.Razor.RemoteTagHelperProviderServiceFactory", + "AssemblySearchPathsConfig": "Microsoft.VisualStudio.Razor.TagHelperProvider.AssemblySearchPathsConfig.json" + }, + "friendServices": [ "roslynRemoteHostCore64S" ] +} \ No newline at end of file diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/language-configuration.json b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/language-configuration.json index c06e8bea2a..b061ef0d59 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/language-configuration.json +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/language-configuration.json @@ -25,8 +25,8 @@ { "open": "<", "close": ">" } ], "indentationRules": { - "increaseIndentPattern": "(?:\\s<(?!(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr))(\\w[\\w\\d]*)([^/>]*(?!/)>)\\s*$)|(?:\\{\\s*$)", - "decreaseIndentPattern": "(?:)|(?:\\})" + "increaseIndentPattern": "<(?!\\?|(?:area|base|br|col|frame|hr|html|img|input|keygen|link|menuitem|meta|param|source|track|wbr)\\b|[^>]*\\/>)([-_\\.A-Za-z0-9]+)(?=\\s|>)\\b[^>]*>(?!.*<\\/\\1>)|)|\\{[^}\"']*$", + "decreaseIndentPattern": "^\\s*(<\\/(?!html)[-_\\.A-Za-z0-9]+\\b[^>]*>|-->|\\})" }, "onEnterRules": [ { diff --git a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest index f9933f7972..8e8b2e936d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest +++ b/src/Razor/src/Microsoft.VisualStudio.RazorExtension/source.extension.vsixmanifest @@ -26,11 +26,14 @@ - - - + + + + + + diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Common.Test/BackgroundDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Common.Test/BackgroundDocumentGeneratorTest.cs index dab5dbbf7f..eb4e8d1556 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Common.Test/BackgroundDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Common.Test/BackgroundDocumentGeneratorTest.cs @@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Common private class TestBackgroundDocumentGenerator : BackgroundDocumentGenerator { - public TestBackgroundDocumentGenerator(ForegroundDispatcher foregroundDispatcher) : base(foregroundDispatcher) + public TestBackgroundDocumentGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(projectSnapshotManagerDispatcher) { } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs index ef2dba85bb..a241a5b037 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/LanguageServerTestBase.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Test.Common { public LanguageServerTestBase() { - Dispatcher = new SingleThreadedForegroundDispatcher(); + Dispatcher = new TestProjectSnapshotManagerDispatcher(); FilePathNormalizer = new FilePathNormalizer(); var logger = new Mock(MockBehavior.Strict).Object; Mock.Get(logger).Setup(l => l.Log(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>())).Verifiable(); @@ -25,27 +25,26 @@ namespace Microsoft.AspNetCore.Razor.Test.Common LoggerFactory = Mock.Of(factory => factory.CreateLogger(It.IsAny()) == logger, MockBehavior.Strict); } - internal ForegroundDispatcher Dispatcher { get; } + internal ProjectSnapshotManagerDispatcher Dispatcher { get; } internal FilePathNormalizer FilePathNormalizer { get; } protected ILoggerFactory LoggerFactory { get; } - private class SingleThreadedForegroundDispatcher : ForegroundDispatcher + private class TestProjectSnapshotManagerDispatcher : ProjectSnapshotManagerDispatcher { - public SingleThreadedForegroundDispatcher() + public TestProjectSnapshotManagerDispatcher() { - ForegroundScheduler = SynchronizationContext.Current == null ? new ThrowingTaskScheduler() : TaskScheduler.FromCurrentSynchronizationContext(); - BackgroundScheduler = TaskScheduler.Default; + DispatcherScheduler = SynchronizationContext.Current == null + ? new ThrowingTaskScheduler() + : TaskScheduler.FromCurrentSynchronizationContext(); } - public override TaskScheduler ForegroundScheduler { get; } - - public override TaskScheduler BackgroundScheduler { get; } + public override TaskScheduler DispatcherScheduler { get; } private Thread Thread { get; } = Thread.CurrentThread; - public override bool IsForegroundThread => Thread.CurrentThread == Thread; + public override bool IsDispatcherThread => Thread.CurrentThread == Thread; } private class ThrowingTaskScheduler : TaskScheduler diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshotManager.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshotManager.cs index 36adac0a55..0085443839 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshotManager.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test.Common/TestProjectSnapshotManager.cs @@ -14,12 +14,12 @@ namespace Microsoft.AspNetCore.Razor.Test.Common { internal class TestProjectSnapshotManager : DefaultProjectSnapshotManager { - private TestProjectSnapshotManager(ForegroundDispatcher dispatcher, Workspace workspace) + private TestProjectSnapshotManager(ProjectSnapshotManagerDispatcher dispatcher, Workspace workspace) : base(dispatcher, new DefaultErrorReporter(), Enumerable.Empty(), workspace) { } - public static TestProjectSnapshotManager Create(ForegroundDispatcher dispatcher) + public static TestProjectSnapshotManager Create(ProjectSnapshotManagerDispatcher dispatcher) { if (dispatcher == null) { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs index 494d9eac21..e9559ce92c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.Language; @@ -505,4 +505,4 @@ expected: @" return provider; } } -} +} \ No newline at end of file diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs index 7719b813ef..f0e880ab68 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Moq; using Newtonsoft.Json.Linq; @@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions public async Task Handle_MissingFile() { // Arrange - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), _emptyDocumentResolver); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), _emptyDocumentResolver); var data = JObject.FromObject(new AddUsingsCodeActionParams() { Uri = new Uri("c:/Test.razor"), @@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = CreateCodeDocument(contents); codeDocument.SetUnsupported(); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var data = JObject.FromObject(new AddUsingsCodeActionParams() { Uri = new Uri(documentPath), @@ -72,7 +73,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = string.Empty; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/\"{Environment.NewLine}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -147,7 +148,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = projectEngine.Process(projectItem); codeDocument.SetFileKind(FileKinds.Legacy); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -180,7 +181,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}
"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -213,7 +214,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@namespace Testing{Environment.NewLine}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -246,7 +247,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/\"{Environment.NewLine}@namespace Testing{Environment.NewLine}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -279,7 +280,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@using System"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, @@ -312,7 +313,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@using System{Environment.NewLine}@using System.Linq{Environment.NewLine}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new AddUsingsCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new AddUsingsCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/AddUsingsCSharpCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/AddUsingsCSharpCodeActionResolverTest.cs index 35d39f10aa..f2ba9203e6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/AddUsingsCSharpCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/AddUsingsCSharpCodeActionResolverTest.cs @@ -17,6 +17,7 @@ using System.Threading; using Newtonsoft.Json.Linq; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Mvc.Razor.Extensions; +using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { @@ -190,7 +191,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions documentVersionCache ??= CreateDocumentVersionCache(); addUsingResolver = new AddUsingsCSharpCodeActionResolver( - new DefaultForegroundDispatcher(), + new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), languageServer, documentVersionCache); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs index 059e6daa86..f0e2f2fa18 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs @@ -19,6 +19,7 @@ using Newtonsoft.Json.Linq; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.AspNetCore.Mvc.Razor.Extensions; using System.Linq; +using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { @@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions razorFormattingService ??= CreateRazorFormattingService(documentUri); csharpCodeActionResolver = new DefaultCSharpCodeActionResolver( - new DefaultForegroundDispatcher(), + new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), languageServer, razorFormattingService, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs index 8a884f9da3..e180c765f2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs @@ -15,6 +15,7 @@ using Moq; using Newtonsoft.Json.Linq; using Xunit; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; +using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions { @@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions public async Task Handle_MissingFile() { // Arrange - var resolver = new CreateComponentCodeActionResolver(new DefaultForegroundDispatcher(), _emptyDocumentResolver); + var resolver = new CreateComponentCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), _emptyDocumentResolver); var data = JObject.FromObject(new CreateComponentCodeActionParams() { Uri = new Uri("c:/Test.razor"), @@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = CreateCodeDocument(contents); codeDocument.SetUnsupported(); - var resolver = new CreateComponentCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new CreateComponentCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var data = JObject.FromObject(new CreateComponentCodeActionParams() { Uri = new Uri(documentPath), @@ -72,7 +73,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = CreateCodeDocument(contents); codeDocument.SetFileKind(FileKinds.Legacy); - var resolver = new CreateComponentCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new CreateComponentCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var data = JObject.FromObject(new CreateComponentCodeActionParams() { Uri = new Uri(documentPath), @@ -95,7 +96,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/test\""; var codeDocument = CreateCodeDocument(contents); - var resolver = new CreateComponentCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new CreateComponentCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new CreateComponentCodeActionParams { Uri = documentUri, @@ -125,7 +126,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/test\"{Environment.NewLine}@namespace Another.Namespace"; var codeDocument = CreateCodeDocument(contents); - var resolver = new CreateComponentCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); + var resolver = new CreateComponentCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new CreateComponentCodeActionParams { Uri = documentUri, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs index 03e2ae31d8..91888a1866 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions public async Task Handle_MissingFile() { // Arrange - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), _emptyDocumentResolver, FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), _emptyDocumentResolver, FilePathNormalizer); var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams() { Uri = new Uri("c:/Test.razor"), @@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = CreateCodeDocument(contents); codeDocument.SetUnsupported(); - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams() { Uri = new Uri("c:/Test.razor"), @@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var codeDocument = CreateCodeDocument(contents); codeDocument.SetFileKind(FileKinds.Legacy); - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); var data = JObject.FromObject(new ExtractToCodeBehindCodeActionParams() { Uri = new Uri("c:/Test.razor"), @@ -111,7 +111,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/test\"{Environment.NewLine}@code {{ private var x = 1; }}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); var actionParams = new ExtractToCodeBehindCodeActionParams { Uri = documentUri, @@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/test\"{Environment.NewLine}@functions {{ private var x = 1; }}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); var actionParams = new ExtractToCodeBehindCodeActionParams { Uri = documentUri, @@ -199,7 +199,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions var contents = $"@page \"/test\"\n@using System.Diagnostics{Environment.NewLine}@code {{ private var x = 1; }}"; var codeDocument = CreateCodeDocument(contents); - var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultForegroundDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); + var resolver = new ExtractToCodeBehindCodeActionResolver(new DefaultProjectSnapshotManagerDispatcher(), CreateDocumentResolver(documentPath, codeDocument), FilePathNormalizer); var actionParams = new ExtractToCodeBehindCodeActionParams { Uri = documentUri, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultHostDocumentFactoryTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultHostDocumentFactoryTest.cs index 3b5400a0c5..57b1f7000f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultHostDocumentFactoryTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DefaultHostDocumentFactoryTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer Dispatcher, Mock.Of(MockBehavior.Strict), Mock.Of(MockBehavior.Strict)); - Factory = new DefaultHostDocumentFactory(Dispatcher, store); + Factory = new DefaultHostDocumentFactory(store); } private DefaultHostDocumentFactory Factory { get; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsEndpointTest.cs index f68fdefdb4..aac3ac069d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsEndpointTest.cs @@ -868,12 +868,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics class TestRazorDiagnosticsEndpointWithRazorDiagnostic : RazorDiagnosticsEndpoint { public TestRazorDiagnosticsEndpointWithRazorDiagnostic( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, RazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : - base(foregroundDispatcher, documentResolver, documentVersionCache, documentMappingService, loggerFactory) + base(projectSnapshotManagerDispatcher, documentResolver, documentVersionCache, documentMappingService, loggerFactory) { } @@ -886,12 +886,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics class TestRazorDiagnosticsEndpointWithoutRazorDiagnostic : RazorDiagnosticsEndpoint { public TestRazorDiagnosticsEndpointWithoutRazorDiagnostic( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, DocumentResolver documentResolver, DocumentVersionCache documentVersionCache, RazorDocumentMappingService documentMappingService, ILoggerFactory loggerFactory) : - base(foregroundDispatcher, documentResolver, documentVersionCache, documentMappingService, loggerFactory) + base(projectSnapshotManagerDispatcher, documentResolver, documentVersionCache, documentMappingService, loggerFactory) { } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MonitorProjectConfigurationFilePathEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MonitorProjectConfigurationFilePathEndpointTest.cs index 79730842a6..88d5b283b5 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MonitorProjectConfigurationFilePathEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MonitorProjectConfigurationFilePathEndpointTest.cs @@ -257,12 +257,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private readonly Func _fileChangeDetectorFactory; public TestMonitorProjectConfigurationFilePathEndpoint( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, WorkspaceDirectoryPathResolver workspaceDirectoryPathResolver, IEnumerable listeners) : this( fileChangeDetectorFactory: null, - foregroundDispatcher, + projectSnapshotManagerDispatcher, filePathNormalizer, workspaceDirectoryPathResolver, listeners) @@ -271,11 +271,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public TestMonitorProjectConfigurationFilePathEndpoint( Func fileChangeDetectorFactory, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, FilePathNormalizer filePathNormalizer, WorkspaceDirectoryPathResolver workspaceDirectoryPathResolver, IEnumerable listeners) : base( - foregroundDispatcher, + projectSnapshotManagerDispatcher, filePathNormalizer, workspaceDirectoryPathResolver, listeners) diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs index bcc890b8d8..505e0419b6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/OpenDocumentGeneratorTest.cs @@ -277,7 +277,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private class TestOpenDocumentGenerator : OpenDocumentGenerator { - public TestOpenDocumentGenerator(ForegroundDispatcher foregroundDispatcher) : base(foregroundDispatcher) + public TestOpenDocumentGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(projectSnapshotManagerDispatcher) { } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationFileChangeDetectorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationFileChangeDetectorTest.cs index 37a03cefca..de2f580cad 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationFileChangeDetectorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationFileChangeDetectorTest.cs @@ -69,9 +69,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public TestProjectConfigurationFileChangeDetector( CancellationTokenSource cancellationTokenSource, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable listeners, - IReadOnlyList existingConfigurationFiles) : base(foregroundDispatcher, new FilePathNormalizer(), listeners) + IReadOnlyList existingConfigurationFiles) : base(projectSnapshotManagerDispatcher, new FilePathNormalizer(), listeners) { _cancellationTokenSource = cancellationTokenSource; _existingConfigurationFiles = existingConfigurationFiles; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationStateSynchronizerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationStateSynchronizerTest.cs index 74cf71b79a..e4b1f50dfe 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationStateSynchronizerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectConfigurationStateSynchronizerTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -19,7 +18,6 @@ using Xunit; namespace Microsoft.AspNetCore.Razor.LanguageServer { - [SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Requires execution on the foreground thread.")] public class ProjectConfigurationStateSynchronizerTest : LanguageServerTestBase { @@ -330,7 +328,8 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer if (hasTask) { var kvp = Assert.Single(synchronizer.ProjectInfoMap); - await Task.Factory.StartNew(() => kvp.Value.ProjectUpdateTask.Wait(), CancellationToken.None, TaskCreationOptions.None, Dispatcher.ForegroundScheduler); + await Dispatcher.RunOnDispatcherThreadAsync( + () => kvp.Value.ProjectUpdateTask.Wait(), CancellationToken.None); } else { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectFileChangeDetectorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectFileChangeDetectorTest.cs index 66b984a07f..1d4253f4f1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectFileChangeDetectorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/ProjectFileChangeDetectorTest.cs @@ -69,9 +69,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public TestProjectFileChangeDetector( CancellationTokenSource cancellationTokenSource, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable listeners, - IReadOnlyList existingprojectFiles) : base(foregroundDispatcher, new FilePathNormalizer(), listeners) + IReadOnlyList existingprojectFiles) : base(projectSnapshotManagerDispatcher, new FilePathNormalizer(), listeners) { _cancellationTokenSource = cancellationTokenSource; _existingProjectFiles = existingprojectFiles; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDiagnosticsPublisherTest.cs index a20fd4120a..a300b2081a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorDiagnosticsPublisherTest.cs @@ -253,9 +253,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer private class TestRazorDiagnosticsPublisher : RazorDiagnosticsPublisher, IDisposable { public TestRazorDiagnosticsPublisher( - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ITextDocumentLanguageServer languageServer, - ILoggerFactory loggerFactory) : base(foregroundDispatcher, languageServer, loggerFactory) + ILoggerFactory loggerFactory) : base(projectSnapshotManagerDispatcher, languageServer, loggerFactory) { // The diagnostics publisher by default will wait 2 seconds until publishing diagnostics. For testing purposes we redcuce // the amount of time we wait for diagnostic publishing because we have more concrete control of the timer and its lifecycle. diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorFileChangeDetectorTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorFileChangeDetectorTest.cs index ed3bbca049..16e3120963 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorFileChangeDetectorTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RazorFileChangeDetectorTest.cs @@ -155,9 +155,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer public TestRazorFileChangeDetector( CancellationTokenSource cancellationTokenSource, - ForegroundDispatcher foregroundDispatcher, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, IEnumerable listeners, - IReadOnlyList existingprojectFiles) : base(foregroundDispatcher, new FilePathNormalizer(), listeners) + IReadOnlyList existingprojectFiles) : base(projectSnapshotManagerDispatcher, new FilePathNormalizer(), listeners) { _cancellationTokenSource = cancellationTokenSource; _existingProjectFiles = existingprojectFiles; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/DefaultRazorSemanticTokenInfoServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/DefaultRazorSemanticTokenInfoServiceTest.cs index bd63e609b4..73283a333e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/DefaultRazorSemanticTokenInfoServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/DefaultRazorSemanticTokenInfoServiceTest.cs @@ -1018,7 +1018,7 @@ slf*@"; loggingFactory.Protected().Setup("CheckDisposed").CallBase(); - var foregroundDispatcher = new DefaultForegroundDispatcher(); + var projectSnapshotManagerDispatcher = new DefaultProjectSnapshotManagerDispatcher(); var documentResolver = new TestDocumentResolver(documentSnapshots); @@ -1029,7 +1029,7 @@ slf*@"; return (new DefaultRazorSemanticTokensInfoService( languageServer.Object, documentMappingService.Object, - foregroundDispatcher, + projectSnapshotManagerDispatcher, documentResolver, documentVersionCache.Object, loggingFactory.Object), languageServer); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Serialization/PlatformAgnosticClientCapabilitiesJsonConverterTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Serialization/PlatformAgnosticClientCapabilitiesJsonConverterTest.cs index 566f0d9455..9ce4f97ce4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Serialization/PlatformAgnosticClientCapabilitiesJsonConverterTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Serialization/PlatformAgnosticClientCapabilitiesJsonConverterTest.cs @@ -18,7 +18,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring.Test // Note this is a small subset of the actual ClientCapabilities provided // for use in basic validations. var rawJson = @"{ - ""supportsCodeActionResolve"": true, ""workspace"": { ""applyEdit"": true, ""workspaceEdit"": { @@ -26,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring.Test } }, ""textDocument"": { - ""_ms_onAutoInsert"": { + ""_vs_onAutoInsert"": { ""dynamicRegistration"": false }, ""synchronization"": { @@ -83,7 +82,6 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Refactoring.Test var capabilities = serializer.Deserialize(new JsonTextReader(stringReader)); // Assert - Assert.True(capabilities.SupportsCodeActionResolve); Assert.True(capabilities.Workspace.ApplyEdit); Assert.Equal(MarkupKind.PlainText, capabilities.TextDocument.Hover.Value.ContentFormat.First()); Assert.Equal(CompletionItemKind.Function, capabilities.TextDocument.Completion.Value.CompletionItemKind.ValueSet.First()); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/BackgroundDocumentProcessedPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/BackgroundDocumentProcessedPublisherTest.cs index 72766df652..5090eea9e7 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/BackgroundDocumentProcessedPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/BackgroundDocumentProcessedPublisherTest.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert Assert.Same(originalSolution, Workspace.CurrentSolution); @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert Assert.Same(originalSolution, Workspace.CurrentSolution); @@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert Assert.Same(originalSolution, Workspace.CurrentSolution); @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert var project = Assert.Single(Workspace.CurrentSolution.Projects); @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert var project = Assert.Single(Workspace.CurrentSolution.Projects); @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var processedPublisher = new BackgroundDocumentProcessedPublisher(Dispatcher, Workspace, LoggerFactory); // Act - await RunOnForegroundAsync(() => processedPublisher.DocumentProcessed(document)); + await RunOnDispatcherThreadAsync(() => processedPublisher.DocumentProcessed(document)); // Assert var afterProcessedDocument = Workspace.GetDocument(backgroundDocumentFilePath); @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var projectSnapshotManager = CreateProjectSnapshotManager(allowNotifyListeners: true); var hostProject = new OmniSharpHostProject("/path/to/unknownproject.csproj", RazorConfiguration.Default, rootNamespace: "TestRootNamespace"); var hostDocument = new OmniSharpHostDocument("/path/to/Counter.razor", "path\\to\\Counter.razor", FileKinds.Component); - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { projectSnapshotManager.ProjectAdded(hostProject); projectSnapshotManager.DocumentAdded(hostProject, hostDocument); @@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin processedPublisher.Initialize(projectSnapshotManager); // Act - await RunOnForegroundAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); + await RunOnDispatcherThreadAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); // Assert Assert.Same(originalSolution, Workspace.CurrentSolution); @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var projectSnapshotManager = CreateProjectSnapshotManager(allowNotifyListeners: true); var hostProject = new OmniSharpHostProject(Project.FilePath, RazorConfiguration.Default, rootNamespace: "TestRootNamespace"); var hostDocument = new OmniSharpHostDocument("/path/to/Counter.razor", "path\\to\\Counter.razor", FileKinds.Component); - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { projectSnapshotManager.ProjectAdded(hostProject); projectSnapshotManager.DocumentAdded(hostProject, hostDocument); @@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin processedPublisher.Initialize(projectSnapshotManager); // Act - await RunOnForegroundAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); + await RunOnDispatcherThreadAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); // Assert Assert.Same(originalSolution, Workspace.CurrentSolution); @@ -164,7 +164,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var projectSnapshotManager = CreateProjectSnapshotManager(allowNotifyListeners: true); var hostProject = new OmniSharpHostProject(Project.FilePath, RazorConfiguration.Default, rootNamespace: "TestRootNamespace"); var hostDocument = new OmniSharpHostDocument("/path/to/Counter.razor", "path\\to\\Counter.razor", FileKinds.Component); - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { projectSnapshotManager.ProjectAdded(hostProject); projectSnapshotManager.DocumentAdded(hostProject, hostDocument); @@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin processedPublisher.Initialize(projectSnapshotManager); // Act - await RunOnForegroundAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); + await RunOnDispatcherThreadAsync(() => projectSnapshotManager.DocumentRemoved(hostProject, hostDocument)); // Assert var project = Assert.Single(Workspace.CurrentSolution.Projects); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/DefaultProjectChangePublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/DefaultProjectChangePublisherTest.cs index fe2d0a5b21..587e44810e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/DefaultProjectChangePublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/DefaultProjectChangePublisherTest.cs @@ -145,10 +145,10 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var publisher = new TestProjectChangePublisher(LoggerFactory); publisher.Initialize(snapshotManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", RazorConfiguration.Default, "TestRootNamespace"); - await RunOnForegroundAsync(() => snapshotManager.ProjectAdded(hostProject)); + await RunOnDispatcherThreadAsync(() => snapshotManager.ProjectAdded(hostProject)); // Act & Assert - await RunOnForegroundAsync(() => snapshotManager.ProjectRemoved(hostProject)); + await RunOnDispatcherThreadAsync(() => snapshotManager.ProjectRemoved(hostProject)); } private class TestProjectChangePublisher : DefaultProjectChangePublisher diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/MSBuildProjectManagerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/MSBuildProjectManagerTest.cs index 4709201d0a..6c48823eaa 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/MSBuildProjectManagerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/MSBuildProjectManagerTest.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin { new OmniSharpHostDocument("file.cshtml", "file.cshtml", FileKinds.Component), }; - var projectSnapshot = await RunOnForegroundAsync(() => + var projectSnapshot = await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); var hostDocument = new OmniSharpHostDocument("file.cshtml", "file.cshtml", FileKinds.Legacy); @@ -58,14 +58,14 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin }); // Act - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => msbuildProjectManager.SynchronizeDocuments( configuredHostDocuments, projectSnapshot, hostProject)); // Assert - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { var refreshedProject = projectManager.GetLoadedProject(hostProject.FilePath); var documentFilePath = Assert.Single(refreshedProject.DocumentFilePaths); @@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin var projectManager = CreateProjectSnapshotManager(); msbuildProjectManager.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", CustomConfiguration, "TestRootNamespace"); - var projectSnapshot = await RunOnForegroundAsync(() => + var projectSnapshot = await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); var hostDocument = new OmniSharpHostDocument("file.razor", "file.razor", FileKinds.Component); @@ -98,14 +98,14 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin }); // Act - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => msbuildProjectManager.SynchronizeDocuments( configuredHostDocuments: Array.Empty(), projectSnapshot, hostProject)); // Assert - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { var refreshedProject = projectManager.GetLoadedProject(hostProject.FilePath); Assert.Empty(refreshedProject.DocumentFilePaths); @@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin var projectManager = CreateProjectSnapshotManager(allowNotifyListeners: true); msbuildProjectManager.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", CustomConfiguration, "TestRootNamespace"); - var projectSnapshot = await RunOnForegroundAsync(() => + var projectSnapshot = await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); projectManager.DocumentAdded(hostProject, hostDocument); @@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin projectManager.Changed += (sender, args) => throw new XunitException("Should not have been notified"); // Act & Assert - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => msbuildProjectManager.SynchronizeDocuments( configuredHostDocuments, projectSnapshot, @@ -159,21 +159,21 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin var projectManager = CreateProjectSnapshotManager(); msbuildProjectManager.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", CustomConfiguration, "TestRootNamespace"); - var projectSnapshot = await RunOnForegroundAsync(() => + var projectSnapshot = await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); return projectManager.GetLoadedProject(hostProject.FilePath); }); // Act - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => msbuildProjectManager.SynchronizeDocuments( configuredHostDocuments, projectSnapshot, hostProject)); // Assert - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { var refreshedProject = projectManager.GetLoadedProject(hostProject.FilePath); var document = refreshedProject.GetDocument("file.razor"); @@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin await msbuildProjectManager.ProjectLoadedAsync(args); // Assert - var project = await RunOnForegroundAsync(() => Assert.Single(projectManager.Projects)); + var project = await RunOnDispatcherThreadAsync(() => Assert.Single(projectManager.Projects)); Assert.Equal(projectInstance.ProjectFileLocation.File, project.FilePath); Assert.Same(CustomConfiguration, project.Configuration); var document = project.GetDocument(hostDocument.FilePath); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/OmniSharpTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/OmniSharpTestBase.cs index 77c8b90c1a..fd07e14192 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/OmniSharpTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/OmniSharpTestBase.cs @@ -39,14 +39,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin _createWithDocumentsTestProjectSnapshotMethod = testProjectSnapshotType.GetMethod("Create", new[] { typeof(string), typeof(string[]), typeof(ProjectWorkspaceState) }); _createProjectSnapshotManagerMethod = testProjectSnapshotManagerType.GetMethod("Create"); _allowNotifyListenersProperty = testProjectSnapshotManagerType.GetProperty("AllowNotifyListeners"); - _dispatcherProperty = typeof(OmniSharpForegroundDispatcher).GetProperty("InternalDispatcher", BindingFlags.NonPublic | BindingFlags.Instance); + _dispatcherProperty = typeof(OmniSharpProjectSnapshotManagerDispatcher).GetProperty("InternalDispatcher", BindingFlags.NonPublic | BindingFlags.Instance); _omniSharpProjectSnapshotMangerConstructor = defaultSnapshotManagerType.GetConstructors().Single(); _omniSharpSnapshotConstructor = typeof(OmniSharpProjectSnapshot).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single(); - Dispatcher = new DefaultOmniSharpForegroundDispatcher(); + Dispatcher = new DefaultOmniSharpProjectSnapshotManagerDispatcher(); } - protected OmniSharpForegroundDispatcher Dispatcher { get; } + protected OmniSharpProjectSnapshotManagerDispatcher Dispatcher { get; } protected OmniSharpProjectSnapshot CreateProjectSnapshot(string projectFilePath) { @@ -77,31 +77,31 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin return snapshotManager; } - protected Task RunOnForegroundAsync(Action action) + protected Task RunOnDispatcherThreadAsync(Action action) { return Task.Factory.StartNew( () => action(), CancellationToken.None, TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + Dispatcher.DispatcherScheduler); } - protected Task RunOnForegroundAsync(Func action) + protected Task RunOnDispatcherThreadAsync(Func action) { return Task.Factory.StartNew( () => action(), CancellationToken.None, TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + Dispatcher.DispatcherScheduler); } - protected Task RunOnForegroundAsync(Func action) + protected Task RunOnDispatcherThreadAsync(Func action) { return Task.Factory.StartNew( async () => await action(), CancellationToken.None, TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + Dispatcher.DispatcherScheduler); } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/TagHelperRefreshTriggerTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/TagHelperRefreshTriggerTest.cs index ebb9f70c15..585e0ef0fc 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/TagHelperRefreshTriggerTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test/TagHelperRefreshTriggerTest.cs @@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin refreshTrigger.Initialize(projectManager); // Act - var result = await RunOnForegroundAsync(() => refreshTrigger.IsComponentFile("file.razor", "/path/to/project.csproj")); + var result = await RunOnDispatcherThreadAsync(() => refreshTrigger.IsComponentFile("file.razor", "/path/to/project.csproj")); // Assert Assert.False(result); @@ -87,10 +87,10 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var refreshTrigger = CreateRefreshTrigger(); refreshTrigger.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", RazorConfiguration.Default, "TestRootNamespace"); - await RunOnForegroundAsync(() => projectManager.ProjectAdded(hostProject)); + await RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(hostProject)); // Act - var result = await RunOnForegroundAsync(() => refreshTrigger.IsComponentFile("file.razor", hostProject.FilePath)); + var result = await RunOnDispatcherThreadAsync(() => refreshTrigger.IsComponentFile("file.razor", hostProject.FilePath)); // Assert Assert.False(result); @@ -105,14 +105,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin refreshTrigger.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", RazorConfiguration.Default, "TestRootNamespace"); var hostDocument = new OmniSharpHostDocument("file.cshtml", "file.cshtml", FileKinds.Legacy); - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); projectManager.DocumentAdded(hostProject, hostDocument); }); // Act - var result = await RunOnForegroundAsync(() => refreshTrigger.IsComponentFile(hostDocument.FilePath, hostProject.FilePath)); + var result = await RunOnDispatcherThreadAsync(() => refreshTrigger.IsComponentFile(hostDocument.FilePath, hostProject.FilePath)); // Assert Assert.False(result); @@ -127,14 +127,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin refreshTrigger.Initialize(projectManager); var hostProject = new OmniSharpHostProject("/path/to/project.csproj", RazorConfiguration.Default, "TestRootNamespace"); var hostDocument = new OmniSharpHostDocument("file.cshtml", "file.cshtml", FileKinds.Component); - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { projectManager.ProjectAdded(hostProject); projectManager.DocumentAdded(hostProject, hostDocument); }); // Act - var result = await RunOnForegroundAsync(() => refreshTrigger.IsComponentFile(hostDocument.FilePath, hostProject.FilePath)); + var result = await RunOnDispatcherThreadAsync(() => refreshTrigger.IsComponentFile(hostDocument.FilePath, hostProject.FilePath)); // Assert Assert.True(result); @@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public async Task ProjectLoaded_TriggersUpdate() { // Arrange - await RunOnForegroundAsync(() => ProjectManager.ProjectAdded(Project1)); + await RunOnDispatcherThreadAsync(() => ProjectManager.ProjectAdded(Project1)); using var mre = new ManualResetEventSlim(initialState: false); var workspaceStateGenerator = new Mock(MockBehavior.Strict); workspaceStateGenerator.Setup(generator => generator.Update(It.IsAny(), It.IsAny())) @@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public async Task ProjectLoaded_BatchesUpdates() { // Arrange - await RunOnForegroundAsync(() => ProjectManager.ProjectAdded(Project1)); + await RunOnDispatcherThreadAsync(() => ProjectManager.ProjectAdded(Project1)); using var mre = new ManualResetEventSlim(initialState: false); var workspaceStateGenerator = new Mock(MockBehavior.Strict); workspaceStateGenerator.Setup(generator => generator.Update(It.IsAny(), It.IsAny())) @@ -213,7 +213,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public async Task RazorDocumentOutputChanged_TriggersUpdate() { // Arrange - await RunOnForegroundAsync(() => ProjectManager.ProjectAdded(Project1)); + await RunOnDispatcherThreadAsync(() => ProjectManager.ProjectAdded(Project1)); using var mre = new ManualResetEventSlim(initialState: false); var workspaceStateGenerator = new Mock(MockBehavior.Strict); workspaceStateGenerator.Setup(generator => generator.Update(It.IsAny(), It.IsAny())) @@ -233,7 +233,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin public async Task RazorDocumentOutputChanged_BatchesUpdates() { // Arrange - await RunOnForegroundAsync(() => ProjectManager.ProjectAdded(Project1)); + await RunOnDispatcherThreadAsync(() => ProjectManager.ProjectAdded(Project1)); using var mre = new ManualResetEventSlim(initialState: false); var workspaceStateGenerator = new Mock(MockBehavior.Strict); workspaceStateGenerator.Setup(generator => generator.Update(It.IsAny(), It.IsAny())) @@ -266,14 +266,14 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin // Arrange using var workspace = TestWorkspace.Create(); var projectManager = CreateProjectSnapshotManager(); - await RunOnForegroundAsync(() => ProjectManager.ProjectAdded(Project1)); + await RunOnDispatcherThreadAsync(() => ProjectManager.ProjectAdded(Project1)); var workspaceStateGenerator = new Mock(MockBehavior.Strict); workspaceStateGenerator.Setup(generator => generator.Update(It.IsAny(), It.IsAny())) .Throws(); var refreshTrigger = CreateRefreshTrigger(workspaceStateGenerator.Object, workspace); // Act & Assert - await RunOnForegroundAsync(() => refreshTrigger.UpdateAfterDelayAsync(Project1.FilePath)); + await RunOnDispatcherThreadAsync(() => refreshTrigger.UpdateAfterDelayAsync(Project1.FilePath)); } [Fact] @@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin var refreshTrigger = CreateRefreshTrigger(workspaceStateGenerator.Object); // Act & Assert - await RunOnForegroundAsync(() => refreshTrigger.UpdateAfterDelayAsync(((ProjectInstance)Project1Instance).ProjectFileLocation.File)); + await RunOnDispatcherThreadAsync(() => refreshTrigger.UpdateAfterDelayAsync(((ProjectInstance)Project1Instance).ProjectFileLocation.File)); } private TagHelperRefreshTrigger CreateRefreshTrigger(OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator = null, Workspace workspace = null, int enqueueDelay = 1) diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Shared/TestProjectSnapshotManager.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Shared/TestProjectSnapshotManager.cs index a0e0ffef3b..b781f129f3 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Shared/TestProjectSnapshotManager.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Shared/TestProjectSnapshotManager.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; +using System.Threading.Tasks; using Moq; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem @@ -9,21 +10,23 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem internal class TestProjectSnapshotManager : DefaultProjectSnapshotManager { public TestProjectSnapshotManager(Workspace workspace) - : base(CreateForegroundDispatcher(), Mock.Of(MockBehavior.Strict), Enumerable.Empty(), workspace) + : base(CreateProjectSnapshotManagerDispatcher(), Mock.Of(MockBehavior.Strict), Enumerable.Empty(), workspace) { } - public TestProjectSnapshotManager(ForegroundDispatcher foregroundDispatcher, Workspace workspace) - : base(foregroundDispatcher, Mock.Of(MockBehavior.Strict), Enumerable.Empty(), workspace) + public TestProjectSnapshotManager(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, Workspace workspace) + : base(projectSnapshotManagerDispatcher, Mock.Of(MockBehavior.Strict), Enumerable.Empty(), workspace) { } public bool AllowNotifyListeners { get; set; } - private static ForegroundDispatcher CreateForegroundDispatcher() + private static ProjectSnapshotManagerDispatcher CreateProjectSnapshotManagerDispatcher() { - var dispatcher = new Mock(MockBehavior.Strict); - dispatcher.Setup(d => d.AssertForegroundThread(It.IsAny())).Verifiable(); + var dispatcher = new Mock(MockBehavior.Strict); + dispatcher.Setup(d => d.AssertDispatcherThread(It.IsAny())).Verifiable(); + dispatcher.Setup(d => d.IsDispatcherThread).Returns(true); + dispatcher.Setup(d => d.DispatcherScheduler).Returns(TaskScheduler.FromCurrentSynchronizationContext()); return dispatcher.Object; } diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/OOPTagHelperResolverTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/OOPTagHelperResolverTest.cs index 172b51cb9e..5f1b33a39d 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/OOPTagHelperResolverTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Remote.Razor.Test/OOPTagHelperResolverTest.cs @@ -169,17 +169,19 @@ namespace Microsoft.CodeAnalysis.Remote.Razor { public TestProjectSnapshotManager(Workspace workspace) : base( - CreateForegroundDispatcher(), + CreateProjectSnapshotManagerDispatcher(), Mock.Of(MockBehavior.Strict), Enumerable.Empty(), workspace) { } - private static ForegroundDispatcher CreateForegroundDispatcher() + private static ProjectSnapshotManagerDispatcher CreateProjectSnapshotManagerDispatcher() { - var dispatcher = new Mock(MockBehavior.Strict); - dispatcher.Setup(d => d.AssertForegroundThread(It.IsAny())).Verifiable(); + var dispatcher = new Mock(MockBehavior.Strict); + dispatcher.Setup(d => d.AssertDispatcherThread(It.IsAny())).Verifiable(); + dispatcher.Setup(d => d.IsDispatcherThread).Returns(true); + dispatcher.Setup(d => d.DispatcherScheduler).Returns(TaskScheduler.FromCurrentSynchronizationContext()); return dispatcher.Object; } } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/SingleThreadedForegroundDispatcher.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/TestProjectSnapshotManagerDispatcher.cs similarity index 63% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/SingleThreadedForegroundDispatcher.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/TestProjectSnapshotManagerDispatcher.cs index 7c76826397..b45ecba643 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/SingleThreadedForegroundDispatcher.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/TestProjectSnapshotManagerDispatcher.cs @@ -10,21 +10,20 @@ using Xunit; namespace Microsoft.CodeAnalysis.Razor { - internal class SingleThreadedForegroundDispatcher : ForegroundDispatcher + internal class TestProjectSnapshotManagerDispatcher : ProjectSnapshotManagerDispatcher { - public SingleThreadedForegroundDispatcher() + public TestProjectSnapshotManagerDispatcher() { - ForegroundScheduler = SynchronizationContext.Current == null ? new ThrowingTaskScheduler() : TaskScheduler.FromCurrentSynchronizationContext(); - BackgroundScheduler = TaskScheduler.Default; + DispatcherScheduler = SynchronizationContext.Current == null + ? new ThrowingTaskScheduler() + : TaskScheduler.FromCurrentSynchronizationContext(); } - public override TaskScheduler ForegroundScheduler { get; } - - public override TaskScheduler BackgroundScheduler { get; } + public override TaskScheduler DispatcherScheduler { get; } private Thread Thread { get; } = Thread.CurrentThread; - public override bool IsForegroundThread => Thread.CurrentThread == Thread; + public override bool IsDispatcherThread => Thread.CurrentThread == Thread; private class ThrowingTaskScheduler : TaskScheduler { @@ -35,12 +34,12 @@ namespace Microsoft.CodeAnalysis.Razor protected override void QueueTask(Task task) { - throw new InvalidOperationException($"Use [{nameof(ForegroundFactAttribute)}]"); + throw new InvalidOperationException($"Use [{nameof(UIFactAttribute)}]"); } protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { - throw new InvalidOperationException($"Use [{nameof(ForegroundFactAttribute)}]"); + throw new InvalidOperationException($"Use [{nameof(UIFactAttribute)}]"); } } } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundDispatcherTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundDispatcherTestBase.cs deleted file mode 100644 index 5d291ca371..0000000000 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundDispatcherTestBase.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Razor.Language.Legacy; -using Microsoft.CodeAnalysis.Razor; - -namespace Xunit -{ - public abstract class ForegroundDispatcherTestBase : ParserTestBase - { - internal ForegroundDispatcher Dispatcher { get; } = new SingleThreadedForegroundDispatcher(); - } -} diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ProjectSnapshotManagerDispatcherTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ProjectSnapshotManagerDispatcherTestBase.cs new file mode 100644 index 0000000000..9c0d867ff3 --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ProjectSnapshotManagerDispatcherTestBase.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor.Language.Legacy; +using Microsoft.CodeAnalysis.Razor; +using Microsoft.VisualStudio.Threading; + +namespace Xunit +{ + public abstract class ProjectSnapshotManagerDispatcherTestBase : ParserTestBase + { + internal ProjectSnapshotManagerDispatcher Dispatcher { get; } = new TestProjectSnapshotManagerDispatcher(); + + internal static JoinableTaskFactory JoinableTaskFactory + { + get + { + var joinableTaskContext = new JoinableTaskContextNode(new JoinableTaskContext()); + return new JoinableTaskFactory(joinableTaskContext.Context); + } + } + } +} diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactAttribute.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactAttribute.cs similarity index 71% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactAttribute.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactAttribute.cs index 49a23f5c89..b1c867c4f7 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactAttribute.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactAttribute.cs @@ -8,8 +8,8 @@ namespace Xunit { // Similar to WpfFactAttribute https://github.com/xunit/samples.xunit/blob/969d9f7e887836f01a6c525324bf3db55658c28f/STAExamples/WpfFactAttribute.cs [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - [XunitTestCaseDiscoverer("Xunit." + nameof(ForegroundFactDiscoverer), "Microsoft.VisualStudio.Editor.Razor.Test.Common")] - public class ForegroundFactAttribute : FactAttribute + [XunitTestCaseDiscoverer("Xunit." + nameof(UIFactDiscoverer), "Microsoft.VisualStudio.Editor.Razor.Test.Common")] + public class UIFactAttribute : FactAttribute { } } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactDiscoverer.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactDiscoverer.cs similarity index 61% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactDiscoverer.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactDiscoverer.cs index 4660b800c3..46c6c78a82 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundFactDiscoverer.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UIFactDiscoverer.cs @@ -6,16 +6,16 @@ using Xunit.Sdk; namespace Xunit { - internal class ForegroundFactDiscoverer : FactDiscoverer + internal class UIFactDiscoverer : FactDiscoverer { - public ForegroundFactDiscoverer(IMessageSink diagnosticMessageSink) + public UIFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { } protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) { - return new ForegroundTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); + return new UITestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); } } } \ No newline at end of file diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTestCase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITestCase.cs similarity index 89% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTestCase.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITestCase.cs index 52caece123..1e046e2071 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTestCase.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITestCase.cs @@ -11,15 +11,15 @@ using Xunit.Sdk; namespace Xunit { - internal class ForegroundTestCase : XunitTestCase + internal class UITestCase : XunitTestCase { [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Called by the de-serializer", error: true)] - public ForegroundTestCase() + public UITestCase() { } - public ForegroundTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) + public UITestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryAttribute.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryAttribute.cs similarity index 70% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryAttribute.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryAttribute.cs index 7a80ba7f41..7192345dd3 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryAttribute.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryAttribute.cs @@ -8,8 +8,8 @@ namespace Xunit { // Similar to WpfTheoryAttribute https://github.com/xunit/samples.xunit/blob/969d9f7e887836f01a6c525324bf3db55658c28f/STAExamples/WpfTheoryAttribute.cs [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - [XunitTestCaseDiscoverer("Xunit." + nameof(ForegroundTheoryDiscoverer), "Microsoft.VisualStudio.Editor.Razor.Test.Common")] - internal class ForegroundTheoryAttribute : TheoryAttribute + [XunitTestCaseDiscoverer("Xunit." + nameof(UITheoryDiscoverer), "Microsoft.VisualStudio.Editor.Razor.Test.Common")] + internal class UITheoryAttribute : TheoryAttribute { } } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryDiscoverer.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryDiscoverer.cs similarity index 65% rename from src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryDiscoverer.cs rename to src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryDiscoverer.cs index f0753d31af..56f761e64f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/ForegroundTheoryDiscoverer.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test.Common/Xunit/UITheoryDiscoverer.cs @@ -7,9 +7,9 @@ using Xunit.Sdk; namespace Xunit { - internal class ForegroundTheoryDiscoverer : TheoryDiscoverer + internal class UITheoryDiscoverer : TheoryDiscoverer { - public ForegroundTheoryDiscoverer(IMessageSink diagnosticMessageSink) + public UITheoryDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { } @@ -18,8 +18,8 @@ namespace Xunit { return new[] { - new ForegroundTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, dataRow), + new UITestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, dataRow), }; } } -} \ No newline at end of file +} diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterIntegrationTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterIntegrationTest.cs index 95f1f8f3fe..c8f5c526b7 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterIntegrationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterIntegrationTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.VisualStudio.Editor.Razor { public class BraceSmartIndenterIntegrationTest : BraceSmartIndenterTestBase { - [ForegroundFact] + [UIFact] public void TextBuffer_OnPostChanged_IndentsInbetweenBraces_BaseIndentation() { // Arrange @@ -30,7 +30,7 @@ namespace Microsoft.VisualStudio.Editor.Razor textBuffer = CreateTextBuffer(initialSnapshot, documentTracker); var codeDocumentProvider = CreateCodeDocumentProvider(initialSnapshot.Content); var editorOperationsFactory = CreateOperationsFactoryService(); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory); // Act textBuffer.ApplyEdit(edit); @@ -39,7 +39,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(expectedIndentResult, ((StringTextSnapshot)textBuffer.CurrentSnapshot).Content); } - [ForegroundFact] + [UIFact] public void TextBuffer_OnPostChanged_IndentsInbetweenBraces_OneLevelOfIndentation() { // Arrange @@ -56,7 +56,7 @@ namespace Microsoft.VisualStudio.Editor.Razor textBuffer = CreateTextBuffer(initialSnapshot, documentTracker); var codeDocumentProvider = CreateCodeDocumentProvider(initialSnapshot.Content); var editorOperationsFactory = CreateOperationsFactoryService(); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory); // Act textBuffer.ApplyEdit(edit); @@ -65,7 +65,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(expectedIndentResult, ((StringTextSnapshot)textBuffer.CurrentSnapshot).Content); } - [ForegroundFact] + [UIFact] public void TextBuffer_OnPostChanged_IndentsInbetweenDirectiveBlockBraces() { // Arrange @@ -82,7 +82,7 @@ namespace Microsoft.VisualStudio.Editor.Razor textBuffer = CreateTextBuffer(initialSnapshot, documentTracker); var codeDocumentProvider = CreateCodeDocumentProvider(initialSnapshot.Content); var editorOperationsFactory = CreateOperationsFactoryService(); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory); // Act textBuffer.ApplyEdit(edit); @@ -91,7 +91,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(expectedIndentResult, ((StringTextSnapshot)textBuffer.CurrentSnapshot).Content); } - [ForegroundFact] + [UIFact] public void TextBuffer_OnPostChanged_DoesNotIndentJavaScript() { // Arrange @@ -107,7 +107,7 @@ namespace Microsoft.VisualStudio.Editor.Razor textBuffer = CreateTextBuffer(initialSnapshot, documentTracker); var codeDocumentProvider = CreateCodeDocumentProvider(initialSnapshot.Content); var editorOperationsFactory = CreateOperationsFactoryService(); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory); // Act textBuffer.ApplyEdit(edit); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTest.cs index 64710edd2b..86f9dba229 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTest.cs @@ -313,7 +313,7 @@ namespace Microsoft.VisualStudio.Editor.Razor editorOperationsFactory.Setup(factory => factory.GetEditorOperations(textView)) .Returns(editorOperations.Object); var codeDocumentProvider = Mock.Of(MockBehavior.Strict); - using var smartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); + using var smartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); // Act smartIndenter.TriggerSmartIndent(textView); @@ -378,7 +378,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(BraceSmartIndenter.BeforeClosingBrace(0, line)); } - [ForegroundFact] + [UIFact] public void TextBuffer_OnChanged_NoopsIfNoChanges() { // Arrange @@ -387,13 +387,13 @@ namespace Microsoft.VisualStudio.Editor.Razor var textContentChangeArgs = new TestTextContentChangedEventArgs(changeCollection); var documentTracker = CreateDocumentTracker(() => Mock.Of(MockBehavior.Strict), Mock.Of(MockBehavior.Strict)); var codeDocumentProvider = Mock.Of(MockBehavior.Strict); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); // Act & Assert braceSmartIndenter.TextBuffer_OnChanged(null, textContentChangeArgs); } - [ForegroundFact] + [UIFact] public void TextBuffer_OnChanged_NoopsIfChangesThatResultInNoChange() { // Arrange @@ -403,7 +403,7 @@ namespace Microsoft.VisualStudio.Editor.Razor var editorOperationsFactory = new Mock(MockBehavior.Strict); var documentTracker = CreateDocumentTracker(() => textBuffer, Mock.Of(MockBehavior.Strict)); var codeDocumentProvider = Mock.Of(MockBehavior.Strict); - using var braceSmartIndenter = new BraceSmartIndenter(Dispatcher, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); + using var braceSmartIndenter = new BraceSmartIndenter(JoinableTaskFactory.Context, documentTracker, codeDocumentProvider, editorOperationsFactory.Object); // Act & Assert textBuffer.ApplyEdits(edit, edit); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTestBase.cs index 833b9fead0..7f963c1b01 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTestBase.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/BraceSmartIndenterTestBase.cs @@ -11,7 +11,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class BraceSmartIndenterTestBase : ForegroundDispatcherTestBase + public class BraceSmartIndenterTestBase : ProjectSnapshotManagerDispatcherTestBase { protected static VisualStudioDocumentTracker CreateDocumentTracker(Func bufferAccessor, ITextView focusedTextView) { diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveAttributeCompletionSourceTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveAttributeCompletionSourceTest.cs index 2a96c22718..02a46c335a 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveAttributeCompletionSourceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveAttributeCompletionSourceTest.cs @@ -16,7 +16,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Completion { - public class RazorDirectiveAttributeCompletionSourceTest : ForegroundDispatcherTestBase + public class RazorDirectiveAttributeCompletionSourceTest : ProjectSnapshotManagerDispatcherTestBase { [Fact] public async Task GetDescriptionAsync_NoDescriptionData_ReturnsEmptyString() diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceProviderTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceProviderTest.cs index 764a78fd74..3d780f534f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceProviderTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceProviderTest.cs @@ -14,7 +14,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Completion { - public class RazorDirectiveCompletionSourceProviderTest : ForegroundDispatcherTestBase + public class RazorDirectiveCompletionSourceProviderTest : ProjectSnapshotManagerDispatcherTestBase { private IContentType RazorContentType { get; } = Mock.Of(c => c.IsOfType(RazorLanguage.ContentType) && c.IsOfType(RazorConstants.LegacyContentType), MockBehavior.Strict); @@ -30,7 +30,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion var properties = new PropertyCollection(); properties.AddProperty(typeof(VisualStudioRazorParser), expectedParser); var razorBuffer = Mock.Of(buffer => buffer.ContentType == RazorContentType && buffer.Properties == properties, MockBehavior.Strict); - var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(Dispatcher, CompletionFactsService); + var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(CompletionFactsService); // Act var completionSource = completionSourceProvider.CreateCompletionSource(razorBuffer); @@ -45,7 +45,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion { // Arrange var razorBuffer = Mock.Of(buffer => buffer.ContentType == RazorContentType && buffer.Properties == new PropertyCollection(), MockBehavior.Strict); - var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(Dispatcher, CompletionFactsService); + var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(CompletionFactsService); // Act var completionSource = completionSourceProvider.CreateCompletionSource(razorBuffer); @@ -59,7 +59,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion { // Arrange var textView = CreateTextView(NonRazorContentType, new PropertyCollection()); - var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(Dispatcher, CompletionFactsService); + var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(CompletionFactsService); // Act var completionSource = completionSourceProvider.GetOrCreate(textView); @@ -76,7 +76,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion var properties = new PropertyCollection(); properties.AddProperty(typeof(VisualStudioRazorParser), expectedParser); var textView = CreateTextView(RazorContentType, properties); - var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(Dispatcher, CompletionFactsService); + var completionSourceProvider = new RazorDirectiveCompletionSourceProvider(CompletionFactsService); // Act var completionSource1 = completionSourceProvider.GetOrCreate(textView); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs index c3e891fc79..309c20bb60 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Completion/RazorDirectiveCompletionSourceTest.cs @@ -18,7 +18,7 @@ using Span = Microsoft.VisualStudio.Text.Span; namespace Microsoft.VisualStudio.Editor.Razor.Completion { - public class RazorDirectiveCompletionSourceTest : ForegroundDispatcherTestBase + public class RazorDirectiveCompletionSourceTest : ProjectSnapshotManagerDispatcherTestBase { private static readonly IReadOnlyList s_defaultDirectives = new[] { @@ -29,7 +29,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion private RazorCompletionFactsService CompletionFactsService { get; } = new DefaultRazorCompletionFactsService(new[] { new DirectiveCompletionItemProvider() }); - [ForegroundFact] + [UIFact] public async Task GetCompletionContextAsync_DoesNotProvideCompletionsPriorToParseResults() { // Arrange @@ -37,7 +37,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion var parser = new Mock(MockBehavior.Strict); parser.Setup(p => p.GetLatestCodeDocumentAsync(It.IsAny(), It.IsAny())) .Returns(Task.FromResult(null)); // CodeDocument will be null faking a parser without a parse. - var completionSource = new RazorDirectiveCompletionSource(Dispatcher, parser.Object, CompletionFactsService); + var completionSource = new RazorDirectiveCompletionSource(parser.Object, CompletionFactsService); var documentSnapshot = new StringTextSnapshot(text); var triggerLocation = new SnapshotPoint(documentSnapshot, 4); var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(1, text.Length - 1 /* validCompletion */)); @@ -50,13 +50,13 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion Assert.Empty(completionContext.Items); } - [ForegroundFact] + [UIFact] public async Task GetCompletionContextAsync_DoesNotProvideCompletionsWhenNotAtCompletionPoint() { // Arrange var text = "@(NotValidCompletionLocation)"; var parser = CreateParser(text); - var completionSource = new RazorDirectiveCompletionSource(Dispatcher, parser, CompletionFactsService); + var completionSource = new RazorDirectiveCompletionSource(parser, CompletionFactsService); var documentSnapshot = new StringTextSnapshot(text); var triggerLocation = new SnapshotPoint(documentSnapshot, 4); var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(2, text.Length - 3 /* @() */)); @@ -70,13 +70,13 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion } // This is more of an integration level test validating the end-to-end completion flow. - [ForegroundFact] + [UIFact] public async Task GetCompletionContextAsync_ProvidesCompletionsWhenAtCompletionPoint() { // Arrange var text = "@"; var parser = CreateParser(text, SectionDirective.Directive); - var completionSource = new RazorDirectiveCompletionSource(Dispatcher, parser, CompletionFactsService); + var completionSource = new RazorDirectiveCompletionSource(parser, CompletionFactsService); var documentSnapshot = new StringTextSnapshot(text); var triggerLocation = new SnapshotPoint(documentSnapshot, 1); var applicableSpan = new SnapshotSpan(documentSnapshot, new Span(1, 0)); @@ -101,7 +101,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion var completionItem = new CompletionItem("TestDirective", Mock.Of(MockBehavior.Strict)); var expectedDescription = new DirectiveCompletionDescription("The expected description"); completionItem.Properties.AddProperty(RazorDirectiveCompletionSource.DescriptionKey, expectedDescription); - var completionSource = new RazorDirectiveCompletionSource(Dispatcher, Mock.Of(MockBehavior.Strict), CompletionFactsService); + var completionSource = new RazorDirectiveCompletionSource(Mock.Of(MockBehavior.Strict), CompletionFactsService); // Act var descriptionObject = await completionSource.GetDescriptionAsync(null, completionItem, CancellationToken.None); @@ -116,7 +116,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Completion { // Arrange var completionItem = new CompletionItem("TestDirective", Mock.Of(MockBehavior.Strict)); - var completionSource = new RazorDirectiveCompletionSource(Dispatcher, Mock.Of(MockBehavior.Strict), CompletionFactsService); + var completionSource = new RazorDirectiveCompletionSource(Mock.Of(MockBehavior.Strict), CompletionFactsService); // Act var descriptionObject = await completionSource.GetDescriptionAsync(null, completionItem, CancellationToken.None); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultEditorSettingsManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultEditorSettingsManagerTest.cs index 37a3e934dd..a8376504bc 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultEditorSettingsManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultEditorSettingsManagerTest.cs @@ -6,7 +6,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultEditorSettingsManagerTest : ForegroundDispatcherTestBase + public class DefaultEditorSettingsManagerTest : ProjectSnapshotManagerDispatcherTestBase { [Fact] public void InitialSettingsAreDefault() diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerIntegrationTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerIntegrationTest.cs index 233644c717..cd4bbaf57f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerIntegrationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerIntegrationTest.cs @@ -10,7 +10,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Documents { - public class DefaultImportDocumentManagerIntegrationTest : ForegroundDispatcherTestBase + public class DefaultImportDocumentManagerIntegrationTest : ProjectSnapshotManagerDispatcherTestBase { public DefaultImportDocumentManagerIntegrationTest() { @@ -31,7 +31,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private RazorProjectEngine ProjectEngine { get; } - [ForegroundFact] + [UIFact] public void Changed_TrackerChanged_ResultsInChangedHavingCorrectArgs() { // Arrange diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerTest.cs index f277ac39de..861335fac6 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultImportDocumentManagerTest.cs @@ -12,7 +12,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultImportDocumentManagerTest : ForegroundDispatcherTestBase + public class DefaultImportDocumentManagerTest : ProjectSnapshotManagerDispatcherTestBase { public DefaultImportDocumentManagerTest() { @@ -33,7 +33,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private RazorProjectEngine ProjectEngine { get; } - [ForegroundFact] + [UIFact] public void OnSubscribed_StartsFileChangeTrackers() { // Arrange @@ -78,7 +78,7 @@ namespace Microsoft.VisualStudio.Editor.Razor fileChangeTracker3.Verify(); } - [ForegroundFact] + [UIFact] public void OnSubscribed_AlreadySubscribed_DoesNothing() { // Arrange @@ -111,7 +111,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(1, callCount); } - [ForegroundFact] + [UIFact] public void OnUnsubscribed_StopsFileChangeTracker() { // Arrange @@ -142,7 +142,7 @@ namespace Microsoft.VisualStudio.Editor.Razor fileChangeTracker.Verify(); } - [ForegroundFact] + [UIFact] public void OnUnsubscribed_AnotherDocumentTrackingImport_DoesNotStopFileChangeTracker() { // Arrange diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectSnapshotProjectEngineFactoryTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectSnapshotProjectEngineFactoryTest.cs index 85cb2b2bda..00bc796f89 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectSnapshotProjectEngineFactoryTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectSnapshotProjectEngineFactoryTest.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.VisualStudio.Editor.Razor; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Xunit; using Mvc1_X = Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X; diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectWorkspaceStateGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectWorkspaceStateGeneratorTest.cs index ccff8999e3..51b9588faf 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectWorkspaceStateGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectWorkspaceStateGeneratorTest.cs @@ -13,7 +13,7 @@ using Xunit; namespace Microsoft.CodeAnalysis.Razor.Workspaces { - public class DefaultProjectWorkspaceStateGeneratorTest : ForegroundDispatcherTestBase + public class DefaultProjectWorkspaceStateGeneratorTest : ProjectSnapshotManagerDispatcherTestBase { public DefaultProjectWorkspaceStateGeneratorTest() { @@ -49,7 +49,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces private ProjectWorkspaceState ProjectWorkspaceStateWithTagHelpers { get; } - [ForegroundFact] + [UIFact] public void Dispose_MakesUpdateNoop() { // Arrange @@ -66,7 +66,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces } } - [ForegroundFact] + [UIFact] public void Update_StartsUpdateTask() { // Arrange @@ -83,7 +83,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces } } - [ForegroundFact] + [UIFact] public void Update_SoftCancelsIncompleteTaskForSameProject() { // Arrange @@ -101,7 +101,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces } } - [ForegroundFact] + [UIFact] public async Task Update_NullWorkspaceProject_ClearsProjectWorkspaceState() { // Arrange @@ -116,7 +116,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces // Act stateGenerator.Update(workspaceProject: null, ProjectSnapshot, CancellationToken.None); - // Jump off the foreground thread so the background work can complete. + // Jump off the UI thread so the background work can complete. await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); // Assert @@ -125,7 +125,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces } } - [ForegroundFact] + [UIFact] public async Task Update_ResolvesTagHelpersAndUpdatesWorkspaceState() { // Arrange @@ -139,7 +139,7 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces // Act stateGenerator.Update(WorkspaceProject, ProjectSnapshot, CancellationToken.None); - // Jump off the foreground thread so the background work can complete. + // Jump off the UI thread so the background work can complete. await Task.Run(() => stateGenerator.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3))); // Assert diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultRazorDocumentManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultRazorDocumentManagerTest.cs index 8b728feb02..3e4278f8da 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultRazorDocumentManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultRazorDocumentManagerTest.cs @@ -3,20 +3,24 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Editor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; using Moq; using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultRazorDocumentManagerTest : ForegroundDispatcherTestBase + public class DefaultRazorDocumentManagerTest : ProjectSnapshotManagerDispatcherTestBase { + private JoinableTaskContext JoinableTaskContext => JoinableTaskFactory.Context; + private IContentType RazorCoreContentType { get; } = Mock.Of(c => c.IsOfType(RazorLanguage.CoreContentType) == true, MockBehavior.Strict); private IContentType NonRazorCoreContentType { get; } = Mock.Of(c => c.IsOfType(It.IsAny()) == false, MockBehavior.Strict); @@ -42,12 +46,12 @@ namespace Microsoft.VisualStudio.Editor.Razor private Workspace Workspace => TestWorkspace.Create(); - [ForegroundFact] - public void OnTextViewOpened_ForNonRazorTextBuffer_DoesNothing() + [UIFact] + public async Task OnTextViewOpened_ForNonRazorTextBuffer_DoesNothing() { // Arrange var editorFactoryService = new Mock(MockBehavior.Strict); - var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService.Object); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService.Object); var textView = Mock.Of(MockBehavior.Strict); var buffers = new Collection() { @@ -55,11 +59,11 @@ namespace Microsoft.VisualStudio.Editor.Razor }; // Act & Assert - documentManager.OnTextViewOpened(textView, buffers); + await documentManager.OnTextViewOpenedAsync(textView, buffers); } - [ForegroundFact] - public void OnTextViewOpened_ForRazorTextBuffer_AddsTextViewToTracker() + [UIFact] + public async Task OnTextViewOpened_ForRazorTextBuffer_AddsTextViewToTracker() { // Arrange var textView = Mock.Of(MockBehavior.Strict); @@ -67,19 +71,23 @@ namespace Microsoft.VisualStudio.Editor.Razor { Mock.Of(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict), }; - var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker; - var editorFactoryService = Mock.Of(factoryService => factoryService.TryGetDocumentTracker(It.IsAny(), out documentTracker) == true, MockBehavior.Strict); - var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService); + var documentTracker = new DefaultVisualStudioDocumentTracker( + Dispatcher, JoinableTaskContext, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, + Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker; + var editorFactoryService = Mock.Of( + factoryService => factoryService.TryGetDocumentTracker( + It.IsAny(), out documentTracker) == true, MockBehavior.Strict); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService); // Act - documentManager.OnTextViewOpened(textView, buffers); + await documentManager.OnTextViewOpenedAsync(textView, buffers); // Assert Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView)); } - [ForegroundFact] - public void OnTextViewOpened_SubscribesAfterFirstTextViewOpened() + [UIFact] + public async Task OnTextViewOpened_SubscribesAfterFirstTextViewOpened() { // Arrange var textView = Mock.Of(MockBehavior.Strict); @@ -88,25 +96,26 @@ namespace Microsoft.VisualStudio.Editor.Razor Mock.Of(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict), Mock.Of(b => b.ContentType == NonRazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict), }; - var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker; + var documentTracker = new DefaultVisualStudioDocumentTracker( + Dispatcher, JoinableTaskContext, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker; var editorFactoryService = Mock.Of(f => f.TryGetDocumentTracker(It.IsAny(), out documentTracker) == true, MockBehavior.Strict); - var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService); // Assert 1 Assert.False(documentTracker.IsSupportedProject); // Act - documentManager.OnTextViewOpened(textView, buffers); + await documentManager.OnTextViewOpenedAsync(textView, buffers); // Assert 2 Assert.True(documentTracker.IsSupportedProject); } - [ForegroundFact] - public void OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing() + [UIFact] + public async Task OnTextViewClosed_TextViewWithoutDocumentTracker_DoesNothing() { // Arrange - var documentManager = new DefaultRazorDocumentManager(Dispatcher, Mock.Of(MockBehavior.Strict)); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, Mock.Of(MockBehavior.Strict)); var textView = Mock.Of(MockBehavior.Strict); var buffers = new Collection() { @@ -114,14 +123,14 @@ namespace Microsoft.VisualStudio.Editor.Razor }; // Act - documentManager.OnTextViewClosed(textView, buffers); + await documentManager.OnTextViewClosedAsync(textView, buffers); // Assert Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker))); } - [ForegroundFact] - public void OnTextViewClosed_ForAnyTextBufferWithTracker_RemovesTextView() + [UIFact] + public async Task OnTextViewClosed_ForAnyTextBufferWithTracker_RemovesTextView() { // Arrange var textView1 = Mock.Of(MockBehavior.Strict); @@ -133,21 +142,25 @@ namespace Microsoft.VisualStudio.Editor.Razor }; // Preload the buffer's properties with a tracker, so it's like we've already tracked this one. - var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[0], ImportDocumentManager); + var documentTracker = new DefaultVisualStudioDocumentTracker( + Dispatcher, JoinableTaskContext, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, + Workspace, buffers[0], ImportDocumentManager); documentTracker.AddTextView(textView1); documentTracker.AddTextView(textView2); buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker); - documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[1], ImportDocumentManager); + documentTracker = new DefaultVisualStudioDocumentTracker( + Dispatcher, JoinableTaskContext, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, + Workspace, buffers[1], ImportDocumentManager); documentTracker.AddTextView(textView1); documentTracker.AddTextView(textView2); buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker); var editorFactoryService = Mock.Of(MockBehavior.Strict); - var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService); // Act - documentManager.OnTextViewClosed(textView2, buffers); + await documentManager.OnTextViewClosedAsync(textView2, buffers); // Assert documentTracker = buffers[0].Properties.GetProperty(typeof(VisualStudioDocumentTracker)); @@ -157,8 +170,8 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Collection(documentTracker.TextViews, v => Assert.Same(v, textView1)); } - [ForegroundFact] - public void OnTextViewClosed_UnsubscribesAfterLastTextViewClosed() + [UIFact] + public async Task nTextViewClosed_UnsubscribesAfterLastTextViewClosed() { // Arrange var textView1 = Mock.Of(MockBehavior.Strict); @@ -168,10 +181,12 @@ namespace Microsoft.VisualStudio.Editor.Razor Mock.Of(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict), Mock.Of(b => b.ContentType == NonRazorCoreContentType && b.Properties == new PropertyCollection(), MockBehavior.Strict), }; - var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, Workspace, buffers[0], ImportDocumentManager); + var documentTracker = new DefaultVisualStudioDocumentTracker( + Dispatcher, JoinableTaskContext, FilePath, ProjectPath, ProjectManager, WorkspaceEditorSettings, + Workspace, buffers[0], ImportDocumentManager); buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker); var editorFactoryService = Mock.Of(MockBehavior.Strict); - var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService); + var documentManager = new DefaultRazorDocumentManager(Dispatcher, JoinableTaskContext, editorFactoryService); // Populate the text views documentTracker.Subscribe(); @@ -179,13 +194,13 @@ namespace Microsoft.VisualStudio.Editor.Razor documentTracker.AddTextView(textView2); // Act 1 - documentManager.OnTextViewClosed(textView2, buffers); + await documentManager.OnTextViewClosedAsync(textView2, buffers); // Assert 1 Assert.True(documentTracker.IsSupportedProject); // Act - documentManager.OnTextViewClosed(textView1, buffers); + await documentManager.OnTextViewClosedAsync(textView1, buffers); // Assert 2 Assert.False(documentTracker.IsSupportedProject); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioDocumentTrackerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioDocumentTrackerTest.cs index 9472e373b5..0199656145 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioDocumentTrackerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioDocumentTrackerTest.cs @@ -18,7 +18,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultVisualStudioDocumentTrackerTest : ForegroundDispatcherWorkspaceTestBase + public class DefaultVisualStudioDocumentTrackerTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase { public DefaultVisualStudioDocumentTrackerTest() { @@ -33,9 +33,9 @@ namespace Microsoft.VisualStudio.Editor.Razor Mock.Get(ImportDocumentManager).Setup(m => m.OnSubscribed(It.IsAny())).Verifiable(); Mock.Get(ImportDocumentManager).Setup(m => m.OnUnsubscribed(It.IsAny())).Verifiable(); - var foregroundDispatcher = new Mock(MockBehavior.Strict); - foregroundDispatcher.Setup(d => d.AssertForegroundThread(It.IsAny())).Verifiable(); - WorkspaceEditorSettings = new DefaultWorkspaceEditorSettings(foregroundDispatcher.Object, Mock.Of(MockBehavior.Strict)); + var projectSnapshotManagerDispatcher = new Mock(MockBehavior.Strict); + projectSnapshotManagerDispatcher.Setup(d => d.AssertDispatcherThread(It.IsAny())).Verifiable(); + WorkspaceEditorSettings = new DefaultWorkspaceEditorSettings(projectSnapshotManagerDispatcher.Object, Mock.Of(MockBehavior.Strict)); SomeTagHelpers = new List() { @@ -50,6 +50,7 @@ namespace Microsoft.VisualStudio.Editor.Razor DocumentTracker = new DefaultVisualStudioDocumentTracker( Dispatcher, + JoinableTaskFactory.Context, FilePath, ProjectPath, ProjectManager, @@ -106,7 +107,7 @@ namespace Microsoft.VisualStudio.Editor.Razor filePath: TestProjectData.SomeProject.FilePath)); } - [ForegroundFact] + [UIFact] public void Subscribe_NoopsIfAlreadySubscribed() { // Arrange @@ -121,7 +122,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(1, callCount); } - [ForegroundFact] + [UIFact] public void Unsubscribe_NoopsIfAlreadyUnsubscribed() { // Arrange @@ -137,7 +138,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(1, callCount); } - [ForegroundFact] + [UIFact] public void Unsubscribe_NoopsIfSubscribeHasBeenCalledMultipleTimes() { // Arrange @@ -159,7 +160,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Equal(1, callCount); } - [ForegroundFact] + [UIFact] public void EditorSettingsManager_Changed_TriggersContextChanged() { // Arrange @@ -178,7 +179,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void ProjectManager_Changed_ProjectAdded_TriggersContextChanged() { // Arrange @@ -201,7 +202,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void ProjectManager_Changed_ProjectChanged_TriggersContextChanged() { // Arrange @@ -224,7 +225,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void ProjectManager_Changed_ProjectRemoved_TriggersContextChanged_WithEphemeralProject() { // Arrange @@ -251,7 +252,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void ProjectManager_Changed_IgnoresUnknownProject() { // Arrange @@ -269,7 +270,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.False(called); } - [ForegroundFact] + [UIFact] public void Import_Changed_ImportAssociatedWithDocument_TriggersContextChanged() { // Arrange @@ -289,7 +290,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void Import_Changed_UnrelatedImport_DoesNothing() { // Arrange @@ -301,7 +302,7 @@ namespace Microsoft.VisualStudio.Editor.Razor DocumentTracker.Import_Changed(null, importChangedArgs); } - [ForegroundFact] + [UIFact] public void Subscribe_SetsSupportedProjectAndTriggersContextChanged() { // Arrange @@ -316,7 +317,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(DocumentTracker.IsSupportedProject); } - [ForegroundFact] + [UIFact] public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged() { // Arrange @@ -339,7 +340,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(called); } - [ForegroundFact] + [UIFact] public void AddTextView_AddsToTextViewCollection() { // Arrange @@ -352,7 +353,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Collection(DocumentTracker.TextViews, v => Assert.Same(v, textView)); } - [ForegroundFact] + [UIFact] public void AddTextView_DoesNotAddDuplicateTextViews() { // Arrange @@ -366,7 +367,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Collection(DocumentTracker.TextViews, v => Assert.Same(v, textView)); } - [ForegroundFact] + [UIFact] public void AddTextView_AddsMultipleTextViewsToCollection() { // Arrange @@ -384,7 +385,7 @@ namespace Microsoft.VisualStudio.Editor.Razor v => Assert.Same(v, textView2)); } - [ForegroundFact] + [UIFact] public void RemoveTextView_RemovesTextViewFromCollection_SingleItem() { // Arrange @@ -398,7 +399,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Empty(DocumentTracker.TextViews); } - [ForegroundFact] + [UIFact] public void RemoveTextView_RemovesTextViewFromCollection_MultipleItems() { // Arrange @@ -419,7 +420,7 @@ namespace Microsoft.VisualStudio.Editor.Razor v => Assert.Same(v, textView3)); } - [ForegroundFact] + [UIFact] public void RemoveTextView_NoopsWhenRemovingTextViewNotInCollection() { // Arrange @@ -435,7 +436,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } - [ForegroundFact] + [UIFact] public void Subscribed_InitializesEphemeralProjectSnapshot() { // Arrange @@ -447,7 +448,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.IsType(DocumentTracker.ProjectSnapshot); } - [ForegroundFact] + [UIFact] public void Subscribed_InitializesRealProjectSnapshot() { // Arrange @@ -460,7 +461,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.IsType(DocumentTracker.ProjectSnapshot); } - [ForegroundFact] + [UIFact] public void Subscribed_ListensToProjectChanges() { // Arrange @@ -484,7 +485,7 @@ namespace Microsoft.VisualStudio.Editor.Razor e => Assert.Equal(ContextChangeKind.ProjectChanged, e.Kind)); } - [ForegroundFact] + [UIFact] public void Subscribed_ListensToProjectRemoval() { // Arrange diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserIntegrationTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserIntegrationTest.cs index e41a9eb29b..0fbe2ac6fa 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserIntegrationTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserIntegrationTest.cs @@ -20,7 +20,7 @@ using SystemDebugger = System.Diagnostics.Debugger; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultVisualStudioRazorParserIntegrationTest : ForegroundDispatcherTestBase + public class DefaultVisualStudioRazorParserIntegrationTest : ProjectSnapshotManagerDispatcherTestBase { private const string TestLinePragmaFileName = "C:\\This\\Path\\Is\\Just\\For\\Line\\Pragmas.cshtml"; private const string TestProjectPath = "C:\\This\\Path\\Is\\Just\\For\\Project.csproj"; @@ -35,7 +35,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private CodeAnalysis.Workspace Workspace { get; } - [ForegroundFact] + [UIFact] public async Task NoDocumentSnapshotParsesComponentFileCorrectly() { // Arrange @@ -59,7 +59,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task BufferChangeStartsFullReparseIfChangeOverlapsMultipleSpans() { // Arrange @@ -85,7 +85,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task AwaitPeriodInsertionAcceptedProvisionally() { // Arrange @@ -105,7 +105,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprAcceptsDCIInStmtBlkAfterIdentifiers() { // ImplicitExpressionAcceptsDotlessCommitInsertionsInStatementBlockAfterIdentifiers @@ -150,7 +150,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprAcceptsDCIInStatementBlock() { // ImpExprAcceptsDotlessCommitInsertionsInStatementBlock @@ -186,7 +186,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprProvisionallyAcceptsDCI() { // ImpExprProvisionallyAcceptsDotlessCommitInsertions @@ -222,7 +222,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact(Skip = "https://github.com/dotnet/aspnetcore/issues/17234")] + [UIFact(Skip = "https://github.com/dotnet/aspnetcore/issues/17234")] public async Task ImpExprProvisionallyAcceptsDCIAfterIdentifiers_CompletesSyntaxTreeRequest() { var original = new StringTextSnapshot("foo @DateTime baz", versionNumber: 0); @@ -250,7 +250,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprProvisionallyAcceptsDCIAfterIdentifiers() { // ImplicitExpressionProvisionallyAcceptsDotlessCommitInsertionsAfterIdentifiers @@ -292,7 +292,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprProvisionallyAccCaseInsensitiveDCI_NewRoslynIntegration() { // ImplicitExpressionProvisionallyAcceptsCaseInsensitiveDotlessCommitInsertions_NewRoslynIntegration @@ -345,7 +345,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprRejectsAcceptableChangeIfPrevWasProvisionallyAccepted() { // ImplicitExpressionRejectsChangeWhichWouldHaveBeenAcceptedIfLastChangeWasProvisionallyAcceptedOnDifferentSpan @@ -368,7 +368,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprAcceptsIdentifierTypedAfterDotIfLastChangeProvisional() { // ImplicitExpressionAcceptsIdentifierTypedAfterDotIfLastChangeWasProvisionalAcceptanceOfDot @@ -391,7 +391,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExpr_AcceptsParenthesisAtEnd_SingleEdit() { // Arrange @@ -410,7 +410,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExpr_AcceptsParenthesisAtEnd_TwoEdits() { // Arrange @@ -432,85 +432,85 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfIfKeywordTyped() { await RunTypeKeywordTestAsync("if"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfDoKeywordTyped() { await RunTypeKeywordTestAsync("do"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfTryKeywordTyped() { await RunTypeKeywordTestAsync("try"); } - [ForegroundFact] + [UIFact] public async Task ImplicitExpressionCorrectlyTriggersReparseIfForKeywordTyped() { await RunTypeKeywordTestAsync("for"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfForEachKeywordTyped() { await RunTypeKeywordTestAsync("foreach"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfWhileKeywordTyped() { await RunTypeKeywordTestAsync("while"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfSwitchKeywordTyped() { await RunTypeKeywordTestAsync("switch"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfLockKeywordTyped() { await RunTypeKeywordTestAsync("lock"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfUsingKeywordTyped() { await RunTypeKeywordTestAsync("using"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfSectionKeywordTyped() { await RunTypeKeywordTestAsync("section"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfInheritsKeywordTyped() { await RunTypeKeywordTestAsync("inherits"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfFunctionsKeywordTyped() { await RunTypeKeywordTestAsync("functions"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfNamespaceKeywordTyped() { await RunTypeKeywordTestAsync("namespace"); } - [ForegroundFact] + [UIFact] public async Task ImpExprCorrectlyTriggersReparseIfClassKeywordTyped() { await RunTypeKeywordTestAsync("class"); @@ -539,7 +539,7 @@ namespace Microsoft.VisualStudio.Editor.Razor { var templateEngineFactory = CreateProjectEngineFactory(); var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskFactory.Context, documentTracker, templateEngineFactory, new DefaultErrorReporter(), @@ -547,7 +547,7 @@ namespace Microsoft.VisualStudio.Editor.Razor { // We block idle work with the below reset events. Therefore, make tests fast and have the idle timer fire as soon as possible. _idleDelay = TimeSpan.FromMilliseconds(1), - NotifyForegroundIdleStart = new ManualResetEventSlim(), + NotifyUIIdleStart = new ManualResetEventSlim(), BlockBackgroundIdleWork = new ManualResetEventSlim(), }; @@ -704,7 +704,7 @@ namespace Microsoft.VisualStudio.Editor.Razor public async Task WaitForParseAsync() { - // Get off of the foreground thread so we can wait for the document structure changed event to fire + // Get off of the UI thread so we can wait for the document structure changed event to fire await Task.Run(() => DoWithTimeoutIfNotDebugging(_parserComplete.Wait)); _parserComplete.Reset(); @@ -717,17 +717,17 @@ namespace Microsoft.VisualStudio.Editor.Razor // Allow background idle work to continue _parser.BlockBackgroundIdleWork.Set(); - // Get off of the foreground thread so we can wait for the idle timer to fire - await Task.Run(() => DoWithTimeoutIfNotDebugging(_parser.NotifyForegroundIdleStart.Wait)); + // Get off of the UI thread so we can wait for the idle timer to fire + await Task.Run(() => DoWithTimeoutIfNotDebugging(_parser.NotifyUIIdleStart.Wait)); Assert.Null(_parser._idleTimer); - // Get off of the foreground thread so we can wait for the document structure changed event to fire for reparse + // Get off of the UI thread so we can wait for the document structure changed event to fire for reparse await Task.Run(() => DoWithTimeoutIfNotDebugging(_reparseComplete.Wait)); _reparseComplete.Reset(); _parser.BlockBackgroundIdleWork.Reset(); - _parser.NotifyForegroundIdleStart.Reset(); + _parser.NotifyUIIdleStart.Reset(); } public void Dispose() diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs index 391576449b..cbaf0cf278 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs @@ -10,12 +10,13 @@ using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.Test; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Moq; using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultVisualStudioRazorParserTest : ForegroundDispatcherTestBase + public class DefaultVisualStudioRazorParserTest : ProjectSnapshotManagerDispatcherTestBase { public DefaultVisualStudioRazorParserTest() { @@ -30,6 +31,8 @@ namespace Microsoft.VisualStudio.Editor.Razor It.IsAny>()) == engine, MockBehavior.Strict); } + private JoinableTaskContext JoinableTaskContext => JoinableTaskFactory.Context; + private ProjectSnapshot ProjectSnapshot { get; } private ProjectSnapshotProjectEngineFactory ProjectEngineFactory { get; } @@ -48,13 +51,13 @@ namespace Microsoft.VisualStudio.Editor.Razor return documentTracker; } - [ForegroundFact] + [UIFact] public async Task GetLatestCodeDocumentAsync_WaitsForParse() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -90,13 +93,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task GetLatestCodeDocumentAsync_NoPendingChangesReturnsImmediately() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -129,13 +132,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void GetLatestCodeDocumentAsync_MultipleCallsSameSnapshotMemoizesReturnedTasks() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -155,13 +158,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void GetLatestCodeDocumentAsync_MultipleCallsDifferentSnapshotsReturnDifferentTasks() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -182,14 +185,14 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task GetLatestCodeDocumentAsync_LatestChangeIsNewerThenRequested_ReturnsImmediately() { // Arrange var documentTracker = CreateDocumentTracker(versionNumber: 1337); var olderSnapshot = new StringTextSnapshot("Older", versionNumber: 910); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -222,7 +225,7 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public async Task GetLatestCodeDocumentAsync_ParserDisposed_ReturnsImmediately() { // Arrange @@ -232,7 +235,7 @@ namespace Microsoft.VisualStudio.Editor.Razor DefaultVisualStudioRazorParser parser; codeDocument.SetSyntaxTree(syntaxTree); using (parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -263,7 +266,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Same(latestCodeDocument, codeDocument); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_Complete_CanBeCalledMultipleTimes() { // Arrange @@ -276,7 +279,7 @@ namespace Microsoft.VisualStudio.Editor.Razor request.Complete(codeDocument); } - [ForegroundFact] + [UIFact] public async Task CodeDocumentRequest_Complete_FinishesTask() { // Arrange @@ -292,7 +295,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.Same(codeDocument, resolvedSyntaxTree); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_Cancel_CanBeCalledMultipleTimes() { // Arrange @@ -304,7 +307,7 @@ namespace Microsoft.VisualStudio.Editor.Razor request.Cancel(); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_Cancel_CancelsTask() { // Arrange @@ -317,7 +320,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(request.Task.IsCanceled); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_LinkedTokenCancel_CancelsTask() { // Arrange @@ -331,7 +334,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.True(request.Task.IsCanceled); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_CompleteToCancelNoops() { // Arrange @@ -351,7 +354,7 @@ namespace Microsoft.VisualStudio.Editor.Razor Assert.False(request.Task.IsCanceled); } - [ForegroundFact] + [UIFact] public void CodeDocumentRequest_CancelToCompleteNoops() { // Arrange @@ -368,12 +371,12 @@ namespace Microsoft.VisualStudio.Editor.Razor request.Complete(codeDocument); } - [ForegroundFact] - public void ReparseOnForeground_NoopsIfDisposed() + [UIFact] + public void ReparseOnUIThread_NoopsIfDisposed() { // Arrange var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -381,15 +384,15 @@ namespace Microsoft.VisualStudio.Editor.Razor parser.Dispose(); // Act & Assert - parser.ReparseOnForeground(null); + parser.ReparseOnUIThread(); } - [ForegroundFact] + [UIFact] public void OnIdle_NoopsIfDisposed() { // Arrange var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -397,15 +400,15 @@ namespace Microsoft.VisualStudio.Editor.Razor parser.Dispose(); // Act & Assert - parser.OnIdle(null); + parser.OnIdle(); } - [ForegroundFact] + [UIFact] public void OnDocumentStructureChanged_NoopsIfDisposed() { // Arrange var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -416,12 +419,12 @@ namespace Microsoft.VisualStudio.Editor.Razor parser.OnDocumentStructureChanged(new object()); } - [ForegroundFact] + [UIFact] public void OnDocumentStructureChanged_IgnoresEditsThatAreOld() { // Arrange using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -442,13 +445,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void OnDocumentStructureChanged_FiresForLatestTextBufferEdit() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -473,13 +476,13 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void OnDocumentStructureChanged_FiresForOnlyLatestTextBufferReparseEdit() { // Arrange var documentTracker = CreateDocumentTracker(); using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -513,12 +516,12 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void StartIdleTimer_DoesNotRestartTimerWhenAlreadyRunning() { // Arrange using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -543,12 +546,12 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void StopIdleTimer_StopsTimer() { // Arrange using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -570,14 +573,14 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void StopParser_DetachesFromTextBufferChangeLoop() { // Arrange var documentTracker = CreateDocumentTracker(); var textBuffer = (TestTextBuffer)documentTracker.TextBuffer; using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(), ProjectEngineFactory, new DefaultErrorReporter(), @@ -594,14 +597,14 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void StartParser_AttachesToTextBufferChangeLoop() { // Arrange var documentTracker = CreateDocumentTracker(); var textBuffer = (TestTextBuffer)documentTracker.TextBuffer; using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, documentTracker, ProjectEngineFactory, new DefaultErrorReporter(), @@ -616,12 +619,12 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void TryReinitializeParser_ReturnsTrue_IfProjectIsSupported() { // Arrange using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(isSupportedProject: true), ProjectEngineFactory, new DefaultErrorReporter(), @@ -635,12 +638,12 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - [ForegroundFact] + [UIFact] public void TryReinitializeParser_ReturnsFalse_IfProjectIsNotSupported() { // Arrange using (var parser = new DefaultVisualStudioRazorParser( - Dispatcher, + JoinableTaskContext, CreateDocumentTracker(isSupportedProject: false), ProjectEngineFactory, new DefaultErrorReporter(), diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultWorkspaceEditorSettingsTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultWorkspaceEditorSettingsTest.cs index d18128d857..653178f9bd 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultWorkspaceEditorSettingsTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultWorkspaceEditorSettingsTest.cs @@ -8,7 +8,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class DefaultWorkspaceEditorSettingsTest : ForegroundDispatcherTestBase + public class DefaultWorkspaceEditorSettingsTest : ProjectSnapshotManagerDispatcherTestBase { [Fact] public void InitialSettingsAreEditorSettingsManagerDefault() @@ -75,7 +75,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private class TestEditorSettingsManagerInternal : DefaultWorkspaceEditorSettings { - public TestEditorSettingsManagerInternal(ForegroundDispatcher foregroundDispatcher) : base(foregroundDispatcher, Mock.Of(MockBehavior.Strict)) + public TestEditorSettingsManagerInternal(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(projectSnapshotManagerDispatcher, Mock.Of(MockBehavior.Strict)) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerBaseTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerBaseTest.cs index 128146a849..8561edd19b 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerBaseTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerBaseTest.cs @@ -6,16 +6,17 @@ using System.Linq; using Microsoft.CodeAnalysis.Razor; using Microsoft.VisualStudio.Test; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Documents { - public class EditorDocumentManagerBaseTest : ForegroundDispatcherTestBase + public class EditorDocumentManagerBaseTest : ProjectSnapshotManagerDispatcherTestBase { public EditorDocumentManagerBaseTest() { - Manager = new TestEditorDocumentManager(Dispatcher); + Manager = new TestEditorDocumentManager(Dispatcher, JoinableTaskFactory.Context); } private TestEditorDocumentManager Manager { get; } @@ -30,7 +31,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents public TestTextBuffer TextBuffer => new TestTextBuffer(new StringTextSnapshot("HI")); - [ForegroundFact] + [UIFact] public void GetOrCreateDocument_CreatesAndCachesDocument() { // Arrange @@ -43,7 +44,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Same(expected, actual); } - [ForegroundFact] + [UIFact] public void GetOrCreateDocument_NoOp() { // Arrange @@ -56,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Same(expected, actual); } - [ForegroundFact] + [UIFact] public void GetOrCreateDocument_SameFile_MulipleProjects() { // Arrange @@ -69,7 +70,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.NotSame(document1, document2); } - [ForegroundFact] + [UIFact] public void GetOrCreateDocument_MulipleFiles_SameProject() { // Arrange @@ -82,7 +83,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.NotSame(document1, document2); } - [ForegroundFact] + [UIFact] public void GetOrCreateDocument_WithBuffer_AttachesBuffer() { // Arrange @@ -99,7 +100,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Empty(Manager.Closed); } - [ForegroundFact] + [UIFact] public void TryGetMatchingDocuments_MultipleDocuments() { // Arrange @@ -116,7 +117,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents d => Assert.Same(document1, d)); } - [ForegroundFact] + [UIFact] public void RemoveDocument_MultipleDocuments_RemovesOne() { // Arrange @@ -133,7 +134,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents d => Assert.Same(document2, d)); } - [ForegroundFact] + [UIFact] public void DocumentOpened_MultipleDocuments_OpensAll() { // Arrange @@ -150,7 +151,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents d => Assert.Same(document1, d)); } - [ForegroundFact] + [UIFact] public void DocumentOpened_MultipleDocuments_ClosesAll() { // Arrange @@ -170,8 +171,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents private class TestEditorDocumentManager : EditorDocumentManagerBase { - public TestEditorDocumentManager(ForegroundDispatcher foregroundDispatcher) - : base(foregroundDispatcher, new DefaultFileChangeTrackerFactory()) + public TestEditorDocumentManager(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, JoinableTaskContext joinableTaskContext) + : base(projectSnapshotManagerDispatcher, joinableTaskContext, new DefaultFileChangeTrackerFactory()) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs index 2e8e699acb..1f4ef2227d 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentManagerListenerTest.cs @@ -8,12 +8,13 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Test; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Moq; using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Documents { - public class EditorDocumentManagerListenerTest + public class EditorDocumentManagerListenerTest : ProjectSnapshotManagerDispatcherTestBase { public EditorDocumentManagerListenerTest() { @@ -56,7 +57,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Same(closed, onClosed); }); - var listener = new EditorDocumentManagerListener(editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed); + var listener = new EditorDocumentManagerListener( + Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, changedOnDisk, changedInEditor, opened, closed); var project = Mock.Of(p => p.FilePath == "/Path/to/project.csproj", MockBehavior.Strict); @@ -76,7 +78,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents .Setup(e => e.GetOrCreateDocument(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(GetEditorDocument(isOpen: true)); - var listener = new EditorDocumentManagerListener(editorDocumentManger.Object, onChangedOnDisk: null, onChangedInEditor: null, onOpened: opened, onClosed: null); + var listener = new EditorDocumentManagerListener( + Dispatcher, JoinableTaskFactory.Context, editorDocumentManger.Object, onChangedOnDisk: null, onChangedInEditor: null, onOpened: opened, onClosed: null); var project = Mock.Of(p => p.FilePath == "/Path/to/project.csproj", MockBehavior.Strict); @@ -91,6 +94,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents { var document = new EditorDocument( Mock.Of(MockBehavior.Strict), + Dispatcher, + JoinableTaskFactory.Context, ProjectFilePath, DocumentFilePath, TextLoader, diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentTest.cs index ef1f2dd078..63a1920e4f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Documents/EditorDocumentTest.cs @@ -11,7 +11,7 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor.Documents { - public class EditorDocumentTest + public class EditorDocumentTest : ProjectSnapshotManagerDispatcherTestBase { public EditorDocumentTest() { @@ -43,6 +43,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents // Arrange & Act using (var document = new EditorDocument( DocumentManager, + Dispatcher, + JoinableTaskFactory.Context, ProjectFilePath, DocumentFilePath, TextLoader, @@ -66,6 +68,8 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents // Arrange & Act using (var document = new EditorDocument( DocumentManager, + Dispatcher, + JoinableTaskFactory.Context, ProjectFilePath, DocumentFilePath, TextLoader, diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/RazorTextViewConnectionListenerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/RazorTextViewConnectionListenerTest.cs index 8b15ed8dc2..5825d4faaa 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/RazorTextViewConnectionListenerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/RazorTextViewConnectionListenerTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.ObjectModel; +using System.Threading.Tasks; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Moq; @@ -9,18 +10,19 @@ using Xunit; namespace Microsoft.VisualStudio.Editor.Razor { - public class RazorTextViewConnectionListenerTest : ForegroundDispatcherTestBase + public class RazorTextViewConnectionListenerTest : ProjectSnapshotManagerDispatcherTestBase { - [ForegroundFact] + [UIFact] public void SubjectBuffersConnected_CallsRazorDocumentManager_OnTextViewOpened() { // Arrange + var textView = Mock.Of(MockBehavior.Strict); var buffers = new Collection(); var documentManager = new Mock(MockBehavior.Strict); - documentManager.Setup(d => d.OnTextViewOpened(textView, buffers)).Verifiable(); + documentManager.Setup(d => d.OnTextViewOpenedAsync(textView, buffers)).Returns(Task.CompletedTask).Verifiable(); - var listener = new RazorTextViewConnectionListener(Dispatcher, documentManager.Object); + var listener = new RazorTextViewConnectionListener(JoinableTaskFactory.Context, documentManager.Object); // Act listener.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers); @@ -29,16 +31,16 @@ namespace Microsoft.VisualStudio.Editor.Razor documentManager.Verify(); } - [ForegroundFact] + [UIFact] public void SubjectBuffersDisonnected_CallsRazorDocumentManager_OnTextViewClosed() { // Arrange var textView = Mock.Of(MockBehavior.Strict); var buffers = new Collection(); var documentManager = new Mock(MockBehavior.Strict); - documentManager.Setup(d => d.OnTextViewClosed(textView, buffers)).Verifiable(); + documentManager.Setup(d => d.OnTextViewClosedAsync(textView, buffers)).Returns(Task.CompletedTask).Verifiable(); - var listener = new RazorTextViewConnectionListener(Dispatcher, documentManager.Object); + var listener = new RazorTextViewConnectionListener(JoinableTaskFactory.Context, documentManager.Object); // Act listener.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers); diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ForegroundDispatcherWorkspaceTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ForegroundDispatcherWorkspaceTestBase.cs deleted file mode 100644 index 495b0ff172..0000000000 --- a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ForegroundDispatcherWorkspaceTestBase.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.Razor; - -namespace Xunit -{ - public abstract class ForegroundDispatcherWorkspaceTestBase : WorkspaceTestBase - { - internal ForegroundDispatcher Dispatcher { get; } = new SingleThreadedForegroundDispatcher(); - } -} diff --git a/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ProjectSnapshotManagerDispatcherWorkspaceTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ProjectSnapshotManagerDispatcherWorkspaceTestBase.cs new file mode 100644 index 0000000000..8e10866a06 --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/Shared/ProjectSnapshotManagerDispatcherWorkspaceTestBase.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Razor; +using Microsoft.VisualStudio.Threading; + +namespace Xunit +{ + public abstract class ProjectSnapshotManagerDispatcherWorkspaceTestBase : WorkspaceTestBase + { + internal ProjectSnapshotManagerDispatcher Dispatcher { get; } = new TestProjectSnapshotManagerDispatcher(); + + internal static JoinableTaskFactory JoinableTaskFactory + { + get + { + var joinableTaskContext = new JoinableTaskContextNode(new JoinableTaskContext()); + return new JoinableTaskFactory(joinableTaskContext.Context); + } + } + } +} diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServer.ContainedLanguage.Test/DefaultFallbackCapabilitiesFilterResolverTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServer.ContainedLanguage.Test/DefaultFallbackCapabilitiesFilterResolverTest.cs index c6b200ebf3..e53cff8912 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServer.ContainedLanguage.Test/DefaultFallbackCapabilitiesFilterResolverTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServer.ContainedLanguage.Test/DefaultFallbackCapabilitiesFilterResolverTest.cs @@ -575,8 +575,8 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage public void Resolve_MSReference_ReturnsTrue() { // Arrange - var methodName = MSLSPMethods.DocumentReferencesName; - var capabilities = new VSServerCapabilities() + var methodName = VSInternalMethods.DocumentReferencesName; + var capabilities = new VSInternalServerCapabilities() { MSReferencesProvider = true, }; @@ -594,7 +594,7 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage public void Resolve_ProjectContext_ReturnsTrue() { // Arrange - var methodName = MSLSPMethods.ProjectContextsName; + var methodName = VSMethods.GetProjectContextsName; var capabilities = new VSServerCapabilities() { ProjectContextProvider = true, @@ -613,10 +613,13 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage public void Resolve_CodeActionResolve_ReturnsTrue() { // Arrange - var methodName = MSLSPMethods.TextDocumentCodeActionResolveName; - var capabilities = new VSServerCapabilities() + var methodName = Methods.CodeActionResolveName; + var capabilities = new ServerCapabilities() { - CodeActionsResolveProvider = true, + CodeActionProvider = new CodeActionOptions() + { + ResolveProvider = true, + }, }; var jobjectCapabilities = JObject.FromObject(capabilities); var filter = Resolver.Resolve(methodName); @@ -632,10 +635,10 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage public void Resolve_OnAutoInsert_ReturnsTrue() { // Arrange - var methodName = MSLSPMethods.OnAutoInsertName; - var capabilities = new VSServerCapabilities() + var methodName = VSInternalMethods.OnAutoInsertName; + var capabilities = new VSInternalServerCapabilities() { - OnAutoInsertProvider = new DocumentOnAutoInsertOptions(), + OnAutoInsertProvider = new VSInternalDocumentOnAutoInsertOptions(), }; var jobjectCapabilities = JObject.FromObject(capabilities); var filter = Resolver.Resolve(methodName); @@ -651,8 +654,8 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage public void Resolve_PullDiagnostics_ReturnsTrue() { // Arrange - var methodName = MSLSPMethods.DocumentPullDiagnosticName; - var capabilities = new VSServerCapabilities() + var methodName = VSInternalMethods.DocumentPullDiagnosticName; + var capabilities = new VSInternalServerCapabilities() { SupportsDiagnosticRequests = true, }; @@ -685,12 +688,12 @@ namespace Microsoft.VisualStudio.LanguageServer.ContainedLanguage [InlineData(Methods.TextDocumentCompletionResolveName)] [InlineData(Methods.TextDocumentDefinitionName)] [InlineData(Methods.TextDocumentDocumentHighlightName)] - [InlineData(MSLSPMethods.DocumentReferencesName)] - [InlineData(MSLSPMethods.ProjectContextsName)] - [InlineData(MSLSPMethods.TextDocumentCodeActionResolveName)] - [InlineData(MSLSPMethods.OnAutoInsertName)] - [InlineData(MSLSPMethods.DocumentPullDiagnosticName)] - [InlineData(MSLSPMethods.WorkspacePullDiagnosticName)] + [InlineData(Methods.CodeActionResolveName)] + [InlineData(VSMethods.GetProjectContextsName)] + [InlineData(VSInternalMethods.DocumentReferencesName)] + [InlineData(VSInternalMethods.OnAutoInsertName)] + [InlineData(VSInternalMethods.DocumentPullDiagnosticName)] + [InlineData(VSInternalMethods.WorkspacePullDiagnosticName)] public void Resolve_NotPresent_ReturnsFalse(string methodName) { // Arrange diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorLanguageServerCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorLanguageServerCustomMessageTargetTest.cs index 56ef26202f..b5b625c944 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorLanguageServerCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorLanguageServerCustomMessageTargetTest.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.LanguageServer.Common; using Microsoft.AspNetCore.Razor.LanguageServer.Semantic; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Client; @@ -270,20 +269,20 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor documentManager.Setup(manager => manager.TryGetDocument(It.IsAny(), out testDocument)) .Returns(true); - var languageServer1Response = new[] { new VSCodeAction() { Title = "Response 1" } }; - var languageServer2Response = new[] { new VSCodeAction() { Title = "Response 2" } }; - IEnumerable> expectedResults = new List>() { - new ReinvokeResponse(_languageClient, languageServer1Response), - new ReinvokeResponse(_languageClient, languageServer2Response), + var languageServer1Response = new[] { new VSInternalCodeAction() { Title = "Response 1" } }; + var languageServer2Response = new[] { new VSInternalCodeAction() { Title = "Response 2" } }; + IEnumerable> expectedResults = new List>() { + new ReinvokeResponse(_languageClient, languageServer1Response), + new ReinvokeResponse(_languageClient, languageServer2Response), }; var requestInvoker = new Mock(MockBehavior.Strict); - requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync( + requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync( Methods.TextDocumentCodeActionName, LanguageServerKind.CSharp.ToContentType(), It.IsAny>(), It.IsAny(), It.IsAny() - )).Returns(Task.FromResult(expectedResults)); + )).Returns(Task.FromResult>>(expectedResults)); var uIContextManager = new Mock(MockBehavior.Strict); var disposable = new Mock(MockBehavior.Strict); @@ -318,25 +317,25 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var requestInvoker = new Mock(MockBehavior.Strict); var documentManager = new Mock(MockBehavior.Strict); - var expectedCodeAction = new VSCodeAction() + var expectedCodeAction = new VSInternalCodeAction() { Title = "Something", Data = new object() }; - var unexpectedCodeAction = new VSCodeAction() + var unexpectedCodeAction = new VSInternalCodeAction() { Title = "Something Else", Data = new object() }; - IEnumerable> expectedResponses = new List> () { - new ReinvokeResponse(_languageClient, expectedCodeAction), - new ReinvokeResponse(_languageClient, unexpectedCodeAction), + IEnumerable> expectedResponses = new List> () { + new ReinvokeResponse(_languageClient, expectedCodeAction), + new ReinvokeResponse(_languageClient, unexpectedCodeAction), }; - requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync( - MSLSPMethods.TextDocumentCodeActionResolveName, + requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnMultipleServersAsync( + Methods.CodeActionResolveName, LanguageServerKind.CSharp.ToContentType(), It.IsAny>(), - It.IsAny(), + It.IsAny(), It.IsAny() )).Returns(Task.FromResult(expectedResponses)); @@ -348,7 +347,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var target = new DefaultRazorLanguageServerCustomMessageTarget( documentManager.Object, JoinableTaskContext, requestInvoker.Object, uIContextManager.Object, disposable.Object, clientOptionsMonitor.Object, documentSynchronizer.Object); - var request = new VSCodeAction() + var request = new VSInternalCodeAction() { Title = "Something", }; @@ -432,7 +431,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var expectedcSharpResults = new OmniSharp.Extensions.LanguageServer.Protocol.Models.Proposals.SemanticTokens(); var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnServerAsync( - LanguageServerConstants.LegacyRazorSemanticTokensEndpoint, + Methods.TextDocumentSemanticTokensFullName, LanguageServerKind.CSharp.ToLanguageServerName(), It.IsAny(), It.IsAny() @@ -485,9 +484,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var expectedResults = new SemanticTokens { }; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnServerAsync( - LanguageServerConstants.LegacyRazorSemanticTokensEndpoint, - RazorLSPConstants.RazorCSharpLanguageServerName, - null, + Methods.TextDocumentSemanticTokensFullName, + LanguageServerKind.CSharp.ToContentType(), It.IsAny(), It.IsAny() )).Returns(Task.FromResult(new ReinvokeResponse(_languageClient, expectedResults))); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorProjectChangePublisherTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorProjectChangePublisherTest.cs index 05e69bbdd1..0726583404 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorProjectChangePublisherTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/DefaultRazorProjectChangePublisherTest.cs @@ -379,7 +379,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test Assert.True(serializationSuccessful); } - [ForegroundFact] + [UIFact] public async Task ProjectAdded_PublishesToCorrectFilePathAsync() { // Arrange @@ -404,7 +404,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test var projectWorkspaceState = new ProjectWorkspaceState(Array.Empty(), CodeAnalysis.CSharp.LanguageVersion.Default); // Act - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { ProjectSnapshotManager.ProjectAdded(hostProject); ProjectSnapshotManager.ProjectWorkspaceStateChanged(projectFilePath, projectWorkspaceState); @@ -416,7 +416,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test Assert.True(serializationSuccessful); } - [ForegroundFact] + [UIFact] public async Task ProjectAdded_DoesNotPublishWithoutProjectWorkspaceStateAsync() { // Arrange @@ -439,7 +439,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test ProjectConfigurationFilePathStore.Set(hostProject.FilePath, expectedConfigurationFilePath); // Act - await RunOnForegroundAsync(() => ProjectSnapshotManager.ProjectAdded(hostProject)).ConfigureAwait(false); + await RunOnDispatcherThreadAsync(() => ProjectSnapshotManager.ProjectAdded(hostProject)).ConfigureAwait(false); Assert.Empty(publisher.DeferredPublishTasks); @@ -447,7 +447,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test Assert.False(serializationSuccessful); } - [ForegroundFact] + [UIFact] public async Task ProjectRemoved_UnSetPublishFilePath_NoopsAsync() { // Arrange @@ -459,15 +459,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test }; publisher.Initialize(ProjectSnapshotManager); var hostProject = new HostProject("/path/to/project.csproj", RazorConfiguration.Default, "TestRootNamespace"); - await RunOnForegroundAsync(() => ProjectSnapshotManager.ProjectAdded(hostProject)).ConfigureAwait(false); + await RunOnDispatcherThreadAsync(() => ProjectSnapshotManager.ProjectAdded(hostProject)).ConfigureAwait(false); // Act & Assert - await RunOnForegroundAsync(() => ProjectSnapshotManager.ProjectRemoved(hostProject)).ConfigureAwait(false); + await RunOnDispatcherThreadAsync(() => ProjectSnapshotManager.ProjectRemoved(hostProject)).ConfigureAwait(false); Assert.Empty(publisher.DeferredPublishTasks); } - [ForegroundFact] + [UIFact] public async Task ProjectAdded_DoesNotFireWhenNotReadyAsync() { // Arrange @@ -493,7 +493,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test var projectWorkspaceState = new ProjectWorkspaceState(Array.Empty(), CodeAnalysis.CSharp.LanguageVersion.Default); // Act - await RunOnForegroundAsync(() => + await RunOnDispatcherThreadAsync(() => { ProjectSnapshotManager.ProjectAdded(hostProject); ProjectSnapshotManager.ProjectWorkspaceStateChanged(projectFilePath, projectWorkspaceState); @@ -532,31 +532,25 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test return snapshotManager; } - protected Task RunOnForegroundAsync(Action action) + protected Task RunOnDispatcherThreadAsync(Action action) { - return Task.Factory.StartNew( + return Dispatcher.RunOnDispatcherThreadAsync( () => action(), - CancellationToken.None, - TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + CancellationToken.None); } - protected Task RunOnForegroundAsync(Func action) + protected Task RunOnDispatcherThreadAsync(Func action) { - return Task.Factory.StartNew( + return Dispatcher.RunOnDispatcherThreadAsync( () => action(), - CancellationToken.None, - TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + CancellationToken.None); } - protected Task RunOnForegroundAsync(Func action) + protected Task RunOnDispatcherThreadAsync(Func action) { - return Task.Factory.StartNew( + return Dispatcher.RunOnDispatcherThreadAsync( async () => await action().ConfigureAwait(true), - CancellationToken.None, - TaskCreationOptions.None, - Dispatcher.ForegroundScheduler); + CancellationToken.None); } private class TestDefaultRazorProjectChangePublisher : DefaultRazorProjectChangePublisher diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/CompletionHandlerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/CompletionHandlerTest.cs index 6e63082c5b..07b6b95d80 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/CompletionHandlerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/CompletionHandlerTest.cs @@ -101,7 +101,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, - Context = new VSCompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "<", InvokeKind = VSCompletionInvokeKind.Typing }, + Context = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "<", InvokeKind = VSInternalCompletionInvokeKind.Typing }, Position = new Position(0, 1) }; @@ -115,8 +115,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { Assert.Equal(Methods.TextDocumentCompletionName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); - var vsCompletionContext = Assert.IsType(completionParams.Context); - Assert.Equal(VSCompletionInvokeKind.Typing, vsCompletionContext.InvokeKind); + var vsCompletionContext = Assert.IsType(completionParams.Context); + Assert.Equal(VSInternalCompletionInvokeKind.Typing, vsCompletionContext.InvokeKind); called = true; }) .Returns(Task.FromResult(new ReinvokeResponse?>(_languageClient, new[] { expectedItem }))); @@ -146,7 +146,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, - Context = new VSCompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "<", InvokeKind = VSCompletionInvokeKind.Typing }, + Context = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "<", InvokeKind = VSInternalCompletionInvokeKind.Typing }, Position = new Position(0, 1) }; @@ -173,7 +173,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp // Assert requestInvoker.VerifyAll(); - Assert.Null(result.Value.Value); + Assert.Null(result); } [Fact] @@ -185,7 +185,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, - Context = new VSCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked, InvokeKind = VSCompletionInvokeKind.Explicit }, + Context = new VSInternalCompletionContext() { TriggerKind = CompletionTriggerKind.Invoked, InvokeKind = VSInternalCompletionInvokeKind.Explicit }, Position = new Position(0, 1) }; @@ -199,8 +199,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { Assert.Equal(Methods.TextDocumentCompletionName, method); Assert.Equal(RazorLSPConstants.RazorCSharpLanguageServerName, clientName); - var vsCompletionContext = Assert.IsType(completionParams.Context); - Assert.Equal(VSCompletionInvokeKind.Explicit, vsCompletionContext.InvokeKind); + var vsCompletionContext = Assert.IsType(completionParams.Context); + Assert.Equal(VSInternalCompletionInvokeKind.Explicit, vsCompletionContext.InvokeKind); called = true; }) .Returns(Task.FromResult(new ReinvokeResponse?>(_languageClient, new[] { expectedItem }))); @@ -298,7 +298,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var rewrittenContext = CompletionHandler.RewriteContext(completionRequest.Context, RazorLanguageKind.CSharp); Assert.True(rewrittenContext.TriggerKind == CompletionTriggerKind.Invoked); - Assert.True(((VSCompletionContext)rewrittenContext).InvokeKind == VSCompletionInvokeKind.Explicit); + Assert.True(((VSInternalCompletionContext)rewrittenContext).InvokeKind == VSInternalCompletionInvokeKind.Explicit); } [Fact] @@ -1017,7 +1017,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { // Arrange var originalData = new object(); - var completionList = new VSCompletionList() + var completionList = new VSInternalCompletionList() { Items = new[] { @@ -1472,7 +1472,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var wordSnapshotSpan = new SnapshotSpan(documentSnapshot.Snapshot, new Span(39, 1)); var wordRange = new TextExtent(wordSnapshotSpan, isSignificant: true); - var completionList = new VSCompletionList + var completionList = new VSInternalCompletionList { Items = new CompletionItem[] { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DefaultLSPDocumentMappingProviderTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DefaultLSPDocumentMappingProviderTest.cs index 8631ddc6db..8419cb2797 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DefaultLSPDocumentMappingProviderTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DefaultLSPDocumentMappingProviderTest.cs @@ -288,7 +288,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp DocumentChanges = (DocumentChanges?.Value as TextDocumentEdit[])?.Append(new TextDocumentEdit() { Edits = edits, - TextDocument = new VersionedTextDocumentIdentifier() + TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = uri, Version = version diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DocumentPullDiagnosticsHandlerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DocumentPullDiagnosticsHandlerTest.cs index f298c1d2b0..6b8f7c77da 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DocumentPullDiagnosticsHandlerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/DocumentPullDiagnosticsHandlerTest.cs @@ -79,9 +79,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp Source = "DocumentPullDiagnosticHandler", }; - private static readonly DiagnosticReport[] s_roslynDiagnosticResponse = new DiagnosticReport[] + private static readonly VSInternalDiagnosticReport[] s_roslynDiagnosticResponse = new VSInternalDiagnosticReport[] { - new DiagnosticReport() + new VSInternalDiagnosticReport() { ResultId = "5", Diagnostics = new Diagnostic[] @@ -117,7 +117,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var documentSynchronizer = Mock.Of(MockBehavior.Strict); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -137,11 +137,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var called = false; var documentManager = CreateDocumentManager(); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( s_roslynDiagnosticResponse, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -150,7 +150,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentSynchronizer = CreateDocumentSynchronizer(); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -183,11 +183,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var called = false; var documentManager = CreateDocumentManager(); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( s_roslynDiagnosticResponse, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -200,7 +200,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp .Returns(Task.FromResult(false)); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer.Object, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -245,7 +245,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp Severity = DiagnosticSeverity.Warning }; - var diagnosticReport = new DiagnosticReport() + var diagnosticReport = new VSInternalDiagnosticReport() { ResultId = "6", Diagnostics = new Diagnostic[] @@ -255,11 +255,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } }; - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( new[] { diagnosticReport }, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -270,7 +270,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentSynchronizer = CreateDocumentSynchronizer(); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -314,7 +314,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp End = new Position(49, 23) }; - var diagnosticReport = new DiagnosticReport() + var diagnosticReport = new VSInternalDiagnosticReport() { ResultId = "6", Diagnostics = new Diagnostic[] @@ -323,11 +323,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp } }; - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( new[] { diagnosticReport }, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -336,7 +336,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentSynchronizer = CreateDocumentSynchronizer(); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -359,11 +359,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var called = false; var documentManager = CreateDocumentManager(hostDocumentVersion: 1); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( s_roslynDiagnosticResponse, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -374,7 +374,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentSynchronizer = CreateDocumentSynchronizer(); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" @@ -397,11 +397,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var called = false; var documentManager = CreateDocumentManager(); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( s_roslynDiagnosticResponse, (method, serverContentType, diagnosticParams, ct) => { - Assert.Equal(MSLSPMethods.DocumentPullDiagnosticName, method); + Assert.Equal(VSInternalMethods.DocumentPullDiagnosticName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); @@ -410,7 +410,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentSynchronizer = CreateDocumentSynchronizer(); var documentDiagnosticsHandler = new DocumentPullDiagnosticsHandler(requestInvoker, documentManager, documentSynchronizer, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new DocumentDiagnosticsParams() + var diagnosticRequest = new VSInternalDocumentDiagnosticsParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, PreviousResultId = "4" diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/FindAllReferencesHandlerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/FindAllReferencesHandlerTest.cs index 0625604528..4bf4a4f225 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/FindAllReferencesHandlerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/FindAllReferencesHandlerTest.cs @@ -118,7 +118,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( + .Setup(r => r.ReinvokeRequestOnServerAsync( It.IsAny(), It.IsAny(), It.IsAny(), @@ -131,7 +131,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterToken); }) - .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); + .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); var projectionResult = new ProjectionResult() { @@ -160,10 +160,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Collection(results, - a => AssertVSReferenceItem(expectedLocation1, a), - b => AssertVSReferenceItem(expectedLocation2, b)); + a => AssertVSInternalReferenceItem(expectedLocation1, a), + b => AssertVSInternalReferenceItem(expectedLocation2, b)); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -254,7 +254,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(r => r.ReinvokeRequestOnServerAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((method, clientName, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentReferencesName, method); @@ -263,7 +263,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterToken); }) - .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); + .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); var projectionResult = new ProjectionResult() { @@ -292,10 +292,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Collection(results, - a => AssertVSReferenceItem(expectedLocation1, a), - b => AssertVSReferenceItem(expectedLocation2, b)); + a => AssertVSInternalReferenceItem(expectedLocation1, a), + b => AssertVSInternalReferenceItem(expectedLocation2, b)); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -352,9 +352,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); var actualLocation = Assert.Single(results); - AssertVSReferenceItem(expectedLocation, actualLocation); + AssertVSInternalReferenceItem(expectedLocation, actualLocation); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -412,9 +412,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); var actualReferenceItem = Assert.Single(results); - AssertVSReferenceItem(expectedReferenceItem, actualReferenceItem); + AssertVSInternalReferenceItem(expectedReferenceItem, actualReferenceItem); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -484,9 +484,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); var actualReferenceItem = Assert.Single(results); - AssertVSReferenceItem(expectedReferenceItem, actualReferenceItem); + AssertVSInternalReferenceItem(expectedReferenceItem, actualReferenceItem); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -533,9 +533,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); var actualLocation = Assert.Single(results); - AssertVSReferenceItem(externalCsharpLocation, actualLocation); + AssertVSInternalReferenceItem(externalCsharpLocation, actualLocation); progressReported = true; completedTokenSource.CancelAfter(0); }); @@ -591,7 +591,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Empty(results); progressReported = true; completedTokenSource.CancelAfter(0); @@ -651,7 +651,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Empty(results); progressReported = true; completedTokenSource.CancelAfter(0); @@ -703,7 +703,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Empty(results); progressReported = true; completedTokenSource.CancelAfter(0); @@ -738,8 +738,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var expectedUris = new Uri[NUM_DOCUMENTS]; var virtualUris = new Uri[NUM_DOCUMENTS]; - var expectedReferences = new VSReferenceItem[NUM_BATCHES][]; - var csharpUnmappedReferences = new VSReferenceItem[NUM_BATCHES][]; + var expectedReferences = new VSInternalReferenceItem[NUM_BATCHES][]; + var csharpUnmappedReferences = new VSInternalReferenceItem[NUM_BATCHES][]; var parameterTokens = new JObject[NUM_BATCHES]; var token = Guid.NewGuid().ToString(); @@ -747,8 +747,8 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentNumber = 0; for (var batch = 0; batch < NUM_BATCHES; ++batch) { - expectedReferences[batch] = new VSReferenceItem[BATCH_SIZE]; - csharpUnmappedReferences[batch] = new VSReferenceItem[BATCH_SIZE]; + expectedReferences[batch] = new VSInternalReferenceItem[BATCH_SIZE]; + csharpUnmappedReferences[batch] = new VSInternalReferenceItem[BATCH_SIZE]; for (var documentInBatch = 0; documentInBatch < BATCH_SIZE; ++documentInBatch) { @@ -776,7 +776,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( + .Setup(r => r.ReinvokeRequestOnServerAsync( It.IsAny(), It.IsAny(), It.IsAny(), @@ -792,7 +792,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterTokens[i]); } }) - .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); + .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); var projectionResult = new ProjectionResult() { @@ -828,10 +828,10 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp referencesHandler.GetTestAccessor().WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; referencesHandler.GetTestAccessor().ImmediateNotificationTimeout = completedTokenSource.Token; - var progressBatchesReported = new ConcurrentBag(); + var progressBatchesReported = new ConcurrentBag(); var progressToken = new ProgressWithCompletion((val) => { - var results = Assert.IsType(val); + var results = Assert.IsType(val); Assert.Equal(BATCH_SIZE, results.Length); progressBatchesReported.Add(results); if (progressBatchesReported.Count == NUM_BATCHES) @@ -854,7 +854,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp Assert.True(lspFarEndpointCalled); var sortedBatchesReported = progressBatchesReported.ToList(); - sortedBatchesReported.Sort((VSReferenceItem[] a, VSReferenceItem[] b) => + sortedBatchesReported.Sort((VSInternalReferenceItem[] a, VSInternalReferenceItem[] b) => { var indexA = a[0].Location.Range.Start.Character; var indexB = b[0].Location.Range.Start.Character; @@ -867,14 +867,14 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { for (var documentInBatch = 0; documentInBatch < BATCH_SIZE; ++documentInBatch) { - AssertVSReferenceItem( + AssertVSInternalReferenceItem( expectedReferences[batch][documentInBatch], sortedBatchesReported[batch][documentInBatch]); } } } - private static bool AssertVSReferenceItem(VSReferenceItem expected, VSReferenceItem actual) + private static bool AssertVSInternalReferenceItem(VSInternalReferenceItem expected, VSInternalReferenceItem actual) { Assert.Equal(expected.Location, actual.Location); Assert.Equal(expected.DisplayPath, actual.DisplayPath); @@ -899,7 +899,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return true; } - private static (LSPRequestInvoker, LSPProgressListener) MockServices(VSReferenceItem csharpLocation, out string token) + private static (LSPRequestInvoker, LSPProgressListener) MockServices(VSInternalReferenceItem csharpLocation, out string token) { var languageServiceBroker = Mock.Of(MockBehavior.Strict); var lspProgressListener = new DefaultLSPProgressListener(languageServiceBroker); @@ -912,7 +912,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { "value", JArray.FromObject(new[] { csharpLocation }) } }; - requestInvoker.Setup(i => i.ReinvokeRequestOnServerAsync( + requestInvoker.Setup(i => i.ReinvokeRequestOnServerAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((method, clientName, definitionParams, ct) => { @@ -921,17 +921,17 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterToken); }) - .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); + .Returns(Task.FromResult(new ReinvokeResponse(_languageClient, Array.Empty()))); return (requestInvoker.Object, lspProgressListener); } - private static VSReferenceItem GetReferenceItem(int position, Uri uri, string text = "text") + private static VSInternalReferenceItem GetReferenceItem(int position, Uri uri, string text = "text") { return GetReferenceItem(position, position, position, position, uri, text); } - private static VSReferenceItem GetReferenceItem( + private static VSInternalReferenceItem GetReferenceItem( int startLine, int startCharacter, int endLine, @@ -941,7 +941,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp string documentName = "document", string projectName = "project") { - return new VSReferenceItem() + return new VSInternalReferenceItem() { Location = new Location() { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnTypeRenameHandlerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/LinkedEditingRangeHandlerTest.cs similarity index 75% rename from src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnTypeRenameHandlerTest.cs rename to src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/LinkedEditingRangeHandlerTest.cs index 47c582eb86..69badbf1e3 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnTypeRenameHandlerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/LinkedEditingRangeHandlerTest.cs @@ -13,7 +13,7 @@ using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp { - public class OnTypeRenameHandlerTest : HandlerTestBase + public class LinkedEditingRangeHandlerTest : HandlerTestBase { private static readonly Uri s_uri = new Uri("C:/path/to/file.razor"); @@ -27,15 +27,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var requestInvoker = Mock.Of(MockBehavior.Strict); var projectionProvider = Mock.Of(MockBehavior.Strict); var documentMappingProvider = Mock.Of(MockBehavior.Strict); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(0, 1) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); @@ -52,15 +52,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp Mock.Get(projectionProvider).Setup(projectionProvider => projectionProvider.GetProjectionAsync(It.IsAny(), It.IsAny(), CancellationToken.None)) .Returns(Task.FromResult(null)); var documentMappingProvider = Mock.Of(MockBehavior.Strict); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(0, 1) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); @@ -81,15 +81,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp }; var projectionProvider = GetProjectionProvider(projectionResult); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(10, 5) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); @@ -105,11 +105,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp documentManager.AddDocument(s_uri, Mock.Of(d => d.Version == 0, MockBehavior.Strict)); var htmlResponse = GetMatchingHTMLBracketRange(10); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( htmlResponse, (method, clientName, highlightParams, ct) => { - Assert.Equal(MSLSPMethods.OnTypeRenameName, method); + Assert.Equal(Methods.TextDocumentLinkedEditingRangeName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); invokerCalled = true; }); @@ -122,15 +122,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentMappingProvider = GetDocumentMappingProvider(expectedResponse.Ranges, 0, RazorLanguageKind.Html); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(10, 5) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokerCalled); @@ -150,11 +150,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp documentManager.AddDocument(s_uri, Mock.Of(d => d.Version == 1, MockBehavior.Strict)); var htmlResponse = GetMatchingHTMLBracketRange(10); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( htmlResponse, (method, clientName, highlightParams, ct) => { - Assert.Equal(MSLSPMethods.OnTypeRenameName, method); + Assert.Equal(Methods.TextDocumentLinkedEditingRangeName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); invokerCalled = true; }); @@ -167,15 +167,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentMappingProvider = GetDocumentMappingProvider(expectedResponse.Ranges, 0 /* Different from document version (1) */, RazorLanguageKind.Html); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(10, 5) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokerCalled); @@ -192,11 +192,11 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp documentManager.AddDocument(s_uri, Mock.Of(d => d.Version == 0, MockBehavior.Strict)); var htmlResponse = GetMatchingHTMLBracketRange(10); - var requestInvoker = GetRequestInvoker( + var requestInvoker = GetRequestInvoker( htmlResponse, (method, clientName, highlightParams, ct) => { - Assert.Equal(MSLSPMethods.OnTypeRenameName, method); + Assert.Equal(Methods.TextDocumentLinkedEditingRangeName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); invokerCalled = true; }); @@ -211,15 +211,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp Mock.Get(documentMappingProvider).Setup(p => p.MapToDocumentRangesAsync(RazorLanguageKind.Html, s_uri, It.IsAny(), CancellationToken.None)) .Returns(Task.FromResult(null)); - var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); - var onTypeRenameRequest = new DocumentOnTypeRenameParams() + var onLinkedEditingRangeHandler = new LinkedEditingRangeHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); + var onLinkedEditingRangeRequest = new LinkedEditingRangeParams() { TextDocument = new TextDocumentIdentifier() { Uri = s_uri }, Position = new Position(10, 5) }; // Act - var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); + var result = await onLinkedEditingRangeHandler.HandleRequestAsync(onLinkedEditingRangeRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokerCalled); @@ -259,9 +259,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp return documentMappingProvider.Object; } - private static DocumentOnTypeRenameResponseItem GetMatchingHTMLBracketRange(int line) + private static LinkedEditingRanges GetMatchingHTMLBracketRange(int line) { - return new DocumentOnTypeRenameResponseItem() + return new LinkedEditingRanges() { Ranges = new[] { new Range() diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnAutoInsertHandlerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnAutoInsertHandlerTest.cs index ef68bd86f5..1ec7fedc2a 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnAutoInsertHandlerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/OnAutoInsertHandlerTest.cs @@ -37,19 +37,19 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var invokedServer = false; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( + .Setup(r => r.ReinvokeRequestOnServerAsync( It.IsAny(), It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny())) - .Callback((method, clientName, formattingParams, ct) => invokedServer = true) - .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); + .Callback((method, clientName, formattingParams, ct) => invokedServer = true) + .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); var projectionProvider = Mock.Of(MockBehavior.Strict); var documentMappingProvider = Mock.Of(MockBehavior.Strict); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider, documentMappingProvider, LoggerProvider); - var request = new DocumentOnAutoInsertParams() + var request = new VSInternalDocumentOnAutoInsertParams() { Character = "?", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, @@ -77,19 +77,19 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var invokedServer = false; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( + .Setup(r => r.ReinvokeRequestOnServerAsync( It.IsAny(), It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny())) - .Callback((method, clientName, formattingParams, ct) => invokedServer = true) - .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); + .Callback((method, clientName, formattingParams, ct) => invokedServer = true) + .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); var projectionProvider = Mock.Of(MockBehavior.Strict); var documentMappingProvider = Mock.Of(MockBehavior.Strict); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider, documentMappingProvider, LoggerProvider); - var request = new DocumentOnAutoInsertParams() + var request = new VSInternalDocumentOnAutoInsertParams() { Character = ">", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, @@ -118,9 +118,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var invokedServer = false; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((method, clientName, formattingParams, ct) => invokedServer = true) - .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); + .Setup(r => r.ReinvokeRequestOnServerAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((method, clientName, formattingParams, ct) => invokedServer = true) + .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() }))); var projectionResult = new ProjectionResult() { @@ -131,7 +131,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var documentMappingProvider = Mock.Of(MockBehavior.Strict); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider, LoggerProvider); - var request = new DocumentOnAutoInsertParams() + var request = new VSInternalDocumentOnAutoInsertParams() { Character = ">", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, @@ -161,15 +161,15 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var mappedTextEdits = false; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( - MSLSPMethods.OnAutoInsertName, + .Setup(r => r.ReinvokeRequestOnServerAsync( + VSInternalMethods.OnAutoInsertName, It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny())) - .Callback((method, serverContentType, formattingParams, ct) => invokedServer = true) - .Returns(Task.FromResult(new ReinvokeResponse( + .Callback((method, serverContentType, formattingParams, ct) => invokedServer = true) + .Returns(Task.FromResult(new ReinvokeResponse( languageClient: _languageClient, - new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" }, TextEditFormat = InsertTextFormat.Snippet }))); + new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" }, TextEditFormat = InsertTextFormat.Snippet }))); var projectionUri = new Uri(Uri.AbsoluteUri + "__virtual.html"); var projectionResult = new ProjectionResult() @@ -187,7 +187,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp .Returns(Task.FromResult(new[] { new TextEdit() })); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider.Object, LoggerProvider); - var request = new DocumentOnAutoInsertParams() + var request = new VSInternalDocumentOnAutoInsertParams() { Character = "=", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, @@ -218,13 +218,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp var mappedTextEdits = false; var requestInvoker = new Mock(MockBehavior.Strict); requestInvoker - .Setup(r => r.ReinvokeRequestOnServerAsync( - MSLSPMethods.OnAutoInsertName, + .Setup(r => r.ReinvokeRequestOnServerAsync( + VSInternalMethods.OnAutoInsertName, It.IsAny(), - It.IsAny(), + It.IsAny(), It.IsAny())) - .Callback((method, clientName, formattingParams, ct) => invokedServer = true) - .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" }, TextEditFormat = InsertTextFormat.Snippet }))); + .Callback((method, clientName, formattingParams, ct) => invokedServer = true) + .Returns(Task.FromResult(new ReinvokeResponse(languageClient: _languageClient, new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" }, TextEditFormat = InsertTextFormat.Snippet }))); var projectionUri = new Uri(Uri.AbsoluteUri + "__virtual.html"); var projectionResult = new ProjectionResult() @@ -242,7 +242,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp .Returns(Task.FromResult(new[] { new TextEdit() { NewText = "mapped-sometext" } })); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider.Object, LoggerProvider); - var request = new DocumentOnAutoInsertParams() + var request = new VSInternalDocumentOnAutoInsertParams() { Character = "/", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/TestLanguageServiceBroker.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/TestLanguageServiceBroker.cs index 6bbf819676..4ba8768f65 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/TestLanguageServiceBroker.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/HtmlCSharp/TestLanguageServiceBroker.cs @@ -60,23 +60,17 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.HtmlCSharp public IRequestBroker FoldingRangeBroker => throw new NotImplementedException(); - public IRequestBroker ProjectContextBroker => throw new NotImplementedException(); - public IEnumerable> FactoryLanguageClients => throw new NotImplementedException(); public IEnumerable> LanguageClients => throw new NotImplementedException(); - public IRequestBroker OnAutoInsertBroker => throw new NotImplementedException(); + IStreamingRequestBroker ILanguageServiceBroker.DocumentDiagnosticsBroker => throw new NotImplementedException(); - public IRequestBroker OnTypeRenameBroker => throw new NotImplementedException(); + IStreamingRequestBroker ILanguageServiceBroker.WorkspaceDiagnosticsBroker => throw new NotImplementedException(); - public IRequestBroker CodeActionsResolveBroker => throw new NotImplementedException(); + IRequestBroker ILanguageServiceBroker.ProjectContextBroker => throw new NotImplementedException(); - public IStreamingRequestBroker DocumentDiagnosticsBroker => throw new NotImplementedException(); - - public IStreamingRequestBroker WorkspaceDiagnosticsBroker => throw new NotImplementedException(); - - public IRequestBroker KindDescriptionResolveBroker => throw new NotImplementedException(); + IRequestBroker ILanguageServiceBroker.KindDescriptionResolveBroker => throw new NotImplementedException(); public TestLanguageServiceBroker(Action callback) { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorDocumentOptionsServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorDocumentOptionsServiceTest.cs new file mode 100644 index 0000000000..e6c746ba75 --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorDocumentOptionsServiceTest.cs @@ -0,0 +1,119 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Razor; +using Microsoft.CodeAnalysis.Razor.Editor; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Test +{ + public class RazorDocumentOptionsServiceTest : WorkspaceTestBase + { + [Fact] + public async Task RazorDocumentOptionsService_ReturnsCorrectOptions_UseTabs() + { + // Arrange + var editorSettings = new EditorSettings(indentWithTabs: true, indentSize: 4); + var clientOptionsMonitor = new RazorLSPClientOptionsMonitor(); + clientOptionsMonitor.UpdateOptions(editorSettings); + var optionsService = new RazorDocumentOptionsService(clientOptionsMonitor); + + var document = InitializeDocument(SourceText.From("text")); + + var useTabsOptionKey = GetUseTabsOptionKey(document); + var tabSizeOptionKey = GetTabSizeOptionKey(document); + var indentationSizeOptionKey = GetIndentationSizeOptionKey(document); + + // Act + var documentOptions = await optionsService.GetOptionsForDocumentAsync(document, CancellationToken.None); + documentOptions.TryGetDocumentOption(useTabsOptionKey, out var useTabs); + documentOptions.TryGetDocumentOption(tabSizeOptionKey, out var tabSize); + documentOptions.TryGetDocumentOption(indentationSizeOptionKey, out var indentationSize); + + // Assert + Assert.True((bool)useTabs); + Assert.Equal(4, (int)tabSize); + Assert.Equal(4, (int)indentationSize); + } + + [Fact] + public async Task RazorDocumentOptionsService_ReturnsCorrectOptions_UseSpaces() + { + // Arrange + var editorSettings = new EditorSettings(indentWithTabs: false, indentSize: 2); + var clientOptionsMonitor = new RazorLSPClientOptionsMonitor(); + clientOptionsMonitor.UpdateOptions(editorSettings); + var optionsService = new RazorDocumentOptionsService(clientOptionsMonitor); + + var document = InitializeDocument(SourceText.From("text")); + + var useTabsOptionKey = GetUseTabsOptionKey(document); + var tabSizeOptionKey = GetTabSizeOptionKey(document); + var indentationSizeOptionKey = GetIndentationSizeOptionKey(document); + + // Act + var documentOptions = await optionsService.GetOptionsForDocumentAsync(document, CancellationToken.None); + documentOptions.TryGetDocumentOption(useTabsOptionKey, out var useTabs); + documentOptions.TryGetDocumentOption(tabSizeOptionKey, out var tabSize); + documentOptions.TryGetDocumentOption(indentationSizeOptionKey, out var indentationSize); + + // Assert + Assert.False((bool)useTabs); + Assert.Equal(2, (int)tabSize); + Assert.Equal(2, (int)indentationSize); + } + + private static OptionKey GetUseTabsOptionKey(Document document) + => new OptionKey(FormattingOptions.UseTabs, document.Project.Language); + + private static OptionKey GetTabSizeOptionKey(Document document) + => new OptionKey(FormattingOptions.TabSize, document.Project.Language); + + private static OptionKey GetIndentationSizeOptionKey(Document document) + => new OptionKey(FormattingOptions.IndentationSize, document.Project.Language); + + // Adapted from DocumentExcerptServiceTestBase's InitializeDocument. + // Adds the text to a ProjectSnapshot, generates code, and updates the workspace. + private Document InitializeDocument(SourceText sourceText) + { + var baseDirectory = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "c:\\users\\example\\src" : "/home/example"; + var hostProject = new HostProject( + Path.Combine(baseDirectory, "SomeProject", "SomeProject.csproj"), RazorConfiguration.Default, "SomeProject"); + var hostDocument = new HostDocument( + Path.Combine(baseDirectory, "SomeProject", "File1.cshtml"), "File1.cshtml", FileKinds.Legacy); + + var project = new DefaultProjectSnapshot( + ProjectState.Create(Workspace.Services, hostProject) + .WithAddedHostDocument(hostDocument, () => Task.FromResult(TextAndVersion.Create(sourceText, VersionStamp.Create())))); + + var documentSnapshot = project.GetDocument(hostDocument.FilePath); + + var solution = Workspace.CurrentSolution.AddProject(ProjectInfo.Create( + ProjectId.CreateNewId(Path.GetFileNameWithoutExtension(hostDocument.FilePath)), + VersionStamp.Create(), + Path.GetFileNameWithoutExtension(hostDocument.FilePath), + Path.GetFileNameWithoutExtension(hostDocument.FilePath), + LanguageNames.CSharp, + hostDocument.FilePath)); + + solution = solution.AddDocument( + DocumentId.CreateNewId(solution.ProjectIds.Single(), hostDocument.FilePath), + hostDocument.FilePath, + new GeneratedDocumentTextLoader(documentSnapshot, hostDocument.FilePath)); + + var document = solution.Projects.Single().Documents.Single(); + return document; + } + } +} diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorHtmlPublishDiagnosticsInterceptorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorHtmlPublishDiagnosticsInterceptorTest.cs index a398f327ae..87e9780545 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorHtmlPublishDiagnosticsInterceptorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServerClient.Razor.Test/RazorHtmlPublishDiagnosticsInterceptorTest.cs @@ -96,10 +96,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_razorUri }; var token = JToken.FromObject(diagnosticRequest); @@ -120,10 +119,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_cshtmlUri }; var token = JToken.FromObject(diagnosticRequest); @@ -144,10 +142,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_razorVirtualCssUri }; var token = JToken.FromObject(diagnosticRequest); @@ -168,10 +165,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_razorVirtualHtmlUri }; @@ -179,7 +175,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var result = await htmlDiagnosticsInterceptor.ApplyChangesAsync(JToken.FromObject(diagnosticRequest), string.Empty, cancellationToken: default).ConfigureAwait(false); // Assert - var updatedParams = result.UpdatedToken.ToObject(); + var updatedParams = result.UpdatedToken.ToObject(); Assert.Empty(updatedParams.Diagnostics); Assert.Equal(s_razorUri, updatedParams.Uri); Assert.True(result.ChangedDocumentUri); @@ -198,10 +194,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor .Returns(true); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager.Object, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_razorVirtualHtmlUri }; @@ -209,7 +204,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var result = await htmlDiagnosticsInterceptor.ApplyChangesAsync(JToken.FromObject(diagnosticRequest), string.Empty, cancellationToken: default).ConfigureAwait(false); // Assert - var updatedParams = result.UpdatedToken.ToObject(); + var updatedParams = result.UpdatedToken.ToObject(); Assert.Empty(updatedParams.Diagnostics); Assert.Equal(s_razorUri, updatedParams.Uri); Assert.True(result.ChangedDocumentUri); @@ -223,10 +218,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = Mock.Of(MockBehavior.Strict); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = Array.Empty(), - Mode = null, Uri = s_razorVirtualHtmlUri }; @@ -234,7 +228,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var result = await htmlDiagnosticsInterceptor.ApplyChangesAsync(JToken.FromObject(diagnosticRequest), string.Empty, cancellationToken: default).ConfigureAwait(false); // Assert - var updatedParams = result.UpdatedToken.ToObject(); + var updatedParams = result.UpdatedToken.ToObject(); Assert.Empty(updatedParams.Diagnostics); Assert.Equal(s_razorUri, updatedParams.Uri); Assert.True(result.ChangedDocumentUri); @@ -248,10 +242,9 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var diagnosticsProvider = GetDiagnosticsProvider(); var htmlDiagnosticsInterceptor = new RazorHtmlPublishDiagnosticsInterceptor(documentManager, diagnosticsProvider, LoggerProvider); - var diagnosticRequest = new VSPublishDiagnosticParams() + var diagnosticRequest = new PublishDiagnosticParams() { Diagnostics = s_diagnostics, - Mode = null, Uri = s_razorVirtualHtmlUri }; @@ -259,7 +252,7 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor var result = await htmlDiagnosticsInterceptor.ApplyChangesAsync(JToken.FromObject(diagnosticRequest), string.Empty, cancellationToken: default).ConfigureAwait(false); // Assert - var updatedParams = result.UpdatedToken.ToObject(); + var updatedParams = result.UpdatedToken.ToObject(); Assert.Equal(s_diagnostics, updatedParams.Diagnostics); Assert.Equal(s_razorUri, updatedParams.Uri); Assert.True(result.ChangedDocumentUri); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs index d4fd4bce3e..aa6502e4d1 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DocumentGenerator/BackgroundDocumentGeneratorTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { // These tests are really integration tests. There isn't a good way to unit test this functionality since // the only thing in here is threading. - public class BackgroundDocumentGeneratorTest : ForegroundDispatcherWorkspaceTestBase + public class BackgroundDocumentGeneratorTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase { public BackgroundDocumentGeneratorTest() { @@ -45,7 +45,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem builder.SetImportFeature(new TestImportProjectFeature()); } - [ForegroundFact] + [UIFact] public async Task ProcessDocument_LongDocumentParse_DoesNotUpdateAfterSuppress() { // Arrange @@ -91,7 +91,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(DynamicFileInfoProvider.DynamicDocuments[hostDocument.FilePath]); } - [ForegroundFact] + [UIFact] public async Task ProcessDocument_SwallowsIOExceptions() { // Arrange @@ -122,7 +122,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.False(queue.NotifyErrorBeingReported.IsSet); } - [ForegroundFact] + [UIFact] public async Task ProcessDocument_SwallowsUnauthorizedAccessExceptions() { // Arrange @@ -153,7 +153,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.False(queue.NotifyErrorBeingReported.IsSet); } - [ForegroundFact] + [UIFact] public async Task Queue_ProcessesNotifications_AndGoesBackToSleep() { // Arrange @@ -192,7 +192,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); } - [ForegroundFact] + [UIFact] public async Task Queue_ProcessesNotifications_AndRestarts() { // Arrange @@ -255,7 +255,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications"); } - [ForegroundFact(Skip = "https://github.com/dotnet/aspnetcore/issues/14805")] + [UIFact(Skip = "https://github.com/dotnet/aspnetcore/issues/14805")] public async Task DocumentChanged_ReparsesRelatedFiles() { // Arrange @@ -318,7 +318,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted"); } - [ForegroundFact] + [UIFact] public async Task DocumentRemoved_ReparsesRelatedFiles() { // Arrange diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/VisualStudioFileChangeTrackerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/VisualStudioFileChangeTrackerTest.cs index 89fc33fe89..856aa016b4 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/VisualStudioFileChangeTrackerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Documents/VisualStudioFileChangeTrackerTest.cs @@ -13,19 +13,11 @@ using Task = System.Threading.Tasks.Task; namespace Microsoft.VisualStudio.Editor.Razor.Documents { - public class VisualStudioFileChangeTrackerTest : ForegroundDispatcherTestBase + public class VisualStudioFileChangeTrackerTest : ProjectSnapshotManagerDispatcherTestBase { - public VisualStudioFileChangeTrackerTest() - { - var joinableTaskContext = new JoinableTaskContextNode(new JoinableTaskContext()); - JoinableTaskFactory = new JoinableTaskFactory(joinableTaskContext.Context); - } - private ErrorReporter ErrorReporter { get; } = new DefaultErrorReporter(); - private JoinableTaskFactory JoinableTaskFactory { get; } - - [ForegroundFact] + [UIFact] public async Task StartListening_AdvisesForFileChange() { // Arrange @@ -34,7 +26,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents .Setup(f => f.AdviseFileChangeAsync(It.IsAny(), It.IsAny<_VSFILECHANGEFLAGS>(), It.IsAny(), It.IsAny())) .Returns(Task.FromResult(123)) .Verifiable(); - var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, Dispatcher, ErrorReporter, fileChangeService.Object, JoinableTaskFactory); + var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, ErrorReporter, fileChangeService.Object, Dispatcher, JoinableTaskFactory.Context); // Act tracker.StartListening(); @@ -44,7 +36,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents fileChangeService.Verify(); } - [ForegroundFact] + [UIFact] public async Task StartListening_AlreadyListening_DoesNothing() { // Arrange @@ -54,7 +46,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents .Setup(f => f.AdviseFileChangeAsync(It.IsAny(), It.IsAny<_VSFILECHANGEFLAGS>(), It.IsAny(), It.IsAny())) .Returns(Task.FromResult(123)) .Callback(() => callCount++); - var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, Dispatcher, ErrorReporter, fileChangeService.Object, JoinableTaskFactory); + var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, ErrorReporter, fileChangeService.Object, Dispatcher, JoinableTaskFactory.Context); tracker.StartListening(); // Act @@ -65,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Equal(1, callCount); } - [ForegroundFact] + [UIFact] public async Task StopListening_UnadvisesForFileChange() { // Arrange @@ -77,7 +69,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents fileChangeService .Setup(f => f.UnadviseFileChangeAsync(123, It.IsAny())) .Verifiable(); - var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, Dispatcher, ErrorReporter, fileChangeService.Object, JoinableTaskFactory); + var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, ErrorReporter, fileChangeService.Object, Dispatcher, JoinableTaskFactory.Context); tracker.StartListening(); // Start listening for changes. await tracker._fileChangeAdviseTask; @@ -89,7 +81,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents fileChangeService.Verify(); } - [ForegroundFact] + [UIFact] public void StopListening_NotListening_DoesNothing() { // Arrange @@ -97,7 +89,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents fileChangeService .Setup(f => f.UnadviseFileChangeAsync(123, It.IsAny())) .Throws(new InvalidOperationException()); - var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, Dispatcher, ErrorReporter, fileChangeService.Object, JoinableTaskFactory); + var tracker = new VisualStudioFileChangeTracker(TestProjectData.SomeProjectImportFile.FilePath, ErrorReporter, fileChangeService.Object, Dispatcher, JoinableTaskFactory.Context); // Act tracker.StopListening(); @@ -106,7 +98,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents Assert.Null(tracker._fileChangeUnadviseTask); } - [ForegroundTheory] + [UITheory] [InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Size, (int)FileChangeKind.Changed)] [InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Time, (int)FileChangeKind.Changed)] [InlineData((uint)_VSFILECHANGEFLAGS.VSFILECHG_Add, (int)FileChangeKind.Added)] @@ -116,7 +108,7 @@ namespace Microsoft.VisualStudio.Editor.Razor.Documents // Arrange var filePath = TestProjectData.SomeProjectImportFile.FilePath; var fileChangeService = Mock.Of(MockBehavior.Strict); - var tracker = new VisualStudioFileChangeTracker(filePath, Dispatcher, ErrorReporter, fileChangeService, JoinableTaskFactory); + var tracker = new VisualStudioFileChangeTracker(filePath, ErrorReporter, fileChangeService, Dispatcher, JoinableTaskFactory.Context); var called = false; tracker.Changed += (sender, args) => diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultProjectSnapshotManagerTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultProjectSnapshotManagerTest.cs index a0a701fdae..7d85dba0de 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultProjectSnapshotManagerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultProjectSnapshotManagerTest.cs @@ -13,7 +13,7 @@ using Xunit; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { - public class DefaultProjectSnapshotManagerTest : ForegroundDispatcherWorkspaceTestBase + public class DefaultProjectSnapshotManagerTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase { public DefaultProjectSnapshotManagerTest() { @@ -72,7 +72,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem services.Add(TagHelperResolver); } - [ForegroundFact] + [UIFact] public void Initialize_DoneInCorrectOrderBasedOnInitializePriorityPriority() { // Arrange @@ -90,7 +90,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(new[] { "highPriority", "lowPriority" }, initializedOrder); } - [ForegroundFact] + [UIFact] public void DocumentAdded_AddsDocument() { // Arrange @@ -107,7 +107,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.DocumentAdded, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentAdded_AddsDocument_Legacy() { // Arrange @@ -130,7 +130,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.DocumentAdded, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentAdded_AddsDocument_Component() { // Arrange @@ -153,7 +153,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.DocumentAdded, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentAdded_IgnoresDuplicate() { // Arrange @@ -171,7 +171,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentAdded_IgnoresUnknownProject() { // Arrange @@ -184,7 +184,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(snapshot); } - [ForegroundFact] + [UIFact] public async Task DocumentAdded_NullLoader_HasEmptyText() { // Arrange @@ -202,7 +202,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(0, text.Length); } - [ForegroundFact] + [UIFact] public async Task DocumentAdded_WithLoader_LoadesText() { // Arrange @@ -222,7 +222,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(expected, actual); } - [ForegroundFact] + [UIFact] public void DocumentAdded_CachesTagHelpers() { // Arrange @@ -240,7 +240,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(originalTagHelpers, newTagHelpers); } - [ForegroundFact] + [UIFact] public void DocumentAdded_CachesProjectEngine() { // Arrange @@ -258,7 +258,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(projectEngine, snapshot.GetProjectEngine()); } - [ForegroundFact] + [UIFact] public void DocumentRemoved_RemovesDocument() { // Arrange @@ -281,7 +281,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.DocumentRemoved, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentRemoved_IgnoresNotFoundDocument() { // Arrange @@ -298,7 +298,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void DocumentRemoved_IgnoresUnknownProject() { // Arrange @@ -311,7 +311,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(snapshot); } - [ForegroundFact] + [UIFact] public void DocumentRemoved_CachesTagHelpers() { // Arrange @@ -332,7 +332,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(originalTagHelpers, newTagHelpers); } - [ForegroundFact] + [UIFact] public void DocumentRemoved_CachesProjectEngine() { // Arrange @@ -352,7 +352,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem snapshot = ProjectManager.GetSnapshot(HostProject); Assert.Same(projectEngine, snapshot.GetProjectEngine()); } - [ForegroundFact] + [UIFact] public async Task DocumentOpened_UpdatesDocument() { // Arrange @@ -373,7 +373,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.True(ProjectManager.IsDocumentOpen(Documents[0].FilePath)); } - [ForegroundFact] + [UIFact] public async Task DocumentClosed_UpdatesDocument() { // Arrange @@ -400,7 +400,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem } - [ForegroundFact] + [UIFact] public async Task DocumentClosed_AcceptsChange() { // Arrange @@ -422,7 +422,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(expected, text); } - [ForegroundFact] + [UIFact] public async Task DocumentChanged_Snapshot_UpdatesDocument() { // Arrange @@ -444,7 +444,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(expected, text); } - [ForegroundFact] + [UIFact] public async Task DocumentChanged_Loader_UpdatesDocument() { // Arrange @@ -467,7 +467,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Same(expected, text); } - [ForegroundFact] + [UIFact] public void ProjectAdded_WithoutWorkspaceProject_NotifiesListeners() { // Arrange @@ -479,7 +479,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectAdded, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectConfigurationChanged_ConfigurationChange_ProjectWorkspaceState_NotifiesListeners() { // Arrange @@ -493,7 +493,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectChanged, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectConfigurationChanged_ConfigurationChange_WithProjectWorkspaceState_NotifiesListeners() { // Arrange @@ -508,7 +508,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectChanged, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectConfigurationChanged_ConfigurationChange_DoesNotCacheProjectEngine() { // Arrange @@ -526,7 +526,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.NotSame(projectEngine, snapshot.GetProjectEngine()); } - [ForegroundFact] + [UIFact] public void ProjectConfigurationChanged_IgnoresUnknownProject() { // Arrange @@ -540,7 +540,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectRemoved_RemovesProject_NotifiesListeners() { // Arrange @@ -556,7 +556,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectRemoved, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectWorkspaceStateChanged_WithoutHostProject_IgnoresWorkspaceState() { // Arrange @@ -570,7 +570,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Null(ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void ProjectWorkspaceStateChanged_WithHostProject_FirstTime_NotifiesListenters() { // Arrange @@ -584,7 +584,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectChanged, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void WorkspaceProjectChanged_WithHostProject_NotifiesListenters() { // Arrange @@ -599,7 +599,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(ProjectChangeKind.ProjectChanged, ProjectManager.ListenersNotifiedOf); } - [ForegroundFact] + [UIFact] public void NestedNotifications_NotifiesListenersInCorrectOrder() { // Arrange @@ -631,7 +631,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private class TestProjectSnapshotManager : DefaultProjectSnapshotManager { - public TestProjectSnapshotManager(ForegroundDispatcher dispatcher, IEnumerable triggers, Workspace workspace) + public TestProjectSnapshotManager(ProjectSnapshotManagerDispatcher dispatcher, IEnumerable triggers, Workspace workspace) : base(dispatcher, Mock.Of(MockBehavior.Strict), triggers, workspace) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultRazorProjectHostTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultRazorProjectHostTest.cs index 288f7d0e71..6dd079b7d1 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultRazorProjectHostTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/DefaultRazorProjectHostTest.cs @@ -10,14 +10,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.VisualStudio.ProjectSystem; using Microsoft.VisualStudio.ProjectSystem.Properties; -using Microsoft.VisualStudio.Threading; using Moq; using Xunit; using ItemCollection = Microsoft.VisualStudio.ProjectSystem.ItemCollection; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { - public class DefaultRazorProjectHostTest : ForegroundDispatcherWorkspaceTestBase + public class DefaultRazorProjectHostTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase { public DefaultRazorProjectHostTest() { @@ -32,8 +31,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem RazorComponentWithTargetPathItems = new ItemCollection(Rules.RazorComponentWithTargetPath.SchemaName); RazorGenerateWithTargetPathItems = new ItemCollection(Rules.RazorGenerateWithTargetPath.SchemaName); RazorGeneralProperties = new PropertyCollection(Rules.RazorGeneral.SchemaName); - - JoinableTaskContext = new JoinableTaskContext(); } private ItemCollection ConfigurationItems { get; } @@ -50,8 +47,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private TestProjectSnapshotManager ProjectManager { get; } - private JoinableTaskContext JoinableTaskContext { get; } - [Fact] public void TryGetDefaultConfiguration_FailsIfNoRule() { @@ -618,12 +613,12 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem extension => Assert.Equal(expectedExtension2Name, extension.ExtensionName)); } - [ForegroundFact] - public async Task DefaultRazorProjectHost_ForegroundThread_CreateAndDispose_Succeeds() + [UIFact] + public async Task DefaultRazorProjectHost_UIThread_CreateAndDispose_Succeeds() { // Arrange var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); // Act & Assert await host.LoadAsync(); @@ -633,12 +628,12 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task DefaultRazorProjectHost_BackgroundThread_CreateAndDispose_Succeeds() { // Arrange var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); // Act & Assert await Task.Run(async () => await host.LoadAsync()); @@ -648,7 +643,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] // This can happen if the .xaml files aren't included correctly. + [UIFact] // This can happen if the .xaml files aren't included correctly. public async Task DefaultRazorProjectHost_OnProjectChanged_NoRulesDefined() { // Arrange @@ -657,7 +652,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); // Act & Assert await Task.Run(async () => await host.LoadAsync()); @@ -667,7 +662,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - // [ForegroundFact] + // [UIFact] // public async Task OnProjectChanged_ReadsProperties_InitializesProject() // { // // Arrange @@ -737,7 +732,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem // Assert.Empty(ProjectManager.Projects); // } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_NoVersionFound_DoesNotIniatializeProject() { // Arrange @@ -760,8 +755,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -776,7 +770,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_UpdateProject_Succeeds() { // Arrange @@ -808,8 +802,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -930,7 +923,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_VersionRemoved_DeinitializesProject() { // Arrange @@ -959,8 +952,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -1001,7 +993,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_AfterDispose_IgnoresUpdate() { // Arrange @@ -1030,8 +1022,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -1076,7 +1067,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectRenamed_RemovesHostProject_CopiesConfiguration() { // Arrange @@ -1106,7 +1097,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices(TestProjectData.SomeProject.FilePath); - var host = new DefaultRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new DefaultRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -1134,7 +1125,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private class TestProjectSnapshotManager : DefaultProjectSnapshotManager { - public TestProjectSnapshotManager(ForegroundDispatcher dispatcher, Workspace workspace) + public TestProjectSnapshotManager(ProjectSnapshotManagerDispatcher dispatcher, Workspace workspace) : base(dispatcher, Mock.Of(MockBehavior.Strict), Array.Empty(), workspace) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackRazorProjectHostTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackRazorProjectHostTest.cs index f3e7866838..1a6ca86985 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackRazorProjectHostTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/FallbackRazorProjectHostTest.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.VisualStudio.ProjectSystem; -using Microsoft.VisualStudio.Threading; using Moq; using Xunit; using ItemCollection = Microsoft.VisualStudio.ProjectSystem.ItemCollection; @@ -15,7 +14,7 @@ using ItemReference = Microsoft.CodeAnalysis.Razor.ProjectSystem.ManagedProjectS namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { - public class FallbackRazorProjectHostTest : ForegroundDispatcherWorkspaceTestBase + public class FallbackRazorProjectHostTest : ProjectSnapshotManagerDispatcherWorkspaceTestBase { public FallbackRazorProjectHostTest() { @@ -28,8 +27,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem ReferenceItems = new ItemCollection(ManagedProjectSystemSchema.ResolvedCompilationReference.SchemaName); ContentItems = new ItemCollection(ManagedProjectSystemSchema.ContentItem.SchemaName); NoneItems = new ItemCollection(ManagedProjectSystemSchema.NoneItem.SchemaName); - - JoinableTaskContext = new JoinableTaskContext(); } private ItemCollection ReferenceItems { get; } @@ -42,8 +39,6 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private ItemCollection NoneItems { get; } - private JoinableTaskContext JoinableTaskContext { get; } - [Fact] public void GetChangedAndRemovedDocuments_ReturnsChangedContentAndNoneItems() { @@ -62,7 +57,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }); var services = new TestProjectSystemServices("C:\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var changes = new TestProjectChangeDescription[] { afterChangeContentItems.ToChange(ContentItems.ToSnapshot()), @@ -104,7 +99,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }); var services = new TestProjectSystemServices("C:\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var changes = new TestProjectChangeDescription[] { ContentItems.ToChange(), @@ -147,7 +142,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }); var services = new TestProjectSystemServices("C:\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var changes = new TestProjectChangeDescription[] { ContentItems.ToChange(), @@ -168,7 +163,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem // Arrange var services = new TestProjectSystemServices("C:\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.LinkPropertyName] = "Index.cshtml", @@ -188,7 +183,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem // Arrange var services = new TestProjectSystemServices("C:\\Path\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.FullPathPropertyName] = "C:\\Path\\site.css", @@ -208,7 +203,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem // Arrange var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.LinkPropertyName] = "site.html", @@ -230,7 +225,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var expectedPath = "C:\\Path\\Index.cshtml"; var services = new TestProjectSystemServices("C:\\Path\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.FullPathPropertyName] = expectedPath, @@ -253,7 +248,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var expectedTargetPath = "C:\\Path\\To\\Index.cshtml"; var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.LinkPropertyName] = "Index.cshtml", @@ -277,7 +272,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var expectedTargetPath = "C:\\Path\\To\\Index.cshtml"; var services = new TestProjectSystemServices("C:\\Path\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); var itemState = new Dictionary() { [ItemReference.LinkPropertyName] = "Index.cshtml", @@ -294,13 +289,13 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(FileKinds.Legacy, document.FileKind); } - [ForegroundFact] - public async Task FallbackRazorProjectHost_ForegroundThread_CreateAndDispose_Succeeds() + [UIFact] + public async Task FallbackRazorProjectHost_UIThread_CreateAndDispose_Succeeds() { // Arrange var services = new TestProjectSystemServices("C:\\To\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); // Act & Assert await host.LoadAsync(); @@ -310,13 +305,13 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task FallbackRazorProjectHost_BackgroundThread_CreateAndDispose_Succeeds() { // Arrange var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); // Act & Assert await Task.Run(async () => await host.LoadAsync()); @@ -326,7 +321,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] // This can happen if the .xaml files aren't included correctly. + [UIFact] // This can happen if the .xaml files aren't included correctly. public async Task OnProjectChanged_NoRulesDefined() { // Arrange @@ -336,7 +331,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), }; @@ -349,7 +344,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_ReadsProperties_InitializesProject() { // Arrange @@ -372,7 +367,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("C:\\Path\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), // Mock for reading the assembly's version }; @@ -397,7 +392,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_NoAssemblyFound_DoesNotIniatializeProject() { // Arrange @@ -407,7 +402,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem }; var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -422,7 +417,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_AssemblyFoundButCannotReadVersion_DoesNotIniatializeProject() { // Arrange @@ -435,7 +430,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager); + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager); await Task.Run(async () => await host.LoadAsync()); Assert.Empty(ProjectManager.Projects); @@ -450,7 +445,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_UpdateProject_Succeeds() { // Arrange @@ -474,7 +469,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("C:\\Path\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), }; @@ -506,7 +501,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_VersionRemoved_DeinitializesProject() { // Arrange @@ -519,7 +514,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), }; @@ -546,7 +541,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectChanged_AfterDispose_IgnoresUpdate() { // Arrange @@ -564,7 +559,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("C:\\Path\\Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), }; @@ -596,7 +591,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(ProjectManager.Projects); } - [ForegroundFact] + [UIFact] public async Task OnProjectRenamed_RemovesHostProject_CopiesConfiguration() { // Arrange @@ -609,7 +604,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem var services = new TestProjectSystemServices("Test.csproj"); - var host = new TestFallbackRazorProjectHost(services, Workspace, ProjectConfigurationFilePathStore, ProjectManager) + var host = new TestFallbackRazorProjectHost(services, Workspace, Dispatcher, ProjectConfigurationFilePathStore, ProjectManager) { AssemblyVersion = new Version(2, 0), // Mock for reading the assembly's version }; @@ -640,8 +635,13 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private class TestFallbackRazorProjectHost : FallbackRazorProjectHost { - internal TestFallbackRazorProjectHost(IUnconfiguredProjectCommonServices commonServices, Workspace workspace, ProjectConfigurationFilePathStore projectConfigurationFilePathStore, ProjectSnapshotManagerBase projectManager) - : base(commonServices, workspace, projectConfigurationFilePathStore, projectManager) + internal TestFallbackRazorProjectHost( + IUnconfiguredProjectCommonServices commonServices, + Workspace workspace, + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + ProjectConfigurationFilePathStore projectConfigurationFilePathStore, + ProjectSnapshotManagerBase projectManager) + : base(commonServices, workspace, projectSnapshotManagerDispatcher, projectConfigurationFilePathStore, projectManager) { } @@ -655,7 +655,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private class TestProjectSnapshotManager : DefaultProjectSnapshotManager { - public TestProjectSnapshotManager(ForegroundDispatcher dispatcher, Workspace workspace) + public TestProjectSnapshotManager(ProjectSnapshotManagerDispatcher dispatcher, Workspace workspace) : base(dispatcher, Mock.Of(MockBehavior.Strict), Array.Empty(), workspace) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs index dc45f28cff..9e3d50c6b2 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/ProjectSystem/WorkspaceProjectStateChangeDetectorTest.cs @@ -7,15 +7,19 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.Razor.Test; +using Microsoft.VisualStudio.Threading; using Moq; using Xunit; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem { - public class WorkspaceProjectStateChangeDetectorTest : ForegroundDispatcherWorkspaceTestBase + public class WorkspaceProjectStateChangeDetectorTest : WorkspaceTestBase { + private static readonly ProjectSnapshotManagerDispatcher Dispatcher = new DefaultProjectSnapshotManagerDispatcher(); + public WorkspaceProjectStateChangeDetectorTest() { EmptySolution = Workspace.CurrentSolution.GetIsolatedSolution(); @@ -59,6 +63,34 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem LanguageNames.CSharp, filePath: "Three.csproj")); + var project2Reference = new ProjectReference(projectId2); + var project3Reference = new ProjectReference(projectId3); + SolutionWithDependentProject = Workspace.CurrentSolution + .AddProject(ProjectInfo.Create( + projectId1, + VersionStamp.Default, + "One", + "One", + LanguageNames.CSharp, + filePath: "One.csproj", + documents: new[] { cshtmlDocumentInfo, razorDocumentInfo, partialComponentClassDocumentInfo, backgroundDocumentInfo }, + projectReferences: new[] { project2Reference })) + .AddProject(ProjectInfo.Create( + projectId2, + VersionStamp.Default, + "Two", + "Two", + LanguageNames.CSharp, + filePath: "Two.csproj", + projectReferences: new[] { project3Reference })) + .AddProject(ProjectInfo.Create( + projectId3, + VersionStamp.Default, + "Three", + "Three", + LanguageNames.CSharp, + filePath: "Three.csproj")); + ProjectNumberOne = SolutionWithTwoProjects.GetProject(projectId1); ProjectNumberTwo = SolutionWithTwoProjects.GetProject(projectId2); ProjectNumberThree = SolutionWithOneProject.GetProject(projectId3); @@ -80,6 +112,8 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem private Solution SolutionWithTwoProjects { get; } + private Solution SolutionWithDependentProject { get; } + private Project ProjectNumberOne { get; } private Project ProjectNumberTwo { get; } @@ -94,25 +128,75 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem public DocumentId PartialComponentClassDocumentId { get; } - [ForegroundTheory] + [UIFact] + public async Task WorkspaceChanged_ProjectEvents_EnqueuesUpdatesForDependentProjects() + { + // Arrange + var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) + { + NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), + }; + + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + + await Dispatcher.RunOnDispatcherThreadAsync(() => + { + projectManager.ProjectAdded(HostProjectOne); + projectManager.ProjectAdded(HostProjectTwo); + projectManager.ProjectAdded(HostProjectThree); + }, CancellationToken.None); + var kind = WorkspaceChangeKind.ProjectChanged; + + // Initialize with a project. This will get removed. + var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject); + detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); + + e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithDependentProject); + detector.NotifyWorkspaceChangedEventComplete.Reset(); + + var solution = SolutionWithDependentProject.WithProjectAssemblyName(ProjectNumberThree.Id, "Changed"); + + e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithDependentProject, newSolution: solution, projectId: ProjectNumberThree.Id); + + // Act + detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); + + // Assert + Assert.Equal(3, detector._deferredUpdates.Count); + Assert.Contains(detector._deferredUpdates, u => u.Key == ProjectNumberOne.Id); + Assert.Contains(detector._deferredUpdates, u => u.Key == ProjectNumberTwo.Id); + Assert.Contains(detector._deferredUpdates, u => u.Key == ProjectNumberThree.Id); + } + + [UITheory] [InlineData(WorkspaceChangeKind.SolutionAdded)] [InlineData(WorkspaceChangeKind.SolutionChanged)] [InlineData(WorkspaceChangeKind.SolutionCleared)] [InlineData(WorkspaceChangeKind.SolutionReloaded)] [InlineData(WorkspaceChangeKind.SolutionRemoved)] - public void WorkspaceChanged_SolutionEvents_EnqueuesUpdatesForProjectsInSolution(WorkspaceChangeKind kind) + public async Task WorkspaceChanged_SolutionEvents_EnqueuesUpdatesForProjectsInSolution(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); - projectManager.ProjectAdded(HostProjectTwo); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) + { + NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), + }; + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => + { + projectManager.ProjectAdded(HostProjectOne); + projectManager.ProjectAdded(HostProjectTwo); + }, CancellationToken.None); var e = new WorkspaceChangeEventArgs(kind, oldSolution: EmptySolution, newSolution: SolutionWithTwoProjects); // Act detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); // Assert Assert.Collection( @@ -121,30 +205,41 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem p => Assert.Equal(ProjectNumberTwo.Id, p.workspaceProject.Id)); } - [ForegroundTheory] + [UITheory] [InlineData(WorkspaceChangeKind.SolutionAdded)] [InlineData(WorkspaceChangeKind.SolutionChanged)] [InlineData(WorkspaceChangeKind.SolutionCleared)] [InlineData(WorkspaceChangeKind.SolutionReloaded)] [InlineData(WorkspaceChangeKind.SolutionRemoved)] - public void WorkspaceChanged_SolutionEvents_EnqueuesStateClear_EnqueuesSolutionProjectUpdates(WorkspaceChangeKind kind) + public async Task WorkspaceChanged_SolutionEvents_EnqueuesStateClear_EnqueuesSolutionProjectUpdates(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); - projectManager.ProjectAdded(HostProjectTwo); - projectManager.ProjectAdded(HostProjectThree); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) + { + NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), + }; + + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + + await Dispatcher.RunOnDispatcherThreadAsync(() => + { + projectManager.ProjectAdded(HostProjectOne); + projectManager.ProjectAdded(HostProjectTwo); + projectManager.ProjectAdded(HostProjectThree); + }, CancellationToken.None); // Initialize with a project. This will get removed. var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject); detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithTwoProjects); + detector.NotifyWorkspaceChangedEventComplete.Reset(); // Act detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); // Assert Assert.Collection( @@ -155,20 +250,21 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem p => Assert.Equal(ProjectNumberTwo.Id, p.workspaceProject.Id)); } - [ForegroundTheory(Skip = "https://github.com/dotnet/aspnetcore/issues/29994")] + [UITheory(Skip = "https://github.com/dotnet/aspnetcore/issues/29994")] [InlineData(WorkspaceChangeKind.ProjectChanged)] [InlineData(WorkspaceChangeKind.ProjectReloaded)] public async Task WorkspaceChanged_ProjectChangeEvents_UpdatesProjectState_AfterDelay(WorkspaceChangeKind kind) { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), + BlockDelayedUpdateWorkAfterEnqueue = new ManualResetEventSlim(initialState: false), }; - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); projectManager.ProjectAdded(HostProjectOne); var solution = SolutionWithTwoProjects.WithProjectAssemblyName(ProjectNumberOne.Id, "Changed"); @@ -183,6 +279,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); + detector.BlockDelayedUpdateWorkAfterEnqueue.Wait(); await detector._deferredUpdates.Single().Value.Task; @@ -191,20 +288,21 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(projectSnapshot.FilePath, HostProjectOne.FilePath); } - [ForegroundFact] + [UIFact] public async Task WorkspaceChanged_DocumentChanged_BackgroundVirtualCS_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), + BlockDelayedUpdateWorkAfterEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(BackgroundVirtualCSharpDocumentId, SourceText.From("public class Foo{}")); @@ -219,6 +317,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); + detector.BlockDelayedUpdateWorkAfterEnqueue.Wait(); await detector._deferredUpdates.Single().Value.Task; @@ -227,20 +326,21 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(projectSnapshot.FilePath, HostProjectOne.FilePath); } - [ForegroundFact] + [UIFact] public async Task WorkspaceChanged_DocumentChanged_CSHTML_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), + BlockDelayedUpdateWorkAfterEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(CshtmlDocumentId, SourceText.From("Hello World")); @@ -255,6 +355,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); + detector.BlockDelayedUpdateWorkAfterEnqueue.Wait(); await detector._deferredUpdates.Single().Value.Task; @@ -263,20 +364,21 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(projectSnapshot.FilePath, HostProjectOne.FilePath); } - [ForegroundFact] + [UIFact] public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), + BlockDelayedUpdateWorkAfterEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None); workspaceStateGenerator.ClearQueue(); var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World")); @@ -291,6 +393,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); + detector.BlockDelayedUpdateWorkAfterEnqueue.Wait(); await detector._deferredUpdates.Single().Value.Task; @@ -299,20 +402,21 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem Assert.Equal(projectSnapshot.FilePath, HostProjectOne.FilePath); } - [ForegroundFact] + [UIFact] public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator) + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) { EnqueueDelay = 1, BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false), + BlockDelayedUpdateWorkAfterEnqueue = new ManualResetEventSlim(initialState: false), }; Workspace.TryApplyChanges(SolutionWithTwoProjects); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None); workspaceStateGenerator.ClearQueue(); var sourceText = SourceText.From( @@ -334,7 +438,7 @@ namespace Microsoft.AspNetCore.Components await document.GetSemanticModelAsync(); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: solution, newSolution: solution, projectId: ProjectNumberOne.Id, PartialComponentClassDocumentId); - + // Act detector.Workspace_WorkspaceChanged(Workspace, e); @@ -344,6 +448,7 @@ namespace Microsoft.AspNetCore.Components Assert.Empty(workspaceStateGenerator.UpdateQueue); detector.BlockDelayedUpdateWorkEnqueue.Set(); + detector.BlockDelayedUpdateWorkAfterEnqueue.Wait(); await detector._deferredUpdates.Single().Value.Task; @@ -352,21 +457,28 @@ namespace Microsoft.AspNetCore.Components Assert.Equal(projectSnapshot.FilePath, HostProjectOne.FilePath); } - [ForegroundFact] - public void WorkspaceChanged_ProjectRemovedEvent_QueuesProjectStateRemoval() + [UIFact] + public async Task WorkspaceChanged_ProjectRemovedEvent_QueuesProjectStateRemoval() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectOne); - projectManager.ProjectAdded(HostProjectTwo); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) + { + NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), + }; + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => + { + projectManager.ProjectAdded(HostProjectOne); + projectManager.ProjectAdded(HostProjectTwo); + }, CancellationToken.None); var solution = SolutionWithTwoProjects.RemoveProject(ProjectNumberOne.Id); var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectRemoved, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); // Assert Assert.Collection( @@ -374,20 +486,24 @@ namespace Microsoft.AspNetCore.Components p => Assert.Null(p.workspaceProject)); } - [ForegroundFact] - public void WorkspaceChanged_ProjectAddedEvent_AddsProject() + [UIFact] + public async Task WorkspaceChanged_ProjectAddedEvent_AddsProject() { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); - var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace); - projectManager.ProjectAdded(HostProjectThree); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher) + { + NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false), + }; + var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace); + await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectThree), CancellationToken.None); var solution = SolutionWithOneProject; var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id); // Act detector.Workspace_WorkspaceChanged(Workspace, e); + detector.NotifyWorkspaceChangedEventComplete.Wait(); // Assert Assert.Collection( @@ -400,7 +516,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class TestComponent{{}} @@ -427,7 +543,7 @@ public partial class TestComponent{{}} { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}} @@ -458,7 +574,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}} @@ -485,7 +601,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}} @@ -514,7 +630,7 @@ namespace Microsoft.AspNetCore.Components { // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From(string.Empty); var syntaxTreeRoot = await CSharpSyntaxTree.ParseText(sourceText).GetRootAsync(); var solution = SolutionWithTwoProjects @@ -539,7 +655,7 @@ namespace Microsoft.AspNetCore.Components // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class NonComponent1 {{}} @@ -575,7 +691,7 @@ namespace Microsoft.AspNetCore.Components // Arrange var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator(); - var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator); + var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher); var sourceText = SourceText.From( $@" public partial class NonComponent1 {{}} @@ -606,17 +722,13 @@ namespace Microsoft.AspNetCore.Components private class TestProjectSnapshotManager : DefaultProjectSnapshotManager { - public TestProjectSnapshotManager(IEnumerable triggers, Workspace workspace) - : base(CreateForegroundDispatcher(), Mock.Of(MockBehavior.Strict), triggers, workspace) + public TestProjectSnapshotManager( + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, + IEnumerable triggers, + Workspace workspace) + : base(projectSnapshotManagerDispatcher, Mock.Of(MockBehavior.Strict), triggers, workspace) { } - - private static ForegroundDispatcher CreateForegroundDispatcher() - { - var dispatcher = new Mock(MockBehavior.Strict); - dispatcher.Setup(d => d.AssertForegroundThread(It.IsAny())).Verifiable(); - return dispatcher.Object; - } } } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LiveShare.Razor.Test/Host/DefaultProjectSnapshotManagerProxyTest.cs b/src/Razor/test/Microsoft.VisualStudio.LiveShare.Razor.Test/Host/DefaultProjectSnapshotManagerProxyTest.cs index 8b43d512c1..326e4e5109 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LiveShare.Razor.Test/Host/DefaultProjectSnapshotManagerProxyTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LiveShare.Razor.Test/Host/DefaultProjectSnapshotManagerProxyTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -15,12 +14,10 @@ using Xunit; namespace Microsoft.VisualStudio.LiveShare.Razor.Host { - public class DefaultProjectSnapshotManagerProxyTest : ForegroundDispatcherTestBase, IDisposable + public class DefaultProjectSnapshotManagerProxyTest : ProjectSnapshotManagerDispatcherTestBase { public DefaultProjectSnapshotManagerProxyTest() { - JoinableTaskContext = new JoinableTaskContext(); - JoinableTaskFactory = new JoinableTaskFactory(JoinableTaskContext); Workspace = TestWorkspace.Create(); var projectWorkspaceState1 = new ProjectWorkspaceState(new[] { @@ -42,10 +39,6 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host projectWorkspaceState2)); } - private JoinableTaskFactory JoinableTaskFactory { get; } - - private JoinableTaskContext JoinableTaskContext { get; } - private Workspace Workspace { get; } private ProjectSnapshot ProjectSnapshot1 { get; } @@ -197,12 +190,6 @@ namespace Microsoft.VisualStudio.LiveShare.Razor.Host Assert.Same(state1, state2); } - [SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/4801")] - public virtual void Dispose() - { - JoinableTaskContext.Dispose(); - } - private class TestProjectSnapshotManager : ProjectSnapshotManager { public TestProjectSnapshotManager(params ProjectSnapshot[] projects) diff --git a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/DefaultDotNetProjectHostTest.cs b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/DefaultDotNetProjectHostTest.cs index b009fb9975..a6df836b54 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/DefaultDotNetProjectHostTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/DefaultDotNetProjectHostTest.cs @@ -7,7 +7,7 @@ using Xunit; namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.ProjectSystem { - public class DefaultDotNetProjectHostTest : ForegroundDispatcherTestBase + public class DefaultDotNetProjectHostTest : ProjectSnapshotManagerDispatcherTestBase { [Fact] public void UpdateRazorHostProject_UnsupportedProjectNoops() diff --git a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/Documents/VisualStudioMacFileChangeTrackerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/Documents/VisualStudioMacFileChangeTrackerTest.cs index 4a75c35834..7313f204d8 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/Documents/VisualStudioMacFileChangeTrackerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/Documents/VisualStudioMacFileChangeTrackerTest.cs @@ -6,9 +6,9 @@ using Xunit; namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { - public class VisualStudioMacFileChangeTrackerTest : ForegroundDispatcherTestBase + public class VisualStudioMacFileChangeTrackerTest : ProjectSnapshotManagerDispatcherTestBase { - [ForegroundFact] + [UIFact] public void StartListening_AdvisesForFileChange() { // Arrange @@ -21,7 +21,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Equal(1, tracker.AttachToFileServiceEventsCount); } - [ForegroundFact] + [UIFact] public void StartListening_AlreadyListening_DoesNothing() { // Arrange @@ -35,7 +35,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Equal(1, tracker.AttachToFileServiceEventsCount); } - [ForegroundFact] + [UIFact] public void StopListening_UnadvisesForFileChange() { // Arrange @@ -50,7 +50,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Equal(1, tracker.DetachFromFileServiceEventsCount); } - [ForegroundFact] + [UIFact] public void StopListening_NotListening_DoesNothing() { // Arrange @@ -69,7 +69,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { public TestFileChangeTracker( string filePath, - ForegroundDispatcher foregroundDispatcher) : base(filePath, foregroundDispatcher) + ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(filePath, projectSnapshotManagerDispatcher) { } diff --git a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/ProjectBuildChangeTriggerTest.cs b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/ProjectBuildChangeTriggerTest.cs index 5c48fd7de3..1746357a68 100644 --- a/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/ProjectBuildChangeTriggerTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test/ProjectBuildChangeTriggerTest.cs @@ -15,7 +15,7 @@ using Workspace = Microsoft.CodeAnalysis.Workspace; namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor { - public class ProjectBuildChangeTriggerTest : ForegroundDispatcherTestBase + public class ProjectBuildChangeTriggerTest : ProjectSnapshotManagerDispatcherTestBase { public ProjectBuildChangeTriggerTest() { @@ -39,7 +39,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor private Workspace Workspace { get; } - [ForegroundFact] + [UIFact] public void ProjectOperations_EndBuild_EnqueuesProjectStateUpdate() { // Arrange @@ -65,7 +65,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Equal(SomeWorkspaceProject, update.workspaceProject); } - [ForegroundFact] + [UIFact] public void ProjectOperations_EndBuild_ProjectWithoutWorkspaceProject_Noops() { // Arrange @@ -93,7 +93,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Empty(workspaceStateGenerator.UpdateQueue); } - [ForegroundFact] + [UIFact] public void ProjectOperations_EndBuild_UntrackedProject_Noops() { // Arrange @@ -116,7 +116,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Empty(workspaceStateGenerator.UpdateQueue); } - [ForegroundFact] + [UIFact] public void ProjectOperations_EndBuild_BuildFailed_Noops() { // Arrange @@ -135,7 +135,7 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor Assert.Empty(workspaceStateGenerator.UpdateQueue); } - [ForegroundFact] + [UIFact] public void ProjectOperations_EndBuild_UnsupportedProject_Noops() { // Arrange