forked from dotnet/roslyn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathITextSnapshotExtensions.cs
105 lines (94 loc) · 5.02 KB
/
ITextSnapshotExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Formatting.Rules;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions
{
internal static partial class ITextSnapshotExtensions
{
/// <summary>
/// format given snapshot and apply text changes to buffer
/// </summary>
public static void FormatAndApplyToBuffer(
this ITextBuffer textBuffer,
TextSpan span,
EditorOptionsService editorOptionsService,
CancellationToken cancellationToken)
{
var document = textBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
{
return;
}
var documentSyntax = ParsedDocument.CreateSynchronously(document, cancellationToken);
var rules = FormattingRuleUtilities.GetFormattingRules(documentSyntax, document.Project.LanguageServices, span, additionalRules: null);
var formatter = document.GetRequiredLanguageService<ISyntaxFormattingService>();
var options = textBuffer.GetSyntaxFormattingOptions(editorOptionsService, document.Project.LanguageServices, explicitFormat: false);
var result = formatter.GetFormattingResult(documentSyntax.Root, SpecializedCollections.SingletonEnumerable(span), options, rules, cancellationToken);
var changes = result.GetTextChanges(cancellationToken);
using (Logger.LogBlock(FunctionId.Formatting_ApplyResultToBuffer, cancellationToken))
{
textBuffer.ApplyChanges(changes);
}
}
/// <summary>
/// Get <see cref="Document"/> from <see cref="Text.Extensions.GetOpenDocumentInCurrentContextWithChanges(ITextSnapshot)"/>
/// once <see cref="IWorkspaceStatusService.WaitUntilFullyLoadedAsync(CancellationToken)"/> returns
///
/// for synchronous code path, make sure to use synchronous version
/// <see cref="GetFullyLoadedOpenDocumentInCurrentContextWithChanges(ITextSnapshot, IUIThreadOperationContext, IThreadingContext)"/>.
/// otherwise, one can get into a deadlock
/// </summary>
public static async Task<Document?> GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(
this ITextSnapshot snapshot, IUIThreadOperationContext operationContext)
{
// just get a document from whatever we have
var document = snapshot.TextBuffer.AsTextContainer().GetOpenDocumentInCurrentContext();
if (document == null)
{
// we don't know about this buffer yet
return null;
}
// partial mode is always cancellable
using (operationContext.AddScope(allowCancellation: true, EditorFeaturesResources.Waiting_for_background_work_to_finish))
{
var service = document.Project.Solution.Workspace.Services.GetService<IWorkspaceStatusService>();
if (service != null)
{
// TODO: decide for prototype, we don't do anything complex and just ask workspace whether it is fully loaded
// later we might need to go and change all these with more specific info such as document/project/solution
await service.WaitUntilFullyLoadedAsync(operationContext.UserCancellationToken).ConfigureAwait(false);
}
// get proper document
return snapshot.GetOpenDocumentInCurrentContextWithChanges();
}
}
/// <summary>
/// Get <see cref="Document"/> from <see cref="Text.Extensions.GetOpenDocumentInCurrentContextWithChanges(ITextSnapshot)"/>
/// once <see cref="IWorkspaceStatusService.WaitUntilFullyLoadedAsync(CancellationToken)"/> returns
/// </summary>
public static Document? GetFullyLoadedOpenDocumentInCurrentContextWithChanges(
this ITextSnapshot snapshot, IUIThreadOperationContext operationContext, IThreadingContext threadingContext)
{
// make sure this is only called from UI thread
threadingContext.ThrowIfNotOnUIThread();
return threadingContext.JoinableTaskFactory.Run(() =>
snapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(operationContext));
}
}
}