noz-cli/NozCli/Commands/LinkCommand.cs
kryptomrx 58410f8d9f feat: link and templates commands with note linking helper
NoteLinkHelper inserts wikilinks into an existing 'Siehe auch' section
or appends one. ApplyPlaceholders fills {{title}}/{{date}}/{{topic}} in
template bodies. new --template <name> fetches a server-side template
before opening the editor. SlugGuard moved to NozCli.Core in a previous
session — remove stale copy from NozCli.
2026-05-17 00:28:22 +02:00

67 lines
2.3 KiB
C#

using NozCli.Core.Client;
using NozCli.Repl;
using Spectre.Console;
namespace NozCli.Commands;
public class LinkCommand : ICommand
{
public string Name => "link";
public string Description => "Add a wikilink from one note to another (builds the graph)";
public string Usage => "link <source> <target> [--both] [--section \"Siehe auch\"]";
public async Task ExecuteAsync(string[] args, ReplContext ctx, CancellationToken ct = default)
{
var both = args.Contains("--both");
var section = ParseFlag(args, "--section") ?? "Siehe auch";
var positional = args.Where(a => !a.StartsWith('-')).ToArray();
if (positional.Length < 2)
{
AnsiConsole.MarkupLine("[red]Usage:[/] link <source> <target> [--both] [--section \"Heading\"]");
return;
}
var source = ctx.ResolveSlug(positional[0]);
var target = ctx.ResolveSlug(positional[1]);
if (source == target)
{
AnsiConsole.MarkupLine("[yellow]Quelle und Ziel sind identisch.[/]");
return;
}
await LinkOneWay(ctx.Api, source, target, section, ct);
if (both)
await LinkOneWay(ctx.Api, target, source, section, ct);
}
private static async Task LinkOneWay(
NozCli.Core.Client.NozApiClient api,
string source, string target, string section, CancellationToken ct)
{
NozCli.Core.Models.NoteContent note = default!;
await AnsiConsole.Status().StartAsync($"Lese {source}…", async _ =>
note = await api.GetNoteAsync(source, ct));
var updated = NoteLinkHelper.AddLink(note.Markdown, target, section);
if (updated == note.Markdown)
{
AnsiConsole.MarkupLine($"[dim]{source}[/] → [dim]{target}[/] [yellow]bereits verlinkt[/]");
return;
}
await AnsiConsole.Status().StartAsync($"Aktualisiere {source}…", async _ =>
await api.PutNoteAsync(source, updated, ct));
AnsiConsole.MarkupLine($"[green]✓[/] [cyan]{source}[/] → [cyan]{target}[/] verlinkt");
}
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;
}
}