//! Output for the command line: the ✦ / ✗ habit, and the `--json` shapes //! agents read. //! //! Colour comes from `src.fmt`, so turning it off turns it off everywhere. //! Every command that prints data has a JSON form with stable field names, and //! every error is `{"error": "..."}` on stderr. Exit codes are fixed: 0 //! success, 1 refusal or error, 2 bad usage. module cli import json2 import os import src.fmt // ok, note and warn print on stdout after clearing the progress line; errors go to stderr. pub fn ok(message string) { done_working() println(' ${fmt.amber(fmt.glyph_ok)} ${message}') } pub fn note(message string) { done_working() println(' ${fmt.dim(message)}') } pub fn warn(message string) { done_working() println(' ${fmt.amber('!')} ${message}') } // fail prints a refusal and returns the exit code to hand back. pub fn fail(message string) int { done_working() eprintln(' ${fmt.red(fmt.glyph_fail)} ${message}') return 1 } pub fn fail_json(message string) int { eprintln(json2.encode({ 'error': message })) return 1 } // usage_error reports a mistake in the command line itself. It can happen // before the options are parsed, so `--json` is looked for on the raw line. pub fn usage_error(message string) int { if '--json' in os.args { fail_json(message) } else { eprintln(' ${fmt.red(fmt.glyph_fail)} ${message}') } return 2 } // refuse reports an error in whichever shape the command was asked for. pub fn refuse(as_json bool, message string) int { if as_json { return fail_json(message) } return fail(message) } pub fn emit_json(value string) { done_working() println(value) }