-
-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Making plugin version aware and detect if csharpier is installed
- Loading branch information
Showing
10 changed files
with
283 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
...er.Rider/src/main/java/com/intellij/csharpierrider/CSharpierProcessPipeMultipleFiles.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package com.intellij.csharpierrider; | ||
|
||
import com.esotericsoftware.minlog.Log; | ||
import com.intellij.openapi.Disposable; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.InputStreamReader; | ||
import java.io.OutputStream; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
// TODO only work with c#? | ||
// TODO workflows? | ||
|
||
public class CSharpierProcessPipeMultipleFiles implements ICSharpierProcess, Disposable { | ||
Logger LOG = Logger.getInstance(CSharpierProcessPipeMultipleFiles.class); | ||
String csharpierPath; | ||
|
||
Process process = null; | ||
OutputStream stdin; | ||
BufferedReader stdOut; | ||
BufferedReader stdError; | ||
|
||
public CSharpierProcessPipeMultipleFiles(String csharpierPath) { | ||
this.csharpierPath = csharpierPath; | ||
try { | ||
process = new ProcessBuilder("dotnet", csharpierPath, "--pipe-multiple-files") | ||
.start(); | ||
|
||
stdin = process.getOutputStream(); | ||
stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); | ||
stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); | ||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
} | ||
|
||
this.formatFile("public class ClassName { }", "Test.cs"); | ||
} | ||
|
||
@Override | ||
public String formatFile(String content, String filePath) { | ||
|
||
try { | ||
LOG.info(filePath); | ||
// TODO we need the real file path | ||
stdin.write("C:\\projects\\csharpier\\Src\\CSharpier\\DocSerializer.cs".getBytes()); | ||
stdin.write('\u0003'); | ||
stdin.write(content.getBytes()); | ||
stdin.write('\u0003'); | ||
stdin.flush(); | ||
|
||
StringBuilder output = new StringBuilder(); | ||
StringBuilder errorOutput = new StringBuilder(); | ||
|
||
AtomicBoolean done = new AtomicBoolean(false); | ||
|
||
Thread outputReaderThread = CreateReadingThread(stdOut, output, done); | ||
outputReaderThread.start(); | ||
|
||
Thread errorReaderThread = CreateReadingThread(stdError, errorOutput, done); | ||
errorReaderThread.start(); | ||
|
||
while (!done.get()) { | ||
Thread.sleep(1); | ||
} | ||
|
||
errorReaderThread.interrupt(); | ||
outputReaderThread.interrupt(); | ||
|
||
Log.info("Output:"); | ||
Log.info(output.toString()); | ||
Log.info("Error:"); | ||
Log.info(errorOutput.toString()); | ||
|
||
return output.toString(); | ||
|
||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
e.printStackTrace(); | ||
return ""; | ||
} | ||
} | ||
|
||
private Thread CreateReadingThread(BufferedReader reader, StringBuilder stringBuilder, AtomicBoolean done) { | ||
return new Thread(() -> { | ||
try { | ||
var nextCharacter = reader.read(); | ||
while (nextCharacter != -1) { | ||
LOG.info("Got Error " + nextCharacter); | ||
if (nextCharacter == '\u0003') { | ||
done.set(true); | ||
return; | ||
} | ||
stringBuilder.append((char) nextCharacter); | ||
nextCharacter = reader.read(); | ||
} | ||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
done.set(true); | ||
} | ||
}); | ||
} | ||
|
||
@Override | ||
public void dispose() { | ||
process.destroy(); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
...CSharpier.Rider/src/main/java/com/intellij/csharpierrider/CSharpierProcessSingleFile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package com.intellij.csharpierrider; | ||
|
||
import com.esotericsoftware.minlog.Log; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.InputStreamReader; | ||
import java.io.OutputStream; | ||
|
||
public class CSharpierProcessSingleFile implements ICSharpierProcess { | ||
Logger LOG = Logger.getInstance(CSharpierProcessSingleFile.class); | ||
String csharpierPath; | ||
|
||
public CSharpierProcessSingleFile(String csharpierPath) { | ||
this.csharpierPath = csharpierPath; | ||
} | ||
|
||
@Override | ||
public String formatFile(String content, String fileName) { | ||
try { | ||
ProcessBuilder processBuilder = new ProcessBuilder("dotnet", csharpierPath, "--write-stdout"); | ||
processBuilder.redirectErrorStream(true); | ||
Process process = processBuilder.start(); | ||
|
||
OutputStream stdin = process.getOutputStream(); | ||
BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); | ||
|
||
stdin.write(content.getBytes()); | ||
stdin.close(); | ||
|
||
StringBuilder output = new StringBuilder(); | ||
|
||
var nextCharacter = stdOut.read(); | ||
while (nextCharacter != -1) { | ||
LOG.info("Got Output " + nextCharacter); | ||
output.append((char)nextCharacter); | ||
nextCharacter = stdOut.read(); | ||
} | ||
|
||
String result = output.toString(); | ||
|
||
if (process.exitValue() == 0 && !result.contains("Failed to compile so was not formatted.")) { | ||
return result; | ||
} | ||
else { | ||
Log.error(result); | ||
} | ||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
} | ||
|
||
return ""; | ||
} | ||
} |
157 changes: 75 additions & 82 deletions
157
Src/CSharpier.Rider/src/main/java/com/intellij/csharpierrider/CSharpierService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,107 @@ | ||
package com.intellij.csharpierrider; | ||
|
||
import com.esotericsoftware.minlog.Log; | ||
import com.intellij.notification.Notification; | ||
import com.intellij.notification.NotificationGroupManager; | ||
import com.intellij.notification.NotificationType; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
import com.intellij.openapi.project.Project; | ||
import org.apache.maven.artifact.versioning.ComparableVersion; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.io.OutputStream; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
// TODO https://plugins.jetbrains.com/docs/intellij/disposers.html#choosing-a-disposable-parent | ||
import java.io.InputStream; | ||
import java.util.Scanner; | ||
|
||
public class CSharpierService { | ||
Logger LOG = Logger.getInstance(ReformatWithCSharpierAction.class); | ||
Process process = null; | ||
OutputStream stdin = null; | ||
BufferedReader stdOut = null; | ||
BufferedReader stdError = null; | ||
String csharpierPath; | ||
ICSharpierProcess csharpierProcess; | ||
Project project; | ||
|
||
public CSharpierService(@NotNull Project project) { | ||
this.project = project; | ||
csharpierPath = getCSharpierPath(); | ||
|
||
public CSharpierService() { | ||
Log.info("Using command dotnet " + csharpierPath); | ||
|
||
csharpierProcess = setupCSharpierProcess(); | ||
} | ||
|
||
public String getCSharpierPath() { | ||
try { | ||
// TODO | ||
String csharpierPath = "C:\\projects\\csharpier\\Src\\CSharpier.Cli\\bin\\Debug\\net6.0\\dotnet-csharpier.dll"; | ||
String csharpierDebugPath = "C:\\projects\\csharpier\\Src\\CSharpier.Cli\\bin\\Debug\\net6.0\\dotnet-csharpier.dll"; | ||
String csharpierReleasePath = csharpierDebugPath.replace("Debug", "Release"); | ||
|
||
process = new ProcessBuilder("dotnet", csharpierPath, "--pipe-multiple-files").start(); | ||
} catch (IOException e) { | ||
LOG.error("error", e); | ||
e.printStackTrace(); | ||
if (new File(csharpierDebugPath).exists()) { | ||
return csharpierDebugPath; | ||
} else if (new File(csharpierReleasePath).exists()) { | ||
return csharpierReleasePath; | ||
} | ||
} catch (Exception ex) { | ||
Log.debug("Could not find local csharpier " + ex.getMessage()); | ||
} | ||
stdin = process.getOutputStream(); | ||
stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); | ||
stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); | ||
|
||
return "csharpier"; | ||
} | ||
|
||
@NotNull | ||
static CSharpierService getInstance(@NotNull Project project) { | ||
return project.getService(CSharpierService.class); | ||
} | ||
|
||
public String format(@NotNull String content, @NotNull String filePath) { | ||
StringBuilder output = new StringBuilder(); | ||
StringBuilder errorOutput = new StringBuilder(); | ||
public String execCmd(String cmd) { | ||
String result = null; | ||
try (InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream(); | ||
Scanner s = new Scanner(inputStream).useDelimiter("\\A") | ||
) { | ||
result = s.hasNext() ? s.next() : null; | ||
} catch (IOException e) { | ||
Log.error(e.getMessage()); | ||
e.printStackTrace(); | ||
} | ||
return result; | ||
} | ||
|
||
private ICSharpierProcess setupCSharpierProcess() { | ||
try { | ||
LOG.info(filePath); | ||
// TODO real path | ||
stdin.write("C:\\projects\\csharpier\\Src\\CSharpier\\DocSerializer.cs".getBytes()); | ||
stdin.write('\u0003'); | ||
stdin.write(content.getBytes()); | ||
stdin.write('\u0003'); | ||
stdin.flush(); | ||
|
||
int end = '\u0003'; | ||
|
||
AtomicBoolean done = new AtomicBoolean(false); | ||
|
||
Thread outStreamReader = new Thread(() -> { | ||
try { | ||
var nextCharacter = stdOut.read(); | ||
while (nextCharacter != -1) { | ||
LOG.info("Got Output " + nextCharacter); | ||
if (nextCharacter == end) { | ||
done.set(true); | ||
return; | ||
} | ||
output.append((char)nextCharacter); | ||
nextCharacter = stdOut.read(); | ||
} | ||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
e.printStackTrace(); | ||
} | ||
}); | ||
outStreamReader.start(); | ||
|
||
Thread errorStreamReader = new Thread(() -> { | ||
try { | ||
var nextCharacter = stdError.read(); | ||
while (nextCharacter != -1) { | ||
LOG.info("Got Error " + nextCharacter); | ||
errorOutput.append((char)nextCharacter); | ||
nextCharacter = stdError.read(); | ||
} | ||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
e.printStackTrace(); | ||
String version = execCmd("dotnet " + this.csharpierPath + " --version"); | ||
Log.info("CSharpier version: " + version); | ||
if (version == null) { | ||
this.displayInstallNeededMessage(); | ||
} | ||
else { | ||
ComparableVersion installedVersion = new ComparableVersion(version); | ||
ComparableVersion pipeFilesVersion = new ComparableVersion("0.12.0"); | ||
if (installedVersion.compareTo(pipeFilesVersion) < 0) { | ||
String content = "Please upgrade to CSharpier >= 0.12.0 for bug fixes and improved formatting speed."; | ||
NotificationGroupManager.getInstance().getNotificationGroup("CSharpier") | ||
.createNotification(content, NotificationType.INFORMATION) | ||
.notify(project); | ||
|
||
return new CSharpierProcessSingleFile(this.csharpierPath); | ||
} | ||
}); | ||
|
||
errorStreamReader.start(); | ||
|
||
int lastLength = errorOutput.length(); | ||
while (!done.get()) { | ||
Thread.sleep(1); | ||
return new CSharpierProcessPipeMultipleFiles(this.csharpierPath); | ||
} | ||
} catch (Exception ex) { | ||
LOG.error(ex); | ||
} | ||
|
||
errorStreamReader.interrupt(); | ||
return new NullCSharpierProcess(); | ||
} | ||
|
||
} catch (Exception e) { | ||
LOG.error("error", e); | ||
e.printStackTrace(); | ||
} | ||
private void displayInstallNeededMessage() { | ||
Notification notification = NotificationGroupManager.getInstance().getNotificationGroup("CSharpier") | ||
.createNotification("CSharpier must be installed globally to support formatting.", NotificationType.WARNING); | ||
|
||
Log.info("Output:"); | ||
Log.info(output.toString()); | ||
Log.info("Error:"); | ||
Log.info(errorOutput.toString()); | ||
// TODO why can't an action be displayed in this??? | ||
// notification.addAction(new EditAction()); | ||
|
||
return output.toString(); | ||
notification.notify(project); | ||
} | ||
|
||
public String format(@NotNull String content, @NotNull String filePath) { | ||
return this.csharpierProcess.formatFile(content, filePath); | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
Src/CSharpier.Rider/src/main/java/com/intellij/csharpierrider/CSharpierStartup.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.intellij.csharpierrider; | ||
|
||
import com.intellij.openapi.project.DumbAware; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.startup.StartupActivity; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class CSharpierStartup implements StartupActivity, DumbAware { | ||
@Override | ||
public void runActivity(@NotNull Project project) { | ||
CSharpierService.getInstance(project); | ||
} | ||
} |
Oops, something went wrong.