mirror of
https://github.com/TangentFoxy/argparse.git
synced 2025-07-28 02:52:20 +00:00
Add help_max_width
property for help description autowrapping.
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
usage string autogeneration.
|
||||
* Added `help_usage_margin` and `help_description_margin` properties
|
||||
for configuring help string autogeneration.
|
||||
* Added `help_max_width` property. If set, descriptions in help string
|
||||
are automatically wrapped to fit into given number of columns.
|
||||
|
||||
### Improvements
|
||||
|
||||
|
@@ -496,4 +496,102 @@ Options:
|
||||
That needs documenting.
|
||||
-h, --help Show this help message and exit.]], parser:get_help())
|
||||
end)
|
||||
|
||||
describe("autowrap", function()
|
||||
it("automatically wraps descriptions to match given max width", function()
|
||||
local parser = Parser "foo"
|
||||
:help_max_width(80)
|
||||
|
||||
parser:option "-f --foo"
|
||||
:description("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " ..
|
||||
"incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation " ..
|
||||
"ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit " ..
|
||||
"in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " ..
|
||||
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
||||
parser:option "-b --bar"
|
||||
:description "See above."
|
||||
|
||||
assert.equal([[
|
||||
Usage: foo [-f <foo>] [-b <bar>] [-h]
|
||||
|
||||
Options:
|
||||
-f <foo>, Lorem ipsum dolor sit amet, consectetur adipiscing
|
||||
--foo <foo> elit, sed do eiusmod tempor incididunt ut labore et
|
||||
dolore magna aliqua. Ut enim ad minim veniam, quis
|
||||
nostrud exercitation ullamco laboris nisi ut aliquip ex
|
||||
ea commodo consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu
|
||||
fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia
|
||||
deserunt mollit anim id est laborum.
|
||||
-b <bar>, See above.
|
||||
--bar <bar>
|
||||
-h, --help Show this help message and exit.]], parser:get_help())
|
||||
end)
|
||||
|
||||
it("preserves existing line breaks", function()
|
||||
local parser = Parser "foo"
|
||||
:help_max_width(80)
|
||||
|
||||
parser:option "-f --foo"
|
||||
:description("This is a long line, it should be broken down into several lines. " .. [[
|
||||
It just keeps going and going.
|
||||
This should always be a new line.
|
||||
Another one.
|
||||
]])
|
||||
parser:option "-b --bar"
|
||||
|
||||
assert.equal([[
|
||||
Usage: foo [-f <foo>] [-b <bar>] [-h]
|
||||
|
||||
Options:
|
||||
-f <foo>, This is a long line, it should be broken down into
|
||||
--foo <foo> several lines. It just keeps going and going.
|
||||
This should always be a new line.
|
||||
Another one.
|
||||
-b <bar>,
|
||||
--bar <bar>
|
||||
-h, --help Show this help message and exit.]], parser:get_help())
|
||||
end)
|
||||
|
||||
it("preserves indentation", function()
|
||||
local parser = Parser "foo"
|
||||
:help_max_width(80)
|
||||
|
||||
parser:option "-f --foo"
|
||||
:description("This is a long line, it should be broken down into several lines.\n" ..
|
||||
" This paragraph is indented with three spaces, so when it gets broken down into several lines, " ..
|
||||
"they will be, too.\n\n" ..
|
||||
" That was an empty line there, preserve it.")
|
||||
|
||||
assert.equal([[
|
||||
Usage: foo [-f <foo>] [-h]
|
||||
|
||||
Options:
|
||||
-f <foo>, This is a long line, it should be broken down into
|
||||
--foo <foo> several lines.
|
||||
This paragraph is indented with three spaces, so
|
||||
when it gets broken down into several lines, they
|
||||
will be, too.
|
||||
|
||||
That was an empty line there, preserve it.
|
||||
-h, --help Show this help message and exit.]], parser:get_help())
|
||||
end)
|
||||
|
||||
it("preserves multiple spaces between words", function()
|
||||
local parser = Parser "foo"
|
||||
:help_max_width(80)
|
||||
|
||||
parser:option "-f --foo"
|
||||
:description("This is a long line with two spaces between words, it should be broken down.")
|
||||
|
||||
assert.equal([[
|
||||
Usage: foo [-f <foo>] [-h]
|
||||
|
||||
Options:
|
||||
-f <foo>, This is a long line with two spaces between
|
||||
--foo <foo> words, it should be broken down.
|
||||
-h, --help Show this help message and exit.]], parser:get_help())
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
@@ -251,6 +251,7 @@ local Parser = class({
|
||||
typechecked("usage_max_width", "number"),
|
||||
typechecked("help_usage_margin", "number"),
|
||||
typechecked("help_description_margin", "number"),
|
||||
typechecked("help_max_width", "number"),
|
||||
add_help
|
||||
})
|
||||
|
||||
@@ -273,6 +274,7 @@ local Command = class({
|
||||
typechecked("usage_max_width", "number"),
|
||||
typechecked("help_usage_margin", "number"),
|
||||
typechecked("help_description_margin", "number"),
|
||||
typechecked("help_max_width", "number"),
|
||||
typechecked("hidden", "boolean"),
|
||||
add_help
|
||||
}, Parser)
|
||||
@@ -800,6 +802,75 @@ local function split_lines(s)
|
||||
return lines
|
||||
end
|
||||
|
||||
local function autowrap_line(line, max_length)
|
||||
-- Algorithm for splitting lines is simple and greedy.
|
||||
local result_lines = {}
|
||||
|
||||
-- Preserve original indentation of the line, put this at the beginning of each result line.
|
||||
local indentation = line:match("^( *)")
|
||||
|
||||
-- Parts of the last line being assembled.
|
||||
local line_parts = {}
|
||||
|
||||
-- Length of the current line.
|
||||
local line_length = 0
|
||||
|
||||
-- Index of the next character to consider.
|
||||
local index = 1
|
||||
|
||||
while true do
|
||||
local word_start, word_finish, word = line:find("([^ ]+)", index)
|
||||
|
||||
if not word_start then
|
||||
-- Ignore trailing spaces, if any.
|
||||
break
|
||||
end
|
||||
|
||||
local preceding_spaces = line:sub(index, word_start - 1)
|
||||
index = word_finish + 1
|
||||
|
||||
if (#line_parts == 0) or (line_length + #preceding_spaces + #word <= max_length) then
|
||||
-- Either this is the very first word or it fits as an addition to the current line, add it.
|
||||
table.insert(line_parts, preceding_spaces) -- For the very first word this adds the indentation.
|
||||
table.insert(line_parts, word)
|
||||
line_length = line_length + #preceding_spaces + #word
|
||||
else
|
||||
-- Does not fit, finish current line and put the word into a new one.
|
||||
table.insert(result_lines, table.concat(line_parts))
|
||||
line_parts = {indentation, word}
|
||||
line_length = #indentation + #word
|
||||
end
|
||||
end
|
||||
|
||||
if #line_parts > 0 then
|
||||
table.insert(result_lines, table.concat(line_parts))
|
||||
end
|
||||
|
||||
if #result_lines == 0 then
|
||||
-- Preserve empty lines.
|
||||
result_lines[1] = ""
|
||||
end
|
||||
|
||||
return result_lines
|
||||
end
|
||||
|
||||
-- Automatically wraps lines within given array,
|
||||
-- attempting to limit line length to `max_length`.
|
||||
-- Existing line splits are preserved.
|
||||
local function autowrap(lines, max_length)
|
||||
local result_lines = {}
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
local autowrapped_lines = autowrap_line(line, max_length)
|
||||
|
||||
for _, autowrapped_line in ipairs(autowrapped_lines) do
|
||||
table.insert(result_lines, autowrapped_line)
|
||||
end
|
||||
end
|
||||
|
||||
return result_lines
|
||||
end
|
||||
|
||||
function Parser:_get_element_help(element)
|
||||
local label_lines = element:_get_label_lines()
|
||||
local description_lines = split_lines(element:_get_description())
|
||||
@@ -815,6 +886,12 @@ function Parser:_get_element_help(element)
|
||||
local description_margin_len = self:_inherit_property("help_description_margin", 25)
|
||||
local description_margin = (" "):rep(description_margin_len)
|
||||
|
||||
local help_max_width = self:_inherit_property("help_max_width")
|
||||
|
||||
if help_max_width then
|
||||
local description_max_width = math.max(help_max_width - description_margin_len, 10)
|
||||
description_lines = autowrap(description_lines, description_max_width)
|
||||
end
|
||||
|
||||
if #label_lines[1] >= (description_margin_len - usage_margin_len) then
|
||||
for _, label_line in ipairs(label_lines) do
|
||||
|
Reference in New Issue
Block a user