public Task <Document> FormatAsync(Document document, ImmutableArray <TextSpan> changes, CancellationToken cancellationToken)
        {
            var root            = document.GetSyntaxRootSynchronously(cancellationToken);
            var formattingSpans = changes.Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken));
        }
예제 #2
0
        private void AdjustIndentationForSpan(
            Document document, ITextEdit edit, TextSpan visibleSpan, IFormattingRule baseIndentationRule, OptionSet options)
        {
            var root = document.GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);

            using (var rulePool = SharedPools.Default <List <IFormattingRule> >().GetPooledObject())
                using (var spanPool = SharedPools.Default <List <TextSpan> >().GetPooledObject())
                {
                    var venusFormattingRules = rulePool.Object;
                    var visibleSpans         = spanPool.Object;

                    venusFormattingRules.Add(baseIndentationRule);
                    venusFormattingRules.Add(ContainedDocumentPreserveFormattingRule.Instance);

                    var formattingRules = venusFormattingRules.Concat(Formatter.GetDefaultFormattingRules(document));

                    var workspace = document.Project.Solution.Workspace;
                    var changes   = Formatter.GetFormattedTextChanges(
                        root, new TextSpan[] { CommonFormattingHelpers.GetFormattingSpan(root, visibleSpan) },
                        workspace, options, formattingRules, CancellationToken.None);

                    visibleSpans.Add(visibleSpan);
                    var newChanges = FilterTextChanges(document.GetTextAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None), visibleSpans, changes.ToReadOnlyCollection()).Where(t => visibleSpan.Contains(t.Span));

                    foreach (var change in newChanges)
                    {
                        edit.Replace(change.Span.ToSpan(), change.NewText);
                    }
                }
        }
예제 #3
0
        public void FormatSpan(SnapshotSpan span)
        {
            // Formatting a snippet isn't cancellable.
            var cancellationToken = CancellationToken.None;

            // At this point, the $selection$ token has been replaced with the selected text and
            // declarations have been replaced with their default text. We need to format the
            // inserted snippet text while carefully handling $end$ position (where the caret goes
            // after Return is pressed). The IExpansionSession keeps a tracking point for this
            // position but we do the tracking ourselves to properly deal with virtual space. To
            // ensure the end location is correct, we take three extra steps:
            // 1. Insert an empty comment ("/**/" or "'") at the current $end$ position (prior
            //    to formatting), and keep a tracking span for the comment.
            // 2. After formatting the new snippet text, find and delete the empty multiline
            //    comment (via the tracking span) and notify the IExpansionSession of the new
            //    $end$ location. If the line then contains only whitespace (due to the formatter
            //    putting the empty comment on its own line), then delete the white space and
            //    remember the indentation depth for that line.
            // 3. When the snippet is finally completed (via Return), and PositionCaretForEditing()
            //    is called, check to see if the end location was on a line containing only white
            //    space in the previous step. If so, and if that line is still empty, then position
            //    the caret in virtual space.
            // This technique ensures that a snippet like "if($condition$) { $end$ }" will end up
            // as:
            //     if ($condition$)
            //     {
            //         $end$
            //     }
            if (!TryGetSubjectBufferSpan(span, out var snippetSpan))
            {
                return;
            }

            // Insert empty comment and track end position
            var snippetTrackingSpan = snippetSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive);

            var fullSnippetSpan = ExpansionSession.GetSnippetSpan();

            var isFullSnippetFormat     = fullSnippetSpan == span;
            var endPositionTrackingSpan = isFullSnippetFormat ? InsertEmptyCommentAndGetEndPositionTrackingSpan() : null;

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(SubjectBuffer.CurrentSnapshot, snippetTrackingSpan.GetSpan(SubjectBuffer.CurrentSnapshot));

            SubjectBuffer.CurrentSnapshot.FormatAndApplyToBuffer(formattingSpan, CancellationToken.None);

            if (isFullSnippetFormat)
            {
                CleanUpEndLocation(endPositionTrackingSpan);

                // Unfortunately, this is the only place we can safely add references and imports
                // specified in the snippet xml. In OnBeforeInsertion we have no guarantee that the
                // snippet xml will be available, and changing the buffer during OnAfterInsertion can
                // cause the underlying tracking spans to get out of sync.
                var currentStartPosition = snippetTrackingSpan.GetStartPoint(SubjectBuffer.CurrentSnapshot).Position;
                AddReferencesAndImports(
                    ExpansionSession, currentStartPosition, cancellationToken);

                SetNewEndPosition(endPositionTrackingSpan);
            }
        }
예제 #4
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesOnPasteAsync(
            Document document,
            TextSpan textSpan,
            DocumentOptionSet?documentOptions,
            CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, textSpan);
            var service        = document.GetRequiredLanguageService <ISyntaxFormattingService>();

            var rules = new List <AbstractFormattingRule>()
            {
                new PasteFormattingRule()
            };

            rules.AddRange(service.GetDefaultFormattingRules());

            if (documentOptions == null)
            {
                var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService <IInferredIndentationService>();
                documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat : false, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, document.Project.Solution.Workspace.Services, document.Project.Language);
            var result            = service.GetFormattingResult(root, SpecializedCollections.SingletonEnumerable(formattingSpan), formattingOptions, rules, cancellationToken);

            return(result.GetTextChanges(cancellationToken).ToImmutableArray());
        }
        protected static async Task <LSP.TextEdit[]?> GetTextEditsAsync(
            RequestContext context,
            LSP.FormattingOptions options,
            IGlobalOptionService globalOptions,
            CancellationToken cancellationToken,
            LSP.Range?range = null)
        {
            var document = context.Document;

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

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var rangeSpan      = (range != null) ? ProtocolConversions.RangeToTextSpan(range, text) : new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, rangeSpan);

            // We should use the options passed in by LSP instead of the document's options.
            var formattingOptions = await ProtocolConversions.GetFormattingOptionsAsync(options, document, globalOptions, cancellationToken).ConfigureAwait(false);

            var services    = document.Project.Solution.Services;
            var textChanges = Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, rules: null, cancellationToken);

            var edits = new ArrayBuilder <LSP.TextEdit>();

            edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
            return(edits.ToArrayAndFree());
        }
예제 #6
0
        public Document Format(Document document, IEnumerable <TextSpan> changes, CancellationToken cancellationToken)
        {
            var root            = document.GetSyntaxRootSynchronously(cancellationToken);
            var formattingSpans = changes.Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken));
        }
        public async Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan.HasValue ? textSpan.Value : new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            return(Formatter.GetFormattedTextChanges(root, new TextSpan[] { formattingSpan }, document.Project.Solution.Workspace, cancellationToken: cancellationToken));
        }
예제 #8
0
        public Document Format(Document document, IEnumerable <TextSpan> changes, CancellationToken cancellationToken)
        {
            var snapshot = document.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken).FindCorrespondingEditorTextSnapshot();

            var root            = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var formattingSpans = changes.Select(s => s.ToSnapshotSpan(snapshot))
                                  .Select(s => CommonFormattingHelpers.GetFormattingSpan(root, s.Span.ToTextSpan()));

            return(Formatter.FormatAsync(document, formattingSpans, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken));
        }
예제 #9
0
        public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document, TextSpan? textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var span = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);
            return Formatter.GetFormattedTextChanges(root,
                SpecializedCollections.SingletonEnumerable(formattingSpan),
                document.Project.Solution.Workspace, options, cancellationToken);
        }
        public async Task <IList <TextChange> > GetFormattingChangesAsync(Document document, TextSpan?textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            var options = await document.GetDocumentOptionsWithInferredIndentationAsync(explicitFormat : true, indentationManagerService : _indentationManagerService, cancellationToken : cancellationToken).ConfigureAwait(false);

            return(Formatter.GetFormattedTextChanges(root,
                                                     SpecializedCollections.SingletonEnumerable(formattingSpan),
                                                     document.Project.Solution.Workspace, options, cancellationToken));
        }
        public Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            ITextBuffer textBuffer,
            TextSpan?textSpan,
            CancellationToken cancellationToken)
        {
            var parsedDocument = ParsedDocument.CreateSynchronously(document, cancellationToken);
            var options        = textBuffer.GetSyntaxFormattingOptions(_editorOptionsService, parsedDocument.LanguageServices, explicitFormat: true);

            var span           = textSpan ?? new TextSpan(0, parsedDocument.Root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(parsedDocument.Root, span);

            return(Task.FromResult(Formatter.GetFormattedTextChanges(parsedDocument.Root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Services, options, cancellationToken).ToImmutableArray()));
        }
예제 #12
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            TextSpan?textSpan,
            CancellationToken cancellationToken)
        {
            var options = await _indentationManager.GetInferredFormattingOptionsAsync(document, explicitFormat : true, cancellationToken).ConfigureAwait(false);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            var services = document.Project.Solution.Workspace.Services;

            return(Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, options, cancellationToken).ToImmutableArray());
        }
예제 #13
0
        public async Task<IList<TextChange>> GetFormattingChangesOnPasteAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, textSpan);
            var service = document.GetLanguageService<ISyntaxFormattingService>();
            if (service == null)
            {
                return SpecializedCollections.EmptyList<TextChange>();
            }

            var rules = new List<IFormattingRule>() { new PasteFormattingRule() };
            rules.AddRange(service.GetDefaultFormattingRules());

            return Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), document.Project.Solution.Workspace, options, rules, cancellationToken);
        }
        private void ApplyEdits(Document document, ITextView textView, ITextBuffer subjectBuffer, string title, CommentSelectionResult edits, CancellationToken cancellationToken)
        {
            var originalSnapshot = subjectBuffer.CurrentSnapshot;

            // Apply the text changes.
            using (var transaction = new CaretPreservingEditTransaction(title, textView, _undoHistoryRegistry, _editorOperationsFactoryService))
            {
                subjectBuffer.ApplyChanges(edits.TextChanges);
                transaction.Complete();
            }

            if (edits.TrackingSpans.Any())
            {
                // Create tracking spans to track the text changes.
                var trackingSpans = edits.TrackingSpans
                                    .SelectAsArray(textSpan => (originalSpan: textSpan, trackingSpan: CreateTrackingSpan(edits.ResultOperation, originalSnapshot, textSpan.TrackingTextSpan)));

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

                if (edits.ResultOperation == Operation.Uncomment && document.SupportsSyntaxTree)
                {
                    // 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 newText       = subjectBuffer.CurrentSnapshot.AsText();
                    var oldSyntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken);
                    var newRoot       = oldSyntaxTree.WithChangedText(newText).GetRoot(cancellationToken);

                    var formattingOptions = subjectBuffer.GetSyntaxFormattingOptions(_editorOptionsService, document.Project.LanguageServices, explicitFormat: false);
                    var formattingSpans   = trackingSnapshotSpans.Select(change => CommonFormattingHelpers.GetFormattingSpan(newRoot, change.Span.ToTextSpan()));
                    var formattedChanges  = Formatter.GetFormattedTextChanges(newRoot, formattingSpans, document.Project.Solution.Services, formattingOptions, rules: null, cancellationToken);

                    subjectBuffer.ApplyChanges(formattedChanges);

                    transaction.Complete();
                }

                // Set the multi selection after edits have been applied.
                textView.SetMultiSelection(trackingSnapshotSpans);
            }
        }
예제 #15
0
        public async Task <ImmutableArray <TextChange> > GetFormattingChangesAsync(
            Document document,
            TextSpan?textSpan,
            DocumentOptionSet?documentOptions,
            CancellationToken cancellationToken)
        {
            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var span           = textSpan ?? new TextSpan(0, root.FullSpan.Length);
            var formattingSpan = CommonFormattingHelpers.GetFormattingSpan(root, span);

            if (documentOptions == null)
            {
                var inferredIndentationService = document.Project.Solution.Workspace.Services.GetRequiredService <IInferredIndentationService>();
                documentOptions = await inferredIndentationService.GetDocumentOptionsWithInferredIndentationAsync(document, explicitFormat : true, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            var services          = document.Project.Solution.Workspace.Services;
            var formattingOptions = SyntaxFormattingOptions.Create(documentOptions, services, document.Project.Language);

            return(Formatter.GetFormattedTextChanges(root, SpecializedCollections.SingletonEnumerable(formattingSpan), services, formattingOptions, cancellationToken).ToImmutableArray());
        }