From b91a8bbfe7428eea38574e93da8b3411568f6c06 Mon Sep 17 00:00:00 2001 From: Bela VanderVoort Date: Sun, 27 Aug 2023 16:27:16 -0500 Subject: [PATCH] Only wait 3 seconds for csharpier to format, otherwise kill it and restart it. (#940) * Only wait 3 seconds for csharpier to format, otherwise kill it and restart it. closes #926 * Better desc for plugin on jetbrains site * adding note about deprecation so it can be fixed later --- Src/CSharpier.Rider/CHANGELOG.md | 3 + Src/CSharpier.Rider/README.md | 4 +- Src/CSharpier.Rider/gradle.properties | 2 +- .../CSharpierProcessPipeMultipleFiles.java | 80 ++++++++++++------- .../ReformatWithCSharpierOnSave.java | 1 + 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/Src/CSharpier.Rider/CHANGELOG.md b/Src/CSharpier.Rider/CHANGELOG.md index 214e64bd1..6bd207040 100644 --- a/Src/CSharpier.Rider/CHANGELOG.md +++ b/Src/CSharpier.Rider/CHANGELOG.md @@ -2,6 +2,9 @@ # csharpier-rider Changelog +## [1.3.9] +- Wait at most 3 seconds for csharpier to format otherwise consider it hung and restart it. + ## [1.3.8] - Add displayName attribute to CSharpier options window to speed up Settings dialog. diff --git a/Src/CSharpier.Rider/README.md b/Src/CSharpier.Rider/README.md index a6c0b30a9..2f9f30209 100644 --- a/Src/CSharpier.Rider/README.md +++ b/Src/CSharpier.Rider/README.md @@ -11,7 +11,6 @@ To use it: - Optionally configure CSharpier to `Run on Save` under Preferences/Settings | Tools | CSharpier Please report any [issues](https://github.com/belav/csharpier/issues) - ## Installation @@ -20,7 +19,6 @@ Please report any [issues](https://github.com/belav/csharpier/issues) Settings/Preferences > Plugins > Marketplace > Search for "CSharpier" > Install Plugin --- -Plugin based on the [IntelliJ Platform Plugin Template][template]. ## Troubleshooting @@ -33,3 +31,5 @@ Plugin based on the [IntelliJ Platform Plugin Template][template]. - Add entry for "#com.intellij.csharpier.CSharpierLogger" - Restart Rider + + diff --git a/Src/CSharpier.Rider/gradle.properties b/Src/CSharpier.Rider/gradle.properties index b6032d139..f039a371f 100644 --- a/Src/CSharpier.Rider/gradle.properties +++ b/Src/CSharpier.Rider/gradle.properties @@ -4,7 +4,7 @@ pluginGroup = com.intellij.csharpier pluginName = csharpier # SemVer format -> https://semver.org -pluginVersion = 1.3.8 +pluginVersion = 1.3.9 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierProcessPipeMultipleFiles.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierProcessPipeMultipleFiles.java index c601b6361..d8c8ce2e0 100644 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierProcessPipeMultipleFiles.java +++ b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/CSharpierProcessPipeMultipleFiles.java @@ -15,6 +15,8 @@ import java.util.concurrent.atomic.AtomicBoolean; public class CSharpierProcessPipeMultipleFiles implements ICSharpierProcess, Disposable { + private final boolean useUtf8; + private final String csharpierPath; Logger logger = CSharpierLogger.getInstance(); Process process = null; @@ -22,12 +24,18 @@ public class CSharpierProcessPipeMultipleFiles implements ICSharpierProcess, Dis BufferedReader stdOut; public CSharpierProcessPipeMultipleFiles(String csharpierPath, boolean useUtf8) { + this.csharpierPath = csharpierPath; + this.useUtf8 = useUtf8; + this.startProcess(); + } + + private void startProcess() { try { - var processBuilder = new ProcessBuilder(csharpierPath, "--pipe-multiple-files"); + var processBuilder = new ProcessBuilder(this.csharpierPath, "--pipe-multiple-files"); processBuilder.environment().put("DOTNET_NOLOGO", "1"); this.process = processBuilder.start(); - var charset = useUtf8 ? "utf-8" : Charset.defaultCharset().toString(); + var charset = this.useUtf8 ? "utf-8" : Charset.defaultCharset().toString(); this.stdin = new OutputStreamWriter(this.process.getOutputStream(), charset); this.stdOut = new BufferedReader(new InputStreamReader(this.process.getInputStream(), charset)); @@ -43,40 +51,56 @@ public CSharpierProcessPipeMultipleFiles(String csharpierPath, boolean useUtf8) @Override public String formatFile(String content, String filePath) { - try { - - this.stdin.write(filePath); - this.stdin.write('\u0003'); - this.stdin.write(content); - this.stdin.write('\u0003'); - this.stdin.flush(); - - var stringBuilder = new StringBuilder(); - - var nextCharacter = this.stdOut.read(); - while (nextCharacter != -1) { - if (nextCharacter == '\u0003') { - break; + var stringBuilder = new StringBuilder(); + + Runnable task = () -> { + try { + this.stdin.write(filePath); + this.stdin.write('\u0003'); + this.stdin.write(content); + this.stdin.write('\u0003'); + this.stdin.flush(); + + var nextCharacter = this.stdOut.read(); + while (nextCharacter != -1) { + if (nextCharacter == '\u0003') { + break; + } + stringBuilder.append((char) nextCharacter); + nextCharacter = this.stdOut.read(); } - stringBuilder.append((char) nextCharacter); - nextCharacter = this.stdOut.read(); + } catch (Exception e) { + this.logger.error(e); + e.printStackTrace(); } + }; - var result = stringBuilder.toString(); + // csharpier will freeze in some instances when "Format on Save" is also installed and the file has compilation errors + // this detects that and recovers from it + var thread = new Thread(task); + thread.start(); + try { + thread.join(3000); + } catch (InterruptedException e) { + // if we interrupt it we shouldn't log it + } - if (result == null || result.isEmpty()) - { - this.logger.info("File is ignored by .csharpierignore or there was an error"); - return ""; - } + if (thread.isAlive()) { + this.logger.warn("CSharpier process appears to be hung, restarting it."); + thread.interrupt(); + this.process.destroy(); + this.startProcess(); + return ""; + } - return result; + var result = stringBuilder.toString(); - } catch (Exception e) { - this.logger.error(e); - e.printStackTrace(); + if (result == null || result.isEmpty()) { + this.logger.info("File is ignored by .csharpierignore or there was an error"); return ""; } + + return result; } @Override diff --git a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierOnSave.java b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierOnSave.java index cb7019f6f..fb5b8975b 100644 --- a/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierOnSave.java +++ b/Src/CSharpier.Rider/src/main/java/com/intellij/csharpier/ReformatWithCSharpierOnSave.java @@ -16,6 +16,7 @@ public class ReformatWithCSharpierOnSave implements AnActionListener { private final Logger logger = CSharpierLogger.getInstance(); public ReformatWithCSharpierOnSave() { + // TODO this is deprecated and should be switched to https://plugins.jetbrains.com/docs/intellij/messaging-infrastructure.html#subscribing-to-a-topic Topics.subscribe(AnActionListener.TOPIC, null, this); }