1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.cli2.util;
18
19 import java.io.PrintWriter;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Set;
27
28 import org.apache.commons.cli2.DisplaySetting;
29 import org.apache.commons.cli2.Group;
30 import org.apache.commons.cli2.HelpLine;
31 import org.apache.commons.cli2.Option;
32 import org.apache.commons.cli2.OptionException;
33 import org.apache.commons.cli2.resource.ResourceConstants;
34 import org.apache.commons.cli2.resource.ResourceHelper;
35
36
37
38
39 public class HelpFormatter {
40
41
42
43 public static final int DEFAULT_FULL_WIDTH = 80;
44
45
46
47
48 public static final String DEFAULT_GUTTER_LEFT = "";
49
50
51
52
53 public static final String DEFAULT_GUTTER_CENTER = " ";
54
55
56
57
58 public static final String DEFAULT_GUTTER_RIGHT = "";
59
60
61
62
63
64
65
66 public static final Set DEFAULT_FULL_USAGE_SETTINGS;
67
68
69
70
71
72
73
74 public static final Set DEFAULT_LINE_USAGE_SETTINGS;
75
76
77
78
79
80 public static final Set DEFAULT_DISPLAY_USAGE_SETTINGS;
81
82 static {
83 final Set fullUsage = new HashSet(DisplaySetting.ALL);
84 fullUsage.remove(DisplaySetting.DISPLAY_ALIASES);
85 fullUsage.remove(DisplaySetting.DISPLAY_GROUP_NAME);
86 fullUsage.remove(DisplaySetting.DISPLAY_OPTIONAL_CHILD_GROUP);
87 DEFAULT_FULL_USAGE_SETTINGS = Collections.unmodifiableSet(fullUsage);
88
89 final Set lineUsage = new HashSet();
90 lineUsage.add(DisplaySetting.DISPLAY_ALIASES);
91 lineUsage.add(DisplaySetting.DISPLAY_GROUP_NAME);
92 lineUsage.add(DisplaySetting.DISPLAY_PARENT_ARGUMENT);
93 DEFAULT_LINE_USAGE_SETTINGS = Collections.unmodifiableSet(lineUsage);
94
95 final Set displayUsage = new HashSet(DisplaySetting.ALL);
96 displayUsage.remove(DisplaySetting.DISPLAY_PARENT_ARGUMENT);
97 DEFAULT_DISPLAY_USAGE_SETTINGS = Collections.unmodifiableSet(displayUsage);
98 }
99
100 private Set fullUsageSettings = new HashSet(DEFAULT_FULL_USAGE_SETTINGS);
101 private Set lineUsageSettings = new HashSet(DEFAULT_LINE_USAGE_SETTINGS);
102 private Set displaySettings = new HashSet(DEFAULT_DISPLAY_USAGE_SETTINGS);
103 private OptionException exception = null;
104 private Group group;
105 private Comparator comparator = null;
106 private String divider = null;
107 private String header = null;
108 private String footer = null;
109 private String shellCommand = "";
110 private PrintWriter out = new PrintWriter(System.out);
111
112
113 private final String gutterLeft;
114 private final String gutterCenter;
115 private final String gutterRight;
116 private final int pageWidth;
117
118
119
120
121 public HelpFormatter() {
122 this(DEFAULT_GUTTER_LEFT, DEFAULT_GUTTER_CENTER, DEFAULT_GUTTER_RIGHT, DEFAULT_FULL_WIDTH);
123 }
124
125
126
127
128
129
130
131
132 public HelpFormatter(final String gutterLeft,
133 final String gutterCenter,
134 final String gutterRight,
135 final int fullWidth) {
136
137 this.gutterLeft = (gutterLeft == null) ? DEFAULT_GUTTER_LEFT : gutterLeft;
138
139
140 this.gutterCenter = (gutterCenter == null) ? DEFAULT_GUTTER_CENTER : gutterCenter;
141
142
143 this.gutterRight = (gutterRight == null) ? DEFAULT_GUTTER_RIGHT : gutterRight;
144
145
146 this.pageWidth = fullWidth - this.gutterLeft.length() - this.gutterRight.length();
147
148
149 int availableWidth = fullWidth - pageWidth + this.gutterCenter.length();
150
151 if (availableWidth < 2) {
152 throw new IllegalArgumentException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.HELPFORMATTER_GUTTER_TOO_LONG));
153 }
154 }
155
156
157
158
159 public void print() {
160 printHeader();
161 printException();
162 printUsage();
163 printHelp();
164 printFooter();
165 out.flush();
166 }
167
168
169
170
171 public void printException() {
172 if (exception != null) {
173 printDivider();
174 printWrapped(exception.getMessage());
175 }
176 }
177
178
179
180
181 public void printHelp() {
182 printDivider();
183
184 final Option option;
185
186 if ((exception != null) && (exception.getOption() != null)) {
187 option = exception.getOption();
188 } else {
189 option = group;
190 }
191
192
193 final List helpLines = option.helpLines(0, displaySettings, comparator);
194
195
196 int usageWidth = 0;
197
198 for (final Iterator i = helpLines.iterator(); i.hasNext();) {
199 final HelpLine helpLine = (HelpLine) i.next();
200 final String usage = helpLine.usage(lineUsageSettings, comparator);
201 usageWidth = Math.max(usageWidth, usage.length());
202 }
203
204
205 final StringBuffer blankBuffer = new StringBuffer();
206
207 for (int i = 0; i < usageWidth; i++) {
208 blankBuffer.append(' ');
209 }
210
211
212 final int descriptionWidth = Math.max(1, pageWidth - gutterCenter.length() - usageWidth);
213
214
215 for (final Iterator i = helpLines.iterator(); i.hasNext();) {
216
217 final HelpLine helpLine = (HelpLine) i.next();
218
219
220 final List descList = wrap(helpLine.getDescription(), descriptionWidth);
221 final Iterator descriptionIterator = descList.iterator();
222
223
224 printGutterLeft();
225 pad(helpLine.usage(lineUsageSettings, comparator), usageWidth, out);
226 out.print(gutterCenter);
227 pad((String) descriptionIterator.next(), descriptionWidth, out);
228 printGutterRight();
229 out.println();
230
231
232 while (descriptionIterator.hasNext()) {
233 printGutterLeft();
234
235
236 out.print(blankBuffer);
237 out.print(gutterCenter);
238 pad((String) descriptionIterator.next(), descriptionWidth, out);
239 printGutterRight();
240 out.println();
241 }
242 }
243
244 printDivider();
245 }
246
247
248
249
250 public void printUsage() {
251 printDivider();
252
253 final StringBuffer buffer = new StringBuffer("Usage:\n");
254 buffer.append(shellCommand).append(' ');
255 group.appendUsage(buffer, fullUsageSettings, comparator, " ");
256 printWrapped(buffer.toString());
257 }
258
259
260
261
262 public void printHeader() {
263 if (header != null) {
264 printDivider();
265 printWrapped(header);
266 }
267 }
268
269
270
271
272 public void printFooter() {
273 if (footer != null) {
274 printWrapped(footer);
275 printDivider();
276 }
277 }
278
279
280
281
282
283 public void printWrapped(final String text) {
284 for (final Iterator i = wrap(text, pageWidth).iterator(); i.hasNext();) {
285 printGutterLeft();
286 pad((String) i.next(), pageWidth, out);
287 printGutterRight();
288 out.println();
289 }
290
291 out.flush();
292 }
293
294
295
296
297 public void printGutterLeft() {
298 if (gutterLeft != null) {
299 out.print(gutterLeft);
300 }
301 }
302
303
304
305
306 public void printGutterRight() {
307 if (gutterRight != null) {
308 out.print(gutterRight);
309 }
310 }
311
312
313
314
315 public void printDivider() {
316 if (divider != null) {
317 out.println(divider);
318 }
319 }
320
321 protected static void pad(final String text,
322 final int width,
323 final PrintWriter writer) {
324 final int left;
325
326
327 if (text == null) {
328 left = 0;
329 } else {
330 writer.write(text);
331 left = text.length();
332 }
333
334
335 for (int i = left; i < width; ++i) {
336 writer.write(' ');
337 }
338 }
339
340 protected static List wrap(final String text,
341 final int width) {
342
343 if (width < 1) {
344 throw new IllegalArgumentException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.HELPFORMATTER_WIDTH_TOO_NARROW,
345 new Object[] {
346 new Integer(width)
347 }));
348 }
349
350
351 if (text == null) {
352 return Collections.singletonList("");
353 }
354
355 final List lines = new ArrayList();
356 final char[] chars = text.toCharArray();
357 int left = 0;
358
359
360 while (left < chars.length) {
361
362 int right = left;
363
364
365 while ((right < chars.length) && (chars[right] != '\n') &&
366 (right < (left + width + 1))) {
367 right++;
368 }
369
370
371 if ((right < chars.length) && (chars[right] == '\n')) {
372
373 final String line = new String(chars, left, right - left);
374 lines.add(line);
375
376
377 left = right + 1;
378
379 if (left == chars.length) {
380 lines.add("");
381 }
382
383
384 continue;
385 }
386
387
388 right = (left + width) - 1;
389
390
391 if (chars.length <= right) {
392
393 final String line = new String(chars, left, chars.length - left);
394 lines.add(line);
395
396
397 break;
398 }
399
400
401 while ((right >= left) && (chars[right] != ' ')) {
402 right--;
403 }
404
405
406 if (right >= left) {
407
408 final String line = new String(chars, left, right - left);
409 lines.add(line);
410
411
412 while ((right < chars.length) && (chars[right] == ' ')) {
413 right++;
414 }
415
416 left = right;
417
418
419 continue;
420 }
421
422
423 right = Math.min(left + width, chars.length);
424
425
426 final String line = new String(chars, left, right - left);
427 lines.add(line);
428
429
430 while ((right < chars.length) && (chars[right] == ' ')) {
431 right++;
432 }
433
434 left = right;
435 }
436
437 return lines;
438 }
439
440
441
442
443
444 public void setComparator(Comparator comparator) {
445 this.comparator = comparator;
446 }
447
448
449
450
451
452
453
454
455 public void setDisplaySettings(Set displaySettings) {
456 this.displaySettings = displaySettings;
457 }
458
459
460
461
462
463 public void setDivider(String divider) {
464 this.divider = divider;
465 }
466
467
468
469
470
471 public void setException(OptionException exception) {
472 this.exception = exception;
473 }
474
475
476
477
478
479 public void setFooter(String footer) {
480 this.footer = footer;
481 }
482
483
484
485
486
487
488
489 public void setFullUsageSettings(Set fullUsageSettings) {
490 this.fullUsageSettings = fullUsageSettings;
491 }
492
493
494
495
496
497 public void setGroup(Group group) {
498 this.group = group;
499 }
500
501
502
503
504
505 public void setHeader(String header) {
506 this.header = header;
507 }
508
509
510
511
512
513
514
515 public void setLineUsageSettings(Set lineUsageSettings) {
516 this.lineUsageSettings = lineUsageSettings;
517 }
518
519
520
521
522
523 public void setShellCommand(String shellCommand) {
524 this.shellCommand = shellCommand;
525 }
526
527
528
529
530 public Comparator getComparator() {
531 return comparator;
532 }
533
534
535
536
537 public Set getDisplaySettings() {
538 return displaySettings;
539 }
540
541
542
543
544 public String getDivider() {
545 return divider;
546 }
547
548
549
550
551 public OptionException getException() {
552 return exception;
553 }
554
555
556
557
558 public String getFooter() {
559 return footer;
560 }
561
562
563
564
565 public Set getFullUsageSettings() {
566 return fullUsageSettings;
567 }
568
569
570
571
572 public Group getGroup() {
573 return group;
574 }
575
576
577
578
579 public String getGutterCenter() {
580 return gutterCenter;
581 }
582
583
584
585
586 public String getGutterLeft() {
587 return gutterLeft;
588 }
589
590
591
592
593 public String getGutterRight() {
594 return gutterRight;
595 }
596
597
598
599
600 public String getHeader() {
601 return header;
602 }
603
604
605
606
607 public Set getLineUsageSettings() {
608 return lineUsageSettings;
609 }
610
611
612
613
614 public int getPageWidth() {
615 return pageWidth;
616 }
617
618
619
620
621 public String getShellCommand() {
622 return shellCommand;
623 }
624
625
626
627
628 public void setPrintWriter(PrintWriter out) {
629 this.out = out;
630 }
631
632
633
634
635 public PrintWriter getPrintWriter() {
636 return out;
637 }
638 }