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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        // 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);
            }
        }
Пример #7
0
        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);
            }
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        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;
                }
            }