Skip to content
This repository was archived by the owner on Jul 12, 2022. It is now read-only.

Commit 311624b

Browse files
committed
Factored out command line parsing
1 parent 5d3ce5a commit 311624b

File tree

3 files changed

+250
-177
lines changed

3 files changed

+250
-177
lines changed

src/CodeFormatter/CodeFormatter.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<Reference Include="System.Xml" />
9999
</ItemGroup>
100100
<ItemGroup>
101+
<Compile Include="CommandLineParser.cs" />
101102
<Compile Include="Program.cs" />
102103
<Compile Include="Properties\AssemblyInfo.cs" />
103104
</ItemGroup>
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.DotNet.CodeFormatting;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Collections.Immutable;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace CodeFormatter
12+
{
13+
public enum Operation
14+
{
15+
Format,
16+
ListRules,
17+
}
18+
19+
public sealed class CommandLineOptions
20+
{
21+
public static readonly CommandLineOptions ListRules = new CommandLineOptions(
22+
Operation.ListRules,
23+
ImmutableArray<string[]>.Empty,
24+
ImmutableArray<string>.Empty,
25+
ImmutableDictionary<string, bool>.Empty,
26+
ImmutableArray<string>.Empty,
27+
ImmutableArray<string>.Empty,
28+
null,
29+
allowTables: false,
30+
verbose: false);
31+
32+
public readonly Operation Operation;
33+
public readonly ImmutableArray<string[]> PreprocessorConfigurations;
34+
public readonly ImmutableArray<string> CopyrightHeader;
35+
public readonly ImmutableDictionary<string, bool> RuleMap;
36+
public readonly ImmutableArray<string> FormatTargets;
37+
public readonly ImmutableArray<string> FileNames;
38+
public readonly string Language;
39+
public readonly bool AllowTables;
40+
public readonly bool Verbose;
41+
42+
public CommandLineOptions(
43+
Operation operation,
44+
ImmutableArray<string[]> preprocessorConfigurations,
45+
ImmutableArray<string> copyrightHeader,
46+
ImmutableDictionary<string, bool> ruleMap,
47+
ImmutableArray<string> formatTargets,
48+
ImmutableArray<string> fileNames,
49+
string language,
50+
bool allowTables,
51+
bool verbose)
52+
{
53+
Operation = operation;
54+
PreprocessorConfigurations = preprocessorConfigurations;
55+
CopyrightHeader = copyrightHeader;
56+
RuleMap = ruleMap;
57+
FileNames = fileNames;
58+
FormatTargets = formatTargets;
59+
Language = language;
60+
AllowTables = allowTables;
61+
Verbose = verbose;
62+
}
63+
}
64+
65+
public static class CommandLineParser
66+
{
67+
private const string FileSwitch = "/file:";
68+
private const string ConfigSwitch = "/c:";
69+
private const string CopyrightSwitch = "/copyright:";
70+
private const string LanguageSwitch = "/lang:";
71+
private const string RuleEnabledSwitch1 = "/rule+:";
72+
private const string RuleEnabledSwitch2 = "/rule:";
73+
private const string RuleDisabledSwitch = "/rule-:";
74+
75+
public static void PrintUsage()
76+
{
77+
Console.WriteLine(
78+
@"CodeFormatter [/file:<filename>] [/lang:<language>] [/c:<config>[,<config>...]>]
79+
[/copyright:<file> | /nocopyright] [/tables] [/nounicode]
80+
[/rule(+|-):rule1,rule2,...] [/verbose]
81+
<project, solution or response file>
82+
83+
/file - Only apply changes to files with specified name
84+
/lang - Specifies the language to use when a responsefile is
85+
specified. i.e. 'C#', 'Visual Basic', ... (default: 'C#')
86+
/c - Additional preprocessor configurations the formatter
87+
should run under.
88+
/copyright - Specifies file containing copyright header.
89+
Use ConvertTests to convert MSTest tests to xUnit.
90+
/nocopyright - Do not update the copyright message.
91+
/tables - Let tables opt out of formatting by defining
92+
DOTNET_FORMATTER
93+
/nounicode - Do not convert unicode strings to escape sequences
94+
/rule(+|-) - Enable (default) or disable the specified rule
95+
/rules - List the available rules
96+
/verbose - Verbose output
97+
");
98+
}
99+
100+
public static bool TryParse(string[] args, out CommandLineOptions options)
101+
{
102+
if (args.Length < 1)
103+
{
104+
PrintUsage();
105+
options = null;
106+
return false;
107+
}
108+
109+
var comparer = StringComparer.OrdinalIgnoreCase;
110+
var formatTargets = new List<string>();
111+
var fileNames = new List<string>();
112+
var configBuilder = ImmutableArray.CreateBuilder<string[]>();
113+
var copyrightHeader = FormattingDefaults.DefaultCopyrightHeader;
114+
var ruleMap = ImmutableDictionary<string, bool>.Empty;
115+
var language = LanguageNames.CSharp;
116+
var allowTables = false;
117+
var verbose = false;
118+
119+
for (int i = 1; i < args.Length; i++)
120+
{
121+
string arg = args[i];
122+
if (arg.StartsWith(ConfigSwitch, StringComparison.OrdinalIgnoreCase))
123+
{
124+
var all = arg.Substring(ConfigSwitch.Length);
125+
var configs = all.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
126+
configBuilder.Add(configs);
127+
}
128+
else if (arg.StartsWith(CopyrightSwitch, StringComparison.OrdinalIgnoreCase))
129+
{
130+
var fileName = arg.Substring(CopyrightSwitch.Length);
131+
try
132+
{
133+
copyrightHeader = ImmutableArray.CreateRange(File.ReadAllLines(fileName));
134+
}
135+
catch (Exception ex)
136+
{
137+
Console.Error.WriteLine("Could not read {0}", fileName);
138+
Console.Error.WriteLine(ex.Message);
139+
options = null;
140+
return false;
141+
}
142+
}
143+
else if (arg.StartsWith(LanguageSwitch, StringComparison.OrdinalIgnoreCase))
144+
{
145+
language = arg.Substring(LanguageSwitch.Length);
146+
}
147+
else if (comparer.Equals(arg, "/nocopyright"))
148+
{
149+
ruleMap = ruleMap.SetItem(FormattingDefaults.CopyrightRuleName, false);
150+
}
151+
else if (comparer.Equals(arg, "/nounicode"))
152+
{
153+
ruleMap = ruleMap.SetItem(FormattingDefaults.UnicodeLiteralsRuleName, false);
154+
}
155+
else if (comparer.Equals(arg, "/verbose"))
156+
{
157+
verbose = true;
158+
}
159+
else if (comparer.Equals(arg, FileSwitch))
160+
{
161+
fileNames.Add(arg.Substring(FileSwitch.Length));
162+
}
163+
else if (comparer.Equals(arg, RuleEnabledSwitch1))
164+
{
165+
UpdateRuleMap(ref ruleMap, arg.Substring(RuleEnabledSwitch1.Length), enabled: true);
166+
}
167+
else if (comparer.Equals(arg, RuleEnabledSwitch2))
168+
{
169+
UpdateRuleMap(ref ruleMap, arg.Substring(RuleEnabledSwitch2.Length), enabled: true);
170+
}
171+
else if (comparer.Equals(arg, RuleDisabledSwitch))
172+
{
173+
UpdateRuleMap(ref ruleMap, arg.Substring(RuleDisabledSwitch.Length), enabled: false);
174+
}
175+
else if (comparer.Equals(arg, "/tables"))
176+
{
177+
allowTables = true;
178+
}
179+
else if (comparer.Equals(arg, "/rules"))
180+
{
181+
options = CommandLineOptions.ListRules;
182+
return true;
183+
}
184+
else
185+
{
186+
formatTargets.Add(arg);
187+
}
188+
}
189+
190+
options = new CommandLineOptions(
191+
Operation.Format,
192+
configBuilder.ToImmutableArray(),
193+
copyrightHeader,
194+
ruleMap,
195+
formatTargets.ToImmutableArray(),
196+
fileNames.ToImmutableArray(),
197+
language,
198+
allowTables,
199+
verbose);
200+
return true;
201+
}
202+
203+
private static void UpdateRuleMap(ref ImmutableDictionary<string, bool> ruleMap, string data, bool enabled)
204+
{
205+
foreach (var current in data.Split(','))
206+
{
207+
ruleMap = ruleMap.SetItem(current, enabled);
208+
}
209+
}
210+
}
211+
}

0 commit comments

Comments
 (0)