1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using Args . Help ;
6+ using Args . Help . Formatters ;
7+
8+ public class ConsoleHelpFormatter : IHelpFormatter
9+ {
10+ protected int BufferWidth { get ; set ; }
11+ protected TextWriter Output { get ; set ; }
12+ protected int CommandSamplePadding { get ; set ; }
13+ protected int ArgumentDescriptionPadding { get ; set ; }
14+
15+ public ConsoleHelpFormatter ( )
16+ : this ( Console . BufferWidth , 1 , 5 )
17+ {
18+ }
19+
20+ public ConsoleHelpFormatter ( int bufferWidth , int commandSamplePadding , int argumentDescriptionPadding )
21+ {
22+ BufferWidth = bufferWidth ;
23+ CommandSamplePadding = commandSamplePadding ;
24+ ArgumentDescriptionPadding = argumentDescriptionPadding ;
25+ }
26+
27+ public virtual void WriteHelp ( ModelHelp modelHelp , TextWriter writer )
28+ {
29+ Output = writer ;
30+
31+ if ( string . IsNullOrEmpty ( modelHelp . HelpText ) == false )
32+ {
33+ WriteJustifiedItem ( string . Empty , modelHelp . HelpText , 0 ) ;
34+ }
35+
36+ WriteUsage ( modelHelp , writer ) ;
37+
38+ Output . WriteLine ( ) ;
39+
40+ WriteArgumentDescriptions ( modelHelp ) ;
41+ }
42+
43+ private void WriteArgumentDescriptions ( ModelHelp modelHelp )
44+ {
45+ var helpMembers = GetHelpMembers ( modelHelp ) ;
46+
47+ var items = helpMembers
48+ . Where ( m => string . IsNullOrEmpty ( m . HelpText ) == false )
49+ . ToDictionary ( ks => ks . OrdinalIndex . HasValue ? ks . Name : GetFullSwitchString ( modelHelp . SwitchDelimiter , ks . Switches ) , es => es . HelpText ) ;
50+
51+ WriteJustifiedOutput ( items , ArgumentDescriptionPadding ) ;
52+ }
53+
54+ protected virtual string GetFullSwitchString ( string switchDelimiter , IEnumerable < string > switches )
55+ {
56+ var values = string . Join ( "|" , switches . Select ( s => switchDelimiter + s ) . ToArray ( ) ) ;
57+
58+ return "[" + values + "]" ;
59+ }
60+
61+ protected virtual void WriteJustifiedOutput ( IDictionary < string , string > lines , int padding )
62+ {
63+ if ( lines . Any ( ) )
64+ {
65+ var totalPadding = lines . Max ( l => l . Key . Length ) + padding ;
66+
67+ foreach ( var line in lines )
68+ {
69+ WriteJustifiedItem ( line . Key , line . Value , totalPadding ) ;
70+ }
71+
72+ Output . WriteLine ( ) ;
73+ }
74+ }
75+
76+ protected virtual void WriteJustifiedItem ( string leftColumnText , string rightColumnText , int totalPadding )
77+ {
78+ rightColumnText = rightColumnText ?? string . Empty ;
79+
80+ Output . Write ( leftColumnText ) ;
81+ Output . Write ( new string ( ' ' , totalPadding - leftColumnText . Length ) ) ;
82+
83+ var maxRightColumnTextLength = BufferWidth - totalPadding - 1 ;
84+
85+ var newLinePadding = new string ( ' ' , totalPadding ) ;
86+
87+ var firstPass = true ;
88+
89+ while ( string . IsNullOrEmpty ( rightColumnText . Trim ( ) ) == false )
90+ {
91+ string part ;
92+ if ( rightColumnText . Length < maxRightColumnTextLength )
93+ part = rightColumnText ;
94+ else
95+ {
96+ part = rightColumnText . Substring ( 0 , maxRightColumnTextLength ) ;
97+
98+ int lastSpaceIndex = - 1 ;
99+
100+ for ( var i = part . Length - 1 ; i >= 0 ; i -- )
101+ {
102+ if ( char . IsWhiteSpace ( part [ i ] ) )
103+ {
104+ lastSpaceIndex = i ;
105+ break ;
106+ }
107+ }
108+
109+ var partLength = lastSpaceIndex > 0 ? lastSpaceIndex + 1 : maxRightColumnTextLength ;
110+
111+ partLength = Math . Min ( partLength , part . Length ) ;
112+
113+ part = part . Substring ( 0 , partLength ) ;
114+ }
115+
116+ //padding is already done if this is the first pass
117+ if ( firstPass == false ) Output . Write ( newLinePadding ) ;
118+
119+ Output . WriteLine ( part ) ;
120+
121+ rightColumnText = rightColumnText . Substring ( part . Length ) ;
122+
123+ firstPass = false ;
124+ }
125+
126+ //while loop was skipped, need new line
127+ if ( firstPass == true )
128+ Output . WriteLine ( ) ;
129+ }
130+
131+ protected virtual void WriteUsage ( ModelHelp modelHelp , TextWriter writer )
132+ {
133+ var helpMembers = GetHelpMembers ( modelHelp ) ;
134+ var values = helpMembers . Select ( m => m . OrdinalIndex . HasValue ? m . Name : GetFullSwitchString ( modelHelp . SwitchDelimiter , m . Switches ) ) ;
135+
136+ //TODO: Figure out actual command name?
137+ var dictionary = new Dictionary < string , string >
138+ {
139+ { "<command>" , string . Join ( " " , values . ToArray ( ) ) }
140+ } ;
141+
142+ WriteJustifiedOutput ( dictionary , CommandSamplePadding ) ;
143+ }
144+
145+ private static IEnumerable < MemberHelp > GetHelpMembers ( ModelHelp modelHelp )
146+ {
147+ var ordinals = modelHelp . Members
148+ . Where ( m => m . OrdinalIndex . HasValue )
149+ . OrderBy ( m => m . OrdinalIndex . Value ) ;
150+
151+ var switches = modelHelp . Members
152+ . Where ( m => m . OrdinalIndex . HasValue == false )
153+ . OrderBy ( m => m . Name ) ;
154+
155+ var memberHelps = ordinals . Concat ( switches ) ;
156+ return memberHelps ;
157+ }
158+ }
0 commit comments