fix stats formatting 3 on export option
This commit is contained in:
Binary file not shown.
@@ -10,133 +10,138 @@ namespace HanaTui.Tui.Components;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StatsPanel
|
public static class StatsPanel
|
||||||
{
|
{
|
||||||
public static IRenderable Build(SystemSnapshot snap, TimeSpan elapsed, int panelWidth)
|
public static IRenderable Build(SystemSnapshot snap, TimeSpan elapsed, int panelWidth)
|
||||||
|
{
|
||||||
|
var barWidth = Math.Max(10, panelWidth - 16);
|
||||||
|
|
||||||
|
var grid = new Grid();
|
||||||
|
grid.AddColumn(new GridColumn().NoWrap());
|
||||||
|
|
||||||
|
// --- CPU ---
|
||||||
|
grid.AddRow(new Markup("[bold yellow]CPU[/]"));
|
||||||
|
|
||||||
|
if (snap.CpuPercents.Length == 0)
|
||||||
{
|
{
|
||||||
var barWidth = Math.Max(10, panelWidth - 16);
|
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||||
|
}
|
||||||
var grid = new Grid();
|
else
|
||||||
grid.AddColumn(new GridColumn().NoWrap());
|
{
|
||||||
|
for (int i = 0; i < snap.CpuPercents.Length; i++)
|
||||||
// --- CPU ---
|
{
|
||||||
grid.AddRow(new Markup("[bold yellow]CPU[/]"));
|
var label = snap.CpuLabels.Length > i ? snap.CpuLabels[i] : $"cpu{i}";
|
||||||
|
var displayLabel = label == "cpu" ? "Total" : label.Replace("cpu", "Core");
|
||||||
if (snap.CpuPercents.Length == 0)
|
var pct = snap.CpuPercents[i];
|
||||||
{
|
// Build as Columns: label | bar | pct — no interpolation of dynamic values into markup
|
||||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
grid.AddRow(BuildBarRow(displayLabel, pct, barWidth));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < snap.CpuPercents.Length; i++)
|
|
||||||
{
|
|
||||||
var label = snap.CpuLabels.Length > i ? snap.CpuLabels[i] : $"cpu{i}";
|
|
||||||
var displayLabel = label == "cpu" ? "Total" : label.Replace("cpu", "Core");
|
|
||||||
var pct = snap.CpuPercents[i];
|
|
||||||
// Build as Columns: label | bar | pct — no interpolation of dynamic values into markup
|
|
||||||
grid.AddRow(BuildBarRow(displayLabel, pct, barWidth));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.AddRow(new Text(""));
|
|
||||||
|
|
||||||
// --- Memory ---
|
|
||||||
grid.AddRow(new Markup("[bold cyan]MEMORY[/]"));
|
|
||||||
if (snap.MemTotalKb > 0)
|
|
||||||
{
|
|
||||||
var memPct = snap.MemUsedPercent;
|
|
||||||
grid.AddRow(BuildBarRow("Used", memPct, barWidth));
|
|
||||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.MemUsedKb)} / {SystemSnapshot.FormatGb(snap.MemTotalKb)}",
|
|
||||||
new Style(Color.Grey)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.AddRow(new Text(""));
|
|
||||||
|
|
||||||
// --- Swap ---
|
|
||||||
grid.AddRow(new Markup("[bold cyan]SWAP[/]"));
|
|
||||||
if (snap.SwapTotalKb > 0)
|
|
||||||
{
|
|
||||||
var swapPct = snap.SwapUsedPercent;
|
|
||||||
grid.AddRow(BuildBarRow("Used", swapPct, barWidth));
|
|
||||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.SwapUsedKb)} / {SystemSnapshot.FormatGb(snap.SwapTotalKb)}",
|
|
||||||
new Style(Color.Grey)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
grid.AddRow(new Markup("[grey]No swap[/]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.AddRow(new Text(""));
|
|
||||||
|
|
||||||
// --- Elapsed ---
|
|
||||||
// Two separate renderables composed — no interpolation of elapsed into markup
|
|
||||||
var elapsedGrid = new Grid();
|
|
||||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
|
||||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
|
||||||
elapsedGrid.AddRow(
|
|
||||||
new Markup("[bold]Elapsed:[/]"),
|
|
||||||
new Text(" " + FormatElapsed(elapsed), new Style(Color.Yellow)));
|
|
||||||
grid.AddRow(elapsedGrid);
|
|
||||||
|
|
||||||
return new Panel(grid)
|
|
||||||
{
|
|
||||||
Header = new PanelHeader("[bold] SYSTEM STATS [/]"),
|
|
||||||
Border = BoxBorder.Rounded,
|
|
||||||
Padding = new Padding(1, 0),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
grid.AddRow(new Text(""));
|
||||||
// Helpers
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// <summary>
|
// --- Memory ---
|
||||||
/// Builds a single bar row as a Grid with three columns:
|
grid.AddRow(new Markup("[bold cyan]MEMORY[/]"));
|
||||||
/// label (dim) | bar (block chars, plain Text with color) | pct (bold)
|
if (snap.MemTotalKb > 0)
|
||||||
/// Nothing here goes through markup parsing with dynamic content.
|
|
||||||
/// </summary>
|
|
||||||
private static IRenderable BuildBarRow(string label, double pct, int barWidth)
|
|
||||||
{
|
{
|
||||||
var filled = (int)Math.Round(pct / 100.0 * barWidth);
|
var memPct = snap.MemUsedPercent;
|
||||||
filled = Math.Clamp(filled, 0, barWidth);
|
grid.AddRow(BuildBarRow("Used", memPct, barWidth));
|
||||||
var empty = barWidth - filled;
|
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.MemUsedKb)} / {SystemSnapshot.FormatGb(snap.MemTotalKb)}",
|
||||||
|
new Style(Color.Grey)));
|
||||||
var filledColor = CpuColor(pct);
|
}
|
||||||
var filledStr = new string('\u2588', filled);
|
else
|
||||||
var emptyStr = new string('\u2591', empty);
|
{
|
||||||
|
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||||
var row = new Grid();
|
|
||||||
row.AddColumn(new GridColumn().NoWrap());
|
|
||||||
var colorMarkup = filledColor.ToMarkup();
|
|
||||||
|
|
||||||
// Construct a seamless markup string
|
|
||||||
var barMarkup = $"[grey][[[/][{colorMarkup}]{filledStr}[/][grey dim]{emptyStr}[/][grey]]][/]";
|
|
||||||
|
|
||||||
row.AddRow(
|
|
||||||
new Text($" {label,-5}", new Style(Color.Grey, decoration: Decoration.Dim)),
|
|
||||||
new Markup(barMarkup), // Replace Columns with a single Markup object
|
|
||||||
new Text($" {pct,5:F1}%", new Style(Color.White, decoration: Decoration.Bold))
|
|
||||||
);
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color CpuColor(double pct) => pct switch
|
grid.AddRow(new Text(""));
|
||||||
|
|
||||||
|
// --- Swap ---
|
||||||
|
grid.AddRow(new Markup("[bold cyan]SWAP[/]"));
|
||||||
|
if (snap.SwapTotalKb > 0)
|
||||||
{
|
{
|
||||||
> 90 => Color.Red,
|
var swapPct = snap.SwapUsedPercent;
|
||||||
> 70 => Color.Yellow,
|
grid.AddRow(BuildBarRow("Used", swapPct, barWidth));
|
||||||
> 40 => Color.Green,
|
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.SwapUsedKb)} / {SystemSnapshot.FormatGb(snap.SwapTotalKb)}",
|
||||||
_ => Color.Blue,
|
new Style(Color.Grey)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
grid.AddRow(new Markup("[grey]No swap[/]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.AddRow(new Text(""));
|
||||||
|
|
||||||
|
// --- Elapsed ---
|
||||||
|
// Two separate renderables composed — no interpolation of elapsed into markup
|
||||||
|
var elapsedGrid = new Grid();
|
||||||
|
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||||
|
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||||
|
elapsedGrid.AddRow(
|
||||||
|
new Markup("[bold]Elapsed:[/]"),
|
||||||
|
new Text(" " + FormatElapsed(elapsed), new Style(Color.Yellow)));
|
||||||
|
grid.AddRow(elapsedGrid);
|
||||||
|
|
||||||
|
return new Panel(grid)
|
||||||
|
{
|
||||||
|
Header = new PanelHeader("[bold] SYSTEM STATS [/]"),
|
||||||
|
Border = BoxBorder.Rounded,
|
||||||
|
Padding = new Padding(1, 0),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatElapsed(TimeSpan t)
|
// -------------------------------------------------------------------------
|
||||||
{
|
// Helpers
|
||||||
if (t.TotalHours >= 1)
|
// -------------------------------------------------------------------------
|
||||||
return $"{(int)t.TotalHours}h {t.Minutes:D2}m {t.Seconds:D2}s";
|
|
||||||
if (t.TotalMinutes >= 1)
|
/// <summary>
|
||||||
return $"{t.Minutes}m {t.Seconds:D2}s";
|
/// Builds a single bar row as a Grid with three columns:
|
||||||
return $"{t.Seconds}s";
|
/// label (dim) | bar (block chars, plain Text with color) | pct (bold)
|
||||||
}
|
/// Nothing here goes through markup parsing with dynamic content.
|
||||||
|
/// </summary>
|
||||||
|
private static IRenderable BuildBarRow(string label, double pct, int barWidth)
|
||||||
|
{
|
||||||
|
var filled = (int)Math.Round(pct / 100.0 * barWidth);
|
||||||
|
filled = Math.Clamp(filled, 0, barWidth);
|
||||||
|
var empty = barWidth - filled;
|
||||||
|
|
||||||
|
var filledColor = CpuColor(pct);
|
||||||
|
var filledStr = new string('\u2588', filled);
|
||||||
|
var emptyStr = new string('\u2591', empty);
|
||||||
|
|
||||||
|
var row = new Grid();
|
||||||
|
|
||||||
|
// FIX: Add all three columns back!
|
||||||
|
row.AddColumn(new GridColumn().NoWrap().Width(9)); // Column 1: Label
|
||||||
|
row.AddColumn(new GridColumn().NoWrap()); // Column 2: Bar
|
||||||
|
row.AddColumn(new GridColumn().NoWrap().Width(7)); // Column 3: Pct
|
||||||
|
|
||||||
|
var colorMarkup = filledColor.ToMarkup();
|
||||||
|
|
||||||
|
// Construct a seamless markup string
|
||||||
|
var barMarkup = $"[grey][[[/][{colorMarkup}]{filledStr}[/][grey dim]{emptyStr}[/][grey]]][/]";
|
||||||
|
|
||||||
|
row.AddRow(
|
||||||
|
new Text($" {label,-5}", new Style(Color.Grey, decoration: Decoration.Dim)),
|
||||||
|
new Markup(barMarkup),
|
||||||
|
new Text($" {pct,5:F1}%", new Style(Color.White, decoration: Decoration.Bold))
|
||||||
|
);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color CpuColor(double pct) => pct switch
|
||||||
|
{
|
||||||
|
> 90 => Color.Red,
|
||||||
|
> 70 => Color.Yellow,
|
||||||
|
> 40 => Color.Green,
|
||||||
|
_ => Color.Blue,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string FormatElapsed(TimeSpan t)
|
||||||
|
{
|
||||||
|
if (t.TotalHours >= 1)
|
||||||
|
return $"{(int)t.TotalHours}h {t.Minutes:D2}m {t.Seconds:D2}s";
|
||||||
|
if (t.TotalMinutes >= 1)
|
||||||
|
return $"{t.Minutes}m {t.Seconds:D2}s";
|
||||||
|
return $"{t.Seconds}s";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user