protected virtual void OnResultsReady(BackgroundParserResultsReadyEventArgs args)
 {
     using (SynchronizeMainThreadState())
     {
         ResultsReady?.Invoke(this, args);
     }
 }
Example #2
0
        private void OnResultsReady(object sender, BackgroundParserResultsReadyEventArgs args)
        {
            _dispatcher.AssertBackgroundThread();

            // Jump back to UI thread to notify structure changes.
            Task.Factory.StartNew(OnDocumentStructureChanged, args, CancellationToken.None, TaskCreationOptions.None, _dispatcher.ForegroundScheduler);
        }
Example #3
0
        public async Task GetLatestCodeDocumentAsync_NoPendingChangesReturnsImmediately()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();

            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var latestChange   = new SourceChange(0, 0, string.Empty);
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
                var codeDocument = TestRazorCodeDocument.CreateEmpty();
                codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
                var args = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);
                parser.OnDocumentStructureChanged(args);

                // Act - 1
                var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync();

                // Assert - 1
                Assert.True(getLatestCodeDocumentTask.IsCompleted);

                // Act - 2
                var latestCodeDocument = await getLatestCodeDocumentTask;

                // Assert - 2
                Assert.Same(latestCodeDocument, codeDocument);
            }
        }
Example #4
0
        public void OnDocumentStructureChanged_FiresForLatestTextBufferEdit()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();

            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var called = false;
                parser.DocumentStructureChanged += (sender, e) => called = true;
                var latestChange   = new SourceChange(0, 0, string.Empty);
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
                var codeDocument = TestRazorCodeDocument.CreateEmpty();
                codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
                var args = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);

                // Act
                parser.OnDocumentStructureChanged(args);

                // Assert
                Assert.True(called);
            }
        }
Example #5
0
        public void GetLatestCodeDocumentAsync_MultipleCallsWithPendingChangesMemoizesReturnedTasks()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();

            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var latestChange   = new SourceChange(0, 0, string.Empty);
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
                var codeDocument = TestRazorCodeDocument.CreateEmpty();
                codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
                var args = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);

                // Act
                var getLatestCodeDocumentTask1 = parser.GetLatestCodeDocumentAsync();
                var getLatestCodeDocumentTask2 = parser.GetLatestCodeDocumentAsync();

                // Assert
                Assert.Same(getLatestCodeDocumentTask1, getLatestCodeDocumentTask2);
            }
        }
Example #6
0
        // Internal for testing
        internal void OnResultsReady(object sender, BackgroundParserResultsReadyEventArgs args)
        {
            _dispatcher.AssertBackgroundThread();

            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);
        }
Example #7
0
        // Internal for testing
#pragma warning disable VSTHRD100 // Avoid async void methods
        internal async void OnResultsReady(object sender, BackgroundParserResultsReadyEventArgs args)
#pragma warning restore VSTHRD100 // Avoid async void methods
        {
            try
            {
                UpdateParserState(args.CodeDocument, args.ChangeReference.Snapshot);

                // 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);
            }
        }
            public void ReturnParcel(BackgroundParserResultsReadyEventArgs args)
            {
                lock (_stateLock)
                {
                    // Clear the current parcel cancellation source
                    if (_currentParcelCancelSource != null)
                    {
                        _currentParcelCancelSource.Dispose();
                        _currentParcelCancelSource = null;
                    }

                    // If there are things waiting to be parsed, just don't fire the event because we're already out of date
                    if (_changes.Any())
                    {
                        return;
                    }
                }
                ResultsReady?.Invoke(this, args);
            }
Example #9
0
        public async Task GetLatestSyntaxTreeAsync_WaitsForParse()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();

            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var latestChange   = new SourceChange(0, 0, string.Empty);
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
                var codeDocument = TestRazorCodeDocument.CreateEmpty();
                var syntaxTree   = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
                codeDocument.SetSyntaxTree(syntaxTree);
                var args = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);

                // Act - 1
                var getLatestSyntaxTreeTask = parser.GetLatestSyntaxTreeAsync(StringTextSnapshot.Empty);

                // Assert - 1
                Assert.False(getLatestSyntaxTreeTask.IsCompleted);

                // Act - 2
                await Task.Run(() => parser.OnResultsReady(sender: null, args));

                // Assert - 2
                Assert.True(getLatestSyntaxTreeTask.IsCompleted);

                // Act - 3
                var latestSyntaxTree = await getLatestSyntaxTreeTask;

                // Assert - 3
                Assert.Same(latestSyntaxTree, syntaxTree);
            }
        }
        public async Task GetLatestCodeDocumentAsync_ParserDisposed_ReturnsImmediately()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();
            var codeDocument    = TestRazorCodeDocument.CreateEmpty();
            var syntaxTree      = RazorSyntaxTree.Parse(TestRazorSourceDocument.Create());
            DefaultVisualStudioRazorParser parser;

            codeDocument.SetSyntaxTree(syntaxTree);
            using (parser = new DefaultVisualStudioRazorParser(
                       JoinableTaskContext,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>(MockBehavior.Strict)))
            {
                var latestChange   = new SourceChange(0, 0, string.Empty);
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(latestChange, latestSnapshot);
                var args = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);

                // Initialize the document with some content so we have a syntax tree to return.
                await Task.Run(() => parser.OnResultsReady(sender: null, args));
            }

            var newerSnapshot = new StringTextSnapshot("Newer", versionNumber: 1337);

            // Act - 1
            var getLatestCodeDocumentTask = parser.GetLatestCodeDocumentAsync(newerSnapshot);

            // Assert - 1
            Assert.True(getLatestCodeDocumentTask.IsCompleted);

            // Act - 2
            var latestCodeDocument = await getLatestCodeDocumentTask;

            // Assert - 2
            Assert.Same(latestCodeDocument, codeDocument);
        }
Example #11
0
        public void OnDocumentStructureChanged_FiresForOnlyLatestTextBufferReparseEdit()
        {
            // Arrange
            var documentTracker = CreateDocumentTracker();

            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       documentTracker,
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var called = false;
                parser.DocumentStructureChanged += (sender, e) => called = true;
                var latestSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
                parser._latestChangeReference = new BackgroundParser.ChangeReference(null, latestSnapshot);
                var codeDocument = TestRazorCodeDocument.CreateEmpty();
                codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(TestRazorSourceDocument.Create()));
                var badArgs = new BackgroundParserResultsReadyEventArgs(
                    // This is a different reparse edit, shouldn't be fired for this call
                    new BackgroundParser.ChangeReference(null, latestSnapshot),
                    codeDocument);
                var goodArgs = new BackgroundParserResultsReadyEventArgs(
                    parser._latestChangeReference,
                    codeDocument);

                // Act - 1
                parser.OnDocumentStructureChanged(badArgs);

                // Assert - 1
                Assert.False(called);

                // Act - 2
                parser.OnDocumentStructureChanged(goodArgs);

                // Assert - 2
                Assert.True(called);
            }
        }
Example #12
0
        public void OnDocumentStructureChanged_IgnoresEditsThatAreOld()
        {
            // Arrange
            using (var parser = new DefaultVisualStudioRazorParser(
                       Dispatcher,
                       CreateDocumentTracker(),
                       ProjectEngineFactory,
                       new DefaultErrorReporter(),
                       Mock.Of <VisualStudioCompletionBroker>()))
            {
                var called = false;
                parser.DocumentStructureChanged += (sender, e) => called = true;
                parser._latestChangeReference    = new BackgroundParser.ChangeReference(null, new StringTextSnapshot(string.Empty));
                var args = new BackgroundParserResultsReadyEventArgs(
                    new BackgroundParser.ChangeReference(new SourceChange(0, 0, string.Empty), new StringTextSnapshot(string.Empty)),
                    TestRazorCodeDocument.CreateEmpty());

                // Act
                parser.OnDocumentStructureChanged(args);

                // Assert
                Assert.False(called);
            }
        }
            // **** BACKGROUND THREAD ****
            private void WorkerLoop()
            {
                try
                {
                    EnsureOnThread();

                    while (!_shutdownToken.IsCancellationRequested)
                    {
                        // Grab the parcel of work to do
                        var parcel = _main.GetParcel();
                        if (parcel.Changes.Any())
                        {
                            try
                            {
                                BackgroundParserResultsReadyEventArgs args = null;
                                using (var linkedCancel = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken, parcel.CancelToken))
                                {
                                    if (!linkedCancel.IsCancellationRequested)
                                    {
                                        // Collect ALL changes
                                        List <ChangeReference> allChanges;

                                        if (_previouslyDiscarded != null)
                                        {
                                            allChanges = Enumerable.Concat(_previouslyDiscarded, parcel.Changes).ToList();
                                        }
                                        else
                                        {
                                            allChanges = parcel.Changes.ToList();
                                        }

                                        var finalChange = allChanges.Last();

                                        var results = ParseChange(finalChange.Snapshot, linkedCancel.Token);

                                        if (results != null && !linkedCancel.IsCancellationRequested)
                                        {
                                            // Clear discarded changes list
                                            _previouslyDiscarded = null;

                                            _currentSyntaxTree = results.GetSyntaxTree();

                                            // Build Arguments
                                            args = new BackgroundParserResultsReadyEventArgs(finalChange, results);
                                        }
                                        else
                                        {
                                            // Parse completed but we were cancelled in the mean time. Add these to the discarded changes set
                                            _previouslyDiscarded = allChanges;
                                        }
                                    }
                                }
                                if (args != null)
                                {
                                    _main.ReturnParcel(args);
                                }
                            }
                            catch (OperationCanceledException)
                            {
                            }
                        }
                        else
                        {
                            Thread.Yield();
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    // Do nothing. Just shut down.
                }
                finally
                {
                    // Clean up main thread resources
                    _main.Dispose();
                }
            }