Property definitions

opts $ OptionContext :: defaultinit
# Context where the options process
class OptionContext
	# Options present in the context
	var options = new Array[Option]

	# Rest of the options after `parse` is called
	var rest = new Array[String]

	# Errors found in the context after parsing
	var context_errors = new Array[String]

	private var optmap = new HashMap[String, Option]

	# Add one or more options to the context
	fun add_option(opts: Option...) do options.add_all(opts)

	# Display all the options available
	fun usage
	do
		var lmax = 1
		for i in options do
			var l = 3
			for n in i.names do
				l += n.length + 2
			end
			if lmax < l then lmax = l
		end

		for i in options do
			if not i.hidden then
				print(i.pretty(lmax))
			end
		end
	end

	# Parse and assign options in `argv` or `args`
	fun parse(argv: nullable Collection[String])
	do
		if argv == null then argv = args
		var it = argv.iterator
		parse_intern(it)
	end

	# Must all option be given before the first argument?
	#
	# When set to `false` (the default), options of the command line are
	# all parsed until the end of the list of arguments or until "--" is met (in this case "--" is discarded).
	#
	# When set to `true` options are parsed until the first non-option is met.
	var options_before_rest = false is writable

	# Parse the command line
	protected fun parse_intern(it: Iterator[String])
	do
		var parseargs = true
		build
		var rest = rest

		while parseargs and it.is_ok do
			var str = it.item
			if str == "--" then
				it.next
				rest.add_all(it.to_a)
				parseargs = false
			else
				# We're looking for packed short options
				if str.chars.last_index_of('-') == 0 and str.length > 2 then
					var next_called = false
					for i in [1..str.length[ do
						var short_opt = "-" + str.chars[i].to_s
						if optmap.has_key(short_opt) then
							var option = optmap[short_opt]
							if option isa OptionParameter then
								it.next
								next_called = true
							end
							option.read_param(self, it)
						end
					end
					if not next_called then it.next
				else
					if optmap.has_key(str) then
						var opt = optmap[str]
						it.next
						opt.read_param(self, it)
					else
						rest.add(it.item)
						it.next
						if options_before_rest then
							rest.add_all(it.to_a)
							parseargs = false
						end
					end
				end
			end
		end

		for opt in options do
			if opt.mandatory and not opt.read then
				context_errors.add("Mandatory option {opt.names.join(", ")} not found.")
			end
		end
	end

	private fun build
	do
		for o in options do
			for n in o.names do
				optmap[n] = o
			end
		end
	end

	# Options parsing errors.
	fun errors: Array[String]
	do
		var errors = new Array[String]
		errors.add_all context_errors
		for o in options do
			for e in o.errors do
				errors.add(e)
			end
		end
		return errors
	end
end
lib/opts/opts.nit:281,1--406,3