Skip to content

Commit

Permalink
Restored the reverted XAML PR (Support XAML LSP in VS Code dotnet#70170
Browse files Browse the repository at this point in the history
…) via cherry-pick of PR commit. The Roslyn insertion will need to be coordinated with a Razor update to switch from the obsolete IRequestContextFactory to AbstractRequestContextFactory.

Addresses dotnet#69471 and dotnet#71114
  • Loading branch information
mgoertz-msft committed Jan 22, 2024
1 parent bf08f8e commit ec6ac20
Show file tree
Hide file tree
Showing 100 changed files with 1,762 additions and 464 deletions.
7 changes: 7 additions & 0 deletions Roslyn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.VisualStudio.Service
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK", "src\Tools\ExternalAccess\CompilerDeveloperSDK\Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK.csproj", "{A833B11C-5072-4A1F-A32B-2700433B0D3D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Xaml", "src\Tools\ExternalAccess\Xaml\Microsoft.CodeAnalysis.ExternalAccess.Xaml.csproj", "{8988270E-393A-4B92-AC1A-534F903CFD34}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost", "src\Workspaces\Core\MSBuild.BuildHost\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj", "{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Copilot", "src\Tools\ExternalAccess\Copilot\Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj", "{5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD}"
Expand Down Expand Up @@ -1316,6 +1318,10 @@ Global
{A833B11C-5072-4A1F-A32B-2700433B0D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A833B11C-5072-4A1F-A32B-2700433B0D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A833B11C-5072-4A1F-A32B-2700433B0D3D}.Release|Any CPU.Build.0 = Release|Any CPU
{8988270E-393A-4B92-AC1A-534F903CFD34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8988270E-393A-4B92-AC1A-534F903CFD34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8988270E-393A-4B92-AC1A-534F903CFD34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8988270E-393A-4B92-AC1A-534F903CFD34}.Release|Any CPU.Build.0 = Release|Any CPU
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1582,6 +1588,7 @@ Global
{172F3A04-644B-492C-9632-B07B52A5C0C4} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
{09E88382-0D7B-4A15-B1AF-0B89A5B67227} = {8DBA5174-B0AA-4561-82B1-A46607697753}
{A833B11C-5072-4A1F-A32B-2700433B0D3D} = {8977A560-45C2-4EC2-A849-97335B382C74}
{8988270E-393A-4B92-AC1A-534F903CFD34} = {8977A560-45C2-4EC2-A849-97335B382C74}
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
{5E8FB6D6-6C5C-42E6-9220-1EAA7ED9BCAD} = {8977A560-45C2-4EC2-A849-97335B382C74}
{09AEDEE4-6358-47C9-8022-3BD37A518070} = {8977A560-45C2-4EC2-A849-97335B382C74}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Composition;
using System.Text;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
Expand All @@ -22,7 +20,7 @@ public VSTypeScriptRequestExecutionQueueProvider()
{
}

public IRequestExecutionQueue<RequestContext> CreateRequestExecutionQueue(AbstractLanguageServer<RequestContext> languageServer, ILspLogger logger, IHandlerProvider handlerProvider)
public IRequestExecutionQueue<RequestContext> CreateRequestExecutionQueue(AbstractLanguageServer<RequestContext> languageServer, ILspLogger logger, AbstractHandlerProvider handlerProvider)
{
var queue = new RoslynRequestExecutionQueue(languageServer, logger, handlerProvider);
queue.Start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,7 @@ private protected static LSP.CompletionParams CreateCompletionParams(
SortText = sortText,
InsertTextFormat = LSP.InsertTextFormat.Plaintext,
Kind = kind,
Data = JObject.FromObject(new CompletionResolveData()
{
ResultId = resultId,
}),
Data = JObject.FromObject(new CompletionResolveData(resultId, ProtocolConversions.DocumentToTextDocumentIdentifier(document))),
Preselect = preselect,
VsResolveTextEditOnCommit = vsResolveTextEditOnCommit,
LabelDetails = labelDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.Razor" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.UnitTesting" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.Xaml" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities"/>
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Features.Test.Utilities"/>
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Features.UnitTests" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@ ValueTask ILspWorkspace.UpdateTextIfPresentAsync(DocumentId documentId, SourceTe
return this.ProjectSystemProjectFactory.ApplyChangeToWorkspaceAsync(
_ =>
{
this.OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false);
if (CurrentSolution.ContainsDocument(documentId))
{
this.OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false);
}
else if (CurrentSolution.ContainsAdditionalDocument(documentId))
{
this.OnAdditionalDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity);
}
return ValueTask.CompletedTask;
},
cancellationToken);
Expand All @@ -77,7 +84,14 @@ internal override ValueTask TryOnDocumentOpenedAsync(DocumentId documentId, Sour
return this.ProjectSystemProjectFactory.ApplyChangeToWorkspaceAsync(
_ =>
{
this.OnDocumentOpened(documentId, textContainer, isCurrentContext, requireDocumentPresentAndClosed: false);
if (CurrentSolution.ContainsDocument(documentId))
{
this.OnDocumentOpened(documentId, textContainer, isCurrentContext, requireDocumentPresentAndClosed: false);
}
else if (CurrentSolution.ContainsAdditionalDocument(documentId))
{
this.OnAdditionalDocumentOpened(documentId, textContainer, isCurrentContext, requireDocumentPresentAndClosed: false);
}
return ValueTask.CompletedTask;
},
cancellationToken);
Expand All @@ -88,27 +102,33 @@ internal override ValueTask TryOnDocumentClosedAsync(DocumentId documentId, Canc
return this.ProjectSystemProjectFactory.ApplyChangeToWorkspaceAsync(
async w =>
{
// TODO(cyrusn): This only works for normal documents currently. We'll have to rethink how things work
// in the world if we ever support additionalfiles/editorconfig in our language server.
var document = w.CurrentSolution.GetDocument(documentId);
var textDocument = w.CurrentSolution.GetDocument(documentId) ?? w.CurrentSolution.GetAdditionalDocument(documentId);
if (document is { FilePath: { } filePath })
if (textDocument is { FilePath: { } filePath })
{
TextLoader loader;
if (document.DocumentState.Attributes.DesignTimeOnly)
var document = textDocument as Document;
if (document?.DocumentState.Attributes.DesignTimeOnly == true)
{
// Dynamic files don't exist on disk so if we were to use the FileTextLoader we'd effectively be emptying out the document.
// We also assume they're not user editable, and hence can't have "unsaved" changes that are expected to go away on close.
// Instead we just maintain their current state as per the LSP view of the world.
var documentText = await document.GetTextAsync(cancellationToken);
var documentText = await textDocument.GetTextAsync(cancellationToken);
loader = new SourceTextLoader(documentText, filePath);
}
else
{
loader = this.ProjectSystemProjectFactory.CreateFileTextLoader(filePath);
}
this.OnDocumentClosedEx(documentId, loader, requireDocumentPresentAndOpen: false);
if (document is not null)
{
this.OnDocumentClosedEx(documentId, loader, requireDocumentPresentAndOpen: false);
}
else
{
this.OnAdditionalDocumentClosed(documentId, loader, requireDocumentPresentAndOpen: false);
}
}
},
cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ protected override ILspServices ConstructLspServices()

var _ = AddHandlers(serviceCollection)
.AddSingleton<ILspLogger>(_logger)
.AddSingleton<IRequestContextFactory<ExampleRequestContext>, ExampleRequestContextFactory>()
.AddSingleton<IHandlerProvider>(s => GetHandlerProvider())
.AddSingleton<AbstractRequestContextFactory<ExampleRequestContext>, ExampleRequestContextFactory>()
.AddSingleton<AbstractHandlerProvider>(s => HandlerProvider)
.AddSingleton<IInitializeManager<InitializeParams, InitializeResult>, CapabilitiesManager>()
.AddSingleton(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Microsoft.CommonLanguageServerProtocol.Framework.Example;

internal class ExampleRequestContextFactory : IRequestContextFactory<ExampleRequestContext>
internal class ExampleRequestContextFactory : AbstractRequestContextFactory<ExampleRequestContext>
{
private readonly ILspServices _lspServices;

Expand All @@ -16,7 +16,7 @@ public ExampleRequestContextFactory(ILspServices lspServices)
_lspServices = lspServices;
}

public Task<ExampleRequestContext> CreateRequestContextAsync<TRequestParam>(IQueueItem<ExampleRequestContext> queueItem, TRequestParam param, CancellationToken cancellationToken)
public override Task<ExampleRequestContext> CreateRequestContextAsync<TRequestParam>(IQueueItem<ExampleRequestContext> queueItem, IMethodHandler methodHandler, TRequestParam requestParam, CancellationToken cancellationToken)
{
var logger = _lspServices.GetRequiredService<ILspLogger>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ public class MultiRegisteringHandler :
{
public bool MutatesSolutionState => throw new System.NotImplementedException();

[LanguageServerEndpoint(Methods.TextDocumentDidCloseName)]
[LanguageServerEndpoint(Methods.TextDocumentDidCloseName, LanguageServerConstants.DefaultLanguageName)]
Task INotificationHandler<DidCloseTextDocumentParams, ExampleRequestContext>.HandleNotificationAsync(DidCloseTextDocumentParams request, ExampleRequestContext requestContext, CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}

[LanguageServerEndpoint(Methods.TextDocumentDidOpenName)]
[LanguageServerEndpoint(Methods.TextDocumentDidOpenName, LanguageServerConstants.DefaultLanguageName)]
Task<SemanticTokensDeltaPartialResult> IRequestHandler<DidOpenTextDocumentParams, SemanticTokensDeltaPartialResult, ExampleRequestContext>.HandleRequestAsync(DidOpenTextDocumentParams request, ExampleRequestContext context, CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}

[LanguageServerEndpoint(Methods.TextDocumentDidChangeName)]
[LanguageServerEndpoint(Methods.TextDocumentDidChangeName, LanguageServerConstants.DefaultLanguageName)]
Task<SemanticTokensDeltaPartialResult> IRequestHandler<DidChangeTextDocumentParams, SemanticTokensDeltaPartialResult, ExampleRequestContext>.HandleRequestAsync(DidChangeTextDocumentParams request, ExampleRequestContext context, CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public void GetMethodHandler(bool supportsGetRegisteredServices)
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices);

var methodHander = handlerProvider.GetMethodHandler(TestMethodHandler.Name, TestMethodHandler.RequestType, TestMethodHandler.ResponseType);
Assert.Same(TestMethodHandler.Instance, methodHander);
var methodHandler = handlerProvider.GetMethodHandler(TestMethodHandler.Name, TestMethodHandler.RequestType, TestMethodHandler.ResponseType, LanguageServerConstants.DefaultLanguageName);
Assert.Same(TestMethodHandler.Instance, methodHandler);
}

[Theory]
Expand All @@ -27,8 +27,8 @@ public void GetMethodHandler_Parameterless(bool supportsGetRegisteredServices)
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices);

var methodHander = handlerProvider.GetMethodHandler(TestParameterlessMethodHandler.Name, requestType: null, TestParameterlessMethodHandler.ResponseType);
Assert.Same(TestParameterlessMethodHandler.Instance, methodHander);
var methodHandler = handlerProvider.GetMethodHandler(TestParameterlessMethodHandler.Name, requestType: null, TestParameterlessMethodHandler.ResponseType, LanguageServerConstants.DefaultLanguageName);
Assert.Same(TestParameterlessMethodHandler.Instance, methodHandler);
}

[Theory]
Expand All @@ -37,8 +37,8 @@ public void GetMethodHandler_Notification(bool supportsGetRegisteredServices)
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices);

var methodHander = handlerProvider.GetMethodHandler(TestNotificationHandler.Name, TestNotificationHandler.RequestType, responseType: null);
Assert.Same(TestNotificationHandler.Instance, methodHander);
var methodHandler = handlerProvider.GetMethodHandler(TestNotificationHandler.Name, TestNotificationHandler.RequestType, responseType: null, LanguageServerConstants.DefaultLanguageName);
Assert.Same(TestNotificationHandler.Instance, methodHandler);
}

[Theory]
Expand All @@ -47,24 +47,24 @@ public void GetMethodHandler_ParameterlessNotification(bool supportsGetRegistere
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices);

var methodHander = handlerProvider.GetMethodHandler(TestParameterlessNotificationHandler.Name, requestType: null, responseType: null);
Assert.Same(TestParameterlessNotificationHandler.Instance, methodHander);
var methodHandler = handlerProvider.GetMethodHandler(TestParameterlessNotificationHandler.Name, requestType: null, responseType: null, LanguageServerConstants.DefaultLanguageName);
Assert.Same(TestParameterlessNotificationHandler.Instance, methodHandler);
}

[Fact]
public void GetMethodHandler_WrongMethod_Throws()
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices: false);

Assert.Throws<InvalidOperationException>(() => handlerProvider.GetMethodHandler("UndefinedMethod", TestMethodHandler.RequestType, TestMethodHandler.ResponseType));
Assert.Throws<InvalidOperationException>(() => handlerProvider.GetMethodHandler("UndefinedMethod", TestMethodHandler.RequestType, TestMethodHandler.ResponseType, LanguageServerConstants.DefaultLanguageName));
}

[Fact]
public void GetMethodHandler_WrongResponseType_Throws()
{
var handlerProvider = GetHandlerProvider(supportsGetRegisteredServices: false);

Assert.Throws<InvalidOperationException>(() => handlerProvider.GetMethodHandler(TestMethodHandler.Name, TestMethodHandler.RequestType, responseType: typeof(long)));
Assert.Throws<InvalidOperationException>(() => handlerProvider.GetMethodHandler(TestMethodHandler.Name, TestMethodHandler.RequestType, responseType: typeof(long), LanguageServerConstants.DefaultLanguageName));
}

[Theory]
Expand All @@ -82,6 +82,21 @@ public void GetRegisteredMethods(bool supportsGetRegisteredServices)
r => Assert.Equal(TestParameterlessNotificationHandler.Name, r.MethodName));
}

[Fact]
public void GetMethodHandler_LanguageHandlers()
{
var handlerProvider = new TestHandlerProvider(providers: [
(TestXamlLanguageHandler.Metadata, TestXamlLanguageHandler.Instance),
(TestDefaultLanguageHandler.Metadata, TestDefaultLanguageHandler.Instance),
]);

var defaultMethodHandler = handlerProvider.GetMethodHandler(TestDefaultLanguageHandler.Name, TestDefaultLanguageHandler.RequestType, TestDefaultLanguageHandler.ResponseType, LanguageServerConstants.DefaultLanguageName);
Assert.Equal(TestDefaultLanguageHandler.Instance, defaultMethodHandler);

var xamlMethodHandler = handlerProvider.GetMethodHandler(TestDefaultLanguageHandler.Name, TestDefaultLanguageHandler.RequestType, TestDefaultLanguageHandler.ResponseType, TestXamlLanguageHandler.Language);
Assert.Equal(TestXamlLanguageHandler.Instance, xamlMethodHandler);
}

private static HandlerProvider GetHandlerProvider(bool supportsGetRegisteredServices)
=> new(GetLspServices(supportsGetRegisteredServices));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@

namespace Microsoft.CommonLanguageServerProtocol.Framework.UnitTests;

internal class TestHandlerProvider : IHandlerProvider
internal class TestHandlerProvider : AbstractHandlerProvider
{
private readonly IEnumerable<(RequestHandlerMetadata metadata, IMethodHandler provider)> _providers;

public TestHandlerProvider(IEnumerable<(RequestHandlerMetadata metadata, IMethodHandler provider)> providers)
=> _providers = providers;

public IMethodHandler GetMethodHandler(string method, Type? requestType, Type? responseType)
=> _providers.Single(p => p.metadata.MethodName == method).provider;
public override IMethodHandler GetMethodHandler(string method, Type? requestType, Type? responseType, string language)
=> _providers.Single(p => p.metadata.MethodName == method && p.metadata.Language == language).provider;

public ImmutableArray<RequestHandlerMetadata> GetRegisteredMethods()
public override ImmutableArray<RequestHandlerMetadata> GetRegisteredMethods()
=> _providers.Select(p => p.metadata).ToImmutableArray();
}
Loading

0 comments on commit ec6ac20

Please sign in to comment.