提交 81082a4a 编写于 作者: D David Barbet

Move remote workspace from liveshare into Roslyn.

上级 07925a72
......@@ -110,12 +110,11 @@
<MicrosoftVisualStudioLanguageCallHierarchyVersion>15.8.27812-alpha</MicrosoftVisualStudioLanguageCallHierarchyVersion>
<MicrosoftVisualStudioLanguageIntellisenseVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioLanguageIntellisenseVersion>
<MicrosoftVisualStudioLanguageNavigateToInterfacesVersion>16.0.467</MicrosoftVisualStudioLanguageNavigateToInterfacesVersion>
<MicrosoftVisualStudioLanguageServerProtocolVersion>16.2.1072</MicrosoftVisualStudioLanguageServerProtocolVersion>
<MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>16.2.1072</MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>
<MicrosoftVisualStudioLiveShareLanguageServicesVersion>1.0.181</MicrosoftVisualStudioLiveShareLanguageServicesVersion>
<MicrosoftVisualStudioLanguageStandardClassificationVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioLanguageStandardClassificationVersion>
<MicrosoftVisualStudioLanguageServerProtocolVersion>16.2.1078</MicrosoftVisualStudioLanguageServerProtocolVersion>
<MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>16.2.1078</MicrosoftVisualStudioLanguageServerProtocolExtensionsVersion>
<MicrosoftVisualStudioLanguageStandardClassificationVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioLanguageStandardClassificationVersion>
<MicrosoftVisualStudioLiveShareLanguageServicesVersion>1.0.181</MicrosoftVisualStudioLiveShareLanguageServicesVersion>
<MicrosoftVisualStudioLiveShareWebEditorsVersion>2.2.0-preview1-t001</MicrosoftVisualStudioLiveShareWebEditorsVersion>
<MicrosoftVisualStudioOLEInteropVersion>7.10.6071</MicrosoftVisualStudioOLEInteropVersion>
<MicrosoftVisualStudioPlatformVSEditorVersion>$(VisualStudioEditorPackagesVersion)</MicrosoftVisualStudioPlatformVSEditorVersion>
<MicrosoftVisualStudioProgressionCodeSchemaVersion>15.8.27812-alpha</MicrosoftVisualStudioProgressionCodeSchemaVersion>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging
{
[ExportContentTypeLanguageService(StringConstants.CSharpLspContentTypeName, StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspContentTypeLanguageService : IContentTypeLanguageService
{
private readonly IContentTypeRegistryService _contentTypeRegistry;
[ImportingConstructor]
public CSharpLspContentTypeLanguageService(IContentTypeRegistryService contentTypeRegistry)
{
_contentTypeRegistry = contentTypeRegistry;
}
public IContentType GetDefaultContentType()
{
return _contentTypeRegistry.GetContentType(StringConstants.CSharpLspLanguageName);
}
}
}
// Copyright (c) Microsoft. 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.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using TextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging
{
/// <summary>
/// CSharp's LSP Debugger Intellisense context
/// Used for intellisense completions in Watch and Immediate Window.
/// Similar to Roslyn's CSharp debugger intellisense context:
/// \src\VisualStudio\CSharp\Impl\LanguageService\CSharpDebuggerIntelliSenseContext.cs
/// </summary>
internal class CSharpLspDebuggerIntelliSenseContext : AbstractDebuggerIntelliSenseContext
{
public CSharpLspDebuggerIntelliSenseContext(
IWpfTextView view,
IVsTextView vsTextView,
IVsTextLines debuggerBuffer,
ITextBuffer contextBuffer,
TextSpan[] currentStatementSpan,
IComponentModel componentModel,
IServiceProvider serviceProvider)
: base(view,
vsTextView,
debuggerBuffer,
contextBuffer,
currentStatementSpan,
componentModel,
serviceProvider,
componentModel.GetService<IContentTypeRegistryService>().GetContentType(StringConstants.CSharpLspContentTypeName))
{
}
protected override int GetAdjustedContextPoint(int contextPoint, Document document)
{
// Determine the position in the buffer at which to end the tracking span representing
// the part of the imaginary buffer before the text in the view.
var tree = document.GetSyntaxTreeSynchronously(CancellationToken.None);
var token = tree.FindTokenOnLeftOfPosition(contextPoint, CancellationToken.None);
// Special case to handle class designer because it asks for debugger IntelliSense using
// spans between members.
if (contextPoint > token.Span.End &&
IsKindOrHasMatchingText(token, SyntaxKind.CloseBraceToken) &&
token.Parent.IsKind(SyntaxKind.Block) &&
token.Parent.Parent is MemberDeclarationSyntax)
{
return contextPoint;
}
if (IsKindOrHasMatchingText(token, SyntaxKind.CloseBraceToken) &&
token.Parent.IsKind(SyntaxKind.Block))
{
return token.SpanStart;
}
return token.FullSpan.End;
}
protected override ITrackingSpan GetPreviousStatementBufferAndSpan(int contextPoint, Document document)
{
var previousTrackingSpan = ContextBuffer.CurrentSnapshot.CreateTrackingSpan(Span.FromBounds(0, contextPoint), SpanTrackingMode.EdgeNegative);
// terminate the previous expression/statement
var buffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(
projectionEditResolver: null,
sourceSpans: new object[] { previousTrackingSpan, StatementTerminator },
options: ProjectionBufferOptions.None,
contentType: ContentType);
return buffer.CurrentSnapshot.CreateTrackingSpan(0, buffer.CurrentSnapshot.Length, SpanTrackingMode.EdgeNegative);
}
public override bool CompletionStartsOnQuestionMark => false;
protected override string StatementTerminator => ";";
private static bool IsKindOrHasMatchingText(SyntaxToken token, SyntaxKind kind) =>
token.Kind() == kind || token.ToString() == SyntaxFacts.GetText(kind);
}
}
// Copyright (c) Microsoft. 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.Runtime.InteropServices;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging
{
[Guid(StringConstants.CSharpLspLanguageServiceGuidString)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders")]
internal class CSharpLspLanguageService : AbstractLanguageService<CSharpLspPackage, CSharpLspLanguageService>
{
public static Guid LanguageServiceGuid { get; } = new Guid(StringConstants.CSharpLspLanguageServiceGuidString);
internal CSharpLspLanguageService(CSharpLspPackage package)
: base(package)
{
}
internal IComponentModel ComponentModel => (IComponentModel)SystemServiceProvider.GetService(typeof(SComponentModel));
protected override Guid DebuggerLanguageId { get; } = new Guid(StringConstants.CSharpLspDebuggerLanguageGuidString);
public override Guid LanguageServiceId { get; } = new Guid(StringConstants.CSharpLspLanguageServiceGuidString);
protected override string ContentTypeName => StringConstants.CSharpLspContentTypeName;
protected override string LanguageName => StringConstants.CSharpLspLanguageName;
protected override string RoslynLanguageName => StringConstants.CSharpLspLanguageName;
public static CSharpLspLanguageService FromServiceProvider(IServiceProvider serviceProvider) =>
VisualStudio.LanguageServices.Implementation.Interop.ComAggregate.GetManagedObject<CSharpLspLanguageService>(serviceProvider.GetService(typeof(CSharpLspLanguageService)));
protected override AbstractDebuggerIntelliSenseContext CreateContext(
IWpfTextView view,
IVsTextView vsTextView,
IVsTextLines debuggerBuffer,
ITextBuffer subjectBuffer,
TextSpan[] currentStatementSpan)
{
return new CSharpLspDebuggerIntelliSenseContext(view,
vsTextView,
debuggerBuffer,
subjectBuffer,
currentStatementSpan,
Package.ComponentModel,
SystemServiceProvider);
}
}
}
// Copyright (c) Microsoft. 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.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging
{
[Guid(StringConstants.CSharpLspPackageGuidString)]
[ProvideLanguageService(StringConstants.CSharpLspLanguageServiceGuidString, StringConstants.CSharpLspLanguageName, 101,
RequestStockColors = true, ShowDropDownOptions = true, ShowCompletion = true, EnableAdvancedMembersOption = true, ShowSmartIndent = true, DefaultToInsertSpaces = true)]
[ProvideService(typeof(CSharpLspLanguageService))]
internal class CSharpLspPackage : AbstractPackage<CSharpLspPackage, CSharpLspLanguageService>
{
protected override VisualStudioWorkspaceImpl CreateWorkspace() => ComponentModel.GetService<VisualStudioWorkspaceImpl>();
protected override string RoslynLanguageName => StringConstants.CSharpLspLanguageName;
protected override IEnumerable<IVsEditorFactory> CreateEditorFactories()
{
return new IVsEditorFactory[] { };
}
protected override CSharpLspLanguageService CreateLanguageService() => new CSharpLspLanguageService(this);
protected override void RegisterMiscellaneousFilesWorkspaceInformation(MiscellaneousFilesWorkspace miscellaneousFilesWorkspace)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging
{
[ExportContentTypeLanguageService(StringConstants.VBLspContentTypeName, StringConstants.VBLspLanguageName), Shared]
internal class VBLspContentTypeLanguageService : IContentTypeLanguageService
{
private readonly IContentTypeRegistryService _contentTypeRegistry;
[ImportingConstructor]
public VBLspContentTypeLanguageService(IContentTypeRegistryService contentTypeRegistry)
{
_contentTypeRegistry = contentTypeRegistry;
}
public IContentType GetDefaultContentType()
{
return _contentTypeRegistry.GetContentType(StringConstants.VBLspContentTypeName);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
/*using System.Composition;
using System.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.GotoDefinition
internal class CSharpLspGotoDefinitionService : RoslynGotoDefinitionService
{
[ImportingConstructor]
public CSharpLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, RoslynLSPClientServiceFactory roslynLspClientServiceFactory,
public CSharpLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, RoslynLspClientServiceFactory roslynLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace, IThreadingContext threadingContext)
: base(streamingPresenter, roslynLspClientServiceFactory, remoteWorkspace, threadingContext) { }
}
......@@ -22,8 +22,8 @@ internal class CSharpLspGotoDefinitionService : RoslynGotoDefinitionService
internal class VBLspGotoDefinitionService : RoslynGotoDefinitionService
{
[ImportingConstructor]
public VBLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, RoslynLSPClientServiceFactory roslynLspClientServiceFactory,
public VBLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, RoslynLspClientServiceFactory roslynLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace, IThreadingContext threadingContext)
: base(streamingPresenter, roslynLspClientServiceFactory, remoteWorkspace, threadingContext) { }
}
}*/
}
// Copyright (c) Microsoft. 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
......@@ -13,7 +12,6 @@
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.VisualStudio.Shell;
using Newtonsoft.Json.Linq;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
using TPL = System.Threading.Tasks;
......@@ -23,19 +21,20 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.GotoDefinition
internal class RoslynGotoDefinitionService : IGoToDefinitionService
{
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
private readonly RoslynLSPClientServiceFactory _roslynLspClientServiceFactory;
private readonly RoslynLspClientServiceFactory _roslynLspClientServiceFactory;
private readonly RemoteLanguageServiceWorkspace _remoteWorkspace;
private readonly IThreadingContext _threadingContext;
public RoslynGotoDefinitionService(
IStreamingFindUsagesPresenter streamingPresenter,
RoslynLSPClientServiceFactory roslynLspClientServiceFactory,
RoslynLspClientServiceFactory roslynLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace,
IThreadingContext threadingContext)
{
_streamingPresenter = streamingPresenter ?? throw new ArgumentNullException(nameof(streamingPresenter));
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
_remoteWorkspace = remoteWorkspace ?? throw new ArgumentNullException(nameof(remoteWorkspace));
_threadingContext = threadingContext ?? throw new ArgumentNullException(nameof(threadingContext));
}
public async TPL.Task<IEnumerable<INavigableItem>> FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken)
......@@ -107,7 +106,7 @@ private async TPL.Task<ImmutableArray<DefinitionItem>> GetDefinitionItemsAsync(D
}
else
{
documentSpan = await location.ToDocumentSpanAsync(_remoteWorkspace, cancellationToken).ConfigureAwait(false);
documentSpan = await _remoteWorkspace.GetDocumentSpanFromLocation(location, cancellationToken).ConfigureAwait(false);
if (documentSpan == null)
{
continue;
......@@ -120,4 +119,4 @@ private async TPL.Task<ImmutableArray<DefinitionItem>> GetDefinitionItemsAsync(D
return definitionItems.ToImmutable();
}
}
}*/
}
......@@ -36,9 +36,13 @@
<ProjectReference Include="..\..\..\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="$(MicrosoftVisualStudioComponentModelHostVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Editor" Version="$(MicrosoftVisualStudioEditorVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Imaging" Version="$(MicrosoftVisualStudioImagingVersion)" />
<PackageReference Include="Microsoft.VisualStudio.LiveShare.LanguageServices" Version="$(MicrosoftVisualStudioLiveShareLanguageServicesVersion)" />
<PackageReference Include="Microsoft.VisualStudio.LiveShare.WebEditors" Version="$(MicrosoftVisualStudioLiveShareWebEditorsVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="$(MicrosoftVisualStudioShell150Version)" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Framework" Version="$(MicrosoftVisualStudioShellFrameworkVersion)" />
<PackageReference Include="StreamJsonRpc" Version="$(StreamJsonRpcVersion)" />
</ItemGroup>
......
// Copyright (c) Microsoft. 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.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Projects
{
/// <summary>
/// Discovers project information for remote directories
/// </summary>
[Export(typeof(RemoteProjectInfoProvider))]
internal class RemoteProjectInfoProvider
{
private readonly IEnumerable<IRemoteProjectInfoProvider> _remoteProjectInfoProviders;
[ImportingConstructor]
public RemoteProjectInfoProvider([ImportMany] IEnumerable<IRemoteProjectInfoProvider> remoteProjectInfoProviders)
{
_remoteProjectInfoProviders = remoteProjectInfoProviders ?? throw new ArgumentNullException(nameof(remoteProjectInfoProviders));
}
public async Task<IReadOnlyCollection<ProjectInfo>> GetRemoteProjectInfosAsync(CancellationToken cancellationToken)
{
var projectInfos = new List<ProjectInfo>();
foreach (var remoteProjectInfoProvider in _remoteProjectInfoProviders)
{
try
{
foreach (var projectInfo in await remoteProjectInfoProvider.GetRemoteProjectInfosAsync(cancellationToken).ConfigureAwait(false))
{
projectInfos.Add(projectInfo);
}
}
catch (Exception)
{
// Continue with the other providers even if one of them fails.
continue;
}
}
return projectInfos;
}
public static ProjectInfo CreateProjectInfo(string projectName, string language, ImmutableArray<string> files)
{
var projectId = ProjectId.CreateNewId();
var docInfos = ImmutableArray.CreateBuilder<DocumentInfo>();
foreach (string file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file);
var docInfo = DocumentInfo.Create(DocumentId.CreateNewId(projectId),
fileName,
filePath: file,
loader: new FileTextLoaderNoException(file, null));
docInfos.Add(docInfo);
}
return ProjectInfo.Create(
projectId,
VersionStamp.Create(),
projectName,
projectName,
language,
documents: docInfos.ToImmutable());
}
}
}
......@@ -12,27 +12,27 @@
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Projects
{
//[Export(typeof(IRemoteProjectInfoProvider))]
[Export(typeof(IRemoteProjectInfoProvider))]
internal class RoslynRemoteProjectInfoProvider : IRemoteProjectInfoProvider
{
private const string SystemUriSchemeExternal = "vslsexternal";
private readonly RoslynLspClientServiceFactory _roslynLspClientServiceFactory;
//private readonly IVsRemoteWorkspaceManager _remoteWorkspaceManager;
private readonly RemoteLanguageServiceWorkspace _remoteLanguageServiceWorkspace;
[ImportingConstructor]
public RoslynRemoteProjectInfoProvider(RoslynLspClientServiceFactory roslynLspClientServiceFactory)//, IVsRemoteWorkspaceManager remoteWorkspaceManager)
public RoslynRemoteProjectInfoProvider(RoslynLspClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
//_remoteWorkspaceManager = remoteWorkspaceManager ?? throw new ArgumentNullException(nameof(remoteWorkspaceManager));
_remoteLanguageServiceWorkspace = remoteLanguageServiceWorkspace ?? throw new ArgumentNullException(nameof(RemoteLanguageServiceWorkspace));
}
public async Task<ImmutableArray<ProjectInfo>> GetRemoteProjectInfosAsync(CancellationToken cancellationToken)
{
/*if (!_remoteWorkspaceManager.IsRemoteSession)
if (!_remoteLanguageServiceWorkspace.IsRemoteSession)
{
return ImmutableArray<ProjectInfo>.Empty;
}*/
}
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
......
// Copyright (c) Microsoft. 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.ComponentModel.Composition;
using Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Debugging;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.Venus;
using Microsoft.VisualStudio.LiveShare.WebEditors.ContainedLanguage;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Razor
{
[Export(typeof(IContainedLanguageProvider))]
internal class CSharpLspContainedLanguageProvider : IContainedLanguageProvider
{
private readonly IContentTypeRegistryService _contentTypeRegistry;
private readonly SVsServiceProvider _serviceProvider;
private readonly RemoteLanguageServiceWorkspace _remoteLanguageServiceWorkspace;
private readonly CSharpLspRazorProject _razorProject;
[ImportingConstructor]
public CSharpLspContainedLanguageProvider(IContentTypeRegistryService contentTypeRegistry,
SVsServiceProvider serviceProvider,
CSharpLspRazorProject razorProject,
RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
{
_contentTypeRegistry = contentTypeRegistry ?? throw new ArgumentNullException(nameof(contentTypeRegistry));
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_razorProject = razorProject ?? throw new ArgumentNullException(nameof(razorProject));
_remoteLanguageServiceWorkspace = remoteLanguageServiceWorkspace ?? throw new ArgumentNullException(nameof(remoteLanguageServiceWorkspace));
}
public IContentType GetContentType(string filePath)
{
return _contentTypeRegistry.GetContentType(StringConstants.CSharpLspContentTypeName);
}
public IVsContainedLanguage GetLanguage(string filePath, IVsTextBufferCoordinator bufferCoordinator)
{
var componentModel = _serviceProvider.GetService(typeof(SComponentModel)) as IComponentModel;
var project = _razorProject.GetProject(filePath);
var languageService = CSharpLspLanguageService.FromServiceProvider(_serviceProvider);
#pragma warning disable CS0618 // Type or member is obsolete - this is liveshare.
return new ContainedLanguage<CSharpLspPackage, CSharpLspLanguageService>(bufferCoordinator,
componentModel,
project,
new RazorProjectHierarchy(filePath),
(uint)VSConstants.VSITEMID.Nil,
languageService,
CodeAnalysis.SourceCodeKind.Regular,
vbHelperFormattingRule: null,
workspace: _remoteLanguageServiceWorkspace);
#pragma warning restore CS0618 // Type or member is obsolete - this is liveshare.
}
}
}
// Copyright (c) Microsoft. 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.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TextManager.Interop;
using System.Linq;
using System;
using System.ComponentModel.Composition;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Razor
{
[Export]
internal class CSharpLspRazorProject
{
private readonly SVsServiceProvider _serviceProvider;
private readonly RemoteLanguageServiceWorkspaceHost _remoteLanguageServiceWorkspaceHost;
#pragma warning disable CS0618 // Type or member is obsolete - used for liveshare.
public AbstractProject GetProject(string projectName)
{
var projectTracker = _remoteLanguageServiceWorkspaceHost.ProjectTracker;
var project = projectTracker.ImmutableProjects.FirstOrDefault(p => p.ProjectSystemName == projectName);
if (project != null)
{
return project;
}
project = new CSharpLspProject(projectTracker, null, projectName, projectName, null, StringConstants.CSharpLspLanguageName, Guid.NewGuid(), _serviceProvider, null, null);
projectTracker.AddProject(project);
return project;
}
#pragma warning restore CS0618 // Type or member is obsolete - used for liveshare.
[ImportingConstructor]
public CSharpLspRazorProject(SVsServiceProvider serviceProvider, RemoteLanguageServiceWorkspaceHost remoteLanguageServiceWorkspaceHost)
{
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_remoteLanguageServiceWorkspaceHost = remoteLanguageServiceWorkspaceHost ?? throw new ArgumentNullException(nameof(remoteLanguageServiceWorkspaceHost));
}
}
#pragma warning disable CS0618 // Type or member is obsolete
internal class CSharpLspProject : AbstractProject
#pragma warning restore CS0618 // Type or member is obsolete
{
public CSharpLspProject(VisualStudioProjectTracker projectTracker,
Func<ProjectId, IVsReportExternalErrors> reportExternalErrorCreatorOpt,
string projectSystemName,
string projectFilePath,
IVsHierarchy hierarchy,
string language,
Guid projectGuid,
IServiceProvider serviceProvider,
VisualStudioWorkspaceImpl visualStudioWorkspaceOpt,
HostDiagnosticUpdateSource hostDiagnosticUpdateSourceOpt,
ICommandLineParserService commandLineParserServiceOpt = null)
: base(projectTracker, reportExternalErrorCreatorOpt, projectSystemName, projectFilePath, hierarchy, language, projectGuid, serviceProvider, visualStudioWorkspaceOpt, hostDiagnosticUpdateSourceOpt, commandLineParserServiceOpt)
{
}
}
}
// Copyright (c) Microsoft. 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;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Razor
{
class RazorProjectHierarchy : IVsHierarchy, IVsProject
{
private readonly string filePath;
public RazorProjectHierarchy(string filePath)
{
this.filePath = filePath ?? throw new ArgumentNullException(nameof(filePath));
}
public int GetMkDocument(uint itemid, out string pbstrMkDocument)
{
pbstrMkDocument = this.filePath;
return VSConstants.S_OK;
}
public int GetProperty(uint itemid, int propid, out object pvar)
{
pvar = null;
return VSConstants.S_FALSE;
}
public int SetSite(VisualStudio.OLE.Interop.IServiceProvider psp)
{
throw new NotImplementedException();
}
public int GetSite(out VisualStudio.OLE.Interop.IServiceProvider ppSP)
{
throw new NotImplementedException();
}
public int QueryClose(out int pfCanClose)
{
throw new NotImplementedException();
}
public int Close()
{
throw new NotImplementedException();
}
public int GetGuidProperty(uint itemid, int propid, out Guid pguid)
{
throw new NotImplementedException();
}
public int SetGuidProperty(uint itemid, int propid, ref Guid rguid)
{
throw new NotImplementedException();
}
public int SetProperty(uint itemid, int propid, object var)
{
throw new NotImplementedException();
}
public int GetNestedHierarchy(uint itemid, ref Guid iidHierarchyNested, out IntPtr ppHierarchyNested, out uint pitemidNested)
{
throw new NotImplementedException();
}
public int GetCanonicalName(uint itemid, out string pbstrName)
{
throw new NotImplementedException();
}
public int ParseCanonicalName(string pszName, out uint pitemid)
{
throw new NotImplementedException();
}
public int Unused0()
{
throw new NotImplementedException();
}
public int AdviseHierarchyEvents(IVsHierarchyEvents pEventSink, out uint pdwCookie)
{
throw new NotImplementedException();
}
public int UnadviseHierarchyEvents(uint dwCookie)
{
throw new NotImplementedException();
}
public int Unused1()
{
throw new NotImplementedException();
}
public int Unused2()
{
throw new NotImplementedException();
}
public int Unused3()
{
throw new NotImplementedException();
}
public int Unused4()
{
throw new NotImplementedException();
}
public int IsDocumentInProject(string pszMkDocument, out int pfFound, VSDOCUMENTPRIORITY[] pdwPriority, out uint pitemid)
{
throw new NotImplementedException();
}
public int OpenItem(uint itemid, ref Guid rguidLogicalView, IntPtr punkDocDataExisting, out IVsWindowFrame ppWindowFrame)
{
throw new NotImplementedException();
}
public int GetItemContext(uint itemid, out VisualStudio.OLE.Interop.IServiceProvider ppSP)
{
throw new NotImplementedException();
}
public int GenerateUniqueItemName(uint itemidLoc, string pszExt, string pszSuggestedRoot, out string pbstrItemName)
{
throw new NotImplementedException();
}
public int AddItem(uint itemidLoc, VSADDITEMOPERATION dwAddItemOperation, string pszItemName, uint cFilesToOpen, string[] rgpszFilesToOpen, IntPtr hwndDlgOwner, VSADDRESULT[] pResult)
{
throw new NotImplementedException();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
/*using System.Composition;
using System.Composition;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Host.Mef;
......@@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.References
internal class CSharpLspFindUsagesService : RoslynFindUsagesService
{
[ImportingConstructor]
public CSharpLspFindUsagesService(RoslynLSPClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
public CSharpLspFindUsagesService(RoslynLspClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
: base(roslynLspClientServiceFactory, remoteLanguageServiceWorkspace)
{
}
......@@ -20,9 +20,9 @@ public CSharpLspFindUsagesService(RoslynLSPClientServiceFactory roslynLspClientS
internal class VBLspFindUsagesService : RoslynFindUsagesService
{
[ImportingConstructor]
public VBLspFindUsagesService(RoslynLSPClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
public VBLspFindUsagesService(RoslynLspClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
: base(roslynLspClientServiceFactory, remoteLanguageServiceWorkspace)
{
}
}
}*/
}
// Copyright (c) Microsoft. 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;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServer;
using Newtonsoft.Json.Linq;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
using LiveShareProtocol = Microsoft.VisualStudio.LiveShare.LanguageServices.Protocol;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare.References
{
internal class RoslynFindUsagesService : IFindUsagesService
{
private readonly RoslynLSPClientServiceFactory _roslynLspClientServiceFactory;
private readonly RoslynLspClientServiceFactory _roslynLspClientServiceFactory;
private readonly RemoteLanguageServiceWorkspace _remoteLanguageServiceWorkspace;
public RoslynFindUsagesService(RoslynLSPClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
public RoslynFindUsagesService(RoslynLspClientServiceFactory roslynLspClientServiceFactory, RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
_remoteLanguageServiceWorkspace = remoteLanguageServiceWorkspace ?? throw new ArgumentNullException(nameof(remoteLanguageServiceWorkspace));
......@@ -45,7 +44,7 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
foreach (var location in locations)
{
var documentSpan = await location.ToDocumentSpanAsync(_remoteLanguageServiceWorkspace, context.CancellationToken).ConfigureAwait(false);
var documentSpan = await _remoteLanguageServiceWorkspace.GetDocumentSpanFromLocation(location, context.CancellationToken).ConfigureAwait(false);
if (documentSpan == null)
{
continue;
......@@ -89,14 +88,16 @@ public async Task FindReferencesAsync(Document document, int position, IFindUsag
foreach (var location in locations)
{
var documentSpan = await location.ToDocumentSpanAsync(_remoteLanguageServiceWorkspace, context.CancellationToken).ConfigureAwait(false);
var documentSpan = await _remoteLanguageServiceWorkspace.GetDocumentSpanFromLocation(location, context.CancellationToken).ConfigureAwait(false);
if (documentSpan == null)
{
continue;
}
#pragma warning disable CS0612 // Type or member is obsolete. TODO.
await context.OnReferenceFoundAsync(new SourceReferenceItem(dummyDef, documentSpan.Value, isWrittenTo: false)).ConfigureAwait(false);
#pragma warning restore CS0612 // Type or member is obsolete
}
}
}
}*/
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.TableManager;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare
{
/// <summary>
/// An error list provider that gets diagnostics from the Roslyn diagnostics service.
/// </summary>
[Export]
internal class RemoteDiagnosticListTable : VisualStudioBaseDiagnosticListTable
{
internal const string IdentifierString = nameof(RemoteDiagnosticListTable);
private readonly LiveTableDataSource _source;
private bool _workspaceDiagnosticsPresent = false;
[ImportingConstructor]
public RemoteDiagnosticListTable(
SVsServiceProvider serviceProvider, RemoteLanguageServiceWorkspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
this(workspace, diagnosticService, provider)
{
ConnectWorkspaceEvents();
}
private RemoteDiagnosticListTable(Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider)
: base(workspace, diagnosticService, provider)
{
_source = new LiveTableDataSource(workspace, diagnosticService, IdentifierString);
AddInitialTableSource(workspace.CurrentSolution, _source);
}
public void UpdateWorkspaceDiagnosticsPresent(bool diagnosticsPresent)
{
_workspaceDiagnosticsPresent = diagnosticsPresent;
}
protected override void AddTableSourceIfNecessary(Solution solution)
{
if (solution.ProjectIds.Count == 0 || TableManager.Sources.Any(s => s == _source))
{
return;
}
// If there's no workspace diagnostic service, we should populate the diagnostics table via language services.
// Otherwise, the workspace diagnostic service will handle it.
if (_workspaceDiagnosticsPresent)
{
return;
}
AddTableSource(_source);
}
protected override void RemoveTableSourceIfNecessary(Solution solution)
{
if (solution.ProjectIds.Count > 0 || !TableManager.Sources.Any(s => s == _source))
{
return;
}
TableManager.RemoveSource(_source);
}
protected override void ShutdownSource()
{
_source.Shutdown();
}
}
}
// Copyright (c) Microsoft. 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.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Projects;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LiveShare;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.TableManager;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.TextManager.Interop;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare
{
/// <summary>
/// A Roslyn workspace that contains projects that exist on a remote machine.
/// </summary>
[Export(typeof(RemoteLanguageServiceWorkspace))]
internal sealed class RemoteLanguageServiceWorkspace : Workspace, IDisposable
{
private readonly IServiceProvider _serviceProvider;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly RunningDocumentTable _rdt;
private readonly IThreadingContext _threadingContext;
private const string ExternalProjectName = "ExternalDocuments";
// A collection of opened documents in RDT, indexed by the cookie of the document.
private ImmutableDictionary<uint, DocumentId> _openedDocs = ImmutableDictionary<uint, DocumentId>.Empty;
private CollaborationSession _session;
private string _remoteRootPath;
private string _externalPath;
private RemoteDiagnosticListTable _remoteDiagnosticListTable;
public bool IsRemoteSession { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="RemoteLanguageServiceWorkspace"/> class.
/// </summary>
[ImportingConstructor]
public RemoteLanguageServiceWorkspace(ExportProvider exportProvider,
SVsServiceProvider serviceProvider,
IDiagnosticService diagnosticService,
ITableManagerProvider tableManagerProvider,
IThreadingContext threadingContext)
: base(VisualStudioMefHostServices.Create(exportProvider), WorkspaceKind.AnyCodeRoslynWorkspace)
{
_serviceProvider = serviceProvider;
_remoteDiagnosticListTable = new RemoteDiagnosticListTable(serviceProvider, this, diagnosticService, tableManagerProvider);
var componentModel = _serviceProvider.GetService(typeof(SComponentModel)) as IComponentModel;
Assumes.Present(componentModel);
_editorAdaptersFactoryService = componentModel.GetService<IVsEditorAdaptersFactoryService>();
_rdt = new RunningDocumentTable(serviceProvider);
_threadingContext = threadingContext;
}
public async Task SetSession(CollaborationSession session)
{
_session = session;
var roots = await session.ListRootsAsync(CancellationToken.None).ConfigureAwait(false);
_remoteRootPath = session.ConvertSharedUriToLocalPath(roots[0]);
_remoteRootPath = _remoteRootPath.Substring(0, _remoteRootPath.Length - 1);
var lastSlash = _remoteRootPath.LastIndexOf('\\');
_externalPath = _remoteRootPath.Substring(0, lastSlash + 1);
_externalPath += "~external";
IsRemoteSession = true;
session.RemoteServicesChanged += (object sender, RemoteServicesChangedEventArgs e) =>
{
_remoteDiagnosticListTable.UpdateWorkspaceDiagnosticsPresent(_session.RemoteServiceNames.Contains("workspaceDiagnostics"));
};
}
public void EndSession()
{
IsRemoteSession = false;
}
public void Init()
{
StartSolutionCrawler();
}
/// <inheritdoc />
public override bool CanOpenDocuments => true;
/// <inheritdoc />
public void OnManagedProjectAdded(ProjectInfo projectInfo)
{
//Notify AnyCode Roslyn workspace a project is being added.
OnProjectAdded(projectInfo);
}
/// <inheritdoc />
public void OnManagedProjectReloaded(ProjectInfo projectInfo)
{
//Notify AnyCode Roslyn workspace a project is being reloaded.
OnProjectReloaded(projectInfo);
}
/// <inheritdoc />
public void OnManagedProjectReferenceAdded(ProjectId projectId, ProjectReference reference)
{
//Notify AnyCode Roslyn workspace a project reference is being reloaded.
OnProjectReferenceAdded(projectId, reference);
}
/// <inheritdoc />
public void UpdateProjectReferences(ProjectId projectId, IEnumerable<ProjectReference> references)
{
var roslynProject = CurrentSolution.GetProject(projectId);
roslynProject = roslynProject.WithProjectReferences(references);
}
/// <inheritdoc />
public void OnFileReloaded(object docInfo)
{
OnDocumentReloaded(docInfo as DocumentInfo);
}
/// <inheritdoc />
public void NotifyOnDocumentOpened(RunningDocumentInfo docInfo)
{
if (_openedDocs.ContainsKey(docInfo.DocCookie))
{
return;
}
Document document = GetOrAddDocument(docInfo.Moniker);
if (document != null)
{
if (docInfo.DocData is IVsTextBuffer)
{
ITextBuffer textBuffer = _editorAdaptersFactoryService.GetDocumentBuffer((IVsTextBuffer)docInfo.DocData);
if (textBuffer != null)
{
SourceTextContainer textContainer = textBuffer.AsTextContainer();
OnDocumentOpened(document.Id, textContainer);
_openedDocs = _openedDocs.SetItem(docInfo.DocCookie, document.Id);
}
}
}
}
private bool IsExternalLocalUri(string localPath)
{
return localPath.StartsWith(_externalPath) &&
localPath.Length > (_externalPath.Length + 1);
}
public Document GetOrAddDocument(string filePath)
{
DocumentId docId = CurrentSolution.GetDocumentIdsWithFilePath(filePath).FirstOrDefault();
if (docId != null)
{
return CurrentSolution.GetDocument(docId);
}
if (!IsRemoteSession)
{
return null;
}
// If the document is within the joined folder or it's a registered external file,
// add it to the workspace, otherwise bail out.
if (!filePath.StartsWith(_remoteRootPath) &&
!IsExternalLocalUri(filePath))
{
return null;
}
var language = GetLanguage(filePath);
// Unsupported language.
if (language == null)
{
return null;
}
var folderName = Path.GetFileNameWithoutExtension(_remoteRootPath);
return AddDocumentToProject(filePath, language, folderName);
}
public Document GetOrAddExternalDocument(string filePath, string language)
{
DocumentId docId = CurrentSolution.GetDocumentIdsWithFilePath(filePath).FirstOrDefault();
if (docId != null)
{
return CurrentSolution.GetDocument(docId);
}
return AddDocumentToProject(filePath, language, ExternalProjectName);
}
public async Task<DocumentSpan?> GetDocumentSpanFromLocation(LSP.Location location, CancellationToken cancellationToken)
{
var document = GetOrAddDocument(location.Uri.LocalPath);
if (document == null)
{
return null;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
// The protocol converter would have synced the file to disk but we the document snapshot that was in the workspace before the sync would have empty text.
// So we need to read from disk in order to map from line\column to a textspan.
if (string.IsNullOrEmpty(text.ToString()))
{
text = SourceText.From(File.ReadAllText(document.FilePath));
// Some features like the FindRefs window try to get the text at the span without opening the document (for eg to classify the span).
// So fork the document to get one with the text. Note that this new document will not be in the CurrentSolution and we don't intend to
// apply it back. By fetching the file, the workspace will get updated anyway. The assumption here is that this document that we are
// handing out is only used for simple inspection and it's version is never compared with the Workspace.CurrentSolution.
document = document.WithText(text);
}
var textSpan = ProtocolConversions.RangeToTextSpan(location.Range, text);
return new DocumentSpan(document, textSpan);
}
private Document AddDocumentToProject(string filePath, string language, string projectName)
{
var project = CurrentSolution.Projects.FirstOrDefault(p => p.Name == projectName && p.Language == language);
if (project == null)
{
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), projectName, projectName, language);
OnManagedProjectAdded(projectInfo);
project = CurrentSolution.GetProject(projectInfo.Id);
}
var docInfo = DocumentInfo.Create(DocumentId.CreateNewId(project.Id),
name: Path.GetFileName(filePath),
loader: new FileTextLoader(filePath, null),
filePath: filePath);
OnDocumentAdded(docInfo);
return CurrentSolution.GetDocument(docInfo.Id);
}
private string GetLanguage(string filePath)
{
var fileExtension = Path.GetExtension(filePath).ToLower();
if (fileExtension == ".cs")
{
return StringConstants.CSharpLspLanguageName;
}
else if (fileExtension == ".ts" || fileExtension == ".js")
{
return StringConstants.TypeScriptLanguageName;
}
return null;
}
/// <inheritdoc />
public void NotifyOnDocumentClosing(RunningDocumentInfo docInfo)
{
if (_openedDocs.TryGetValue(docInfo.DocCookie, out DocumentId id))
{
// check if the doc is part of the current Roslyn workspace before notifying Roslyn.
if (CurrentSolution.ContainsProject(id.ProjectId))
{
OnDocumentClosed(id, new FileTextLoaderNoException(docInfo.Moniker, null));
_openedDocs = _openedDocs.Remove(docInfo.DocCookie);
}
}
}
/// <inheritdoc />
public override void OpenDocument(DocumentId documentId, bool activate = true)
{
var doc = CurrentSolution.GetDocument(documentId);
if (doc != null)
{
var svc = _serviceProvider.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
Report.IfNotPresent(svc);
if (svc == null)
{
return;
}
_threadingContext.JoinableTaskFactory.Run(async () =>
{
await _session.DownloadFileAsync(_session.ConvertLocalPathToSharedUri(doc.FilePath), CancellationToken.None).ConfigureAwait(true);
});
Guid logicalView = Guid.Empty;
if (ErrorHandler.Succeeded(svc.OpenDocumentViaProject(doc.FilePath,
ref logicalView,
out var sp,
out IVsUIHierarchy hier,
out uint itemid,
out IVsWindowFrame frame))
&& frame != null)
{
if (activate)
{
frame.Show();
}
else
{
frame.ShowNoActivate();
}
var docInfo = _rdt.GetDocumentInfo(doc.FilePath);
if (docInfo.DocCookie != VSConstants.VSCOOKIE_NIL)
{
NotifyOnDocumentOpened(docInfo);
}
}
}
}
/// <inheritdoc />
public override bool CanApplyChange(ApplyChangesKind feature)
{
switch (feature)
{
case ApplyChangesKind.ChangeDocument:
case ApplyChangesKind.AddDocument:
case ApplyChangesKind.RemoveDocument:
return true;
default:
return false;
}
}
/// <inheritdoc />
public void AddOpenedDocument(string filePath, DocumentId docId)
{
var runningDocInfo = _rdt.GetDocumentInfo(filePath);
if (runningDocInfo.DocCookie != VSConstants.VSCOOKIE_NIL)
{
_openedDocs = _openedDocs.SetItem(runningDocInfo.DocCookie, docId);
}
}
/// <inheritdoc />
public void RemoveOpenedDocument(string filePath)
{
var runningDocInfo = _rdt.GetDocumentInfo(filePath);
if (runningDocInfo.DocCookie != VSConstants.VSCOOKIE_NIL)
{
_openedDocs = _openedDocs.Remove(runningDocInfo.DocCookie);
}
}
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
StopSolutionCrawler();
base.Dispose(disposing);
}
/// <inheritdoc />
protected override void ApplyDocumentTextChanged(DocumentId documentId, SourceText text)
{
var document = CurrentSolution.GetDocument(documentId);
if (document != null)
{
if (_openedDocs.Values.Contains(documentId) || IsDocumentOpen(documentId))
{
var textBuffer = _threadingContext.JoinableTaskFactory.Run(async () =>
{
var sourceText = await document.GetTextAsync().ConfigureAwait(false);
var textContainer = sourceText.Container;
return textContainer.TryGetTextBuffer();
});
UpdateText(textBuffer, text);
}
else
{
// The edits would get sent by the co-authoring service to the owner.
// The invisible editor saves the file on being disposed, which should get reflected on the owner's side.
using (var invisibleEditor = new InvisibleEditor(_serviceProvider, document.FilePath, hierarchyOpt: null,
needsSave: true, needsUndoDisabled: false))
{
UpdateText(invisibleEditor.TextBuffer, text);
}
}
}
}
private static void UpdateText(ITextBuffer textBuffer, SourceText text)
{
using (var edit = textBuffer.CreateEdit(EditOptions.DefaultMinimalChange, reiteratedVersionNumber: null, editTag: null))
{
var oldSnapshot = textBuffer.CurrentSnapshot;
var oldText = oldSnapshot.AsText();
var changes = text.GetTextChanges(oldText);
foreach (var change in changes)
{
edit.Replace(change.Span.Start, change.Span.Length, change.NewText);
}
edit.Apply();
}
}
private void StartSolutionCrawler()
{
DiagnosticProvider.Enable(this, DiagnosticProvider.Options.Syntax);
}
private void StopSolutionCrawler()
{
DiagnosticProvider.Disable(this);
}
}
}
// Copyright (c) Microsoft. 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.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.LiveShare.Projects;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LiveShare;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
using Task = System.Threading.Tasks.Task;
namespace Microsoft.CodeAnalysis.ExternalAccess.LiveShare
{
/// <summary>
/// Remote language service workspace host
/// </summary>
[Export(typeof(RemoteLanguageServiceWorkspaceHost))]
[ExportCollaborationService(typeof(RemoteLanguageServiceSession),
Scope = SessionScope.Guest,
Role = ServiceRole.LocalService,
Features = "LspServices",
CreationPriority = (int)ServiceRole.LocalService + 2100)]
internal sealed class RemoteLanguageServiceWorkspaceHost : ICollaborationServiceFactory
{
// A collection of loaded Roslyn Project IDs, indexed by project path.
private ImmutableDictionary<string, ProjectId> _loadedProjects = ImmutableDictionary.Create<string, ProjectId>(StringComparer.OrdinalIgnoreCase);
private ImmutableDictionary<string, ProjectInfo> _loadedProjectInfo = ImmutableDictionary.Create<string, ProjectInfo>(StringComparer.OrdinalIgnoreCase);
private TaskCompletionSource<bool> _projectsLoadedTaskCompletionSource = new TaskCompletionSource<bool>();
private readonly RemoteLanguageServiceWorkspace _remoteLanguageServiceWorkspace;
private readonly RemoteProjectInfoProvider _remoteProjectInfoProvider;
private readonly RunningDocumentTable _rdt;
// TODO: remove this project language to extension map with the switch to LSP
private readonly ImmutableDictionary<string, string[]> _projectLanguageToExtensionMap;
private readonly SVsServiceProvider _serviceProvider;
public Workspace Workspace => _remoteLanguageServiceWorkspace;
/// <summary>
/// Initializes a new instance of the <see cref="RemoteLanguageServiceWorkspaceHost"/> class.
/// </summary>
/// <param name="remoteLanguageServiceWorkspace">The workspace</param>
[ImportingConstructor]
public RemoteLanguageServiceWorkspaceHost(RemoteLanguageServiceWorkspace remoteLanguageServiceWorkspace,
RemoteProjectInfoProvider remoteProjectInfoProvider,
SVsServiceProvider serviceProvider)
{
_remoteLanguageServiceWorkspace = Requires.NotNull(remoteLanguageServiceWorkspace, nameof(remoteLanguageServiceWorkspace));
_remoteProjectInfoProvider = Requires.NotNull(remoteProjectInfoProvider, nameof(remoteProjectInfoProvider));
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_rdt = new RunningDocumentTable(serviceProvider);
var builder = ImmutableDictionary.CreateBuilder<string, string[]>(StringComparer.OrdinalIgnoreCase);
builder.Add("TypeScript", new string[] { ".js", ".jsx", ".ts", ".tsx" });
builder.Add("C#_Remote", new string[] { ".cs" });
_projectLanguageToExtensionMap = builder.ToImmutable();
}
public async Task<ICollaborationService> CreateServiceAsync(CollaborationSession collaborationSession, CancellationToken cancellationToken)
{
await _remoteLanguageServiceWorkspace.SetSession(collaborationSession).ConfigureAwait(false);
_remoteLanguageServiceWorkspace.Init();
// Kick off loading the projects in the background.
// Clients can call EnsureProjectsLoadedAsync to await completion.
LoadProjectsAsync(CancellationToken.None).Forget();
var lifeTimeService = new RemoteLanguageServiceSession();
lifeTimeService.Disposed += (s, e) =>
{
_remoteLanguageServiceWorkspace.EndSession();
CloseAllProjects();
_remoteLanguageServiceWorkspace.Dispose();
_projectsLoadedTaskCompletionSource = new TaskCompletionSource<bool>();
};
return lifeTimeService;
}
public VisualStudioProjectTracker ProjectTracker { get; private set; }
public async Task InitializeProjectTrackerAsync()
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
#pragma warning disable CS0618 // Type or member is obsolete. This is the new liveshare layer.
ProjectTracker = new VisualStudioProjectTracker(_serviceProvider, _remoteLanguageServiceWorkspace);
var documentProvider = (DocumentProvider)Activator.CreateInstance(typeof(DocumentProvider));
var metadataReferenceProvider = _remoteLanguageServiceWorkspace.Services.GetService<VisualStudioMetadataReferenceManager>();
var ruleSetFileProvider = _remoteLanguageServiceWorkspace.Services.GetService<VisualStudioRuleSetManager>();
ProjectTracker.InitializeProviders(documentProvider, metadataReferenceProvider, ruleSetFileProvider);
ProjectTracker.StartPushingToWorkspaceAndNotifyOfOpenDocuments(Enumerable.Empty<AbstractProject>());
#pragma warning restore CS0618 // Type or member is obsolete. This is the new liveshare layer.
}
/// <summary>
/// Ensures LoadProjectsAsync has completed
/// </summary>
public async Task EnsureProjectsLoadedAsync(CancellationToken cancellationToken)
{
using (var token = cancellationToken.Register(() =>
{
_projectsLoadedTaskCompletionSource.SetCanceled();
}))
{
await _projectsLoadedTaskCompletionSource.Task.ConfigureAwait(false);
}
}
/// <summary>
/// Calls <see cref="CodeAnalysis.Workspace.OnDocumentOpened(DocumentId, SourceTextContainer, bool)"/>
/// </summary>
/// <param name="docInfo">The document being opened.</param>
public void NotifyOnDocumentOpened(RunningDocumentInfo docInfo)
{
_remoteLanguageServiceWorkspace.NotifyOnDocumentOpened(docInfo);
}
/// <summary>
/// Calls <see cref="CodeAnalysis.Workspace.OnDocumentClosed(DocumentId, TextLoader, bool)"/>
/// </summary>
/// <param name="docInfo">The document info.</param>
public void NotifyOnDocumentClosing(RunningDocumentInfo docInfo)
{
_remoteLanguageServiceWorkspace.NotifyOnDocumentClosing(docInfo);
}
/// <summary>
/// Loads (or reloads) the corresponding Roslyn project and the direct referenced projects in the host environment.
/// </summary>
private async Task LoadProjectsAsync(CancellationToken cancellationToken)
{
try
{
await InitializeProjectTrackerAsync().ConfigureAwait(false);
var projectInfos = await _remoteProjectInfoProvider.GetRemoteProjectInfosAsync(cancellationToken).ConfigureAwait(false);
foreach (var projectInfo in projectInfos)
{
var projectName = projectInfo.Name;
if (!_loadedProjects.TryGetValue(projectName, out ProjectId projectId))
{
projectId = projectInfo.Id;
// Adds the Roslyn project into the current solution;
// and raise WorkspaceChanged event (WorkspaceChangeKind.ProjectAdded)
_remoteLanguageServiceWorkspace.OnManagedProjectAdded(projectInfo);
_loadedProjects = _loadedProjects.Add(projectName, projectId);
_loadedProjectInfo = _loadedProjectInfo.Add(projectName, projectInfo);
// TODO : figure out what changes we need to listen to.
}
else
{
if (_loadedProjectInfo.TryGetValue(projectName, out ProjectInfo projInfo))
{
_remoteLanguageServiceWorkspace.OnManagedProjectReloaded(projInfo);
}
}
}
_projectsLoadedTaskCompletionSource.SetResult(true);
}
catch (Exception ex)
{
_projectsLoadedTaskCompletionSource.SetException(ex);
}
}
private void CloseAllProjects()
{
foreach (var projectId in _loadedProjects.Values)
{
_remoteLanguageServiceWorkspace.OnProjectRemoved(projectId);
}
_loadedProjects = _loadedProjects.Clear();
_loadedProjectInfo = _loadedProjectInfo.Clear();
}
private class RemoteLanguageServiceSession : ICollaborationService, IDisposable
{
public event EventHandler Disposed;
public void Dispose()
{
Disposed?.Invoke(this, null);
}
}
}
}
......@@ -17,6 +17,10 @@ internal class StringConstants
public const string VBLspLanguageName = "VB_LSP";
public const string VBLspContentTypeName = "VB_LSP";
public const string CSharpLspPackageGuidString = "9d42b837-b615-4574-80e1-f48828b6954d";
public const string CSharpLspLanguageServiceGuidString = "69463241-e026-48b2-a08b-a1a83f0cbafe";
public const string CSharpLspDebuggerLanguageGuidString = "8D07D1C6-5DE2-45CE-AEBF-7E21E03F9B10";
// Note: this workspace kind is defined in Roslyn's:
// Implementation\DebuggerIntelliSense\DebuggerIntellisenseWorkspace.cs
// It is misspelled there as "DebbugerIntellisense"
......
......@@ -115,6 +115,7 @@
<InternalsVisibleTo Include="Roslyn.VisualStudio.Next.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.LiveShare" />
<InternalsVisibleTo Include="FSharp.Editor" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="FSharp.LanguageService" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="$(MoqPublicKey)" LoadsWithinVisualStudio="false" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册