From e3fb90a8703e7af05ab499ac6bc65309851b2bdb Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Fri, 1 Aug 2025 19:02:26 +1000 Subject: [PATCH] Use Terminal Logger --- .../Features/Build/BuildService.cs | 13 ++++++-- .../Features/Logging/ChannelTextWriter.cs | 33 +++++++++++++++++++ .../Logging/InternalTerminalLoggerFactory.cs | 31 +++++++++++++++++ .../Components/TerminalOutputDisplay.razor | 28 +++++++++++----- src/SharpIDE.Photino/SharpIDE.Photino.csproj | 1 + src/SharpIDE.Photino/wwwroot/index.html | 2 ++ 6 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 src/SharpIDE.Application/Features/Logging/ChannelTextWriter.cs create mode 100644 src/SharpIDE.Application/Features/Logging/InternalTerminalLoggerFactory.cs diff --git a/src/SharpIDE.Application/Features/Build/BuildService.cs b/src/SharpIDE.Application/Features/Build/BuildService.cs index f661c29..fd227a7 100644 --- a/src/SharpIDE.Application/Features/Build/BuildService.cs +++ b/src/SharpIDE.Application/Features/Build/BuildService.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Text; using System.Threading.Channels; using Microsoft.Build.Execution; using Microsoft.Build.Framework; @@ -17,18 +18,26 @@ public enum BuildType public class BuildService { public event Func BuildStarted = () => Task.CompletedTask; - public Channel BuildOutputChannel { get; } = Channel.CreateUnbounded(); + public ChannelTextWriter BuildTextWriter { get; } = new ChannelTextWriter(); public async Task MsBuildSolutionAsync(string solutionFilePath, BuildType buildType = BuildType.Build) { + var normalOut = Console.Out; + Console.SetOut(BuildTextWriter); + var terminalLogger = InternalTerminalLoggerFactory.CreateLogger(); + terminalLogger.Parameters = "FORCECONSOLECOLOR"; + terminalLogger.Verbosity = LoggerVerbosity.Minimal; var buildParameters = new BuildParameters { Loggers = [ //new BinaryLogger { Parameters = "msbuild.binlog" }, - new ConsoleLogger(LoggerVerbosity.Minimal, message => BuildOutputChannel.Writer.TryWrite(message), s => { }, () => { }), + //new ConsoleLogger(LoggerVerbosity.Minimal, message => BuildOutputChannel.Writer.TryWrite(message), s => { }, () => { }) {Parameters = "FORCECONSOLECOLOR"}, + terminalLogger //new InMemoryLogger(LoggerVerbosity.Normal) ], }; + Console.SetOut(normalOut); + string[] targetsToBuild = buildType switch { BuildType.Build => ["Restore", "Build"], diff --git a/src/SharpIDE.Application/Features/Logging/ChannelTextWriter.cs b/src/SharpIDE.Application/Features/Logging/ChannelTextWriter.cs new file mode 100644 index 0000000..3704392 --- /dev/null +++ b/src/SharpIDE.Application/Features/Logging/ChannelTextWriter.cs @@ -0,0 +1,33 @@ +using System.Text; +using System.Threading.Channels; + +namespace SharpIDE.Application.Features.Logging; + +// I could do this, or provide an XTermWriter. 🤷‍♂️ +public class ChannelTextWriter : TextWriter +{ + public override Encoding Encoding { get; } = Encoding.UTF8; + public Channel ConsoleChannel { get; } = Channel.CreateUnbounded(); + + public override void Write(char value) + { + ConsoleChannel.Writer.TryWrite(value.ToString()); + } + + public override void Write(string? value) + { + ConsoleChannel.Writer.TryWrite(value!); + } + public override void WriteLine(string? value) + { + throw new NotImplementedException(); + } + public override void WriteLine(char value) + { + throw new NotImplementedException(); + } + public override void WriteLine() + { + throw new NotImplementedException(); + } +} diff --git a/src/SharpIDE.Application/Features/Logging/InternalTerminalLoggerFactory.cs b/src/SharpIDE.Application/Features/Logging/InternalTerminalLoggerFactory.cs new file mode 100644 index 0000000..f32756f --- /dev/null +++ b/src/SharpIDE.Application/Features/Logging/InternalTerminalLoggerFactory.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using Microsoft.Build.Framework; + +namespace SharpIDE.Application.Features.Logging; + +public class InternalTerminalLoggerFactory +{ + public static ILogger CreateLogger() + { + var type = Type.GetType("Microsoft.Build.Logging.TerminalLogger, Microsoft.Build"); + + if (type == null) throw new Exception("TerminalLogger type not found"); + + var method = type.GetMethod( + "CreateTerminalOrConsoleLogger", + BindingFlags.NonPublic | BindingFlags.Static); + + if (method == null) throw new Exception("CreateTerminalOrConsoleLogger method not found"); + + string[]? args = []; + bool supportsAnsi = true; + bool outputIsScreen = true; + uint? originalConsoleMode = 0x0007; + + object? logger = method.Invoke( + obj: null, + parameters: [args, supportsAnsi, outputIsScreen, originalConsoleMode]); + + return (ILogger)logger!; // This will be an ILogger (or INodeLogger) instance + } +} diff --git a/src/SharpIDE.Photino/Components/TerminalOutputDisplay.razor b/src/SharpIDE.Photino/Components/TerminalOutputDisplay.razor index 0c016c8..9f304f9 100644 --- a/src/SharpIDE.Photino/Components/TerminalOutputDisplay.razor +++ b/src/SharpIDE.Photino/Components/TerminalOutputDisplay.razor @@ -1,35 +1,45 @@ @using SharpIDE.Application.Features.Build +@using XtermBlazor @inject BuildService BuildService @inject IJSRuntime JsRuntime @implements IDisposable -
- @foreach (var line in _outputLines) - { - @line - } +
+
@code { private List _outputLines = []; private ElementReference _logContainer; + private Xterm _terminalRef; + + private TerminalOptions _options = new TerminalOptions + { + CursorBlink = true, + CursorStyle = CursorStyle.Bar, + Columns = 140, + Theme = + { + Background = "#303030", + }, + }; + protected override async Task OnInitializedAsync() { BuildService.BuildStarted += ClearPreviousOutput; - await foreach (var logLine in BuildService.BuildOutputChannel.Reader.ReadAllAsync()) + await foreach (var logLine in BuildService.BuildTextWriter.ConsoleChannel.Reader.ReadAllAsync()) { - _outputLines.Add(logLine); - await InvokeAsync(StateHasChanged); - await ScrollToBottomAsync(); + await _terminalRef.Write(logLine); } } private async Task ClearPreviousOutput() { _outputLines.Clear(); + await _terminalRef.Clear(); await InvokeAsync(StateHasChanged); } diff --git a/src/SharpIDE.Photino/SharpIDE.Photino.csproj b/src/SharpIDE.Photino/SharpIDE.Photino.csproj index 44528f5..ce19fb6 100644 --- a/src/SharpIDE.Photino/SharpIDE.Photino.csproj +++ b/src/SharpIDE.Photino/SharpIDE.Photino.csproj @@ -23,6 +23,7 @@ + diff --git a/src/SharpIDE.Photino/wwwroot/index.html b/src/SharpIDE.Photino/wwwroot/index.html index aa06f56..489917e 100644 --- a/src/SharpIDE.Photino/wwwroot/index.html +++ b/src/SharpIDE.Photino/wwwroot/index.html @@ -7,6 +7,7 @@ + @@ -19,6 +20,7 @@
+