args.v

2.4 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}2324pub fn parse(command string, raw []string, spec Options) !Args {25	mut args := Args{}26	mut index := 027	for index < raw.len {28		item := raw[index]29		if item == '--' {30			args.positional << raw[index + 1..]31			break32		}33		if item.starts_with('--') {34			mut name := item[2..]35			mut inline := ''36			if at := name.index('=') {37				inline = name[at + 1..]38				name = name[..at]39			}40			if name in spec.values {41				mut value := inline42				if value == '' {43					index++44					if index >= raw.len {45						return error('--${name} needs a value')46					}47					value = raw[index]48				}49				args.values[name] = value50				args.multi[name] << value51			} else if name in spec.flags {52				if inline != '' {53					return error('--${name} takes no value')54				}55				args.flags[name] = true56			} else {57				return error('unknown option "--${name}" for "koh ${command}"')58			}59		} else if item.starts_with('-') && item.len > 1 {60			return error('unknown option "${item}" for "koh ${command}"')61		} else {62			args.positional << item63		}64		index++65	}66	return args67}6869pub fn (args &Args) flag(name string) bool {70	return args.flags[name]71}7273pub fn (args &Args) value(name string) string {74	return args.values[name] or { '' }75}7677// values_of returns every value given for an option, in the order they were78// given. An option that never repeated has the one value it took.79pub fn (args &Args) values_of(name string) []string {80	return args.multi[name] or { []string{} }81}8283pub fn (args &Args) value_or_none(name string) ?string {84	if name in args.values {85		return args.values[name]86	}87	return none88}8990pub fn (args &Args) json() bool {91	return args.flag('json')92}9394// positional_at returns the argument at `index`, or '' when it is missing.95pub fn (args &Args) positional_at(index int) string {96	if index >= args.positional.len {97		return ''98	}99	return args.positional[index]100}