// SPDX-FileCopyrightText: (C) Copyright 2026 Pim van Pelt // SPDX-License-Identifier: Apache-2.0 package cli import ( "encoding/json" "fmt" "os" ) // Format selects how command results are rendered. It is process-global, // toggled once at startup via SetFormat (parallel to SetColor), so command // functions can stay simple: they describe a result once and the framework // renders it the chosen way. type Format int const ( // FormatText renders the human-readable string a command passes to Emit. FormatText Format = iota // FormatJSON marshals the machine value a command passes to Emit and // ignores the text. Color is irrelevant in this mode. FormatJSON ) var outputFormat Format // SetFormat selects the output format for Emit. Call it once at startup, e.g. // from a -json flag. func SetFormat(f Format) { outputFormat = f } // OutputFormat reports the current output format. func OutputFormat() Format { return outputFormat } // IsJSON reports whether output is in JSON mode. Commands can use it to skip // building the (then-unused) text representation, or to suppress banners. func IsJSON() bool { return outputFormat == FormatJSON } // Emit renders one command result to stdout. In FormatText mode it prints text // — which the caller may have colorized with Paint/Label/KV — followed by a // newline. In FormatJSON mode it marshals v (indented) and ignores text. The // caller supplies both: text is the human form, v is the machine form. This is // the single seam that lets the same command serve "show foo" and "-json show // foo". Returns an error only if JSON marshaling fails. // // For multi-record output, marshal a slice as v and join the text yourself; // Emit is one call per logical result so the JSON stays a single document. func Emit(text string, v any) error { if outputFormat == FormatJSON { b, err := json.MarshalIndent(v, "", " ") if err != nil { return fmt.Errorf("marshal json: %w", err) } _, _ = fmt.Fprintln(os.Stdout, string(b)) return nil } _, _ = fmt.Fprintln(os.Stdout, text) return nil } // KV renders "key=value" with the key (and the '=') painted blue when color is // enabled, leaving the value in normal font. It is the building block for // one-line text output and pairs with Emit's text argument. func KV(key, value string) string { return Label(key+"=") + value }