refactor to reusable terminal display

This commit is contained in:
Matt Parker
2025-08-10 00:01:03 +10:00
parent 58b6261264
commit 2b0518c9d8
2 changed files with 76 additions and 66 deletions

View File

@@ -1,45 +1,16 @@
@using Ardalis.GuardClauses
@using SharpIDE.Application.Features.Build
@using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence
@using XtermBlazor
@inject BuildService BuildService
@implements IDisposable
<style>
.xterm-underline-5.xterm-underline-5 { /* Specificity hack lol */
text-decoration: dotted underline;
}
</style>
<div style="width: 100%; height: 100%; overflow: visible">
<Xterm @ref="@_terminalRef" Options="@_options" Style="height: calc(100% - 1px)" Addons="@_addons" OnFirstRender="@OnFirstRender"/>
</div>
<TerminalDisplay @ref="_terminalDisplayRef"/>
@code {
[Parameter, EditorRequired]
public SharpIdeProjectModel Project { get; set; } = null!;
private Xterm _terminalRef;
private readonly TerminalOptions _options = new TerminalOptions
{
CursorBlink = true,
CursorStyle = CursorStyle.Bar,
Columns = 140,
FontFamily = "Cascadia Code",
FontWeightBold = "400",
Theme =
{
BrightGreen = "#98c379",
BrightRed = "#e06c75",
Foreground = "#dcdfe4",
Background = "#282c34",
},
};
private HashSet<string> _addons = ["addon-fit"];
private TerminalDisplay _terminalDisplayRef = null!;
protected override async Task OnInitializedAsync()
{
@@ -52,14 +23,15 @@
{
Guard.Against.Null(Project);
Guard.Against.Null(Project.RunningOutputChannel, nameof(Project.RunningOutputChannel));
await ClearPreviousOutput();
if (_terminalDisplayRef is not null) await _terminalDisplayRef.Clear();
_ = Task.Run(async () =>
{
try
{
await foreach (var log in Project.RunningOutputChannel.Reader.ReadAllAsync())
{
await _terminalRef.Write(log);
// Better hope you don't get a log until we get the component ref lol
await _terminalDisplayRef.Write(log);
}
}
catch (Exception e)
@@ -69,38 +41,5 @@
});
}
private async Task ClearPreviousOutput()
{
if (_terminalRef is not null)
{
await _terminalRef.Clear();
await InvokeAsync(StateHasChanged);
}
}
public void Dispose() => Project.ProjectStartedRunning -= OnProjectStartedRunning;
private async Task OnFirstRender()
{
await _terminalRef.Addon("addon-fit").InvokeVoidAsync("fit");
_ = Task.Run(async () =>
{
try
{
while (true)
{
await Task.Delay(500).ConfigureAwait(false);
await InvokeAsync(async () =>
{
await _terminalRef.Addon("addon-fit").InvokeVoidAsync("fit");
});
}
}
catch (Exception e)
{
await DispatchExceptionAsync(e);
}
});
}
}

View File

@@ -0,0 +1,71 @@
@using XtermBlazor
<style>
.xterm-underline-5.xterm-underline-5 { /* Specificity hack lol */
text-decoration: dotted underline;
}
</style>
<div style="width: 100%; height: 100%; overflow: visible">
<Xterm @ref="@_terminalRef" Options="@_options" Style="height: calc(100% - 1px)" Addons="@_addons" OnFirstRender="@OnFirstRender"/>
</div>
@code {
private Xterm _terminalRef;
private readonly TerminalOptions _options = new TerminalOptions
{
CursorBlink = true,
CursorStyle = CursorStyle.Bar,
Columns = 140,
FontFamily = "Cascadia Code",
FontWeightBold = "400",
Theme =
{
BrightGreen = "#98c379",
BrightRed = "#e06c75",
Foreground = "#dcdfe4",
Background = "#282c34",
},
};
private HashSet<string> _addons = ["addon-fit"];
public async Task Write(string line)
{
await _terminalRef.Write(line);
}
public async Task Clear()
{
if (_terminalRef is not null)
{
await _terminalRef.Clear();
await InvokeAsync(StateHasChanged);
}
}
private async Task OnFirstRender()
{
await _terminalRef.Addon("addon-fit").InvokeVoidAsync("fit");
_ = Task.Run(async () =>
{
try
{
while (true)
{
await Task.Delay(500).ConfigureAwait(false);
await InvokeAsync(async () =>
{
await _terminalRef.Addon("addon-fit").InvokeVoidAsync("fit");
});
}
}
catch (Exception e)
{
await DispatchExceptionAsync(e);
}
});
}
}