diff --git a/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider.cs b/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider.cs
index 00b10c770e5de1a3cd13c0e9b75232186e61b40a..ee13dcf005fa7606523a70640d9dd432a9c90582 100644
--- a/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider.cs
+++ b/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProvider.cs
@@ -1,11 +1,10 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
+using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorLogger;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
@@ -17,6 +16,8 @@ namespace Microsoft.CodeAnalysis.Editor.Options
// isn't yet available outside of Visual Studio.
internal sealed partial class EditorConfigDocumentOptionsProvider : IDocumentOptionsProvider
{
+ private const int EventDelayInMillisecond = 50;
+
private readonly object _gate = new object();
///
@@ -25,14 +26,21 @@ internal sealed partial class EditorConfigDocumentOptionsProvider : IDocumentOpt
///
private readonly Dictionary> _openDocumentContexts = new Dictionary>();
+ private readonly Workspace _workspace;
private readonly ICodingConventionsManager _codingConventionsManager;
private readonly IErrorLoggerService _errorLogger;
- internal EditorConfigDocumentOptionsProvider(Workspace workspace)
+ private ResettableDelay _resettableDelay;
+
+ internal EditorConfigDocumentOptionsProvider(Workspace workspace, ICodingConventionsManager codingConventionsManager)
{
- _codingConventionsManager = CodingConventionsManagerFactory.CreateCodingConventionsManager();
+ _workspace = workspace;
+
+ _codingConventionsManager = codingConventionsManager;
_errorLogger = workspace.Services.GetService();
+ _resettableDelay = ResettableDelay.CompletedDelay;
+
workspace.DocumentOpened += Workspace_DocumentOpened;
workspace.DocumentClosed += Workspace_DocumentClosed;
}
@@ -47,7 +55,13 @@ private void Workspace_DocumentClosed(object sender, DocumentEventArgs e)
// Ensure we dispose the context, which we'll do asynchronously
contextTask.ContinueWith(
- t => t.Result.Dispose(),
+ t =>
+ {
+ var context = t.Result;
+
+ context.CodingConventionsChangedAsync -= OnCodingConventionsChangedAsync;
+ context.Dispose();
+ },
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
@@ -59,7 +73,14 @@ private void Workspace_DocumentOpened(object sender, DocumentEventArgs e)
{
lock (_gate)
{
- _openDocumentContexts.Add(e.Document.Id, Task.Run(() => GetConventionContextAsync(e.Document.FilePath, CancellationToken.None)));
+ var contextTask = Task.Run(async () =>
+ {
+ var context = await GetConventionContextAsync(e.Document.FilePath, CancellationToken.None).ConfigureAwait(false);
+ context.CodingConventionsChangedAsync += OnCodingConventionsChangedAsync;
+ return context;
+ });
+
+ _openDocumentContexts.Add(e.Document.Id, contextTask);
}
}
@@ -122,5 +143,39 @@ private Task GetConventionContextAsync(string path, Ca
() => _codingConventionsManager.GetConventionContextAsync(path, cancellationToken),
defaultValue: EmptyCodingConventionContext.Instance);
}
+
+ private Task OnCodingConventionsChangedAsync(object sender, CodingConventionsChangedEventArgs arg)
+ {
+ // this is a temporary workaround. once we finish the work to put editorconfig file as a part of roslyn solution snapshot,
+ // that system will automatically pick up option changes and update snapshot. and it will work regardless
+ // whether a file is opened in editor or not.
+ //
+ // but until then, we need to explicitly touch workspace to update snapshot. and
+ // only works for open files. it is not easy to track option changes for closed files with current model.
+ // related tracking issue - https://github.com/dotnet/roslyn/issues/26250
+
+ lock (_gate)
+ {
+ if (!_resettableDelay.Task.IsCompleted)
+ {
+ _resettableDelay.Reset();
+ }
+ else
+ {
+ // since this event gets raised for all documents that are affected by 1 editconfig file,
+ // and since for now we make that event as whole solution changed event, we don't need to update
+ // snapshot for each events. aggregate all events to 1.
+ var delay = new ResettableDelay(EventDelayInMillisecond);
+ delay.Task.ContinueWith(_ => _workspace.OnOptionChanged(),
+ CancellationToken.None,
+ TaskContinuationOptions.ExecuteSynchronously,
+ TaskScheduler.Default);
+
+ _resettableDelay = delay;
+ }
+ }
+
+ return Task.CompletedTask;
+ }
}
}
diff --git a/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs b/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
index 32b650532d41469fa28fe94e97883e076c2bc012..7ae91f27def9371508495ead6c658a520e98ea79 100644
--- a/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
+++ b/src/EditorFeatures/Core.Wpf/Options/EditorConfigDocumentOptionsProviderFactory.cs
@@ -3,15 +3,25 @@
using System;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Options;
+using Microsoft.VisualStudio.CodingConventions;
namespace Microsoft.CodeAnalysis.Editor.Options
{
[Export(typeof(IDocumentOptionsProviderFactory))]
class EditorConfigDocumentOptionsProviderFactory : IDocumentOptionsProviderFactory
{
+ private readonly ICodingConventionsManager _codingConventionsManager;
+
+ [ImportingConstructor]
+ [Obsolete("Never call this directly")]
+ public EditorConfigDocumentOptionsProviderFactory(ICodingConventionsManager codingConventionsManager)
+ {
+ _codingConventionsManager = codingConventionsManager;
+ }
+
public IDocumentOptionsProvider Create(Workspace workspace)
{
- return new EditorConfigDocumentOptionsProvider(workspace);
+ return new EditorConfigDocumentOptionsProvider(workspace, _codingConventionsManager);
}
}
}
diff --git a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs
index 05133be012a37b4247c2564f5c2d5c5df7067101..54acf0e2b994435f5102aade51a2bd5e597e4847 100644
--- a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs
+++ b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs
@@ -9,6 +9,8 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
{
internal class ResettableDelay
{
+ public static readonly ResettableDelay CompletedDelay = new ResettableDelay();
+
private readonly int _delayInMilliseconds;
private readonly TaskCompletionSource