From 8576cc83a2b4609dbc9add44cde7758a8dc03d5c Mon Sep 17 00:00:00 2001 From: kryptomrx Date: Sun, 17 May 2026 00:38:19 +0200 Subject: [PATCH] feat: search command in REPL with topic-aware context --- NozCli/Commands/SearchCommand.cs | 61 ++++++++++++++++++++++++++++++++ NozCli/Repl/CommandRegistry.cs | 1 + 2 files changed, 62 insertions(+) create mode 100644 NozCli/Commands/SearchCommand.cs diff --git a/NozCli/Commands/SearchCommand.cs b/NozCli/Commands/SearchCommand.cs new file mode 100644 index 0000000..10bb045 --- /dev/null +++ b/NozCli/Commands/SearchCommand.cs @@ -0,0 +1,61 @@ +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; + } +} diff --git a/NozCli/Repl/CommandRegistry.cs b/NozCli/Repl/CommandRegistry.cs index 95b6c80..43f6f08 100644 --- a/NozCli/Repl/CommandRegistry.cs +++ b/NozCli/Repl/CommandRegistry.cs @@ -25,6 +25,7 @@ public class CommandRegistry new TreeCommand(), new MkdirCommand(), new MvCommand(), + new SearchCommand(), new LinkCommand(), new TemplatesCommand(), new VersionCommand(),