args.v

2.5 KB · raw

1//! Command line parsing.2//!3//! Each command declares the options it takes, so a typo is refused with a4//! usage error instead of being ignored — an agent's mistake should be loud.56module cli78pub struct Options {9pub:10	values []string // options that take a value11	flags  []string // options that take none12}1314pub struct Args {15pub mut:16	positional []string17	values     map[string]string18	flags      map[string]bool19	// Options that took a value more than once keep every value here, in order,20	// for the few commands that accept a repeat (`koh build --platform`).21	multi map[string][]string22}2324// parse refuses what the command did not declare: an unknown option, a value given to a flag, a missing25// value. `--` ends the options.26pub fn parse(command string, raw []string, spec Options) !Args {27	mut args := Args{}28	mut index := 029	for index < raw.len {30		item := raw[index]31		if item == '--' {32			args.positional << raw[index + 1..]33			break34		}35		if item.starts_with('--') {36			mut name := item[2..]37			mut inline := ''38			if at := name.index('=') {39				inline = name[at + 1..]40				name = name[..at]41			}42			if name in spec.values {43				mut value := inline44				if value == '' {45					index++46					if index >= raw.len {47						return error('--${name} needs a value')48					}49					value = raw[index]50				}51				args.values[name] = value52				args.multi[name] << value53			} else if name in spec.flags {54				if inline != '' {55					return error('--${name} takes no value')56				}57				args.flags[name] = true58			} else {59				return error('unknown option "--${name}" for "koh ${command}"')60			}61		} else if item.starts_with('-') && item.len > 1 {62			return error('unknown option "${item}" for "koh ${command}"')63		} else {64			args.positional << item65		}66		index++67	}68	return args69}7071pub fn (args &Args) flag(name string) bool {72	return args.flags[name]73}7475pub fn (args &Args) value(name string) string {76	return args.values[name] or { '' }77}7879// values_of returns every value given for an option, in the order they were80// given. An option that never repeated has the one value it took.81pub fn (args &Args) values_of(name string) []string {82	return args.multi[name] or { []string{} }83}8485pub fn (args &Args) value_or_none(name string) ?string {86	if name in args.values {87		return args.values[name]88	}89	return none90}9192pub fn (args &Args) json() bool {93	return args.flag('json')94}9596// positional_at returns the argument at `index`, or '' when it is missing.97pub fn (args &Args) positional_at(index int) string {98	if index >= args.positional.len {99		return ''100	}101	return args.positional[index]102}