示例#1
0
        public void CheckForStructureChangesStartsFullReparseIfChangeOverlapsMultipleSpans()
        {
            // Arrange
            using (var parser = new RazorEditorParser(CreateHost(), TestLinePragmaFileName))
            {
                var original = new StringTextBuffer("Foo @bar Baz");
                var changed = new StringTextBuffer("Foo @bap Daz");
                var change = new TextChange(7, 3, original, 3, changed);

                var parseComplete = new ManualResetEventSlim();
                var 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
                var result = parser.CheckForStructureChanges(change);

                // Assert
                Assert.Equal(PartialParseResult.Rejected, result);
                MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
                Assert.Equal(2, parseCount);
            }
        }
        private bool TryGetDocumentWithFullyQualifiedTypeName(Document document, out TextSpan updatedTextSpan, out Document documentWithFullyQualifiedTypeName)
        {
            documentWithFullyQualifiedTypeName = null;
            updatedTextSpan = default(TextSpan);

            var surfaceBufferFieldSpan = new VsTextSpan[1];
            if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK)
            {
                return false;
            }

            SnapshotSpan subjectBufferFieldSpan;
            if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out subjectBufferFieldSpan))
            {
                return false;
            }

            var originalTextSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length);
            updatedTextSpan = new TextSpan(subjectBufferFieldSpan.Start, _fullyQualifiedName.Length);

            var textChange = new TextChange(originalTextSpan, _fullyQualifiedName);
            var newText = document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None).WithChanges(textChange);

            documentWithFullyQualifiedTypeName = document.WithText(newText);
            return true;
        }
示例#3
0
 public virtual bool OwnsChange(Span target, TextChange change)
 {
     var end = target.Start.AbsoluteIndex + target.Length;
     var changeOldEnd = change.OldPosition + change.OldLength;
     return change.OldPosition >= target.Start.AbsoluteIndex &&
            (changeOldEnd < end || (changeOldEnd == end && AcceptedCharacters != AcceptedCharacters.None));
 }
        private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            TextChange textChange = new TextChange(new TextSpan(diagnostic.Location.SourceSpan.Start, 1), string.Empty);
            return document.WithText(text.WithChanges(textChange));
        }
示例#5
0
 public void RaiseChangeCompleted(TextChange change)
 {
     var e = ChangeCompleted;
     if (e != null)
     {
         e(this, change);
     }
 }
        private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken token)
        {
            var newLine = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp);

            var sourceText = await document.GetTextAsync(token).ConfigureAwait(false);
            var textChange = new TextChange(diagnostic.Location.SourceSpan, newLine);

            return document.WithText(sourceText.WithChanges(textChange));
        }
示例#7
0
        private CompletionChange(TextChange textChange, int? newPosition, bool includesCommitCharacter)
        {
            TextChange = textChange;
#pragma warning disable CS0618 // Type or member is obsolete
            TextChanges = ImmutableArray.Create(textChange);
#pragma warning restore CS0618 // Type or member is obsolete
            NewPosition = newPosition;
            IncludesCommitCharacter = includesCommitCharacter;
        }
示例#8
0
#pragma warning disable RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads.
#pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters
        public static CompletionChange Create(
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters
#pragma warning restore RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads.
            TextChange textChange,
            int? newPosition = null,
            bool includesCommitCharacter = false)
        {
            return new CompletionChange(textChange, newPosition, includesCommitCharacter);
        }
 public void Bug18241()
 {
     var tree = SyntaxFactory.ParseSyntaxTree(" class C { void M() { await X() on ");
     SourceText text = tree.GetText();
     TextSpan span = new TextSpan(text.Length, 0);
     TextChange change = new TextChange(span, "/*comment*/");
     SourceText newText = text.WithChanges(change);
     // This line caused an assertion and then crashed in the parser.
     var newTree = tree.WithChangedText(newText);
 }
示例#10
0
        public void TestIsDelete()
        {
            // Arrange
            var oldBuffer = new Mock<ITextBuffer>().Object;
            var newBuffer = new Mock<ITextBuffer>().Object;
            var change = new TextChange(0, 1, oldBuffer, 0, newBuffer);

            // Assert
            Assert.True(change.IsDelete);
        }
示例#11
0
        public void TestDeleteCreatesTheRightSizeChange()
        {
            // Arrange
            var oldBuffer = new Mock<ITextBuffer>().Object;
            var newBuffer = new Mock<ITextBuffer>().Object;
            var change = new TextChange(0, 1, oldBuffer, 0, newBuffer);

            // Assert
            Assert.Equal(0, change.NewText.Length);
            Assert.Equal(1, change.OldText.Length);
        }
示例#12
0
 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);
            }
            var 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;
        }
示例#14
0
 private void Create(params string[] lines)
 {
     _textView = CreateTextView(lines);
     _textBuffer = _textView.TextBuffer;
     _factory = new MockRepository(MockBehavior.Loose);
     _operations = _factory.Create<ICommonOperations>(MockBehavior.Strict);
     _vimTextBuffer = _factory.Create<IVimTextBuffer>(MockBehavior.Strict);
     _vimTextBuffer.SetupProperty(x => x.LastEditPoint);
     _trackerRaw = new TextChangeTracker(_vimTextBuffer.Object, _textView, _operations.Object);
     _trackerRaw.TrackCurrentChange = true;
     _tracker = _trackerRaw;
     _tracker.ChangeCompleted += (sender, args) => { _lastChange = args.TextChange; };
 }
示例#15
0
        public void ConstructorInitializesProperties()
        {
            // Act
            var oldBuffer = new Mock<ITextBuffer>().Object;
            var newBuffer = new Mock<ITextBuffer>().Object;
            var change = new TextChange(42, 24, oldBuffer, 1337, newBuffer);

            // Assert
            Assert.Equal(42, change.OldPosition);
            Assert.Equal(24, change.OldLength);
            Assert.Equal(1337, change.NewLength);
            Assert.Same(newBuffer, change.NewBuffer);
            Assert.Same(oldBuffer, change.OldBuffer);
        }
示例#16
0
 public void CheckForStructureChangesRequiresNonNullBufferInChange()
 {
     var change = new TextChange();
     var parameterName = "change";
     var exception = Assert.Throws<ArgumentException>(
         parameterName,
         () =>
         {
             using (var parser = new RazorEditorParser(CreateHost(), "C:\\Foo.cshtml"))
             {
                 parser.CheckForStructureChanges(change);
             }
         });
     ExceptionHelpers.ValidateArgumentException(parameterName, RazorResources.FormatStructure_Member_CannotBeNull(nameof(change.NewBuffer), nameof(TextChange)), exception);
 }
示例#17
0
        public virtual EditResult ApplyChange(Span target, TextChange change, bool force)
        {
            var result = PartialParseResult.Accepted;
            var normalized = change.Normalize();
            if (!force)
            {
                result = CanAcceptChange(target, normalized);
            }

            // If the change is accepted then apply the change
            if ((result & PartialParseResult.Accepted) == PartialParseResult.Accepted)
            {
                return new EditResult(result, UpdateSpan(target, normalized));
            }
            return new EditResult(result, new SpanBuilder(target));
        }
示例#18
0
 protected virtual SpanBuilder UpdateSpan(Span target, TextChange normalizedChange)
 {
     var newContent = normalizedChange.ApplyChange(target);
     var newSpan = new SpanBuilder(target);
     newSpan.ClearSymbols();
     foreach (ISymbol sym in Tokenizer(newContent))
     {
         sym.OffsetStart(target.Start);
         newSpan.Accept(sym);
     }
     if (target.Next != null)
     {
         var newEnd = SourceLocationTracker.CalculateNewLocation(target.Start, newContent);
         target.Next.ChangeStart(newEnd);
     }
     return newSpan;
 }
示例#19
0
        private string AdjustForVirtualSpace(TextChange textChange)
        {
            var newText = textChange.NewText;

            var caretPoint = this.TextView.Caret.Position.BufferPosition;
            var virtualCaretPoint = this.TextView.Caret.Position.VirtualBufferPosition;

            if (textChange.Span.IsEmpty &&
                textChange.Span.Start == caretPoint &&
                virtualCaretPoint.IsInVirtualSpace)
            {
                // They're in virtual space and the text change is specified against the cursor
                // position that isn't in virtual space.  In this case, add the virtual spaces to the
                // thing we're adding.
                var editorOperations = _editorOperationsFactoryService.GetEditorOperations(this.TextView);
                var whitespace = editorOperations.GetWhitespaceForVirtualSpace(virtualCaretPoint);
                return whitespace + newText;
            }

            return newText;
        }
示例#20
0
        public TextChange(TextChange change, ITextProvider newTextProvider)
            : this()
        {
            this.Combine(change);

            ITextSnapshotProvider newSnapshotProvider = newTextProvider as ITextSnapshotProvider;
            ITextSnapshotProvider changeNewSnapshotProvider = change.NewTextProvider as ITextSnapshotProvider;

            if ((newSnapshotProvider != null) && (changeNewSnapshotProvider != null))
            {
                ITextSnapshot changeNewSnapshot = changeNewSnapshotProvider.Snapshot;
                ITextSnapshot newSnapshot = newSnapshotProvider.Snapshot;

                if (changeNewSnapshot.Version.ReiteratedVersionNumber != newSnapshot.Version.ReiteratedVersionNumber)
                {
                    SnapshotSpan changeNewSpan = change.NewRange.ToSnapshotSpan(changeNewSnapshot);
                    Span? oldChangedSpan;
                    Span? newChangedSpan;

                    if (changeNewSnapshot.Version.GetChangedExtent(newSnapshot.Version, out oldChangedSpan, out newChangedSpan))
                    {
                        int start = Math.Min(oldChangedSpan.Value.Start, change.NewRange.Start);
                        int end = Math.Max(oldChangedSpan.Value.End, change.NewRange.End);

                        changeNewSpan = new SnapshotSpan(changeNewSnapshot, Span.FromBounds(start, end));
                    }

                    SnapshotSpan newSpan = changeNewSpan.TranslateTo(newSnapshot, SpanTrackingMode.EdgeInclusive);

                    NewRange = new TextRange(newSpan.Start.Position, newSpan.Length);
                }
            }

            NewTextProvider = newTextProvider;
            Version = NewTextProvider.Version;
        }
示例#21
0
        internal async Task <(bool, SumType <CompletionItem[], CompletionList>?)> TryGetProvisionalCompletionsAsync(CompletionParams request, LSPDocumentSnapshot documentSnapshot, ProjectionResult projection, CancellationToken cancellationToken)
        {
            SumType <CompletionItem[], CompletionList>?result = null;

            if (projection.LanguageKind != RazorLanguageKind.Html ||
                request.Context.TriggerKind != CompletionTriggerKind.TriggerCharacter ||
                request.Context.TriggerCharacter != ".")
            {
                return(false, result);
            }

            if (projection.Position.Character == 0)
            {
                // We're at the start of line. Can't have provisional completions here.
                return(false, result);
            }

            var previousCharacterPosition   = new Position(projection.Position.Line, projection.Position.Character - 1);
            var previousCharacterProjection = await _projectionProvider.GetProjectionAsync(documentSnapshot, previousCharacterPosition, cancellationToken).ConfigureAwait(false);

            if (previousCharacterProjection == null || previousCharacterProjection.LanguageKind != RazorLanguageKind.CSharp)
            {
                return(false, result);
            }

            if (!(_documentManager is TrackingLSPDocumentManager trackingDocumentManager))
            {
                return(false, result);
            }

            // Edit the CSharp projected document to contain a '.'. This allows C# completion to provide valid
            // completion items for moments when a user has typed a '.' that's typically interpreted as Html.
            var addProvisionalDot = new TextChange(
                TextSpan.FromBounds(previousCharacterProjection.PositionIndex, previousCharacterProjection.PositionIndex),
                ".");

            await _joinableTaskFactory.SwitchToMainThreadAsync();

            trackingDocumentManager.UpdateVirtualDocument <CSharpVirtualDocument>(documentSnapshot.Uri, new[] { addProvisionalDot }, previousCharacterProjection.HostDocumentVersion);

            var provisionalCompletionParams = new CompletionParams()
            {
                Context      = request.Context,
                Position     = new Position(previousCharacterProjection.Position.Line, previousCharacterProjection.Position.Character + 1),
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = previousCharacterProjection.Uri
                }
            };

            result = await _requestInvoker.ReinvokeRequestOnServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>(
                Methods.TextDocumentCompletionName,
                LanguageServerKind.CSharp,
                provisionalCompletionParams,
                cancellationToken).ConfigureAwait(true);

            // We have now obtained the necessary completion items. We no longer need the provisional change. Revert.
            var removeProvisionalDot = new TextChange(
                TextSpan.FromBounds(previousCharacterProjection.PositionIndex, previousCharacterProjection.PositionIndex + 1),
                string.Empty);

            trackingDocumentManager.UpdateVirtualDocument <CSharpVirtualDocument>(documentSnapshot.Uri, new[] { removeProvisionalDot }, previousCharacterProjection.HostDocumentVersion);

            return(true, result);
        }
示例#22
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());
            });
        }
示例#23
0
        private static void CleanupSourceMappingStart(FormattingContext context, Range sourceMappingRange, List <TextChange> changes, bool isOnType, out bool newLineAdded)
        {
            newLineAdded = false;

            //
            // We look through every source mapping that intersects with the affected range and
            // bring the first line to its own line and adjust its indentation,
            //
            // E.g,
            //
            // @{   public int x = 0;
            // }
            //
            // becomes,
            //
            // @{
            //    public int x  = 0;
            // }
            //

            var text = context.SourceText;
            var sourceMappingSpan = sourceMappingRange.AsTextSpan(text);

            if (!ShouldFormat(context, sourceMappingSpan, allowImplicitStatements: false))
            {
                // We don't want to run cleanup on this range.
                return;
            }

            if (sourceMappingRange.Start.Character == 0)
            {
                // It already starts on a fresh new line which doesn't need cleanup.
                // E.g, (The mapping starts at | in the below case)
                // @{
                //     @: Some html
                // |   var x = 123;
                // }
                //

                return;
            }

            // @{
            //     if (true)
            //     {
            //         <div></div>|
            //
            //              |}
            // }
            // We want to return the length of the range marked by |...|
            //
            var whitespaceLength = text.GetFirstNonWhitespaceOffset(sourceMappingSpan, out var newLineCount);

            if (whitespaceLength == null)
            {
                // There was no content after the start of this mapping. Meaning it already is clean.
                // E.g,
                // @{|
                //    ...
                // }

                return;
            }

            var spanToReplace = new TextSpan(sourceMappingSpan.Start, whitespaceLength.Value);

            if (!context.TryGetIndentationLevel(spanToReplace.End, out var contentIndentLevel))
            {
                // Can't find the correct indentation for this content. Leave it alone.
                return;
            }

            if (newLineCount == 0)
            {
                newLineAdded = true;
                newLineCount = 1;
            }

            // At this point, `contentIndentLevel` should contain the correct indentation level for `}` in the above example.
            // Make sure to preserve the same number of blank lines as the original string had
            var replacement = PrependLines(context.GetIndentationLevelString(contentIndentLevel), context.NewLineString, newLineCount);

            // After the below change the above example should look like,
            // @{
            //     if (true)
            //     {
            //         <div></div>
            //     }
            // }
            var change = new TextChange(spanToReplace, replacement);

            changes.Add(change);
        }
示例#24
0
 public void QueueChange(TextChange change)
 {
     _main.QueueChange(change);
 }
示例#25
0
 public static TextChange.Insert AsInsert(this TextChange change)
 {
     return((TextChange.Insert)change);
 }
示例#26
0
 public static TextChange.DeleteRight AsDeleteRight(this TextChange change)
 {
     return((TextChange.DeleteRight)change);
 }
示例#27
0
 public static bool IsInsert(this TextChange change, string text)
 {
     return(change.IsInsert && change.AsInsert().Item == text);
 }
        public void InheritFromNetModuleMetadata01()
        {
            var modRef = TestReferences.MetadataTests.NetModule01.ModuleCS00;

            var text1 = @"
class Test : StaticModClass
{";
            var text2 = @"
    public static int Main()
    {
        r";

            var tree = SyntaxFactory.ParseSyntaxTree(String.Empty);
            var comp = CreateCompilationWithMscorlib(syntaxTree: tree, references: new[] { modRef });

            var currComp = comp;

            var oldTree = comp.SyntaxTrees.First();
            var oldIText = oldTree.GetText();
            var span = new TextSpan(oldIText.Length, 0);
            var change = new TextChange(span, text1);

            var newIText = oldIText.WithChanges(change);
            var newTree = oldTree.WithChangedText(newIText);
            currComp = currComp.ReplaceSyntaxTree(oldTree, newTree);

            var model = currComp.GetSemanticModel(newTree);
            var id = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(s => s.ToString() == "StaticModClass").First();
            // NRE is thrown later but this one has to be called first
            var symInfo = model.GetSymbolInfo(id);
            Assert.NotNull(symInfo.Symbol);

            oldTree = newTree;
            oldIText = oldTree.GetText();
            span = new TextSpan(oldIText.Length, 0);
            change = new TextChange(span, text2);

            newIText = oldIText.WithChanges(change);
            newTree = oldTree.WithChangedText(newIText);
            currComp = currComp.ReplaceSyntaxTree(oldTree, newTree);

            model = currComp.GetSemanticModel(newTree);
            id = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(s => s.ToString() == "StaticModClass").First();
            symInfo = model.GetSymbolInfo(id);
            Assert.NotNull(symInfo.Symbol);
        }
 private static int CompareTextChanges(TextChange x, TextChange y)
 {
     return x.Span.CompareTo(y.Span);
 }
示例#30
0
 protected virtual PartialParseResult CanAcceptChange(Span target, TextChange normalizedChange)
 {
     return(PartialParseResult.Rejected);
 }
示例#31
0
 /// <summary>
 /// Returns the old text referenced by the change.
 /// </summary>
 /// <remarks>
 /// If the content has already been updated by applying the change, this data will be _invalid_
 /// </remarks>
 protected internal static string GetOldText(Span target, TextChange change)
 {
     return(target.Content.Substring(change.OldPosition - target.Start.AbsoluteIndex, change.OldLength));
 }
示例#32
0
 internal virtual BackgroundParseTask CreateBackgroundTask(RazorEngineHost host, string fileName, TextChange change)
 {
     return(BackgroundParseTask.StartNew(new RazorTemplateEngine(Host), FileName, change));
 }
示例#33
0
        private bool TryGetSubTextChange(
            SourceText originalText, TextSpan visibleSpanInOriginalText,
            string rightText, TextSpan spanInOriginalText, TextSpan spanInRightText, out TextChange textChange)
        {
            textChange = default;

            var visibleFirstLineInOriginalText = originalText.Lines.GetLineFromPosition(visibleSpanInOriginalText.Start);
            var visibleLastLineInOriginalText  = originalText.Lines.GetLineFromPosition(visibleSpanInOriginalText.End);

            // skip easy case
            // 1. things are out of visible span
            if (!visibleSpanInOriginalText.IntersectsWith(spanInOriginalText))
            {
                return(false);
            }

            // 2. there are no intersects
            var snippetInRightText = rightText.Substring(spanInRightText.Start, spanInRightText.Length);

            if (visibleSpanInOriginalText.Contains(spanInOriginalText) && visibleSpanInOriginalText.End != spanInOriginalText.End)
            {
                textChange = new TextChange(spanInOriginalText, snippetInRightText);
                return(true);
            }

            // okay, more complex case. things are intersecting boundaries.
            var firstLineOfRightTextSnippet = snippetInRightText.GetFirstLineText();
            var lastLineOfRightTextSnippet  = snippetInRightText.GetLastLineText();

            // there are 4 complex cases - these are all heuristic. not sure what better way I have. and the heuristic is heavily based on
            // text differ's behavior.

            // 1. it is a single line
            if (visibleFirstLineInOriginalText.LineNumber == visibleLastLineInOriginalText.LineNumber)
            {
                // don't do anything
                return(false);
            }

            // 2. replacement contains visible spans
            if (spanInOriginalText.Contains(visibleSpanInOriginalText))
            {
                // header
                // don't do anything

                // body
                textChange = new TextChange(
                    TextSpan.FromBounds(visibleFirstLineInOriginalText.EndIncludingLineBreak, visibleLastLineInOriginalText.Start),
                    snippetInRightText.Substring(firstLineOfRightTextSnippet.Length, snippetInRightText.Length - firstLineOfRightTextSnippet.Length - lastLineOfRightTextSnippet.Length));

                // footer
                // don't do anything

                return(true);
            }

            // 3. replacement intersects with start
            if (spanInOriginalText.Start < visibleSpanInOriginalText.Start &&
                visibleSpanInOriginalText.Start <= spanInOriginalText.End &&
                spanInOriginalText.End < visibleSpanInOriginalText.End)
            {
                // header
                // don't do anything

                // body
                if (visibleFirstLineInOriginalText.EndIncludingLineBreak <= spanInOriginalText.End)
                {
                    textChange = new TextChange(
                        TextSpan.FromBounds(visibleFirstLineInOriginalText.EndIncludingLineBreak, spanInOriginalText.End),
                        snippetInRightText.Substring(firstLineOfRightTextSnippet.Length));
                    return(true);
                }

                return(false);
            }

            // 4. replacement intersects with end
            if (visibleSpanInOriginalText.Start < spanInOriginalText.Start &&
                spanInOriginalText.Start <= visibleSpanInOriginalText.End &&
                visibleSpanInOriginalText.End <= spanInOriginalText.End)
            {
                // body
                if (spanInOriginalText.Start <= visibleLastLineInOriginalText.Start)
                {
                    textChange = new TextChange(
                        TextSpan.FromBounds(spanInOriginalText.Start, visibleLastLineInOriginalText.Start),
                        snippetInRightText.Substring(0, snippetInRightText.Length - lastLineOfRightTextSnippet.Length));
                    return(true);
                }

                // footer
                // don't do anything

                return(false);
            }

            // if it got hit, then it means there is a missing case
            throw ExceptionUtilities.Unreachable;
        }
示例#34
0
        public override void OnDidChangeTextDocument(DidChangeTextDocumentParams parameters)
        {
            var fileCompiler = GetFileCompilerFromStringUri(parameters.uri, false); //Text Change do not have to trigger node phase, it's only a another event that will do it

            if (fileCompiler == null)
            {
                return;
            }

            Uri objUri = new Uri(parameters.uri);

            #region Convert text changes format from multiline range replacement to single line updates

            TextChangedEvent textChangedEvent = new TextChangedEvent();
            foreach (var contentChange in parameters.contentChanges)
            {
                // Split the text updated into distinct lines
                List <string> lineUpdates = null;
                bool          replacementTextStartsWithNewLine = false;

                if (!string.IsNullOrEmpty(contentChange.text))
                {
                    replacementTextStartsWithNewLine = contentChange.text[0] == '\r' ||
                                                       contentChange.text[0] == '\n';
                    //Allow to know if a new line was added
                    //Split on \r \n to know the number of lines added
                    lineUpdates = contentChange.text.Replace("\r", "").Split('\n').ToList();
                    if (string.IsNullOrEmpty(lineUpdates.FirstOrDefault()) && replacementTextStartsWithNewLine)
                    {
                        lineUpdates.RemoveAt(0);
                    }
                }

                // Document cleared
                if (contentChange.range == null)
                {
                    //JCM: I have noticed that if the entire text has changed, is better to reload the entire file
                    //To avoid crashes.
                    try
                    {
                        typeCobolWorkspace.OpenSourceFile(objUri, contentChange.text, this.Workspace.LsrTestOptions);
                        return;
                    }
                    catch (Exception e)
                    {
                        //Don't rethow an exception on save.
                        RemoteConsole.Error(string.Format("Error while handling notification {0} : {1}",
                                                          "textDocument/didChange", e.Message));
                        return;
                    }
                }
                // Document updated
                else
                {
                    // Get original lines text before change
                    string originalFirstLineText =
                        fileCompiler.CompilationResultsForProgram.CobolTextLines[contentChange.range.start.line]
                        .Text;
                    string originalLastLineText = originalFirstLineText;


                    // Check if the first line was inserted
                    int firstLineIndex = contentChange.range.start.line;
                    int firstLineChar  = contentChange.range.start.character;
                    if (replacementTextStartsWithNewLine &&
                        !(contentChange.range.start.character < originalLastLineText.Length))
                    {
                        firstLineIndex++;
                        firstLineChar = 0;
                    }
                    else if (replacementTextStartsWithNewLine)
                    //Detected that the add line appeared inside an existing line
                    {
                        lineUpdates.Add(lineUpdates.First());
                        //Add the default 7 spaces + add lineUpdates in order to update the current line and add the new one.
                    }

                    // Check if the last line was deleted
                    int lastLineIndex = contentChange.range.end.line;
                    if (contentChange.range.end.line > contentChange.range.start.line &&
                        contentChange.range.end.character == 0)
                    {
                        //Allows to detect if the next line was suppressed
                    }
                    if (contentChange.text?.Length == 0)
                    {
                        lineUpdates = new List <string>();
                    }

                    if (lastLineIndex > firstLineIndex)
                    {
                        originalLastLineText =
                            fileCompiler.CompilationResultsForProgram.CobolTextLines[
                                Math.Min(lastLineIndex,
                                         fileCompiler.CompilationResultsForProgram.CobolTextLines.Count - 1)].Text;
                    }

                    // Text not modified at the beginning of the first replaced line
                    string startOfFirstLine = null;
                    if (firstLineChar > 0)
                    {
                        if (originalFirstLineText.Length >= contentChange.range.start.character)
                        {
                            startOfFirstLine = originalFirstLineText.Substring(0,
                                                                               contentChange.range.start.character);
                        }
                        else
                        {
                            startOfFirstLine = originalFirstLineText.Substring(0, originalFirstLineText.Length) +
                                               new string(' ',
                                                          contentChange.range.start.character - originalFirstLineText.Length);
                        }
                    }

                    // Text not modified at the end of the last replaced line
                    string endOfLastLine = null;
                    if (contentChange.range.end.character < originalLastLineText.Length)
                    {
                        endOfLastLine = originalLastLineText.Substring(contentChange.range.end.character);
                    }

                    // Remove all the old lines
                    for (int i = firstLineIndex; i <= lastLineIndex; i++)
                    {
                        var textChange = new TextChange(TextChangeType.LineRemoved, firstLineIndex, null);
                        textChangedEvent.TextChanges.Add(textChange);
                        //Mark the index line to be removed. The index will remains the same for each line delete, because text change are apply one after another
                    }

                    // Insert the updated lines
                    if (!(startOfFirstLine == null && lineUpdates == null && endOfLastLine == null))
                    {
                        int lineUpdatesCount = (lineUpdates != null && lineUpdates.Count > 0)
                            ? lineUpdates.Count
                            : 1;
                        for (int i = 0; i < lineUpdatesCount; i++)
                        {
                            string newLine = (lineUpdates != null && lineUpdates.Count > 0)
                                ? lineUpdates[i]
                                : string.Empty;
                            if (i == 0)
                            {
                                newLine = startOfFirstLine + newLine;
                            }
                            if (i == lineUpdatesCount - 1)
                            {
                                newLine = newLine + endOfLastLine;
                            }
                            var textChange = new TextChange(TextChangeType.LineInserted, firstLineIndex + i,
                                                            new TextLineSnapshot(firstLineIndex + i, newLine, null));
                            textChangedEvent.TextChanges.Add(textChange);
                        }
                    }
                }
            }

            #endregion

            // Update the source file with the computed text changes
            typeCobolWorkspace.UpdateSourceFile(objUri, textChangedEvent);

            // DEBUG information
            RemoteConsole.Log("Udpated source file : " + objUri.LocalPath);
            foreach (var textChange in textChangedEvent.TextChanges)
            {
                RemoteConsole.Log(" - " + textChange.ToString());
            }
        }
示例#35
0
 public static bool IsDeleteRight(this TextChange change, int count)
 {
     return(change.IsDeleteRight && change.AsDeleteRight().Item == count);
 }
示例#36
0
 protected void Create(params string[] lines)
 {
     _textBuffer = EditorUtil.CreateBuffer(lines);
     _factory = new MockRepository(MockBehavior.Loose);
     _textCaret = _factory.Create<ITextCaret>();
     _textView = _factory.Create<ITextView>();
     _textView.SetupGet(x => x.Caret).Returns(_textCaret.Object);
     _textView.SetupGet(x => x.HasAggregateFocus).Returns(true);
     _mouse = _factory.Create<IMouseDevice>();
     _keyboard = _factory.Create<IKeyboardDevice>();
     _vimBuffer = new MockVimBuffer()
     {
         TextViewImpl = _textView.Object,
         TextBufferImpl = _textBuffer
     };
     _trackerRaw = new TextChangeTracker(_vimBuffer, _keyboard.Object, _mouse.Object);
     _tracker = _trackerRaw;
     _tracker.ChangeCompleted += (sender, data) => { _lastChange = data; };
 }
示例#37
0
 public static TextChange.Combination AsCombination(this TextChange change)
 {
     return((TextChange.Combination)change);
 }
        public void IncrementalParseTopDownCommentOutLines()
        {
            var text = @"// <Title> Query Expression syntax </Title>
// <Description>
// from, join, on, equals, into, let, orderby, ascending, descending, group, by
// @-with contextual keywords parseable as a type or identifier in a query expression
// Various combinations
// </Description>
// <RelatedBugs></RelatedBugs>

//<Expects status=success></Expects>

// <Code> 

using System;
using System.Linq;

public class from { }
public class join { }
public class on { }
public class equals { }
public class into { }
public class let { }
public class orderby : let { }
public class ascending : orderby, descending { }
public interface descending { }
public class group { }
public class by { }

public class QueryExpressionTest
{
    public static int Main()
    {
        var array02a = new[] { new join(), new join(), new join() } as object[];
        var array02b = new[] { new join(), new join(), new join() } as object[];
        var query02 = from i in array02a join j in array02b on (@from)i equals (@from)j select new { i, j };

        var array03a = new[] { new on(), new on(), new on() } as object[];
        var array03b = new[] { new on(), new on(), new on() } as object[];
        var query03 = from @on i in array03a join j in array03b on i equals (@on)j select new { i, j };

        var array04a = new[] { new equals(), new equals(), new equals() } as object[];

        return 0;
    }
}
";

            var currTree = SyntaxFactory.ParseSyntaxTree(text);
            var currIText = currTree.GetText();

            var items = text.Split('\n');
            int currLen = 0;
            foreach (var item in items)
            {
                var span = new TextSpan(currLen, 0);
                var change = new TextChange(span, "// ");
                currLen += item.Length + 3;

                currIText = currIText.WithChanges(change);
                currTree = currTree.WithChangedText(currIText);

                var fullTree = SyntaxFactory.ParseSyntaxTree(currIText.ToString());

                int incCount = currTree.GetCompilationUnitRoot().ChildNodesAndTokens().Count;
                int fullCount = fullTree.GetCompilationUnitRoot().ChildNodesAndTokens().Count;

                WalkTreeAndVerify(currTree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot());
            }
        }
示例#39
0
 public static TextChange.DeleteLeft AsDeleteLeft(this TextChange change)
 {
     return((TextChange.DeleteLeft)change);
 }
        public void DontReuseLambdaParameterAsMethodParameter()
        {
            var items = new string[]
            {
                "a b.c*/ d => {e(f =>",
                "/*",
            };

            var oldText = SourceText.From(items[0]);
            var oldTree = SyntaxFactory.ParseSyntaxTree(oldText); // f is a simple lambda parameter

            var change = new TextChange(new TextSpan(0, 0), items[1]); // Prepend
            var newText = oldText.WithChanges(change); // f is a method decl parameter

            var incrTree = oldTree.WithChangedText(newText);
            var fullTree = SyntaxFactory.ParseSyntaxTree(newText);

            Assert.Equal(
                fullTree.GetDiagnostics().Select(d => d.ToString()),
                incrTree.GetDiagnostics().Select(d => d.ToString()));

            WalkTreeAndVerify(incrTree.GetRoot(), fullTree.GetRoot());
        }
示例#41
0
 private static int CompareTextChanges(TextChange x, TextChange y)
 {
     return(x.Span.CompareTo(y.Span));
 }
示例#42
0
 private CompletionChange(TextChange textChange, int?newPosition, bool includesCommitCharacter)
 {
     TextChange              = textChange;
     NewPosition             = newPosition;
     IncludesCommitCharacter = includesCommitCharacter;
 }
示例#43
0
        private static void CleanupSourceMappingEnd(FormattingContext context, Range sourceMappingRange, List <TextChange> changes, bool newLineWasAddedAtStart)
        {
            //
            // We look through every source mapping that intersects with the affected range and
            // bring the content after the last line to its own line and adjust its indentation,
            //
            // E.g,
            //
            // @{
            //     if (true)
            //     {  <div></div>
            //     }
            // }
            //
            // becomes,
            //
            // @{
            //    if (true)
            //    {
            //        </div></div>
            //    }
            // }
            //

            var text = context.SourceText;
            var sourceMappingSpan   = sourceMappingRange.AsTextSpan(text);
            var mappingEndLineIndex = sourceMappingRange.End.Line;

            var startsInCSharpContext = context.Indentations[mappingEndLineIndex].StartsInCSharpContext;

            // If the span is on a single line, and we added a line, then end point is now on a line that does start in a C# context.
            if (!startsInCSharpContext && newLineWasAddedAtStart && sourceMappingRange.Start.Line == mappingEndLineIndex)
            {
                startsInCSharpContext = true;
            }

            if (!startsInCSharpContext)
            {
                // For corner cases like (Position marked with |),
                // It is already in a separate line. It doesn't need cleaning up.
                // @{
                //     if (true}
                //     {
                //         |<div></div>
                //     }
                // }
                //
                return;
            }

            var endSpan = TextSpan.FromBounds(sourceMappingSpan.End, sourceMappingSpan.End);

            if (!ShouldFormat(context, endSpan, allowImplicitStatements: false))
            {
                // We don't want to run cleanup on this range.
                return;
            }

            var contentStartOffset = text.Lines[mappingEndLineIndex].GetFirstNonWhitespaceOffset(sourceMappingRange.End.Character);

            if (contentStartOffset == null)
            {
                // There is no content after the end of this source mapping. No need to clean up.
                return;
            }

            var spanToReplace = new TextSpan(sourceMappingSpan.End, 0);

            if (!context.TryGetIndentationLevel(spanToReplace.End, out var contentIndentLevel))
            {
                // Can't find the correct indentation for this content. Leave it alone.
                return;
            }

            // At this point, `contentIndentLevel` should contain the correct indentation level for `}` in the above example.
            var replacement = context.NewLineString + context.GetIndentationLevelString(contentIndentLevel);

            // After the below change the above example should look like,
            // @{
            //     if (true)
            //     {
            //         <div></div>
            //     }
            // }
            var change = new TextChange(spanToReplace, replacement);

            changes.Add(change);
        }
示例#44
0
 /// <summary>
 /// Returns true if the specified change is an insertion of text at the end of this span.
 /// </summary>
 protected internal static bool IsEndDeletion(Span target, TextChange change)
 {
     return(change.IsDelete && IsAtEndOfSpan(target, change));
 }
示例#45
0
        public override async Task <CompletionChange> GetChangeAsync(Document doc, CompletionItem item, char?commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
        {
            (string beforeText, string afterText, string newMethod) = await GetInsertText(item.Properties);

            TextChange change;

            if (newMethod != null && RoslynCompletionData.RequestInsertText)               // check for completion window manager to prevent the insertion cursor popup when the changes are queried by code diagnostics.
            {
                change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), item.Properties [MethodNameKey] + ";");
                var semanticModel = await doc.GetSemanticModelAsync(cancellationToken);

                if (!doc.IsOpen() || await doc.IsForkedDocumentWithSyntaxChangesAsync(cancellationToken))
                {
                    return(CompletionChange.Create(change));
                }

                var document = IdeApp.Workbench.ActiveDocument;
                var editor   = document.Editor;

                void StartInsertionMode()
                {
                    if (editor.EditMode != EditMode.Edit)
                    {
                        return;
                    }
                    var parsedDocument  = document.DocumentContext.ParsedDocument;
                    var declaringType   = semanticModel.GetEnclosingSymbolMD <INamedTypeSymbol> (item.Span.Start, default(CancellationToken));
                    var insertionPoints = InsertionPointService.GetInsertionPoints(
                        document.Editor,
                        semanticModel,
                        declaringType,
                        editor.CaretOffset
                        );
                    var options = new InsertionModeOptions(
                        GettextCatalog.GetString("Create new method"),
                        insertionPoints,
                        point => {
                        if (!point.Success)
                        {
                            return;
                        }
                        point.InsertionPoint.Insert(document.Editor, document.DocumentContext, newMethod);
                    }
                        );

                    editor.StartInsertionMode(options);
                }

                if (editor.TextView is Microsoft.VisualStudio.Text.Editor.IMdTextView)
                {
                    await Runtime.RunInMainThread(StartInsertionMode);
                }
                else
                {
                    StartInsertionMode();
                }

                return(CompletionChange.Create(change));
            }
            change = new TextChange(new TextSpan(item.Span.Start, item.Span.Length), beforeText + afterText);

            return(CompletionChange.Create(change, item.Span.Start + (beforeText != null ? beforeText.Length : 0)));
        }
示例#46
0
 /// <summary>
 /// Returns true if the specified change is a replacement of text at the end of this span.
 /// </summary>
 protected internal static bool IsEndReplace(Span target, TextChange change)
 {
     return(change.IsReplace && IsAtEndOfSpan(target, change));
 }
示例#47
0
 protected internal static bool IsAtEndOfSpan(Span target, TextChange change)
 {
     return((change.OldPosition + change.OldLength) == (target.Start.AbsoluteIndex + target.Length));
 }
示例#48
0
            static string GetTextChangeTextWithCaretAtLocation(SourceText sourceText, TextChange textChange, LinePosition desiredCaretLinePosition)
            {
                var desiredCaretLocation = sourceText.Lines.GetPosition(desiredCaretLinePosition);

                Debug.Assert(desiredCaretLocation >= textChange.Span.Start);
                var offsetInTextChange = desiredCaretLocation - textChange.Span.Start;
                var newText            = textChange.NewText !.Insert(offsetInTextChange, "$0");

                return(newText);
            }
示例#49
0
        internal static async Task VerifyExpectedTextAsync(
            string intentName,
            string activeDocument,
            string[] additionalDocuments,
            string[] expectedTexts,
            OptionsCollection?options = null,
            string?intentData         = null,
            string?priorText          = null)
        {
            var documentSet = additionalDocuments.Prepend(activeDocument).ToArray();

            using var workspace = TestWorkspace.CreateCSharp(documentSet, composition: EditorTestCompositions.EditorFeatures);
            options?.SetGlobalOptions(workspace.GlobalOptions);

            var intentSource = workspace.ExportProvider.GetExportedValue <IIntentSourceProvider>();

            // The first document will be the active document.
            var document   = workspace.Documents.Single(d => d.Name == "test1.cs");
            var textBuffer = document.GetTextBuffer();

            // Get the text change to rewind the document to the correct pre-intent location.
            var rewindTextChange = new TextChange(document.AnnotatedSpans["typed"].Single(), priorText ?? string.Empty);

            // Get the current snapshot span to pass in.
            var currentSnapshot = new SnapshotSpan(textBuffer.CurrentSnapshot, new Span(0, textBuffer.CurrentSnapshot.Length));

            var priorSelection = TextSpan.FromBounds(rewindTextChange.Span.Start, rewindTextChange.Span.Start);

            if (document.AnnotatedSpans.ContainsKey("priorSelection"))
            {
                priorSelection = document.AnnotatedSpans["priorSelection"].Single();
            }

            var intentContext = new IntentRequestContext(
                intentName,
                currentSnapshot,
                ImmutableArray.Create(rewindTextChange),
                priorSelection,
                intentData: intentData);
            var results = await intentSource.ComputeIntentsAsync(intentContext, CancellationToken.None).ConfigureAwait(false);

            // For now, we're just taking the first result to match intellicode behavior.
            var result = results.First();

            var actualDocumentTexts = new List <string>();

            foreach (var documentChange in result.DocumentChanges)
            {
                // Get the document and open it.  Since we're modifying the text buffer we don't care about linked documents.
                var documentBuffer = workspace.GetTestDocument(documentChange.Key).GetTextBuffer();

                using var edit = documentBuffer.CreateEdit();
                foreach (var change in documentChange.Value)
                {
                    edit.Replace(change.Span.ToSpan(), change.NewText);
                }

                edit.Apply();

                actualDocumentTexts.Add(documentBuffer.CurrentSnapshot.GetText());
            }

            Assert.Equal(expectedTexts.Length, actualDocumentTexts.Count);
            foreach (var expectedText in expectedTexts)
            {
                Assert.True(actualDocumentTexts.Contains(expectedText));
            }
        }
示例#50
0
 public CompletionChange WithTextChange(TextChange textChange)
 {
     return(new CompletionChange(textChange, this.NewPosition, this.IncludesCommitCharacter));
 }
        private static List<TextChange> MergeOverlappingRegions(List<TextChange> changes)
        {
            // Note: we assume the changes are ordered by CompareTextChanges
            var newChanges = new List<TextChange>();

            for (int i = 0; i < changes.Count; i++)
            {
                TextChange change = changes[i];
                for (int j = i + 1; j < changes.Count; j++)
                {
                    TextChange nextChange = changes[j];

                    if (nextChange.Span.Start <= change.Span.End &&
                        nextChange.Span.End >= change.Span.End)
                    {
                        // This change overlaps but is not contained within the previous change.
                        // In the case that this change ends where the previous change ends, we need to take
                        // the replacement text of this change, because it is possible for end directives to
                        // need non-empty replacement.
                        change = new TextChange(new TextSpan(change.Span.Start, nextChange.Span.End - change.Span.Start), nextChange.NewText);
                        i = j;
                    }
                }

                newChanges.Add(change);
            }

            return newChanges;
        }
示例#52
0
        private void RewriteStyleAttributes(ResponseAnalysisContext context, string html)
        {
            var headIndex = html.IndexOf("</head>", StringComparison.OrdinalIgnoreCase);

            if (headIndex == -1)
            {
                return;
            }

            SortedList <string, StringSegment> inlineStyles = null;

            foreach (var index in FastHtmlParser.FindAllAttributeIndexes(html, "style"))
            {
                // get content
                var inner = FastHtmlParser.GetAttributeValueAtName(html, "style", index);
                if (inner.Length == 0)
                {
                    continue;
                }

                if (inlineStyles == null)
                {
                    inlineStyles = new SortedList <string, StringSegment>();
                }

                // compute hash
                var hash = ComputeHash(inner.Trim());

                if (!inlineStyles.ContainsKey(hash))
                {
                    inlineStyles.Add(hash, inner);
                }

                // add change
                context.AddChange(TextChange.Remove(html, index, inner.Offset + inner.Length + 1 - index));

                var tagIndex       = FastHtmlParser.FindOpenTagAtAttribute(html, index);
                var classAttribute = FastHtmlParser.GetAttributeValueAtTag(html, "class", tagIndex);
                if (classAttribute.Length > 0)
                {
                    context.AddChange(TextChange.Insert(html, classAttribute.Offset + classAttribute.Length, "_" + hash));
                }
                else
                {
                    context.AddChange(FastHtmlParser.CreateInsertAttributeChange(html, tagIndex, "class", "_" + hash));
                }
            }

            // assemble inline styles
            if (inlineStyles != null && inlineStyles.Count > 0)
            {
                var hashBuilder = new InplaceStringBuilder(inlineStyles.Count * HashBytes * 2);
                foreach (var entry in inlineStyles)
                {
                    hashBuilder.Append(entry.Key);
                }

                var hash = ComputeHash(hashBuilder.ToString());
                if (!InlineContentService.ContainsStyleByHash(hash))
                {
                    var contentBuilder = StringBuilderPool.Get();
                    foreach (var entry in inlineStyles)
                    {
                        contentBuilder.Append('.');
                        contentBuilder.Append('_');
                        contentBuilder.Append(entry.Key);
                        contentBuilder.Append('{');
                        contentBuilder.Append(entry.Value.Value);
                        contentBuilder.Append('}');
                    }
                    InlineContentService.TryAddStyleByHash(hash, contentBuilder.ToString());
                    StringBuilderPool.Return(contentBuilder);
                }

                var tag = $"<link rel=\"stylesheet\" href=\"/.waf/styles/{hash}\" type=\"text/css\" />";
                context.AddChange(TextChange.Insert(html, headIndex, tag));
            }
        }
示例#53
0
 public void TearDown()
 {
     _tracker = null;
     _textBuffer = null;
     _lastChange = null;
 }
示例#54
0
        internal override async Task <CompletionChange> GetChangeAsync(Document document, CompletionItem completionItem, TextSpan completionListSpan, char?commitKey, CancellationToken cancellationToken)
        {
            LogCommit();
            var containingNamespace = ImportCompletionItem.GetContainingNamespace(completionItem);

            if (await ShouldCompleteWithFullyQualifyTypeName().ConfigureAwait(false))
            {
                var fullyQualifiedName = $"{containingNamespace}.{completionItem.DisplayText}";
                var change             = new TextChange(completionListSpan, fullyQualifiedName);

                return(CompletionChange.Create(change));
            }

            // Find context node so we can use it to decide where to insert using/imports.
            var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var addImportContextNode = root.FindToken(completionListSpan.Start, findInsideTrivia: true).Parent;

            // Add required using/imports directive.
            var addImportService = document.GetRequiredLanguageService <IAddImportsService>();
            var optionSet        = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var placeSystemNamespaceFirst = optionSet.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language);
            var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);

            var importNode = CreateImport(document, containingNamespace);

            var rootWithImport     = addImportService.AddImport(compilation, root, addImportContextNode, importNode, placeSystemNamespaceFirst, cancellationToken);
            var documentWithImport = document.WithSyntaxRoot(rootWithImport);
            // This only formats the annotated import we just added, not the entire document.
            var formattedDocumentWithImport = await Formatter.FormatAsync(documentWithImport, Formatter.Annotation, cancellationToken : cancellationToken).ConfigureAwait(false);

            var builder = ArrayBuilder <TextChange> .GetInstance();

            // Get text change for add import
            var importChanges = await formattedDocumentWithImport.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);

            builder.AddRange(importChanges);

            // Create text change for complete type name.
            //
            // Note: Don't try to obtain TextChange for completed type name by replacing the text directly,
            //       then use Document.GetTextChangesAsync on document created from the changed text. This is
            //       because it will do a diff and return TextChanges with minimum span instead of actual
            //       replacement span.
            //
            //       For example: If I'm typing "asd", the completion provider could be triggered after "a"
            //       is typed. Then if I selected type "AsnEncodedData" to commit, by using the approach described
            //       above, we will get a TextChange of "AsnEncodedDat" with 0 length span, instead of a change of
            //       the full display text with a span of length 1. This will later mess up span-tracking and end up
            //       with "AsnEncodedDatasd" in the code.
            builder.Add(new TextChange(completionListSpan, completionItem.DisplayText));

            // Then get the combined change
            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var newText = text.WithChanges(builder);

            return(CompletionChange.Create(Utilities.Collapse(newText, builder.ToImmutableAndFree())));

            async Task <bool> ShouldCompleteWithFullyQualifyTypeName()
            {
                if (!IsAddingImportsSupported(document))
                {
                    return(true);
                }

                // We might need to qualify unimported types to use them in an import directive, because they only affect members of the containing
                // import container (e.g. namespace/class/etc. declarations).
                //
                // For example, `List` and `StringBuilder` both need to be fully qualified below:
                //
                //      using CollectionOfStringBuilders = System.Collections.Generic.List<System.Text.StringBuilder>;
                //
                // However, if we are typing in an C# using directive that is inside a nested import container (i.e. inside a namespace declaration block),
                // then we can add an using in the outer import container instead (this is not allowed in VB).
                //
                // For example:
                //
                //      using System.Collections.Generic;
                //      using System.Text;
                //
                //      namespace Foo
                //      {
                //          using CollectionOfStringBuilders = List<StringBuilder>;
                //      }
                //
                // Here we will always choose to qualify the unimported type, just to be consistent and keeps things simple.
                return(await IsInImportsDirectiveAsync(document, completionListSpan.Start, cancellationToken).ConfigureAwait(false));
            }
        }
        public void IncrementalParseStopAtEscapeBackSlash()
        {
            var text1 = @"using System;

class Program
{
    static void Main()
    {
";

            var text2 = @"        Console.WriteLine(""\'\0\a\b\";

            var comp = CSharpTestBase.CreateCompilationWithMscorlib(SyntaxFactory.ParseSyntaxTree(String.Empty));

            var oldTree = comp.SyntaxTrees.First();
            var oldIText = oldTree.GetText();
            var span = new TextSpan(oldIText.Length, 0);
            var change = new TextChange(span, text1);

            var newIText = oldIText.WithChanges(change);
            var newTree = oldTree.WithChangedText(newIText);

            var fullTree = SyntaxFactory.ParseSyntaxTree(newIText.ToString(), options: newTree.Options);
            var fullText = fullTree.GetCompilationUnitRoot().ToFullString();
            var incText = newTree.GetCompilationUnitRoot().ToFullString();
            Assert.Equal(fullText.Length, incText.Length);
            Assert.Equal(fullText, incText);
            // 
            oldTree = newTree;
            oldIText = oldTree.GetText();
            span = new TextSpan(oldIText.Length, 0);
            change = new TextChange(span, text2);

            newIText = oldIText.WithChanges(change);
            newTree = oldTree.WithChangedText(newIText);

            fullTree = SyntaxFactory.ParseSyntaxTree(newIText.ToString(), options: newTree.Options);
            fullText = fullTree.GetCompilationUnitRoot().ToFullString();
            incText = newTree.GetCompilationUnitRoot().ToFullString();
            Assert.Equal(fullText.Length, incText.Length);
            Assert.Equal(fullText, incText);
        }
示例#56
0
        /// <summary>
        /// Starts the fast operations to be executed at every user interaction with the <see cref="RichTextBox"/>.
        /// </summary>
        /// <param name="richTextBox">
        /// The <see cref="RichTextBox"/> which text was changed.
        /// </param>
        /// <param name="eventArgs">
        /// The <see cref="TextChangedEventArgs"/> containing specific information about the user interaction.
        /// </param>
        /// <param name="scheduler">
        /// The <see cref="TaskScheduler"/> containing GUI-context.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// One or all of the parameters was/ were passed as null.
        /// </exception>
        public static async Task CodeAlteredAsync(RichTextBox richTextBox, TextChangedEventArgs eventArgs, TaskScheduler scheduler)
        {
            if (richTextBox == null)
            {
                throw new ArgumentNullException("richTextBox");
            }

            if (eventArgs == null)
            {
                throw new ArgumentNullException("eventArgs");
            }

            if (scheduler == null)
            {
                throw new ArgumentNullException("scheduler");
            }

            if (NoTextChangedPlox)
            {
                return;
            }

            var text =
                new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd).Text.Replace(
                    " ",
                    string.Empty);

            if (richTextBox.Document == null || text == "\r\n")
            {
                RecognitionEngine.AllWordsInCode.Clear();
                MistakeEngine.Mistakes.Clear();
                MainWindow.ErrorListView.Items.Clear();
                return;
            }

            TextChange textChange  = null;
            var        textChanges = eventArgs.Changes;

            if (textChanges != null && textChanges.Count > 0)
            {
                textChange = textChanges.First();
            }

            if (textChange == null || (textChange.AddedLength <= 0 && textChange.RemovedLength <= 0))
            {
                return;
            }

            IEnumerable <Word> changedWords = RecognitionEngine.RecognizeWordsInCode(richTextBox.CaretPosition, CurrentProgrammingLanguage).Result;

            var newWord = changedWords.First();

            if (newWord.Content == string.Empty)
            {
                await FacilitateCoding.PseudoSenseAsync(newWord, RecognitionEngine.AllWordsInCode, CurrentProgrammingLanguage, MainWindow.CodeListBox);

                return;
            }

            switch (pseudoSenseTask.Status)
            {
            case TaskStatus.Created:
                pseudoSenseTask.Start(scheduler);
                break;

            case TaskStatus.RanToCompletion:
            case TaskStatus.Faulted:
                pseudoSenseTask.Dispose();
                pseudoSenseTask = new Task(
                    () => FacilitateCoding.PseudoSenseAsync(newWord, RecognitionEngine.AllWordsInCode, CurrentProgrammingLanguage, MainWindow.CodeListBox),
                    cancellationToken.Token,
                    TaskCreationOptions.LongRunning);
                pseudoSenseTask.Start(scheduler);
                break;
            }
        }
        public void IncrementalParseStatementAfterQuery()
        {
            var text = @"
using System.Linq;
 
class equals
{
    static void Main(string[] args)
    {
        equals[] a;
        var q = from x in args select x;
        a = new[] { new equals() };
    }
}
";

            var currTree = SyntaxFactory.ParseSyntaxTree(text);
            var currIText = currTree.GetText();

            // Insert "// " before the "x" in "select x"; the next statement becomes part of the query.
            var span = new TextSpan(text.LastIndexOf('x'), 0);
            var change = new TextChange(span, "// ");

            currIText = currIText.WithChanges(change);
            currTree = currTree.WithChangedText(currIText);

            var fullTree = SyntaxFactory.ParseSyntaxTree(currIText.ToString());

            WalkTreeAndVerify(currTree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot());
        }
示例#58
0
 public virtual EditResult ApplyChange(Span target, TextChange change)
 {
     return(ApplyChange(target, change, force: false));
 }
 [Fact]//(Skip = "Bug")]
 public void RemovePartialFromClassWithIncorrectSpan()
 {
     var test = @"partial class C{}";
     var resultString = "class C{}";
     var startTree = SyntaxTree.Parse(test);
     var finalString = startTree.GetCompilationUnitRoot().ToString();
     var incrementalChange = new TextChange(startTree.Text, SourceText.From(resultString), new TextChangeRange[] { new TextChangeRange(new TextSpan(0, 7), 0) }); // NOTE: The string length here is a bit too short for the change
     var newTree = startTree.WithChange(incrementalChange);
     var output = newTree.GetCompilationUnitRoot().ToString();
     Assert.Equal(output, resultString);
 }
示例#60
0
        protected internal static bool IsAtEndOfFirstLine(Span target, TextChange change)
        {
            int endOfFirstLine = target.Content.IndexOfAny(new char[] { (char)0x000d, (char)0x000a, (char)0x2028, (char)0x2029 });

            return(endOfFirstLine == -1 || (change.OldPosition - target.Start.AbsoluteIndex) <= endOfFirstLine);
        }