diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierOptions.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierOptions.cs index 8560c6922..e8f6b778d 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierOptions.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierOptions.cs @@ -39,17 +39,11 @@ public class CSharpierOptions )] public string? CustomPath { get; set; } - [Category("CSharpier - Developer")] - [DisplayName("Use CSharpier Server")] - [Description("Use http communication to csharpier - Experimental as of 0.27.2")] - public bool UseServer { get; set; } - protected void LoadFrom(CSharpierOptions newInstance) { this.SolutionRunOnSave = newInstance.SolutionRunOnSave; this.GlobalRunOnSave = newInstance.GlobalRunOnSave; this.GlobalLogDebugMessages = newInstance.GlobalLogDebugMessages; - this.UseServer = newInstance.UseServer; this.CustomPath = newInstance.CustomPath; } @@ -124,7 +118,6 @@ await LoadOptionsFromFile( newInstance.GlobalRunOnSave = o.RunOnSave; newInstance.GlobalLogDebugMessages = o.LogDebugMessages; newInstance.CustomPath = o.CustomPath; - newInstance.UseServer = o.UseServer; } ); @@ -179,7 +172,6 @@ await SaveOptions( RunOnSave = this.GlobalRunOnSave, LogDebugMessages = this.GlobalLogDebugMessages, CustomPath = this.CustomPath, - UseServer = this.UseServer } ); } @@ -214,7 +206,6 @@ private class OptionsDto public bool? RunOnSave { get; set; } public bool LogDebugMessages { get; set; } public string? CustomPath { get; set; } - public bool UseServer { get; set; } } } } diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessPipeMultipleFiles.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessPipeMultipleFiles.cs index 60aff8857..c00338168 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessPipeMultipleFiles.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessPipeMultipleFiles.cs @@ -2,9 +2,7 @@ using System.Diagnostics; using System.IO; using System.Text; -using System.Threading; using System.Threading.Tasks; -using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; using Process = System.Diagnostics.Process; namespace CSharpier.VisualStudio @@ -16,10 +14,18 @@ public class CSharpierProcessPipeMultipleFiles : ICSharpierProcess private readonly string csharpierPath; private StreamWriter standardIn; - public CSharpierProcessPipeMultipleFiles(string csharpierPath, Logger logger) + public string Version { get; } + public bool ProcessFailedToStart { get; private set; } + + public CSharpierProcessPipeMultipleFiles( + string csharpierPath, + string version, + Logger logger + ) { this.logger = logger; this.csharpierPath = csharpierPath; + this.Version = version; this.StartProcess(); @@ -29,8 +35,6 @@ public CSharpierProcessPipeMultipleFiles(string csharpierPath, Logger logger) this.FormatFile("public class ClassName { }", "Test.cs"); } - public bool ProcessFailedToStart { get; set; } - private void StartProcess() { try diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessProvider.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessProvider.cs index 84a7ace4c..bbed930f3 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessProvider.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessProvider.cs @@ -217,11 +217,22 @@ private ICSharpierProcess SetupCSharpierProcess(string directory, string version var installedVersion = new Version(version); var pipeFilesVersion = new Version("0.12.0"); - if (CSharpierOptions.Instance.UseServer) + var serverVersion = new Version("0.28.0"); + ICSharpierProcess cSharpierProcess; + + if (installedVersion.CompareTo(serverVersion) >= 0) + { + cSharpierProcess = new CSharpierProcessServer(customPath, version, this.logger); + } + else if (installedVersion.CompareTo(pipeFilesVersion) >= 0) { - return new CSharpierProcessServer(customPath, this.logger); + cSharpierProcess = new CSharpierProcessPipeMultipleFiles( + customPath, + version, + this.logger + ); } - if (installedVersion.CompareTo(pipeFilesVersion) < 0) + else { if (!this.warnedForOldVersion) { @@ -231,18 +242,19 @@ private ICSharpierProcess SetupCSharpierProcess(string directory, string version this.warnedForOldVersion = true; } - return new CSharpierProcessSingleFile(customPath, this.logger); + cSharpierProcess = new CSharpierProcessSingleFile( + customPath, + version, + this.logger + ); } - var csharpierProcess = new CSharpierProcessPipeMultipleFiles( - customPath, - this.logger - ); - if (csharpierProcess.ProcessFailedToStart) + + if (cSharpierProcess.ProcessFailedToStart) { this.DisplayFailureMessage(); } - return csharpierProcess; + return cSharpierProcess; } catch (Exception ex) { diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessServer.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessServer.cs index a36b7b576..c83514b46 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessServer.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessServer.cs @@ -2,22 +2,27 @@ using System.Diagnostics; using System.IO; using System.Net; +using System.Text; using System.Threading.Tasks; using CSharpier.VisualStudio; using Newtonsoft.Json; -public class CSharpierProcessServer : ICSharpierProcess, IDisposable +public class CSharpierProcessServer : ICSharpierProcess2, IDisposable { private readonly string csharpierPath; private readonly Logger logger; private int port; private Process? process; - public bool ProcessFailedToStart; + public bool ProcessFailedToStart { get; private set; } - public CSharpierProcessServer(string csharpierPath, Logger logger) + public string Version { get; } + + public CSharpierProcessServer(string csharpierPath, string version, Logger logger) { this.logger = logger; this.csharpierPath = csharpierPath; + this.Version = version; + this.StartProcess(); this.logger.Debug("Warm CSharpier with initial format"); @@ -79,15 +84,21 @@ private void StartProcess() } public string FormatFile(string content, string filePath) + { + var parameter = new FormatFileParameter { fileName = filePath, fileContents = content }; + + var result = this.formatFile(parameter); + return result?.formattedFile ?? string.Empty; + } + + public FormatFileResult? formatFile(FormatFileParameter parameter) { if (this.ProcessFailedToStart) { this.logger.Warn("CSharpier process failed to start. Formatting cannot occur."); - return ""; + return null; } - var data = new FormatFileDto { fileContents = content, fileName = filePath }; - var url = "http://localhost:" + this.port + "/format"; try @@ -98,23 +109,26 @@ public string FormatFile(string content, string filePath) using (var streamWriter = new StreamWriter(request.GetRequestStream())) { - streamWriter.Write(JsonConvert.SerializeObject(data)); + streamWriter.Write(JsonConvert.SerializeObject(parameter)); } var response = (HttpWebResponse)request.GetResponse(); if (response.StatusCode != HttpStatusCode.OK) { + this.logger.Warn( + "Csharpier server returned non-200 status code of " + response.StatusCode + ); response.Close(); - return ""; + return null; } - using (var streamReader = new StreamReader(response.GetResponseStream())) + using (var streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { var result = JsonConvert.DeserializeObject( streamReader.ReadToEnd() ); - return result.formattedFile ?? ""; + return result; } } catch (Exception e) @@ -122,22 +136,11 @@ public string FormatFile(string content, string filePath) this.logger.Warn("Failed posting to the csharpier server. " + e); } - return ""; + return null; } public void Dispose() { - this.process?.Dispose(); - } - - private class FormatFileDto - { - public string fileContents; - public string fileName; - } - - private class FormatFileResult - { - public string? formattedFile; + this.process?.Kill(); } } diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessSingleFile.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessSingleFile.cs index e2b0de62d..aeafbbaa1 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessSingleFile.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/CSharpierProcessSingleFile.cs @@ -8,10 +8,14 @@ public class CSharpierProcessSingleFile : ICSharpierProcess private readonly string csharpierPath; private readonly Logger logger; - public CSharpierProcessSingleFile(string csharpierPath, Logger logger) + public string Version { get; } + public bool ProcessFailedToStart => false; + + public CSharpierProcessSingleFile(string csharpierPath, string version, Logger logger) { this.csharpierPath = csharpierPath; this.logger = logger; + this.Version = version; } public string FormatFile(string content, string fileName) diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/FormattingService.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/FormattingService.cs index 28619bf05..79b8726a6 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/FormattingService.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/FormattingService.cs @@ -49,32 +49,79 @@ public void Format(Document document) var endPoint = textDocument.EndPoint.CreateEditPoint(); var text = startPoint.GetText(endPoint); - this.logger.Info("Formatting started for " + document.FullName + "."); - var stopwatch = Stopwatch.StartNew(); + var csharpierProcess = this.cSharpierProcessProvider.GetProcessFor(document.FullName); - var newText = this - .cSharpierProcessProvider.GetProcessFor(document.FullName) - .FormatFile(text, document.FullName); + this.logger.Info( + "Formatting started for " + + document.FullName + + " using CSharpier " + + csharpierProcess.Version + ); + var stopwatch = Stopwatch.StartNew(); - this.logger.Info("Formatted in " + stopwatch.ElapsedMilliseconds + "ms"); - if (string.IsNullOrEmpty(newText) || newText.Equals(text)) + void UpdateText(string formattedText) { - this.logger.Debug( - "Skipping write because " - + ( - string.IsNullOrEmpty(newText) - ? "result is empty" - : "current document equals result" - ) + startPoint.ReplaceText( + endPoint, + formattedText, + (int)vsEPReplaceTextOptions.vsEPReplaceTextKeepMarkers ); - return; } - startPoint.ReplaceText( - endPoint, - newText, - (int)vsEPReplaceTextOptions.vsEPReplaceTextKeepMarkers - ); + if (csharpierProcess is ICSharpierProcess2 csharpierProcess2) + { + var parameter = new FormatFileParameter + { + fileContents = text, + fileName = document.FullName + }; + var result = csharpierProcess2.formatFile(parameter); + + this.logger.Info("Formatted in " + stopwatch.ElapsedMilliseconds + "ms"); + + if (result == null) + { + return; + } + + switch (result.status) + { + case Status.Formatted: + UpdateText(result.formattedFile); + break; + case Status.Ignored: + this.logger.Info("File is ignored by csharpier cli."); + break; + case Status.Failed: + this.logger.Warn( + "CSharpier cli failed to format the file and returned the following error: " + + result.errorMessage + ); + break; + } + } + else + { + var result = csharpierProcess.FormatFile(text, document.FullName); + + this.logger.Info("Formatted in " + stopwatch.ElapsedMilliseconds + "ms"); + + if (string.IsNullOrEmpty(result) || result.Equals(text)) + { + this.logger.Debug( + "Skipping write because " + + ( + string.IsNullOrEmpty(result) + ? "result is empty" + : "current document equals result" + ) + ); + } + else + { + UpdateText(result); + } + } } public bool ProcessSupportsFormatting(Document document) => diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/ICSharpierProcess.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/ICSharpierProcess.cs index 82193c8a6..a48485f4f 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/ICSharpierProcess.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/ICSharpierProcess.cs @@ -2,7 +2,34 @@ namespace CSharpier.VisualStudio { public interface ICSharpierProcess { + string Version { get; } + bool ProcessFailedToStart { get; } string FormatFile(string content, string fileName); void Dispose(); } + + public interface ICSharpierProcess2 : ICSharpierProcess + { + FormatFileResult? formatFile(FormatFileParameter parameter); + } + + public class FormatFileParameter + { + public string fileContents; + public string fileName; + } + + public class FormatFileResult + { + public string formattedFile; + public Status status; + public string errorMessage; + } + + public enum Status + { + Formatted, + Ignored, + Failed + } } diff --git a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/NullCSharpierProcess.cs b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/NullCSharpierProcess.cs index 62380183b..74b2e1a40 100644 --- a/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/NullCSharpierProcess.cs +++ b/Src/CSharpier.VisualStudio/CSharpier.VisualStudioShared/NullCSharpierProcess.cs @@ -6,6 +6,9 @@ public class NullCSharpierProcess : ICSharpierProcess private NullCSharpierProcess() { } + public string Version => "NULL"; + public bool ProcessFailedToStart => false; + public string FormatFile(string content, string fileName) { return string.Empty;