Skip to content

Commit bd5df17

Browse files
author
fabien.menager
committed
Better console output
1 parent 1fe03b4 commit bd5df17

4 files changed

Lines changed: 236 additions & 134 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<PackageVersion Include="Basic.Reference.Assemblies.Net100" Version="1.8.4" />
2222
</ItemGroup>
2323
<ItemGroup>
24+
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
2425
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
2526
<PackageVersion Include="coverlet.collector" Version="8.0.1" />
2627
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System.Text.RegularExpressions;
2+
using Spectre.Console;
3+
4+
namespace ReadmeSample;
5+
6+
/// <summary>Spectre.Console rendering helpers used by Program.cs.</summary>
7+
internal static class ConsoleHelper
8+
{
9+
/// <summary>
10+
/// Applies Spectre.Console markup to a raw SQL string:
11+
/// string literals → green, SQL keywords → bold cyan, ef_* helpers → dim grey.
12+
/// </summary>
13+
public static string SqlMarkup(string sql)
14+
{
15+
// Escape [ and ] so Spectre doesn't misinterpret them as markup tags.
16+
var esc = Markup.Escape(sql);
17+
18+
// One-pass regex — order of alternatives matters:
19+
// group 1 → single-quoted string literals
20+
// group 2 → multi-word keywords (INNER JOIN, LEFT JOIN, ORDER BY, GROUP BY)
21+
// group 3 → single-word SQL keywords
22+
// group 4 → SQLite-specific ef_* helper functions
23+
return Regex.Replace(
24+
esc,
25+
@"('[^']*')"
26+
+ @"|(\bINNER JOIN\b|\bLEFT JOIN\b|\bORDER BY\b|\bGROUP BY\b)"
27+
+ @"|(\bSELECT\b|\bFROM\b|\bWHERE\b|\bCASE\b|\bWHEN\b|\bTHEN\b|\bELSE\b|\bEND\b"
28+
+ @"|\bAND\b|\bOR\b|\bNOT\b|\bNULL\b|\bIS\b|\bIN\b|\bON\b|\bAS\b"
29+
+ @"|\bLIMIT\b|\bCOALESCE\b|\bCAST\b)"
30+
+ @"|(\bef_\w+\b)",
31+
m =>
32+
{
33+
if (m.Groups[1].Success) return $"[green]{m.Value}[/]";
34+
if (m.Groups[2].Success || m.Groups[3].Success) return $"[bold deepskyblue1]{m.Value}[/]";
35+
if (m.Groups[4].Success) return $"[grey50]{m.Value}[/]";
36+
return m.Value;
37+
},
38+
RegexOptions.IgnoreCase);
39+
}
40+
41+
/// <summary>Renders a numbered feature section header using a yellow rule.</summary>
42+
public static void Section(int n, string title)
43+
{
44+
AnsiConsole.WriteLine();
45+
AnsiConsole.Write(
46+
new Rule($"[bold yellow]Feature {n}[/] — [white]{Markup.Escape(title)}[/]")
47+
.LeftJustified()
48+
.RuleStyle("dim yellow"));
49+
AnsiConsole.WriteLine();
50+
}
51+
52+
/// <summary>Renders a SQL string inside a rounded panel with syntax highlighting.</summary>
53+
public static void ShowSql(string sql)
54+
{
55+
AnsiConsole.Write(new Panel(new Markup(SqlMarkup(sql)))
56+
{
57+
Header = new PanelHeader("[grey50] SQL [/]"),
58+
Border = BoxBorder.Rounded,
59+
BorderStyle = Style.Parse("grey"),
60+
Padding = new Padding(1, 0, 1, 0),
61+
});
62+
AnsiConsole.WriteLine();
63+
}
64+
65+
/// <summary>Formats a currency amount in bold spring-green.</summary>
66+
public static string Money(decimal v) =>
67+
$"[bold springgreen2]{Markup.Escape(v.ToString("C"))}[/]";
68+
69+
/// <summary>Formats a boolean as coloured true/false.</summary>
70+
public static string BoolMark(bool v) =>
71+
v ? "[bold chartreuse1]true[/]" : "[bold red1]false[/]";
72+
73+
/// <summary>Formats a priority label with traffic-light colouring.</summary>
74+
public static string PriorityMark(string? p) => p switch
75+
{
76+
"High" => "[bold red1]High[/]",
77+
"Medium" => "[bold yellow]Medium[/]",
78+
_ => "[bold green]Low[/]",
79+
};
80+
81+
/// <summary>Formats an order status string with semantic colouring.</summary>
82+
public static string StatusMark(string? s) => s switch
83+
{
84+
"Fulfilled" => $"[bold green]{Markup.Escape(s)}[/]",
85+
"Cancelled" => $"[bold red1]{Markup.Escape(s)}[/]",
86+
_ => $"[bold yellow]{Markup.Escape(s ?? "?")}[/]",
87+
};
88+
}
89+

0 commit comments

Comments
 (0)