Skip to content

Commit 0b115d5

Browse files
Cleanup help formatting (#277)
* Changed deprecatedFormatFunc BiFunction to Function, updated docs, added HelpFromatter.getDescription(Option) * fixed checkstyle issue * Changes as per review * Fix Javadoc since tag --------- Co-authored-by: Gary Gregory <garydgregory@users.noreply.github.com>
1 parent 65cb6cd commit 0b115d5

3 files changed

Lines changed: 143 additions & 139 deletions

File tree

src/main/java/org/apache/commons/cli/HelpFormatter.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
3030
import java.util.Iterator;
3131
import java.util.List;
3232
import java.util.Objects;
33-
import java.util.function.BiFunction;
33+
import java.util.function.Function;
3434
import java.util.function.Supplier;
3535

3636
/**
@@ -78,12 +78,12 @@ public static final class Builder implements Supplier<HelpFormatter> {
7878
/**
7979
* A function to convert a description (not null) and a deprecated Option (not null) to help description
8080
*/
81-
private static final BiFunction<String, Option, String> DEFAULT_DEPRECATED_FORMAT = (d, o) -> "[Deprecated] " + d;
81+
private static final Function<Option, String> DEFAULT_DEPRECATED_FORMAT = o -> "[Deprecated] " + getDescription(o);
8282

8383
/**
8484
* Formatter for deprecated options.
8585
*/
86-
private BiFunction<String, Option, String> deprecatedFormatFunc = DEFAULT_DEPRECATED_FORMAT;
86+
private Function<Option, String> deprecatedFormatFunc = DEFAULT_DEPRECATED_FORMAT;
8787

8888
/**
8989
* The output PrintWriter, defaults to wrapping {@link System#out}.
@@ -113,7 +113,7 @@ public Builder setPrintWriter(final PrintWriter printWriter) {
113113
* @return this.
114114
* @since 1.8.0
115115
*/
116-
public Builder setShowDeprecated(final BiFunction<String, Option, String> showDeprecatedFunc) {
116+
public Builder setShowDeprecated(final Function<Option, String> showDeprecatedFunc) {
117117
this.deprecatedFormatFunc = showDeprecatedFunc;
118118
return this;
119119
}
@@ -129,6 +129,16 @@ public Builder setShowDeprecated(final boolean useDefaultFormat) {
129129
}
130130
}
131131

132+
/**
133+
* Gets the option description or an empty string if the description is {@code null}.
134+
* @param option The option to get the description from.
135+
* @return the option description or an empty string if the description is {@code null}.
136+
* @since 1.8.0
137+
*/
138+
public static String getDescription(final Option option) {
139+
String desc = option.getDescription();
140+
return desc == null ? "" : desc;
141+
}
132142
/**
133143
* This class implements the {@code Comparator} interface for comparing Options.
134144
*/
@@ -266,9 +276,9 @@ private static PrintWriter createDefaultPrintWriter() {
266276
protected Comparator<Option> optionComparator = new OptionComparator();
267277

268278
/**
269-
* BiFunction to format the description for a deprecated option.
279+
* Function to format the description for a deprecated option.
270280
*/
271-
private final BiFunction<String, Option, String> deprecatedFormatFunc;
281+
private final Function<Option, String> deprecatedFormatFunc;
272282

273283
/**
274284
* Where to print help.
@@ -291,7 +301,7 @@ public HelpFormatter() {
291301
* Constructs a new instance.
292302
* @param printStream TODO
293303
*/
294-
private HelpFormatter(final BiFunction<String, Option, String> deprecatedFormatFunc, final PrintWriter printStream) {
304+
private HelpFormatter(final Function<Option, String> deprecatedFormatFunc, final PrintWriter printStream) {
295305
// TODO All other instance HelpFormatter instance variables.
296306
// Make HelpFormatter immutable for 2.0
297307
this.deprecatedFormatFunc = deprecatedFormatFunc;
@@ -795,7 +805,7 @@ protected StringBuffer renderOptions(final StringBuffer sb, final int width, fin
795805
optBuf.append(dpad);
796806
final int nextLineTabStop = max + descPad;
797807
if (deprecatedFormatFunc != null && option.isDeprecated()) {
798-
optBuf.append(deprecatedFormatFunc.apply(option.getDescription() == null ? "" : option.getDescription(), option).trim());
808+
optBuf.append(deprecatedFormatFunc.apply(option).trim());
799809
} else if (option.getDescription() != null) {
800810
optBuf.append(option.getDescription());
801811
}

src/site/xdoc/usage.xml

Lines changed: 113 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ try {
382382
}
383383
catch (ParseException exp) {
384384
System.out.println("Unexpected exception:" + exp.getMessage());
385-
}</source>
385+
} </source>
386386
</section>
387387
<section name="Converting (Parsing) Option Values">
388388
<p>
@@ -392,31 +392,30 @@ catch (ParseException exp) {
392392
that the "count" option should return an Integer the following code could be used:
393393
</p>
394394
<source>
395-
public static void main(String[] args) {
396-
Option count = Option.builder("count")
397-
.hasArg()
398-
.desc("the number of things")
399-
.type(Integer.class)
400-
.build();
401-
Options options = new Options().addOption(count);
402-
// create the parser
403-
CommandLineParser parser = new DefaultParser();
404-
try {
405-
// parse the command line arguments
406-
CommandLine line = parser.parse(options, args);
407-
}
408-
catch (ParseException exp) {
409-
// oops, something went wrong
410-
System.err.println("Parsing failed. Reason: " + exp.getMessage());
411-
}
412-
413-
try {
414-
Integer value = line.getParsedOptionValue(count);
415-
System.out.format("The value is %s\m", value );
416-
} catch (ParseException e) {
417-
e.printStackTrace();
418-
}
419-
}</source>
395+
public static void main(String[] args) {
396+
Option count = Option.builder("count")
397+
.hasArg()
398+
.desc("the number of things")
399+
.type(Integer.class)
400+
.build();
401+
Options options = new Options().addOption(count);
402+
// create the parser
403+
CommandLineParser parser = new DefaultParser();
404+
try {
405+
// parse the command line arguments
406+
CommandLine line = parser.parse(options, args);
407+
} catch (ParseException exp) {
408+
// oops, something went wrong
409+
System.err.println("Parsing failed. Reason: " + exp.getMessage());
410+
}
411+
412+
try {
413+
Integer value = line.getParsedOptionValue(count);
414+
System.out.format("The value is %s%n", value );
415+
} catch (ParseException e) {
416+
e.printStackTrace();
417+
}
418+
} </source>
420419
<p>
421420
The value types natively supported by commons-cli are:
422421
<ul>
@@ -446,12 +445,11 @@ catch (ParseException exp) {
446445
Conversions can be specified without using the <code>TypeHandler</code> class by specifying the converter
447446
directly during the option build. For example:
448447
<source>
449-
Option fooOpt = Option.builder("foo")
450-
.hasArg()
451-
.desc("the foo arg")
452-
.converter((s) -> new Foo(s))
453-
.build();
454-
</source>
448+
Option fooOpt = Option.builder("foo")
449+
.hasArg()
450+
.desc("the foo arg")
451+
.converter(Foo::new)
452+
.build();</source>
455453
The above will create an option that passes the string value to the Foo constructor when <code>commandLine.getParsedOptionValue(fooOpt)</code> is called.
456454
</p>
457455
<p>
@@ -466,145 +464,141 @@ catch (ParseException exp) {
466464
<code>deprecated</code> method.
467465

468466
Usage of the deprecated option is announced when the presence of the option is checked
469-
or the value of the option is retrieved. By default the announcement printed to Standard out.
467+
or the value of the option is retrieved. By default, the announcement printed to Standard out.
470468

471-
The HelpFormatter output will be default show the description prefixed by "[Deprecated]"
469+
The HelpFormatter output will by default show the description prefixed by "[Deprecated]"
472470
</p>
473471
<p>
474472
The examples below will implement <code>doSomething</code> in the following code block.
475473
<source>
476-
public static void main(String[] args) {
477-
Option n = Option.builder("n")
478-
.deprecated(DeprecatedAttributes.builder()
479-
.setDescription("Use '-count' instead")
480-
.setForRemoval(true)
481-
.setSince("now").get())
482-
.hasArg()
483-
.desc("the number of things")
484-
.type(Integer.class)
485-
.build();
486-
Option count = Option.builder("count")
487-
.hasArg()
488-
.desc("the number of things")
489-
.type(Integer.class)
490-
.build();
491-
Options options = new Options().addOption(n).addOption(count);
474+
public static void main(String[] args) {
475+
Option n = Option.builder("n")
476+
.deprecated(DeprecatedAttributes.builder()
477+
.setDescription("Use '-count' instead")
478+
.setForRemoval(true)
479+
.setSince("now").get())
480+
.hasArg()
481+
.desc("the number of things")
482+
.type(Integer.class)
483+
.build();
484+
Option count = Option.builder("count")
485+
.hasArg()
486+
.desc("the number of things")
487+
.type(Integer.class)
488+
.build();
489+
Options options = new Options().addOption(n).addOption(count);
492490

493-
doSomething(options);
494-
}
495-
</source>
491+
doSomething(options);
492+
} </source>
496493
</p>
497494

498495
<subsection name="Changing Usage Announcement">
499496
<p>
500-
The usage announcement may be changed by providing a <code>Consumer&gt;Option&lt;></code> to the
501-
<code>CommandLine.Builder.deprecatedHandler</code> method.
497+
The usage announcement may be changed by providing a <code>Consumer&lt;Option></code> to the
498+
<code>CommandLine.Builder.deprecatedHandler</code> method. This is commonly used to log usage
499+
of deprecated options rather than printing them on the standard output.
502500
</p>
503501
<p>
504502
for example if <code>doSomething</code> is implemented as:
505503
</p>
506-
<sorce>
507-
void doSomething(Options options) {
508-
CommandLineParser parser = new DefaultParser();
509-
CommandLine line;
510-
try {
511-
// parse the command line arguments
512-
line = parser.parse(options, new String[] {"-n", "5"});
513-
System.out.println( "n="+line.getParsedOptionValue("n"));
514-
} catch (ParseException exp) {
515-
// oops, something went wrong
516-
System.err.println("Parsing failed. Reason: " + exp.getMessage());
517-
}
518-
}
519-
</sorce>
504+
<source>
505+
void doSomething(Options options) {
506+
CommandLineParser parser = new DefaultParser();
507+
CommandLine line;
508+
try {
509+
// parse the command line arguments
510+
line = parser.parse(options, new String[] {"-n", "5"});
511+
System.out.println("n=" + line.getParsedOptionValue("n"));
512+
} catch (ParseException exp) {
513+
// oops, something went wrong
514+
System.err.println("Parsing failed. Reason: " + exp.getMessage());
515+
}
516+
} </source>
520517
<p>
521518
The output of the run would be.
522519
</p>
523520

524521
<source>
525-
Option 'n': Deprecated for removal since now: Use '-count' instead
526-
n=5
527-
</source>
522+
Option 'n': Deprecated for removal since now: Use '-count' instead
523+
n=5 </source>
528524

529525
<p>
530526
for example if <code>doSomething</code> is implemented as:
531527
</p>
532528

533529
<source>
534-
void doSomething(Options options) {
535-
Consumer&gt;Option&lt; deprecatedUsageAnnouncement = o -> {
536-
final StringBuilder buf = new StringBuilder()
537-
.append("'")
538-
.append(o.getOpt())
539-
.append("'");
540-
if (o.getLongOpt() != null) {
541-
buf.append("'").append(o.getLongOpt()).append("'");
542-
}
543-
System.err.printf("ERROR: Option %s: %s%n", buf, o.getDeprecated());
544-
};
545-
DefaultParser parser = DefaultParser.builder().setDeprecatedHandler(deprecatedUsageAnnouncement).build();
546-
CommandLine line;
547-
try {
548-
// parse the command line arguments
549-
line = parser.parse(options, new String[] {"-n", "5"});
550-
System.out.println( "n="+line.getParsedOptionValue("n"));
551-
} catch (ParseException exp) {
552-
// oops, something went wrong
553-
System.err.println("Parsing failed. Reason: " + exp.getMessage());
554-
}
555-
}
556-
</source>
530+
void doSomething(Options options) {
531+
Consumer&lt;Option> deprecatedUsageAnnouncement = o -> {
532+
final StringBuilder buf = new StringBuilder()
533+
.append("'")
534+
.append(o.getOpt())
535+
.append("'");
536+
if (o.getLongOpt() != null) {
537+
buf.append("'").append(o.getLongOpt()).append("'");
538+
}
539+
System.err.printf("ERROR: Option %s: %s%n", buf, o.getDeprecated());
540+
};
541+
DefaultParser parser = DefaultParser.builder().setDeprecatedHandler(deprecatedUsageAnnouncement).build();
542+
CommandLine line;
543+
try {
544+
// parse the command line arguments
545+
line = parser.parse(options, new String[] {"-n", "5"});
546+
System.out.println("n=" + line.getParsedOptionValue("n"));
547+
} catch (ParseException exp) {
548+
// oops, something went wrong
549+
System.err.println("Parsing failed. Reason: " + exp.getMessage());
550+
}
551+
} </source>
557552
<p>
558553
The output of the run would be.
559554
</p>
560555
<source>
561-
ERROR: Option 'n': Deprecated for removal since now: Use '-count' instead
562-
n=5
563-
</source>
556+
ERROR: Option 'n': Deprecated for removal since now: Use '-count' instead
557+
n=5 </source>
564558
<p>
565559
However, the first line would be printed on system err instead of system out.
566560
</p>
567561

568562
</subsection>
569563
<subsection name="Changing help format">
564+
<p>By default the help formater prints "[Deprecated]" in front of the description for the option. This can
565+
be changed to display any values desired.
566+
</p>
570567
<p>
571568
If <code>doSomething</code> is implemented as:
572569
<source>
573-
void doSomething(Options options) {
574-
HelpFormatter formatter = HelpFormatter.builder().get();
575-
formatter.printHelp("Command line syntax:", options);
576-
}
577-
</source>
570+
void doSomething(Options options) {
571+
HelpFormatter formatter = HelpFormatter.builder().get();
572+
formatter.printHelp("Command line syntax:", options);
573+
} </source>
578574
To output is
579575
<source>
580-
usage: Command line syntax:
581-
-count &lt;arg> the number of things
582-
-n &lt;arg> [Deprecated] the number of things
583-
</source>
576+
usage: Command line syntax:
577+
-count &lt;arg> the number of things
578+
-n &lt;arg> [Deprecated] the number of things</source>
584579
</p>
585580
<p>
586581
The display of deprecated options may be changed through the use of the
587582
<code>HelpFormatter.Builder.setShowDeprecated()</code> method.
588583
<ul>
589584
<li>Calling <code>HelpFormatter.Builder.setShowDeprecated(false)</code> will disable the "[Deprecated]" tag.</li>
590-
<li>Calling <code>HelpFormatter.Builder.setShowDeprecated</code> with a <code>BiFunction&lt;String, Option, String></code>
585+
<li>Calling <code>HelpFormatter.Builder.setShowDeprecated</code> with a <code>Function&lt;Option, String></code>
591586
will use the output of the function as the description for the option.</li>
592587
</ul>
593588
As an example of the second case above, changing the implementation of <code>doSomething</code> to
594589
<source>
595-
void doSomething(Options options) {
596-
BiFunction&lt;String, Option, String> disp = (desc, option) -> String.format( "%s. %s", desc, option.getDeprecated().toString());
597-
HelpFormatter formatter = HelpFormatter.builder().setShowDeprecated(disp).get();
598-
formatter.printHelp("Command line syntax:", options);
599-
}
600-
</source>
590+
void doSomething(Options options) {
591+
Function&lt;Option, String> disp = option -> String.format("%s. %s", HelpFormatter.getDescription(option),
592+
option.getDeprecated().toString());
593+
HelpFormatter formatter = HelpFormatter.builder().setShowDeprecated(disp).get();
594+
formatter.printHelp("Command line syntax:", options);
595+
} </source>
601596
changes the output to
602597
<source>
603-
usage: Command line syntax:
604-
-count &lt;arg> the number of things
605-
-n &lt;arg> the number of things. Deprecated for removal since now:
606-
Use '-count' instead
607-
</source>
598+
usage: Command line syntax:
599+
-count &lt;arg> the number of things
600+
-n &lt;arg> the number of things. Deprecated for removal since now:
601+
Use '-count' instead</source>
608602
</p>
609603
</subsection>
610604
</section>

0 commit comments

Comments
 (0)