args.v

2.6 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			mut has_inline := false39			if at := name.index('=') {40				inline = name[at + 1..]41				name = name[..at]42				has_inline = true43			}44			if name in spec.values {45				mut value := inline46				if !has_inline {47					index++48					if index >= raw.len {49						return error('--${name} needs a value')50					}51					value = raw[index]52				}53				args.values[name] = value54				args.multi[name] << value55			} else if name in spec.flags {56				if has_inline {57					return error('--${name} takes no value')58				}59				args.flags[name] = true60			} else {61				return error('unknown option "--${name}" for "koh ${command}"')62			}63		} else if item.starts_with('-') && item.len > 1 {64			return error('unknown option "${item}" for "koh ${command}"')65		} else {66			args.positional << item67		}68		index++69	}70	return args71}7273pub fn (args &Args) flag(name string) bool {74	return args.flags[name]75}7677pub fn (args &Args) value(name string) string {78	return args.values[name] or { '' }79}8081// values_of returns every value given for an option, in the order they were82// given. An option that never repeated has the one value it took.83pub fn (args &Args) values_of(name string) []string {84	return args.multi[name] or { []string{} }85}8687pub fn (args &Args) value_or_none(name string) ?string {88	if name in args.values {89		return args.values[name]90	}91	return none92}9394pub fn (args &Args) json() bool {95	return args.flag('json')96}9798// positional_at returns the argument at `index`, or '' when it is missing.99pub fn (args &Args) positional_at(index int) string {100	if index >= args.positional.len {101		return ''102	}103	return args.positional[index]104}