Skip to content

Commit

Permalink
Merge pull request dotnet#40 from dibarbet/instantiate_roslyn_server
Browse files Browse the repository at this point in the history
Instantiate the roslyn LSP server with text sync support
  • Loading branch information
dibarbet authored Oct 24, 2022
2 parents c354b40 + 4661541 commit 5a40ba9
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 52 deletions.
13 changes: 13 additions & 0 deletions server/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\snk\keypair.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>

<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest-All</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
</Project>
2 changes: 2 additions & 0 deletions server/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>
<MicrosoftCodeAnalysisLanguageServerProtocolVersion>4.5.0-1.22524.1</MicrosoftCodeAnalysisLanguageServerProtocolVersion>
<MicrosoftExtensionsLoggingVersion>6.0.0</MicrosoftExtensionsLoggingVersion>
<MicrosoftExtensionsLoggingAbstractionsVersion>6.0.2</MicrosoftExtensionsLoggingAbstractionsVersion>
<MicrosoftExtensionsLoggingConsoleVersion>$(MicrosoftExtensionsLoggingVersion)</MicrosoftExtensionsLoggingConsoleVersion>
<MicrosoftVisualStudioCompositionVersion>17.2.41</MicrosoftVisualStudioCompositionVersion>
<StreamJsonRpcVersion>2.12.27</StreamJsonRpcVersion>
</PropertyGroup>
</Project>
2 changes: 2 additions & 0 deletions server/Microsoft.CodeAnalysis.LanguageServer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6BB63E09-D5FD-4EF7-8041-1150449A6058}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
NuGet.config = NuGet.config
EndProjectSection
EndProject
Global
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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.

using System.Collections.Immutable;
using System.Reflection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Composition;

namespace Microsoft.CodeAnalysis.LanguageServer;

internal sealed class ExportProviderBuilder
{
/// <summary>
/// These assemblies won't necessarily be loaded when we want to run MEF discovery.
/// We'll need to add them to the catalog manually.
/// </summary>
private static readonly ImmutableHashSet<string> AssembliesToDiscover = ImmutableHashSet.Create(
"Microsoft.CodeAnalysis.LanguageServer.Protocol.dll",
"Microsoft.CodeAnalysis.Features.dll",
"Microsoft.CodeAnalysis.Workspaces.dll");

public static async Task<ExportProvider> CreateExportProviderAsync()
{
var baseDirectory = AppContext.BaseDirectory;
var assembliesWithFullPath = AssembliesToDiscover.Select(a => Path.Combine(baseDirectory, a));

var discovery = PartDiscovery.Combine(
new AttributedPartDiscovery(Resolver.DefaultInstance, isNonPublicSupported: true), // "NuGet MEF" attributes (Microsoft.Composition)
new AttributedPartDiscoveryV1(Resolver.DefaultInstance));

// TODO - we should likely cache the catalog so we don't have to rebuild it every time.
var catalog = ComposableCatalog.Create(Resolver.DefaultInstance)
.AddParts(await discovery.CreatePartsAsync(Assembly.GetExecutingAssembly()))
.AddParts(await discovery.CreatePartsAsync(assembliesWithFullPath))
.WithCompositionService(); // Makes an ICompositionService export available to MEF parts to import

// Assemble the parts into a valid graph.
var config = CompositionConfiguration.Create(catalog);
_ = config.ThrowOnErrors();

// Prepare an ExportProvider factory based on this graph.
var exportProviderFactory = config.CreateExportProviderFactory();

// Create an export provider, which represents a unique container of values.
// You can create as many of these as you want, but typically an app needs just one.
var exportProvider = exportProviderFactory.CreateExportProvider();

// Obtain our first exported value
return exportProvider;
}
}
29 changes: 29 additions & 0 deletions server/Microsoft.CodeAnalysis.LanguageServer/HostLspLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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.

using Microsoft.Extensions.Logging;

namespace Microsoft.CodeAnalysis.LanguageServer;

internal sealed class HostLspLogger : ILspServiceLogger
{
private readonly ILogger _logger;

public HostLspLogger(ILogger logger)
{
_logger = logger;
}

public void LogEndContext(string message, params object[] @params) => _logger.LogTrace($"[{DateTime.UtcNow:hh:mm:ss.fff}][End]{message}", @params);

public void LogError(string message, params object[] @params) => _logger.LogError(message, @params);

public void LogException(Exception exception, string? message = null, params object[] @params) => _logger.LogError(exception, message, @params);

public void LogInformation(string message, params object[] @params) => _logger.LogInformation(message, @params);

public void LogStartContext(string message, params object[] @params) => _logger.LogTrace($"[{DateTime.UtcNow:hh:mm:ss.fff}][Start]{message}", @params);

public void LogWarning(string message, params object[] @params) => _logger.LogWarning(message, @params);
}
47 changes: 0 additions & 47 deletions server/Microsoft.CodeAnalysis.LanguageServer/JsonRpcServer.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.

using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.LanguageServer;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Composition;
using StreamJsonRpc;

namespace Microsoft.CodeAnalysis.LanguageServer;

internal sealed class LanguageServerHost
{
private readonly JsonRpc _jsonRpc;
private readonly ILogger _logger;
private readonly AbstractLanguageServer<RequestContext> _roslynLanguageServer;

public LanguageServerHost(Stream inputStream, Stream outputStream, ILogger logger, ExportProvider exportProvider)
{
_logger = logger;

var handler = new HeaderDelimitedMessageHandler(outputStream, inputStream, new JsonMessageFormatter());

// If there is a jsonrpc disconnect or server shutdown, that is handled by the AbstractLanguageServer. No need to do anything here.
_jsonRpc = new JsonRpc(handler)
{
ExceptionStrategy = ExceptionProcessing.CommonErrorData,
};

var roslynLspFactory = exportProvider.GetExportedValue<ILanguageServerFactory>();
var capabilitiesProvider = new ServerCapabilitiesProvider();
var lspLogger = new HostLspLogger(logger);
_roslynLanguageServer = roslynLspFactory.Create(_jsonRpc, capabilitiesProvider, WellKnownLspServerKinds.CSharpVisualBasicLspServer, lspLogger);
}

public async Task StartAsync()
{
_logger.LogInformation("Starting server...");
_jsonRpc.StartListening();
await _jsonRpc.Completion.ConfigureAwait(false);
await _roslynLanguageServer.WaitForExitAsync().ConfigureAwait(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.LanguageServer;

internal sealed class ServerCapabilitiesProvider : ICapabilitiesProvider
{
public ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities)
{
return new()
{
TextDocumentSync = new TextDocumentSyncOptions
{
Change = TextDocumentSyncKind.Incremental,
OpenClose = true,
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

using System.Composition;

namespace Microsoft.CodeAnalysis.LanguageServer.LanguageServer;

/// <summary>
/// Implements the workspace registration service so that any new workspaces we
/// create are automatically registered by <see cref="LspWorkspaceRegistrationEventListener"/>
/// </summary>
[Export(typeof(LspWorkspaceRegistrationService))]
internal class WorkspaceRegistrationService : LspWorkspaceRegistrationService
{
public override string GetHostWorkspaceKind()
{
// For now mark the host workspace kind as the 'main' workspace where
// 'workspace/XXXX' requests go to.
return WorkspaceKind.Host;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand All @@ -8,10 +8,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.LanguageServer.Protocol" Version="$(MicrosoftCodeAnalysisLanguageServerProtocolVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsoleVersion)" />
<PackageReference Include="StreamJsonRpc" Version="$(StreamJsonRpcVersion)" />
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="$(MicrosoftVisualStudioCompositionVersion)" />
</ItemGroup>

</Project>
12 changes: 9 additions & 3 deletions server/Microsoft.CodeAnalysis.LanguageServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@
// 1. File logs for feedback
// 2. Logs to vscode output window.
// 3. Telemetry
// Also decide how we configure logging (env variables, extension settings, etc.)
// https://github.com/microsoft/vscode-csharp-next/issues/12
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole((options) => options.LogToStandardErrorThreshold = LogLevel.Trace));
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Trace);
builder.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);
});
var logger = loggerFactory.CreateLogger<ILogger>();

LaunchDebuggerIfEnabled(args);

var jsonRpc = new RoslynLanguageServer(Console.OpenStandardInput(), Console.OpenStandardOutput(), logger);
var exportProvider = await ExportProviderBuilder.CreateExportProviderAsync();
var jsonRpc = new LanguageServerHost(Console.OpenStandardInput(), Console.OpenStandardOutput(), logger, exportProvider);

await jsonRpc.StartAsync();
await jsonRpc.StartAsync().ConfigureAwait(false);

return;

Expand Down
14 changes: 14 additions & 0 deletions server/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<configuration>
<packageSources>
<clear />
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="vs-impl" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json" />
<add key="vssdk" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vssdk/nuget/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>
Binary file added server/snk/keypair.snk
Binary file not shown.
1 change: 0 additions & 1 deletion src/lsptoolshost/roslynLanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,5 @@ function startServer(outputChannel: vscode.OutputChannel) : cp.ChildProcess {
];

let childProcess = cp.spawn('dotnet', args);
childProcess.stderr.on("data", data => outputChannel.append(`STDER: ${data.toString()}`));
return childProcess;
}

0 comments on commit 5a40ba9

Please sign in to comment.