Skip to content

Commit dcdd655

Browse files
committed
Show message box when exceptions occur due to wrong file encoding (the source files must be saved using utf-8 encoding).
1 parent dc51df9 commit dcdd655

5 files changed

+148
-35
lines changed

AsyncToSyncCodeRoundtripSynchroniserMonitorNet.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
113113
<HintPath>packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
114114
</Reference>
115+
<Reference Include="System.Windows.Forms" />
115116
<Reference Include="System.IO.Compression" />
116117
<Reference Include="System.IO.Compression.FileSystem" />
117118
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
@@ -181,6 +182,7 @@
181182
</ItemGroup>
182183
<ItemGroup>
183184
<Content Include="copyrights.txt" />
185+
<Content Include="todo.txt" />
184186
</ItemGroup>
185187
<ItemGroup>
186188
<Folder Include="icon\" />

AsyncToSyncConverter.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static class AsyncToSyncConverter
2222
public static readonly List<KVP> Replacements = new List<KVP>()
2323
{
2424
//NB! VS may put the /*--await--*/ on a separate line therefore need handling for various space types after /*--await--*/
25+
//TODO!: ensure that await starts at word boundary
2526
new KVP("await ", "/*--await--*/ "),
2627
new KVP("await\t", "/*--await--*/\t"),
2728
new KVP("await\r", "/*--await--*/\r"),
@@ -32,13 +33,22 @@ static class AsyncToSyncConverter
3233

3334
new KVP(@" async Task ", @" /*--async Task--*/void "),
3435
//new KVP(@" async void ", @" /*--async void--*/void "),
36+
new KVP(@" async IAsyncEnumerable", @" /*--async IAsyncEnumerable--*/IEnumerable"),
3537
new KVP(@" async ", @" /*--async--*/ "),
38+
39+
new KVP("(async ", "(/*--async--*/ "),
40+
new KVP("(async\t", "(/*--async--*/\t"),
41+
new KVP("(async\r", "(/*--async--*/\r"),
42+
new KVP("(async\n", "(/*--async--*/\n"),
43+
3644
new KVP(@" Task ", @" /*--Task--*/void "), //method return type
3745
new KVP(@"Task ", @"/*--Task--*/Action "), //method argument type
46+
new KVP(@"Task<T> ", @"/*--Task<T>--*/Func<T> "), //method argument type
3847

3948
new KVP(@").Wait();", @")/*--.Wait()--*/;"),
4049
//new KVP("Task.Delay", "/*--Task.Delay--*/System.Threading.Thread.Sleep"), //this needs special regex in sync to async direction
4150
new KVP(@"Task.FromResult", @"/*--Task.FromResult--*/"),
51+
new KVP(@"Task.WhenAll", @"/*--Task.WhenAll--*/"),
4252
new KVP(@" AsyncLock", @" /*--AsyncLock--*/object"),
4353

4454
new KVP(@"#define ASYNC", @"#define NOASYNC"),
@@ -53,14 +63,18 @@ static class AsyncToSyncConverter
5363
private const string TaskDelayReplaceRegexReplacement = @"/*--Task.Delay--*/System.Threading.Thread.Sleep";
5464

5565

56-
private static readonly Regex TaskReplaceRegex = new Regex(@"(\s+)(async\s+)?Task<([^ (]+)>(\s+)", RegexOptions.Singleline | RegexOptions.Compiled);
66+
private static readonly Regex TaskReplaceRegex = new Regex(@"(\s+)(async\s+)?Task<([^(]+)>(\s+)", RegexOptions.Singleline | RegexOptions.Compiled);
5767
private const string TaskReplaceRegexReplacement = @"$1/*--$2Task<--*/$3/*-->--*/$4";
5868

5969

6070
private static readonly Regex AsyncLockReplaceRegex = new Regex(@"using([^(]*)[(]await(\s+[^(]+)[.]LockAsync[(][)][)]", RegexOptions.Singleline | RegexOptions.Compiled);
6171
private const string AsyncLockReplaceRegexReplacement = @"/*--using--*/lock$1(/*--await--*/ $2/*--.Lock A s y n c()--*/)";
6272

6373

74+
private static readonly Regex FuncTaskReplaceRegex = new Regex(@"([\s,(]+)Func<Task<([^=)]+)>>", RegexOptions.Singleline | RegexOptions.Compiled);
75+
private const string FuncTaskReplaceRegexReplacement = @"$1Func</*--Task<--*/$2/*-->--*/>";
76+
77+
6478
public static async Task AsyncFileUpdated(string fullName, Context context)
6579
{
6680
//using (await Global.FileOperationAsyncLock.LockAsync())
@@ -71,6 +85,7 @@ public static async Task AsyncFileUpdated(string fullName, Context context)
7185

7286

7387

88+
fileData = FuncTaskReplaceRegex.Replace(fileData, FuncTaskReplaceRegexReplacement);
7489
fileData = AsyncLockReplaceRegex.Replace(fileData, AsyncLockReplaceRegexReplacement);
7590
fileData = TaskReplaceRegex.Replace(fileData, TaskReplaceRegexReplacement);
7691
fileData = TaskDelayReplaceRegex.Replace(fileData, TaskDelayReplaceRegexReplacement);

Program.cs

+74-17
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
using System.Text;
1818
using System.Threading;
1919
using System.Threading.Tasks;
20+
using System.Windows.Forms;
2021
using Microsoft.Extensions.Configuration;
2122
using myoddweb.directorywatcher;
2223
using myoddweb.directorywatcher.interfaces;
24+
using Nito.AsyncEx;
2325

2426
namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
2527
{
@@ -45,7 +47,7 @@ internal static class Global
4547

4648

4749

48-
internal static readonly AsyncLockQueueDictionary FileOperationLocks = new AsyncLockQueueDictionary();
50+
internal static readonly AsyncLockQueueDictionary<string> FileOperationLocks = new AsyncLockQueueDictionary<string>();
4951
//internal static readonly AsyncLock FileOperationAsyncLock = new AsyncLock();
5052
}
5153
#pragma warning restore S2223
@@ -227,7 +229,7 @@ await ConsoleWatch.OnAddedAsync
227229

228230

229231
//listen for the Ctrl+C
230-
WaitForCtrlC();
232+
await WaitForCtrlC();
231233

232234
Console.WriteLine("Stopping...");
233235

@@ -241,7 +243,7 @@ await ConsoleWatch.OnAddedAsync
241243
}
242244
catch (Exception ex)
243245
{
244-
WriteException(ex);
246+
await WriteException(ex);
245247
}
246248
}
247249

@@ -306,36 +308,75 @@ private static IEnumerable<FileInfo> ProcessSubDirs(DirectoryInfo srcDirInfo, st
306308
} //foreach (var dirInfo in dirInfos)
307309
#endif
308310
} //private static IEnumerable<FileInfo> ProcessSubDirs(DirectoryInfo srcDirInfo, string searchPattern, bool forHistory, int recursionLevel = 0)
309-
private static void WriteException(Exception ex)
311+
private static async Task WriteException(Exception ex)
310312
{
311313
if (ex is AggregateException aggex)
312314
{
313-
WriteException(aggex.InnerException);
315+
await WriteException(aggex.InnerException);
314316
foreach (var aggexInner in aggex.InnerExceptions)
315317
{
316-
WriteException(aggexInner);
318+
await WriteException(aggexInner);
317319
}
318320
return;
319321
}
320322

321-
Console.WriteLine(ex.Message);
323+
//Console.WriteLine(ex.Message);
324+
StringBuilder message = new StringBuilder(ex.Message);
322325
while (ex.InnerException != null)
323326
{
324327
ex = ex.InnerException;
325-
Console.WriteLine(ex.Message);
328+
//Console.WriteLine(ex.Message);
329+
message.Append(Environment.NewLine + ex.Message);
326330
}
331+
332+
333+
var time = DateTime.Now;
334+
var msg = $"[{time:yyyy.MM.dd HH:mm:ss.ffff}]:{message}";
335+
await AddMessage(ConsoleColor.Red, msg, time, showAlert: true);
336+
}
337+
338+
private static async Task AddMessage(ConsoleColor color, string message, DateTime time, bool showAlert = false)
339+
{
340+
await Task.Run(() =>
341+
{
342+
lock (ConsoleWatch.Lock)
343+
{
344+
try
345+
{
346+
Console.ForegroundColor = color;
347+
Console.WriteLine(message);
348+
349+
if (
350+
showAlert
351+
&& (ConsoleWatch.PrevAlertTime != time || ConsoleWatch.PrevAlertMessage != message)
352+
)
353+
{
354+
MessageBox.Show(message, "AsyncToSyncCodeRoundtripSynchroniserMonitor");
355+
}
356+
}
357+
catch (Exception e)
358+
{
359+
Console.ForegroundColor = ConsoleColor.Red;
360+
Console.WriteLine(e.Message);
361+
}
362+
finally
363+
{
364+
Console.ForegroundColor = ConsoleWatch._consoleColor;
365+
}
366+
}
367+
});
327368
}
328369

329-
private static void WaitForCtrlC()
370+
private static Task WaitForCtrlC()
330371
{
331-
var exitEvent = new ManualResetEvent(false);
372+
var exitEvent = new AsyncManualResetEvent(false);
332373
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
333374
{
334375
e.Cancel = true;
335376
Console.WriteLine("Stop detected.");
336377
exitEvent.Set();
337378
};
338-
exitEvent.WaitOne();
379+
return exitEvent.WaitAsync();
339380
}
340381
}
341382

@@ -368,20 +409,23 @@ internal class ConsoleWatch
368409
/// <summary>
369410
/// The original console color
370411
/// </summary>
371-
private static readonly ConsoleColor _consoleColor = Console.ForegroundColor;
412+
internal static readonly ConsoleColor _consoleColor = Console.ForegroundColor;
372413

373414
/// <summary>
374415
/// We need a static lock so it is shared by all.
375416
/// </summary>
376-
private static readonly object Lock = new object();
417+
internal static readonly object Lock = new object();
377418
//private static readonly AsyncLock AsyncLock = new AsyncLock(); //TODO: use this
378419

420+
internal static DateTime PrevAlertTime;
421+
internal static string PrevAlertMessage;
422+
379423
#pragma warning disable S2223 //Warning S2223 Change the visibility of 'DoingInitialSync' or make it 'const' or 'readonly'.
380424
public static bool DoingInitialSync = false;
381425
#pragma warning restore S2223
382426

383427
private static ConcurrentDictionary<string, DateTime> BidirectionalConverterSavedFileDates = new ConcurrentDictionary<string, DateTime>();
384-
private static readonly AsyncLockQueueDictionary FileEventLocks = new AsyncLockQueueDictionary();
428+
private static readonly AsyncLockQueueDictionary<string> FileEventLocks = new AsyncLockQueueDictionary<string>();
385429

386430

387431
#pragma warning disable S1118 //Warning S1118 Hide this public constructor by making it 'protected'.
@@ -422,7 +466,9 @@ public static async Task WriteException(Exception ex, Context context)
422466
message.Append(Environment.NewLine + ex.Message);
423467
}
424468

425-
await AddMessage(ConsoleColor.Red, message.ToString(), context);
469+
470+
var msg = $"[{context.Time.ToLocalTime():yyyy.MM.dd HH:mm:ss.ffff}] : {context.Event?.FullName} : {message}";
471+
await AddMessage(ConsoleColor.Red, msg, context, showAlert: true);
426472
}
427473

428474
public static bool IsSyncPath(string fullNameInvariant)
@@ -836,7 +882,7 @@ private static async Task OnTouchedAsync(IFileSystemEvent fse, CancellationToken
836882
// }
837883
//}
838884

839-
public static async Task AddMessage(ConsoleColor color, string message, Context context)
885+
public static async Task AddMessage(ConsoleColor color, string message, Context context, bool showAlert = false)
840886
{
841887
await Task.Run(() =>
842888
{
@@ -846,7 +892,18 @@ await Task.Run(() =>
846892
try
847893
{
848894
Console.ForegroundColor = color;
849-
Console.WriteLine($"[{context.Time.ToLocalTime():yyyy.MM.dd HH:mm:ss.ffff}]:{message}");
895+
Console.WriteLine(message);
896+
897+
if (
898+
showAlert
899+
&& (PrevAlertTime != context.Time || PrevAlertMessage != message)
900+
)
901+
{
902+
PrevAlertTime = context.Time;
903+
PrevAlertMessage = message;
904+
905+
MessageBox.Show(message, "AsyncToSyncCodeRoundtripSynchroniserMonitor");
906+
}
850907
}
851908
catch (Exception e)
852909
{

SyncToAsyncConverter.cs

+6
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ static class SyncToAsyncConverter
3838
private static readonly Regex AsyncLockReplaceRegex = new Regex(@"/[*]--using--[*]/\s*lock(\s*)[(]/[*]--await--[*]/\s+([^/*()-]+)/[*]--[.]Lock\sA\ss\sy\sn\sc[(][)]--[*]/\s*[)]", RegexOptions.Singleline | RegexOptions.Compiled);
3939
private const string AsyncLockReplaceRegexReplacement = @"using$1(await $2.LockAsync())";
4040

41+
42+
private static readonly Regex FuncTaskReplaceRegex = new Regex(@"([\s,(]+)Func</[*]--Task<--[*]/([^=)]+)/[*]-->--[*]/>", RegexOptions.Singleline | RegexOptions.Compiled);
43+
private const string FuncTaskReplaceRegexReplacement = @"$1Func<Task<$2>>";
44+
45+
4146
static SyncToAsyncConverter()
4247
{
4348
var asyncToSyncReplacements = AsyncToSyncConverter.Replacements.GetReverse(); //NB! use reverse order
@@ -72,6 +77,7 @@ public static async Task SyncFileUpdated(string fullName, Context context)
7277
fileData = TaskDelayReplaceRegex.Replace(fileData, TaskDelayReplaceRegexReplacement);
7378
fileData = TaskReplaceRegex.Replace(fileData, TaskReplaceRegexReplacement);
7479
fileData = AsyncLockReplaceRegex.Replace(fileData, AsyncLockReplaceRegexReplacement);
80+
fileData = FuncTaskReplaceRegex.Replace(fileData, FuncTaskReplaceRegexReplacement);
7581

7682

7783
foreach (var replacement in Replacements)

0 commit comments

Comments
 (0)