Skip to content

Commit 5354f54

Browse files
rogeralsingclaude
andcommitted
Fix live panel width to prevent UI flickering
- Set fixed 80-character panel width - Truncate all content to fit within panel - Cap progress bar at 100% to handle count mismatches - Wrap panel in fixed-width table container Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 630bd6b commit 5354f54

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

src/Asynkron.TestRunner/LiveDisplay.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ namespace Asynkron.TestRunner;
99
/// </summary>
1010
public class LiveDisplay
1111
{
12+
private const int PanelWidth = 80;
13+
private const int ContentWidth = PanelWidth - 4; // Account for panel borders
14+
1215
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
1316
private readonly object _lock = new();
1417

@@ -29,15 +32,15 @@ public void SetTotal(int total)
2932

3033
public void TestStarted(string displayName)
3134
{
32-
lock (_lock) _running.Add(Truncate(displayName, 60));
35+
lock (_lock) _running.Add(Truncate(displayName, ContentWidth));
3336
}
3437

3538
public void TestPassed(string displayName)
3639
{
3740
lock (_lock)
3841
{
3942
_passed++;
40-
_running.Remove(Truncate(displayName, 60));
43+
_running.Remove(Truncate(displayName, ContentWidth));
4144
_lastCompleted = displayName;
4245
_lastStatus = "[green]✓[/]";
4346
}
@@ -48,7 +51,7 @@ public void TestFailed(string displayName)
4851
lock (_lock)
4952
{
5053
_failed++;
51-
_running.Remove(Truncate(displayName, 60));
54+
_running.Remove(Truncate(displayName, ContentWidth));
5255
_lastCompleted = displayName;
5356
_lastStatus = "[red]✗[/]";
5457
}
@@ -59,7 +62,7 @@ public void TestSkipped(string displayName)
5962
lock (_lock)
6063
{
6164
_skipped++;
62-
_running.Remove(Truncate(displayName, 60));
65+
_running.Remove(Truncate(displayName, ContentWidth));
6366
_lastCompleted = displayName;
6467
_lastStatus = "[yellow]○[/]";
6568
}
@@ -70,7 +73,7 @@ public void TestHanging(string displayName)
7073
lock (_lock)
7174
{
7275
_hanging++;
73-
_running.Remove(Truncate(displayName, 60));
76+
_running.Remove(Truncate(displayName, ContentWidth));
7477
_lastCompleted = displayName;
7578
_lastStatus = "[red]⏱[/]";
7679
}
@@ -81,7 +84,7 @@ public void TestCrashed(string displayName)
8184
lock (_lock)
8285
{
8386
_crashed++;
84-
_running.Remove(Truncate(displayName, 60));
87+
_running.Remove(Truncate(displayName, ContentWidth));
8588
_lastCompleted = displayName;
8689
_lastStatus = "[red]💥[/]";
8790
}
@@ -129,21 +132,29 @@ public IRenderable Render()
129132
CreateRunningSection()
130133
);
131134

132-
return new Panel(layout)
135+
var panel = new Panel(layout)
133136
.Header($"[bold]Test Progress[/] [dim]({completed}/{_total})[/]")
134137
.Border(BoxBorder.Rounded)
135-
.BorderColor(Color.Grey);
138+
.BorderColor(Color.Grey)
139+
.Expand();
140+
141+
// Wrap in a fixed-width container
142+
var table = new Table().NoBorder().HideHeaders();
143+
table.AddColumn(new TableColumn("").Width(PanelWidth));
144+
table.AddRow(panel);
145+
146+
return table;
136147
}
137148
}
138149

139150
private IRenderable CreateProgressBar(int completed, int total)
140151
{
141152
if (total == 0) return new Text("");
142153

143-
var percentage = (double)completed / total;
144-
var width = Math.Min(60, Console.WindowWidth - 10);
145-
var filled = (int)(percentage * width);
146-
var empty = width - filled;
154+
var percentage = Math.Min(1.0, (double)completed / total);
155+
var barWidth = ContentWidth - 7; // Leave room for " 100 %"
156+
var filled = (int)(percentage * barWidth);
157+
var empty = barWidth - filled;
147158

148159
var color = _failed > 0 || _crashed > 0 || _hanging > 0 ? "red" : "green";
149160
var bar = $"[{color}]{new string('█', filled)}[/][dim]{new string('░', empty)}[/]";
@@ -154,18 +165,19 @@ private IRenderable CreateProgressBar(int completed, int total)
154165
private IRenderable CreateRunningSection()
155166
{
156167
var lines = new List<IRenderable>();
168+
var textWidth = ContentWidth - 4; // Leave room for status icon and spacing
157169

158170
if (_lastCompleted != null && _lastStatus != null)
159171
{
160-
lines.Add(new Markup($"{_lastStatus} {Markup.Escape(Truncate(_lastCompleted, 70))}"));
172+
lines.Add(new Markup($"{_lastStatus} {Markup.Escape(Truncate(_lastCompleted, textWidth))}"));
161173
}
162174

163175
if (_running.Count > 0)
164176
{
165177
var runningList = _running.Take(3).ToList();
166178
foreach (var test in runningList)
167179
{
168-
lines.Add(new Markup($"[dim]► {Markup.Escape(test)}[/]"));
180+
lines.Add(new Markup($"[dim]► {Markup.Escape(Truncate(test, textWidth))}[/]"));
169181
}
170182
if (_running.Count > 3)
171183
{

0 commit comments

Comments
 (0)