Skip to content
This repository was archived by the owner on Sep 11, 2023. It is now read-only.

Commit 128513a

Browse files
committed
fixed program crashing when compiling (read desc)
In this commit, I changed the way the program handles compilation errors. Previously, if a plugin failed to compile, the program would redirect the errors to a text file, and read them off of there. I believe certain crashes were related to the program trying to read the file at the same time as some other file sync program (like Dropbox, Drive, etc.) while working inside synced directories. Now, the editor reads the compiler process standard output and extracts errors with a Regex in case the compilation was unsuccessful, avoiding to rely on external files.
1 parent c4bb8aa commit 128513a

File tree

1 file changed

+78
-81
lines changed

1 file changed

+78
-81
lines changed

UI/MainWindow/MainWindowSPCompiler.cs

Lines changed: 78 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace SPCode.UI
1717
{
1818
public partial class MainWindow
1919
{
20-
private List<string> ScriptsCompiled;
20+
private List<string> ScriptsCompiled = new();
2121

2222
private readonly List<string> CompiledFileNames = new();
2323
private readonly List<string> CompiledFiles = new();
@@ -40,6 +40,9 @@ public partial class MainWindow
4040

4141
private static readonly Encoding _ansi = Encoding.GetEncoding(1251);
4242

43+
private static readonly RegexOptions _regexOptions = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Multiline;
44+
private readonly Regex _errorFilterRegex = new(Constants.ErrorFilterRegex, _regexOptions);
45+
4346
/// <summary>
4447
/// Compiles the specified scripts.
4548
/// </summary>
@@ -69,7 +72,6 @@ private async void Compile_SPScripts(bool compileAll = true)
6972
FileInfo spCompInfo = null;
7073
var SpCompFound = false;
7174
var PressedEscape = false;
72-
var hadError = false;
7375
var dontCreateFile = false;
7476
TotalErrors = 0;
7577
TotalWarnings = 0;
@@ -97,7 +99,7 @@ await this.ShowMessageAsync(Translate("Error"),
9799
}
98100

99101
// If the compiler was found, it starts adding to a list all of the files to compile
100-
ScriptsCompiled = new();
102+
ScriptsCompiled.Clear();
101103
if (compileAll)
102104
{
103105
if (!EditorReferences.Any())
@@ -144,8 +146,6 @@ await this.ShowMessageAsync(Translate("Error"),
144146
ProgressTask.SetProgress(0.0);
145147

146148
var stringOutput = new StringBuilder();
147-
var regexOptions = RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Multiline;
148-
var errorFilterRegex = new Regex(Constants.ErrorFilterRegex, regexOptions);
149149

150150
var compiledSuccess = 0;
151151

@@ -164,14 +164,6 @@ await this.ShowMessageAsync(Translate("Error"),
164164
var fileInfo = new FileInfo(file);
165165
if (fileInfo.Exists)
166166
{
167-
var process = new Process();
168-
process.StartInfo.WorkingDirectory =
169-
fileInfo.DirectoryName ?? throw new NullReferenceException();
170-
process.StartInfo.UseShellExecute = true;
171-
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
172-
process.StartInfo.CreateNoWindow = true;
173-
process.StartInfo.FileName = spCompInfo.FullName;
174-
175167
dontCreateFile = ee.DontCreateFileBox.IsChecked.HasValue && ee.DontCreateFileBox.IsChecked.Value;
176168
string outFile;
177169
string destinationFileName;
@@ -192,12 +184,6 @@ await this.ShowMessageAsync(Translate("Error"),
192184
fileInfo.FullName, fileInfo.Name, outFile, destinationFileName);
193185
}
194186

195-
var errorFile = $@"{fileInfo.DirectoryName}\error_{Environment.TickCount}_{file.GetHashCode():X}_{i}.txt";
196-
if (File.Exists(errorFile))
197-
{
198-
File.Delete(errorFile);
199-
}
200-
201187
var includeDirectories = new StringBuilder();
202188
foreach (var dir in currentConfig.SMDirectories)
203189
{
@@ -206,31 +192,30 @@ await this.ShowMessageAsync(Translate("Error"),
206192

207193
var includeStr = includeDirectories.ToString();
208194

209-
process.StartInfo.Arguments =
210-
"\"" + fileInfo.FullName + "\" -o=\"" + outFile + "\" -e=\"" + errorFile + "\"" +
211-
includeStr + " -O=" + currentConfig.OptimizeLevel + " -v=" + currentConfig.VerboseLevel;
195+
var process = new Process();
196+
var startInfo = new ProcessStartInfo
197+
{
198+
WorkingDirectory = fileInfo.DirectoryName ?? throw new NullReferenceException(),
199+
UseShellExecute = false,
200+
RedirectStandardOutput = true,
201+
RedirectStandardError = true,
202+
WindowStyle = ProcessWindowStyle.Hidden,
203+
CreateNoWindow = true,
204+
FileName = spCompInfo.FullName,
205+
Arguments = $"\"{fileInfo.FullName}\" -o=\"{outFile}\" {includeStr} -O={currentConfig.OptimizeLevel} -v={currentConfig.VerboseLevel}"
206+
};
207+
208+
var sb = new StringBuilder();
209+
process.StartInfo = startInfo;
212210
ProgressTask.SetProgress((i + 1 - 0.5d) / compileCount);
213211

214-
215212
ProcessUITasks();
216213

217214
try
218215
{
219216
process.Start();
217+
sb.Append(process.StandardOutput.ReadToEnd());
220218
process.WaitForExit();
221-
222-
if (process.ExitCode != 1 && process.ExitCode != 0)
223-
{
224-
await ProgressTask.CloseAsync();
225-
await this.ShowMessageAsync(Translate("Error"),
226-
"The SourcePawn compiler has crashed.\n" +
227-
"Try again, or file an issue at the SourcePawn GitHub repository describing your steps that led to this instance in detail.\n" +
228-
$"Exit code: {process.ExitCode:X}", MessageDialogStyle.Affirmative,
229-
MetroDialogOptions);
230-
LoggingControl.LogAction($"Compiler crash detected, file: {fileInfo.Name}", 2);
231-
InCompiling = false;
232-
return;
233-
}
234219
}
235220
catch (Exception)
236221
{
@@ -242,60 +227,72 @@ await this.ShowMessageAsync(Translate("SPCompNotStarted"),
242227
return;
243228
}
244229

245-
if (File.Exists(errorFile))
230+
switch (process.ExitCode)
246231
{
247-
hadError = false;
248-
var errorStr = Encoding.UTF8.GetString(Encoding.Convert(_ansi, Encoding.UTF8, _ansi.GetBytes(File.ReadAllText(errorFile, _ansi))));
249-
CurrentErrorString = errorStr;
250-
stringOutput.AppendLine(errorStr.Trim('\n', '\r'));
251-
var mc = errorFilterRegex.Matches(errorStr);
252-
for (var j = 0; j < mc.Count; ++j)
232+
// Successful compilation
233+
case 0:
234+
{
235+
LoggingControl.LogAction($"{fileInfo.Name}{(TotalWarnings > 0 ? $" ({TotalWarnings} warnings)" : "")}");
236+
compiledSuccess++;
237+
break;
238+
}
239+
240+
// Failed compilation
241+
case 1:
253242
{
254-
if (mc[j].Groups["Type"].Value.Contains("error"))
243+
LoggingControl.LogAction(fileInfo.Name + " (error)");
244+
var matches = _errorFilterRegex.Matches(sb.ToString());
245+
foreach (Match match in matches)
255246
{
256-
hadError = true;
257-
TotalErrors++;
258-
var item = new ErrorDataGridRow
259-
{
260-
File = mc[j].Groups["File"].Value.Trim(),
261-
Line = mc[j].Groups["Line"].Value.Trim(),
262-
Type = mc[j].Groups["Type"].Value.Trim(),
263-
Details = mc[j].Groups["Details"].Value.Trim()
264-
};
265-
if (!HideErrors)
247+
if (match.Groups["Type"].Value.Contains("error"))
266248
{
267-
ErrorResultGrid.Items.Add(item);
249+
TotalErrors++;
250+
var item = new ErrorDataGridRow
251+
{
252+
File = match.Groups["File"].Value.Trim(),
253+
Line = match.Groups["Line"].Value.Trim(),
254+
Type = match.Groups["Type"].Value.Trim(),
255+
Details = match.Groups["Details"].Value.Trim()
256+
};
257+
if (!HideErrors)
258+
{
259+
ErrorResultGrid.Items.Add(item);
260+
}
261+
CurrentErrors.Add(item);
268262
}
269-
CurrentErrors.Add(item);
270-
}
271-
if (mc[j].Groups["Type"].Value.Contains("warning"))
272-
{
273-
TotalWarnings++;
274-
var item = new ErrorDataGridRow
275-
{
276-
File = mc[j].Groups["File"].Value.Trim(),
277-
Line = mc[j].Groups["Line"].Value.Trim(),
278-
Type = mc[j].Groups["Type"].Value.Trim(),
279-
Details = mc[j].Groups["Details"].Value.Trim()
280-
};
281-
if (!HideWarnings)
263+
if (match.Groups["Type"].Value.Contains("warning"))
282264
{
283-
ErrorResultGrid.Items.Add(item);
265+
TotalWarnings++;
266+
var item = new ErrorDataGridRow
267+
{
268+
File = match.Groups["File"].Value.Trim(),
269+
Line = match.Groups["Line"].Value.Trim(),
270+
Type = match.Groups["Type"].Value.Trim(),
271+
Details = match.Groups["Details"].Value.Trim()
272+
};
273+
if (!HideWarnings)
274+
{
275+
ErrorResultGrid.Items.Add(item);
276+
}
277+
CurrentWarnings.Add(item);
284278
}
285-
CurrentWarnings.Add(item);
286279
}
280+
break;
287281
}
288-
File.Delete(errorFile);
289-
}
290282

291-
if (hadError)
292-
{
293-
LoggingControl.LogAction(fileInfo.Name + " (error)");
294-
}
295-
else
296-
{
297-
LoggingControl.LogAction($"{fileInfo.Name}{(TotalWarnings > 0 ? $" ({TotalWarnings} warnings)" : "")}");
298-
compiledSuccess++;
283+
// Compiler crash
284+
default:
285+
{
286+
await ProgressTask.CloseAsync();
287+
await this.ShowMessageAsync(Translate("Error"),
288+
"The SourcePawn compiler has crashed.\n" +
289+
"Try again, or file an issue at the SourcePawn GitHub repository describing your steps that led to this instance in detail.\n" +
290+
$"Exit code: {process.ExitCode:X}", MessageDialogStyle.Affirmative,
291+
MetroDialogOptions);
292+
LoggingControl.LogAction($"Compiler crash detected, file: {fileInfo.Name}", 2);
293+
InCompiling = false;
294+
return;
295+
}
299296
}
300297

301298
if (!dontCreateFile && File.Exists(outFile))
@@ -324,7 +321,7 @@ await this.ShowMessageAsync(Translate("SPCompNotStarted"),
324321
Status_ErrorText.Text = (TotalErrors == 1 ? string.Format(Translate("status_error"), "1") : string.Format(Translate("status_errors"), TotalErrors)).ToLowerInvariant();
325322
Status_WarningText.Text = (TotalWarnings == 1 ? string.Format(Translate("status_warning"), "1") : string.Format(Translate("status_warnings"), TotalWarnings)).ToLowerInvariant();
326323

327-
if (!PressedEscape)
324+
if (!PressedEscape && compiledSuccess > 0)
328325
{
329326
ProgressTask.SetProgress(1.0);
330327
if (currentConfig.AutoCopy && !dontCreateFile)

0 commit comments

Comments
 (0)