11using System . Linq ;
2+ using System . Text ;
23using ScriptCs . Contracts ;
34
45namespace ScriptCs . ReplCommands
@@ -28,13 +29,94 @@ public object Execute(IRepl repl, object[] args)
2829 {
2930 Guard . AgainstNullArgument ( "repl" , repl ) ;
3031
31- _console . WriteLine ( "The following commands are available in the REPL:" ) ;
32+ _console . WriteLine ( "\n The following commands are available in the REPL:" ) ;
3233 foreach ( var command in repl . Commands . OrderBy ( x => x . Key ) )
3334 {
34- _console . WriteLine ( string . Format ( ":{0,-15}{1,10}" , command . Key , command . Value . Description ) ) ;
35+ string key = string . Format ( " :{0,-15} - " , command . Key ) ;
36+
37+ // make sure we have a good width for formatting purposes
38+ int descWidth = _console . Width - key . Length - 1 ;
39+ if ( descWidth > 25 )
40+ {
41+ _console . WriteLine ( string . Format ( "{0}{1,10}" , key , WrapTextToColumn ( command . Value . Description , descWidth , indentWidth : key . Length ) ) ) ;
42+ }
43+ else
44+ {
45+ // safe-guard: just in the case we have a really long Repl Command "key"
46+ // and a really narrow console width don't wrap the description
47+ // note: the extra newline if to at least make somewhat readable
48+ _console . WriteLine ( string . Format ( "{0}{1,10}\n " , key , command . Value . Description ) ) ;
49+ }
3550 }
51+ _console . WriteLine ( string . Empty ) ;
3652
3753 return null ;
3854 }
55+
56+ /// <summary>
57+ /// Word wrap text to specified column width.
58+ /// </summary>
59+ /// <param name="text">Unformatted text.</param>
60+ /// <param name="columnWidth">Size of the column width.</param>
61+ /// <param name="indentWidth">Indentation width when the text is wrap. The first line is not indented.</param>
62+ /// <param name="initialWidth">First line indent width.</param>
63+ /// <returns>Formatted text.</returns>
64+ /// <remarks>In the future, I believe this method will be moved into some sort of formatting helper class.</remarks>
65+ private string WrapTextToColumn ( string text , int columnWidth , int indentWidth = 0 , int initialWidth = 0 )
66+ {
67+ // check the initial width
68+ if ( ( initialWidth < 0 ) || ( initialWidth > ( indentWidth + columnWidth ) ) )
69+ {
70+ throw new System . ArgumentOutOfRangeException ( "initialWidth" ) ;
71+ }
72+
73+ // TODO: Add additional parameter error checking
74+
75+ StringBuilder paragraph = new StringBuilder ( text . Trim ( ) ) ;
76+
77+ // add the initial space to text
78+ paragraph . Insert ( 0 , " " , initialWidth ) ;
79+
80+ if ( paragraph . Length > ( columnWidth ) )
81+ {
82+ int pos = columnWidth ;
83+ int backSearchLimit = initialWidth ;
84+ do
85+ {
86+ // find a whitespace we can wrap the description line
87+ int savedPos = pos ;
88+ while ( ! char . IsWhiteSpace ( paragraph [ pos ] ) )
89+ {
90+ pos -- ;
91+
92+ // guard against not finding a natural whitespace
93+ // don't go below the spaces we create (indent)
94+ if ( pos < backSearchLimit )
95+ {
96+ pos = savedPos ;
97+ break ;
98+ }
99+ }
100+
101+ if ( char . IsWhiteSpace ( paragraph [ pos ] ) )
102+ {
103+ paragraph . Remove ( pos , 1 ) ; // remove the whitespace we found
104+ }
105+ // inject a newline
106+ paragraph . Insert ( pos , System . Environment . NewLine ) ;
107+ pos += System . Environment . NewLine . Length ;
108+ paragraph . Insert ( pos , " " , indentWidth ) ;
109+ pos += indentWidth ;
110+
111+ // prevent searching for whitespace to go below the spaces we put in
112+ backSearchLimit = pos ;
113+
114+ pos += columnWidth ;
115+ } while ( pos < paragraph . Length ) ;
116+
117+ }
118+
119+ return paragraph . ToString ( ) ;
120+ }
39121 }
40122}
0 commit comments