diff --git a/Directory.Packages.props b/Directory.Packages.props
index d1ad925b..0d4d315a 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -43,8 +43,10 @@
+
+
diff --git a/MSBuildLanguageServer/Import/MSBuildLanguageServer.cs b/MSBuildLanguageServer/Import/MSBuildLanguageServer.cs
index 1a11c8d8..d9ce7cf8 100644
--- a/MSBuildLanguageServer/Import/MSBuildLanguageServer.cs
+++ b/MSBuildLanguageServer/Import/MSBuildLanguageServer.cs
@@ -1,7 +1,7 @@
// modified copy of
-// https://github.com/dotnet/roslyn/blob/c5b98ae61ab894230786db2cde711ce4525a2597/src/Features/LanguageServer/Protocol/RoslynLanguageServer.cs
+// https://github.com/dotnet/roslyn/blob/b292a51d13e020e350366ac305706367cd9db5c2/src/Features/LanguageServer/Protocol/RoslynLanguageServer.cs
// changes annotated inline with // MODIFICATION
-//
+
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -9,21 +9,20 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.Handler.ServerLifetime;
using Microsoft.CommonLanguageServerProtocol.Framework;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Roslyn.LanguageServer.Protocol;
using Roslyn.Utilities;
using StreamJsonRpc;
namespace Microsoft.CodeAnalysis.LanguageServer
{
- internal sealed class MSBuildLanguageServer : AbstractLanguageServer, IOnInitialized
+ internal sealed class MSBuildLanguageServer : SystemTextJsonLanguageServer, IOnInitialized
{
private readonly AbstractLspServiceProvider _lspServiceProvider;
private readonly ImmutableDictionary>> _baseServices;
@@ -32,19 +31,17 @@ internal sealed class MSBuildLanguageServer : AbstractLanguageServer supportedLanguages,
WellKnownLspServerKinds serverKind)
- : base(jsonRpc, serializer, logger)
+ : base(jsonRpc, serializerOptions, logger)
{
_lspServiceProvider = lspServiceProvider;
_serverKind = serverKind;
- VSCodeInternalExtensionUtilities.AddVSCodeInternalExtensionConverters(serializer);
-
// Create services that require base dependencies (jsonrpc) or are more complex to create to the set manually.
_baseServices = GetBaseServices(jsonRpc, logger, capabilitiesProvider, hostServices, serverKind, supportedLanguages);
@@ -52,6 +49,13 @@ public MSBuildLanguageServer(
Initialize();
}
+ public static SystemTextJsonFormatter CreateJsonMessageFormatter()
+ {
+ var messageFormatter = new SystemTextJsonFormatter();
+ messageFormatter.JsonSerializerOptions.AddLspSerializerOptions();
+ return messageFormatter;
+ }
+
protected override ILspServices ConstructLspServices()
{
return _lspServiceProvider.CreateServices(_serverKind, _baseServices);
@@ -89,9 +93,9 @@ private ImmutableDictionary>> Ge
AddBaseService(new InitializedHandler());
AddBaseService(this);
- //MODIFICATION 1
+ // MODIFICATION 1
/*
- AddBaseService(new LanguageInfoProvider());
+ AddBaseService(new LanguageInfoProvider());
// In all VS cases, we already have a misc workspace. Specifically
// Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.MiscellaneousFilesWorkspace. In
@@ -102,7 +106,7 @@ private ImmutableDictionary>> Ge
*/
// END MODIFICATION 1
- return baseServices.ToImmutableDictionary();
+ return baseServices.ToImmutableDictionary();
void AddBaseService(T instance) where T : class
{
@@ -122,9 +126,9 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon
return Task.CompletedTask;
}
- // MODIFICATION 3
+ // MODIFICATION 2
/*
- protected override string GetLanguageForRequest(string methodName, JToken? parameters)
+ protected override string GetLanguageForRequest(string methodName, JsonElement? parameters)
{
if (parameters == null)
{
@@ -145,12 +149,11 @@ protected override string GetLanguageForRequest(string methodName, JToken? param
// { "textDocument": { "uri": "" ... } ... }
//
// We can easily identify the URI for the request by looking for this structure
- var textDocumentToken = parameters["textDocument"] ?? parameters["_vs_textDocument"];
- if (textDocumentToken is not null)
+ if (parameters.Value.TryGetProperty("textDocument", out var textDocumentToken) ||
+ parameters.Value.TryGetProperty("_vs_textDocument", out textDocumentToken))
{
- var uriToken = textDocumentToken["uri"];
- Contract.ThrowIfNull(uriToken, "textDocument does not have a uri property");
- var uri = uriToken.ToObject(_jsonSerializer);
+ var uriToken = textDocumentToken.GetProperty("uri");
+ var uri = JsonSerializer.Deserialize(uriToken, ProtocolConversions.LspJsonSerializerOptions);
Contract.ThrowIfNull(uri, "Failed to deserialize uri property");
var language = lspWorkspaceManager.GetLanguageForUri(uri);
Logger.LogInformation($"Using {language} from request text document");
@@ -161,10 +164,10 @@ protected override string GetLanguageForRequest(string methodName, JToken? param
// { "data": { "TextDocument": { "uri": "" ... } ... } ... }
//
// We can deserialize the data object using our unified DocumentResolveData.
- var dataToken = parameters["data"];
- if (dataToken is not null)
+ //var dataToken = parameters["data"];
+ if (parameters.Value.TryGetProperty("data", out var dataToken))
{
- var data = dataToken.ToObject(_jsonSerializer);
+ var data = JsonSerializer.Deserialize(dataToken, ProtocolConversions.LspJsonSerializerOptions);
Contract.ThrowIfNull(data, "Failed to document resolve data object");
var language = lspWorkspaceManager.GetLanguageForUri(data.TextDocument.Uri);
Logger.LogInformation($"Using {language} from data text document");
@@ -176,7 +179,8 @@ protected override string GetLanguageForRequest(string methodName, JToken? param
return LanguageServerConstants.DefaultLanguageName;
static bool ShouldUseDefaultLanguage(string methodName)
- => methodName switch
+ {
+ return methodName switch
{
Methods.InitializeName => true,
Methods.InitializedName => true,
@@ -188,7 +192,9 @@ static bool ShouldUseDefaultLanguage(string methodName)
Methods.ExitName => true,
_ => false,
};
+ }
}
*/
+ // END MODIFICATION 2
}
}
\ No newline at end of file
diff --git a/MSBuildLanguageServer/Import/ProtocolConversions.cs b/MSBuildLanguageServer/Import/ProtocolConversions.cs
index 211dae38..993c03c7 100644
--- a/MSBuildLanguageServer/Import/ProtocolConversions.cs
+++ b/MSBuildLanguageServer/Import/ProtocolConversions.cs
@@ -1,5 +1,6 @@
// modified copy of
-// https://raw.githubusercontent.com/dotnet/roslyn/fca6e1fcdcded85e69cc32e15acfb6820cd45597/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs// changes annotated inline with // MODIFICATION
+// https://raw.githubusercontent.com/dotnet/roslyn/044acb4ec888bf080b707e3db6818107e018d80b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs
+// changes annotated inline with // MODIFICATION
// with portions commented out using /* */ comments
// Licensed to the .NET Foundation under one or more agreements.
@@ -12,10 +13,11 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
+using System.Text.Json;
using System.Text.RegularExpressions;
-/*
using System.Threading;
using System.Threading.Tasks;
+/*
using Microsoft.CodeAnalysis.DocumentHighlighting;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Formatting;
@@ -111,7 +113,23 @@ internal static partial class ProtocolConversions
{
{ WellKnownTags.Deprecated, ImmutableArray.Create(LSP.CompletionItemTag.Deprecated) },
}.ToImmutableDictionary();
+ */
+
+ public static JsonSerializerOptions AddLspSerializerOptions(this JsonSerializerOptions options)
+ {
+ LSP.VSInternalExtensionUtilities.AddVSInternalExtensionConverters(options);
+ options.Converters.Add(new NaturalObjectConverter());
+ return options;
+ }
+ ///
+ /// Options that know how to serialize / deserialize basic LSP types.
+ /// Useful when there are particular fields that are not serialized or deserialized by normal request handling (for example
+ /// deserializing a field that is typed as object instead of a concrete type).
+ ///
+ public static JsonSerializerOptions LspJsonSerializerOptions = new JsonSerializerOptions().AddLspSerializerOptions();
+
+ /*
// TO-DO: More LSP.CompletionTriggerKind mappings are required to properly map to Roslyn CompletionTriggerKinds.
// https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1178726
public static async Task LSPToRoslynCompletionTriggerAsync(
@@ -176,8 +194,9 @@ static async Task GetInsertionCharacterAsync(Document document, int positi
return triggerCharacter;
}
}
-*/
- public static string GetDocumentFilePathFromUri(Uri uri)
+ */
+
+ public static string GetDocumentFilePathFromUri(Uri uri)
=> uri.IsFile ? uri.LocalPath : uri.AbsoluteUri;
///
@@ -207,9 +226,9 @@ public static Uri CreateAbsoluteUri(string absolutePath)
internal static Uri CreateRelativePatternBaseUri(string path)
{
- // According to VSCode LSP RelativePattern spec,
+ // According to VSCode LSP RelativePattern spec,
// found at https://github.com/microsoft/vscode/blob/9e1974682eb84eebb073d4ae775bad1738c281f6/src/vscode-dts/vscode.d.ts#L2226
- // the baseUri should not end in a trailing separator, nor should it
+ // the baseUri should not end in a trailing separator, nor should it
// have any relative segmeents (., ..)
if (path[^1] == System.IO.Path.DirectorySeparatorChar)
{
@@ -289,7 +308,8 @@ private static bool IsAscii(string filePath)
return true;
}
-/*
+
+ /*
public static LSP.TextDocumentPositionParams PositionToTextDocumentPositionParams(int position, SourceText text, Document document)
{
return new LSP.TextDocumentPositionParams()
@@ -535,10 +555,12 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText
return location;
}
}
-*/
+ */
+
public static LSP.CodeDescription? HelpLinkToCodeDescription(Uri? uri)
=> (uri != null) ? new LSP.CodeDescription { Href = uri } : null;
-/*
+ /*
+
public static LSP.SymbolKind NavigateToKindToSymbolKind(string kind)
{
if (Enum.TryParse(kind, out var symbolKind))
@@ -958,7 +980,7 @@ static string GetStyledText(TaggedText taggedText, bool isInCodeBlock)
if (!string.IsNullOrEmpty(taggedText.NavigationHint) && taggedText.NavigationHint == taggedText.NavigationTarget)
return $"[{text}]({taggedText.NavigationHint})";
- // Markdown ignores spaces at the start of lines outside of code blocks,
+ // Markdown ignores spaces at the start of lines outside of code blocks,
// so we replace regular spaces with non-breaking spaces to ensure structural space is retained.
// We want to use regular spaces everywhere else to allow the client to wrap long text.
if (!isCode && taggedText.Tag is TextTags.Space or TextTags.ContainerStart)
diff --git a/MSBuildLanguageServer/MSBuildLanguageServer.csproj b/MSBuildLanguageServer/MSBuildLanguageServer.csproj
index b1c48c00..f8ca539a 100644
--- a/MSBuildLanguageServer/MSBuildLanguageServer.csproj
+++ b/MSBuildLanguageServer/MSBuildLanguageServer.csproj
@@ -95,6 +95,7 @@
+
@@ -109,6 +110,13 @@
GenerateSource="true" ClassName="Microsoft.CodeAnalysis.CodeAnalysisResources" />
+
+
+
+
+
@@ -122,7 +130,8 @@
-
+
+
@@ -132,7 +141,6 @@
StronglyTypedClassName="$([System.String]::Copy('%(ClassName)').Substring($([MSBuild]::Add($([System.String]::Copy('%(ClassName)').LastIndexOf('.')), 1))))"
StronglyTypedNamespace="$([System.String]::Copy('%(ClassName)').Substring(0, $([System.String]::Copy('%(ClassName)').LastIndexOf('.'))))"
Generator="MSBuild:Compile"
- Link="sdk\resource\%(ClassName).resx"
StronglyTypedFileName="$(IntermediateOutputPath)\%(ClassName).Designer.cs"
LogicalName="%(ClassName).resources" />
diff --git a/MSBuildLanguageServer/MSBuildLanguageServerFactory.cs b/MSBuildLanguageServer/MSBuildLanguageServerFactory.cs
index 3061faad..fcc0262d 100644
--- a/MSBuildLanguageServer/MSBuildLanguageServerFactory.cs
+++ b/MSBuildLanguageServer/MSBuildLanguageServerFactory.cs
@@ -7,7 +7,7 @@
using System.Composition;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.CodeAnalysis.Host;
-using Newtonsoft.Json;
+using System.Text.Json;
[Export(typeof(ILanguageServerFactory)), Shared]
[method: ImportingConstructor]
@@ -17,7 +17,7 @@ class MSBuildLanguageServerFactory (CSharpVisualBasicLspServiceProvider lspServi
public AbstractLanguageServer Create (
JsonRpc jsonRpc,
- JsonSerializer jsonSerializer,
+ JsonSerializerOptions options,
ICapabilitiesProvider capabilitiesProvider,
WellKnownLspServerKinds serverKind,
AbstractLspLogger logger,
@@ -26,7 +26,7 @@ public AbstractLanguageServer Create (
return new Microsoft.CodeAnalysis.LanguageServer.MSBuildLanguageServer (
lspServiceProvider,
jsonRpc,
- jsonSerializer,
+ options,
capabilitiesProvider,
logger,
hostServices,
diff --git a/external/roslyn b/external/roslyn
index 93d19c2e..044acb4e 160000
--- a/external/roslyn
+++ b/external/roslyn
@@ -1 +1 @@
-Subproject commit 93d19c2e18409d849860569be30128b2077f2ce8
+Subproject commit 044acb4ec888bf080b707e3db6818107e018d80b