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

Commit c3026e8

Browse files
committed
Add method to exempt code from formatting
This change adds the preprocessor symbol DOTNET_FORMATTER to every project in the formatted Solution. This allows developers to exempt code from formatting by surrounding blocks with ``` csharp #if !DOTNET_FORMATTER ``` This should only be done on the rare occasions where insignificant white space serves to make the code significantly more readable. For example in large unicode tables. In general this feature should be avoided. closes #37
1 parent 84f4847 commit c3026e8

File tree

3 files changed

+111
-26
lines changed

3 files changed

+111
-26
lines changed

src/Microsoft.DotNet.CodeFormatting.Tests/Rules/CombinationTest.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,81 @@ internal void M()
146146
s_formattingEngine.PreprocessorConfigurations = ImmutableArray.CreateRange(new[] { new[] { "DOG" } });
147147
Verify(text, expected, runFormatter: false);
148148
}
149+
150+
[Fact]
151+
public void TableCode()
152+
{
153+
var text = @"
154+
class C
155+
{
156+
void G() {
157+
158+
}
159+
160+
#if !DOTNET_FORMATTER
161+
void M() {
162+
}
163+
#endif
164+
}";
165+
166+
var expected = @"
167+
// header
168+
169+
internal class C
170+
{
171+
private void G()
172+
{
173+
}
174+
175+
#if !DOTNET_FORMATTER
176+
void M() {
177+
}
178+
#endif
179+
}";
180+
181+
Verify(text, expected, runFormatter: false);
182+
}
183+
184+
/// <summary>
185+
/// Make sure the code which deals with additional configurations respects the
186+
/// table exception.
187+
/// </summary>
188+
[Fact]
189+
public void TableCodeAndAdditionalConfiguration()
190+
{
191+
var text = @"
192+
class C
193+
{
194+
#if TEST
195+
void G(){
196+
}
197+
#endif
198+
199+
#if !DOTNET_FORMATTER
200+
void M() {
201+
}
202+
#endif
203+
}";
204+
205+
var expected = @"
206+
// header
207+
208+
internal class C
209+
{
210+
#if TEST
211+
void G()
212+
{
213+
}
214+
#endif
215+
216+
#if !DOTNET_FORMATTER
217+
void M() {
218+
}
219+
#endif
220+
}";
221+
222+
s_formattingEngine.PreprocessorConfigurations = ImmutableArray.CreateRange(new[] { new[] { "TEST" } });
223+
Verify(text, expected, runFormatter: false);
224+
}
149225
}
150226
}

src/Microsoft.DotNet.CodeFormatting/FormattingEngineImplementation.cs

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414

1515
using Microsoft.CodeAnalysis;
1616
using Microsoft.CodeAnalysis.Text;
17+
using Microsoft.CodeAnalysis.CSharp;
1718

1819
namespace Microsoft.DotNet.CodeFormatting
1920
{
2021
[Export(typeof(IFormattingEngine))]
2122
internal sealed class FormattingEngineImplementation : IFormattingEngine
2223
{
24+
internal const string TablePreprocessorSymbolName = "DOTNET_FORMATTER";
25+
2326
private readonly Options _options;
2427
private readonly IEnumerable<IFormattingFilter> _filters;
2528
private readonly IEnumerable<ISyntaxFormattingRule> _syntaxRules;
@@ -88,43 +91,44 @@ private async Task FormatAsync(Workspace workspace, IReadOnlyList<DocumentId> do
8891

8992
watch.Stop();
9093

91-
await SaveChanges(solution, originalSolution, cancellationToken);
94+
if (!workspace.TryApplyChanges(solution))
95+
{
96+
FormatLogger.WriteErrorLine("Unable to save changes to disk");
97+
}
98+
9299
FormatLogger.WriteLine("Total time {0}", watch.Elapsed);
93100
}
94101

102+
internal Solution AddTablePreprocessorSymbol(Solution solution)
103+
{
104+
var projectIds = solution.ProjectIds;
105+
foreach (var projectId in projectIds)
106+
{
107+
var project = solution.GetProject(projectId);
108+
var parseOptions = project.ParseOptions as CSharpParseOptions;
109+
if (parseOptions != null)
110+
{
111+
var list = new List<string>();
112+
list.AddRange(parseOptions.PreprocessorSymbolNames);
113+
list.Add(TablePreprocessorSymbolName);
114+
parseOptions = parseOptions.WithPreprocessorSymbols(list);
115+
solution = project.WithParseOptions(parseOptions).Solution;
116+
}
117+
}
118+
119+
return solution;
120+
}
121+
95122
internal async Task<Solution> FormatCoreAsync(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
96123
{
97124
var solution = originalSolution;
125+
solution = AddTablePreprocessorSymbol(originalSolution);
98126
solution = await RunSyntaxPass(solution, documentIds, cancellationToken);
99127
solution = await RunLocalSemanticPass(solution, documentIds, cancellationToken);
100128
solution = await RunGlobalSemanticPass(solution, documentIds, cancellationToken);
101129
return solution;
102130
}
103131

104-
private async Task SaveChanges(Solution solution, Solution originalSolution, CancellationToken cancellationToken)
105-
{
106-
foreach (var projectChange in solution.GetChanges(originalSolution).GetProjectChanges())
107-
{
108-
foreach (var documentId in projectChange.GetChangedDocuments())
109-
{
110-
var document = solution.GetDocument(documentId);
111-
var sourceText = await document.GetTextAsync(cancellationToken);
112-
using (var file = File.Open(document.FilePath, FileMode.Truncate, FileAccess.Write))
113-
{
114-
// The encoding of the file can change during the rewrite. Make sure to save with the
115-
// original encoding
116-
var originalDocument = originalSolution.GetDocument(documentId);
117-
var originalSourceText = await originalDocument.GetTextAsync(cancellationToken);
118-
119-
using (var writer = new StreamWriter(file, originalSourceText.Encoding))
120-
{
121-
sourceText.Write(writer, cancellationToken);
122-
}
123-
}
124-
}
125-
}
126-
}
127-
128132
private bool ShouldBeProcessed(Document document)
129133
{
130134
foreach (var filter in _filters)

src/Microsoft.DotNet.CodeFormatting/Rules/IsFormattedFormattingRule.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.CodeAnalysis.CSharp;
1212
using System.Linq;
1313
using Microsoft.CodeAnalysis.CSharp.Syntax;
14+
using System.Collections.Generic;
1415

1516
namespace Microsoft.DotNet.CodeFormatting.Rules
1617
{
@@ -35,7 +36,11 @@ public async Task<SyntaxNode> ProcessAsync(Document document, SyntaxNode syntaxN
3536
var parseOptions = (CSharpParseOptions)document.Project.ParseOptions;
3637
foreach (var configuration in _options.PreprocessorConfigurations)
3738
{
38-
var newParseOptions = parseOptions.WithPreprocessorSymbols(configuration);
39+
var list = new List<string>(configuration.Length + 1);
40+
list.AddRange(configuration);
41+
list.Add(FormattingEngineImplementation.TablePreprocessorSymbolName);
42+
43+
var newParseOptions = parseOptions.WithPreprocessorSymbols(list);
3944
document = project.WithParseOptions(newParseOptions).GetDocument(document.Id);
4045
document = await Formatter.FormatAsync(document, cancellationToken: cancellationToken);
4146
}

0 commit comments

Comments
 (0)