Example #1
0
            public void QueueChange(TextChange change)
            {
                RazorEditorTrace.TraceLine(RazorResources.FormatTrace_QueuingParse(Path.GetFileName(_fileName), change));
                EnsureOnThread();
                lock (_stateLock)
                {
                    // CurrentParcel token source is not null ==> There's a parse underway
                    if (_currentParcelCancelSource != null)
                    {
                        _currentParcelCancelSource.Cancel();
                    }

                    _changes.Add(change);
                    _hasParcel.Set();
                }
            }
Example #2
0
            // **** BACKGROUND THREAD ****
            private void WorkerLoop()
            {
                long?  elapsedMs    = null;
                string fileNameOnly = Path.GetFileName(_fileName);

#if EDITOR_TRACING
                Stopwatch sw = new Stopwatch();
#endif

                try
                {
                    RazorEditorTrace.TraceLine(RazorResources.FormatTrace_BackgroundThreadStart(fileNameOnly));
                    EnsureOnThread();

#if ASPNETCORE50
                    var spinWait = new SpinWait();
#endif

                    while (!_shutdownToken.IsCancellationRequested)
                    {
                        // Grab the parcel of work to do
                        WorkParcel parcel = _main.GetParcel();
                        if (parcel.Changes.Any())
                        {
                            RazorEditorTrace.TraceLine(RazorResources.FormatTrace_ChangesArrived(fileNameOnly, parcel.Changes.Count));
                            try
                            {
                                DocumentParseCompleteEventArgs args = null;
                                using (var linkedCancel = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken, parcel.CancelToken))
                                {
                                    if (!linkedCancel.IsCancellationRequested)
                                    {
                                        // Collect ALL changes
#if EDITOR_TRACING
                                        if (_previouslyDiscarded != null && _previouslyDiscarded.Any())
                                        {
                                            RazorEditorTrace.TraceLine(RazorResources.Trace_CollectedDiscardedChanges, fileNameOnly, _previouslyDiscarded.Count);
                                        }
#endif
                                        List <TextChange> allChanges;

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

                                        TextChange finalChange = allChanges.Last();
#if EDITOR_TRACING
                                        sw.Start();
#endif
                                        GeneratorResults results = ParseChange(finalChange.NewBuffer, linkedCancel.Token);
#if EDITOR_TRACING
                                        sw.Stop();
                                        elapsedMs = sw.ElapsedMilliseconds;
                                        sw.Reset();
#endif
                                        RazorEditorTrace.TraceLine(
                                            RazorResources.FormatTrace_ParseComplete(
                                                fileNameOnly,
                                                elapsedMs.HasValue ? elapsedMs.Value.ToString(CultureInfo.InvariantCulture) : "?"));

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

                                            // Take the current tree and check for differences
#if EDITOR_TRACING
                                            sw.Start();
#endif
                                            bool treeStructureChanged = _currentParseTree == null || TreesAreDifferent(_currentParseTree, results.Document, allChanges, parcel.CancelToken);
#if EDITOR_TRACING
                                            sw.Stop();
                                            elapsedMs = sw.ElapsedMilliseconds;
                                            sw.Reset();
#endif
                                            _currentParseTree = results.Document;
                                            RazorEditorTrace.TraceLine(RazorResources.FormatTrace_TreesCompared(
                                                                           fileNameOnly,
                                                                           elapsedMs.HasValue ? elapsedMs.Value.ToString(CultureInfo.InvariantCulture) : "?",
                                                                           treeStructureChanged));

                                            // Build Arguments
                                            args = new DocumentParseCompleteEventArgs()
                                            {
                                                GeneratorResults     = results,
                                                SourceChange         = finalChange,
                                                TreeStructureChanged = treeStructureChanged
                                            };
                                        }
                                        else
                                        {
                                            // Parse completed but we were cancelled in the mean time. Add these to the discarded changes set
                                            RazorEditorTrace.TraceLine(RazorResources.FormatTrace_ChangesDiscarded(fileNameOnly, allChanges.Count));
                                            _previouslyDiscarded = allChanges;
                                        }

#if CHECK_TREE
                                        if (args != null)
                                        {
                                            // Rewind the buffer and sanity check the line mappings
                                            finalChange.NewBuffer.Position = 0;
                                            int lineCount = finalChange.NewBuffer.ReadToEnd().Split(new string[] { Environment.NewLine, "\r", "\n" }, StringSplitOptions.None).Count();
                                            Debug.Assert(
                                                !args.GeneratorResults.DesignTimeLineMappings.Any(pair => pair.Value.StartLine > lineCount),
                                                "Found a design-time line mapping referring to a line outside the source file!");
                                            Debug.Assert(
                                                !args.GeneratorResults.Document.Flatten().Any(span => span.Start.LineIndex > lineCount),
                                                "Found a span with a line number outside the source file");
                                            Debug.Assert(
                                                !args.GeneratorResults.Document.Flatten().Any(span => span.Start.AbsoluteIndex > parcel.NewBuffer.Length),
                                                "Found a span with an absolute offset outside the source file");
                                        }
#endif
                                    }
                                }
                                if (args != null)
                                {
                                    _main.ReturnParcel(args);
                                }
                            }
                            catch (OperationCanceledException)
                            {
                            }
                        }
                        else
                        {
                            RazorEditorTrace.TraceLine(RazorResources.FormatTrace_NoChangesArrived(fileNameOnly));
#if NET45
                            // No Yield in CoreCLR

                            Thread.Yield();
#else
                            // This does the equivalent of thread.yield under the covers.
                            spinWait.SpinOnce();
#endif
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    // Do nothing. Just shut down.
                }
                finally
                {
                    RazorEditorTrace.TraceLine(RazorResources.FormatTrace_BackgroundThreadShutdown(fileNameOnly));

                    // Clean up main thread resources
                    _main.Dispose();
                }
            }