output.v

1.7 KB · raw

1//! Output formatting: the ✦ / ✗ habit, colour that can be turned off, and the2//! `--json` shapes agents read.3//!4//! Every command that prints data has a JSON form with stable field names, and5//! every error is `{"error": "..."}` on stderr. Exit codes are fixed: 06//! success, 1 refusal or error, 2 bad usage.78module cli910import json11import os1213const glyph_ok = '✦'14const glyph_fail = '✗'1516pub fn color_enabled() bool {17	if os.getenv('NO_COLOR') != '' || os.getenv('KOH_NO_COLOR') != '' {18		return false19	}20	return os.is_atty(1) != 021}2223fn paint(text string, code string) string {24	if !color_enabled() {25		return text26	}27	return '\x1b[${code}m${text}\x1b[0m'28}2930pub fn amber(text string) string {31	return paint(text, '38;5;214')32}3334pub fn red(text string) string {35	return paint(text, '38;5;203')36}3738pub fn dim(text string) string {39	return paint(text, '38;5;245')40}4142pub fn green(text string) string {43	return paint(text, '38;5;114')44}4546pub fn ok(message string) {47	println('  ${amber(glyph_ok)} ${message}')48}4950pub fn note(message string) {51	println('  ${dim(message)}')52}5354pub fn warn(message string) {55	println('  ${amber('!')} ${message}')56}5758// fail prints a refusal and returns the exit code to hand back.59pub fn fail(message string) int {60	eprintln('  ${red(glyph_fail)} ${message}')61	return 162}6364pub fn fail_json(message string) int {65	eprintln(json.encode({66		'error': message67	}))68	return 169}7071pub fn usage_error(message string) int {72	eprintln('  ${red(glyph_fail)} ${message}')73	return 274}7576// refuse reports an error in whichever shape the command was asked for.77pub fn refuse(as_json bool, message string) int {78	if as_json {79		return fail_json(message)80	}81	return fail(message)82}8384pub fn emit_json(value string) {85	println(value)86}