Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
closes #1109
  • Loading branch information
belav committed Apr 19, 2024
1 parent a2a547a commit ee9f50c
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 42 deletions.
13 changes: 10 additions & 3 deletions Src/CSharpier.VSCode/src/CSharpierProcessPipeMultipleFiles.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import { Logger } from "./Logger";
import { ICSharpierProcess } from "./CSharpierProcess";
import { ICSharpierProcess } from "./ICSharpierProcess";
import { getDotNetRoot } from "./DotNetProvider";
import * as process from "process";

export class CSharpierProcessPipeMultipleFiles implements ICSharpierProcess {
private process: ChildProcessWithoutNullStreams;
private callbacks: ((result: string) => void)[] = [];
private logger: Logger;
private nextFile: string = "";
public processFailedToStart = false;
private processFailedToStart = false;
private version: string;

constructor(logger: Logger, csharpierPath: string, workingDirectory: string) {
constructor(logger: Logger, csharpierPath: string, workingDirectory: string, version: string) {
this.logger = logger;
this.process = this.spawnProcess(csharpierPath, workingDirectory);
this.version = version;

this.logger.debug("Warm CSharpier with initial format");
// warm by formatting a file twice, the 3rd time is when it gets really fast
Expand Down Expand Up @@ -96,4 +99,8 @@ export class CSharpierProcessPipeMultipleFiles implements ICSharpierProcess {
(this.process.stdin as any).pause();
this.process.kill();
}

getVersion(): string {
return this.version;
}
}
42 changes: 28 additions & 14 deletions Src/CSharpier.VSCode/src/CSharpierProcessProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import { Logger } from "./Logger";
import * as path from "path";
import * as semver from "semver";
import * as convert from "xml-js";
import { ICSharpierProcess, NullCSharpierProcess } from "./CSharpierProcess";
import { ICSharpierProcess } from "./ICSharpierProcess";
import { CSharpierProcessSingleFile } from "./CSharpierProcessSingleFile";
import { CSharpierProcessPipeMultipleFiles } from "./CSharpierProcessPipeMultipleFiles";
import * as fs from "fs";
import { InstallerService } from "./InstallerService";
import { CustomPathInstaller } from "./CustomPathInstaller";
import { execDotNet } from "./DotNetProvider";
import { NullCSharpierProcess } from "./NullCSharpierProcess";
import { CSharpierProcessServer } from "./CSharpierProcessServer";
import { ICSharpierProcess2 } from "./ICSharpierProcess";

export class CSharpierProcessProvider implements Disposable {
warnedForOldVersion = false;
Expand Down Expand Up @@ -62,7 +65,7 @@ export class CSharpierProcessProvider implements Disposable {
delete this.warmingByDirectory[directory];
}

public getProcessFor = (filePath: string) => {
public getProcessFor: ICSharpierProcess | ICSharpierProcess2 = (filePath: string) => {
const directory = this.getDirectoryOfFile(filePath);
let version = this.csharpierVersionByDirectory[directory];
if (!version) {
Expand Down Expand Up @@ -218,26 +221,37 @@ export class CSharpierProcessProvider implements Disposable {

this.logger.debug(`Adding new version ${version} process for ${directory}`);

if (semver.lt(version, "0.12.0")) {
let csharpierProcess: ICSharpierProcess;

if (semver.gte(version, "0.28.0")) {
csharpierProcess = new CSharpierProcessServer(
this.logger,
customPath,
directory,
version,
);
} else if (semver.gte(version, "0.12.0")) {
csharpierProcess = new CSharpierProcessPipeMultipleFiles(
this.logger,
customPath,
directory,
version,
);
} else {
if (!this.warnedForOldVersion) {
window.showInformationMessage(
"Please upgrade to CSharpier >= 0.12.0 for bug fixes and improved formatting speed.",
);
this.warnedForOldVersion = true;
}
return new CSharpierProcessSingleFile(this.logger, customPath);
} else {
const csharpierProcess = new CSharpierProcessPipeMultipleFiles(
this.logger,
customPath,
directory,
);
if (csharpierProcess.processFailedToStart) {
this.displayFailureMessage();
}
csharpierProcess = new CSharpierProcessSingleFile(this.logger, customPath, version);
}

return csharpierProcess;
if (csharpierProcess.processFailedToStart) {
this.displayFailureMessage();
}

return csharpierProcess;
} catch (ex: any) {
this.logger.error(ex.output.toString());
this.logger.debug(
Expand Down
163 changes: 163 additions & 0 deletions Src/CSharpier.VSCode/src/CSharpierProcessServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import { Logger } from "./Logger";
import { FormatFileParameter, FormatFileResult, ICSharpierProcess2 } from "./ICSharpierProcess";

export class CSharpierProcessServer implements ICSharpierProcess2 {
private csharpierPath: string;
private logger: Logger;
private port: number = 0;
private process: ChildProcessWithoutNullStreams;
private processFailedToStart = false;
private version: string;

constructor(logger: Logger, csharpierPath: string, workingDirectory: string, version: string) {
this.logger = logger;
this.csharpierPath = csharpierPath;
this.process = this.spawnProcess(csharpierPath, workingDirectory);
this.version = version;

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 spawnProcess(
csharpierPath: string,
workingDirectory: string,
): ChildProcessWithoutNullStreams {
const csharpierProcess = spawn(csharpierPath, ["--server"], {
stdio: "pipe",
cwd: workingDirectory,
env: { ...process.env, DOTNET_NOLOGO: "1" },
});

let output = "";
const regex = /^Started on (\d+)/;

// TODO look at pipe / https://github.com/belav/csharpier/pull/1127/files#diff-844ad2632d6fd1e83ce639f4f1ef23e8dad4f547b7a524b9e1ed715feff04958
csharpierProcess.stdout.on("data", chunk => {
this.logger.debug("Got chunk of size " + chunk.length);
output += chunk;
this.logger.debug("Got " + output);
if (regex.test(output)) {
this.port = parseInt(output.match(regex)![1], 10);
}
});

return csharpierProcess;
}

// 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 async formatFile(content: string, filePath: string): Promise<string> {
const parameter = {
fileName: filePath,
fileContents: content,
};
const result = await this.formatFile2(parameter);
return result?.formattedFile ?? "";
}

public async formatFile2(parameter: FormatFileParameter): Promise<FormatFileResult | null> {
if (this.processFailedToStart) {
this.logger.warn("CSharpier process failed to start. Formatting cannot occur.");
return null;
}

const 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(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 null;
// }
//
// using (var streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
// {
// var result = JsonConvert.DeserializeObject<FormatFileResult>(
// streamReader.ReadToEnd()
// );
// return result;
// }
} catch (e) {
this.logger.warn("Failed posting to the csharpier server. " + e);
}

return null;
}

dispose() {
(this.process.stdin as any).pause();
this.process.kill();
}

getVersion(): string {
return this.version;
}
}
11 changes: 9 additions & 2 deletions Src/CSharpier.VSCode/src/CSharpierProcessSingleFile.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { Logger } from "./Logger";
import { spawn } from "child_process";
import { ICSharpierProcess } from "./CSharpierProcess";
import { ICSharpierProcess } from "./ICSharpierProcess";
import * as path from "path";
import { getDotNetRoot } from "./DotNetProvider";
import * as process from "process";

export class CSharpierProcessSingleFile implements ICSharpierProcess {
private readonly csharpierPath: string;
private logger: Logger;
private version: string;

constructor(logger: Logger, csharpierPath: string) {
constructor(logger: Logger, csharpierPath: string, version: string) {
this.logger = logger;
this.csharpierPath = csharpierPath;
this.version = version;
}

formatFile(content: string, filePath: string): Promise<string> {
Expand Down Expand Up @@ -40,4 +43,8 @@ export class CSharpierProcessSingleFile implements ICSharpierProcess {
}

dispose() {}

getVersion(): string {
return this.version;
}
}
2 changes: 1 addition & 1 deletion Src/CSharpier.VSCode/src/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { ExtensionContext, window, workspace } from "vscode";
import { CSharpierProcessProvider } from "./CSharpierProcessProvider";
import { FormattingService } from "./FormattingService";
import { Logger } from "./Logger";
import { NullCSharpierProcess } from "./CSharpierProcess";
import { findDotNet } from "./DotNetProvider";
import { options } from "./Options";
import { NullCSharpierProcess } from "./NullCSharpierProcess";

export async function activate(context: ExtensionContext) {
if (!workspace.isTrusted) {
Expand Down
Loading

0 comments on commit ee9f50c

Please sign in to comment.