LANCommander/LANCommander.Launcher/UI/Components/PowerShellConsole.razor
Pat Hartl e6c12b4809 Refactor script debugging
Instead of providing delegates to a ScriptClient singleton, script execution now relies on dependency injection for debugging. This can be handled by registering an implementation of IScriptDebugger. Multiple script debuggers are supported. These changes required the creation of a PowerShellScriptFactory to handle DI of the service provider to the script.

In the case of LANCommander, "debugging" scripts really just gives an opportunity for the application to break after a script's execution and provide a poor-man's pty. This could be expanded upon in the future to hook directly into PowerShell's debugging functionality, but would require a substantial refactor to script execution.
2025-11-26 01:09:52 -06:00

96 lines
No EOL
2.6 KiB
Text

@using LANCommander.Launcher.Services.PowerShell
@using XtermBlazor
@using LogLevel = Microsoft.Extensions.Logging.LogLevel
@inject ScriptDebugger Debugger
<div class="terminal @(Visible ? "" : "hidden")">
<Xterm @ref="Terminal" Options="_options" OnFirstRender="@OnFirstRender" Addons="@Addons" />
</div>
@code {
private bool Visible { get; set; } = false;
private Xterm Terminal;
private TaskCompletionSource<string> InputTaskCompletionSource;
private TerminalOptions _options = new TerminalOptions
{
CursorBlink = true,
CursorStyle = CursorStyle.Bar,
};
private HashSet<string> Addons = new HashSet<string>()
{
"readline",
"addon-fit"
};
protected override async Task OnInitializedAsync()
{
Debugger.OnDebugStart = async (ps) =>
{
Terminal?.Clear();
Visible = true;
await InvokeAsync(StateHasChanged);
await Terminal.Addon("addon-fit").InvokeVoidAsync("fit");
};
Debugger.OnOutput = async (level, message) =>
{
switch (level)
{
case LogLevel.Error:
await Terminal.WriteLine($"\x1b[0;31m{message}");
break;
case LogLevel.Warning:
await Terminal.WriteLine($"\x1b[0;33m{message}");
break;
case LogLevel.Debug:
await Terminal.WriteLine($"\x1b[0;37m{message}");
break;
case LogLevel.Trace:
await Terminal.WriteLine($"\x1b[0;36m{message}");
break;
case LogLevel.Information:
await Terminal.WriteLine($"\x1b[0;37m{message}");
break;
}
};
Debugger.OnDebugBreak = async (ps) =>
{
while (true)
{
var input = await ReadLine();
if (input.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
if (input.StartsWith('$'))
input = "Write-Host " + input;
ps.Commands.Clear();
ps.AddScript(input);
await ps.InvokeAsync();
}
Visible = false;
await InvokeAsync(StateHasChanged);
};
}
private async Task OnFirstRender()
{
await Terminal.Addon("addon-fit").InvokeVoidAsync("fit");
}
private async Task<string> ReadLine()
{
return await Terminal.Addon("readline").InvokeAsync<string>("read", "> ");
}
}