/// <summary>
        /// Add the necessary edits to uncomment out a single span.
        /// </summary>
        private void UncommentSpan(
            Document document, ICommentSelectionService service, SnapshotSpan span,
            ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> spansToSelect, CancellationToken cancellationToken)
        {
            var info = service.GetInfoAsync(document, span.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken);

            // If the selection is exactly a block comment, use it as priority over single line comments.
            if (info.SupportsBlockComment && TryUncommentExactlyBlockComment(info, span, textChanges, spansToSelect))
            {
                return;
            }

            if (info.SupportsSingleLineComment &&
                TryUncommentSingleLineComments(info, span, textChanges, spansToSelect))
            {
                return;
            }

            // 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.
            if (info.SupportsBlockComment)
            {
                UncommentContainingBlockComment(info, span, textChanges, spansToSelect);
            }
        }
Пример #2
0
        private static void UncommentSpan(
            ICommentSelectionService service, SnapshotSpan span,
            ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> spansToSelect)
        {
            var info = service.GetInfo();

            // If the selection is exactly a block comment, use it as priority over single line comments.
            if (info.SupportsBlockComment && TryUncommentExactlyBlockComment(info, span, textChanges, spansToSelect))
            {
                return;
            }

            if (info.SupportsSingleLineComment &&
                TryUncommentSingleLineComments(info, span, textChanges, spansToSelect))
            {
                return;
            }

            // 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.
            if (info.SupportsBlockComment)
            {
                UncommentContainingBlockComment(info, span, textChanges, spansToSelect);
            }
        }
Пример #3
0
 internal abstract Task <CommentSelectionResult> CollectEditsAsync(
     Document document,
     ICommentSelectionService service,
     ITextBuffer textBuffer,
     NormalizedSnapshotSpanCollection selectedSpans,
     TCommand command,
     CancellationToken cancellationToken
     );
        private static Document Format(ICommentSelectionService service, ITextSnapshot snapshot, IEnumerable <SnapshotSpan> changes, CancellationToken cancellationToken)
        {
            var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return(null);
            }

            var textSpans = changes.SelectAsArray(change => change.Span.ToTextSpan());

            return(service.FormatAsync(document, textSpans, cancellationToken).WaitAndGetResult(cancellationToken));
        }
        private void Format(ICommentSelectionService service, ITextSnapshot snapshot, IEnumerable <ITrackingSpan> changes, CancellationToken cancellationToken)
        {
            var document = snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return;
            }

            var textSpans   = changes.Select(s => s.GetSpan(snapshot).Span.ToTextSpan()).ToImmutableArray();
            var newDocument = service.FormatAsync(document, textSpans, cancellationToken).WaitAndGetResult(cancellationToken);

            newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, cancellationToken);
        }
 /// <summary>
 /// Add the necessary edits to the given spans. Also collect tracking spans over each span.
 ///
 /// Internal so that it can be called by unit tests.
 /// </summary>
 internal void CollectEdits(
     Document document, ICommentSelectionService service, NormalizedSnapshotSpanCollection selectedSpans,
     List <TextChange> textChanges, List <ITrackingSpan> trackingSpans, Operation operation, CancellationToken cancellationToken)
 {
     foreach (var span in selectedSpans)
     {
         if (operation == Operation.Comment)
         {
             CommentSpan(document, service, span, textChanges, trackingSpans, cancellationToken);
         }
         else
         {
             UncommentSpan(document, service, span, textChanges, trackingSpans, cancellationToken);
         }
     }
 }
Пример #7
0
        internal override Task <CommentSelectionResult> CollectEditsAsync(
            Document document,
            ICommentSelectionService service,
            ITextBuffer subjectBuffer,
            NormalizedSnapshotSpanCollection selectedSpans,
            Operation operation,
            CancellationToken cancellationToken
            )
        {
            var spanTrackingList = ArrayBuilder <CommentTrackingSpan> .GetInstance();

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

            foreach (var span in selectedSpans)
            {
                if (operation == Operation.Comment)
                {
                    CommentSpan(
                        document,
                        service,
                        span,
                        textChanges,
                        spanTrackingList,
                        cancellationToken
                        );
                }
                else
                {
                    UncommentSpan(
                        document,
                        service,
                        span,
                        textChanges,
                        spanTrackingList,
                        cancellationToken
                        );
                }
            }

            return(Task.FromResult(
                       new CommentSelectionResult(
                           textChanges.ToArrayAndFree(),
                           spanTrackingList.ToArrayAndFree(),
                           operation
                           )
                       ));
        }
        /// <summary>
        /// Add the necessary edits to uncomment out a single span.
        /// </summary>
        private void UncommentSpan(
            Document document, ICommentSelectionService service, SnapshotSpan span,
            List <TextChange> textChanges, List <ITrackingSpan> spansToSelect, CancellationToken cancellationToken)
        {
            var info = service.GetInfoAsync(document, span.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken);

            if (info.SupportsSingleLineComment &&
                TryUncommentSingleLineComments(info, span, textChanges, spansToSelect))
            {
                return;
            }

            if (info.SupportsBlockComment)
            {
                UncommentContainingBlockComment(info, span, textChanges, spansToSelect);
            }
        }
        /// <summary>
        /// Applies the requested edits and sets the selection.
        /// This operation is not cancellable.
        /// </summary>
        private void ApplyEdits(Document document, ITextView textView, ITextBuffer subjectBuffer,
                                ICommentSelectionService service, string title, CommentSelectionResult edits)
        {
            // Create tracking spans to track the text changes.
            var currentSnapshot = subjectBuffer.CurrentSnapshot;
            var trackingSpans   = edits.TrackingSpans
                                  .SelectAsArray(textSpan => (originalSpan: textSpan, trackingSpan: CreateTrackingSpan(edits.ResultOperation, currentSnapshot, textSpan.TrackingTextSpan)));

            // Apply the text changes.
            using (var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                document.Project.Solution.Workspace.ApplyTextChanges(document.Id, edits.TextChanges.Distinct(), CancellationToken.None);
                transaction.Complete();
            }

            // Convert the tracking spans into snapshot spans for formatting and selection.
            var trackingSnapshotSpans = trackingSpans.Select(s => CreateSnapshotSpan(subjectBuffer.CurrentSnapshot, s.trackingSpan, s.originalSpan));

            if (trackingSnapshotSpans.Any())
            {
                if (edits.ResultOperation == Operation.Uncomment)
                {
                    // Format the document only during uncomment operations.  Use second transaction so it can be undone.
                    using var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService);

                    var formattedDocument = Format(service, subjectBuffer.CurrentSnapshot, trackingSnapshotSpans, CancellationToken.None);
                    if (formattedDocument != null)
                    {
                        formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, CancellationToken.None);
                        transaction.Complete();
                    }
                }

                // Set the multi selection after edits have been applied.
                textView.SetMultiSelection(trackingSnapshotSpans);
            }
        }
Пример #10
0
        internal async override Task <CommentSelectionResult> CollectEditsAsync(Document document, ICommentSelectionService service,
                                                                                ITextBuffer subjectBuffer, NormalizedSnapshotSpanCollection selectedSpans, ValueTuple command, CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.CommandHandler_ToggleLineComment, KeyValueLogMessage.Create(LogType.UserAction, m =>
            {
                m[LanguageNameString] = document.Project.Language;
                m[LengthString] = subjectBuffer.CurrentSnapshot.Length;
            }), cancellationToken))
            {
                var commentInfo = await service.GetInfoAsync(document, selectedSpans.First().Span.ToTextSpan(), cancellationToken).ConfigureAwait(false);

                if (commentInfo.SupportsSingleLineComment)
                {
                    return(ToggleLineComment(commentInfo, selectedSpans));
                }

                return(s_emptyCommentSelectionResult);
            }
        }
        /// <summary>
        /// Add the necessary edits to comment out a single span.
        /// </summary>
        private void CommentSpan(
            Document document, ICommentSelectionService service, SnapshotSpan span,
            ArrayBuilder <TextChange> textChanges, ArrayBuilder <CommentTrackingSpan> trackingSpans, CancellationToken cancellationToken)
        {
            var(firstLine, lastLine) = DetermineFirstAndLastLine(span);

            if (span.IsEmpty && firstLine.IsEmptyOrWhitespace())
            {
                // No selection, and on an empty line, don't do anything.
                return;
            }

            if (!span.IsEmpty && string.IsNullOrWhiteSpace(span.GetText()))
            {
                // Just whitespace selected, don't do anything.
                return;
            }

            // Get the information from the language as to how they'd like to comment this region.
            var commentInfo = service.GetInfoAsync(document, span.Span.ToTextSpan(), cancellationToken).WaitAndGetResult(cancellationToken);

            if (!commentInfo.SupportsBlockComment && !commentInfo.SupportsSingleLineComment)
            {
                // Neither type of comment supported.
                return;
            }

            if (commentInfo.SupportsBlockComment && !commentInfo.SupportsSingleLineComment)
            {
                // Only block comments supported here.  If there is a span, just surround that
                // span with a block comment.  If tehre is no span then surround the entire line
                // with a block comment.
                if (span.IsEmpty)
                {
                    var firstNonWhitespaceOnLine = firstLine.GetFirstNonWhitespacePosition();
                    var insertPosition           = firstNonWhitespaceOnLine ?? firstLine.Start;

                    span = new SnapshotSpan(span.Snapshot, Span.FromBounds(insertPosition, firstLine.End));
                }

                AddBlockComment(span, textChanges, trackingSpans, commentInfo);
            }
            else if (!commentInfo.SupportsBlockComment && commentInfo.SupportsSingleLineComment)
            {
                // Only single line comments supported here.
                AddSingleLineComments(span, textChanges, trackingSpans, firstLine, lastLine, commentInfo);
            }
            else
            {
                // both comment forms supported.  Do a block comment only if a portion of code is
                // selected on a single line, otherwise comment out all the lines using single-line
                // comments.
                if (!span.IsEmpty &&
                    !SpanIncludesAllTextOnIncludedLines(span) &&
                    firstLine.LineNumber == lastLine.LineNumber)
                {
                    AddBlockComment(span, textChanges, trackingSpans, commentInfo);
                }
                else
                {
                    AddSingleLineComments(span, textChanges, trackingSpans, firstLine, lastLine, commentInfo);
                }
            }
        }