diff --git a/spec/std/option_parser_spec.cr b/spec/std/option_parser_spec.cr index d7e701e0f4d3..2c6d9f3882ce 100644 --- a/spec/std/option_parser_spec.cr +++ b/spec/std/option_parser_spec.cr @@ -789,3 +789,117 @@ describe "OptionParser" do args.should eq(%w(file --bar)) end end + +describe "OptionParser with summary_width and summary_indent" do + it "formats flags and descriptions with default summary_width and summary_indent" do + parser = OptionParser.new + + parser.on("-f", "--flag", "A short description") { } + parser.on("-l", "--long-flag", "A long description for testing purposes") { } + + output = parser.to_s + + expected_output = <<-USAGE + -f, --flag A short description + -l, --long-flag A long description for testing purposes + USAGE + + output.should eq(expected_output) + end + + it "formats flags and descriptions with custom summary_width and summary_indent" do + parser = OptionParser.new + parser.summary_width = 40 + parser.summary_indent = "|" * 6 + + parser.on("-f", "--flag", "A short description") { } + parser.on("-l", "--long-flag", "A long description for testing purposes") { } + + output = parser.to_s + + expected_output = <<-USAGE + ||||||-f, --flag A short description + ||||||-l, --long-flag A long description for testing purposes + USAGE + + output.should eq(expected_output) + end + + it "handles multiline descriptions correctly with summary_width" do + parser = OptionParser.new + parser.summary_width = 20 + parser.summary_indent = " " * 4 + + parser.on("--complex-option", "This is a detailed description\nspanning multiple lines for testing") { } + + output = parser.to_s + + expected_output = <<-USAGE + --complex-option This is a detailed description + spanning multiple lines for testing + USAGE + + output.should eq(expected_output) + end + + it "adjusts formatting when flag length exceeds summary_width" do + parser = OptionParser.new + parser.summary_width = 20 + parser.summary_indent = " " * 4 + + parser.on("--very-very-long-option", "Description that follows a very\nlong flag") { } + + output = parser.to_s + + expected_output = <<-USAGE + --very-very-long-option + Description that follows a very + long flag + USAGE + + output.should eq(expected_output) + end + + it "handles extreme summary_width values (e.g., 0)" do + parser = OptionParser.new + parser.summary_width = 0 + parser.summary_indent = " " * 4 + + parser.on("--short", "No space for flags!") { } + + output = parser.to_s + + expected_output = <<-USAGE + --short + No space for flags! + USAGE + + output.should eq(expected_output) + end + + it "handles extreme summary_indent values (e.g., empty string)" do + parser = OptionParser.new + parser.summary_width = 20 + parser.summary_indent = "" + + parser.on("--test", "Indentation removed") { } + + output = parser.to_s + + expected_output = <<-USAGE + --test Indentation removed + USAGE + + output.should eq(expected_output) + end + + # it "raises an error for invalid summary_width or summary_indent" do + # parser = OptionParser.new + # expect_raises ArgumentError, "Invalid summary width: -10" do + # parser.summary_width = -10 + # end + # expect_raises ArgumentError, "Invalid summary indent: -5" do + # parser.summary_indent = -5 + # end + # end +end diff --git a/src/option_parser.cr b/src/option_parser.cr index 5f61e73cd58d..72032dfa697a 100644 --- a/src/option_parser.cr +++ b/src/option_parser.cr @@ -316,13 +316,20 @@ class OptionParser @flags.join io, '\n' end + # Width for option list portion of summary. + property summary_width : Int32 = 32 + + # Indentation for summary. + property summary_indent : String = " " + private def append_flag(flag, description) - indent = " " * 37 - description = description.gsub("\n", "\n#{indent}") - if flag.size >= 33 - @flags << " #{flag}\n#{indent}#{description}" + description_indent = "#{summary_indent}#{" " * summary_width} " # Adjust the indent based on summary_width + description = description.gsub("\n", "\n#{description_indent}") + + if flag.size >= summary_width + @flags << "#{summary_indent}#{flag}\n#{description_indent}#{description}" else - @flags << " #{flag}#{" " * (33 - flag.size)}#{description}" + @flags << "#{summary_indent}#{flag}#{" " * (summary_width - flag.size)} #{description}" end end @@ -342,6 +349,8 @@ class OptionParser old_missing_option = @missing_option old_invalid_option = @invalid_option old_before_each = @before_each + old_summary_width = @summary_width + old_summary_indent = @summary_indent begin yield @@ -354,6 +363,8 @@ class OptionParser @missing_option = old_missing_option @invalid_option = old_invalid_option @before_each = old_before_each + @summary_width = old_summary_width + @summary_indent = old_summary_indent end end