Make it so the RazorDirectiveCompletionProvider doesn't load extra assemblies in C#.

- Added a layer of indirection to allow for proper Lazy loading of Razor and future async completion specific assemblies.
This commit is contained in:
N. Taylor Mullen 2018-09-19 17:45:39 -07:00
parent 04eb1e677c
commit c371fa29fe
2 changed files with 60 additions and 31 deletions

View File

@ -37,15 +37,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
CSharpCodeParser.TagHelperPrefixDirectiveDescriptor, CSharpCodeParser.TagHelperPrefixDirectiveDescriptor,
}; };
private readonly Lazy<RazorCodeDocumentProvider> _codeDocumentProvider; private readonly Lazy<RazorCodeDocumentProvider> _codeDocumentProvider;
private readonly Lazy<RazorCompletionFactsService> _completionFactsService; private readonly Lazy<CompletionProviderDependencies> _dependencies;
private readonly IAsyncCompletionBroker _asyncCompletionBroker;
private readonly RazorTextBufferProvider _textBufferProvider; private readonly RazorTextBufferProvider _textBufferProvider;
[ImportingConstructor] [ImportingConstructor]
public RazorDirectiveCompletionProvider( public RazorDirectiveCompletionProvider(
[Import(typeof(RazorCodeDocumentProvider))] Lazy<RazorCodeDocumentProvider> codeDocumentProvider, [Import(typeof(RazorCodeDocumentProvider))] Lazy<RazorCodeDocumentProvider> codeDocumentProvider,
[Import(typeof(RazorCompletionFactsService))] Lazy<RazorCompletionFactsService> completionFactsService, [Import(typeof(CompletionProviderDependencies))] Lazy<CompletionProviderDependencies> dependencies,
IAsyncCompletionBroker asyncCompletionBroker,
RazorTextBufferProvider textBufferProvider) RazorTextBufferProvider textBufferProvider)
{ {
if (codeDocumentProvider == null) if (codeDocumentProvider == null)
@ -53,14 +51,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(codeDocumentProvider)); throw new ArgumentNullException(nameof(codeDocumentProvider));
} }
if (completionFactsService == null) if (dependencies == null)
{ {
throw new ArgumentNullException(nameof(completionFactsService)); throw new ArgumentNullException(nameof(dependencies));
}
if (asyncCompletionBroker == null)
{
throw new ArgumentNullException(nameof(asyncCompletionBroker));
} }
if (textBufferProvider == null) if (textBufferProvider == null)
@ -69,8 +62,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
} }
_codeDocumentProvider = codeDocumentProvider; _codeDocumentProvider = codeDocumentProvider;
_completionFactsService = completionFactsService; _dependencies = dependencies;
_asyncCompletionBroker = asyncCompletionBroker;
_textBufferProvider = textBufferProvider; _textBufferProvider = textBufferProvider;
} }
@ -112,13 +104,6 @@ namespace Microsoft.VisualStudio.Editor.Razor
return Task.CompletedTask; return Task.CompletedTask;
} }
if (!_textBufferProvider.TryGetFromDocument(context.Document, out var textBuffer) ||
!_asyncCompletionBroker.IsCompletionSupported(textBuffer.ContentType))
{
// Completion is not supported.
return Task.CompletedTask;
}
var result = AddCompletionItems(context); var result = AddCompletionItems(context);
return result; return result;
@ -129,6 +114,13 @@ namespace Microsoft.VisualStudio.Editor.Razor
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private Task AddCompletionItems(CompletionContext context) private Task AddCompletionItems(CompletionContext context)
{ {
if (!_textBufferProvider.TryGetFromDocument(context.Document, out var textBuffer) ||
!_dependencies.Value.AsyncCompletionBroker.IsCompletionSupported(textBuffer.ContentType))
{
// Completion is not supported.
return Task.CompletedTask;
}
if (!_codeDocumentProvider.Value.TryGetFromDocument(context.Document, out var codeDocument)) if (!_codeDocumentProvider.Value.TryGetFromDocument(context.Document, out var codeDocument))
{ {
// A Razor code document has not yet been associated with the document. // A Razor code document has not yet been associated with the document.
@ -149,7 +141,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
} }
var location = new SourceSpan(razorSnapshotPoint.Position, 0); var location = new SourceSpan(razorSnapshotPoint.Position, 0);
var razorCompletionItems = _completionFactsService.Value.GetCompletionItems(syntaxTree, location); var razorCompletionItems = _dependencies.Value.CompletionFactsService.GetCompletionItems(syntaxTree, location);
foreach (var razorCompletionItem in razorCompletionItems) foreach (var razorCompletionItem in razorCompletionItems)
{ {
@ -208,4 +200,40 @@ namespace Microsoft.VisualStudio.Editor.Razor
return false; return false;
} }
} }
// These types are only for this class to provide indirection for assembly loads.
internal abstract class CompletionProviderDependencies
{
public abstract RazorCompletionFactsService CompletionFactsService { get; }
public abstract IAsyncCompletionBroker AsyncCompletionBroker { get; }
}
[System.Composition.Shared]
[Export(typeof(CompletionProviderDependencies))]
internal class DefaultCompletionProviderDependencies : CompletionProviderDependencies
{
[ImportingConstructor]
public DefaultCompletionProviderDependencies(
RazorCompletionFactsService completionFactsService,
IAsyncCompletionBroker asyncCompletionBroker)
{
if (completionFactsService == null)
{
throw new ArgumentNullException(nameof(completionFactsService));
}
if (asyncCompletionBroker == null)
{
throw new ArgumentNullException(nameof(asyncCompletionBroker));
}
CompletionFactsService = completionFactsService;
AsyncCompletionBroker = asyncCompletionBroker;
}
public override RazorCompletionFactsService CompletionFactsService { get; }
public override IAsyncCompletionBroker AsyncCompletionBroker { get; }
}
} }

View File

@ -30,8 +30,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
var razorBuffer = Mock.Of<ITextBuffer>(buffer => buffer.ContentType == Mock.Of<IContentType>()); var razorBuffer = Mock.Of<ITextBuffer>(buffer => buffer.ContentType == Mock.Of<IContentType>());
TextBufferProvider = Mock.Of<RazorTextBufferProvider>(provider => provider.TryGetFromDocument(It.IsAny<TextDocument>(), out razorBuffer) == true); TextBufferProvider = Mock.Of<RazorTextBufferProvider>(provider => provider.TryGetFromDocument(It.IsAny<TextDocument>(), out razorBuffer) == true);
CompletionFactsService = new DefaultRazorCompletionFactsService(); CompletionFactsService = new DefaultRazorCompletionFactsService();
CompletionProviderDependencies = new Lazy<CompletionProviderDependencies>(() => new DefaultCompletionProviderDependencies(CompletionFactsService, CompletionBroker));
} }
private Lazy<CompletionProviderDependencies> CompletionProviderDependencies { get; }
private IAsyncCompletionBroker CompletionBroker { get; } private IAsyncCompletionBroker CompletionBroker { get; }
private RazorTextBufferProvider TextBufferProvider { get; } private RazorTextBufferProvider TextBufferProvider { get; }
@ -52,8 +55,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(); var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>();
var completionProvider = new RazorDirectiveCompletionProvider( var completionProvider = new RazorDirectiveCompletionProvider(
new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object), new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object),
new Lazy<RazorCompletionFactsService>(() => CompletionFactsService), CompletionProviderDependencies,
CompletionBroker,
TextBufferProvider); TextBufferProvider);
// Act // Act
@ -75,8 +77,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(); var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>();
var completionProvider = new RazorDirectiveCompletionProvider( var completionProvider = new RazorDirectiveCompletionProvider(
new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object), new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object),
new Lazy<RazorCompletionFactsService>(() => CompletionFactsService), CompletionProviderDependencies,
CompletionBroker,
TextBufferProvider); TextBufferProvider);
// Act // Act
@ -94,7 +95,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(MockBehavior.Strict); var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(MockBehavior.Strict);
var completionProvider = new FailOnGetCompletionsProvider( var completionProvider = new FailOnGetCompletionsProvider(
new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object), new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object),
CompletionBroker, CompletionProviderDependencies,
TextBufferProvider); TextBufferProvider);
var document = CreateDocument(); var document = CreateDocument();
document = document.WithFilePath("NotRazor.cs"); document = document.WithFilePath("NotRazor.cs");
@ -122,7 +123,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(MockBehavior.Strict); var codeDocumentProvider = new Mock<RazorCodeDocumentProvider>(MockBehavior.Strict);
var completionProvider = new FailOnGetCompletionsProvider( var completionProvider = new FailOnGetCompletionsProvider(
new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object), new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object),
CompletionBroker, CompletionProviderDependencies,
TextBufferProvider); TextBufferProvider);
var context = CreateContext(1, completionProvider, document); var context = CreateContext(1, completionProvider, document);
@ -140,7 +141,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
.Returns(false); .Returns(false);
var completionProvider = new FailOnGetCompletionsProvider( var completionProvider = new FailOnGetCompletionsProvider(
new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object), new Lazy<RazorCodeDocumentProvider>(() => codeDocumentProvider.Object),
CompletionBroker, CompletionProviderDependencies,
TextBufferProvider); TextBufferProvider);
var document = CreateDocument(); var document = CreateDocument();
var context = CreateContext(1, completionProvider, document); var context = CreateContext(1, completionProvider, document);
@ -156,7 +157,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var codeDocumentProvider = CreateCodeDocumentProvider("@", Enumerable.Empty<DirectiveDescriptor>()); var codeDocumentProvider = CreateCodeDocumentProvider("@", Enumerable.Empty<DirectiveDescriptor>());
var completionProvider = new FailOnGetCompletionsProvider( var completionProvider = new FailOnGetCompletionsProvider(
codeDocumentProvider, codeDocumentProvider,
CompletionBroker, CompletionProviderDependencies,
TextBufferProvider, TextBufferProvider,
canGetSnapshotPoint: false); canGetSnapshotPoint: false);
var document = CreateDocument(); var document = CreateDocument();
@ -223,10 +224,10 @@ namespace Microsoft.VisualStudio.Editor.Razor
public FailOnGetCompletionsProvider( public FailOnGetCompletionsProvider(
Lazy<RazorCodeDocumentProvider> codeDocumentProvider, Lazy<RazorCodeDocumentProvider> codeDocumentProvider,
IAsyncCompletionBroker asyncCompletionBroker, Lazy<CompletionProviderDependencies> completionProviderDependencies,
RazorTextBufferProvider textBufferProvider, RazorTextBufferProvider textBufferProvider,
bool canGetSnapshotPoint = true) bool canGetSnapshotPoint = true)
: base(codeDocumentProvider, new Lazy<RazorCompletionFactsService>(() => new DefaultRazorCompletionFactsService()), asyncCompletionBroker, textBufferProvider) : base(codeDocumentProvider, completionProviderDependencies, textBufferProvider)
{ {
_canGetSnapshotPoint = canGetSnapshotPoint; _canGetSnapshotPoint = canGetSnapshotPoint;
} }