Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/QsCompiler/LanguageServer/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
Expand Down Expand Up @@ -123,9 +124,45 @@ public void Dispose()
internal Task NotifyClientAsync(string method, object args) =>
this.rpc.NotifyWithParameterObjectAsync(method, args); // no need to wait for completion

internal Task<T> InvokeAsync<T>(string method, object args) =>
this.rpc.InvokeWithParameterObjectAsync<T>(method, args);

internal Task PublishDiagnosticsAsync(PublishDiagnosticParams diagnostics) =>
this.NotifyClientAsync(Methods.TextDocumentPublishDiagnosticsName, diagnostics);

internal async void CheckDotNetSdkVersion()
{
var isDotNet31Installed = DotNetSdkHelper.IsDotNet31Installed();
if (isDotNet31Installed == null)
{
this.LogToWindow("Unable to detect .NET SDK versions", MessageType.Error);
}
else
{
if (isDotNet31Installed != true)
{
const string dotnet31Url = "https://dotnet.microsoft.com/download/dotnet-core/3.1";
this.LogToWindow($".NET Core SDK 3.1 not found. Quantum Development Kit Extension requires .NET Core SDK 3.1 to work properly ({dotnet31Url}).", MessageType.Error);
var downloadAction = new MessageActionItem { Title = "Download" };
var cancelAction = new MessageActionItem { Title = "No, thanks" };
var selectedAction = await this.ShowDialogInWindowAsync(
"Quantum Development Kit Extension requires .NET Core SDK 3.1 to work properly. Please install .NET Core SDK 3.1 and restart Visual Studio.",
MessageType.Error,
new[] { downloadAction, cancelAction });
if (selectedAction != null
&& selectedAction.Title == downloadAction.Title)
{
Process.Start(new ProcessStartInfo
{
FileName = dotnet31Url,
UseShellExecute = true,
CreateNoWindow = true,
});
}
}
}
}

/// <summary>
/// does not actually do anything unless the corresponding flag is defined upon compilation
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/QsCompiler/LanguageServer/LanguageServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@
<ItemGroup>
<Compile Include="..\..\Common\DelaySign.cs" Link="Properties\DelaySign.cs" />
</ItemGroup>
<ItemGroup>
<None Include="global.language-server.json" Link="global.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
11 changes: 10 additions & 1 deletion src/QsCompiler/LanguageServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ private static int LogAndExit(ReturnCode code, string? logFile = null, string? m

public static int Main(string[] args)
{
// We need to set the current directory to the same directory of
// the LanguageServer executable so that it will pick the global.json file
// and force the MSBuildLocator to use .NET Core SDK 3.1
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

var parser = new Parser(parser => parser.HelpWriter = null); // we want our own custom format for the version info
var options = parser.ParseArguments<Options>(args);
return options.MapResult(
Expand Down Expand Up @@ -120,8 +125,11 @@ private static int Run(Options options)
}
catch (Exception ex)
{
// Don't exit here, since exiting without establishing a connection will result in a cryptic failure of the extension.
// Instead, we proceed to create a server instance and establish the connection.
// Any errors can then be properly processed via the standard server-client communication as needed.
Log("[ERROR] MsBuildLocator could not register defaults.", options.LogFile);
return LogAndExit(ReturnCode.MSBUILD_UNINITIALIZED, options.LogFile, ex.ToString());
Log(ex, options.LogFile);
}

QsLanguageServer server;
Expand All @@ -140,6 +148,7 @@ private static int Run(Options options)
Log("Listening...", options.LogFile);
try
{
server.CheckDotNetSdkVersion();
server.WaitForShutdown();
}
catch (Exception ex)
Expand Down
40 changes: 40 additions & 0 deletions src/QsCompiler/LanguageServer/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Quantum.QsCompiler;
Expand Down Expand Up @@ -34,6 +37,21 @@ internal static void ShowInWindow(this QsLanguageServer server, string text, Mes
_ = server.NotifyClientAsync(Methods.WindowShowMessageName, message);
}

/// <summary>
/// Shows a dialog window with options (actions) to the user, and returns the selected option (action).
/// </summary>
internal static async Task<MessageActionItem> ShowDialogInWindowAsync(this QsLanguageServer server, string text, MessageType severity, MessageActionItem[] actionItems)
{
var message =
new ShowMessageRequestParams()
{
Message = text,
MessageType = severity,
Actions = actionItems
};
return await server.InvokeAsync<MessageActionItem>(Methods.WindowShowMessageRequestName, message);
}

/// <summary>
/// Logs the given text in the editor.
/// </summary>
Expand Down Expand Up @@ -124,4 +142,26 @@ public override void Initialize(IEventSource eventSource)
}
}
}

internal static class DotNetSdkHelper
{
private static readonly Regex DotNet31Regex = new Regex(@"^3\.1\.\d+", RegexOptions.Multiline | RegexOptions.Compiled);

public static bool? IsDotNet31Installed()
{
var process = Process.Start(new ProcessStartInfo
{
FileName = "dotnet",
Arguments = "--list-sdks",
RedirectStandardOutput = true,
});
if (process?.WaitForExit(3000) != true || process.ExitCode != 0)
{
return null;
}

var sdks = process.StandardOutput.ReadToEnd();
return DotNet31Regex.IsMatch(sdks);
}
}
}
6 changes: 6 additions & 0 deletions src/QsCompiler/LanguageServer/global.language-server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "3.1.100",
"rollForward": "latestFeature"
}
}