Make VisualStudioRazorParserFactory VisualStudio agnostic.

- Removed the `Microsoft.VisualStudio.Language.IntelliSense` dependency from `Microsoft.VisualStudio.Editor.Razor` because it isn't supported in VS for mac.
- Replaced `ICompletionBroker` usage in the VS agnostic dll with a new abstract type `VisualStudioCompletionBroker`. This also enables us to implement completion
- Added Mac implementation of new `VisualStudioCompletionBroker`.

#1789
This commit is contained in:
N. Taylor Mullen 2017-12-06 17:23:45 -08:00
parent f708c463d9
commit 37eed518f8
15 changed files with 226 additions and 76 deletions

View File

@ -27,6 +27,7 @@
<MicrosoftVisualStudioShellInterop80PackageVersion>8.0.50727</MicrosoftVisualStudioShellInterop80PackageVersion>
<MicrosoftVisualStudioShellInterop90PackageVersion>9.0.30729</MicrosoftVisualStudioShellInterop90PackageVersion>
<MicrosoftVisualStudioShellInteropPackageVersion>7.10.6071</MicrosoftVisualStudioShellInteropPackageVersion>
<MicrosoftVisualStudioTextUIPackageVersion>15.6.161-preview</MicrosoftVisualStudioTextUIPackageVersion>
<MonoAddinsPackageVersion>1.3.7</MonoAddinsPackageVersion>
<MonoDevelopSdkPackageVersion>1.0.0</MonoDevelopSdkPackageVersion>
<MoqPackageVersion>4.7.49</MoqPackageVersion>

View File

@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer;
using Timer = System.Threading.Timer;
@ -28,7 +27,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
internal ChangeReference _latestChangeReference;
private readonly object IdleLock = new object();
private readonly ICompletionBroker _completionBroker;
private readonly VisualStudioCompletionBroker _completionBroker;
private readonly VisualStudioDocumentTracker _documentTracker;
private readonly ForegroundDispatcher _dispatcher;
private readonly RazorTemplateEngineFactoryService _templateEngineFactory;
@ -50,7 +49,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
VisualStudioDocumentTracker documentTracker,
RazorTemplateEngineFactoryService templateEngineFactory,
ErrorReporter errorReporter,
ICompletionBroker completionBroker)
VisualStudioCompletionBroker completionBroker)
{
if (dispatcher == null)
{

View File

@ -2,45 +2,47 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using TemplateEngineFactoryService = Microsoft.CodeAnalysis.Razor.RazorTemplateEngineFactoryService;
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
namespace Microsoft.VisualStudio.Editor.Razor
{
[System.Composition.Shared]
[Export(typeof(VisualStudioRazorParserFactory))]
internal class DefaultVisualStudioRazorParserFactory : VisualStudioRazorParserFactory
{
private readonly ForegroundDispatcher _dispatcher;
private readonly TemplateEngineFactoryService _templateEngineFactoryService;
private readonly ICompletionBroker _completionBroker;
private readonly RazorTemplateEngineFactoryService _templateEngineFactoryService;
private readonly VisualStudioCompletionBroker _completionBroker;
private readonly ErrorReporter _errorReporter;
[ImportingConstructor]
public DefaultVisualStudioRazorParserFactory(
ICompletionBroker completionBroker,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
ForegroundDispatcher dispatcher,
ErrorReporter errorReporter,
VisualStudioCompletionBroker completionBroker,
RazorTemplateEngineFactoryService templateEngineFactoryService)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
if (errorReporter == null)
{
throw new ArgumentNullException(nameof(errorReporter));
}
if (completionBroker == null)
{
throw new ArgumentNullException(nameof(completionBroker));
}
if (workspace == null)
if (templateEngineFactoryService == null)
{
throw new ArgumentNullException(nameof(workspace));
throw new ArgumentNullException(nameof(templateEngineFactoryService));
}
_dispatcher = dispatcher;
_errorReporter = errorReporter;
_completionBroker = completionBroker;
_dispatcher = workspace.Services.GetRequiredService<ForegroundDispatcher>();
_errorReporter = workspace.Services.GetRequiredService<ErrorReporter>();
var razorLanguageServices = workspace.Services.GetLanguageServices(RazorLanguage.Name);
_templateEngineFactoryService = razorLanguageServices.GetRequiredService<TemplateEngineFactoryService>();
_templateEngineFactoryService = templateEngineFactoryService;
}
public override VisualStudioRazorParser Create(VisualStudioDocumentTracker documentTracker)

View File

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.VisualStudio.Editor.Razor
{
[Shared]
[ExportLanguageServiceFactory(typeof(VisualStudioRazorParserFactory), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultVisualStudioRazorParserFactoryFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
var workspaceServices = languageServices.WorkspaceServices;
var dispatcher = workspaceServices.GetRequiredService<ForegroundDispatcher>();
var errorReporter = workspaceServices.GetRequiredService<ErrorReporter>();
var completionBroker = languageServices.GetRequiredService<VisualStudioCompletionBroker>();
var templateEngineFactoryService = languageServices.GetRequiredService<RazorTemplateEngineFactoryService>();
return new DefaultVisualStudioRazorParserFactory(
dispatcher,
errorReporter,
completionBroker,
templateEngineFactoryService);
}
}
}

View File

@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="$(VSIX_MicrosoftCodeAnalysisCSharpFeaturesPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.EditorFeatures.Text" Version="$(VSIX_MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Language.Intellisense" Version="$(MicrosoftVisualStudioLanguageIntellisensePackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Text.UI" Version="$(MicrosoftVisualStudioTextUIPackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal abstract class VisualStudioCompletionBroker : ILanguageService
{
public abstract bool IsCompletionActive(ITextView textView);
}
}

View File

@ -1,9 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal abstract class VisualStudioRazorParserFactory
internal abstract class VisualStudioRazorParserFactory : ILanguageService
{
public abstract VisualStudioRazorParser Create(VisualStudioDocumentTracker documentTracker);
}

View File

@ -23,7 +23,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
[ImportingConstructor]
public DefaultRazorEditorFactoryService(
VisualStudioDocumentTrackerFactory documentTrackerFactory,
VisualStudioRazorParserFactory parserFactory,
VisualStudioWorkspaceAccessor workspaceAccessor)
{
if (documentTrackerFactory == null)
@ -31,20 +30,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
throw new ArgumentNullException(nameof(documentTrackerFactory));
}
if (parserFactory == null)
{
throw new ArgumentNullException(nameof(parserFactory));
}
if (workspaceAccessor == null)
{
throw new ArgumentNullException(nameof(workspaceAccessor));
}
_documentTrackerFactory = documentTrackerFactory;
_parserFactory = parserFactory;
var razorLanguageServices = workspaceAccessor.Workspace.Services.GetLanguageServices(RazorLanguage.Name);
_parserFactory = razorLanguageServices.GetRequiredService<VisualStudioRazorParserFactory>();
_braceSmartIndenterFactory = razorLanguageServices.GetRequiredService<BraceSmartIndenterFactory>();
}

View File

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
{
internal class DefaultVisualStudioCompletionBroker : VisualStudioCompletionBroker
{
private readonly ICompletionBroker _completionBroker;
public DefaultVisualStudioCompletionBroker(ICompletionBroker completionBroker)
{
if (completionBroker == null)
{
throw new ArgumentNullException(nameof(completionBroker));
}
_completionBroker = completionBroker;
}
public override bool IsCompletionActive(ITextView textView)
{
if (textView == null)
{
throw new ArgumentNullException(nameof(textView));
}
var completionIsActive = _completionBroker.IsCompletionActive(textView);
return completionIsActive;
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
{
[Shared]
[ExportLanguageServiceFactory(typeof(VisualStudioCompletionBroker), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultVisualStudioCompletionBrokerFactory : ILanguageServiceFactory
{
private readonly ICompletionBroker _completionBroker;
[ImportingConstructor]
public DefaultVisualStudioCompletionBrokerFactory(ICompletionBroker completionBroker)
{
if (completionBroker == null)
{
throw new ArgumentNullException(nameof(completionBroker));
}
_completionBroker = completionBroker;
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultVisualStudioCompletionBroker(_completionBroker);
}
}
}

View File

@ -23,6 +23,7 @@
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.8.0" Version="$(MicrosoftVisualStudioShellInterop80PackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.9.0" Version="$(MicrosoftVisualStudioShellInterop90PackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="$(MicrosoftVisualStudioShellInteropPackageVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Language.Intellisense" Version="$(MicrosoftVisualStudioLanguageIntellisensePackageVersion)" />
<!-- We need to use this version of Json.Net to maintain consistency with Visual Studio. -->
<PackageReference Include="Newtonsoft.Json" Version="$(VisualStudio_NewtonsoftJsonPackageVersion)" />
</ItemGroup>

View File

@ -0,0 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Text.Editor;
using MonoDevelop.Ide.CodeCompletion;
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.Editor
{
internal class DefaultVisualStudioCompletionBroker : VisualStudioCompletionBroker
{
public override bool IsCompletionActive(ITextView textView)
{
if (textView == null)
{
throw new ArgumentNullException(nameof(textView));
}
if (textView.HasAggregateFocus)
{
return CompletionWindowManager.IsVisible;
}
// Text view does not have focus, if the completion window is visible it's for a different text view.
return false;
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor;
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor.Editor
{
[Shared]
[ExportLanguageServiceFactory(typeof(VisualStudioCompletionBroker), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultVisualStudioCompletionBrokerFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultVisualStudioCompletionBroker();
}
}
}

View File

@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Test;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
@ -711,37 +710,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
}
}
private class TestCompletionBroker : ICompletionBroker
private class TestCompletionBroker : VisualStudioCompletionBroker
{
public ICompletionSession CreateCompletionSession(ITextView textView, ITrackingPoint triggerPoint, bool trackCaret)
{
throw new NotImplementedException();
}
public void DismissAllSessions(ITextView textView)
{
throw new NotImplementedException();
}
public ReadOnlyCollection<ICompletionSession> GetSessions(ITextView textView)
{
throw new NotImplementedException();
}
public bool IsCompletionActive(ITextView textView)
{
return false;
}
public ICompletionSession TriggerCompletion(ITextView textView)
{
throw new NotImplementedException();
}
public ICompletionSession TriggerCompletion(ITextView textView, ITrackingPoint triggerPoint, bool trackCaret)
{
throw new NotImplementedException();
}
public override bool IsCompletionActive(ITextView textView) => false;
}
}
}

View File

@ -2,11 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Test;
using Microsoft.VisualStudio.Text;
using Moq;
@ -36,7 +34,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
// Act & Assert
@ -52,7 +50,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
// Act & Assert
@ -68,7 +66,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>());
Mock.Of<VisualStudioCompletionBroker>());
parser.Dispose();
// Act & Assert
@ -84,7 +82,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
@ -112,7 +110,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
documentTracker,
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
var called = false;
parser.DocumentStructureChanged += (sender, e) => called = true;
@ -141,7 +139,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>())
Mock.Of<VisualStudioCompletionBroker>())
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
IdleDelay = TimeSpan.FromSeconds(5)
@ -171,7 +169,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>())
Mock.Of<VisualStudioCompletionBroker>())
{
BlockBackgroundIdleWork = new ManualResetEventSlim(),
IdleDelay = TimeSpan.FromSeconds(5)
@ -200,7 +198,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
parser.StartParser();
@ -224,7 +222,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
documentTracker,
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
// Act
parser.StartParser();
@ -244,7 +242,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(isSupportedProject: true),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
// Act
var result = parser.TryReinitializeParser();
@ -263,7 +261,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
CreateDocumentTracker(isSupportedProject: false),
Mock.Of<RazorTemplateEngineFactoryService>(),
new DefaultErrorReporter(),
Mock.Of<ICompletionBroker>()))
Mock.Of<VisualStudioCompletionBroker>()))
{
// Act
var result = parser.TryReinitializeParser();