Split labels for multi-alias options into lines in help string

This commit is contained in:
Peter Melnichenko
2018-04-08 15:03:56 +03:00
parent 5c1a6896fc
commit 8baabbbe23
4 changed files with 137 additions and 24 deletions

View File

@@ -18,6 +18,9 @@
* `--` can now be used as a normal option name, with arguments * `--` can now be used as a normal option name, with arguments
after `--` always passed to it verbatim (#17). after `--` always passed to it verbatim (#17).
* When generating help messages for options with arguments and multiple
aliases, usage strings for different aliases are put on separate lines and
vertically aligned (#15).
## 0.5.0 (2015-12-09) ## 0.5.0 (2015-12-09)

View File

@@ -106,6 +106,55 @@ Options:
-h, --help Show this help message and exit.]], parser:get_help()) -h, --help Show this help message and exit.]], parser:get_help())
end) end)
it("puts different aliases on different lines if there are arguments", function()
local parser = Parser "foo"
parser:option "-o --output"
assert.equal([[
Usage: foo [-o <output>] [-h]
Options:
-o <output>,
--output <output>
-h, --help Show this help message and exit.]], parser:get_help())
end)
it("handles description with more lines than usage", function()
local parser = Parser "foo"
parser:option "-o --output"
:description [[
Sets output file.
If missing, 'a.out' is used by default.
If '-' is passed, output to stdount.
]]
assert.equal([[
Usage: foo [-o <output>] [-h]
Options:
-o <output>, Sets output file.
--output <output> If missing, 'a.out' is used by default.
If '-' is passed, output to stdount.
-h, --help Show this help message and exit.]], parser:get_help())
end)
it("handles description with less lines than usage", function()
local parser = Parser "foo"
parser:option "-o --output"
:description "Sets output file."
assert.equal([[
Usage: foo [-o <output>] [-h]
Options:
-o <output>, Sets output file.
--output <output>
-h, --help Show this help message and exit.]], parser:get_help())
end)
it("shows default values", function() it("shows default values", function()
local parser = Parser "foo" local parser = Parser "foo"
parser:option "-o" parser:option "-o"

View File

@@ -106,8 +106,8 @@ Arguments:
version Version of the rock. version Version of the rock.
Options: Options:
-f <from>, --from <from> -f <from>, Fetch the rock from this server.
Fetch the rock from this server. --from <from>
-h, --help Show this help message and exit. -h, --help Show this help message and exit.
]], get_output("foo install --help")) ]], get_output("foo install --help"))
end) end)

View File

@@ -445,26 +445,43 @@ function Option:_get_default_argname()
return "<" .. self:_get_default_target() .. ">" return "<" .. self:_get_default_target() .. ">"
end end
-- Returns label to be shown in the help message. -- Returns labels to be shown in the help message.
function Argument:_get_label() function Argument:_get_label_lines()
return self._name return {self._name}
end end
function Option:_get_label() function Option:_get_label_lines()
local variants = {}
local argument_list = self:_get_argument_list() local argument_list = self:_get_argument_list()
table.insert(argument_list, 1, nil)
for _, alias in ipairs(self._aliases) do if #argument_list == 0 then
argument_list[1] = alias -- Don't put aliases for simple flags like `-h` on different lines.
table.insert(variants, table.concat(argument_list, " ")) return {table.concat(self._aliases, ", ")}
end end
return table.concat(variants, ", ") local longest_alias_length = -1
for _, alias in ipairs(self._aliases) do
longest_alias_length = math.max(longest_alias_length, #alias)
end
local argument_list_repr = table.concat(argument_list, " ")
local lines = {}
for i, alias in ipairs(self._aliases) do
local line = (" "):rep(longest_alias_length - #alias) .. alias .. " " .. argument_list_repr
if i ~= #self._aliases then
line = line .. ","
end
table.insert(lines, line)
end
return lines
end end
function Command:_get_label() function Command:_get_label_lines()
return table.concat(self._aliases, ", ") return {table.concat(self._aliases, ", ")}
end end
function Argument:_get_description() function Argument:_get_description()
@@ -737,22 +754,66 @@ function Parser:get_usage()
end end
local margin_len = 3 local margin_len = 3
local margin_len2 = 25 local margin2_len = 25
local margin = (" "):rep(margin_len) local margin = (" "):rep(margin_len)
local margin2 = (" "):rep(margin_len2) local margin2 = (" "):rep(margin2_len)
local function make_two_columns(s1, s2) local function split_lines(s)
if s2 == "" then if s == "" then
return margin .. s1 return {}
end end
s2 = s2:gsub("\n", "\n" .. margin2) local lines = {}
if #s1 < (margin_len2-margin_len) then if s:sub(-1) ~= "\n" then
return margin .. s1 .. (" "):rep(margin_len2-margin_len-#s1) .. s2 s = s .. "\n"
end
for line in s:gmatch("([^\n]*)\n") do
table.insert(lines, line)
end
return lines
end
local function get_element_help(element)
local label_lines = element:_get_label_lines()
local description_lines = split_lines(element:_get_description())
local result_lines = {}
-- All label lines should have the same length (except the last one, it has no comma).
-- If too long, start description after all the label lines.
-- Otherwise, combine label and description lines.
if #label_lines[1] >= (margin2_len - margin_len) then
for _, label_line in ipairs(label_lines) do
table.insert(result_lines, margin .. label_line)
end
for _, description_line in ipairs(description_lines) do
table.insert(result_lines, margin2 .. description_line)
end
else else
return margin .. s1 .. "\n" .. margin2 .. s2 for i = 1, math.max(#label_lines, #description_lines) do
local label_line = label_lines[i]
local description_line = description_lines[i]
local line = ""
if label_line then
line = margin .. label_line
end
if description_line and description_line ~= "" then
line = line .. (" "):rep(margin2_len - #line) .. description_line
end
table.insert(result_lines, line)
end
end end
return table.concat(result_lines, "\n")
end end
local function get_group_types(group) local function get_group_types(group)
@@ -771,7 +832,7 @@ local function add_group_help(blocks, added_elements, label, elements)
for _, element in ipairs(elements) do for _, element in ipairs(elements) do
if not element._hidden and not added_elements[element] then if not element._hidden and not added_elements[element] then
added_elements[element] = true added_elements[element] = true
table.insert(buf, make_two_columns(element:_get_label(), element:_get_description())) table.insert(buf, get_element_help(element))
end end
end end