Watch2- part 2- first fast implementation
The first attempt to writing the code was very fast – and, surely, not testable. (Speedy Gonzales would be proud!)
Some observations:
1. If you start any process inside a console application, you should intercept the cancel signal and stop the process.
This is done by using the CancelKeyPress event of the Console class.
This is important because the user can cancel the process by pressing Ctrl+C.
(Because who doesn’t love a good Ctrl+C in the morning?)
Console.CancelKeyPress += delegate { // call methods to clean up Kill(proc); };
2. If you want to stop the dotnet watch after it detects a change in the file system, you cannot. You need to kill the process and start it again. So, you need to kill the process and start it again.
(It’s like a phoenix, it must die to be reborn!)
3. Spectre.Console is a really good library to create console applications with a lot of features. I used it to create messages with different colors and styles.
(Because plain text is so last century.)
4. The code is very simple and easy to understand. I used the Process class to start the dotnet watch process and the Console class to write messages to the console.
(Simple and easy, just like making a cup of coffee… if you have a coffee machine.)
This is the final code:
using Spectre.Console; using System.Diagnostics; Process? proc = null; Console.CancelKeyPress += delegate { // call methods to clean up Kill(proc); }; bool shouldWait = false; while (true) { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = "dotnet"; startInfo.Arguments = "watch " + string.Join(' ', args); //startInfo.LoadUserProfile = true; startInfo.WorkingDirectory = Environment.CurrentDirectory; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardInput = true; startInfo.RedirectStandardError = true; startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; proc = new Process(); proc.StartInfo = startInfo; proc.OutputDataReceived += (sender, e) => { if (shouldWait) { shouldWait = false; Kill(proc); Thread.Sleep(15_000); return; } var line = e.Data; if (line == null) return; if (line.Contains("dotnet watch")) { if (line.Contains("Started")) { Console.Clear(); } if (line.Contains("Building")) { } } if (line.Contains(": error ")) { AnsiConsole.MarkupLineInterpolated($"->[bold red]:cross_mark: {e.Data}[/]"); return; } if (line.Contains("Waiting for a file to change before")) { Console.WriteLine("wain"); shouldWait = true; } Console.WriteLine("->" + e.Data); }; proc.ErrorDataReceived += (sender, e) => { if (e.Data != null) { AnsiConsole.MarkupLineInterpolated($"->[bold red]:cross_mark: {e.Data}[/]"); return; } }; AnsiConsole.MarkupLineInterpolated($"[bold green]Starting...[/]"); proc.Start(); Console.Clear(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); await proc.WaitForExitAsync(); } static void Kill(Process? proc) { if (proc == null) return; if (proc.HasExited) return; proc.Kill(true); proc.Close(); proc = null; }