using System.Text;
using XFESystem.Console;
using XFESystem.Core;
using Xunit;
namespace XFESystem.Desktop.Tests;
public sealed class TerminalDesktopTests
{
[Fact]
public void OpeningTerminalPaintsTheConciseBlueShellWithoutDemoToolbarOrDemoHitRegion()
{
var canvas = new Canvas(); int demos = 0;
var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), consoleDemo: () => demos++);
var window = desktop.Open(DesktopApplication.Terminal); desktop.Render();
Assert.NotNull(window.Shell); Assert.Equal("0.3.0-dev.4", window.Shell.Version);
string text = canvas.TerminalText(window);
Assert.Contains("XFESystem|XFEstudio", text); Assert.Contains("0.3.0-dev.4", text); Assert.Contains("help", text);
Assert.DoesNotContain("Run Demo", text); Assert.DoesNotContain("development session", text);
Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, true);
desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, false);
Assert.Equal(0, demos); Assert.Same(window, desktop.ActiveWindow);
}
[Fact]
public void DesktopKeyboardAndPasteExecuteRealRamCommandsAndRetainHistoryDraft()
{
var storage = new MemoryWorkspace(false); var desktop = new DesktopSession(new Canvas(), storage);
var window = desktop.Open(DesktopApplication.Terminal);
Run(desktop, "md Work"); Run(desktop, "cd Work"); Run(desktop, "mf Hello.txt"); Run(desktop, "write Hello.txt \"Hello XFE\"");
Assert.Equal("Hello XFE", storage.ReadText(SystemPaths.Documents + "\\Work\\Hello.txt"));
Assert.Equal(SystemPaths.Documents + "\\Work", window.Location);
Assert.True(desktop.PasteTerminalInput("draft")); desktop.Key(DesktopKey.Up); Assert.Equal("write Hello.txt \"Hello XFE\"", window.Shell!.Input);
desktop.Key(DesktopKey.Up); Assert.Equal("mf Hello.txt", window.Shell.Input);
desktop.Key(DesktopKey.Down); desktop.Key(DesktopKey.Down); Assert.Equal("draft", window.Shell.Input);
desktop.Key(DesktopKey.Escape); Assert.Empty(window.Shell.Input); Assert.Same(window, desktop.ActiveWindow);
Assert.False(desktop.PasteTerminalInput("mf Bad.txt\n"));
Run(desktop, "cat Hello.txt"); Assert.Contains("Hello XFE", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
desktop.Key(DesktopKey.CloseWindow); Assert.Empty(desktop.Windows);
}
[Fact]
public void MouseMovesTheInputCaretAndLeftDeleteInsertContinueEditingTheSameCommand()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
var window = desktop.Open(DesktopApplication.Terminal); Assert.True(desktop.PasteTerminalInput("abcd")); desktop.Render();
var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
int x = prompt.X + canvas.TextWidth(prompt.Text) + 16, y = prompt.Y + 7;
desktop.Pointer(x, y, true); desktop.Pointer(x, y, false); Assert.Equal(2, window.Shell!.Caret);
desktop.Key(DesktopKey.Delete); desktop.Key(DesktopKey.Character, 'X'); Assert.Equal("abXd", window.Shell.Input);
desktop.Key(DesktopKey.Left); desktop.Key(DesktopKey.Backspace); Assert.Equal("aXd", window.Shell.Input);
desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Insert); desktop.Key(DesktopKey.Character, 'Z'); Assert.Equal("ZXd", window.Shell.Input);
}
[Fact]
public void ProgramOutputIsFrozenDuringWorkerOwnershipAndPublishedOnlyByUiCompletion()
{
var canvas = new Canvas(); var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
TerminalProgramRequest? request = null;
var desktop = new DesktopSession(canvas, storage) { TerminalProgramRequested = value => request = value };
var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll");
Assert.NotNull(request); Assert.True(window.TerminalProgramRunning); var frozen = window.Terminal;
Assert.Equal(window.Id, request.WindowId); Assert.Same(window.Shell!.ProgramOutput, request.Output);
request.Output.Write("\u001b[38;2;23;45;67mWORKER ANSI\u001b[0m\r\n");
Assert.False(desktop.PasteTerminalInput("echo blocked")); desktop.Key(DesktopKey.Character, 'x'); desktop.Key(DesktopKey.Enter);
Assert.Empty(window.Shell.Input); Assert.Equal(new[] { "run App.dll" }, window.Shell.History);
desktop.Key(DesktopKey.Cancel); Assert.Contains("cannot interrupt", window.Status);
desktop.Render(); Assert.Same(frozen, window.Terminal); Assert.DoesNotContain("WORKER ANSI", canvas.TerminalText(window));
desktop.RefreshTerminalOutput(window.Id); Assert.False(window.TerminalProgramRunning); canvas.Clear(); desktop.Render();
Assert.Contains("WORKER ANSI", canvas.TerminalText(window));
Assert.Contains(canvas.Texts, item => item.Color == 0x172D43 && item.Text == "W");
Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
}
[Fact]
public void ClosedProgramWindowIsNotReopenedByItsLateCompletion()
{
var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
TerminalProgramRequest? request = null;
var desktop = new DesktopSession(new Canvas(), storage) { TerminalProgramRequested = value => request = value };
var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll"); desktop.Close(window.Id);
request!.Output.WriteLine("Late output"); desktop.RefreshTerminalOutput(window.Id);
Assert.Empty(desktop.Windows);
}
[Fact]
public void CaretBlinksAndLongInputStaysInsideTheTerminalAfterResize()
{
var canvas = new Canvas(); long now = 0;
var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), monotonicMilliseconds: () => now);
var window = desktop.Open(DesktopApplication.Terminal); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
now = 500; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.False(canvas.HasTerminalCaret(window));
now = 1000; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
desktop.PasteTerminalInput(new string('a', 200));
var original = window.Bounds; int x = original.X + original.Width - 5, y = original.Y + original.Height - 5;
desktop.Pointer(x, y, true); desktop.Pointer(x - 480, y, true); desktop.Pointer(x - 480, y, false);
canvas.Clear(); desktop.Render(); Assert.True(window.Bounds.Width < original.Width);
foreach (var item in canvas.Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2))
Assert.True(item.X + canvas.TextWidth(item.Text) <= window.Bounds.X + window.Bounds.Width - 2, item.Text);
desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Character, 'Z'); Assert.StartsWith("Z", window.Shell!.Input);
}
[Fact]
public void RealWheelScrollsCompletedOutputAndTypingReturnsToTheLivePrompt()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
for (int index = 0; index < 45; index++) Run(desktop, "echo row" + index);
desktop.Render(); string tail = canvas.TerminalText(window); Assert.Contains("row44", tail);
int x = window.Bounds.X + 100, y = window.Bounds.Y + 160;
desktop.Pointer(x, y, false, wheel: 3); canvas.Clear(); desktop.Render(); string earlier = canvas.TerminalText(window);
Assert.NotEqual(tail, earlier); Assert.DoesNotContain("row44", earlier);
desktop.Key(DesktopKey.Character, 'h'); canvas.Clear(); desktop.Render(); Assert.Contains("row44", canvas.TerminalText(window));
}
[Fact]
public void LegacySnapshotOutputRetainsItsAnsiColorsAlongsideTheShell()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
var output = new TerminalBuffer(40, 4); output.Write("\u001b[38;2;11;22;33mStyled legacy\u001b[0m\r\n");
desktop.SetTerminalSnapshot(output.Snapshot()); var window = desktop.ActiveWindow!; desktop.Render();
Assert.Contains("Styled legacy", canvas.TerminalText(window));
Assert.Contains(canvas.Texts, item => item.Text == "S" && item.Color == 0x0B1621);
Run(desktop, "echo usable"); Assert.Contains("usable", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
}
[Theory]
[InlineData("")]
[InlineData("\r")]
public void PartialProgramLinesRemainVisibleAndThePromptAndSubmittedCommandStartOnTheNextRow(string ending)
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
desktop.WriteTerminalOutput("\u001b[38;2;1;2;3mpartial" + ending + "\u001b[0m", window.Id); desktop.Render();
int outputY = canvas.Texts.First(item => item.Color == 0x010203).Y;
var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
Assert.Equal(outputY + 20, prompt.Y);
Run(desktop, "echo next");
var frame = window.Terminal!;
string previous = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 3).Text));
string command = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 4).Text));
Assert.StartsWith("partial", previous); Assert.DoesNotContain("> ", previous); Assert.Contains("> echo next", command);
}
private static void Run(DesktopSession desktop, string command)
{ Assert.True(desktop.PasteTerminalInput(command)); desktop.Key(DesktopKey.Enter); }
private sealed class Canvas : IDesktopCanvas
{
public int Width => 1280; public int Height => 800;
public readonly List<(string Text, uint Color, int X, int Y)> Texts = [];
public readonly List<(uint Color, int X, int Y, int Width, int Height)> Fills = [];
public int TextWidth(string text) => text.EnumerateRunes().Sum(rune => rune.Value > 255 ? 16 : 8);
public void Fill(uint rgb, int x, int y, int width, int height) => Fills.Add((rgb, x, y, width, height));
public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
public void Text(string text, uint rgb, int x, int y) => Texts.Add((text, rgb, x, y));
public void Present() { }
public void Clear() { Texts.Clear(); Fills.Clear(); }
public string TerminalText(DesktopWindow window)
{
var result = new StringBuilder();
foreach (var row in Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2)
.GroupBy(item => item.Y).OrderBy(row => row.Key))
{
int right = row.Min(item => item.X);
foreach (var item in row.OrderBy(item => item.X))
{
if (item.X - right >= 8) result.Append(' ', (item.X - right) / 8);
result.Append(item.Text); right = item.X + TextWidth(item.Text);
}
result.AppendLine();
}
return result.ToString();
}
public bool HasTerminalCaret(DesktopWindow window) => Fills.Any(item => item.Color == 0x75C9F5 && item.Width == 2 && item.Height == 16 && item.Y >= window.Bounds.Y + 35);
}
}
using System.Text;
using XFESystem.Console;
using XFESystem.Core;
using Xunit;
namespace XFESystem.Desktop.Tests;
public sealed class TerminalDesktopTests
{
[Fact]
public void OpeningTerminalPaintsTheConciseBlueShellWithoutDemoToolbarOrDemoHitRegion()
{
var canvas = new Canvas(); int demos = 0;
var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), consoleDemo: () => demos++);
var window = desktop.Open(DesktopApplication.Terminal); desktop.Render();
Assert.NotNull(window.Shell); Assert.Equal("0.3.0-dev.4", window.Shell.Version);
string text = canvas.TerminalText(window);
Assert.Contains("XFESystem|XFEstudio", text); Assert.Contains("0.3.0-dev.4", text); Assert.Contains("help", text);
Assert.DoesNotContain("Run Demo", text); Assert.DoesNotContain("development session", text);
Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, true);
desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, false);
Assert.Equal(0, demos); Assert.Same(window, desktop.ActiveWindow);
}
[Fact]
public void DesktopKeyboardAndPasteExecuteRealRamCommandsAndRetainHistoryDraft()
{
var storage = new MemoryWorkspace(false); var desktop = new DesktopSession(new Canvas(), storage);
var window = desktop.Open(DesktopApplication.Terminal);
Run(desktop, "md Work"); Run(desktop, "cd Work"); Run(desktop, "mf Hello.txt"); Run(desktop, "write Hello.txt \"Hello XFE\"");
Assert.Equal("Hello XFE", storage.ReadText(SystemPaths.Documents + "\\Work\\Hello.txt"));
Assert.Equal(SystemPaths.Documents + "\\Work", window.Location);
Assert.True(desktop.PasteTerminalInput("draft")); desktop.Key(DesktopKey.Up); Assert.Equal("write Hello.txt \"Hello XFE\"", window.Shell!.Input);
desktop.Key(DesktopKey.Up); Assert.Equal("mf Hello.txt", window.Shell.Input);
desktop.Key(DesktopKey.Down); desktop.Key(DesktopKey.Down); Assert.Equal("draft", window.Shell.Input);
desktop.Key(DesktopKey.Escape); Assert.Empty(window.Shell.Input); Assert.Same(window, desktop.ActiveWindow);
Assert.False(desktop.PasteTerminalInput("mf Bad.txt\n"));
Run(desktop, "cat Hello.txt"); Assert.Contains("Hello XFE", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
desktop.Key(DesktopKey.CloseWindow); Assert.Empty(desktop.Windows);
}
[Fact]
public void MouseMovesTheInputCaretAndLeftDeleteInsertContinueEditingTheSameCommand()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
var window = desktop.Open(DesktopApplication.Terminal); Assert.True(desktop.PasteTerminalInput("abcd")); desktop.Render();
var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
int x = prompt.X + canvas.TextWidth(prompt.Text) + 16, y = prompt.Y + 7;
desktop.Pointer(x, y, true); desktop.Pointer(x, y, false); Assert.Equal(2, window.Shell!.Caret);
desktop.Key(DesktopKey.Delete); desktop.Key(DesktopKey.Character, 'X'); Assert.Equal("abXd", window.Shell.Input);
desktop.Key(DesktopKey.Left); desktop.Key(DesktopKey.Backspace); Assert.Equal("aXd", window.Shell.Input);
desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Insert); desktop.Key(DesktopKey.Character, 'Z'); Assert.Equal("ZXd", window.Shell.Input);
}
[Fact]
public void ProgramOutputIsFrozenDuringWorkerOwnershipAndPublishedOnlyByUiCompletion()
{
var canvas = new Canvas(); var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
TerminalProgramRequest? request = null;
var desktop = new DesktopSession(canvas, storage) { TerminalProgramRequested = value => request = value };
var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll");
Assert.NotNull(request); Assert.True(window.TerminalProgramRunning); var frozen = window.Terminal;
Assert.Equal(window.Id, request.WindowId); Assert.Same(window.Shell!.ProgramOutput, request.Output);
request.Output.Write("\u001b[38;2;23;45;67mWORKER ANSI\u001b[0m\r\n");
Assert.False(desktop.PasteTerminalInput("echo blocked")); desktop.Key(DesktopKey.Character, 'x'); desktop.Key(DesktopKey.Enter);
Assert.Empty(window.Shell.Input); Assert.Equal(new[] { "run App.dll" }, window.Shell.History);
desktop.Key(DesktopKey.Cancel); Assert.Contains("cannot interrupt", window.Status);
desktop.Render(); Assert.Same(frozen, window.Terminal); Assert.DoesNotContain("WORKER ANSI", canvas.TerminalText(window));
desktop.RefreshTerminalOutput(window.Id); Assert.False(window.TerminalProgramRunning); canvas.Clear(); desktop.Render();
Assert.Contains("WORKER ANSI", canvas.TerminalText(window));
Assert.Contains(canvas.Texts, item => item.Color == 0x172D43 && item.Text == "W");
Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
}
[Fact]
public void ClosedProgramWindowIsNotReopenedByItsLateCompletion()
{
var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
TerminalProgramRequest? request = null;
var desktop = new DesktopSession(new Canvas(), storage) { TerminalProgramRequested = value => request = value };
var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll"); desktop.Close(window.Id);
request!.Output.WriteLine("Late output"); desktop.RefreshTerminalOutput(window.Id);
Assert.Empty(desktop.Windows);
}
[Fact]
public void CaretBlinksAndLongInputStaysInsideTheTerminalAfterResize()
{
var canvas = new Canvas(); long now = 0;
var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), monotonicMilliseconds: () => now);
var window = desktop.Open(DesktopApplication.Terminal); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
now = 500; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.False(canvas.HasTerminalCaret(window));
now = 1000; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
desktop.PasteTerminalInput(new string('a', 200));
var original = window.Bounds; int x = original.X + original.Width - 5, y = original.Y + original.Height - 5;
desktop.Pointer(x, y, true); desktop.Pointer(x - 480, y, true); desktop.Pointer(x - 480, y, false);
canvas.Clear(); desktop.Render(); Assert.True(window.Bounds.Width < original.Width);
foreach (var item in canvas.Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2))
Assert.True(item.X + canvas.TextWidth(item.Text) <= window.Bounds.X + window.Bounds.Width - 2, item.Text);
desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Character, 'Z'); Assert.StartsWith("Z", window.Shell!.Input);
}
[Fact]
public void RealWheelScrollsCompletedOutputAndTypingReturnsToTheLivePrompt()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
for (int index = 0; index < 45; index++) Run(desktop, "echo row" + index);
desktop.Render(); string tail = canvas.TerminalText(window); Assert.Contains("row44", tail);
int x = window.Bounds.X + 100, y = window.Bounds.Y + 160;
desktop.Pointer(x, y, false, wheel: 3); canvas.Clear(); desktop.Render(); string earlier = canvas.TerminalText(window);
Assert.NotEqual(tail, earlier); Assert.DoesNotContain("row44", earlier);
desktop.Key(DesktopKey.Character, 'h'); canvas.Clear(); desktop.Render(); Assert.Contains("row44", canvas.TerminalText(window));
}
[Fact]
public void LegacySnapshotOutputRetainsItsAnsiColorsAlongsideTheShell()
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
var output = new TerminalBuffer(40, 4); output.Write("\u001b[38;2;11;22;33mStyled legacy\u001b[0m\r\n");
desktop.SetTerminalSnapshot(output.Snapshot()); var window = desktop.ActiveWindow!; desktop.Render();
Assert.Contains("Styled legacy", canvas.TerminalText(window));
Assert.Contains(canvas.Texts, item => item.Text == "S" && item.Color == 0x0B1621);
Run(desktop, "echo usable"); Assert.Contains("usable", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
}
[Theory]
[InlineData("")]
[InlineData("\r")]
public void PartialProgramLinesRemainVisibleAndThePromptAndSubmittedCommandStartOnTheNextRow(string ending)
{
var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
desktop.WriteTerminalOutput("\u001b[38;2;1;2;3mpartial" + ending + "\u001b[0m", window.Id); desktop.Render();
int outputY = canvas.Texts.First(item => item.Color == 0x010203).Y;
var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
Assert.Equal(outputY + 20, prompt.Y);
Run(desktop, "echo next");
var frame = window.Terminal!;
string previous = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 3).Text));
string command = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 4).Text));
Assert.StartsWith("partial", previous); Assert.DoesNotContain("> ", previous); Assert.Contains("> echo next", command);
}
private static void Run(DesktopSession desktop, string command)
{ Assert.True(desktop.PasteTerminalInput(command)); desktop.Key(DesktopKey.Enter); }
private sealed class Canvas : IDesktopCanvas
{
public int Width => 1280; public int Height => 800;
public readonly List<(string Text, uint Color, int X, int Y)> Texts = [];
public readonly List<(uint Color, int X, int Y, int Width, int Height)> Fills = [];
public int TextWidth(string text) => text.EnumerateRunes().Sum(rune => rune.Value > 255 ? 16 : 8);
public void Fill(uint rgb, int x, int y, int width, int height) => Fills.Add((rgb, x, y, width, height));
public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
public void Text(string text, uint rgb, int x, int y) => Texts.Add((text, rgb, x, y));
public void Present() { }
public void Clear() { Texts.Clear(); Fills.Clear(); }
public string TerminalText(DesktopWindow window)
{
var result = new StringBuilder();
foreach (var row in Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2)
.GroupBy(item => item.Y).OrderBy(row => row.Key))
{
int right = row.Min(item => item.X);
foreach (var item in row.OrderBy(item => item.X))
{
if (item.X - right >= 8) result.Append(' ', (item.X - right) / 8);
result.Append(item.Text); right = item.X + TextWidth(item.Text);
}
result.AppendLine();
}
return result.ToString();
}
public bool HasTerminalCaret(DesktopWindow window) => Fills.Any(item => item.Color == 0x75C9F5 && item.Width == 2 && item.Height == 16 && item.Y >= window.Bounds.Y + 35);
}
}