Exemple #1
0
        private static bool TryUncommentExactlyBlockComment(
            CommentSelectionInfo info,
            SnapshotSpan span,
            ArrayBuilder <TextChange> textChanges,
            ArrayBuilder <CommentTrackingSpan> spansToSelect
            )
        {
            var spanText        = span.GetText();
            var trimmedSpanText = spanText.Trim();

            // See if the selection includes just a block comment (plus whitespace)
            if (
                trimmedSpanText.StartsWith(info.BlockCommentStartString, StringComparison.Ordinal) &&
                trimmedSpanText.EndsWith(info.BlockCommentEndString, StringComparison.Ordinal)
                )
            {
                var positionOfStart =
                    span.Start
                    + spanText.IndexOf(info.BlockCommentStartString, StringComparison.Ordinal);
                var positionOfEnd =
                    span.Start
                    + spanText.LastIndexOf(info.BlockCommentEndString, StringComparison.Ordinal);
                UncommentPosition(info, textChanges, spansToSelect, positionOfStart, positionOfEnd);
                return(true);
            }

            return(false);
        }
Exemple #2
0
        private static void UncommentPosition(
            CommentSelectionInfo info,
            ArrayBuilder <TextChange> textChanges,
            ArrayBuilder <CommentTrackingSpan> spansToSelect,
            int positionOfStart,
            int positionOfEnd
            )
        {
            if (positionOfStart < 0 || positionOfEnd < 0)
            {
                return;
            }

            spansToSelect.Add(
                new CommentTrackingSpan(
                    TextSpan.FromBounds(
                        positionOfStart,
                        positionOfEnd + info.BlockCommentEndString.Length
                        )
                    )
                );
            DeleteText(
                textChanges,
                new TextSpan(positionOfStart, info.BlockCommentStartString.Length)
                );
            DeleteText(textChanges, new TextSpan(positionOfEnd, info.BlockCommentEndString.Length));
        }
Exemple #3
0
        private static void AddSingleLineComments(
            SnapshotSpan span,
            ArrayBuilder <TextChange> textChanges,
            ArrayBuilder <CommentTrackingSpan> trackingSpans,
            ITextSnapshotLine firstLine,
            ITextSnapshotLine lastLine,
            CommentSelectionInfo commentInfo
            )
        {
            // Select the entirety of the lines, so that another comment operation will add more
            // comments, not insert block comments.
            trackingSpans.Add(
                new CommentTrackingSpan(
                    TextSpan.FromBounds(firstLine.Start.Position, lastLine.End.Position)
                    )
                );
            var indentToCommentAt = DetermineSmallestIndent(span, firstLine, lastLine);

            ApplySingleLineCommentToNonBlankLines(
                commentInfo,
                textChanges,
                firstLine,
                lastLine,
                indentToCommentAt
                );
        }
Exemple #4
0
        private CommentSelectionResult ToggleLineComment(CommentSelectionInfo commentInfo,
                                                         NormalizedSnapshotSpanCollection selectedSpans)
        {
            var textChanges = ArrayBuilder <TextChange> .GetInstance();

            var trackingSpans = ArrayBuilder <CommentTrackingSpan> .GetInstance();

            var linesInSelections = selectedSpans.ToDictionary(
                span => span,
                span => GetLinesFromSelectedSpan(span).ToImmutableArray());

            Operation operation;

            // If any of the lines are uncommented, add comments.
            if (linesInSelections.Values.Any(lines => SelectionHasUncommentedLines(lines, commentInfo)))
            {
                foreach (var selection in linesInSelections)
                {
                    CommentLines(selection.Key, selection.Value, textChanges, trackingSpans, commentInfo);
                }

                operation = Operation.Comment;
            }
            else
            {
                foreach (var selection in linesInSelections)
                {
                    UncommentLines(selection.Value, textChanges, trackingSpans, commentInfo);
                }

                operation = Operation.Uncomment;
            }

            return(new CommentSelectionResult(textChanges, trackingSpans, operation));
        }
        private void UncommentContainingBlockComment(CommentSelectionInfo info, SnapshotSpan span, ArrayBuilder <TextChange> textChanges,
                                                     ArrayBuilder <CommentTrackingSpan> spansToSelect)
        {
            // See if we are (textually) contained in a block comment.
            // This could allow a selection that spans multiple block comments to uncomment the beginning of
            // the first and end of the last.  Oh well.
            var positionOfEnd   = -1;
            var text            = span.Snapshot.AsText();
            var positionOfStart = text.LastIndexOf(info.BlockCommentStartString, span.Start, caseSensitive: true);

            // If we found a start comment marker, make sure there isn't an end comment marker after it but before our span.
            if (positionOfStart >= 0)
            {
                var lastEnd = text.LastIndexOf(info.BlockCommentEndString, span.Start, caseSensitive: true);
                if (lastEnd < positionOfStart)
                {
                    positionOfEnd = text.IndexOf(info.BlockCommentEndString, span.End, caseSensitive: true);
                }
                else if (lastEnd + info.BlockCommentEndString.Length > span.End)
                {
                    // The end of the span is *inside* the end marker, so searching backwards found it.
                    positionOfEnd = lastEnd;
                }
            }

            UncommentPosition(info, span, textChanges, spansToSelect, positionOfStart, positionOfEnd);
        }
        private bool TryUncommentSingleLineComments(CommentSelectionInfo info, SnapshotSpan span, ArrayBuilder <TextChange> textChanges,
                                                    ArrayBuilder <CommentTrackingSpan> spansToSelect)
        {
            // First see if we're selecting any lines that have the single-line comment prefix.
            // If so, then we'll just remove the single-line comment prefix from those lines.
            var(firstLine, lastLine) = DetermineFirstAndLastLine(span);

            for (var lineNumber = firstLine.LineNumber; lineNumber <= lastLine.LineNumber; ++lineNumber)
            {
                var line     = span.Snapshot.GetLineFromLineNumber(lineNumber);
                var lineText = line.GetText();
                if (lineText.Trim().StartsWith(info.SingleLineCommentString, StringComparison.Ordinal))
                {
                    DeleteText(textChanges, new TextSpan(line.Start.Position + lineText.IndexOf(info.SingleLineCommentString, StringComparison.Ordinal), info.SingleLineCommentString.Length));
                }
            }

            // If we made any changes, select the entirety of the lines we change, so that subsequent invocations will
            // affect the same lines.
            if (textChanges.Count == 0)
            {
                return(false);
            }

            spansToSelect.Add(new CommentTrackingSpan(TextSpan.FromBounds(firstLine.Start.Position, lastLine.End.Position)));
            return(true);
        }
Exemple #7
0
        private static void ApplySingleLineCommentToNonBlankLines(
            CommentSelectionInfo info,
            ArrayBuilder <TextChange> textChanges,
            ITextSnapshotLine firstLine,
            ITextSnapshotLine lastLine,
            int indentToCommentAt
            )
        {
            var snapshot = firstLine.Snapshot;

            for (
                var lineNumber = firstLine.LineNumber;
                lineNumber <= lastLine.LineNumber;
                ++lineNumber
                )
            {
                var line = snapshot.GetLineFromLineNumber(lineNumber);
                if (!line.IsEmptyOrWhitespace())
                {
                    InsertText(
                        textChanges,
                        line.Start + indentToCommentAt,
                        info.SingleLineCommentString
                        );
                }
            }
        }
Exemple #8
0
        private static bool IsLineCommentedOrEmpty(ITextSnapshotLine line, CommentSelectionInfo info)
        {
            var lineText = line.GetText();

            // We don't add / remove anything for empty lines.
            return(lineText.Trim().StartsWith(info.SingleLineCommentString, StringComparison.Ordinal) || line.IsEmptyOrWhitespace());
        }
Exemple #9
0
 private static void AddBlockComment(
     SnapshotSpan span,
     ArrayBuilder <TextChange> textChanges,
     ArrayBuilder <CommentTrackingSpan> trackingSpans,
     CommentSelectionInfo commentInfo
     )
 {
     trackingSpans.Add(new CommentTrackingSpan(TextSpan.FromBounds(span.Start, span.End)));
     InsertText(textChanges, span.Start, commentInfo.BlockCommentStartString);
     InsertText(textChanges, span.End, commentInfo.BlockCommentEndString);
 }
        private void UncommentPosition(CommentSelectionInfo info, SnapshotSpan span, List <TextChange> textChanges, List <ITrackingSpan> spansToSelect, int positionOfStart, int positionOfEnd)
        {
            if (positionOfStart < 0 || positionOfEnd < 0)
            {
                return;
            }

            spansToSelect.Add(span.Snapshot.CreateTrackingSpan(Span.FromBounds(positionOfStart, positionOfEnd + info.BlockCommentEndString.Length), SpanTrackingMode.EdgeExclusive));
            DeleteText(textChanges, new TextSpan(positionOfStart, info.BlockCommentStartString.Length));
            DeleteText(textChanges, new TextSpan(positionOfEnd, info.BlockCommentEndString.Length));
        }
Exemple #11
0
 public bool EndsWithAnyBlockCommentMarker(CommentSelectionInfo commentInfo)
 {
     return(_trimmedText.EndsWith(
                commentInfo.BlockCommentStartString,
                StringComparison.Ordinal
                ) ||
            _trimmedText.EndsWith(
                commentInfo.BlockCommentEndString,
                StringComparison.Ordinal
                ));
 }
        private void UncommentContainingBlockComment(CommentSelectionInfo info, SnapshotSpan span, List <TextChange> textChanges, List <ITrackingSpan> spansToSelect)
        {
            // We didn't make any single line changes.  If the language supports block comments, see
            // if we're inside a containing block comment and uncomment that.

            var positionOfStart = -1;
            var positionOfEnd   = -1;
            var spanText        = span.GetText();
            var trimmedSpanText = spanText.Trim();

            // See if the selection includes just a block comment (plus whitespace)
            if (trimmedSpanText.StartsWith(info.BlockCommentStartString, StringComparison.Ordinal) && trimmedSpanText.EndsWith(info.BlockCommentEndString, StringComparison.Ordinal))
            {
                positionOfStart = span.Start + spanText.IndexOf(info.BlockCommentStartString, StringComparison.Ordinal);
                positionOfEnd   = span.Start + spanText.LastIndexOf(info.BlockCommentEndString, StringComparison.Ordinal);
            }
            else
            {
                // See if we are (textually) contained in a block comment.
                // This could allow a selection that spans multiple block comments to uncomment the beginning of
                // the first and end of the last.  Oh well.
                var text = span.Snapshot.AsText();
                positionOfStart = text.LastIndexOf(info.BlockCommentStartString, span.Start, caseSensitive: true);

                // If we found a start comment marker, make sure there isn't an end comment marker after it but before our span.
                if (positionOfStart >= 0)
                {
                    var lastEnd = text.LastIndexOf(info.BlockCommentEndString, span.Start, caseSensitive: true);
                    if (lastEnd < positionOfStart)
                    {
                        positionOfEnd = text.IndexOf(info.BlockCommentEndString, span.End, caseSensitive: true);
                    }
                    else if (lastEnd + info.BlockCommentEndString.Length > span.End)
                    {
                        // The end of the span is *inside* the end marker, so searching backwards found it.
                        positionOfEnd = lastEnd;
                    }
                }
            }

            if (positionOfStart < 0 || positionOfEnd < 0)
            {
                return;
            }

            spansToSelect.Add(span.Snapshot.CreateTrackingSpan(Span.FromBounds(positionOfStart, positionOfEnd + info.BlockCommentEndString.Length), SpanTrackingMode.EdgeExclusive));
            DeleteText(textChanges, new TextSpan(positionOfStart, info.BlockCommentStartString.Length));
            DeleteText(textChanges, new TextSpan(positionOfEnd, info.BlockCommentEndString.Length));
        }
Exemple #13
0
        private static void UncommentLines(ImmutableArray<ITextSnapshotLine> commentedLines, ArrayBuilder<TextChange> textChanges,
            ArrayBuilder<CommentTrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
        {
            foreach (var line in commentedLines)
            {
                if (!line.IsEmptyOrWhitespace())
                {
                    var text = line.GetText();
                    var commentIndex = text.IndexOf(commentInfo.SingleLineCommentString) + line.Start;
                    var spanToRemove = TextSpan.FromBounds(commentIndex, commentIndex + commentInfo.SingleLineCommentString.Length);
                    DeleteText(textChanges, spanToRemove);
                }
            }

            trackingSpans.Add(new CommentTrackingSpan(TextSpan.FromBounds(commentedLines.First().Start, commentedLines.Last().End)));
        }
Exemple #14
0
        protected override Task <ImmutableArray <TextSpan> > GetBlockCommentsInDocumentAsync(
            Document document,
            ITextSnapshot snapshot,
            TextSpan linesContainingSelections,
            CommentSelectionInfo commentInfo,
            CancellationToken cancellationToken
            )
        {
            var allText        = snapshot.AsText();
            var commentedSpans = ArrayBuilder <TextSpan> .GetInstance();

            var openIdx = 0;

            while (
                (
                    openIdx = allText.IndexOf(
                        commentInfo.BlockCommentStartString,
                        openIdx,
                        caseSensitive: true
                        )
                ) >= 0
                )
            {
                // Retrieve the first closing marker located after the open index.
                var closeIdx = allText.IndexOf(
                    commentInfo.BlockCommentEndString,
                    openIdx + commentInfo.BlockCommentStartString.Length,
                    caseSensitive: true
                    );
                // If an open marker is found without a close marker, it's an unclosed comment.
                if (closeIdx < 0)
                {
                    closeIdx = allText.Length - commentInfo.BlockCommentEndString.Length;
                }

                var blockCommentSpan = new TextSpan(
                    openIdx,
                    closeIdx + commentInfo.BlockCommentEndString.Length - openIdx
                    );
                commentedSpans.Add(blockCommentSpan);
                openIdx = closeIdx;
            }

            return(Task.FromResult(commentedSpans.ToImmutableAndFree()));
        }
        protected override async Task <ImmutableArray <TextSpan> > GetBlockCommentsInDocumentAsync(
            Document document,
            ITextSnapshot snapshot,
            TextSpan linesContainingSelections,
            CommentSelectionInfo commentInfo,
            CancellationToken cancellationToken
            )
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            // Only search for block comments intersecting the lines in the selections.
            return(root.DescendantTrivia(linesContainingSelections)
                   .Where(
                       trivia =>
                       trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) ||
                       trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)
                       )
                   .SelectAsArray(blockCommentTrivia => blockCommentTrivia.Span));
        }
Exemple #16
0
 private bool SelectionHasUncommentedLines(ImmutableArray <ITextSnapshotLine> linesInSelection, CommentSelectionInfo commentInfo)
 => linesInSelection.Any(l => !IsLineCommentedOrEmpty(l, commentInfo));
Exemple #17
0
        private static void CommentLines(SnapshotSpan selectedSpan, ImmutableArray <ITextSnapshotLine> linesInSelection,
                                         ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
        {
            var indentation = DetermineSmallestIndent(selectedSpan, linesInSelection.First(), linesInSelection.Last());

            foreach (var line in linesInSelection)
            {
                if (!line.IsEmptyOrWhitespace())
                {
                    InsertText(textChanges, line.Start + indentation, commentInfo.SingleLineCommentString);
                }
            }

            trackingSpans.Add(new CommentTrackingSpan(
                                  TextSpan.FromBounds(linesInSelection.First().Start, linesInSelection.Last().End)));
        }
        private async Task <CommentSelectionResult> ToggleBlockCommentsAsync(Document document, CommentSelectionInfo commentInfo,
                                                                             ITextStructureNavigator navigator, NormalizedSnapshotSpanCollection selectedSpans, CancellationToken cancellationToken)
        {
            var firstLineAroundSelection = selectedSpans.First().Start.GetContainingLine().Start;
            var lastLineAroundSelection  = selectedSpans.Last().End.GetContainingLine().End;
            var linesContainingSelection = TextSpan.FromBounds(firstLineAroundSelection, lastLineAroundSelection);
            var blockCommentedSpans      = await GetBlockCommentsInDocumentAsync(
                document, selectedSpans.First().Snapshot, linesContainingSelection, commentInfo, cancellationToken).ConfigureAwait(false);

            var blockCommentSelections = selectedSpans.SelectAsArray(span => new BlockCommentSelectionHelper(blockCommentedSpans, span));

            var returnOperation = Operation.Uncomment;

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

            var trackingSpans = ArrayBuilder <CommentTrackingSpan> .GetInstance();

            // Try to uncomment until an already uncommented span is found.
            foreach (var blockCommentSelection in blockCommentSelections)
            {
                // If any selection does not have comments to remove, then the operation should be comment.
                if (!TryUncommentBlockComment(blockCommentedSpans, blockCommentSelection, textChanges, trackingSpans, commentInfo))
                {
                    returnOperation = Operation.Comment;
                    break;
                }
            }

            if (returnOperation == Operation.Comment)
            {
                textChanges.Clear();
                trackingSpans.Clear();
                foreach (var blockCommentSelection in blockCommentSelections)
                {
                    BlockCommentSpan(blockCommentSelection, navigator, textChanges, trackingSpans, commentInfo);
                }
            }

            return(new CommentSelectionResult(textChanges.ToArrayAndFree(), trackingSpans.ToArrayAndFree(), returnOperation));
        }
 /// <summary>
 /// Retrieves data about the commented spans near the selection.
 /// </summary>
 /// <param name="document">the current document.</param>
 /// <param name="snapshot">the current text snapshot.</param>
 /// <param name="linesContainingSelections">
 ///     a span that contains text from the first character of the first line in the selection(s)
 ///     until the last character of the last line in the selection(s)
 /// </param>
 /// <param name="commentInfo">the comment information for the document.</param>
 /// <param name="cancellationToken">a cancellation token.</param>
 /// <returns>any commented spans relevant to the selection in the document.</returns>
 protected abstract Task <ImmutableArray <TextSpan> > GetBlockCommentsInDocumentAsync(Document document, ITextSnapshot snapshot,
                                                                                      TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken);
        private static void DeleteBlockComment(BlockCommentSelectionHelper blockCommentSelection, TextSpan spanToRemove,
                                               ArrayBuilder <TextChange> textChanges, CommentSelectionInfo commentInfo)
        {
            DeleteText(textChanges, new TextSpan(spanToRemove.Start, commentInfo.BlockCommentStartString.Length));
            var endMarkerPosition = spanToRemove.End - commentInfo.BlockCommentEndString.Length;

            // Sometimes the block comment will be missing a close marker.
            if (Equals(blockCommentSelection.GetSubstringFromText(endMarkerPosition, commentInfo.BlockCommentEndString.Length),
                       commentInfo.BlockCommentEndString))
            {
                DeleteText(textChanges, new TextSpan(endMarkerPosition, commentInfo.BlockCommentEndString.Length));
            }
        }
 private static void AddBlockComment(CommentSelectionInfo commentInfo, TextSpan span, ArrayBuilder <TextChange> textChanges)
 {
     InsertText(textChanges, span.Start, commentInfo.BlockCommentStartString);
     InsertText(textChanges, span.End, commentInfo.BlockCommentEndString);
 }
        /// <summary>
        /// Adds a block comment when the selection already contains block comment(s).
        /// The result will be sequential block comments with the entire selection being commented out.
        /// </summary>
        private static void AddBlockCommentWithIntersectingSpans(BlockCommentSelectionHelper blockCommentSelection,
                                                                 ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
        {
            var selectedSpan = blockCommentSelection.SelectedSpan;

            var amountToAddToStart = 0;
            var amountToAddToEnd   = 0;

            // Add comments to all uncommented spans in the selection.
            foreach (var uncommentedSpan in blockCommentSelection.UncommentedSpansInSelection)
            {
                AddBlockComment(commentInfo, uncommentedSpan, textChanges);
            }

            var startsWithCommentMarker = blockCommentSelection.StartsWithAnyBlockCommentMarker(commentInfo);
            var endsWithCommentMarker   = blockCommentSelection.EndsWithAnyBlockCommentMarker(commentInfo);

            // If the start is commented (and not a comment marker), close the current comment and open a new one.
            if (blockCommentSelection.IsLocationCommented(selectedSpan.Start) && !startsWithCommentMarker)
            {
                InsertText(textChanges, selectedSpan.Start, commentInfo.BlockCommentEndString);
                InsertText(textChanges, selectedSpan.Start, commentInfo.BlockCommentStartString);
                // Shrink the tracking so the previous comment start marker is not included in selection.
                amountToAddToStart = commentInfo.BlockCommentEndString.Length;
            }

            // If the end is commented (and not a comment marker), close the current comment and open a new one.
            if (blockCommentSelection.IsLocationCommented(selectedSpan.End) && !endsWithCommentMarker)
            {
                InsertText(textChanges, selectedSpan.End, commentInfo.BlockCommentEndString);
                InsertText(textChanges, selectedSpan.End, commentInfo.BlockCommentStartString);
                // Shrink the tracking span so the next comment start marker is not included in selection.
                amountToAddToEnd = -commentInfo.BlockCommentStartString.Length;
            }

            trackingSpans.Add(new CommentTrackingSpan(selectedSpan, amountToAddToStart, amountToAddToEnd));
        }
        private static void BlockCommentSpan(BlockCommentSelectionHelper blockCommentSelection, ITextStructureNavigator navigator,
                                             ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
        {
            // Add sequential block comments if the selection contains any intersecting comments.
            if (blockCommentSelection.HasIntersectingBlockComments())
            {
                AddBlockCommentWithIntersectingSpans(blockCommentSelection, textChanges, trackingSpans, commentInfo);
            }
            else
            {
                // Comment the selected span or caret location.
                var spanToAdd = blockCommentSelection.SelectedSpan;
                if (spanToAdd.IsEmpty)
                {
                    var caretLocation = GetCaretLocationAfterToken(navigator, blockCommentSelection);
                    spanToAdd = TextSpan.FromBounds(caretLocation, caretLocation);
                }

                trackingSpans.Add(new CommentTrackingSpan(spanToAdd));
                AddBlockComment(commentInfo, spanToAdd, textChanges);
            }
        }
 private void AddBlockComment(SnapshotSpan span, List <TextChange> textChanges, List <ITrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
 {
     trackingSpans.Add(span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive));
     InsertText(textChanges, span.Start, commentInfo.BlockCommentStartString);
     InsertText(textChanges, span.End, commentInfo.BlockCommentEndString);
 }
        private void AddSingleLineComments(SnapshotSpan span, List <TextChange> textChanges, List <ITrackingSpan> trackingSpans, ITextSnapshotLine firstLine, ITextSnapshotLine lastLine, CommentSelectionInfo commentInfo)
        {
            // Select the entirety of the lines, so that another comment operation will add more
            // comments, not insert block comments.
            trackingSpans.Add(span.Snapshot.CreateTrackingSpan(Span.FromBounds(firstLine.Start.Position, lastLine.End.Position), SpanTrackingMode.EdgeInclusive));
            var indentToCommentAt = DetermineSmallestIndent(span, firstLine, lastLine);

            ApplySingleLineCommentToNonBlankLines(commentInfo, textChanges, firstLine, lastLine, indentToCommentAt);
        }
 internal VSTypeScriptCommentSelectionInfo(CommentSelectionInfo underlyingObject)
 {
     UnderlyingObject = underlyingObject;
 }
        /// <summary>
        /// Retrieves block comments near the selection in the document.
        /// Uses the CSharp syntax tree to find the commented spans.
        /// </summary>
        protected override ImmutableArray <TextSpan> GetBlockCommentsInDocument(Document document, ITextSnapshot snapshot,
                                                                                TextSpan linesContainingSelections, CommentSelectionInfo commentInfo, CancellationToken cancellationToken)
        {
            var root = document.GetRequiredSyntaxRootSynchronously(cancellationToken);

            // Only search for block comments intersecting the lines in the selections.
            return(root.DescendantTrivia(linesContainingSelections)
                   .Where(trivia => trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia))
                   .SelectAsArray(blockCommentTrivia => blockCommentTrivia.Span));
        }
 private static bool TryUncommentBlockComment(ImmutableArray <TextSpan> blockCommentedSpans,
                                              BlockCommentSelectionHelper blockCommentSelection, ArrayBuilder <TextChange> textChanges,
                                              ArrayBuilder <CommentTrackingSpan> trackingSpans, CommentSelectionInfo commentInfo)
 {
     // If the selection is just a caret, try and uncomment blocks on the same line with only whitespace on the line.
     if (blockCommentSelection.SelectedSpan.IsEmpty &&
         blockCommentSelection.TryGetBlockCommentOnSameLine(blockCommentedSpans, out var blockCommentOnSameLine))
     {
         DeleteBlockComment(blockCommentSelection, blockCommentOnSameLine, textChanges, commentInfo);
         trackingSpans.Add(new CommentTrackingSpan(blockCommentOnSameLine));
         return(true);
     }
     // If the selection is entirely commented, remove any block comments that intersect.
     else if (blockCommentSelection.IsEntirelyCommented())
     {
         var intersectingBlockComments = blockCommentSelection.IntersectingBlockComments;
         foreach (var spanToRemove in intersectingBlockComments)
         {
             DeleteBlockComment(blockCommentSelection, spanToRemove, textChanges, commentInfo);
         }
         var trackingSpan = TextSpan.FromBounds(intersectingBlockComments.First().Start, intersectingBlockComments.Last().End);
         trackingSpans.Add(new CommentTrackingSpan(trackingSpan));
         return(true);
     }
     else
     {
         return(false);
     }
 }