fix color formatting core dump

This commit is contained in:
2026-05-20 11:20:00 +02:00
parent 27cf1b6314
commit 3e9d80fe98
3 changed files with 74 additions and 33 deletions
+54 -21
View File
@@ -1,5 +1,6 @@
using HanaTui.Hana; using HanaTui.Hana;
using Spectre.Console; using Spectre.Console;
using SysText = System.Text;
namespace HanaTui.Tui; namespace HanaTui.Tui;
@@ -9,6 +10,10 @@ namespace HanaTui.Tui;
/// </summary> /// </summary>
public static class KeySelectionScreen public static class KeySelectionScreen
{ {
// Sentinel values for the non-key choices
private const string ManualEntry = "__MANUAL__";
private const string ExitChoice = "__EXIT__";
public static string? Run() public static string? Run()
{ {
AnsiConsole.Clear(); AnsiConsole.Clear();
@@ -28,7 +33,7 @@ public static class KeySelectionScreen
// Show client path for reference // Show client path for reference
var clientDir = HdbClientLocator.ClientDirectory; var clientDir = HdbClientLocator.ClientDirectory;
if (clientDir is not null) if (clientDir is not null)
AnsiConsole.MarkupLine($"[dim]HDB client: {clientDir}[/]\n"); AnsiConsole.MarkupLine($"[dim]HDB client: {Markup.Escape(clientDir)}[/]\n");
// Load keys with a spinner // Load keys with a spinner
List<HdbUserstoreKey> keys = []; List<HdbUserstoreKey> keys = [];
@@ -47,49 +52,77 @@ public static class KeySelectionScreen
AnsiConsole.MarkupLine("You can still enter a key name manually.\n"); AnsiConsole.MarkupLine("You can still enter a key name manually.\n");
} }
// Build selection choices // Build a plain-string list where the value IS the key name (or sentinel).
var choices = new List<string>(); // We use SelectionPrompt<string> with a display converter so Spectre renders
// the label as markup but we always get back the plain key name.
var choiceNames = new List<string>();
var displayMap = new Dictionary<string, string>(); // name -> display label
foreach (var k in keys) foreach (var k in keys)
{ {
var detail = BuildKeyDetail(k); choiceNames.Add(k.Name);
choices.Add(detail); displayMap[k.Name] = BuildKeyDisplay(k);
} }
choices.Add("[dim][ Enter key name manually ][/]");
choices.Add("[red][ Exit ][/]"); choiceNames.Add(ManualEntry);
displayMap[ManualEntry] = "[ Enter key name manually ]";
choiceNames.Add(ExitChoice);
displayMap[ExitChoice] = "[ Exit ]";
var prompt = new SelectionPrompt<string>() var prompt = new SelectionPrompt<string>()
.Title("[bold]Select HDBUSERSTORE key:[/]") .Title("[bold]Select HDBUSERSTORE key:[/]")
.PageSize(15) .PageSize(15)
.HighlightStyle(Style.Parse("bold dodgerblue1")) .HighlightStyle(Style.Parse("bold dodgerblue1"))
.AddChoices(choices); .UseConverter(name => displayMap.TryGetValue(name, out var label) ? label : name)
.AddChoices(choiceNames);
var selected = AnsiConsole.Prompt(prompt); var selected = AnsiConsole.Prompt(prompt);
if (selected.Contains("Exit")) if (selected == ExitChoice)
return null; return null;
if (selected.Contains("manually")) if (selected == ManualEntry)
{ {
var manual = AnsiConsole.Ask<string>("[bold]Enter HDBUSERSTORE key name:[/]").Trim(); var manual = AnsiConsole.Ask<string>("[bold]Enter HDBUSERSTORE key name:[/]").Trim();
return string.IsNullOrWhiteSpace(manual) ? null : manual; return string.IsNullOrWhiteSpace(manual) ? null : manual;
} }
// Extract the key name from the formatted string (it's always the first word) // selected is already the plain key name
var keyName = selected.Split(' ')[0].Trim(); return selected;
return keyName;
} }
private static string BuildKeyDetail(HdbUserstoreKey k) /// <summary>
/// Builds a plain-text display label (no markup) for a key.
/// Spectre's UseConverter renders the returned string as plain text.
/// </summary>
private static string BuildKeyDisplay(HdbUserstoreKey k)
{ {
var parts = new List<string> { k.Name }; var sb = new SysText.StringBuilder(k.Name);
if (!string.IsNullOrEmpty(k.Host)) if (!string.IsNullOrEmpty(k.Host))
parts.Add($"[dim]{k.Host}:{k.Port}[/]"); {
if (!string.IsNullOrEmpty(k.Tenant)) sb.Append(" ");
parts.Add($"[dim]@{k.Tenant}[/]"); sb.Append(k.Host);
if (!string.IsNullOrEmpty(k.User)) if (!string.IsNullOrEmpty(k.Port))
parts.Add($"[dim]user={k.User}[/]"); {
sb.Append(':');
sb.Append(k.Port);
}
}
return string.Join(" ", parts); if (!string.IsNullOrEmpty(k.Tenant))
{
sb.Append('@');
sb.Append(k.Tenant);
}
if (!string.IsNullOrEmpty(k.User))
{
sb.Append(" user=");
sb.Append(k.User);
}
return sb.ToString();
} }
} }
+5 -5
View File
@@ -32,15 +32,15 @@ public static class MainMenuScreen
if (key is not null) if (key is not null)
{ {
var conn = key.Host + ":" + key.Port +
(string.IsNullOrEmpty(key.Tenant) ? "" : "@" + key.Tenant) +
" user=" + key.User;
AnsiConsole.MarkupLine( AnsiConsole.MarkupLine(
$" Key: [bold yellow]{key.Name}[/] " + $" Key: [bold yellow]{Markup.Escape(key.Name)}[/] [dim]{Markup.Escape(conn)}[/]");
$"[dim]{key.Host}:{key.Port}" +
(string.IsNullOrEmpty(key.Tenant) ? "" : $"@{key.Tenant}") +
$" user={key.User}[/]");
} }
else else
{ {
AnsiConsole.MarkupLine($" Key: [bold yellow]{keyName}[/]"); AnsiConsole.MarkupLine($" Key: [bold yellow]{Markup.Escape(keyName)}[/]");
} }
AnsiConsole.WriteLine(); AnsiConsole.WriteLine();
+15 -7
View File
@@ -38,22 +38,30 @@ public static class OperationForms
if (error is not null) if (error is not null)
AnsiConsole.MarkupLine($"[yellow][[WARN]] Could not fetch schemas: {Markup.Escape(error)}[/]"); AnsiConsole.MarkupLine($"[yellow][[WARN]] Could not fetch schemas: {Markup.Escape(error)}[/]");
var choices = new List<string>(schemas); // Use sentinel strings as values so no markup leaks into choice labels
choices.Add("[dim][ Enter manually ][/]"); const string manualSentinel = "__MANUAL__";
choices.Add("[dim][ Cancel ][/]"); const string cancelSentinel = "__CANCEL__";
var choiceValues = new List<string>(schemas) { manualSentinel, cancelSentinel };
var prompt = new SelectionPrompt<string>() var prompt = new SelectionPrompt<string>()
.Title($"[bold]{title}[/]") .Title($"[bold]{Markup.Escape(title)}[/]")
.PageSize(15) .PageSize(15)
.HighlightStyle(Style.Parse("bold dodgerblue1")) .HighlightStyle(Style.Parse("bold dodgerblue1"))
.AddChoices(choices); .UseConverter(v => v switch
{
manualSentinel => "[ Enter manually ]",
cancelSentinel => "[ Cancel ]",
_ => v,
})
.AddChoices(choiceValues);
var selected = AnsiConsole.Prompt(prompt); var selected = AnsiConsole.Prompt(prompt);
if (selected.Contains("Cancel")) if (selected == cancelSentinel)
return null; return null;
if (selected.Contains("manually")) if (selected == manualSentinel)
{ {
var manual = AnsiConsole.Ask<string>("Enter schema name:").Trim(); var manual = AnsiConsole.Ask<string>("Enter schema name:").Trim();
return string.IsNullOrWhiteSpace(manual) ? null : manual; return string.IsNullOrWhiteSpace(manual) ? null : manual;