Move useful terminal methods to component, remove old addon registration

This commit is contained in:
Pat Hartl 2026-01-03 23:58:50 -06:00
parent eda3a8e7bc
commit fbcb02a863
3 changed files with 65 additions and 45 deletions

View file

@ -5,68 +5,53 @@
@inject ScriptDebugger Debugger
<div class="terminal @(Visible ? "" : "hidden")">
<Xterm @ref="Terminal" Options="_options" OnFirstRender="@OnFirstRender" Addons="@Addons" />
<Terminal @ref="_terminal" Options="_options" OnFirstRender="@OnFirstRender" Addons="@_addons" />
</div>
@code {
private bool Visible { get; set; } = false;
private Xterm Terminal;
private TaskCompletionSource<string> InputTaskCompletionSource;
private bool Visible { get; set; }
private Terminal? _terminal;
private TerminalOptions _options = new TerminalOptions
private TerminalOptions _options = new()
{
CursorBlink = true,
CursorStyle = CursorStyle.Bar,
};
private HashSet<string> Addons = new HashSet<string>()
private HashSet<string> _addons = new()
{
"readline",
"addon-fit"
};
protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
Debugger.OnDebugStart = async (ps) =>
Debugger.OnDebugStart = async _ =>
{
Terminal?.Clear();
if (_terminal is null)
return;
await _terminal.Clear();
Visible = true;
await InvokeAsync(StateHasChanged);
await Terminal.Addon("addon-fit").InvokeVoidAsync("fit");
await _terminal.FitAsync();
};
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;
}
if (_terminal is not null)
await _terminal.WriteLine(message, level);
};
Debugger.OnDebugBreak = async (context) =>
Debugger.OnDebugBreak = async context =>
{
if (_terminal is null)
return;
while (true)
{
var input = await ReadLine();
var input = await _terminal.ReadLineAsync();
if (input.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
@ -84,11 +69,7 @@
private async Task OnFirstRender()
{
await Terminal.Addon("addon-fit").InvokeVoidAsync("fit");
}
private async Task<string> ReadLine()
{
return await Terminal.Addon("readline").InvokeAsync<string>("read", "> ");
if (_terminal is not null)
await _terminal.FitAsync();
}
}

View file

@ -38,11 +38,6 @@
<script src="_framework/blazor.webview.js"></script>
<script>
XtermBlazor.registerAddons({
"readline": new XtermAddons.Readline(),
"addon-fit": new XtermAddons.Fit()
});
window.sendMessage = function (message) {
window.external.sendMessage(message);
}

View file

@ -2,6 +2,7 @@ using LANCommander.UI.Extensions;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using XtermBlazor;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace LANCommander.UI.Components;
@ -16,4 +17,47 @@ public partial class Terminal : Xterm
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JS.ExecuteVoidAsync("RegisterXtermAddons");
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
await FitAsync();
}
/// <summary>
/// Write a line to the terminal with a specified log level
/// </summary>
/// <param name="message">Message to send</param>
/// <param name="level">LogLevel to write</param>
public async Task WriteLine(string message, LogLevel level = LogLevel.Information)
{
var code = level switch
{
LogLevel.Error => 31,
LogLevel.Warning => 33,
LogLevel.Debug => 37,
LogLevel.Trace => 36,
LogLevel.Information => 37,
_ => 37,
};
await base.WriteLine($"\x1b[0;{code}m{message}");
}
/// <summary>
/// Rerenders the terminal and changes the size to fit within the element's rect. Utilizes the `addon-fit` addon.
/// </summary>
public async Task FitAsync()
=> await Addon("addon-fit").InvokeVoidAsync("fit");
/// <summary>
/// Wait for user input in the terminal
/// </summary>
/// <param name="prefix"></param>
public async Task<string> ReadLineAsync(string prefix = "> ")
=> await Addon("readline").InvokeAsync<string>("read", prefix);
}