public async Task ProvideSemanticTokensAsync_CannotLookupVirtualDocument_ReturnsNullAsync()
        {
            // Arrange
            var testDocUri = new Uri("C:/path/to/file.razor");
            LSPDocumentSnapshot testDocument = new TestLSPDocumentSnapshot(testDocUri, 0);

            var documentManager = new Mock <TrackingLSPDocumentManager>(MockBehavior.Strict);

            documentManager.Setup(manager => manager.TryGetDocument(It.IsAny <Uri>(), out testDocument))
            .Returns(true);
            var target  = new DefaultRazorLanguageServerCustomMessageTarget(documentManager.Object);
            var request = new ProvideSemanticTokensRangeParams(
                textDocument: new OmniSharpTextDocumentIdentifier()
            {
                Uri = new Uri("C:/path/to/file.razor")
            },
                requiredHostDocumentVersion: 0,
                range: new OmniSharp.Extensions.LanguageServer.Protocol.Models.Range());

            // Act
            var result = await target.ProvideSemanticTokensRangeAsync(request, CancellationToken.None);

            // Assert
            Assert.Null(result);
        }
        private async Task <int[]?> GetMatchingCSharpResponseAsync(
            TextDocumentIdentifier textDocumentIdentifier,
            long documentVersion,
            Range csharpRange,
            CancellationToken cancellationToken)
        {
            var parameter = new ProvideSemanticTokensRangeParams(textDocumentIdentifier, documentVersion, csharpRange);
            var request   = await _languageServer.SendRequestAsync(LanguageServerConstants.RazorProvideSemanticTokensRangeEndpoint, parameter);

            var csharpResponse = await request.Returning <ProvideSemanticTokensResponse>(cancellationToken);

            if (csharpResponse is null)
            {
                // C# isn't ready yet, don't make Razor wait for it. Once C# is ready they'll send a refresh notification.
                return(Array.Empty <int>());
            }
            else if (csharpResponse.HostDocumentSyncVersion != null && csharpResponse.HostDocumentSyncVersion != documentVersion)
            {
                // No C# response or C# is out of sync with us. Unrecoverable, return null to indicate no change.
                // Once C# syncs up they'll send a refresh notification.
                return(null);
            }

            var response = csharpResponse.Tokens ?? Array.Empty <int>();

            return(response);
        }
        public async Task ProvideSemanticTokensAsync_ReturnsSemanticTokensAsync()
        {
            // Arrange
            var testDocUri        = new Uri("C:/path/to - project/file.razor");
            var testVirtualDocUri = new Uri("C:/path/to - project/file2.razor.g");
            var testCSharpDocUri  = new Uri("C:/path/to - project/file.razor.g.cs");

            var documentVersion              = 0;
            var testVirtualDocument          = new TestVirtualDocumentSnapshot(testVirtualDocUri, 0);
            var csharpVirtualDocument        = new CSharpVirtualDocumentSnapshot(testCSharpDocUri, TextBuffer.CurrentSnapshot, 0);
            LSPDocumentSnapshot testDocument = new TestLSPDocumentSnapshot(testDocUri, documentVersion, testVirtualDocument, csharpVirtualDocument);

            var documentManager = new Mock <TrackingLSPDocumentManager>(MockBehavior.Strict);

            documentManager.Setup(manager => manager.TryGetDocument(testDocUri, out testDocument))
            .Returns(true);

            var expectedcSharpResults = new VSSemanticTokensResponse();
            var requestInvoker        = new Mock <LSPRequestInvoker>(MockBehavior.Strict);

            requestInvoker.Setup(invoker => invoker.ReinvokeRequestOnServerAsync <OmniSharp.Extensions.LanguageServer.Protocol.Models.SemanticTokensRangeParams, VSSemanticTokensResponse>(
                                     TextBuffer,
                                     Methods.TextDocumentSemanticTokensRangeName,
                                     LanguageServerKind.CSharp.ToLanguageServerName(),
                                     It.IsAny <OmniSharp.Extensions.LanguageServer.Protocol.Models.SemanticTokensRangeParams>(),
                                     It.IsAny <CancellationToken>()
                                     )).Returns(Task.FromResult(new ReinvocationResponse <VSSemanticTokensResponse>("languageClient", expectedcSharpResults)));

            var uIContextManager     = new Mock <RazorUIContextManager>(MockBehavior.Strict);
            var disposable           = new Mock <IDisposable>(MockBehavior.Strict);
            var documentSynchronizer = new Mock <LSPDocumentSynchronizer>(MockBehavior.Strict);

            documentSynchronizer.Setup(r => r.TrySynchronizeVirtualDocumentAsync(0, It.IsAny <CSharpVirtualDocumentSnapshot>(), It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(true));

            var target = new DefaultRazorLanguageServerCustomMessageTarget(
                documentManager.Object, JoinableTaskContext, requestInvoker.Object,
                uIContextManager.Object, disposable.Object, EditorSettingsManager, documentSynchronizer.Object);
            var request = new ProvideSemanticTokensRangeParams(
                textDocument: new OmniSharpTextDocumentIdentifier()
            {
                Uri = new Uri("C:/path/to%20-%20project/file.razor")
            },
                requiredHostDocumentVersion: 0,
                range: new OmniSharp.Extensions.LanguageServer.Protocol.Models.Range());
            var expectedResults = new ProvideSemanticTokensResponse(expectedcSharpResults.Data, documentVersion);

            // Act
            var result = await target.ProvideSemanticTokensRangeAsync(request, CancellationToken.None);

            // Assert
            Assert.Equal(expectedResults, result);
        }
 public abstract Task <ProvideSemanticTokensResponse?> ProvideSemanticTokensRangeAsync(ProvideSemanticTokensRangeParams semanticTokensParams, CancellationToken cancellationToken);
Example #5
0
        public override async Task <ProvideSemanticTokensResponse?> ProvideSemanticTokensRangeAsync(
            ProvideSemanticTokensRangeParams semanticTokensParams,
            CancellationToken cancellationToken)
        {
            if (semanticTokensParams is null)
            {
                throw new ArgumentNullException(nameof(semanticTokensParams));
            }

            if (semanticTokensParams.Range is null)
            {
                throw new ArgumentNullException(nameof(semanticTokensParams.Range));
            }

            var csharpDoc = GetCSharpDocumentSnapshsot(semanticTokensParams.TextDocument.Uri.ToUri());

            if (csharpDoc is null)
            {
                return(null);
            }

            var synchronized = await _documentSynchronizer.TrySynchronizeVirtualDocumentAsync(
                (int)semanticTokensParams.RequiredHostDocumentVersion, csharpDoc, cancellationToken);

            if (!synchronized)
            {
                // If we're unable to synchronize we won't produce useful results, but we have to indicate
                // it's due to out of sync by providing the old version
                return(new ProvideSemanticTokensResponse(tokens: null, hostDocumentSyncVersion: csharpDoc.HostDocumentSyncVersion));
            }

            var csharpTextDocument = semanticTokensParams.TextDocument with {
                Uri = csharpDoc.Uri
            };

            semanticTokensParams = semanticTokensParams with {
                TextDocument = csharpTextDocument
            };

            var newParams = new SemanticTokensRangeParams
            {
                TextDocument       = semanticTokensParams.TextDocument,
                PartialResultToken = semanticTokensParams.PartialResultToken,
                Range = semanticTokensParams.Range,
            };

            var textBuffer    = csharpDoc.Snapshot.TextBuffer;
            var csharpResults = await _requestInvoker.ReinvokeRequestOnServerAsync <SemanticTokensRangeParams, VSSemanticTokensResponse>(
                textBuffer,
                Methods.TextDocumentSemanticTokensRangeName,
                RazorLSPConstants.RazorCSharpLanguageServerName,
                newParams,
                cancellationToken).ConfigureAwait(false);

            var result = csharpResults?.Response;

            if (result is null)
            {
                // Weren't able to re-invoke C# semantic tokens but we have to indicate it's due to out of sync by providing the old version
                return(new ProvideSemanticTokensResponse(tokens: null, hostDocumentSyncVersion: csharpDoc.HostDocumentSyncVersion));
            }

            var response = new ProvideSemanticTokensResponse(result.Data, semanticTokensParams.RequiredHostDocumentVersion);

            return(response);
        }