forked from scriptcs/scriptcs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHelpCommand.cs
More file actions
122 lines (102 loc) · 4.41 KB
/
HelpCommand.cs
File metadata and controls
122 lines (102 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System.Linq;
using System.Text;
using ScriptCs.Contracts;
namespace ScriptCs.ReplCommands
{
public class HelpCommand : IReplCommand
{
private readonly IConsole _console;
public HelpCommand(IConsole console)
{
Guard.AgainstNullArgument("console", console);
_console = console;
}
public string Description
{
get { return "Shows this help."; }
}
public string CommandName
{
get { return "help"; }
}
public object Execute(IRepl repl, object[] args)
{
Guard.AgainstNullArgument("repl", repl);
_console.WriteLine("\nThe following commands are available in the REPL:");
foreach (var command in repl.Commands.OrderBy(x => x.Key))
{
string key = string.Format(" :{0,-15} - ", command.Key);
// make sure we have a good width for formatting purposes
int descWidth = _console.Width - key.Length - 1;
if (descWidth > 25)
{
_console.WriteLine(string.Format("{0}{1,10}", key, WrapTextToColumn(command.Value.Description, descWidth, indentWidth: key.Length)));
}
else
{
// safe-guard: just in the case we have a really long Repl Command "key"
// and a really narrow console width don't wrap the description
// note: the extra newline if to at least make somewhat readable
_console.WriteLine(string.Format("{0}{1,10}\n", key, command.Value.Description));
}
}
_console.WriteLine(string.Empty);
return null;
}
/// <summary>
/// Word wrap text to specified column width.
/// </summary>
/// <param name="text">Unformatted text.</param>
/// <param name="columnWidth">Size of the column width.</param>
/// <param name="indentWidth">Indentation width when the text is wrap. The first line is not indented.</param>
/// <param name="initialWidth">First line indent width.</param>
/// <returns>Formatted text.</returns>
/// <remarks>In the future, I believe this method will be moved into some sort of formatting helper class.</remarks>
private string WrapTextToColumn(string text, int columnWidth, int indentWidth = 0, int initialWidth = 0)
{
// check the initial width
if ((initialWidth < 0) || (initialWidth > (indentWidth + columnWidth)))
{
throw new System.ArgumentOutOfRangeException("initialWidth");
}
// TODO: Add additional parameter error checking
StringBuilder paragraph = new StringBuilder(text.Trim());
// add the initial space to text
paragraph.Insert(0, " ", initialWidth);
if (paragraph.Length > (columnWidth))
{
int pos = columnWidth;
int backSearchLimit = initialWidth;
do
{
// find a whitespace we can wrap the description line
int savedPos = pos;
while (!char.IsWhiteSpace(paragraph[pos]))
{
pos--;
// guard against not finding a natural whitespace
// don't go below the spaces we create (indent)
if (pos < backSearchLimit)
{
pos = savedPos;
break;
}
}
if (char.IsWhiteSpace(paragraph[pos]))
{
paragraph.Remove(pos, 1); // remove the whitespace we found
}
// inject a newline
paragraph.Insert(pos, System.Environment.NewLine);
pos += System.Environment.NewLine.Length;
paragraph.Insert(pos, " ", indentWidth);
pos += indentWidth;
// prevent searching for whitespace to go below the spaces we put in
backSearchLimit = pos;
pos += columnWidth;
} while (pos < paragraph.Length);
}
return paragraph.ToString();
}
}
}