diff --git a/src/parsing.jl b/src/parsing.jl index 74edac6..c50e1e7 100644 --- a/src/parsing.jl +++ b/src/parsing.jl @@ -137,7 +137,7 @@ function usage_string(settings::ArgParseSettings) usage_pre = "usage: " * (isempty(settings.prog) ? "" : settings.prog) - lc_len_limit = 24 + lc_len_limit = settings.help_alignment_width cmd_lst = String[] pos_lst = String[] @@ -238,7 +238,8 @@ function usage_string(settings::ArgParseSettings) str_nonwrapped = usage_pre * excl_str * optl_str * posl_str * cmdl_str str_wrapped = TextWrap.wrap(str_nonwrapped, break_long_words = false, break_on_hyphens = false, - subsequent_indent = min(usage_len, lc_len_limit)) + subsequent_indent = min(usage_len, lc_len_limit), + width = settings.help_width) out_str = replace(str_wrapped, nbspc => ' ') @@ -282,7 +283,8 @@ function gen_help_text(arg::ArgParseField, settings::ArgParseSettings) end function print_group(io::IO, lst::Vector, desc::AbstractString, lc_usable_len::Int, lc_len::Int, - lmargin::AbstractString, rmargin::AbstractString, sindent::AbstractString) + lmargin::AbstractString, rmargin::AbstractString, sindent::AbstractString, + width::Int) isempty(lst) && return println(io, desc, ":") for l in lst @@ -291,12 +293,12 @@ function print_group(io::IO, lst::Vector, desc::AbstractString, lc_usable_len::I rfill = " "^(lc_len - l1len) ll_nonwrapped = l[1] * rfill * rmargin * l[2] ll_wrapped = TextWrap.wrap(ll_nonwrapped, break_long_words = false, break_on_hyphens = false, - initial_indent = lmargin, subsequent_indent = sindent) + initial_indent = lmargin, subsequent_indent = sindent, width = width) println_unnbsp(io, ll_wrapped) else println_unnbsp(io, lmargin, l[1]) l2_wrapped = TextWrap.wrap(l[2], break_long_words = false, break_on_hyphens = false, - initial_indent = sindent, subsequent_indent = sindent) + initial_indent = sindent, subsequent_indent = sindent, width = width) println_unnbsp(io, l2_wrapped) end end @@ -307,7 +309,7 @@ show_help(settings::ArgParseSettings; kw...) = show_help(stdout, settings; kw... function show_help(io::IO, settings::ArgParseSettings; exit_when_done = !isinteractive()) - lc_len_limit = 24 + lc_len_limit = settings.help_alignment_width lc_left_indent = 2 lc_right_margin = 2 @@ -366,25 +368,25 @@ function show_help(io::IO, settings::ArgParseSettings; exit_when_done = !isinter println(io, usage_str) println(io) - show_message(io, settings.description, settings.preformatted_description) + show_message(io, settings.description, settings.preformatted_description, settings.help_width) for ag in settings.args_groups print_group(io, group_lists[ag.name], ag.desc, lc_usable_len, lc_len, - lmargin, rmargin, sindent) + lmargin, rmargin, sindent, settings.help_width) end - show_message(io, settings.epilog, settings.preformatted_epilog) + show_message(io, settings.epilog, settings.preformatted_epilog, settings.help_width) exit_when_done && exit(0) return end -function show_message(io::IO, message::AbstractString, preformatted::Bool) +function show_message(io::IO, message::AbstractString, preformatted::Bool, width::Int) if !isempty(message) if preformatted print(io, message) else for l in split(message, "\n\n") - message_wrapped = TextWrap.wrap(l, break_long_words = false, break_on_hyphens = false) + message_wrapped = TextWrap.wrap(l, break_long_words = false, break_on_hyphens = false, width = width) println_unnbsp(io, message_wrapped) end end diff --git a/src/settings.jl b/src/settings.jl index d343445..22f38cd 100644 --- a/src/settings.jl +++ b/src/settings.jl @@ -165,6 +165,13 @@ This is the list of general settings currently available: action) is added to the argument table. * `add_version` (default = `false`): if `true`, a `--version` option (triggering the `:show_version` action) is added to the argument table. +* `help_width` (default = `70`): set the width of the help text. This does not affect the + `usage` line if it is provided by the user rather than being auto-generated; it also does not + affect the `description/epilog` lines if the `preformatted_description/epilog` options are set to + `false`. +* `help_alignment_width` (default = `24`): set the maximum width of the left column of the help + text, where options and arguments names are listed. This also affects the indentation of the usage + line when it is auto-generated. It must be ≥ 4 and should be less than `help_width`. * `fromfile_prefix_chars` (default = `Set{Char}()`): an argument beginning with one of these characters will specify a file from which arguments will be read, one argument read per line. Alphanumeric characters and the hyphen-minus (`'-'`) are prohibited. @@ -246,6 +253,8 @@ mutable struct ArgParseSettings version::AbstractString add_help::Bool add_version::Bool + help_width::Int + help_alignment_width::Int fromfile_prefix_chars::Set{Char} autofix_names::Bool error_on_conflict::Bool @@ -269,6 +278,8 @@ mutable struct ArgParseSettings version::AbstractString = "Unspecified version", add_help::Bool = true, add_version::Bool = false, + help_width::Integer = 70, + help_alignment_width::Integer = 24, fromfile_prefix_chars = Set{Char}(), autofix_names::Bool = false, error_on_conflict::Bool = true, @@ -283,8 +294,8 @@ mutable struct ArgParseSettings fromfile_prefix_chars = check_prefix_chars(fromfile_prefix_chars) return new( prog, description, epilog, usage, version, add_help, add_version, - fromfile_prefix_chars, autofix_names, error_on_conflict, - suppress_warnings, allow_ambiguous_opts, commands_are_required, + help_width, help_alignment_width, fromfile_prefix_chars, autofix_names, + error_on_conflict, suppress_warnings, allow_ambiguous_opts, commands_are_required, copy(std_groups), "", ArgParseTable(), exc_handler, preformatted_description, preformatted_epilog, exit_after_help diff --git a/test/argparse_test13.jl b/test/argparse_test13.jl new file mode 100644 index 0000000..a124dd9 --- /dev/null +++ b/test/argparse_test13.jl @@ -0,0 +1,182 @@ +# test 13: help_width and help_alignment_width settings + +@testset "test 13" begin + +function ap_settings13() + + s = ArgParseSettings(description = "Test 13 for ArgParse.jl. This description is made unnecessarily long for the sake of testing the help_text_width setting.", + epilog = "This epilog is also made unnecessarily long for the same reason as the description, i.e., testing the help_text_width setting.", + exc_handler = ArgParse.debug_handler) + + @add_arg_table! s begin + "--option1" + arg_type = Int + default = 0 + help = "an option, not used for much really, " * + "indeed it is not actually used for anything. " * + "That is why its name is so undescriptive." + "-O", "--long-option" + arg_type = Symbol + default = :xyz + help = "another option, this time it has a fancy name " * + "and yet it is still completely useless." + "arg1" + help = "first argument" + required = true + "arg2" + default = "no arg2 given" + help = "second argument" + end + + return s +end + +let s = ap_settings13() + @test stringhelp(s) == """ + usage: $(basename(Base.source_path())) [--option1 OPTION1] [-O LONG-OPTION] arg1 + [arg2] + + Test 13 for ArgParse.jl. This description is made unnecessarily long + for the sake of testing the help_text_width setting. + + positional arguments: + arg1 first argument + arg2 second argument (default: "no arg2 given") + + optional arguments: + --option1 OPTION1 an option, not used for much really, indeed it + is not actually used for anything. That is why + its name is so undescriptive. (type: Int64, + default: 0) + -O, --long-option LONG-OPTION + another option, this time it has a fancy name + and yet it is still completely useless. (type: + Symbol, default: :xyz) + + This epilog is also made unnecessarily long for the same reason as the + description, i.e., testing the help_text_width setting. + + """ + + s.help_width = 120 + + @test stringhelp(s) == """ + usage: $(basename(Base.source_path())) [--option1 OPTION1] [-O LONG-OPTION] arg1 [arg2] + + Test 13 for ArgParse.jl. This description is made unnecessarily long for the sake of testing the help_text_width + setting. + + positional arguments: + arg1 first argument + arg2 second argument (default: "no arg2 given") + + optional arguments: + --option1 OPTION1 an option, not used for much really, indeed it is not actually used for anything. That is why + its name is so undescriptive. (type: Int64, default: 0) + -O, --long-option LONG-OPTION + another option, this time it has a fancy name and yet it is still completely useless. (type: + Symbol, default: :xyz) + + This epilog is also made unnecessarily long for the same reason as the description, i.e., testing the help_text_width + setting. + + """ + + s.help_width = 50 + + @test stringhelp(s) == """ + usage: $(basename(Base.source_path())) [--option1 OPTION1] + [-O LONG-OPTION] arg1 + [arg2] + + Test 13 for ArgParse.jl. This description is made + unnecessarily long for the sake of testing the + help_text_width setting. + + positional arguments: + arg1 first argument + arg2 second argument (default: + "no arg2 given") + + optional arguments: + --option1 OPTION1 an option, not used for + much really, indeed it is + not actually used for + anything. That is why its + name is so undescriptive. + (type: Int64, default: 0) + -O, --long-option LONG-OPTION + another option, this time + it has a fancy name and + yet it is still completely + useless. (type: Symbol, + default: :xyz) + + This epilog is also made unnecessarily long for + the same reason as the description, i.e., testing + the help_text_width setting. + + """ + + s.help_width = 100 + s.help_alignment_width = 50 + + @test stringhelp(s) == """ + usage: $(basename(Base.source_path())) [--option1 OPTION1] [-O LONG-OPTION] arg1 [arg2] + + Test 13 for ArgParse.jl. This description is made unnecessarily long for the sake of testing the + help_text_width setting. + + positional arguments: + arg1 first argument + arg2 second argument (default: "no arg2 given") + + optional arguments: + --option1 OPTION1 an option, not used for much really, indeed it is not actually used + for anything. That is why its name is so undescriptive. (type: + Int64, default: 0) + -O, --long-option LONG-OPTION another option, this time it has a fancy name and yet it is still + completely useless. (type: Symbol, default: :xyz) + + This epilog is also made unnecessarily long for the same reason as the description, i.e., testing + the help_text_width setting. + + """ + + s.help_width = 50 + s.help_alignment_width = 4 + + @test stringhelp(s) == """ + usage: $(basename(Base.source_path())) [--option1 OPTION1] + [-O LONG-OPTION] arg1 [arg2] + + Test 13 for ArgParse.jl. This description is made + unnecessarily long for the sake of testing the + help_text_width setting. + + positional arguments: + arg1 + first argument + arg2 + second argument (default: "no arg2 given") + + optional arguments: + --option1 OPTION1 + an option, not used for much really, indeed it + is not actually used for anything. That is why + its name is so undescriptive. (type: Int64, + default: 0) + -O, --long-option LONG-OPTION + another option, this time it has a fancy name + and yet it is still completely useless. (type: + Symbol, default: :xyz) + + This epilog is also made unnecessarily long for + the same reason as the description, i.e., testing + the help_text_width setting. + + """ + +end + +end diff --git a/test/runtests.jl b/test/runtests.jl index e19cddf..dbcd279 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,7 +2,7 @@ module ArgParseTests include("common.jl") -for i = 1:12 +for i = 1:13 try s_i = lpad(string(i), 2, "0") include("argparse_test$s_i.jl")