1:
17: package ;
18:
19: import ;
20: import ;
21: import ;
22:
23: import ;
24: import ;
25: import ;
26: import ;
27: import ;
28: import ;
29: import ;
30:
31: import ;
32: import ;
33: import ;
34: import ;
35: import ;
36: import ;
37: import ;
38:
39:
45: public class HelpFormatter
46: {
47:
50: public static final int DEFAULT_FULL_WIDTH = 80;
51:
52:
55: public static final int DEFAULT_DESCRIPTION_WIDTH = -1;
56:
57:
60: public static final String DEFAULT_GUTTER_LEFT = "";
61:
62:
65: public static final String DEFAULT_GUTTER_CENTER = " ";
66:
67:
70: public static final String DEFAULT_GUTTER_RIGHT = "";
71:
72:
78: public static final Set DEFAULT_FULL_USAGE_SETTINGS;
79:
80:
86: public static final Set DEFAULT_LINE_USAGE_SETTINGS;
87:
88:
92: public static final Set DEFAULT_DISPLAY_USAGE_SETTINGS;
93:
94: static
95: {
96: final Set fullUsage = new HashSet( DisplaySetting.ALL );
97: fullUsage.remove( DisplaySetting.DISPLAY_ALIASES );
98: fullUsage.remove( DisplaySetting.DISPLAY_GROUP_NAME );
99: DEFAULT_FULL_USAGE_SETTINGS = Collections.unmodifiableSet( fullUsage );
100:
101: final Set lineUsage = new HashSet();
102: lineUsage.add( DisplaySetting.DISPLAY_ALIASES );
103: lineUsage.add( DisplaySetting.DISPLAY_GROUP_NAME );
104: lineUsage.add( DisplaySetting.DISPLAY_PARENT_ARGUMENT );
105: DEFAULT_LINE_USAGE_SETTINGS = Collections.unmodifiableSet( lineUsage );
106:
107: final Set displayUsage = new HashSet( DisplaySetting.ALL );
108: displayUsage.remove( DisplaySetting.DISPLAY_PARENT_ARGUMENT );
109: DEFAULT_DISPLAY_USAGE_SETTINGS = Collections.unmodifiableSet( displayUsage );
110: }
111:
112: private Set m_fullUsageSettings = new HashSet( DEFAULT_FULL_USAGE_SETTINGS );
113: private Set m_lineUsageSettings = new HashSet( DEFAULT_LINE_USAGE_SETTINGS );
114: private Set m_displaySettings = new HashSet( DEFAULT_DISPLAY_USAGE_SETTINGS );
115: private OptionException m_exception = null;
116: private Group m_group;
117: private Comparator m_comparator = null;
118: private String m_divider = null;
119: private String m_header = null;
120: private String m_footer = null;
121: private String m_shellCommand = "";
122: private PrintWriter m_out = new PrintWriter( System.out );
123:
124:
125: private final String m_gutterLeft;
126: private final String m_gutterCenter;
127: private final String m_gutterRight;
128: private final int m_pageWidth;
129: private final int m_descriptionWidth;
130:
131:
134: public HelpFormatter()
135: {
136: this(
137: DEFAULT_GUTTER_LEFT, DEFAULT_GUTTER_CENTER, DEFAULT_GUTTER_RIGHT,
138: DEFAULT_FULL_WIDTH, DEFAULT_DESCRIPTION_WIDTH );
139: }
140:
141:
148: public HelpFormatter(
149: final String gutterLeft, final String gutterCenter, final String gutterRight,
150: final int fullWidth )
151: {
152: this( gutterLeft, gutterCenter, gutterRight, fullWidth, DEFAULT_DESCRIPTION_WIDTH );
153: }
154:
155:
163: public HelpFormatter(
164: final String gutterLeft, final String gutterCenter, final String gutterRight,
165: final int fullWidth, final int descriptionWidth )
166: {
167:
168: if( null == gutterLeft )
169: {
170: m_gutterLeft = DEFAULT_GUTTER_LEFT;
171: }
172: else
173: {
174: m_gutterLeft = gutterLeft;
175: }
176:
177: if( null == gutterCenter )
178: {
179: m_gutterCenter = DEFAULT_GUTTER_CENTER;
180: }
181: else
182: {
183: m_gutterCenter = gutterCenter;
184: }
185:
186: if( null == gutterRight )
187: {
188: m_gutterRight = DEFAULT_GUTTER_RIGHT;
189: }
190: else
191: {
192: m_gutterRight = gutterRight;
193: }
194:
195: m_descriptionWidth = descriptionWidth;
196:
197:
198: m_pageWidth = fullWidth - m_gutterLeft.length() - m_gutterRight.length();
199:
200:
201: int availableWidth = fullWidth - m_pageWidth + m_gutterCenter.length();
202:
203: if( availableWidth < 2 )
204: {
205: throw new IllegalArgumentException(
206: ResourceHelper.getResourceHelper().getMessage(
207: ResourceConstants.HELPFORMATTER_GUTTER_TOO_LONG ) );
208: }
209: }
210:
211:
215: public void print() throws IOException
216: {
217: printHeader();
218: printException();
219: printUsage();
220: printHelp();
221: printFooter();
222: m_out.flush();
223: }
224:
225:
229: public void printException() throws IOException
230: {
231: if( m_exception != null )
232: {
233: printDivider();
234: printWrapped( m_exception.getMessage() );
235: }
236: }
237:
238:
242: public void printHelp() throws IOException
243: {
244: printDivider();
245: final Option option;
246: if( ( m_exception != null ) && ( m_exception.getOption() != null ) )
247: {
248: option = m_exception.getOption();
249: }
250: else
251: {
252: option = m_group;
253: }
254:
255:
256: final List helpLines = option.helpLines( 0, m_displaySettings, m_comparator );
257:
258:
259: int usageWidth = 0;
260:
261: for( final Iterator i = helpLines.iterator(); i.hasNext();)
262: {
263: final HelpLine helpLine = (HelpLine) i.next();
264: final String usage = helpLine.usage( m_lineUsageSettings, m_comparator );
265: usageWidth = Math.max( usageWidth, usage.length() );
266: }
267:
268:
269:
270:
271:
272:
273: if( m_descriptionWidth > -1 )
274: {
275: int max = m_pageWidth - m_descriptionWidth;
276: if( usageWidth > max )
277: {
278: usageWidth = max;
279: }
280: }
281:
282:
283: final StringBuffer blankBuffer = new StringBuffer();
284:
285: for( int i = 0; i < usageWidth; i++ )
286: {
287: blankBuffer.append( ' ' );
288: }
289:
290:
291: final int descriptionWidth =
292: Math.max( 1, m_pageWidth - m_gutterCenter.length() - usageWidth );
293:
294:
295: for( final Iterator i = helpLines.iterator(); i.hasNext();)
296: {
297:
298: final HelpLine helpLine = (HelpLine) i.next();
299:
300:
301: final List descList = wrap( helpLine.getDescription(), descriptionWidth );
302: final Iterator descriptionIterator = descList.iterator();
303:
304:
305: printGutterLeft();
306: pad( helpLine.usage( m_lineUsageSettings, m_comparator ), usageWidth, m_out );
307: m_out.print( m_gutterCenter );
308: pad( (String) descriptionIterator.next(), descriptionWidth, m_out );
309: printGutterRight();
310: m_out.println();
311:
312:
313: while( descriptionIterator.hasNext() )
314: {
315: printGutterLeft();
316:
317:
318: m_out.print( blankBuffer );
319: m_out.print( m_gutterCenter );
320: pad( (String) descriptionIterator.next(), descriptionWidth, m_out );
321: printGutterRight();
322: m_out.println();
323: }
324: }
325: printDivider();
326: }
327:
328:
332: public void printUsage() throws IOException
333: {
334: printDivider();
335: final StringBuffer buffer = new StringBuffer( "Usage:\n" );
336: buffer.append( m_shellCommand ).append( ' ' );
337: String separator = getSeparator();
338: m_group.appendUsage( buffer, m_fullUsageSettings, m_comparator, separator );
339: printWrapped( buffer.toString() );
340: }
341:
342: private String getSeparator()
343: {
344: if( m_group.getMaximum() == 1 )
345: {
346: return " | ";
347: }
348: else
349: {
350: return " ";
351: }
352: }
353:
354:
358: public void printHeader() throws IOException
359: {
360: if( m_header != null )
361: {
362: printDivider();
363: printWrapped( m_header );
364: }
365: }
366:
367:
371: public void printFooter() throws IOException
372: {
373: if( m_footer != null )
374: {
375: printWrapped( m_footer );
376: printDivider();
377: }
378: }
379:
380:
385: protected void printWrapped( final String text ) throws IOException
386: {
387: for( final Iterator i = wrap( text, m_pageWidth ).iterator(); i.hasNext();)
388: {
389: printGutterLeft();
390: pad( (String) i.next(), m_pageWidth, m_out );
391: printGutterRight();
392: m_out.println();
393: }
394: }
395:
396:
399: public void printGutterLeft()
400: {
401: if( m_gutterLeft != null )
402: {
403: m_out.print( m_gutterLeft );
404: }
405: }
406:
407:
410: public void printGutterRight()
411: {
412: if( m_gutterRight != null )
413: {
414: m_out.print( m_gutterRight );
415: }
416: }
417:
418:
421: public void printDivider()
422: {
423: if( m_divider != null )
424: {
425: m_out.println( m_divider );
426: }
427: }
428:
429:
436: protected static void pad(
437: final String text, final int width, final Writer writer )
438: throws IOException
439: {
440: final int left;
441:
442:
443: if ( text == null )
444: {
445: left = 0;
446: }
447: else
448: {
449: writer.write( text );
450: left = text.length();
451: }
452:
453:
454: for( int i = left; i < width; ++i )
455: {
456: writer.write( ' ' );
457: }
458: }
459:
460:
467: protected static List wrap( final String text, final int width )
468: {
469:
470: if( width < 1 )
471: {
472: throw new IllegalArgumentException(
473: ResourceHelper.getResourceHelper().getMessage(
474: ResourceConstants.HELPFORMATTER_WIDTH_TOO_NARROW,
475: new Object[]{new Integer( width )} ) );
476: }
477:
478:
479: if( text == null )
480: {
481: return Collections.singletonList( "" );
482: }
483:
484: final List lines = new ArrayList();
485: final char[] chars = text.toCharArray();
486: int left = 0;
487:
488:
489: while( left < chars.length )
490: {
491:
492: int right = left;
493:
494:
495: while(
496: ( right < chars.length )
497: && ( chars[right] != '\n' )
498: && ( right < ( left + width + 1 ) ) )
499: {
500: right++;
501: }
502:
503:
504: if( ( right < chars.length ) && ( chars[right] == '\n' ) )
505: {
506:
507: final String line = new String( chars, left, right - left );
508: lines.add( line );
509:
510:
511: left = right + 1;
512:
513: if( left == chars.length )
514: {
515: lines.add( "" );
516: }
517:
518:
519: continue;
520: }
521:
522:
523: right = ( left + width ) - 1;
524:
525:
526: if( chars.length <= right )
527: {
528:
529: final String line = new String( chars, left, chars.length - left );
530: lines.add( line );
531:
532:
533: break;
534: }
535:
536:
537: while( ( right >= left ) && ( chars[right] != ' ' ) )
538: {
539: right--;
540: }
541:
542:
543: if( right >= left )
544: {
545:
546: final String line = new String( chars, left, right - left );
547: lines.add( line );
548:
549:
550: while( ( right < chars.length ) && ( chars[right] == ' ' ) )
551: {
552: right++;
553: }
554:
555: left = right;
556:
557:
558: continue;
559: }
560:
561:
562: right = Math.min( left + width, chars.length );
563:
564:
565: final String line = new String( chars, left, right - left );
566: lines.add( line );
567:
568:
569: while( ( right < chars.length ) && ( chars[right] == ' ' ) )
570: {
571: right++;
572: }
573:
574: left = right;
575: }
576:
577: return lines;
578: }
579:
580:
584: public void setComparator( Comparator comparator )
585: {
586: m_comparator = comparator;
587: }
588:
589:
596: public void setDisplaySettings( Set displaySettings )
597: {
598: m_displaySettings = displaySettings;
599: }
600:
601:
605: public void setDivider( String divider )
606: {
607: m_divider = divider;
608: }
609:
610:
614: public void setException( OptionException exception )
615: {
616: m_exception = exception;
617: }
618:
619:
623: public void setFooter( String footer )
624: {
625: m_footer = footer;
626: }
627:
628:
634: public void setFullUsageSettings( Set fullUsageSettings )
635: {
636: m_fullUsageSettings = fullUsageSettings;
637: }
638:
639:
643: public void setGroup( Group group )
644: {
645: m_group = group;
646: }
647:
648:
652: public void setHeader( String header )
653: {
654: m_header = header;
655: }
656:
657:
663: public void setLineUsageSettings( Set lineUsageSettings )
664: {
665: m_lineUsageSettings = lineUsageSettings;
666: }
667:
668:
672: public void setShellCommand( String shellCommand )
673: {
674: m_shellCommand = shellCommand;
675: }
676:
677:
681: public Comparator getComparator()
682: {
683: return m_comparator;
684: }
685:
686:
690: public Set getDisplaySettings()
691: {
692: return m_displaySettings;
693: }
694:
695:
699: public String getDivider()
700: {
701: return m_divider;
702: }
703:
704:
708: public OptionException getException()
709: {
710: return m_exception;
711: }
712:
713:
717: public String getFooter()
718: {
719: return m_footer;
720: }
721:
722:
726: public Set getFullUsageSettings()
727: {
728: return m_fullUsageSettings;
729: }
730:
731:
735: public Group getGroup()
736: {
737: return m_group;
738: }
739:
740:
744: public String getGutterCenter()
745: {
746: return m_gutterCenter;
747: }
748:
749:
753: public String getGutterLeft()
754: {
755: return m_gutterLeft;
756: }
757:
758:
762: public String getGutterRight()
763: {
764: return m_gutterRight;
765: }
766:
767:
771: public String getHeader()
772: {
773: return m_header;
774: }
775:
776:
780: public Set getLineUsageSettings()
781: {
782: return m_lineUsageSettings;
783: }
784:
785:
789: public int getPageWidth()
790: {
791: return m_pageWidth;
792: }
793:
794:
798: public String getShellCommand()
799: {
800: return m_shellCommand;
801: }
802:
803:
807: public void setPrintWriter( PrintWriter out )
808: {
809: m_out = out;
810: }
811:
812:
816: public PrintWriter getPrintWriter()
817: {
818: return m_out;
819: }
820: }