private ReferenceOutputCapturingContainer Create(string filePath) { var documentContainer = new ReferenceOutputCapturingContainer(); documentContainer.GeneratedCSharpChanged += (sender, args) => { var generatedDocumentContainer = (GeneratedDocumentContainer)sender; var latestDocument = generatedDocumentContainer.LatestDocument; _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { // Document isn't opened, no need to notify the client return; } if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var nullableHostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishCSharp(filePath, args.NewText, hostDocumentVersion); }, CancellationToken.None); }; documentContainer.GeneratedHtmlChanged += (sender, args) => { var generatedDocumentContainer = (GeneratedDocumentContainer)sender; var latestDocument = generatedDocumentContainer.LatestDocument; _ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { // Document isn't opened, no need to notify the client return; } if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var nullableHostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishHtml(filePath, args.NewText, hostDocumentVersion); }, CancellationToken.None); }; return(documentContainer); }
private GeneratedDocumentContainer Create(string filePath) { var documentContainer = new GeneratedDocumentContainer(); documentContainer.GeneratedCSharpChanged += (sender, args) => { var generatedDocumentContainer = (GeneratedDocumentContainer)sender; var latestDocument = generatedDocumentContainer.LatestDocument; Task.Factory.StartNew(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { // Document isn't opened, no need to notify the client return; } if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var nullableHostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishCSharp(filePath, args.NewText, hostDocumentVersion); }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); }; documentContainer.GeneratedHtmlChanged += (sender, args) => { var generatedDocumentContainer = (GeneratedDocumentContainer)sender; var latestDocument = generatedDocumentContainer.LatestDocument; Task.Factory.StartNew(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { // Document isn't opened, no need to notify the client return; } if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var nullableHostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var hostDocumentVersion = nullableHostDocumentVersion.Value; _generatedDocumentPublisher.PublishHtml(filePath, args.NewText, hostDocumentVersion); }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); }; return(documentContainer); }
// Internal virtual for testing internal virtual void ReportUnsynchronizableContent(KeyValuePair <string, DocumentSnapshot>[] work) { _foregroundDispatcher.AssertForegroundThread(); // This method deals with reporting unsynchronized content. At this point we've force evaluation of each document // in the work queue; however, some documents may be identical versions of the last synchronized document if // one's content does not differ. In this case, the output of the two generated documents is the same but we still // need to let the client know that we've processed its latest text change. This allows the client to understand // when it's operating on out-of-date output. for (var i = 0; i < work.Length; i++) { var document = work[i].Value; if (!(document is DefaultDocumentSnapshot defaultDocument)) { continue; } if (!_documentVersionCache.TryGetDocumentVersion(document, out var syncVersion)) { // Document is no longer important. continue; } var latestSynchronizedDocument = defaultDocument.State.HostDocument.GeneratedCodeContainer.LatestDocument; if (latestSynchronizedDocument == null || latestSynchronizedDocument == document) { // Already up-to-date continue; } if (IdenticalOutputAfterParse(document, latestSynchronizedDocument, syncVersion)) { // Documents are identical but we didn't synchronize them because they didn't need to be re-evaluated. var request = new UpdateCSharpBufferRequest() { HostDocumentFilePath = document.FilePath, Changes = Array.Empty <TextChange>(), HostDocumentVersion = syncVersion }; _router.Client.SendRequest("updateCSharpBuffer", request); } } }
public async Task <RazorLanguageQueryResponse> Handle(RazorLanguageQueryParams request, CancellationToken cancellationToken) { long documentVersion = -1; DocumentSnapshot documentSnapshot = null; await Task.Factory.StartNew(() => { _documentResolver.TryResolveDocument(request.Uri.AbsolutePath, out documentSnapshot); if (!_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out documentVersion)) { Debug.Fail("Document should always be available here."); } return(documentSnapshot); }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); var sourceText = await documentSnapshot.GetTextAsync(); var linePosition = new LinePosition((int)request.Position.Line, (int)request.Position.Character); var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); var responsePosition = request.Position; if (codeDocument.IsUnsupported()) { // All language queries on unsupported documents return Html. This is equivalent to what pre-VSCode Razor was capable of. return(new RazorLanguageQueryResponse() { Kind = RazorLanguageKind.Html, Position = responsePosition, PositionIndex = hostDocumentIndex, HostDocumentVersion = documentVersion, }); } var syntaxTree = codeDocument.GetSyntaxTree(); var classifiedSpans = syntaxTree.GetClassifiedSpans(); var tagHelperSpans = syntaxTree.GetTagHelperSpans(); var languageKind = GetLanguageKind(classifiedSpans, tagHelperSpans, hostDocumentIndex); var responsePositionIndex = hostDocumentIndex; if (languageKind == RazorLanguageKind.CSharp) { if (TryGetCSharpProjectedPosition(codeDocument, hostDocumentIndex, out var projectedPosition, out var projectedIndex)) { // For C# locations, we attempt to return the corresponding position // within the projected document responsePosition = projectedPosition; responsePositionIndex = projectedIndex; } else { // It no longer makes sense to think of this location as C#, since it doesn't // correspond to any position in the projected document. This should not happen // since there should be source mappings for all the C# spans. languageKind = RazorLanguageKind.Razor; responsePositionIndex = hostDocumentIndex; } }
public async Task <RazorDiagnosticsResponse> Handle(RazorDiagnosticsParams request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } cancellationToken.ThrowIfCancellationRequested(); int?documentVersion = null; DocumentSnapshot documentSnapshot = null; await Task.Factory.StartNew(() => { _documentResolver.TryResolveDocument(request.RazorDocumentUri.GetAbsoluteOrUNCPath(), out documentSnapshot); Debug.Assert(documentSnapshot != null, "Failed to get the document snapshot, could not map to document ranges."); if (documentSnapshot is null || !_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out documentVersion)) { documentVersion = null; } }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); if (documentSnapshot is null) { return(new RazorDiagnosticsResponse() { Diagnostics = null, HostDocumentVersion = null }); } var unmappedDiagnostics = request.Diagnostics; var filteredDiagnostics = unmappedDiagnostics.Where(d => !CanDiagnosticBeFiltered(request.Kind, d)).ToArray(); if (!filteredDiagnostics.Any()) { // No diagnostics left after filtering. return(new RazorDiagnosticsResponse() { Diagnostics = Array.Empty <Diagnostic>(), HostDocumentVersion = documentVersion }); } var mappedDiagnostics = await MapDiagnosticsAsync( request, filteredDiagnostics, documentSnapshot).ConfigureAwait(false); return(new RazorDiagnosticsResponse() { Diagnostics = mappedDiagnostics, HostDocumentVersion = documentVersion, });
public override void DocumentProcessed(DocumentSnapshot document) { _foregroundDispatcher.AssertForegroundThread(); if (!_projectManager.IsDocumentOpen(document.FilePath)) { return; } if (!(document is DefaultDocumentSnapshot defaultDocument)) { return; } if (!_documentVersionCache.TryGetDocumentVersion(document, out var syncVersion)) { // Document is no longer important. return; } var latestSynchronizedDocument = defaultDocument.State.HostDocument.GeneratedCodeContainer.LatestDocument; if (latestSynchronizedDocument == null || latestSynchronizedDocument == document) { // Already up-to-date return; } if (IdenticalOutputAfterParse(document, latestSynchronizedDocument, syncVersion)) { // Documents are identical but we didn't synchronize them because they didn't need to be re-evaluated. var request = new UpdateCSharpBufferRequest() { HostDocumentFilePath = document.FilePath, Changes = Array.Empty <TextChange>(), HostDocumentVersion = syncVersion }; _router.Client.SendRequest("updateCSharpBuffer", request); } }
public override void DocumentProcessed(DocumentSnapshot document) { _foregroundDispatcher.AssertForegroundThread(); if (!_projectManager.IsDocumentOpen(document.FilePath)) { return; } if (!(document is DefaultDocumentSnapshot defaultDocument)) { return; } if (!_documentVersionCache.TryGetDocumentVersion(document, out var syncVersion)) { // Document is no longer important. return; } var latestSynchronizedDocument = defaultDocument.State.HostDocument.GeneratedCodeContainer.LatestDocument; if (latestSynchronizedDocument == null || latestSynchronizedDocument == document) { // Already up-to-date return; } if (IdenticalOutputAfterParse(document, latestSynchronizedDocument, syncVersion)) { // Documents are identical but we didn't synchronize them because they didn't need to be re-evaluated. var result = document.TryGetText(out var latestText); Debug.Assert(result, "We just successfully retrieved the text version, this should always return true."); _csharpPublisher.Publish(document.FilePath, latestText, syncVersion); } }
public override void DocumentProcessed(DocumentSnapshot document) { _projectSnapshotManagerDispatcher.AssertDispatcherThread(); if (!_projectManager.IsDocumentOpen(document.FilePath)) { return; } if (document is not DefaultDocumentSnapshot defaultDocument) { return; } if (!_documentVersionCache.TryGetDocumentVersion(document, out var nullableSyncVersion)) { // Document is no longer important. return; } var syncVersion = nullableSyncVersion.Value; var documentContainer = defaultDocument.State.GeneratedDocumentContainer; var latestSynchronizedDocument = documentContainer.LatestDocument; if (latestSynchronizedDocument is null || latestSynchronizedDocument == document) { // Already up-to-date return; } if (UnchangedHostDocument(document, latestSynchronizedDocument, syncVersion)) { // Documents are identical but we didn't synchronize them because they didn't need to be re-evaluated. _generatedDocumentPublisher.PublishCSharp(document.FilePath, documentContainer.CSharpSourceTextContainer.CurrentText, syncVersion); _generatedDocumentPublisher.PublishHtml(document.FilePath, documentContainer.HtmlSourceTextContainer.CurrentText, syncVersion); } }
private GeneratedCodeContainer Create(string filePath) { var codeContainer = new GeneratedCodeContainer(); codeContainer.GeneratedCodeChanged += (sender, args) => { var generatedCodeContainer = (GeneratedCodeContainer)sender; IReadOnlyList <TextChange> textChanges; if (args.NewText.ContentEquals(args.OldText)) { // If the content is equal then no need to update the underlying CSharp buffer. textChanges = Array.Empty <TextChange>(); } else { textChanges = args.NewText.GetTextChanges(args.OldText); } var latestDocument = generatedCodeContainer.LatestDocument; Task.Factory.StartNew(() => { if (!_projectSnapshotManager.IsDocumentOpen(filePath)) { // Document isn't opened, no need to notify the client return; } if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var hostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var request = new UpdateCSharpBufferRequest() { HostDocumentFilePath = filePath, Changes = textChanges, HostDocumentVersion = hostDocumentVersion, }; _server.Value.Client.SendRequest("updateCSharpBuffer", request); }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); }; return(codeContainer); }
public override HostDocument Create(string documentFilePath) { var hostDocument = new HostDocument(documentFilePath, documentFilePath); hostDocument.GeneratedCodeContainer.GeneratedCodeChanged += (sender, args) => { var generatedCodeContainer = (GeneratedCodeContainer)sender; IReadOnlyList <TextChange> textChanges; if (args.NewText.ContentEquals(args.OldText)) { // If the content is equal then no need to update the underlying CSharp buffer. textChanges = Array.Empty <TextChange>(); } else { textChanges = args.NewText.GetTextChanges(args.OldText); } var latestDocument = generatedCodeContainer.LatestDocument; Task.Factory.StartNew(() => { if (!_documentVersionCache.TryGetDocumentVersion(latestDocument, out var hostDocumentVersion)) { // Cache entry doesn't exist, document most likely was evicted from the cache/too old. return; } var request = new UpdateCSharpBufferRequest() { HostDocumentFilePath = documentFilePath, Changes = textChanges, HostDocumentVersion = hostDocumentVersion }; _router.Client.SendRequest("updateCSharpBuffer", request); }, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler); }; return(hostDocument); }
public async Task <RazorDiagnosticsResponse> Handle(RazorDiagnosticsParams request, CancellationToken cancellationToken) { if (request is null) { throw new ArgumentNullException(nameof(request)); } _logger.LogInformation($"Received {request.Kind:G} diagnostic request for {request.RazorDocumentUri} with {request.Diagnostics.Length} diagnostics."); cancellationToken.ThrowIfCancellationRequested(); int?documentVersion = null; DocumentSnapshot documentSnapshot = null; await Task.Factory.StartNew(() => { _documentResolver.TryResolveDocument(request.RazorDocumentUri.GetAbsoluteOrUNCPath(), out documentSnapshot); Debug.Assert(documentSnapshot != null, "Failed to get the document snapshot, could not map to document ranges."); if (documentSnapshot is null || !_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out documentVersion)) { documentVersion = null; } }, cancellationToken, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler).ConfigureAwait(false); if (documentSnapshot is null) { _logger.LogInformation($"Failed to find document {request.RazorDocumentUri}."); return(new RazorDiagnosticsResponse() { Diagnostics = null, HostDocumentVersion = null }); } var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); if (codeDocument?.IsUnsupported() != false) { _logger.LogInformation("Unsupported code document."); return(new RazorDiagnosticsResponse() { Diagnostics = Array.Empty <Diagnostic>(), HostDocumentVersion = documentVersion }); } var unmappedDiagnostics = request.Diagnostics; var filteredDiagnostics = request.Kind == RazorLanguageKind.CSharp ? FilterCSharpDiagnostics(unmappedDiagnostics) : await FilterHTMLDiagnosticsAsync(unmappedDiagnostics, codeDocument, documentSnapshot).ConfigureAwait(false); if (!filteredDiagnostics.Any()) { _logger.LogInformation("No diagnostics remaining after filtering."); return(new RazorDiagnosticsResponse() { Diagnostics = Array.Empty <Diagnostic>(), HostDocumentVersion = documentVersion }); } _logger.LogInformation($"{filteredDiagnostics.Length}/{unmappedDiagnostics.Length} diagnostics remain after filtering."); var mappedDiagnostics = MapDiagnostics( request, filteredDiagnostics, codeDocument); _logger.LogInformation($"Returning {mappedDiagnostics.Length} mapped diagnostics."); return(new RazorDiagnosticsResponse() { Diagnostics = mappedDiagnostics, HostDocumentVersion = documentVersion, }); }
public async Task <RazorLanguageQueryResponse> Handle(RazorLanguageQueryParams request, CancellationToken cancellationToken) { int?documentVersion = null; DocumentSnapshot documentSnapshot = null; await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(() => { _documentResolver.TryResolveDocument(request.Uri.GetAbsoluteOrUNCPath(), out documentSnapshot); Debug.Assert(documentSnapshot != null, "Failed to get the document snapshot, could not map to document ranges."); if (!_documentVersionCache.TryGetDocumentVersion(documentSnapshot, out documentVersion)) { // This typically happens for closed documents. documentVersion = null; } return(documentSnapshot); }, cancellationToken).ConfigureAwait(false); var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); var sourceText = await documentSnapshot.GetTextAsync(); var linePosition = new LinePosition(request.Position.Line, request.Position.Character); var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); var responsePosition = request.Position; if (codeDocument.IsUnsupported()) { // All language queries on unsupported documents return Html. This is equivalent to what pre-VSCode Razor was capable of. return(new RazorLanguageQueryResponse() { Kind = RazorLanguageKind.Html, Position = responsePosition, PositionIndex = hostDocumentIndex, HostDocumentVersion = documentVersion, }); } var responsePositionIndex = hostDocumentIndex; var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex); if (languageKind == RazorLanguageKind.CSharp) { if (_documentMappingService.TryMapToProjectedDocumentPosition(codeDocument, hostDocumentIndex, out var projectedPosition, out var projectedIndex)) { // For C# locations, we attempt to return the corresponding position // within the projected document responsePosition = projectedPosition; responsePositionIndex = projectedIndex; } else { // It no longer makes sense to think of this location as C#, since it doesn't // correspond to any position in the projected document. This should not happen // since there should be source mappings for all the C# spans. languageKind = RazorLanguageKind.Razor; responsePositionIndex = hostDocumentIndex; } }