mirror of
https://github.com/TangentFoxy/argparse.git
synced 2025-07-28 11:02:20 +00:00
Add support for grouping elements in help message
This commit is contained in:
@@ -224,4 +224,98 @@ Commands:
|
|||||||
assert.equal([[
|
assert.equal([[
|
||||||
Usage: foo]], parser:get_help())
|
Usage: foo]], parser:get_help())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("supports grouping options", function()
|
||||||
|
local parser = Parser "foo"
|
||||||
|
:add_help(false)
|
||||||
|
parser:argument "thing"
|
||||||
|
|
||||||
|
parser:group("Options for setting position",
|
||||||
|
parser:option "--coords"
|
||||||
|
:args(2)
|
||||||
|
:argname {"<x>", "<y>"}
|
||||||
|
:description "Set coordinates.",
|
||||||
|
parser:option "--polar"
|
||||||
|
:args(2)
|
||||||
|
:argname {"<rad>", "<ang>"}
|
||||||
|
:description "Set polar coordinates."
|
||||||
|
)
|
||||||
|
|
||||||
|
parser:group("Options for setting style",
|
||||||
|
parser:flag "--dotted"
|
||||||
|
:description "More dots.",
|
||||||
|
parser:option "--width"
|
||||||
|
:argname "<px>"
|
||||||
|
:description "Set width."
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal([[
|
||||||
|
Usage: foo [--coords <x> <y>] [--polar <rad> <ang>] [--dotted]
|
||||||
|
[--width <px>] <thing>
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
thing
|
||||||
|
|
||||||
|
Options for setting position:
|
||||||
|
--coords <x> <y> Set coordinates.
|
||||||
|
--polar <rad> <ang> Set polar coordinates.
|
||||||
|
|
||||||
|
Options for setting style:
|
||||||
|
--dotted More dots.
|
||||||
|
--width <px> Set width.]], parser:get_help())
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("adds default group with 'other' prefix if not all elements of a type are grouped", function()
|
||||||
|
local parser = Parser "foo"
|
||||||
|
|
||||||
|
parser:group("Main arguments",
|
||||||
|
parser:argument "foo",
|
||||||
|
parser:argument "bar",
|
||||||
|
parser:flag "--use-default-args"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser:argument "optional"
|
||||||
|
:args "?"
|
||||||
|
|
||||||
|
parser:group("Main options",
|
||||||
|
parser:flag "--something",
|
||||||
|
parser:option "--test"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser:flag "--version"
|
||||||
|
|
||||||
|
parser:group("Some commands",
|
||||||
|
parser:command "foo",
|
||||||
|
parser:command "bar"
|
||||||
|
)
|
||||||
|
|
||||||
|
parser:command "another-command"
|
||||||
|
|
||||||
|
assert.equal([[
|
||||||
|
Usage: foo [--use-default-args] [--something] [--test <test>]
|
||||||
|
[--version] [-h] <foo> <bar> [<optional>] <command> ...
|
||||||
|
|
||||||
|
Main arguments:
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
--use-default-args
|
||||||
|
|
||||||
|
Other arguments:
|
||||||
|
optional
|
||||||
|
|
||||||
|
Main options:
|
||||||
|
--something
|
||||||
|
--test <test>
|
||||||
|
|
||||||
|
Other options:
|
||||||
|
--version
|
||||||
|
-h, --help Show this help message and exit.
|
||||||
|
|
||||||
|
Some commands:
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
|
||||||
|
Other commands:
|
||||||
|
another-command]], parser:get_help())
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
@@ -232,6 +232,7 @@ local Parser = class({
|
|||||||
_options = {},
|
_options = {},
|
||||||
_commands = {},
|
_commands = {},
|
||||||
_mutexes = {},
|
_mutexes = {},
|
||||||
|
_groups = {},
|
||||||
_require_command = true,
|
_require_command = true,
|
||||||
_handle_options = true
|
_handle_options = true
|
||||||
}, {
|
}, {
|
||||||
@@ -585,6 +586,21 @@ function Parser:mutex(...)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Parser:group(name, ...)
|
||||||
|
assert(type(name) == "string", ("bad argument #1 to 'group' (string expected, got %s)"):format(type(name)))
|
||||||
|
|
||||||
|
local group = {name = name, ...}
|
||||||
|
|
||||||
|
for i, element in ipairs(group) do
|
||||||
|
local mt = getmetatable(element)
|
||||||
|
assert(mt == Option or mt == Argument or mt == Command,
|
||||||
|
("bad argument #%d to 'group' (Option or Argument or Command expected)"):format(i + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(self._groups, group)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
local max_usage_width = 70
|
local max_usage_width = 70
|
||||||
local usage_welcome = "Usage: "
|
local usage_welcome = "Usage: "
|
||||||
|
|
||||||
@@ -739,6 +755,31 @@ local function make_two_columns(s1, s2)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_group_types(group)
|
||||||
|
local types = {}
|
||||||
|
|
||||||
|
for _, element in ipairs(group) do
|
||||||
|
types[getmetatable(element)] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
return types
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_group_help(blocks, added_elements, label, elements)
|
||||||
|
local buf = {label}
|
||||||
|
|
||||||
|
for _, element in ipairs(elements) do
|
||||||
|
if not element._hidden and not added_elements[element] then
|
||||||
|
added_elements[element] = true
|
||||||
|
table.insert(buf, make_two_columns(element:_get_label(), element:_get_description()))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #buf > 1 then
|
||||||
|
table.insert(blocks, table.concat(buf, "\n"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Parser:get_help()
|
function Parser:get_help()
|
||||||
if self._help then
|
if self._help then
|
||||||
return self._help
|
return self._help
|
||||||
@@ -750,20 +791,49 @@ function Parser:get_help()
|
|||||||
table.insert(blocks, self._description)
|
table.insert(blocks, self._description)
|
||||||
end
|
end
|
||||||
|
|
||||||
local labels = {"Arguments:", "Options:", "Commands:"}
|
-- 1. Put groups containing arguments first, then other arguments.
|
||||||
|
-- 2. Put remaining groups containing options, then other options.
|
||||||
|
-- 3. Put remaining groups containing commands, then other commands.
|
||||||
|
-- Assume that an element can't be in several groups.
|
||||||
|
local groups_by_type = {
|
||||||
|
[Argument] = {},
|
||||||
|
[Option] = {},
|
||||||
|
[Command] = {}
|
||||||
|
}
|
||||||
|
|
||||||
for i, elements in ipairs{self._arguments, self._options, self._commands} do
|
for _, group in ipairs(self._groups) do
|
||||||
local buf = {labels[i]}
|
local group_types = get_group_types(group)
|
||||||
|
|
||||||
for _, element in ipairs(elements) do
|
for _, mt in ipairs({Argument, Option, Command}) do
|
||||||
if not element._hidden then
|
if group_types[mt] then
|
||||||
table.insert(buf, make_two_columns(element:_get_label(), element:_get_description()))
|
table.insert(groups_by_type[mt], group)
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if #buf > 1 then
|
local default_groups = {
|
||||||
table.insert(blocks, table.concat(buf, "\n"))
|
{name = "Arguments", type = Argument, elements = self._arguments},
|
||||||
|
{name = "Options", type = Option, elements = self._options},
|
||||||
|
{name = "Commands", type = Command, elements = self._commands}
|
||||||
|
}
|
||||||
|
|
||||||
|
local added_elements = {}
|
||||||
|
|
||||||
|
for _, default_group in ipairs(default_groups) do
|
||||||
|
local type_groups = groups_by_type[default_group.type]
|
||||||
|
|
||||||
|
for _, group in ipairs(type_groups) do
|
||||||
|
add_group_help(blocks, added_elements, group.name .. ":", group)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local default_label = default_group.name .. ":"
|
||||||
|
|
||||||
|
if #type_groups > 0 then
|
||||||
|
default_label = "Other " .. default_label:gsub("^.", string.lower)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_group_help(blocks, added_elements, default_label, default_group.elements)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self._epilog then
|
if self._epilog then
|
||||||
|
Reference in New Issue
Block a user