using NozCli.Repl; using Spectre.Console; namespace NozCli.Commands; public class SearchCommand : ICommand { public string Name => "search"; public string Description => "Full-text search via Meilisearch"; public string Usage => "search [--topic ] [--limit ]"; private static readonly Dictionary StatusDot = new() { ["seed"] = "[yellow]◦[/]", ["budding"] = "[magenta]◈[/]", ["evergreen"] = "[cyan]◉[/]", }; public async Task ExecuteAsync(string[] args, ReplContext ctx, CancellationToken ct = default) { var topic = ParseFlag(args, "--topic") ?? ctx.CurrentTopic; var limitRaw = ParseFlag(args, "--limit"); var limit = limitRaw is not null && int.TryParse(limitRaw, out var l) ? l : 10; var query = string.Join(' ', args.Where(a => !a.StartsWith('-') && a != ParseFlag(args, "--topic") && a != ParseFlag(args, "--limit"))); if (string.IsNullOrWhiteSpace(query)) { AnsiConsole.MarkupLine("[red]Usage:[/] search [--topic ] [--limit ]"); return; } List hits = []; await AnsiConsole.Status().StartAsync($"Suche nach »{query}«…", async _ => hits = await ctx.Api.SearchAsync(query, topic, limit, ct)); if (hits.Count == 0) { AnsiConsole.MarkupLine($"[dim]Keine Treffer für »{Markup.Escape(query)}«.[/]"); return; } AnsiConsole.MarkupLine($"[dim]{hits.Count} Treffer[/]\n"); foreach (var h in hits) { var dot = StatusDot.GetValueOrDefault(h.Status, "·"); var desc = h.Description is { Length: > 0 } d ? $"\n [dim]{Markup.Escape(d)}[/]" : ""; AnsiConsole.MarkupLine($" {dot} [cyan]{Markup.Escape(h.Slug)}[/] [white]{Markup.Escape(h.Title)}[/]{desc}"); } AnsiConsole.WriteLine(); } private static string? ParseFlag(string[] args, string flag) { var idx = Array.IndexOf(args, flag); return idx >= 0 && idx + 1 < args.Length ? args[idx + 1] : null; } }