From db7e73ea3dd7bdb04480c494b89b91c461a58ed6 Mon Sep 17 00:00:00 2001 From: Allister Beharry Date: Wed, 27 Dec 2023 17:19:36 -0400 Subject: [PATCH] Add Compile Sollidity File implementation. --- src/Stratis.VS.StratisEVM/SolidityCompiler.cs | 60 ++++++++ ...lidityFileContextActionsProviderFactory.cs | 7 +- .../SolidityLanguageClient.cs | 39 +++++- .../SolidityLanguageSettings.json | 7 +- .../Stratis.VS.StratisEVM.csproj | 2 + .../StratisEVMPackage.cs | 11 +- .../StratisEVMPackage.vsct | 2 +- src/Stratis.VS.StratisEVM/VSUtil.cs | 128 ++++++++++++++++++ .../contracts/BasicDeployments.sol | 5 +- .../contracts/ReceivesEth.sol | 4 +- .../{hardhat.config.js => hardhat.config.ts} | 2 +- 11 files changed, 245 insertions(+), 22 deletions(-) create mode 100644 src/Stratis.VS.StratisEVM/SolidityCompiler.cs create mode 100644 src/Stratis.VS.StratisEVM/VSUtil.cs rename tests/solidity/hardhat-ignition-examples-main/{hardhat.config.js => hardhat.config.ts} (78%) diff --git a/src/Stratis.VS.StratisEVM/SolidityCompiler.cs b/src/Stratis.VS.StratisEVM/SolidityCompiler.cs new file mode 100644 index 0000000..7394272 --- /dev/null +++ b/src/Stratis.VS.StratisEVM/SolidityCompiler.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Threading; +using Stratis.DevEx; + +namespace Stratis.VS.StratisEVM +{ + public class SolidityCompiler : Runtime + { + public static async Task CompileFileAsync(string file) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + ProcessStartInfo info = new ProcessStartInfo(); + info.FileName = "cmd.exe"; + info.Arguments = "/c solc " + file + " --bin"; + info.RedirectStandardOutput = true; + info.RedirectStandardError = true; + info.UseShellExecute = false; + info.CreateNoWindow = true; + var process = new Process(); + process.StartInfo = info; + process.EnableRaisingEvents = true; + process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => + { + if (e.Data != null && e.Data.Length > 0) + { + VSUtil.LogInfo("Solidity Compiler", e.Data.Trim()); + } + }; + process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => + { + if (e.Data != null && e.Data.Length > 0) + { + VSUtil.LogError("Solidity Compiler", e.Data.Trim()); + } + }; + try + { + if (!process.Start()) + { + VSUtil.LogError("Could not start Solidity Compiler process {process}.", info.FileName + " " + info.Arguments); + return; + } + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + await process.WaitForExitAsync(); + } + catch (Exception ex) + { + VSUtil.LogError("Solidity Compiler", ex); + return; + } + } + } +} diff --git a/src/Stratis.VS.StratisEVM/SolidityFileContextActionsProviderFactory.cs b/src/Stratis.VS.StratisEVM/SolidityFileContextActionsProviderFactory.cs index 03857bb..a417939 100644 --- a/src/Stratis.VS.StratisEVM/SolidityFileContextActionsProviderFactory.cs +++ b/src/Stratis.VS.StratisEVM/SolidityFileContextActionsProviderFactory.cs @@ -55,11 +55,10 @@ public Task> GetActionsAsync(string filePath, new MyContextAction( fileContext, new Tuple(ProviderCommandGroup, StratisEVMPackageIds.Cmd1Id), - "My Action" + fileContext.DisplayName, + "Compile Solidity File" + fileContext.DisplayName, async (fCtxt, progress, ct) => { - - await OutputWindowPaneAsync("command 1"); + await SolidityCompiler.CompileFileAsync(filePath); }), // Toggle word count type command: @@ -91,7 +90,7 @@ internal static async Task OutputWindowPaneAsync(string message) windowFrame.Show(); } - outputWindow.CreatePane(ActionOutputWindowPane, "Actions", 1, 1); + outputWindow.CreatePane(ActionOutputWindowPane, "Solidity Compiler", 1, 1); outputWindow.GetPane(ActionOutputWindowPane, out outputPane); outputPane.Activate(); } diff --git a/src/Stratis.VS.StratisEVM/SolidityLanguageClient.cs b/src/Stratis.VS.StratisEVM/SolidityLanguageClient.cs index b979f22..1a07f58 100644 --- a/src/Stratis.VS.StratisEVM/SolidityLanguageClient.cs +++ b/src/Stratis.VS.StratisEVM/SolidityLanguageClient.cs @@ -22,6 +22,8 @@ using Stratis.DevEx; using Microsoft.VisualStudio.Shell.Interop; +using System.Windows.Ink; +using Stratis.VS.StratisEVM; namespace Stratis.VS { @@ -94,6 +96,7 @@ protected bool StartLanguageServerProcess() var programPath = "cmd.exe"; info.FileName = programPath; info.Arguments = "/c " + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "npm", "nomicfoundation-solidity-language-server.cmd") + " --stdio"; + //info.Arguments = "/c " + "node " + "c:\\Projects\\vscode-solidity\\dist\\cli\\server.js" + " --stdio"; info.RedirectStandardInput = true; info.RedirectStandardOutput = true; info.UseShellExecute = false; @@ -104,12 +107,13 @@ protected bool StartLanguageServerProcess() process.EnableRaisingEvents = true; process.Exited += (e, args) => { - Info("Language server proceess exited. Restarting."); - process.Start(); + Info("Language server proceess exited."); }; ServerProcess = process; return process.Start(); } + + #region ILanguageClient, ILanguageClientCustomMessage2 implementation public async Task ActivateAsync(CancellationToken token) { await Task.Yield(); @@ -118,8 +122,15 @@ public async Task ActivateAsync(CancellationToken token) Info("Solution dir is {d}", dir); this.InitializationOptions = JObject.FromObject(new { - workspaceFolders = new string[] {dir}, - rootUri = dir + enabledAsYouTypeCompilationErrorCheck = true, + maxNumberOfProblems = true + //workspaceFolders = new string[] {dir}, + //rootUri = dir + //compileUsingLocalVersion = "C:\\Users\\Allister\\Downloads\\soljson.js", + //enabledAsYouTypeCompilationErrorCheck = true, + //defaultCompiler = "local", + //compileUsingLocalVersion = "C:\\Users\\Allister\\Downloads\\soljson.js" + //compileUsingRemoteVersion = "latest", }); if (StartLanguageServerProcess()) @@ -176,6 +187,7 @@ public Task OnServerInitializeFailedAsync(ILanguag return Task.FromResult(failureContext); } + #endregion #endregion internal class SolidityLanguageClientMiddleLayer : ILanguageClientMiddleLayer @@ -189,11 +201,28 @@ public async Task HandleNotificationAsync(string methodName, JToken methodParam, { Info("Notification {req} {param}.", methodName, methodParam.ToString()); await sendNotification(methodParam); + /* + if (methodName == "textDocument/didChange") + { + methodParam.Root["contentChanges"] = JArray.FromObject(new[] {new + { + text = methodParam.Root["contentChanges"][0]["text"].Value(), + } }); + Info("didchange Notification {req} {param}.", methodName, methodParam.ToString()); + await sendNotification(methodParam); + + } + else + { + Info("Notification {req} {param}.", methodName, methodParam.ToString()); + await sendNotification(methodParam); + } + */ } public async Task HandleRequestAsync(string methodName, JToken methodParam, Func> sendRequest) { - var resp = await sendRequest(methodParam); + var resp = await sendRequest(methodParam); Info("Request {req} {param}: {resp}", methodName, methodParam.ToString(), resp?.ToString() ?? "(null)"); return resp; } diff --git a/src/Stratis.VS.StratisEVM/SolidityLanguageSettings.json b/src/Stratis.VS.StratisEVM/SolidityLanguageSettings.json index 554ca79..7134b68 100644 --- a/src/Stratis.VS.StratisEVM/SolidityLanguageSettings.json +++ b/src/Stratis.VS.StratisEVM/SolidityLanguageSettings.json @@ -1,5 +1,8 @@ { "solidity.trace.server": "Verbose", - "solidity.telemetry": true, - "solidity.maxNumberOfProblems": 1 + "solidity.telemetry": false, + "solidity.maxNumberOfProblems": 1, + "solidity.enabledAsYouTypeCompilationErrorCheck": true, + "solidity.defaultCompiler": "localFile", + "solidity.compileUsingLocalVersion": "C:\\Users\\Allister\\Downloads\\soljson.js" } \ No newline at end of file diff --git a/src/Stratis.VS.StratisEVM/Stratis.VS.StratisEVM.csproj b/src/Stratis.VS.StratisEVM/Stratis.VS.StratisEVM.csproj index 2cddb40..ad660a3 100644 --- a/src/Stratis.VS.StratisEVM/Stratis.VS.StratisEVM.csproj +++ b/src/Stratis.VS.StratisEVM/Stratis.VS.StratisEVM.csproj @@ -46,12 +46,14 @@ + + diff --git a/src/Stratis.VS.StratisEVM/StratisEVMPackage.cs b/src/Stratis.VS.StratisEVM/StratisEVMPackage.cs index 31b5689..337283e 100644 --- a/src/Stratis.VS.StratisEVM/StratisEVMPackage.cs +++ b/src/Stratis.VS.StratisEVM/StratisEVMPackage.cs @@ -47,6 +47,7 @@ static StratisEVMPackage() Runtime.Initialize("Stratis.VS.StratisEVM", "VS"); } #endregion + #region Methods #region IVsSolutionEvents7 @@ -88,15 +89,17 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke { await base.InitializeAsync(cancellationToken, progress); Runtime.Info("StratisEVM package initialized."); + await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + VSUtil.InitializeVSServices(this); // When initialized asynchronously, the current thread may be a background thread at this point. // Do any initialization that requires the UI thread after switching to the UI thread. - await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + VSUtil.LogInfo("Stratis EVM", "log init"); + } - - - #endregion + #endregion } } diff --git a/src/Stratis.VS.StratisEVM/StratisEVMPackage.vsct b/src/Stratis.VS.StratisEVM/StratisEVMPackage.vsct index 8e71ea8..b4554ea 100644 --- a/src/Stratis.VS.StratisEVM/StratisEVMPackage.vsct +++ b/src/Stratis.VS.StratisEVM/StratisEVMPackage.vsct @@ -58,7 +58,7 @@ DynamicVisibility DefaultInvisible - Solidity Command 1 + Compile Solidity File diff --git a/src/Stratis.VS.StratisEVM/VSUtil.cs b/src/Stratis.VS.StratisEVM/VSUtil.cs new file mode 100644 index 0000000..a387913 --- /dev/null +++ b/src/Stratis.VS.StratisEVM/VSUtil.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Threading; + +using Stratis.DevEx; +using static System.Net.Mime.MediaTypeNames; + +namespace Stratis.VS.StratisEVM +{ + public class VSUtil : Runtime + { + protected static Dictionary logWindowPanes = new Dictionary (); + + protected static IVsUIShell uiShell; + + protected static IVsOutputWindow outputWindow; + + protected static string[] LogWindowNames = new string[] { "Stratis EVM", "Solidity Compiler" }; + protected static IVsOutputWindowPane GetLogOutputPane(string name) + { + IVsOutputWindowPane outputPane = null; + if (!logWindowPanes.ContainsKey(name) || ErrorHandler.Failed(outputWindow.GetPane(logWindowPanes[name], out outputPane))) + { + var guid = Guid.NewGuid(); + outputWindow.CreatePane(ref guid, name, 1, 1); + outputWindow.GetPane(ref guid, out outputPane); + if (outputPane != null) + { + logWindowPanes[name] = guid; + } + } + return outputPane; + } + public static void LogInfo(string logname, string text) + { + Info("(" + logname + ") " + text); + IVsOutputWindowPane outputPane = GetLogOutputPane(logname); + if (outputPane is null) + { + Error("Could not get output window pane {l}.", logname); + return; + } + else + { + if (ErrorHandler.Failed(outputPane.OutputStringThreadSafe(DateTime.Now.ToString() + ": " + text + Environment.NewLine))) + { + Error("Could not log to output window pane {l}.", logname); + } + } + } + + public static void LogError(string logname, string text) + { + Error("(" + logname + ") " + text); + IVsOutputWindowPane outputPane = GetLogOutputPane(logname); + if (outputPane is null) + { + Error("Could not get output window pane {l}.", logname); + return; + } + else + { + if (ErrorHandler.Failed(outputPane.OutputStringThreadSafe(DateTime.Now.ToString() + ": " + text + Environment.NewLine))) + { + Error("Could not log to output window pane {l}.", logname); + } + } + } + + public static void LogError(string logname, Exception ex) + { + LogError(logname, "(" + logname + ") (exception) " + ex.Message); + } + public static bool InitializeVSServices(IServiceProvider provider) + { + ThreadHelper.ThrowIfNotOnUIThread(); + if (uiShell is null) + { + uiShell = provider.GetService(typeof(SVsUIShell)) as IVsUIShell; + if (uiShell is null) + { + Error("Could not initialize Visual Studio UI shell."); + return false; + } + } + if (outputWindow is null) + { + var ow = provider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow; + if (ow != null) + { + outputWindow = ow; + } + else + { + Error("Could not initialize Visual Studio Ouput Window."); + return false; + } + + } + IVsOutputWindowPane outputPane = null; + foreach (var name in LogWindowNames) + { + if (!logWindowPanes.ContainsKey(name) || ErrorHandler.Failed(outputWindow.GetPane(logWindowPanes[name], out outputPane))) + { + var guid = Guid.NewGuid(); + outputWindow.CreatePane(ref guid, name, 1, 1); + outputWindow.GetPane(ref guid, out outputPane); + if (outputPane != null) + { + logWindowPanes[name] = guid; + } + else + { + Error("Could not create Visual Studio Ouput Window pane {name}.", name); + } + } + } + VSServicesInitialized = true; + return VSServicesInitialized; + } + + public static bool VSServicesInitialized = false; + } +} diff --git a/tests/solidity/hardhat-ignition-examples-main/contracts/BasicDeployments.sol b/tests/solidity/hardhat-ignition-examples-main/contracts/BasicDeployments.sol index 3da59ea..99faa6f 100644 --- a/tests/solidity/hardhat-ignition-examples-main/contracts/BasicDeployments.sol +++ b/tests/solidity/hardhat-ignition-examples-main/contracts/BasicDeployments.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.23; contract HelloWorld { string public message; @@ -18,8 +18,7 @@ contract WrappedHelloWorld { } function message() public view returns (string memory) { - return inner.message(); + return inner.message - } } diff --git a/tests/solidity/hardhat-ignition-examples-main/contracts/ReceivesEth.sol b/tests/solidity/hardhat-ignition-examples-main/contracts/ReceivesEth.sol index 01e5948..66d35e5 100644 --- a/tests/solidity/hardhat-ignition-examples-main/contracts/ReceivesEth.sol +++ b/tests/solidity/hardhat-ignition-examples-main/contracts/ReceivesEth.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.23; contract ReceivesEth { - uint public amount = 1 ether; + uint public amount = 1 et; receive() external payable { require(msg.value == amount, "Wrong amount"); diff --git a/tests/solidity/hardhat-ignition-examples-main/hardhat.config.js b/tests/solidity/hardhat-ignition-examples-main/hardhat.config.ts similarity index 78% rename from tests/solidity/hardhat-ignition-examples-main/hardhat.config.js rename to tests/solidity/hardhat-ignition-examples-main/hardhat.config.ts index 2cdfed1..bd9476c 100644 --- a/tests/solidity/hardhat-ignition-examples-main/hardhat.config.js +++ b/tests/solidity/hardhat-ignition-examples-main/hardhat.config.ts @@ -1,4 +1,4 @@ /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { - solidity: "0.8.19", + solidity: "0.8.23", };