Skip to content

Commit

Permalink
Adding support for csharpier server
Browse files Browse the repository at this point in the history
  • Loading branch information
belav committed Feb 23, 2024
1 parent bcc992f commit 7744ebc
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="83d6b6a0-9e25-4034-80f3-38445d8a8837" Version="1.5.1" Language="en-US" Publisher="CSharpier" />
<Identity Id="83d6b6a0-9e25-4034-80f3-38445d8a8837" Version="1.5.2" Language="en-US" Publisher="CSharpier" />
<DisplayName>CSharpier</DisplayName>
<Description xml:space="preserve">CSharpier is an opinionated code formatter for c#. It uses Roslyn to parse your code and re-prints it using its own rules.</Description>
<MoreInfo>https://github.com/belav/csharpier</MoreInfo>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="edd8b38c-baa1-46c6-b82e-1da7a0ba597b" Version="1.5.1" Language="en-US" Publisher="CSharpier" />
<Identity Id="edd8b38c-baa1-46c6-b82e-1da7a0ba597b" Version="1.5.2" Language="en-US" Publisher="CSharpier" />
<DisplayName>CSharpier 2019</DisplayName>
<Description xml:space="preserve">CSharpier is an opinionated code formatter for c#. It uses Roslyn to parse your code and re-prints it using its own rules.</Description>
<MoreInfo>https://github.com/belav/csharpier</MoreInfo>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)CSharpierPackage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpierProcessServer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpierProcessPipeMultipleFiles.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpierProcessSingleFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CSharpierProcessProvider.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ 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;
}

Expand Down Expand Up @@ -118,6 +124,7 @@ await LoadOptionsFromFile(
newInstance.GlobalRunOnSave = o.RunOnSave;
newInstance.GlobalLogDebugMessages = o.LogDebugMessages;
newInstance.CustomPath = o.CustomPath;
newInstance.UseServer = o.UseServer;
}
);

Expand Down Expand Up @@ -171,7 +178,8 @@ await SaveOptions(
{
RunOnSave = this.GlobalRunOnSave,
LogDebugMessages = this.GlobalLogDebugMessages,
CustomPath = this.CustomPath
CustomPath = this.CustomPath,
UseServer = this.UseServer
}
);
}
Expand Down Expand Up @@ -205,7 +213,8 @@ private class OptionsDto
{
public bool? RunOnSave { get; set; }
public bool LogDebugMessages { get; set; }
public string CustomPath { get; set; }
public string? CustomPath { get; set; }
public bool UseServer { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,18 @@ IProgress<ServiceProgressData> progress
Logger.Instance.Error(ex);
}

SolutionEvents.OnAfterOpenSolution += HandleOpenSolution;
SolutionEvents.OnAfterOpenSolution += this.HandleOpenSolution;
}

private void HandleOpenSolution(object sender, OpenSolutionEventArgs e)
{
CSharpierOptions.Instance.Load();
}

protected override void Dispose(bool disposing)
{
CSharpierProcessProvider.GetInstance(this).KillRunningProcesses();
base.Dispose(disposing);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ private ICSharpierProcess SetupCSharpierProcess(string directory, string version

var installedVersion = new Version(version);
var pipeFilesVersion = new Version("0.12.0");
if (CSharpierOptions.Instance.UseServer)
{
return new CSharpierProcessServer(customPath, this.logger);
}
if (installedVersion.CompareTo(pipeFilesVersion) < 0)
{
if (!this.warnedForOldVersion)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using CSharpier.VisualStudio;
using Newtonsoft.Json;

public class CSharpierProcessServer : ICSharpierProcess, IDisposable
{
private readonly string csharpierPath;
private readonly Logger logger;
private int port;
private Process? process;
public bool ProcessFailedToStart;

public CSharpierProcessServer(string csharpierPath, Logger logger)
{
this.logger = logger;
this.csharpierPath = csharpierPath;
this.StartProcess();

this.logger.Debug("Warm CSharpier with initial format");
// warm by formatting a file twice, the 3rd time is when it gets really fast
this.FormatFile("public class ClassName { }", "/Temp/Test.cs");
this.FormatFile("public class ClassName { }", "/Temp/Test.cs");
}

private void StartProcess()
{
try
{
var processStartInfo = new ProcessStartInfo(this.csharpierPath, "--server")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
Environment = { ["DOTNET_NOLOGO"] = "1" }
};
this.process = Process.Start(processStartInfo);

var output = string.Empty;

var task = Task.Run(() =>
{
output = this.process!.StandardOutput.ReadLine();
});

if (!task.Wait(TimeSpan.FromSeconds(2)))
{
this.logger.Warn(
"Spawning the csharpier server timed out. Formatting cannot occur."
);
this.process!.Kill();
return;
}

if (this.process!.HasExited)
{
this.logger.Warn(
"Spawning the csharpier server failed because it exited. "
+ this.process!.StandardError.ReadToEnd()
);
this.ProcessFailedToStart = true;
return;
}

var portString = output.Replace("Started on ", "");
this.port = int.Parse(portString);

this.logger.Debug("Connecting via port " + portString);
}
catch (Exception e)
{
this.logger.Warn("Failed to spawn the needed csharpier server." + e);
this.ProcessFailedToStart = true;
}
}

public string FormatFile(string content, string filePath)
{
if (this.ProcessFailedToStart)
{
this.logger.Warn("CSharpier process failed to start. Formatting cannot occur.");
return "";
}

var data = new FormatFileDto { fileContents = content, fileName = filePath };

var url = "http://localhost:" + this.port + "/format";

try
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";

using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(JsonConvert.SerializeObject(data));
}

var response = (HttpWebResponse)request.GetResponse();

if (response.StatusCode != HttpStatusCode.OK)
{
response.Close();
return "";
}

using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = JsonConvert.DeserializeObject<FormatFileResult>(
streamReader.ReadToEnd()
);
return result.formattedFile ?? "";
}
}
catch (Exception e)
{
this.logger.Warn("Failed posting to the csharpier server. " + e);
}

return "";
}

public void Dispose()
{
this.process?.Dispose();
}

private class FormatFileDto
{
public string fileContents;
public string fileName;
}

private class FormatFileResult
{
public string? formattedFile;
}
}
5 changes: 4 additions & 1 deletion Src/CSharpier.VisualStudio/ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## [1.5.1]
## [1.5.2]
- Experimental support for CSharpier Server

## [1.5.1]
- Fix for occasional NRE

## [1.5.0]
Expand Down
23 changes: 14 additions & 9 deletions Src/CSharpier.VisualStudio/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
This extension adds support for [CSharpier](https://github.com/belav/csharpier), an opinionated code formatter for c#.
It uses Roslyn to parse your code and re-prints it using its own rules.
The printing process was ported from [prettier](https://prettier.io/) but has evolved over time.
This extension makes use of the dotnet tool [CSharpier](https://github.com/belav/csharpier) to format your code and is versioned independently.

CSharpier is an opinionated code formatter for c#. It uses Roslyn to parse your code and re-prints it using its own rules. The printing process was ported from [prettier](https://prettier.io/) but has evolved over time.

## CSharpier Version
The extension determines which version of csharpier is needed to format a given file by looking for a dotnet manifest file. If one is not found it looks for a globally installed version of CSharpier.

## Usage

To use it:
- Install csharpier globally with `dotnet tool install -g csharpier`
- Use the `Reformat with CSharpier` right click context menu action.
- Optionally configure a keyboard shortcut for `EditorContextMenus.CodeWindow.ReformatWithCSharpier`
- Optionally configure `Reformat with CSharpier on Save` under Tools | Options | CSharpier | General
- This option can be configured at the solution level or at the global level.

Please report any [issues](https://github.com/belav/csharpier/issues)

### Troubleshooting
CSharpier will log messages and errors to Output | Show output from: CSharpier
Debug logging can be turned on under Tools | Options | CSharpier | Log Debug Messages
CSharpier will log messages and errors to Output | Show output from: CSharpier

Debug logging can be turned on under Tools | Options | CSharpier | Log Debug Messages

The extension installs CSharpier to `C:\Users\{CurrentUser}\AppData\Local\CSharpier`. Closing the extension and deleting this folder can fix issues with bad installs.

Please report any [issues](https://github.com/belav/csharpier/issues)

0 comments on commit 7744ebc

Please sign in to comment.