using System.Diagnostics; using NozCli.Core.Client; using NozCli.Core.Models; using NozCli.Repl; using Spectre.Console; namespace NozCli.Commands; public class NewCommand : ICommand { public string Name => "new"; public string Description => "Create a new note and open it in nano (or -c for VS Code)"; public string Usage => "new [-c] [--template ] "; public async Task ExecuteAsync(string[] args, ReplContext ctx, CancellationToken ct = default) { var useCode = args.Contains("-c") || args.Contains("--code"); var templateName = ParseFlag(args, "--template") ?? ParseFlag(args, "-t"); var nameArg = args.FirstOrDefault(a => !a.StartsWith('-')); if (nameArg is null) { AnsiConsole.MarkupLine("[red]Usage: new [-c] [--template ] [/]"); return; } var slug = ctx.ResolveNewSlug(nameArg); if (ctx.NoteCache.Any(n => n.Slug == slug)) { AnsiConsole.MarkupLine($"[yellow]Notiz existiert bereits:[/] {slug} [dim](use 'edit' to modify it)[/]"); return; } var topic = ctx.CurrentTopic ?? (slug.Contains('/') ? slug.Split('/')[0] : slug); var title = ToTitle(slug.Split('/').Last()); var lang = "de"; string noteBody; if (templateName is not null) { TemplateContent? tmpl = null; await AnsiConsole.Status().StartAsync($"Lade Template '{templateName}'…", async _ => tmpl = await ctx.Api.GetTemplateAsync(templateName, ct)); if (tmpl is null) { AnsiConsole.MarkupLine($"[red]Template '{templateName}' nicht gefunden.[/] Verfügbare Templates mit [white]templates[/] anzeigen."); return; } noteBody = NoteLinkHelper.ApplyPlaceholders(tmpl.Body, title, topic, lang, "seed"); } else { noteBody = $"# {title}\n\n"; } var template = $""" --- title: "{title}" description: "" topic: {topic} status: seed lang: {lang} --- {noteBody.TrimStart()} """; var tmp = Path.Combine(Path.GetTempPath(), $"noz-new-{slug.Replace('/', '-')}.md"); await File.WriteAllTextAsync(tmp, template); string markdown; try { var (editor, editorArgs) = useCode ? EditCommand.ResolveCode(tmp, ctx.Config.CodeEditor) : EditCommand.ResolveTerminal(tmp, ctx.Config.Editor); AnsiConsole.MarkupLine($"[dim]Opening {editor} …[/]"); var proc = Process.Start(new ProcessStartInfo { FileName = editor, Arguments = editorArgs, UseShellExecute = false, }); proc?.WaitForExit(); markdown = await File.ReadAllTextAsync(tmp); } finally { if (File.Exists(tmp)) File.Delete(tmp); } if (markdown.Trim() == template.Trim()) { AnsiConsole.MarkupLine("[dim]No changes — note not created.[/]"); return; } var push = AnsiConsole.Confirm($"Push [cyan]{slug}[/] to server?"); if (!push) { AnsiConsole.MarkupLine("[dim]Discarded.[/]"); return; } await AnsiConsole.Status().StartAsync("Creating…", async _ => { await ctx.Api.PutNoteAsync(slug, markdown, ct); ctx.NoteCache = await ctx.Api.GetNotesAsync(ct); }); AnsiConsole.MarkupLine($"[green]✓[/] {slug} created"); } private static string ToTitle(string slug) => string.Join(' ', slug.Split('-').Select(w => w.Length > 0 ? char.ToUpper(w[0]) + w[1..] : w)); 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; } }