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());
            });
        }
 private BackgroundParseTask(RazorTemplateEngine engine, string sourceFileName, TextChange change)
 {
     Change = change;
     Engine = engine;
     SourceFileName = sourceFileName;
     InnerTask = new Task(() => Run(_cancelSource.Token), _cancelSource.Token);
 }
        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.AreEqual(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.AreEqual(PartialParseResult.Rejected, result);
            MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
            Assert.AreEqual(2, parseCount);
        }
Exemplo n.º 4
0
 public virtual bool OwnsChange(Span target, TextChange change)
 {
     int end = target.Start.AbsoluteIndex + target.Length;
     int changeOldEnd = change.OldPosition + change.OldLength;
     return change.OldPosition >= target.Start.AbsoluteIndex &&
            (changeOldEnd < end || (changeOldEnd == end && AcceptedCharacters != AcceptedCharacters.None));
 }
Exemplo n.º 5
0
        public void OwnsChangeReturnsFalseIfChangeIsReplacementOrDeleteAtSpanEnd() {
            // Arrange
            Span span = new CodeSpan(new SourceLocation(42, 0, 42), "FooBarBaz");
            TextChange change = new TextChange(51, 2, new StringTextBuffer("BooBarBaz"), 3, new StringTextBuffer("Foo"));

            // Act/Assert
            Assert.IsFalse(span.OwnsChange(change));
        }
Exemplo n.º 6
0
        public void OwnsChangeReturnsTrueIfChangeIsInsertionAtSpanEndAndCanGrowIsTrue() {
            // Arrange
            Span span = new CodeSpan(new SourceLocation(42, 0, 42), "FooBarBaz");
            TextChange change = new TextChange(51, 0, new StringTextBuffer("BooBarBaz"), 3, new StringTextBuffer("Foo"));

            // Act/Assert
            Assert.IsTrue(span.OwnsChange(change));
        }
Exemplo n.º 7
0
        public void OwnsChangeReturnsFalseIfChangeStartsAfterSpanEnds() {
            // Arrange
            Span span = new CodeSpan(new SourceLocation(42, 0, 42), "FooBarBaz");
            TextChange change = new TextChange(52, 3, new StringTextBuffer("BooBarBaz"), 3, new StringTextBuffer("Foo"));

            // Act/Assert
            Assert.IsFalse(span.OwnsChange(change));
        }
Exemplo n.º 8
0
        public void OwnsChangeReturnsTrueIfSpanContentEntirelyContainsOldSpan() {
            // Arrange
            Span span = new CodeSpan(new SourceLocation(42, 0, 42), "FooBarBaz");
            TextChange change = new TextChange(45, 3, new StringTextBuffer("BooBarBaz"), 3, new StringTextBuffer("Foo"));

            // Act/Assert
            Assert.IsTrue(span.OwnsChange(change));
        }
        public void CheckForStructureChangesRequiresNonNullBufferInChange() {
            TextChange change = new TextChange();
            ExceptionAssert.ThrowsArgumentException(() => new RazorEditorParser(CreateHost(),
                                                                     "C:\\Foo.cshtml").CheckForStructureChanges(change),
                                                    "change",
                                                    String.Format(RazorResources.Structure_Member_CannotBeNull, "Buffer", "TextChange"));

        }
Exemplo n.º 10
0
        public void TestIsInsert() {
            // Arrange 
            ITextBuffer oldBuffer = new Mock<ITextBuffer>().Object;
            ITextBuffer newBuffer = new Mock<ITextBuffer>().Object;
            TextChange change = new TextChange(0, 0, oldBuffer, 35, newBuffer);

            // Assert
            Assert.IsTrue(change.IsInsert);
        }
Exemplo n.º 11
0
        public void TestIsReplace() {
            // Arrange 
            ITextBuffer oldBuffer = new Mock<ITextBuffer>().Object;
            ITextBuffer newBuffer = new Mock<ITextBuffer>().Object;
            TextChange change = new TextChange(0, 5, oldBuffer, 10, newBuffer);

            // Assert
            Assert.IsTrue(change.IsReplace);
        }
        public void TestIsDelete()
        {
            // Arrange 
            ITextBuffer oldBuffer = new Mock<ITextBuffer>().Object;
            ITextBuffer newBuffer = new Mock<ITextBuffer>().Object;
            TextChange change = new TextChange(0, 1, oldBuffer, 0, newBuffer);

            // Assert
            Assert.True(change.IsDelete);
        }
Exemplo n.º 13
0
        public void TestDeleteCreatesTheRightSizeChange()
        {
            // Arrange 
            ITextBuffer oldBuffer = new Mock<ITextBuffer>().Object;
            ITextBuffer newBuffer = new Mock<ITextBuffer>().Object;
            TextChange change = new TextChange(0, 1, oldBuffer, 0, newBuffer);

            // Assert
            Assert.Equal(0, change.NewText.Length);
            Assert.Equal(1, change.OldText.Length);
        }
Exemplo n.º 14
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);
        }
 protected override PartialParseResult CanAcceptChange(Span target, TextChange normalizedChange)
 {
     if (((AutoCompleteAtEndOfSpan && IsAtEndOfSpan(target, normalizedChange)) || IsAtEndOfFirstLine(target, normalizedChange)) &&
         normalizedChange.IsInsert &&
         ParserHelpers.IsNewLine(normalizedChange.NewText) &&
         AutoCompleteString != null)
     {
         return PartialParseResult.Rejected | PartialParseResult.AutoCompleteBlock;
     }
     return PartialParseResult.Rejected;
 }
        protected override PartialParseResult CanAcceptChange(Span target, TextChange normalizedChange)
        {
            if (AcceptedCharacters == AcceptedCharacters.Any)
            {
                return PartialParseResult.Rejected;
            }

            // In some editors intellisense insertions are handled as "dotless commits".  If an intellisense selection is confirmed 
            // via something like '.' a dotless commit will append a '.' and then insert the remaining intellisense selection prior 
            // to the appended '.'.  This 'if' statement attempts to accept the intermediate steps of a dotless commit via 
            // intellisense.  It will accept two cases:
            //     1. '@foo.' -> '@foobaz.'.
            //     2. '@foobaz..' -> '@foobaz.bar.'. Includes Sub-cases '@foobaz()..' -> '@foobaz().bar.' etc.
            // The key distinction being the double '.' in the second case.
            if (IsDotlessCommitInsertion(target, normalizedChange))
            {
                return HandleDotlessCommitInsertion(target);
            }

            if (IsAcceptableReplace(target, normalizedChange))
            {
                return HandleReplacement(target, normalizedChange);
            }
            int changeRelativePosition = normalizedChange.OldPosition - target.Start.AbsoluteIndex;

            // Get the edit context
            char? lastChar = null;
            if (changeRelativePosition > 0 && target.Content.Length > 0)
            {
                lastChar = target.Content[changeRelativePosition - 1];
            }

            // Don't support 0->1 length edits
            if (lastChar == null)
            {
                return PartialParseResult.Rejected;
            }

            // Accepts cases when insertions are made at the end of a span or '.' is inserted within a span.
            if (IsAcceptableInsertion(target, normalizedChange))
            {
                // Handle the insertion
                return HandleInsertion(target, lastChar.Value, normalizedChange);
            }

            if (IsAcceptableDeletion(target, normalizedChange))
            {
                return HandleDeletion(target, lastChar.Value, normalizedChange);
            }

            return PartialParseResult.Rejected;
        }
        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);
        }
        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);
        }
Exemplo n.º 19
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);
        }
Exemplo n.º 20
0
        public void ConstructorInitializesProperties() {
            // Act
            ITextBuffer oldBuffer = new Mock<ITextBuffer>().Object;
            ITextBuffer newBuffer = new Mock<ITextBuffer>().Object;
            TextChange change = new TextChange(42, 24, oldBuffer, 1337, newBuffer);

            // Assert
            Assert.AreEqual(42, change.OldPosition);
            Assert.AreEqual(24, change.OldLength);
            Assert.AreEqual(1337, change.NewLength);
            Assert.AreSame(newBuffer, change.NewBuffer);
            Assert.AreSame(oldBuffer, change.OldBuffer);
        }
Exemplo n.º 21
0
        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));
        }
Exemplo n.º 22
0
 protected virtual SpanBuilder UpdateSpan(Span target, TextChange normalizedChange)
 {
     string newContent = normalizedChange.ApplyChange(target);
     SpanBuilder newSpan = new SpanBuilder(target);
     newSpan.ClearSymbols();
     foreach (ISymbol sym in Tokenizer(newContent))
     {
         sym.OffsetStart(target.Start);
         newSpan.Accept(sym);
     }
     if (target.Next != null)
     {
         SourceLocation newEnd = SourceLocationTracker.CalculateNewLocation(target.Start, newContent);
         target.Next.ChangeStart(newEnd);
     }
     return newSpan;
 }
Exemplo n.º 23
0
        public void LocateOwnerReturnsNullIfNoSpanReturnsTrueForOwnsSpan() {
            // Arrange
            Block block = new Block(BlockType.Markup, new SyntaxTreeNode[] {
                new MarkupSpan(SourceLocation.Zero, "Foo "),
                new StatementBlock(new SyntaxTreeNode[] {
                    new TransitionSpan(new SourceLocation(4, 0, 4), "@"),
                    new CodeSpan(new SourceLocation(5, 0, 5), "bar"),
                }),
                new MarkupSpan(new SourceLocation(8,0,8), " Baz")
            });
            TextChange change = new TextChange(128, 1, new StringTextBuffer("Foo @bar Baz"), 1, new StringTextBuffer("Foo @bor Baz"));

            // Act
            Span actual = block.LocateOwner(change);

            // Assert
            Assert.IsNull(actual);
        }
Exemplo n.º 24
0
        public void LocateOwnerReturnsSpanWhichReturnsTrueForOwnsSpan() {
            // Arrange
            Span expected = new CodeSpan(new SourceLocation(5, 0, 5), "bar");
            Block block = new MarkupBlock(new SyntaxTreeNode[] {
                new MarkupSpan(SourceLocation.Zero, "Foo "),
                new StatementBlock(new SyntaxTreeNode[] {
                    new TransitionSpan(new SourceLocation(4, 0, 4), "@"),
                    expected,
                }),
                new MarkupSpan(new SourceLocation(8,0,8), " Baz")
            });
            TextChange change = new TextChange(6, 1, new StringTextBuffer("Foo @bar Baz"), 1, new StringTextBuffer("Foo @bor Baz"));

            // Act
            Span actual = block.LocateOwner(change);

            // Assert
            Assert.AreSame(expected, actual);
        }
        protected override PartialParseResult CanAcceptChange(Span target, TextChange normalizedChange)
        {
            if (AcceptedCharacters == AcceptedCharacters.Any)
            {
                return PartialParseResult.Rejected;
            }

            if (IsAcceptableReplace(target, normalizedChange))
            {
                return HandleReplacement(target, normalizedChange);
            }
            int changeRelativePosition = normalizedChange.OldPosition - target.Start.AbsoluteIndex;

            // Get the edit context
            char? lastChar = null;
            if (changeRelativePosition > 0 && target.Content.Length > 0)
            {
                lastChar = target.Content[changeRelativePosition - 1];
            }

            // Don't support 0->1 length edits
            if (lastChar == null)
            {
                return PartialParseResult.Rejected;
            }

            // Only support insertions at the end of the span
            if (IsAcceptableInsertion(target, normalizedChange))
            {
                // Handle the insertion
                return HandleInsertion(target, lastChar.Value, normalizedChange);
            }

            if (IsAcceptableDeletion(target, normalizedChange))
            {
                return HandleDeletion(target, lastChar.Value, normalizedChange);
            }

            return PartialParseResult.Rejected;
        }
        protected override PartialParseResult CanAcceptChange(TextChange change) {
            if (AcceptedCharacters == AcceptedCharacters.Any) {
                // TODO: Support partial parsing within brackets (with provisionally accepted "(" and "["?)
                return PartialParseResult.Rejected;
            }

            if (IsAcceptableReplace(change)) {
                return HandleReplacement(change);
            }
            else {
                int changeRelativePosition = change.OldPosition - Start.AbsoluteIndex;

                // Get the edit context
                char? lastChar = null;
                if (changeRelativePosition > 0 && Content.Length > 0) {
                    lastChar = Content[changeRelativePosition - 1];
                }

                // Don't support 0->1 length edits
                if (lastChar == null) {
                    return PartialParseResult.Rejected;
                }

                // Only support insertions at the end of the span
                if (IsAcceptableInsertion(change)) {
                    // Handle the insertion
                    return HandleInsertion(lastChar.Value, change);

                }
                else if (IsAcceptableDeletion(change)) {
                    return HandleDeletion(lastChar.Value, change);
                }
            }

            return PartialParseResult.Rejected;
        }
 private static bool IsAcceptableReplace(Span target, TextChange change)
 {
     return IsEndReplace(target, change) ||
            (change.IsReplace && RemainingIsWhitespace(target, change));
 }
        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;
        }
 private PartialParseResult HandleInsertionAfterDot(Span target, TextChange change)
 {
     // If the insertion is a full identifier, accept it
     if (ParserHelpers.IsIdentifier(change.NewText))
     {
         return TryAcceptChange(target, change);
     }
     return PartialParseResult.Rejected;
 }
 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;
     }
 }