Skip to content

Commit 8f1a5c6

Browse files
committed
Give OmniSharp the ability to configure fallback analyzerconfigoptions
1 parent d638246 commit 8f1a5c6

File tree

3 files changed

+119
-1
lines changed

3 files changed

+119
-1
lines changed

src/Features/ExternalAccess/OmniSharp/Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
https://github.com/OmniSharp/omnisharp-roslyn
1111
</PackageDescription>
1212
</PropertyGroup>
13-
13+
1414
<ItemGroup>
1515
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CSharp" />
1616
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.UnitTests" />
1717
<!--
1818
⚠ ONLY OMNISHARP ASSEMBLIES MAY BE ADDED HERE ⚠
1919
-->
20+
<InternalsVisibleTo Include="OmniSharp.Host" Key="$(OmniSharpKey)" />
2021
<InternalsVisibleTo Include="OmniSharp.Roslyn" Key="$(OmniSharpKey)" />
2122
<InternalsVisibleTo Include="OmniSharp.Roslyn.CSharp" Key="$(OmniSharpKey)" />
2223
<InternalsVisibleTo Include="OmniSharp.Roslyn.CSharp.Tests" Key="$(OmniSharpKey)" />
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ImplementType;
6+
7+
namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options;
8+
9+
internal sealed record class OmniSharpEditorConfigOptions
10+
{
11+
public OmniSharpLineFormattingOptions LineFormattingOptions { get; init; } = new();
12+
public OmniSharpImplementTypeOptions ImplementTypeOptions { get; init; } = new();
13+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Immutable;
7+
using Microsoft.CodeAnalysis.Diagnostics;
8+
using Microsoft.CodeAnalysis.Formatting;
9+
using Microsoft.CodeAnalysis.ErrorReporting;
10+
using Microsoft.CodeAnalysis.Options;
11+
using Roslyn.Utilities;
12+
using Microsoft.CodeAnalysis.ImplementType;
13+
14+
namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options;
15+
16+
using Workspace = CodeAnalysis.Workspace;
17+
18+
internal static class OmniSharpSolutionAnalyzerConfigOptionsUpdater
19+
{
20+
internal static void UpdateOptions(Workspace workspace, OmniSharpEditorConfigOptions editorConfigOptions)
21+
{
22+
try
23+
{
24+
workspace.SetCurrentSolution(UpdateOptions, changeKind: WorkspaceChangeKind.SolutionChanged);
25+
26+
Solution UpdateOptions(Solution oldSolution)
27+
{
28+
var oldFallbackOptions = oldSolution.FallbackAnalyzerOptions;
29+
oldFallbackOptions.TryGetValue(LanguageNames.CSharp, out var csharpFallbackOptions);
30+
31+
var changedOptions = DetermineChangedOptions(csharpFallbackOptions, editorConfigOptions);
32+
if (changedOptions.IsEmpty)
33+
{
34+
return oldSolution;
35+
}
36+
37+
var builder = ImmutableDictionary.CreateBuilder<string, string>(AnalyzerConfigOptions.KeyComparer);
38+
if (csharpFallbackOptions is not null)
39+
{
40+
// copy existing option values:
41+
foreach (var oldKey in csharpFallbackOptions.Keys)
42+
{
43+
if (csharpFallbackOptions.TryGetValue(oldKey, out var oldValue))
44+
{
45+
builder.Add(oldKey, oldValue);
46+
}
47+
}
48+
}
49+
50+
// update changed values:
51+
foreach (var (key, value) in changedOptions)
52+
{
53+
builder[key] = value;
54+
}
55+
56+
var newFallbackOptions = oldFallbackOptions.SetItem(
57+
LanguageNames.CSharp,
58+
StructuredAnalyzerConfigOptions.Create(new DictionaryAnalyzerConfigOptions(builder.ToImmutable())));
59+
60+
return oldSolution.WithFallbackAnalyzerOptions(newFallbackOptions);
61+
}
62+
}
63+
catch (Exception e) when (FatalError.ReportAndPropagate(e, ErrorSeverity.Diagnostic))
64+
{
65+
throw ExceptionUtilities.Unreachable();
66+
}
67+
}
68+
69+
private static ImmutableDictionary<string, string> DetermineChangedOptions(
70+
StructuredAnalyzerConfigOptions? csharpFallbackOptions,
71+
OmniSharpEditorConfigOptions editorConfigOptions)
72+
{
73+
var builder = ImmutableDictionary.CreateBuilder<string, string>();
74+
75+
AddOptionIfChanged(FormattingOptions2.UseTabs, csharpFallbackOptions, editorConfigOptions.LineFormattingOptions.UseTabs, builder);
76+
AddOptionIfChanged(FormattingOptions2.UseTabs, csharpFallbackOptions, editorConfigOptions.LineFormattingOptions.UseTabs, builder);
77+
AddOptionIfChanged(FormattingOptions2.TabSize, csharpFallbackOptions, editorConfigOptions.LineFormattingOptions.TabSize, builder);
78+
AddOptionIfChanged(FormattingOptions2.IndentationSize, csharpFallbackOptions, editorConfigOptions.LineFormattingOptions.IndentationSize, builder);
79+
AddOptionIfChanged(FormattingOptions2.NewLine, csharpFallbackOptions, editorConfigOptions.LineFormattingOptions.NewLine, builder);
80+
81+
AddOptionIfChanged(ImplementTypeOptionsStorage.InsertionBehavior, csharpFallbackOptions, (ImplementTypeInsertionBehavior)editorConfigOptions.ImplementTypeOptions.InsertionBehavior, builder);
82+
AddOptionIfChanged(ImplementTypeOptionsStorage.PropertyGenerationBehavior, csharpFallbackOptions, (ImplementTypePropertyGenerationBehavior)editorConfigOptions.ImplementTypeOptions.PropertyGenerationBehavior, builder);
83+
84+
return builder.ToImmutable();
85+
86+
static void AddOptionIfChanged<T>(
87+
PerLanguageOption2<T> option,
88+
StructuredAnalyzerConfigOptions? analyzerConfigOptions,
89+
T value,
90+
ImmutableDictionary<string, string>.Builder builder)
91+
{
92+
var configName = option.Definition.ConfigName;
93+
var configValue = option.Definition.Serializer.Serialize(value);
94+
95+
if (analyzerConfigOptions?.TryGetValue(configName, out var existingValue) == true &&
96+
existingValue == configValue)
97+
{
98+
return;
99+
}
100+
101+
builder.Add(configName, configValue);
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)