Added a LiveShareWorkspaceProvider to enable location of the remote workspace in live share scenarios.
- MEF is the primary means of resolving the new live share provider therefore we allow it to not be registered. - The new contract is in the Editor.Razor binary so the LiveShare bits don't have to take the dependency on the windows binary in Razor (has a lot of baggage). - This is specific to live share but providing a generic way to resolve workspaces didn't seem reasonable given the varying expectations in VS4Mac. If we need to make a more generic solution in the future we'll revisit this; for now this is a straight forward inclusion of live share functionality. - Added tests to validate the new behavior. - This unblocks the live share scenario of resolving the remote workspace. We can't rely on the projection buffers to provide the correct workspace because that workspace is wired up too late in the process of opening a Razor file. #2335
This commit is contained in:
parent
1d5245c421
commit
e0e1c39cce
|
|
@ -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;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
internal abstract class LiveShareWorkspaceProvider
|
||||
{
|
||||
public abstract bool TryGetWorkspace(ITextBuffer textBuffer, out Workspace workspace);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,12 +19,14 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
private readonly IBufferGraphFactoryService _bufferGraphService;
|
||||
private readonly TextBufferProjectService _projectService;
|
||||
private readonly Workspace _defaultWorkspace;
|
||||
private readonly LiveShareWorkspaceProvider _liveShareWorkspaceProvider;
|
||||
|
||||
[ImportingConstructor]
|
||||
public DefaultVisualStudioWorkspaceAccessor(
|
||||
IBufferGraphFactoryService bufferGraphService,
|
||||
TextBufferProjectService projectService,
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace defaultWorkspace)
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace defaultWorkspace,
|
||||
[Import(typeof(LiveShareWorkspaceProvider), AllowDefault = true)] LiveShareWorkspaceProvider liveShareWorkspaceProvider)
|
||||
{
|
||||
if (bufferGraphService == null)
|
||||
{
|
||||
|
|
@ -44,6 +46,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
_bufferGraphService = bufferGraphService;
|
||||
_projectService = projectService;
|
||||
_defaultWorkspace = defaultWorkspace;
|
||||
_liveShareWorkspaceProvider = liveShareWorkspaceProvider;
|
||||
}
|
||||
|
||||
public override bool TryGetWorkspace(ITextBuffer textBuffer, out Workspace workspace)
|
||||
|
|
@ -56,12 +59,18 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
// We do a best effort approach in this method to get the workspace that belongs to the TextBuffer.
|
||||
// The approaches we take to find the workspace are:
|
||||
//
|
||||
// 1. Look for a C# projection buffer associated with the Razor buffer. If we can find one we let
|
||||
// 1. If we have a live share workspace provider, ask it for the workspace.
|
||||
// 2. Look for a C# projection buffer associated with the Razor buffer. If we can find one we let
|
||||
// Roslyn take control of finding the Workspace (projectionBuffer.GetWorkspace()). If not,
|
||||
// fall back to determining if we can use the default workspace.
|
||||
// 2. Look to see if this ITextBuffer is associated with a host project. If we find that our Razor
|
||||
// 3. Look to see if this ITextBuffer is associated with a host project. If we find that our Razor
|
||||
// buffer has a host project, we make the assumption that we should use the default VisualStudioWorkspace.
|
||||
|
||||
if (TryGetWorkspaceFromLiveShare(textBuffer, out workspace))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryGetWorkspaceFromProjectionBuffer(textBuffer, out workspace))
|
||||
{
|
||||
return true;
|
||||
|
|
@ -76,6 +85,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
return false;
|
||||
}
|
||||
|
||||
// Internal for testing
|
||||
internal bool TryGetWorkspaceFromLiveShare(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
if (_liveShareWorkspaceProvider != null &&
|
||||
_liveShareWorkspaceProvider.TryGetWorkspace(textBuffer, out workspace))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Internal virtual for testing
|
||||
internal virtual bool TryGetWorkspaceFromProjectionBuffer(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,27 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
{
|
||||
public class DefaultVisualStudioWorkspaceAccessorTest
|
||||
{
|
||||
private static readonly LiveShareWorkspaceProvider NoLiveShare = null;
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspace_PrioritizesLiveShareWhenResolvingWorkspaces()
|
||||
{
|
||||
// Arrange
|
||||
var expectedWorkspace = TestWorkspace.Create();
|
||||
var liveShareWorkspaceProvider = new Mock<LiveShareWorkspaceProvider>();
|
||||
liveShareWorkspaceProvider.Setup(provider => provider.TryGetWorkspace(It.IsAny<ITextBuffer>(), out expectedWorkspace))
|
||||
.Returns(true);
|
||||
var workspaceAccessor = new TestWorkspaceAccessor(canGetWorkspaceFromProjectionBuffer: true, canGetWorkspaceFromHostProject: true, liveShareWorkspaceProvider.Object);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspace(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(expectedWorkspace, workspace);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspace_CanGetWorkspaceFromProjectionBuffersOnly()
|
||||
{
|
||||
|
|
@ -56,6 +77,57 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromLiveShare_NoLiveShareProvider_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create(), NoLiveShare);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromLiveShare(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromLiveShare_CanNotFindWorkspace_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
Workspace nullWorkspace = null;
|
||||
var liveShareWorkspaceProvider = new Mock<LiveShareWorkspaceProvider>();
|
||||
liveShareWorkspaceProvider.Setup(provider => provider.TryGetWorkspace(It.IsAny<ITextBuffer>(), out nullWorkspace))
|
||||
.Returns(false);
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create(), liveShareWorkspaceProvider.Object);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromLiveShare(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromLiveShare_CanFindWorkspace_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var expectedWorkspace = TestWorkspace.Create();
|
||||
var liveShareWorkspaceProvider = new Mock<LiveShareWorkspaceProvider>();
|
||||
liveShareWorkspaceProvider.Setup(provider => provider.TryGetWorkspace(It.IsAny<ITextBuffer>(), out expectedWorkspace))
|
||||
.Returns(true);
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create(), liveShareWorkspaceProvider.Object);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromLiveShare(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(expectedWorkspace, workspace);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromProjectionBuffer_NoProjectionBuffer_ReturnsFalse()
|
||||
{
|
||||
|
|
@ -66,7 +138,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
var bufferGraphService = new Mock<IBufferGraphFactoryService>();
|
||||
bufferGraphService.Setup(service => service.CreateBufferGraph(It.IsAny<ITextBuffer>()))
|
||||
.Returns(bufferGraph.Object);
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(bufferGraphService.Object, Mock.Of<TextBufferProjectService>(), TestWorkspace.Create());
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(bufferGraphService.Object, Mock.Of<TextBufferProjectService>(), TestWorkspace.Create(), NoLiveShare);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
|
|
@ -80,7 +152,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
public void TryGetWorkspaceFromHostProject_NoHostProject_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create());
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create(), NoLiveShare);
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
|
|
@ -97,7 +169,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
var projectService = Mock.Of<TextBufferProjectService>(service => service.GetHostProject(textBuffer) == new object());
|
||||
var defaultWorkspace = TestWorkspace.Create();
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), projectService, defaultWorkspace);
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), projectService, defaultWorkspace, NoLiveShare);
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromHostProject(textBuffer, out var workspace);
|
||||
|
|
@ -113,10 +185,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
private readonly bool _canGetWorkspaceFromHostProject;
|
||||
|
||||
internal TestWorkspaceAccessor(bool canGetWorkspaceFromProjectionBuffer, bool canGetWorkspaceFromHostProject) :
|
||||
this(canGetWorkspaceFromProjectionBuffer, canGetWorkspaceFromHostProject, NoLiveShare)
|
||||
{
|
||||
}
|
||||
|
||||
internal TestWorkspaceAccessor(
|
||||
bool canGetWorkspaceFromProjectionBuffer,
|
||||
bool canGetWorkspaceFromHostProject,
|
||||
LiveShareWorkspaceProvider liveShareWorkspaceProvider) :
|
||||
base(
|
||||
Mock.Of<IBufferGraphFactoryService>(),
|
||||
Mock.Of<TextBufferProjectService>(),
|
||||
TestWorkspace.Create())
|
||||
TestWorkspace.Create(),
|
||||
liveShareWorkspaceProvider)
|
||||
{
|
||||
_canGetWorkspaceFromProjectionBuffer = canGetWorkspaceFromProjectionBuffer;
|
||||
_canGetWorkspaceFromHostProject = canGetWorkspaceFromHostProject;
|
||||
|
|
@ -147,4 +228,4 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue