示例#1
0
        public void ImplicitExpressionAcceptsIdentifierTypedAfterDotIfLastChangeWasProvisionalAcceptanceOfDot()
        {
            // Arrange
            TextChange        dotTyped  = new TextChange(8, 0, new StringTextBuffer("foo @foo bar"), 1, new StringTextBuffer("foo @foo. bar"));
            TextChange        charTyped = new TextChange(9, 0, new StringTextBuffer("foo @foo. bar"), 1, new StringTextBuffer("foo @foo.b bar"));
            TestParserManager manager   = CreateParserManager();

            manager.InitializeWithDocument(dotTyped.OldBuffer);

            // Apply the dot change
            Assert.AreEqual(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));

            // Act (apply the identifier start char change)
            PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);

            // Assert
            Assert.AreEqual(PartialParseResult.Accepted, result, "The change was not fully accepted!");
            Assert.IsFalse(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
            ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
                                             new MarkupBlock(
                                                 new MarkupSpan("foo "),
                                                 new ExpressionBlock(
                                                     new TransitionSpan(RazorParser.TransitionString, hidden: false, acceptedCharacters: AcceptedCharacters.None),
                                                     new ImplicitExpressionSpan("foo.b", CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false, acceptedCharacters: AcceptedCharacters.NonWhiteSpace)
                                                     ),
                                                 new MarkupSpan(" bar")));
        }
示例#2
0
 private void CreateAutoBlockCompleter(PartialParseResult parseResult, TextChange textChange)
 {
     if (IsFlagSet(parseResult, PartialParseResult.AutoCompleteBlock))
     {
         _autoBlockCompletor = new AutoBlockCompletor(TextView, textChange.NewPosition, _razorEditorParser.GetAutoCompleteString());
         return;
     }
     if (textChange.OldLength == 0 && textChange.NewLength > 0 && textChange.NewLength <= 2 && Whitespace.IsNewLine((textChange.NewBuffer as IShimTextBuffer).Snapshot.GetText(textChange.NewPosition, textChange.NewLength)) && _viewBuffer.ContentType.IsOfType("RazorCSharp"))
     {
         ITextSnapshot     currentSnapshot  = _viewBuffer.CurrentSnapshot;
         ITextSnapshotLine lineFromPosition = currentSnapshot.GetLineFromPosition(textChange.NewPosition);
         string            text             = lineFromPosition.GetText();
         int num = Math.Min(lineFromPosition.Length, textChange.NewPosition - lineFromPosition.Start) - 1;
         while (num >= 0 && char.IsWhiteSpace(text[num]))
         {
             num--;
         }
         if (num >= 1 && text[num] == '{' && text[num - 1] == '@')
         {
             int num2 = textChange.NewPosition + textChange.NewLength;
             ITextSnapshotLine lineFromPosition2 = currentSnapshot.GetLineFromPosition(num2);
             string            text2             = lineFromPosition2.GetText();
             int num3 = num2 - lineFromPosition2.Start;
             while (num3 < lineFromPosition2.Length && char.IsWhiteSpace(text2[num3]))
             {
                 num3++;
             }
             if (num3 < lineFromPosition2.Length && text2[num3] == '}')
             {
                 _autoBlockCompletor = new AutoBlockCompletor(TextView, textChange.NewPosition, string.Empty);
             }
         }
     }
 }
示例#3
0
        internal static void WriteDebugTree(string sourceFile, Block document, PartialParseResult result, TextChange change, RazorEditorParser parser, bool treeStructureChanged)
        {
            if (!OutputDebuggingEnabled)
            {
                return;
            }

            RunTask(() =>
            {
                string outputFileName = Normalize(sourceFile) + "_tree";
                string outputPath     = Path.Combine(Path.GetDirectoryName(sourceFile), outputFileName);

                var treeBuilder = new StringBuilder();
                WriteTree(document, treeBuilder);
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Last Change: {0}", change);
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Normalized To: {0}", change.Normalize());
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Partial Parse Result: {0}", result);
                treeBuilder.AppendLine();
                if (result.HasFlag(PartialParseResult.Rejected))
                {
                    treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Tree Structure Changed: {0}", treeStructureChanged);
                    treeBuilder.AppendLine();
                }
                if (result.HasFlag(PartialParseResult.AutoCompleteBlock))
                {
                    treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Auto Complete Insert String: \"{0}\"", parser.GetAutoCompleteString());
                    treeBuilder.AppendLine();
                }
                File.WriteAllText(outputPath, treeBuilder.ToString());
            });
        }
示例#4
0
        public void CheckForStructureChangesStartsFullReparseIfChangeOverlapsMultipleSpans()
        {
            // Arrange
            RazorEditorParser parser   = new RazorEditorParser(CreateHost(), TestLinePragmaFileName);
            ITextBuffer       original = new StringTextBuffer("Foo @bar Baz");
            ITextBuffer       changed  = new StringTextBuffer("Foo @bap Daz");
            TextChange        change   = new TextChange(7, 3, original, 3, changed);

            ManualResetEventSlim parseComplete = new ManualResetEventSlim();
            int parseCount = 0;

            parser.DocumentParseComplete += (sender, args) =>
            {
                Interlocked.Increment(ref parseCount);
                parseComplete.Set();
            };

            Assert.Equal(PartialParseResult.Rejected, parser.CheckForStructureChanges(new TextChange(0, 0, new StringTextBuffer(String.Empty), 12, original)));
            MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait); // Wait for the parse to finish
            parseComplete.Reset();

            // Act
            PartialParseResult result = parser.CheckForStructureChanges(change);

            // Assert
            Assert.Equal(PartialParseResult.Rejected, result);
            MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
            Assert.Equal(2, parseCount);
        }
示例#5
0
        public void ImplicitExpressionRejectsChangeWhichWouldHaveBeenAcceptedIfLastChangeWasProvisionallyAcceptedOnDifferentSpan()
        {
            // Arrange
            TextChange        dotTyped  = new TextChange(8, 0, new StringTextBuffer("foo @foo @bar"), 1, new StringTextBuffer("foo @foo. @bar"));
            TextChange        charTyped = new TextChange(14, 0, new StringTextBuffer("foo @foo. @barb"), 1, new StringTextBuffer("foo @foo. @barb"));
            TestParserManager manager   = CreateParserManager();

            manager.InitializeWithDocument(dotTyped.OldBuffer);

            // Apply the dot change
            Assert.AreEqual(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));

            // Act (apply the identifier start char change)
            PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);

            // Assert
            Assert.AreEqual(PartialParseResult.Rejected, result, "The change was accepted despite the previous change being provisionally accepted!");
            Assert.IsFalse(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
            ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
                                             new MarkupBlock(
                                                 new MarkupSpan("foo "),
                                                 new ExpressionBlock(
                                                     new TransitionSpan(RazorParser.TransitionString, hidden: false, acceptedCharacters: AcceptedCharacters.None),
                                                     new ImplicitExpressionSpan("foo", VBCodeParser.DefaultKeywords, acceptTrailingDot: false, acceptedCharacters: AcceptedCharacters.NonWhiteSpace)
                                                     ),
                                                 new MarkupSpan(". "),
                                                 new ExpressionBlock(
                                                     new TransitionSpan(RazorParser.TransitionString, hidden: false, acceptedCharacters: AcceptedCharacters.None),
                                                     new ImplicitExpressionSpan("barb", VBCodeParser.DefaultKeywords, acceptTrailingDot: false, acceptedCharacters: AcceptedCharacters.NonWhiteSpace)
                                                     ),
                                                 new MarkupSpan(String.Empty)));
        }
        public void ImplicitExpressionProvisionallyAcceptsDotlessCommitInsertions()
        {
            SpanFactory       factory    = SpanFactory.CreateCsHtml();
            var               changed    = new StringTextBuffer("foo @DateT. baz");
            var               old        = new StringTextBuffer("foo @DateT baz");
            var               textChange = new TextChange(10, 0, old, 1, changed);
            TestParserManager manager    = CreateParserManager();
            Action <TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
            {
                PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);

                // Assert
                Assert.Equal(expectedResult, result);
                Assert.Equal(1, manager.ParseCount);

                ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
                                                     factory.Markup("foo "),
                                                     new ExpressionBlock(
                                                         factory.CodeTransition(),
                                                         factory.Code(expectedCode).AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
                                                     factory.Markup(" baz")));
            };

            manager.InitializeWithDocument(textChange.OldBuffer);

            // This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
            applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateT.");

            old        = changed;
            changed    = new StringTextBuffer("foo @DateTime. baz");
            textChange = new TextChange(10, 0, old, 3, changed);

            applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateTime.");
        }
        internal static void WriteDebugTree(string sourceFile, Block document, PartialParseResult result, TextChange change, RazorEditorParser parser, bool treeStructureChanged)
        {
            if (!OutputDebuggingEnabled)
            {
                return;
            }

            RunTask(() =>
            {
                string outputFileName = Normalize(sourceFile) + "_tree";
                string outputPath = Path.Combine(Path.GetDirectoryName(sourceFile), outputFileName);

                var treeBuilder = new StringBuilder();
                WriteTree(document, treeBuilder);
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Last Change: {0}", change);
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Normalized To: {0}", change.Normalize());
                treeBuilder.AppendLine();
                treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Partial Parse Result: {0}", result);
                treeBuilder.AppendLine();
                if (result.HasFlag(PartialParseResult.Rejected))
                {
                    treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Tree Structure Changed: {0}", treeStructureChanged);
                    treeBuilder.AppendLine();
                }
                if (result.HasFlag(PartialParseResult.AutoCompleteBlock))
                {
                    treeBuilder.AppendFormat(CultureInfo.CurrentCulture, "Auto Complete Insert String: \"{0}\"", parser.GetAutoCompleteString());
                    treeBuilder.AppendLine();
                }
                File.WriteAllText(outputPath, treeBuilder.ToString());
            });
        }
        public void ImplicitExpressionAcceptsIdentifierTypedAfterDotIfLastChangeWasProvisionalAcceptanceOfDot()
        {
            var factory = SpanFactory.CreateCsHtml();

            // Arrange
            TextChange        dotTyped  = new TextChange(8, 0, new StringTextBuffer("foo @foo bar"), 1, new StringTextBuffer("foo @foo. bar"));
            TextChange        charTyped = new TextChange(9, 0, new StringTextBuffer("foo @foo. bar"), 1, new StringTextBuffer("foo @foo.b bar"));
            TestParserManager manager   = CreateParserManager();

            manager.InitializeWithDocument(dotTyped.OldBuffer);

            // Apply the dot change
            Assert.Equal(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));

            // Act (apply the identifier start char change)
            PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);

            // Assert
            Assert.Equal(PartialParseResult.Accepted, result);
            Assert.False(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
            ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
                                             new MarkupBlock(
                                                 factory.Markup("foo "),
                                                 new ExpressionBlock(
                                                     factory.CodeTransition(),
                                                     factory.Code("foo.b")
                                                     .AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
                                                     .Accepts(AcceptedCharacters.NonWhiteSpace)),
                                                 factory.Markup(" bar")));
        }
示例#9
0
        public void ImplicitExpressionAcceptsDotlessCommitInsertionsInStatementBlockAfterIdentifiers()
        {
            SpanFactory      factory = SpanFactory.CreateCsHtml();
            StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
                                                            + "    @DateTime." + Environment.NewLine
                                                            + "}");
            StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
                                                        + "    @DateTime" + Environment.NewLine
                                                        + "}");

            var textChange = new TextChange(17, 0, old, 1, changed);

            using (TestParserManager manager = CreateParserManager())
            {
                Action <TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
                {
                    PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);

                    // Assert
                    Assert.Equal(expectedResult, result);
                    Assert.Equal(1, manager.ParseCount);
                    ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
                                                         factory.EmptyHtml(),
                                                         new StatementBlock(
                                                             factory.CodeTransition(),
                                                             factory.MetaCode("{").Accepts(AcceptedCharacters.None),
                                                             factory.Code("\r\n    ").AsStatement(),
                                                             new ExpressionBlock(
                                                                 factory.CodeTransition(),
                                                                 factory.Code(expectedCode)
                                                                 .AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
                                                                 .Accepts(AcceptedCharacters.NonWhiteSpace)),
                                                             factory.Code("\r\n").AsStatement(),
                                                             factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
                                                         factory.EmptyHtml()));
                };

                manager.InitializeWithDocument(textChange.OldBuffer);

                // This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
                applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime.");

                old     = changed;
                changed = new StringTextBuffer("@{" + Environment.NewLine
                                               + "    @DateTime.." + Environment.NewLine
                                               + "}");
                textChange = new TextChange(18, 0, old, 1, changed);

                applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime..");

                old     = changed;
                changed = new StringTextBuffer("@{" + Environment.NewLine
                                               + "    @DateTime.Now." + Environment.NewLine
                                               + "}");
                textChange = new TextChange(18, 0, old, 3, changed);

                applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime.Now.");
            }
        }
            public PartialParseResult CheckForStructureChangesAndWait(TextChange change)
            {
                PartialParseResult result = Parser.CheckForStructureChanges(change);

                if (result.HasFlag(PartialParseResult.Rejected))
                {
                    WaitForParse();
                }
                return(result);
            }
        private PartialParseResult HandleDotlessCommitInsertion(Span target)
        {
            PartialParseResult result = PartialParseResult.Accepted;

            if (!AcceptTrailingDot && target.Content.LastOrDefault() == '.')
            {
                result |= PartialParseResult.Provisional;
            }
            return(result);
        }
示例#12
0
        /// <summary>
        /// Determines if a change will cause a structural change to the document and if not, applies it to the existing tree.
        /// If a structural change would occur, automatically starts a reparse
        /// </summary>
        /// <remarks>
        /// NOTE: The initial incremental parsing check and actual incremental parsing (if possible) occurs
        /// on the callers thread.  However, if a full reparse is needed, this occurs on a background thread.
        /// </remarks>
        /// <param name="change">The change to apply to the parse tree</param>
        /// <returns>A PartialParseResult value indicating the result of the incremental parse</returns>
        public virtual PartialParseResult CheckForStructureChanges(TextChange change)
        {
            // Validate the change
            long?elapsedMs = null;

#if EDITOR_TRACING
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif
            RazorEditorTrace.TraceLine(RazorResources.FormatTrace_EditorReceivedChange(Path.GetFileName(FileName), change));
            if (change.NewBuffer == null)
            {
                throw new ArgumentException(RazorResources.FormatStructure_Member_CannotBeNull(
                                                "Buffer",
                                                "TextChange"), "change");
            }

            PartialParseResult result = PartialParseResult.Rejected;

            // If there isn't already a parse underway, try partial-parsing
            string changeString = String.Empty;
            using (_parser.SynchronizeMainThreadState())
            {
                // Capture the string value of the change while we're synchronized
                changeString = change.ToString();

                // Check if we can partial-parse
                if (CurrentParseTree != null && _parser.IsIdle)
                {
                    result = TryPartialParse(change);
                }
            }

            // If partial parsing failed or there were outstanding parser tasks, start a full reparse
            if (result.HasFlag(PartialParseResult.Rejected))
            {
                _parser.QueueChange(change);
            }

            // Otherwise, remember if this was provisionally accepted for next partial parse
            LastResultProvisional = result.HasFlag(PartialParseResult.Provisional);
            VerifyFlagsAreValid(result);

#if EDITOR_TRACING
            sw.Stop();
            elapsedMs = sw.ElapsedMilliseconds;
            sw.Reset();
#endif
            RazorEditorTrace.TraceLine(
                RazorResources.FormatTrace_EditorProcessedChange(
                    Path.GetFileName(FileName),
                    changeString, elapsedMs.HasValue ? elapsedMs.Value.ToString(CultureInfo.InvariantCulture) : "?",
                    result.ToString()));
            return(result);
        }
        private PartialParseResult TryAcceptChange(Span target, TextChange change, PartialParseResult acceptResult = PartialParseResult.Accepted)
        {
            string content = change.ApplyChange(target);

            if (StartsWithKeyword(content))
            {
                return(PartialParseResult.Rejected | PartialParseResult.SpanContextChanged);
            }

            return(acceptResult);
        }
示例#14
0
        private PartialParseResult TryAcceptChange(Span target, SourceChange change, PartialParseResult acceptResult = PartialParseResult.Accepted)
        {
            var content = change.GetEditedContent(target);

            if (StartsWithKeyword(content))
            {
                return(PartialParseResult.Rejected | PartialParseResult.SpanContextChanged);
            }

            return(acceptResult);
        }
示例#15
0
        public void ApplyChangeReturnsRejectedIfTerminatorStringNull()
        {
            // Arrange
            var span   = new CodeSpan(new SourceLocation(0, 0, 0), "foo");
            var change = new TextChange(0, 0, new StringTextBuffer("foo"), 1, new StringTextBuffer("bfoo"));

            // Act
            PartialParseResult result = span.ApplyChange(change);

            // Assert
            Assert.AreEqual(PartialParseResult.Rejected, result);
        }
示例#16
0
        private PartialParseResult TryPartialParse(TextChange change)
        {
            PartialParseResult result = PartialParseResult.Rejected;

            // Try the last change owner
            if (
                _lastChangeOwner != null &&
                _lastChangeOwner.EditHandler.OwnsChange(_lastChangeOwner, change)
                )
            {
                EditResult editResult = _lastChangeOwner.EditHandler.ApplyChange(
                    _lastChangeOwner,
                    change
                    );
                result = editResult.Result;
                if (!editResult.Result.HasFlag(PartialParseResult.Rejected))
                {
                    _lastChangeOwner.ReplaceWith(editResult.EditedSpan);
                }

                return(result);
            }

            // Locate the span responsible for this change
            _lastChangeOwner = CurrentParseTree.LocateOwner(change);

            if (LastResultProvisional)
            {
                // Last change owner couldn't accept this, so we must do a full reparse
                result = PartialParseResult.Rejected;
            }
            else if (_lastChangeOwner != null)
            {
                EditResult editRes = _lastChangeOwner.EditHandler.ApplyChange(
                    _lastChangeOwner,
                    change
                    );
                result = editRes.Result;
                if (!editRes.Result.HasFlag(PartialParseResult.Rejected))
                {
                    _lastChangeOwner.ReplaceWith(editRes.EditedSpan);
                }
                if (result.HasFlag(PartialParseResult.AutoCompleteBlock))
                {
                    _lastAutoCompleteSpan = _lastChangeOwner;
                }
                else
                {
                    _lastAutoCompleteSpan = null;
                }
            }
            return(result);
        }
示例#17
0
        protected static void RunFullReparseTest(TextChange change, PartialParseResult additionalFlags = (PartialParseResult)0)
        {
            // Arrange
            TestParserManager manager = CreateParserManager();

            manager.InitializeWithDocument(change.OldBuffer);

            // Act
            PartialParseResult result = manager.CheckForStructureChangesAndWait(change);

            // Assert
            Assert.Equal(PartialParseResult.Rejected | additionalFlags, result);
            Assert.Equal(2, manager.ParseCount);
        }
示例#18
0
        public void SpanWithAcceptTrailingDotOnAcceptsIntelliSenseReplaceWhichActuallyInsertsDot()
        {
            // Arrange
            var span       = new ImplicitExpressionSpan("abcd", CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true, acceptedCharacters: AcceptedCharacters.None);
            var newBuffer  = new StringTextBuffer("abcd.");
            var oldBuffer  = new StringTextBuffer("abcd");
            var textChange = new TextChange(0, 4, oldBuffer, 5, newBuffer);

            // Act
            PartialParseResult result = span.ApplyChange(textChange);

            // Assert
            Assert.AreEqual(PartialParseResult.Accepted, result);
        }
示例#19
0
        public void SpanWithAcceptTrailingDotOffProvisionallyAcceptsEndReplacementWithTrailingDot()
        {
            // Arrange
            var span       = new ImplicitExpressionSpan("abcd.", CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false, acceptedCharacters: AcceptedCharacters.None);
            var newBuffer  = new StringTextBuffer("abcdef.");
            var oldBuffer  = new StringTextBuffer("abcd.");
            var textChange = new TextChange(0, 5, oldBuffer, 7, newBuffer);

            // Act
            PartialParseResult result = span.ApplyChange(textChange);

            // Assert
            Assert.AreEqual(PartialParseResult.Accepted | PartialParseResult.Provisional, result);
        }
示例#20
0
        protected static void RunFullReparseTest(TextChange change, PartialParseResult additionalFlags = (PartialParseResult)0)
        {
            // Arrange
            TestParserManager manager = CreateParserManager();

            manager.InitializeWithDocument(change.OldBuffer);

            // Act
            PartialParseResult result = manager.CheckForStructureChangesAndWait(change);

            // Assert
            Assert.AreEqual(PartialParseResult.Rejected | additionalFlags, result, "The specified change did not cause a structural change");
            Assert.AreEqual(2, manager.ParseCount, "Expected that the change would cause a full reparse");
        }
示例#21
0
        private PartialParseResult TryPartialParse(TextChange change)
        {
            PartialParseResult result = PartialParseResult.Rejected;

            // Try the last change owner
            if (_lastChangeOwner != null && _lastChangeOwner.EditHandler.OwnsChange(_lastChangeOwner, change))
            {
                EditResult editResult = _lastChangeOwner.EditHandler.ApplyChange(_lastChangeOwner, change);
                result = editResult.Result;
                if (!editResult.Result.HasFlag(PartialParseResult.Rejected))
                {
                    _lastChangeOwner.ReplaceWith(editResult.EditedSpan);
                }

                // If the last change was provisional, then the result of this span's attempt to parse partially goes
                // Otherwise, accept the change if this span accepted it, but if it didn't, just do the standard search.
                if (LastResultProvisional || result.HasFlag(PartialParseResult.Accepted))
                {
                    return(result);
                }
            }

            // Locate the span responsible for this change
            _lastChangeOwner = CurrentParseTree.LocateOwner(change);

            if (LastResultProvisional)
            {
                // Last change owner couldn't accept this, so we must do a full reparse
                result = PartialParseResult.Rejected;
            }
            else if (_lastChangeOwner != null)
            {
                EditResult editRes = _lastChangeOwner.EditHandler.ApplyChange(_lastChangeOwner, change);
                result = editRes.Result;
                if (!editRes.Result.HasFlag(PartialParseResult.Rejected))
                {
                    _lastChangeOwner.ReplaceWith(editRes.EditedSpan);
                }
                if (result.HasFlag(PartialParseResult.AutoCompleteBlock))
                {
                    _lastAutoCompleteSpan = _lastChangeOwner;
                }
                else
                {
                    _lastAutoCompleteSpan = null;
                }
            }
            return(result);
        }
示例#22
0
        protected static void RunPartialParseTest(TextChange change, Block newTreeRoot, PartialParseResult additionalFlags = (PartialParseResult)0)
        {
            // Arrange
            TestParserManager manager = CreateParserManager();

            manager.InitializeWithDocument(change.OldBuffer);

            // Act
            PartialParseResult result = manager.CheckForStructureChangesAndWait(change);

            // Assert
            Assert.Equal(PartialParseResult.Accepted | additionalFlags, result);
            Assert.Equal(1, manager.ParseCount);
            ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, newTreeRoot);
        }
示例#23
0
        public void ApplyChangeReturnsRejectedWithoutAutoCompleteBlockIfTerminatorStringNonNullAndEditIsNewlineInsertOnSecondLine()
        {
            // Arrange
            var span = new CodeSpan(new SourceLocation(0, 0, 0), "foo\r\nbar\r\nbaz")
            {
                AutoCompleteString = "}"
            };
            var change = new TextChange(8, 0, new StringTextBuffer("foo\r\nbar\r\nbaz"), 2, new StringTextBuffer("foo\r\nb\r\nar\r\nbaz"));

            // Act
            PartialParseResult result = span.ApplyChange(change);

            // Assert
            Assert.AreEqual(PartialParseResult.Rejected, result);
        }
示例#24
0
 private static void VerifyFlagsAreValid(PartialParseResult result)
 {
     Debug.Assert(((result & PartialParseResult.Accepted) == PartialParseResult.Accepted) ||
                  ((result & PartialParseResult.Rejected) == PartialParseResult.Rejected),
                  "Partial Parse result does not have either of Accepted or Rejected flags set");
     Debug.Assert(((result & PartialParseResult.Rejected) == PartialParseResult.Rejected) ||
                  ((result & PartialParseResult.SpanContextChanged) != PartialParseResult.SpanContextChanged),
                  "Partial Parse result was Accepted AND had SpanContextChanged flag set");
     Debug.Assert(((result & PartialParseResult.Rejected) == PartialParseResult.Rejected) ||
                  ((result & PartialParseResult.AutoCompleteBlock) != PartialParseResult.AutoCompleteBlock),
                  "Partial Parse result was Accepted AND had AutoCompleteBlock flag set");
     Debug.Assert(((result & PartialParseResult.Accepted) == PartialParseResult.Accepted) ||
                  ((result & PartialParseResult.Provisional) != PartialParseResult.Provisional),
                  "Partial Parse result was Rejected AND had Provisional flag set");
 }
示例#25
0
        /// <summary>
        /// Determines if a change will cause a structural change to the document and if not, applies it to the existing tree.
        /// If a structural change would occur, automatically starts a reparse
        /// </summary>
        /// <remarks>
        /// NOTE: The initial incremental parsing check and actual incremental parsing (if possible) occurs
        /// on the callers thread.  However, if a full reparse is needed, this occurs on a background thread.
        /// </remarks>
        /// <param name="change">The change to apply to the parse tree</param>
        /// <returns>A PartialParseResult value indicating the result of the incremental parse</returns>
        public virtual PartialParseResult CheckForStructureChanges(TextChange change)
        {
            // Validate the change
            if (change.NewBuffer == null)
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture,
                                                          RazorResources.Structure_Member_CannotBeNull,
                                                          "Buffer",
                                                          "TextChange"), "change");
            }

            PartialParseResult result = PartialParseResult.Rejected;

            // Lock the state objects
            lock (_lock)
            {
                // If there isn't already a parse underway, try partial-parsing
                if (CurrentParseTree != null && _outstandingParserTasks.Count == 0)
                {
                    result = TryPartialParse(change);
                }

                // If partial parsing failed or there were outstanding parser tasks, start a full reparse
                if (result.HasFlag(PartialParseResult.Rejected))
                {
                    QueueFullReparse(change);
                }
#if DEBUG
                else
                {
                    if (CurrentParseTree != null)
                    {
                        RazorDebugHelpers.WriteDebugTree(FileName, CurrentParseTree, result, change, this, false);
                    }
                    if (_currentCompileUnit != null)
                    {
                        RazorDebugHelpers.WriteGeneratedCode(FileName, _currentCompileUnit);
                    }
                }
#endif

                // Otherwise, remember if this was provisionally accepted for next partial parse
                LastResultProvisional = result.HasFlag(PartialParseResult.Provisional);
            }
            VerifyFlagsAreValid(result);
            return(result);
        }
        public virtual EditResult ApplyChange(Span target, TextChange change, bool force)
        {
            PartialParseResult result     = PartialParseResult.Accepted;
            TextChange         normalized = change.Normalize();

            if (!force)
            {
                result = CanAcceptChange(target, normalized);
            }

            // If the change is accepted then apply the change
            if (result.HasFlag(PartialParseResult.Accepted))
            {
                return(new EditResult(result, UpdateSpan(target, normalized)));
            }
            return(new EditResult(result, new SpanBuilder(target)));
        }
示例#27
0
文件: Span.cs 项目: 316729240/M5
        /// <summary>
        /// Applies the specified change to this span, optionally forcing it to accept it
        /// </summary>
        /// <param name="force">If true, no evaluation is performed, the content of the span is simply updated based on the change</param>
        /// <remarks>
        /// If this method returns a value with the PartialParseResults.Accepted flag, the change has been applied to the span.
        /// If force was specified, this does not indicate that the partial parsing was successful, only that the Span now reflects the applied change.
        /// </remarks>
        /// <returns>true if the change was successfully applied, false if it wasn't</returns>
        public PartialParseResult ApplyChange(TextChange change, bool force)
        {
            PartialParseResult result     = PartialParseResult.Accepted;
            TextChange         normalized = change.Normalize();

            if (!force)
            {
                result = CanAcceptChange(normalized);
            }

            // If the change is accepted then apply the change
            if (result.HasFlag(PartialParseResult.Accepted))
            {
                UpdateContent(normalized);
            }

            return(result);
        }
示例#28
0
        private void CheckForStructureChanges(TextChange textChange)
        {
            SetProvisionallyAcceptedState(false);
            PartialParseResult partialParseResult = _razorEditorParser.CheckForStructureChanges(textChange);

            CreateAutoBlockCompleter(partialParseResult, textChange);
            if (IsFlagSet(partialParseResult, PartialParseResult.Rejected))
            {
                _pendingShimTextChange = new TextChange?(textChange);
            }
            if (IsFlagSet(partialParseResult, PartialParseResult.Provisional))
            {
                SetProvisionallyAcceptedState(true);
            }
            if (IsFlagSet(partialParseResult, PartialParseResult.SpanContextChanged))
            {
                _spanContextChanged = true;
            }
        }
示例#29
0
        public void ImplicitExpressionRejectsWholeIdentifierReplacementToKeyword()
        {
            // Arrange
            RazorEngineHost   host   = CreateHost();
            RazorEditorParser parser = new RazorEditorParser(host, @"C:\This\Is\A\Test\Path");

            TestParserManager manager    = new TestParserManager(parser);
            StringTextBuffer  old        = new StringTextBuffer("foo @date baz");
            StringTextBuffer  changed    = new StringTextBuffer("foo @if baz");
            TextChange        textChange = new TextChange(5, 4, old, 2, changed);

            manager.InitializeWithDocument(old);

            // Act
            PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);

            // Assert
            Assert.Equal(PartialParseResult.Rejected, result);
            Assert.Equal(2, manager.ParseCount);
        }
        private PartialParseResult HandleReplacement(Span target, TextChange change)
        {
            // Special Case for IntelliSense commits.
            //  When IntelliSense commits, we get two changes (for example user typed "Date", then committed "DateTime" by pressing ".")
            //  1. Insert "." at the end of this span
            //  2. Replace the "Date." at the end of the span with "DateTime."
            //  We need partial parsing to accept case #2.
            string oldText = GetOldText(target, change);

            PartialParseResult result = PartialParseResult.Rejected;

            if (EndsWithDot(oldText) && EndsWithDot(change.NewText))
            {
                result = PartialParseResult.Accepted;
                if (!AcceptTrailingDot)
                {
                    result |= PartialParseResult.Provisional;
                }
            }
            return(result);
        }
 private PartialParseResult HandleInsertionAfterIdPart(Span target, TextChange change)
 {
     // If the insertion is a full identifier part, accept it
     if (ParserHelpers.IsIdentifier(change.NewText, requireIdentifierStart: false))
     {
         return(TryAcceptChange(target, change));
     }
     else if (EndsWithDot(change.NewText))
     {
         // Accept it, possibly provisionally
         PartialParseResult result = PartialParseResult.Accepted;
         if (!AcceptTrailingDot)
         {
             result |= PartialParseResult.Provisional;
         }
         return(TryAcceptChange(target, change, result));
     }
     else
     {
         return(PartialParseResult.Rejected);
     }
 }
示例#32
0
		private void CreateAutoBlockCompleter(PartialParseResult parseResult, TextChange textChange)
		{
			if (IsFlagSet(parseResult, PartialParseResult.AutoCompleteBlock))
			{
				_autoBlockCompletor = new AutoBlockCompletor(TextView, textChange.NewPosition, _razorEditorParser.GetAutoCompleteString());
				return;
			}
			if (textChange.OldLength == 0 && textChange.NewLength > 0 && textChange.NewLength <= 2 && Whitespace.IsNewLine((textChange.NewBuffer as IShimTextBuffer).Snapshot.GetText(textChange.NewPosition, textChange.NewLength)) && _viewBuffer.ContentType.IsOfType("RazorCSharp"))
			{
				ITextSnapshot currentSnapshot = _viewBuffer.CurrentSnapshot;
				ITextSnapshotLine lineFromPosition = currentSnapshot.GetLineFromPosition(textChange.NewPosition);
				string text = lineFromPosition.GetText();
				int num = Math.Min(lineFromPosition.Length, textChange.NewPosition - lineFromPosition.Start) - 1;
				while (num >= 0 && char.IsWhiteSpace(text[num]))
				{
					num--;
				}
				if (num >= 1 && text[num] == '{' && text[num - 1] == '@')
				{
					int num2 = textChange.NewPosition + textChange.NewLength;
					ITextSnapshotLine lineFromPosition2 = currentSnapshot.GetLineFromPosition(num2);
					string text2 = lineFromPosition2.GetText();
					int num3 = num2 - lineFromPosition2.Start;
					while (num3 < lineFromPosition2.Length && char.IsWhiteSpace(text2[num3]))
					{
						num3++;
					}
					if (num3 < lineFromPosition2.Length && text2[num3] == '}')
					{
						_autoBlockCompletor = new AutoBlockCompletor(TextView, textChange.NewPosition, string.Empty);
					}
				}
			}
		}
        private PartialParseResult TryAcceptChange(Span target, TextChange change, PartialParseResult acceptResult = PartialParseResult.Accepted)
        {
            string content = change.ApplyChange(target);
            if (StartsWithKeyword(content))
            {
                return PartialParseResult.Rejected | PartialParseResult.SpanContextChanged;
            }

            return acceptResult;
        }
示例#34
0
 public EditResult(PartialParseResult result, SpanBuilder editedSpan)
 {
     Result = result;
     EditedSpan = editedSpan;
 }
示例#35
0
		private bool IsFlagSet(PartialParseResult toTest, PartialParseResult flag)
		{
			return (toTest & flag) > (PartialParseResult)0;
		}
示例#36
0
 private static void VerifyFlagsAreValid(PartialParseResult result)
 {
     Debug.Assert(((result & PartialParseResult.Accepted) == PartialParseResult.Accepted) ||
                  ((result & PartialParseResult.Rejected) == PartialParseResult.Rejected),
                  "Partial Parse result does not have either of Accepted or Rejected flags set");
     Debug.Assert(((result & PartialParseResult.Rejected) == PartialParseResult.Rejected) ||
                  ((result & PartialParseResult.SpanContextChanged) != PartialParseResult.SpanContextChanged),
                  "Partial Parse result was Accepted AND had SpanContextChanged flag set");
     Debug.Assert(((result & PartialParseResult.Rejected) == PartialParseResult.Rejected) ||
                  ((result & PartialParseResult.AutoCompleteBlock) != PartialParseResult.AutoCompleteBlock),
                  "Partial Parse result was Accepted AND had AutoCompleteBlock flag set");
     Debug.Assert(((result & PartialParseResult.Accepted) == PartialParseResult.Accepted) ||
                  ((result & PartialParseResult.Provisional) != PartialParseResult.Provisional),
                  "Partial Parse result was Rejected AND had Provisional flag set");
 }