From b90760f73f03449a6882e3e6ed0aa9aaff379333 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 22 Mar 2021 17:42:19 -0700 Subject: [PATCH 001/145] Pass CancellationToken to SelectAsArrayAsync --- .../Core/Portable/Collections/ImmutableArrayExtensions.cs | 5 +++-- src/Features/Core/Portable/EditAndContinue/EditSession.cs | 4 ++-- .../Core/Portable/FindUsages/IRemoteFindUsagesService.cs | 2 +- .../Portable/NavigateTo/AbstractNavigateToSearchService.cs | 2 +- src/Features/Core/Portable/Remote/RemoteArguments.cs | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 025896ce62492..8c16096b12924 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -10,6 +10,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; @@ -226,13 +227,13 @@ public static ImmutableArray SelectAsArray(this Immutab /// /// Maps an immutable array through a function that returns ValueTasks, returning the new ImmutableArray. /// - public static async ValueTask> SelectAsArrayAsync(this ImmutableArray array, Func> selector) + public static async ValueTask> SelectAsArrayAsync(this ImmutableArray array, Func> selector, CancellationToken cancellationToken) { var builder = ArrayBuilder.GetInstance(array.Length); foreach (var item in array) { - builder.Add(await selector(item).ConfigureAwait(false)); + builder.Add(await selector(item, cancellationToken).ConfigureAwait(false)); } return builder.ToImmutableAndFree(); diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index a9734f8af2462..e5c87fa13de7c 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -869,13 +869,13 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol // since we already checked that no changed document is out-of-sync above. var oldActiveExceptionRegions = await GetBaseActiveExceptionRegionsAsync(solution, cancellationToken).ConfigureAwait(false); - var lineEdits = await projectChanges.LineChanges.SelectAsArrayAsync(async lineChange => + var lineEdits = await projectChanges.LineChanges.SelectAsArrayAsync(async (lineChange, cancellationToken) => { var document = await newProject.GetDocumentAsync(lineChange.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(document); Contract.ThrowIfNull(document.FilePath); return new SequencePointUpdates(document.FilePath, lineChange.Changes); - }).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); using var pdbStream = SerializableBytes.CreateWritableStream(); using var metadataStream = SerializableBytes.CreateWritableStream(); diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs index edf29e693ec83..44fef86da77f6 100644 --- a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs @@ -244,7 +244,7 @@ public static SerializableDefinitionItem Dehydrate(int id, DefinitionItem item) public async ValueTask RehydrateAsync(Solution solution, CancellationToken cancellationToken) { - var sourceSpans = await SourceSpans.SelectAsArrayAsync(ss => ss.RehydrateAsync(solution, cancellationToken)).ConfigureAwait(false); + var sourceSpans = await SourceSpans.SelectAsArrayAsync((ss, cancellationToken) => ss.RehydrateAsync(solution, cancellationToken), cancellationToken).ConfigureAwait(false); return new DefinitionItem.DefaultDefinitionItem( Tags, diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs index c8d3ef646d019..b472c3a4e9eae 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs @@ -76,7 +76,7 @@ private static ValueTask> RehydrateAsync { if (result.HasValue) { - return result.Value.SelectAsArrayAsync(r => r.RehydrateAsync(solution, cancellationToken)); + return result.Value.SelectAsArrayAsync((r, cancellationToken) => r.RehydrateAsync(solution, cancellationToken), cancellationToken); } else { diff --git a/src/Features/Core/Portable/Remote/RemoteArguments.cs b/src/Features/Core/Portable/Remote/RemoteArguments.cs index 1cdfdbe4b4444..7e6587437e335 100644 --- a/src/Features/Core/Portable/Remote/RemoteArguments.cs +++ b/src/Features/Core/Portable/Remote/RemoteArguments.cs @@ -178,7 +178,7 @@ public async ValueTask RehydrateAsync(Solution solution, Cancell { var childItems = ChildItems == null ? ImmutableArray.Empty - : await ChildItems.SelectAsArrayAsync(c => c.RehydrateAsync(solution, cancellationToken)).ConfigureAwait(false); + : await ChildItems.SelectAsArrayAsync((c, cancellationToken) => c.RehydrateAsync(solution, cancellationToken), cancellationToken).ConfigureAwait(false); return new NavigableItem( Glyph, DisplayTaggedParts, From 3cdcb84834d594d730c2b76aa96f43d0e16d8809 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 22 Mar 2021 17:45:47 -0700 Subject: [PATCH 002/145] Export option persisters via IOptionPersisterProvider --- .../ProjectCacheHostServiceFactoryTests.cs | 2 +- .../TestOptionsServiceFactory.cs | 3 +- ...ceWithSharedGlobalOptionsServiceFactory.cs | 2 +- .../Options/LanguageSettingsPersister.cs | 10 +--- .../LanguageSettingsPersisterProvider.cs | 54 +++++++++++++++++++ .../LocalUserRegistryOptionPersister.cs | 12 ++--- ...ocalUserRegistryOptionPersisterProvider.cs | 46 ++++++++++++++++ ...amingVisualStudioProfileOptionPersister.cs | 12 ++--- ...ualStudioProfileOptionPersisterProvider.cs | 54 +++++++++++++++++++ .../TaskList/CommentTaskTokenSerializer.cs | 23 +++----- .../CommentTaskTokenSerializerProvider.cs | 53 ++++++++++++++++++ src/VisualStudio/Core/Def/RoslynPackage.cs | 5 +- .../Portable/Options/GlobalOptionService.cs | 34 +++++++++--- .../Options/IOptionPersisterProvider.cs | 11 ++++ .../WorkspaceServices/TestOptionService.cs | 2 +- .../TestOptionsServiceFactory.cs | 2 +- ...TemporaryWorkspaceOptionsServiceFactory.cs | 2 +- 17 files changed, 271 insertions(+), 56 deletions(-) create mode 100644 src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs create mode 100644 src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs diff --git a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs index ca814e68648ff..edd6ece01ced9 100644 --- a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs +++ b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs @@ -273,7 +273,7 @@ public MockHostWorkspaceServices(HostServices hostServices, Workspace workspace) _hostServices = hostServices; _workspace = workspace; - var globalOptionService = new GlobalOptionService(ImmutableArray>.Empty, ImmutableArray>.Empty); + var globalOptionService = new GlobalOptionService(ImmutableArray>.Empty, ImmutableArray>.Empty); _optionService = new OptionServiceFactory.OptionService(globalOptionService, this); } diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs index f12e5f639cae5..b31551cd4d340 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests @@ -34,7 +33,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs index fc67ba83138fa..2c7ecfb3663a1 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs @@ -31,7 +31,7 @@ internal class TestOptionsServiceWithSharedGlobalOptionsServiceFactory : IWorksp public TestOptionsServiceWithSharedGlobalOptionsServiceFactory( [ImportMany] IEnumerable> optionProviders) { - _globalOptionService = new GlobalOptionService(optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); + _globalOptionService = new GlobalOptionService(optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs index 50c67eed76007..65619b1bcfb6e 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs @@ -5,7 +5,6 @@ #nullable disable using System; -using System.ComponentModel.Composition; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -14,12 +13,10 @@ using Microsoft.CodeAnalysis.Editor.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Setup; using Microsoft.VisualStudio.TextManager.Interop; using Roslyn.Utilities; -using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { @@ -27,7 +24,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options /// An that syncs core language settings against the settings that exist for all languages /// in Visual Studio and whose backing store is provided by the shell. This includes things like default tab size, tabs vs. spaces, etc. /// - [Export(typeof(IOptionPersister))] internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObject, IVsTextManagerEvents4, IOptionPersister { private readonly IVsTextManager4 _textManager; @@ -49,15 +45,13 @@ internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObj /// /// We make sure this code is from the UI by asking for all in /// - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public LanguageSettingsPersister( IThreadingContext threadingContext, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + IVsTextManager4 textManager, IGlobalOptionService optionService) : base(threadingContext, assertIsForeground: true) { - _textManager = (IVsTextManager4)serviceProvider.GetService(typeof(SVsTextManager)); + _textManager = textManager; _optionService = optionService; // TODO: make this configurable diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs new file mode 100644 index 0000000000000..8d985ab4c4188 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.Utilities; +using Microsoft.VisualStudio.TextManager.Interop; +using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class LanguageSettingsPersisterProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IServiceProvider _serviceProvider; + private readonly IGlobalOptionService _optionService; + private LanguageSettingsPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LanguageSettingsPersisterProvider( + IThreadingContext threadingContext, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + IGlobalOptionService optionService) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + _optionService = optionService; + } + + public IOptionPersister GetPersister() + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + _threadingContext.ThrowIfNotOnUIThread(); + + var textManager = _serviceProvider.GetService(); + Assumes.Present(textManager); + + _lazyPersister ??= new LanguageSettingsPersister(_threadingContext, textManager, _optionService); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs index b37f26d496c78..d1a5cccfd1317 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs @@ -5,12 +5,11 @@ #nullable disable using System; -using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -21,7 +20,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options /// /// Serializes options marked with to the local hive-specific registry. /// - [Export(typeof(IOptionPersister))] internal sealed class LocalUserRegistryOptionPersister : IOptionPersister { /// @@ -30,12 +28,10 @@ internal sealed class LocalUserRegistryOptionPersister : IOptionPersister private readonly object _gate = new(); private readonly RegistryKey _registryKey; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LocalUserRegistryOptionPersister([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + public LocalUserRegistryOptionPersister(IThreadingContext threadingContext, IServiceProvider serviceProvider) { - // Starting in Dev16, the ILocalRegistry service behind this call is free-threaded, and since the service is offered by msenv.dll can be requested - // without any marshalling (explicit or otherwise) to the UI thread. + threadingContext.ThrowIfNotOnUIThread(); + this._registryKey = VSRegistry.RegistryRoot(serviceProvider, __VsLocalRegistryType.RegType_UserSettings, writable: true); } diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs new file mode 100644 index 0000000000000..dbb0d5a226bf6 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Shell; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class LocalUserRegistryOptionPersisterProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IServiceProvider _serviceProvider; + private LocalUserRegistryOptionPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LocalUserRegistryOptionPersisterProvider( + IThreadingContext threadingContext, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + } + + public IOptionPersister GetPersister() + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + _threadingContext.ThrowIfNotOnUIThread(); + + _lazyPersister ??= new LocalUserRegistryOptionPersister(_threadingContext, _serviceProvider); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs index 8ae75996ce521..3592dd8c8e0b6 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.ComponentModel.Composition; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -16,11 +15,9 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Setup; using Microsoft.VisualStudio.Settings; -using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options @@ -28,7 +25,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options /// /// Serializes settings marked with to and from the user's roaming profile. /// - [Export(typeof(IOptionPersister))] internal sealed class RoamingVisualStudioProfileOptionPersister : ForegroundThreadAffinitizedObject, IOptionPersister { // NOTE: This service is not public or intended for use by teams/individuals outside of Microsoft. Any data stored is subject to deletion without warning. @@ -49,14 +45,12 @@ private class SVsSettingsPersistenceManager { }; /// /// We make sure this code is from the UI by asking for all in /// - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) - : base(threadingContext, assertIsForeground: true) // The GetService call requires being on the UI thread or else it will marshal and risk deadlock + public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, ISettingsManager settingsManager) + : base(threadingContext, assertIsForeground: true) { Contract.ThrowIfNull(globalOptionService); - _settingManager = (ISettingsManager)serviceProvider.GetService(typeof(SVsSettingsPersistenceManager)); + _settingManager = settingsManager; _globalOptionService = globalOptionService; // While the settings persistence service should be available in all SKUs it is possible an ISO shell author has undefined the diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs new file mode 100644 index 0000000000000..81d4a0f1cdcce --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.Internal.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.LanguageServices.Utilities; +using Microsoft.VisualStudio.Settings; +using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class RoamingVisualStudioProfileOptionPersisterProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IServiceProvider _serviceProvider; + private readonly IGlobalOptionService _optionService; + private RoamingVisualStudioProfileOptionPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RoamingVisualStudioProfileOptionPersisterProvider( + IThreadingContext threadingContext, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + IGlobalOptionService optionService) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + _optionService = optionService; + } + + public IOptionPersister GetPersister() + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + _threadingContext.ThrowIfNotOnUIThread(); + + var settingsManager = _serviceProvider.GetService(); + + _lazyPersister ??= new RoamingVisualStudioProfileOptionPersister(_threadingContext, _optionService, settingsManager); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs index 00eb6e2070ef6..59ff0d339ce1a 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs @@ -2,39 +2,30 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; using System.Collections.Generic; using System.ComponentModel; -using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList { - [Export(typeof(IOptionPersister))] internal class CommentTaskTokenSerializer : IOptionPersister { - private readonly ITaskList _taskList; + private readonly ITaskList? _taskList; private readonly IGlobalOptionService _globalOptionService; - private string _lastCommentTokenCache = null; + private string? _lastCommentTokenCache = null; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CommentTaskTokenSerializer( IGlobalOptionService globalOptionService, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + ITaskList? taskList) { _globalOptionService = globalOptionService; // The SVsTaskList may not be available or doesn't actually implement ITaskList // in the "devenv /build" scenario - _taskList = serviceProvider.GetService(typeof(SVsTaskList)) as ITaskList; + _taskList = taskList; // GetTaskTokenList is safe in the face of nulls _lastCommentTokenCache = GetTaskTokenList(_taskList); @@ -45,7 +36,7 @@ public CommentTaskTokenSerializer( } } - public bool TryFetch(OptionKey optionKey, out object value) + public bool TryFetch(OptionKey optionKey, out object? value) { value = string.Empty; if (optionKey != TodoCommentOptions.TokenList) @@ -57,7 +48,7 @@ public bool TryFetch(OptionKey optionKey, out object value) return true; } - public bool TryPersist(OptionKey optionKey, object value) + public bool TryPersist(OptionKey optionKey, object? value) { // it never persists return false; @@ -85,7 +76,7 @@ private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) _globalOptionService.RefreshOption(TodoCommentOptions.TokenList, _lastCommentTokenCache); } - private static string GetTaskTokenList(ITaskList taskList) + private static string GetTaskTokenList(ITaskList? taskList) { var commentTokens = taskList?.CommentTokens; if (commentTokens == null || commentTokens.Count == 0) diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs new file mode 100644 index 0000000000000..5e2192e66e2c7 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.Utilities; +using ITaskList = Microsoft.VisualStudio.Shell.ITaskList; +using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; +using SVsTaskList = Microsoft.VisualStudio.Shell.Interop.SVsTaskList; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class CommentTaskTokenSerializerProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IServiceProvider _serviceProvider; + private readonly IGlobalOptionService _optionService; + private CommentTaskTokenSerializer? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommentTaskTokenSerializerProvider( + IThreadingContext threadingContext, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + IGlobalOptionService optionService) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + _optionService = optionService; + } + + public IOptionPersister GetPersister() + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + _threadingContext.ThrowIfNotOnUIThread(); + + var taskList = _serviceProvider.GetService(); + _lazyPersister ??= new CommentTaskTokenSerializer(_optionService, taskList); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 7261ce5c45d59..872b0f0cf600c 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -113,7 +113,10 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke Assumes.Present(_componentModel); // Ensure the options persisters are loaded since we have to fetch options from the shell - _componentModel.GetExtensions(); + foreach (var provider in _componentModel.GetExtensions()) + { + _ = provider.GetPersister(); + } _workspace = _componentModel.GetService(); _workspace.Services.GetService(); diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index d9575b789f9e6..dbd7d52aa6dca 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -9,6 +9,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options.Providers; @@ -26,7 +28,7 @@ internal class GlobalOptionService : IGlobalOptionService = ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer); private readonly Lazy> _lazyAllOptions; - private readonly ImmutableArray> _optionSerializers; + private readonly ImmutableArray> _optionSerializerProviders; private readonly ImmutableDictionary>> _serializableOptionsByLanguage; private readonly HashSet _forceComputedLanguages; @@ -38,6 +40,8 @@ internal class GlobalOptionService : IGlobalOptionService private ImmutableDictionary _visualBasicEditorConfigKeysToOptions = s_emptyEditorConfigKeysToOptions; #pragma warning restore IDE0044 // Add readonly modifier + private ImmutableArray _lazyOptionSerializers; + private ImmutableDictionary _currentValues; private ImmutableHashSet _changedOptionKeys; private ImmutableArray _registeredWorkspaces; @@ -46,10 +50,10 @@ internal class GlobalOptionService : IGlobalOptionService [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] public GlobalOptionService( [ImportMany] IEnumerable> optionProviders, - [ImportMany] IEnumerable> optionSerializers) + [ImportMany] IEnumerable> optionSerializers) { _lazyAllOptions = new Lazy>(() => optionProviders.SelectMany(p => p.Value.Options).ToImmutableHashSet()); - _optionSerializers = optionSerializers.ToImmutableArray(); + _optionSerializerProviders = optionSerializers.ToImmutableArray(); _serializableOptionsByLanguage = CreateLazySerializableOptionsByLanguage(optionProviders); _forceComputedLanguages = new HashSet(); _registeredWorkspaces = ImmutableArray.Empty; @@ -91,12 +95,28 @@ static ImmutableHashSet ComputeSerializableOptionsFromProviders(Immutab } } + private ImmutableArray GetOptionPersisters() + { + if (_lazyOptionSerializers is { IsDefault: false } optionSerializers) + { + return optionSerializers; + } + + var constructedOptionSerializers = _optionSerializerProviders.SelectAsArray( + static (lazyProvider) => lazyProvider.Value.GetPersister()); + + optionSerializers = constructedOptionSerializers.WhereNotNull().ToImmutableArray(); + ImmutableInterlocked.InterlockedInitialize(ref _lazyOptionSerializers, optionSerializers); + + return _lazyOptionSerializers; + } + private object? LoadOptionFromSerializerOrGetDefault(OptionKey optionKey) { - foreach (var serializer in _optionSerializers) + foreach (var serializer in GetOptionPersisters()) { // We have a deserializer, so deserialize and use that value. - if (serializer.Value.TryFetch(optionKey, out var deserializedValue)) + if (serializer.TryFetch(optionKey, out var deserializedValue)) { return deserializedValue; } @@ -326,9 +346,9 @@ public void SetOptions(OptionSet optionSet) SetOptionCore(optionKey, setValue); - foreach (var serializer in _optionSerializers) + foreach (var serializer in GetOptionPersisters()) { - if (serializer.Value.TryPersist(optionKey, setValue)) + if (serializer.TryPersist(optionKey, setValue)) { break; } diff --git a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs new file mode 100644 index 0000000000000..692c090fe9767 --- /dev/null +++ b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Options +{ + internal interface IOptionPersisterProvider + { + IOptionPersister GetPersister(); + } +} diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs index 0fd51261e3ffa..815407148b502 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs @@ -20,7 +20,7 @@ public static OptionServiceFactory.OptionService GetService(Workspace workspace, { new Lazy(() => optionProvider ??= new TestOptionsProvider(), new LanguageMetadata(LanguageNames.CSharp)) }, - Enumerable.Empty>()), workspaceServices: workspace.Services); + Enumerable.Empty>()), workspaceServices: workspace.Services); } internal class TestOptionsProvider : IOptionProvider diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs index f2b3c951bc5fd..b0b0135eb8be8 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs @@ -33,7 +33,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs index b4eab22359401..bc6780b909f65 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs @@ -31,7 +31,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } From b6c096a0face407067841c80ca9670b211a01c59 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 22 Mar 2021 18:42:57 -0700 Subject: [PATCH 003/145] Avoid loading packages synchronously Closes #37377 --- .../LanguageService/AbstractPackage`2.cs | 4 ++-- .../LanguageSettingsPersisterProvider.cs | 21 +++++++++++------- ...ocalUserRegistryOptionPersisterProvider.cs | 11 +++++++--- ...ualStudioProfileOptionPersisterProvider.cs | 21 +++++++++++------- .../CommentTaskTokenSerializerProvider.cs | 22 ++++++++++++------- src/VisualStudio/Core/Def/RoslynPackage.cs | 2 +- .../Portable/Options/GlobalOptionService.cs | 2 +- .../Options/IOptionPersisterProvider.cs | 7 +++++- 8 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs index 83fa01597711b..25c72e285146c 100644 --- a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs +++ b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractPackage`2.cs @@ -43,7 +43,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var shell = (IVsShell)await GetServiceAsync(typeof(SVsShell)).ConfigureAwait(true); + var shell = (IVsShell7)await GetServiceAsync(typeof(SVsShell)).ConfigureAwait(true); var solution = (IVsSolution)await GetServiceAsync(typeof(SVsSolution)).ConfigureAwait(true); cancellationToken.ThrowIfCancellationRequested(); Assumes.Present(shell); @@ -65,7 +65,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke return _languageService.ComAggregate; }); - shell.LoadPackage(Guids.RoslynPackageId, out var setupPackage); + await shell.LoadPackageAsync(Guids.RoslynPackageId); var miscellaneousFilesWorkspace = this.ComponentModel.GetService(); RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace); diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs index 8d985ab4c4188..3f23a2c4e99e3 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs @@ -5,13 +5,13 @@ using System; using System.ComponentModel.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.TextManager.Interop; -using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { @@ -19,7 +19,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal sealed class LanguageSettingsPersisterProvider : IOptionPersisterProvider { private readonly IThreadingContext _threadingContext; - private readonly IServiceProvider _serviceProvider; + private readonly IAsyncServiceProvider _serviceProvider; private readonly IGlobalOptionService _optionService; private LanguageSettingsPersister? _lazyPersister; @@ -27,7 +27,7 @@ internal sealed class LanguageSettingsPersisterProvider : IOptionPersisterProvid [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public LanguageSettingsPersisterProvider( IThreadingContext threadingContext, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, IGlobalOptionService optionService) { _threadingContext = threadingContext; @@ -35,16 +35,21 @@ public LanguageSettingsPersisterProvider( _optionService = optionService; } - public IOptionPersister GetPersister() + public IOptionPersister? TryGetPersister() + { + return _lazyPersister; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) { return _lazyPersister; } - _threadingContext.ThrowIfNotOnUIThread(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var textManager = _serviceProvider.GetService(); + var textManager = (IVsTextManager4?)await _serviceProvider.GetServiceAsync(typeof(SVsTextManager)).ConfigureAwait(true); Assumes.Present(textManager); _lazyPersister ??= new LanguageSettingsPersister(_threadingContext, textManager, _optionService); diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs index dbb0d5a226bf6..2d2390d09606d 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs @@ -5,7 +5,7 @@ using System; using System.ComponentModel.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; @@ -30,14 +30,19 @@ public LocalUserRegistryOptionPersisterProvider( _serviceProvider = serviceProvider; } - public IOptionPersister GetPersister() + public IOptionPersister? TryGetPersister() + { + return _lazyPersister; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) { return _lazyPersister; } - _threadingContext.ThrowIfNotOnUIThread(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); _lazyPersister ??= new LocalUserRegistryOptionPersister(_threadingContext, _serviceProvider); return _lazyPersister; diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs index 81d4a0f1cdcce..41f15ae9da2ff 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs @@ -5,14 +5,14 @@ using System; using System.ComponentModel.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.Internal.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.Settings; -using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { @@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal sealed class RoamingVisualStudioProfileOptionPersisterProvider : IOptionPersisterProvider { private readonly IThreadingContext _threadingContext; - private readonly IServiceProvider _serviceProvider; + private readonly IAsyncServiceProvider _serviceProvider; private readonly IGlobalOptionService _optionService; private RoamingVisualStudioProfileOptionPersister? _lazyPersister; @@ -28,7 +28,7 @@ internal sealed class RoamingVisualStudioProfileOptionPersisterProvider : IOptio [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public RoamingVisualStudioProfileOptionPersisterProvider( IThreadingContext threadingContext, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, IGlobalOptionService optionService) { _threadingContext = threadingContext; @@ -36,16 +36,21 @@ public RoamingVisualStudioProfileOptionPersisterProvider( _optionService = optionService; } - public IOptionPersister GetPersister() + public IOptionPersister? TryGetPersister() + { + return _lazyPersister; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) { return _lazyPersister; } - _threadingContext.ThrowIfNotOnUIThread(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var settingsManager = _serviceProvider.GetService(); + var settingsManager = (ISettingsManager?)await _serviceProvider.GetServiceAsync(typeof(SVsSettingsPersistenceManager)).ConfigureAwait(true); _lazyPersister ??= new RoamingVisualStudioProfileOptionPersister(_threadingContext, _optionService, settingsManager); return _lazyPersister; diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs index 5e2192e66e2c7..1df6e905f7ef9 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs @@ -5,13 +5,13 @@ using System; using System.ComponentModel.Composition; using System.Threading; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; -using Microsoft.VisualStudio.LanguageServices.Utilities; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; using ITaskList = Microsoft.VisualStudio.Shell.ITaskList; -using SVsServiceProvider = Microsoft.VisualStudio.Shell.SVsServiceProvider; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; using SVsTaskList = Microsoft.VisualStudio.Shell.Interop.SVsTaskList; namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList @@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList internal sealed class CommentTaskTokenSerializerProvider : IOptionPersisterProvider { private readonly IThreadingContext _threadingContext; - private readonly IServiceProvider _serviceProvider; + private readonly IAsyncServiceProvider _serviceProvider; private readonly IGlobalOptionService _optionService; private CommentTaskTokenSerializer? _lazyPersister; @@ -28,7 +28,7 @@ internal sealed class CommentTaskTokenSerializerProvider : IOptionPersisterProvi [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CommentTaskTokenSerializerProvider( IThreadingContext threadingContext, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, IGlobalOptionService optionService) { _threadingContext = threadingContext; @@ -36,16 +36,22 @@ public CommentTaskTokenSerializerProvider( _optionService = optionService; } - public IOptionPersister GetPersister() + public IOptionPersister? TryGetPersister() + { + return _lazyPersister; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) { return _lazyPersister; } - _threadingContext.ThrowIfNotOnUIThread(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var taskList = _serviceProvider.GetService(); + // Not all SVsTaskList implementations implement ITaskList, but when it does we will use it + var taskList = await _serviceProvider.GetServiceAsync(typeof(SVsTaskList)).ConfigureAwait(true) as ITaskList; _lazyPersister ??= new CommentTaskTokenSerializer(_optionService, taskList); return _lazyPersister; } diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 872b0f0cf600c..bcd54de103ae3 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -115,7 +115,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke // Ensure the options persisters are loaded since we have to fetch options from the shell foreach (var provider in _componentModel.GetExtensions()) { - _ = provider.GetPersister(); + _ = await provider.GetOrCreatePersisterAsync(cancellationToken).ConfigureAwait(true); } _workspace = _componentModel.GetService(); diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index dbd7d52aa6dca..9cfa044e43f1e 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -103,7 +103,7 @@ private ImmutableArray GetOptionPersisters() } var constructedOptionSerializers = _optionSerializerProviders.SelectAsArray( - static (lazyProvider) => lazyProvider.Value.GetPersister()); + static (lazyProvider) => lazyProvider.Value.TryGetPersister()); optionSerializers = constructedOptionSerializers.WhereNotNull().ToImmutableArray(); ImmutableInterlocked.InterlockedInitialize(ref _lazyOptionSerializers, optionSerializers); diff --git a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs index 692c090fe9767..4022046cb7a9d 100644 --- a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs +++ b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs @@ -2,10 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Threading; +using System.Threading.Tasks; + namespace Microsoft.CodeAnalysis.Options { internal interface IOptionPersisterProvider { - IOptionPersister GetPersister(); + IOptionPersister? TryGetPersister(); + + ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken); } } From fcc29a2c6892b2620303cf686e9d07a8c694c326 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Mon, 22 Mar 2021 19:33:15 -0700 Subject: [PATCH 004/145] Avoid loading assemblies on the UI thread Closes AB#761238 --- src/VisualStudio/Core/Def/RoslynPackage.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index bcd54de103ae3..2a7af63156b33 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; @@ -113,7 +114,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke Assumes.Present(_componentModel); // Ensure the options persisters are loaded since we have to fetch options from the shell - foreach (var provider in _componentModel.GetExtensions()) + foreach (var provider in await GetOptionPersistersAsync(_componentModel, cancellationToken).ConfigureAwait(true)) { _ = await provider.GetOrCreatePersisterAsync(cancellationToken).ConfigureAwait(true); } @@ -139,6 +140,15 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke _solutionEventMonitor = new SolutionEventMonitor(_workspace); TrackBulkFileOperations(); + + static async Task> GetOptionPersistersAsync(IComponentModel componentModel, CancellationToken cancellationToken) + { + // Switch to a background thread to ensure assembly loads don't show up as UI delays attributed to + // InitializeAsync. + await TaskScheduler.Default; + + return componentModel.GetExtensions().ToImmutableArray(); + } } private void InitializeColors() From b92dc39a0c535aabf1b4944739182f67e1364fe0 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Tue, 23 Mar 2021 20:40:26 -0700 Subject: [PATCH 005/145] Ensure GlobalOptionService always has persister instances --- .../Utilities/WorkspaceThreadingService.cs | 31 +++++++++++++++ .../ProjectCacheHostServiceFactoryTests.cs | 2 +- .../TestOptionsServiceFactory.cs | 8 ++-- ...ceWithSharedGlobalOptionsServiceFactory.cs | 6 +-- .../LanguageSettingsPersisterProvider.cs | 5 --- ...ocalUserRegistryOptionPersisterProvider.cs | 5 --- ...ualStudioProfileOptionPersisterProvider.cs | 5 --- .../CommentTaskTokenSerializerProvider.cs | 5 --- .../Portable/Options/GlobalOptionService.cs | 38 ++++++++++++++++--- .../Options/IOptionPersisterProvider.cs | 11 +++++- .../Utilities/IWorkspaceThreadingService.cs | 19 ++++++++++ .../WorkspaceServices/TestOptionService.cs | 11 ++++-- .../TestOptionsServiceFactory.cs | 8 ++-- ...TemporaryWorkspaceOptionsServiceFactory.cs | 6 ++- 14 files changed, 119 insertions(+), 41 deletions(-) create mode 100644 src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs create mode 100644 src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs diff --git a/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs b/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs new file mode 100644 index 0000000000000..ec046b340bf44 --- /dev/null +++ b/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities +{ + [Export(typeof(IWorkspaceThreadingService))] + [Shared] + internal sealed class WorkspaceThreadingService : IWorkspaceThreadingService + { + private readonly IThreadingContext _threadingContext; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public WorkspaceThreadingService(IThreadingContext threadingContext) + { + _threadingContext = threadingContext; + } + + public TResult Run(Func> asyncMethod) + { + return _threadingContext.JoinableTaskFactory.Run(asyncMethod); + } + } +} diff --git a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs index edd6ece01ced9..a01bff35edaa1 100644 --- a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs +++ b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs @@ -273,7 +273,7 @@ public MockHostWorkspaceServices(HostServices hostServices, Workspace workspace) _hostServices = hostServices; _workspace = workspace; - var globalOptionService = new GlobalOptionService(ImmutableArray>.Empty, ImmutableArray>.Empty); + var globalOptionService = new GlobalOptionService(workspaceThreadingService: null, ImmutableArray>.Empty, ImmutableArray>.Empty); _optionService = new OptionServiceFactory.OptionService(globalOptionService, this); } diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs index b31551cd4d340..846ceda99d15c 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests @@ -19,13 +18,16 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests [ExportWorkspaceServiceFactory(typeof(IOptionService), ServiceLayer.Test), Shared, PartNotDiscoverable] internal class TestOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -33,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs index 2c7ecfb3663a1..d72d4b71f1669 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests @@ -29,9 +28,10 @@ internal class TestOptionsServiceWithSharedGlobalOptionsServiceFactory : IWorksp [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceWithSharedGlobalOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { - _globalOptionService = new GlobalOptionService(optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); + _globalOptionService = new GlobalOptionService(workspaceThreadingService, optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs index 3f23a2c4e99e3..7e534f45b9e57 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs @@ -35,11 +35,6 @@ public LanguageSettingsPersisterProvider( _optionService = optionService; } - public IOptionPersister? TryGetPersister() - { - return _lazyPersister; - } - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs index 2d2390d09606d..5e408cdbcccda 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs @@ -30,11 +30,6 @@ public LocalUserRegistryOptionPersisterProvider( _serviceProvider = serviceProvider; } - public IOptionPersister? TryGetPersister() - { - return _lazyPersister; - } - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs index 41f15ae9da2ff..0a4f21738065a 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersisterProvider.cs @@ -36,11 +36,6 @@ public RoamingVisualStudioProfileOptionPersisterProvider( _optionService = optionService; } - public IOptionPersister? TryGetPersister() - { - return _lazyPersister; - } - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs index 1df6e905f7ef9..399ea1cb82607 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs @@ -36,11 +36,6 @@ public CommentTaskTokenSerializerProvider( _optionService = optionService; } - public IOptionPersister? TryGetPersister() - { - return _lazyPersister; - } - public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) { if (_lazyPersister is not null) diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index 9cfa044e43f1e..f4db1fab6a34b 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options @@ -27,6 +28,7 @@ internal class GlobalOptionService : IGlobalOptionService private static readonly ImmutableDictionary s_emptyEditorConfigKeysToOptions = ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer); + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly Lazy> _lazyAllOptions; private readonly ImmutableArray> _optionSerializerProviders; private readonly ImmutableDictionary>> _serializableOptionsByLanguage; @@ -49,9 +51,11 @@ internal class GlobalOptionService : IGlobalOptionService [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] public GlobalOptionService( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders, [ImportMany] IEnumerable> optionSerializers) { + _workspaceThreadingService = workspaceThreadingService; _lazyAllOptions = new Lazy>(() => optionProviders.SelectMany(p => p.Value.Options).ToImmutableHashSet()); _optionSerializerProviders = optionSerializers.ToImmutableArray(); _serializableOptionsByLanguage = CreateLazySerializableOptionsByLanguage(optionProviders); @@ -97,18 +101,42 @@ static ImmutableHashSet ComputeSerializableOptionsFromProviders(Immutab private ImmutableArray GetOptionPersisters() { + // If _lazyOptionSerializers is already initialized, return its value directly. if (_lazyOptionSerializers is { IsDefault: false } optionSerializers) { return optionSerializers; } - var constructedOptionSerializers = _optionSerializerProviders.SelectAsArray( - static (lazyProvider) => lazyProvider.Value.TryGetPersister()); - - optionSerializers = constructedOptionSerializers.WhereNotNull().ToImmutableArray(); - ImmutableInterlocked.InterlockedInitialize(ref _lazyOptionSerializers, optionSerializers); + ImmutableInterlocked.InterlockedInitialize( + ref _lazyOptionSerializers, + GetOptionPersistersSlow(_workspaceThreadingService, _optionSerializerProviders, CancellationToken.None)); return _lazyOptionSerializers; + + // Local functions + static ImmutableArray GetOptionPersistersSlow( + IWorkspaceThreadingService? workspaceThreadingService, + ImmutableArray> optionSerializerProviders, + CancellationToken cancellationToken) + { + if (workspaceThreadingService is not null) + { + return workspaceThreadingService.Run(() => GetOptionPersistersAsync(optionSerializerProviders, cancellationToken)); + } + else + { + return GetOptionPersistersAsync(optionSerializerProviders, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); + } + } + + static async Task> GetOptionPersistersAsync( + ImmutableArray> optionSerializerProviders, + CancellationToken cancellationToken) + { + return await optionSerializerProviders.SelectAsArrayAsync( + static (lazyProvider, cancellationToken) => lazyProvider.Value.GetOrCreatePersisterAsync(cancellationToken), + cancellationToken).ConfigureAwait(false); + } } private object? LoadOptionFromSerializerOrGetDefault(OptionKey optionKey) diff --git a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs index 4022046cb7a9d..d5e118dc30336 100644 --- a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs +++ b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs @@ -9,8 +9,15 @@ namespace Microsoft.CodeAnalysis.Options { internal interface IOptionPersisterProvider { - IOptionPersister? TryGetPersister(); - + /// + /// Gets the . If the persister does not already exist, it is created. + /// + /// + /// This method is safe for concurrent use from any thread. No guarantees are made regarding the use of the UI + /// thread. + /// + /// A cancellation token the operation may observe. + /// The option persister. ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken); } } diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs new file mode 100644 index 0000000000000..8ac4617acdd48 --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Shared.Utilities +{ + /// + /// An optional interface which allows an environment to customize the behavior for synchronous methods that need to + /// block on the result of an asynchronous invocation. An implementation of this is provided in the MEF catalog when + /// applicable. + /// + internal interface IWorkspaceThreadingService + { + TResult Run(Func> asyncMethod); + } +} diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs index 815407148b502..18551dcb3069e 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs @@ -3,12 +3,13 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; namespace Microsoft.CodeAnalysis.UnitTests { @@ -16,7 +17,11 @@ internal static class TestOptionService { public static OptionServiceFactory.OptionService GetService(Workspace workspace, IOptionProvider? optionProvider = null) { - return new OptionServiceFactory.OptionService(new GlobalOptionService(new[] + var mefHostServices = (IMefHostExportProvider)workspace.Services.HostServices; + var workspaceThreadingService = mefHostServices.GetExportedValues().SingleOrDefault(); + return new OptionServiceFactory.OptionService(new GlobalOptionService( + workspaceThreadingService, + new[] { new Lazy(() => optionProvider ??= new TestOptionsProvider(), new LanguageMetadata(LanguageNames.CSharp)) }, diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs index b0b0135eb8be8..9f9bea5445824 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UnitTests @@ -19,13 +18,16 @@ namespace Microsoft.CodeAnalysis.UnitTests [ExportWorkspaceServiceFactory(typeof(IOptionService), ServiceLayer.Host), Shared] internal class TestOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -33,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs index bc6780b909f65..effa4bfe07047 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote @@ -17,13 +18,16 @@ namespace Microsoft.CodeAnalysis.Remote [ExportWorkspaceServiceFactory(typeof(IOptionService), WorkspaceKind.RemoteTemporaryWorkspace), Shared] internal class TemporaryWorkspaceOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TemporaryWorkspaceOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -31,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } From b7a924e95d08b77bab80b54867ceaf99848000bc Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 24 Mar 2021 20:28:50 -0700 Subject: [PATCH 006/145] Update documentation --- .../Options/LocalUserRegistryOptionPersister.cs | 6 ++++++ .../Shared/Utilities/IWorkspaceThreadingService.cs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs index d1a5cccfd1317..e1582bef9a6e9 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs @@ -30,6 +30,12 @@ internal sealed class LocalUserRegistryOptionPersister : IOptionPersister public LocalUserRegistryOptionPersister(IThreadingContext threadingContext, IServiceProvider serviceProvider) { + // Starting with Dev16, the ILocalRegistry service is expected to be free-threaded, and aquiring it from the + // global service provider is expected to complete without any UI thread marshaling requirements. However, + // since none of this is publicly documented, we keep this assertion for maximum compatibility assurance. + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.vsregistry.registryroot + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.interop.ilocalregistry + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.interop.slocalregistry threadingContext.ThrowIfNotOnUIThread(); this._registryKey = VSRegistry.RegistryRoot(serviceProvider, __VsLocalRegistryType.RegType_UserSettings, writable: true); diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs index 8ac4617acdd48..bd68191deea62 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs +++ b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs @@ -12,6 +12,16 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities /// block on the result of an asynchronous invocation. An implementation of this is provided in the MEF catalog when /// applicable. /// + /// + /// For Visual Studio, Microsoft.VisualStudio.Threading provides the JoinableTaskFactory.Run method, which is + /// the expected way to invoke an asynchronous method from a synchronous entry point and block on its completion. + /// Other environments may choose to use this or any other strategy, or omit an implementation of this interface to + /// allow callers to simply use . + /// + /// New code is expected to use fully-asynchronous programming where possible. In cases where external APIs + /// restrict ability to be asynchronous, this service allows Roslyn to adhere to environmental policies related to + /// joining asynchronous work. + /// internal interface IWorkspaceThreadingService { TResult Run(Func> asyncMethod); From 32b901b50d4300c640c25523d256606c2077b5b4 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 24 Mar 2021 20:29:17 -0700 Subject: [PATCH 007/145] Null-annotate RoamingVisualStudioProfileOptionPersister --- ...amingVisualStudioProfileOptionPersister.cs | 22 +++++++++---------- .../Options/RoamingProfileStorageLocation.cs | 6 ++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs index 3592dd8c8e0b6..a44ed3c153297 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel; @@ -31,7 +29,7 @@ internal sealed class RoamingVisualStudioProfileOptionPersister : ForegroundThre [Guid("9B164E40-C3A2-4363-9BC5-EB4039DEF653")] private class SVsSettingsPersistenceManager { }; - private readonly ISettingsManager _settingManager; + private readonly ISettingsManager? _settingManager; private readonly IGlobalOptionService _globalOptionService; /// @@ -45,7 +43,7 @@ private class SVsSettingsPersistenceManager { }; /// /// We make sure this code is from the UI by asking for all in /// - public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, ISettingsManager settingsManager) + public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, ISettingsManager? settingsManager) : base(threadingContext, assertIsForeground: true) { Contract.ThrowIfNull(globalOptionService); @@ -65,7 +63,7 @@ public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingCont private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, PropertyChangedEventArgs args) { - List optionsToRefresh = null; + List? optionsToRefresh = null; lock (_optionsToMonitorForChangesGate) { @@ -95,8 +93,10 @@ private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, Propert return System.Threading.Tasks.Task.CompletedTask; } - private object GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable roamingSerializations) + private object? GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable roamingSerializations) { + Contract.ThrowIfNull(_settingManager); + // There can be more than 1 roaming location in the order of their priority. // When fetching a value, we iterate all of them until we find the first one that exists. // When persisting a value, we always use the first location. @@ -120,7 +120,7 @@ private object GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable internal sealed class RoamingProfileStorageLocation : OptionStorageLocation2 { - private readonly Func _keyNameFromLanguageName; + private readonly Func _keyNameFromLanguageName; - public string GetKeyNameForLanguage(string languageName) + public string GetKeyNameForLanguage(string? languageName) { var unsubstitutedKeyName = _keyNameFromLanguageName(languageName); @@ -38,7 +38,7 @@ public RoamingProfileStorageLocation(string keyName) /// Creates a that has different key names for different languages. /// /// A function that maps from a value to the key name. - public RoamingProfileStorageLocation(Func keyNameFromLanguageName) + public RoamingProfileStorageLocation(Func keyNameFromLanguageName) => _keyNameFromLanguageName = keyNameFromLanguageName; } } From f917e5f579cf5ca7c01d655793dab776732cab66 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 25 Mar 2021 09:20:30 -0700 Subject: [PATCH 008/145] Remove the default value for TodoCommentOptions.TokenList The correct value for this option is sourced from ITaskList. Including a default value hides cases where options fail to load. --- .../TodoComment/NoCompilationTodoCommentTests.cs | 6 +++++- .../CSharpTest/TodoComment/TodoCommentTests.cs | 7 ++++++- .../TestUtilities/TodoComments/AbtractTodoCommentTests.cs | 4 +++- .../VisualBasicTest/TodoComment/TodoCommentTests.vb | 5 ++++- .../Core/Test.Next/Services/ServiceHubServicesTests.cs | 5 ++++- .../Core/Portable/TodoComments/TodoCommentOptions.cs | 2 +- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs b/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs index b345017bbc2da..1c349c610f725 100644 --- a/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Host.Mef; @@ -27,7 +28,7 @@ public class NoCompilationTodoCommentTests : AbstractTodoCommentTests { protected override TestWorkspace CreateWorkspace(string codeWithMarker) { - return TestWorkspace.CreateWorkspace(XElement.Parse( + var workspace = TestWorkspace.CreateWorkspace(XElement.Parse( $@" {codeWithMarker} @@ -36,6 +37,9 @@ protected override TestWorkspace CreateWorkspace(string codeWithMarker) typeof(NoCompilationContentTypeDefinitions), typeof(NoCompilationContentTypeLanguageService), typeof(NoCompilationTodoCommentService))); + + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)); + return workspace; } [Fact, WorkItem(1192024, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1192024")] diff --git a/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs b/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs index ee8d13571d5d9..d0afce28ba083 100644 --- a/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs @@ -5,6 +5,7 @@ #nullable disable using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.TodoComments; @@ -16,7 +17,11 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.TodoComment public class TodoCommentTests : AbstractTodoCommentTests { protected override TestWorkspace CreateWorkspace(string codeWithMarker) - => TestWorkspace.CreateCSharp(codeWithMarker); + { + var workspace = TestWorkspace.CreateCSharp(codeWithMarker); + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)); + return workspace; + } [Fact] public async Task SingleLineTodoComment_Colon() diff --git a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs index 900a29ed0783c..13ca0f4ef358b 100644 --- a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs +++ b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs @@ -25,6 +25,8 @@ namespace Microsoft.CodeAnalysis.Test.Utilities.TodoComments { public abstract class AbstractTodoCommentTests { + protected const string DefaultTokenList = "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0"; + protected abstract TestWorkspace CreateWorkspace(string codeWithMarker); protected async Task TestAsync(string codeWithMarker) @@ -38,7 +40,7 @@ protected async Task TestAsync(string codeWithMarker) var document = workspace.CurrentSolution.GetDocument(documentId); var service = document.GetLanguageService(); var todoComments = await service.GetTodoCommentsAsync(document, - TodoCommentDescriptor.Parse(TodoCommentOptions.TokenList.DefaultValue), + TodoCommentDescriptor.Parse(workspace.Options.GetOption(TodoCommentOptions.TokenList)), CancellationToken.None); using var _ = ArrayBuilder.GetInstance(out var converted); diff --git a/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb b/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb index ee22f45fe47b8..6d18c7bbe7f70 100644 --- a/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb +++ b/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Editor.Implementation.TodoComments Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities.TodoComments @@ -12,7 +13,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.TodoComment Inherits AbstractTodoCommentTests Protected Overrides Function CreateWorkspace(codeWithMarker As String) As TestWorkspace - Return TestWorkspace.CreateVisualBasic(codeWithMarker) + Dim workspace = TestWorkspace.CreateVisualBasic(codeWithMarker) + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)) + Return workspace End Function diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index 235f616df98a6..8862614262558 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.DesignerAttribute; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Options; @@ -24,6 +25,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.TodoComments; using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.VisualStudio.Threading; using Nerdbank.Streams; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -121,6 +123,7 @@ public async Task TestTodoComments() // TODO: Test"; using var workspace = CreateWorkspace(); + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0")); workspace.InitializeDocuments(LanguageNames.CSharp, files: new[] { source }, openDocuments: false); using var client = await InProcRemoteHostClient.GetTestClientAsync(workspace).ConfigureAwait(false); @@ -142,7 +145,7 @@ public async Task TestTodoComments() (service, callbackId, cancellationToken) => service.ComputeTodoCommentsAsync(callbackId, cancellationToken), cancellationTokenSource.Token); - var data = await callback.Data; + var data = await callback.Data.WithTimeout(TimeSpan.FromMinutes(1)); Assert.Equal(solution.Projects.Single().Documents.Single().Id, data.Item1); Assert.Equal(1, data.Item2.Length); diff --git a/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs b/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs index 1816e77dbfbb8..7192c322c6ec2 100644 --- a/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs +++ b/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments { internal static class TodoCommentOptions { - public static readonly Option TokenList = new(nameof(TodoCommentOptions), nameof(TokenList), defaultValue: "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0"); + public static readonly Option TokenList = new(nameof(TodoCommentOptions), nameof(TokenList), defaultValue: ""); } [ExportOptionProvider, Shared] From b659480c4e02f7f7244dbb88c47b260fc8108d85 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 25 Mar 2021 09:21:24 -0700 Subject: [PATCH 009/145] Add fast path for empty TODO tokens --- .../Core/Portable/TodoComments/AbstractTodoCommentService.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs index 0fb45669359f3..fde046b3e7fa7 100644 --- a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs +++ b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs @@ -29,6 +29,9 @@ public async Task> GetTodoCommentsAsync( ImmutableArray commentDescriptors, CancellationToken cancellationToken) { + if (commentDescriptors.IsEmpty) + return ImmutableArray.Empty; + cancellationToken.ThrowIfCancellationRequested(); // strongly hold onto text and tree From 05ae9e8d0a0327adccb55eec602a32e384ed996f Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Thu, 25 Mar 2021 09:21:37 -0700 Subject: [PATCH 010/145] Simplify interpolation --- .../Def/Implementation/TaskList/CommentTaskTokenSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs index 00eb6e2070ef6..1fc00e852198e 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs @@ -101,7 +101,7 @@ private static string GetTaskTokenList(ITaskList taskList) continue; } - result.Add($"{commentToken.Text}:{((int)commentToken.Priority).ToString()}"); + result.Add($"{commentToken.Text}:{(int)commentToken.Priority}"); } return string.Join("|", result); From 5ac103e4e096c7109b07e405c04cfe48f5fb1624 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 17:47:31 -0700 Subject: [PATCH 011/145] Temp work remove' --- eng/Versions.props | 1 + ...stractNavigateToSearchService.InProcess.cs | 56 +++++++++++++++---- src/Tools/IdeBenchmarks/IdeBenchmarks.csproj | 1 + .../IdeCoreBenchmarks.csproj | 2 + .../IdeCoreBenchmarks/NavigateToBenchmarks.cs | 20 +++++-- src/Tools/IdeCoreBenchmarks/Program.cs | 10 +++- .../AbstractPersistentStorageService.cs | 3 + .../AbstractSQLitePersistentStorageService.cs | 1 + 8 files changed, 73 insertions(+), 21 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index da6f91a9cf921..7047177de63e1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -49,6 +49,7 @@ 0.9.3 0.12.1 + 0.12.1 1.4.4 $(MicrosoftVisualStudioShellPackagesVersion) $(MicrosoftVisualStudioShellPackagesVersion) diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index dbcc69b31ab86..861958153569c 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs @@ -62,24 +62,56 @@ private static async Task FindSearchResultsAsync( { // If the user created a dotted pattern then we'll grab the last part of the name var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern); - var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); + // Prioritize the active documents if we have any. + + var allDocs = await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + var highPriDocs = priorityDocuments.Where(d => project.ContainsDocument(d.Id)).ToSet(); + var lowPriDocs = allDocs.Where(d => !highPriDocs.Contains(d)).ToSet(); - var containerMatcherOpt = patternContainerOpt != null - ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainerOpt) - : null; + var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); + + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, highPriDocs, cancellationToken).ConfigureAwait(false); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, lowPriDocs, cancellationToken).ConfigureAwait(false); + } - using (nameMatcher) - using (containerMatcherOpt) + private static async Task ProcessDocumentsAsync( + Document searchDocument, string patternName, string patternContainerOpt, DeclaredSymbolInfoKindSet kinds, + Func onResultFound, ISet documents, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var tasks); + + foreach (var document in documents) { - using var _1 = ArrayBuilder.GetInstance(out var nameMatches); - using var _2 = ArrayBuilder.GetInstance(out var containerMatches); + if (searchDocument != null && searchDocument != document) + continue; - var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); + cancellationToken.ThrowIfCancellationRequested(); + tasks.Add(Task.Run(async () => + { + var containerMatcherOpt = patternContainerOpt != null + ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainerOpt) + : null; + + using var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); + using var _1 = containerMatcherOpt; + using var _2 = ArrayBuilder.GetInstance(out var nameMatches); + using var _3 = ArrayBuilder.GetInstance(out var containerMatches); + + var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); - await ComputeSearchResultsAsync( - project, priorityDocuments, searchDocument, nameMatcher, containerMatcherOpt, - declaredSymbolInfoKindsSet, nameMatches, containerMatches, onResultFound, cancellationToken).ConfigureAwait(false); + foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos) + { + await AddResultIfMatchAsync( + document, declaredSymbolInfo, + nameMatcher, containerMatcherOpt, + kinds, + nameMatches, containerMatches, + onResultFound, cancellationToken).ConfigureAwait(false); + } + }, cancellationToken)); } + + await Task.WhenAll(tasks).ConfigureAwait(false); } private static async Task ComputeSearchResultsAsync( diff --git a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj index bbf9dd53d33d4..b065f2f981f14 100644 --- a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj +++ b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj index 96f5f69e160da..759610bb4ce53 100644 --- a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj +++ b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj @@ -14,9 +14,11 @@ + + diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 95d25ea3856d2..38ba8d4c90683 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -31,8 +32,8 @@ public class NavigateToBenchmarks public NavigateToBenchmarks() { - var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); - _solutionPath = Path.Combine(roslynRoot, @"C:\github\roslyn\Compilers.sln"); + // var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); + _solutionPath = @"C:\github\roslyn\Roslyn.sln"; if (!File.Exists(_solutionPath)) throw new ArgumentException("Couldn't find Roslyn.sln"); @@ -74,30 +75,37 @@ public void Cleanup() [Benchmark] public async Task RunNavigateTo() { + Console.WriteLine("Press enter"); + Console.ReadLine(); + var solution = _workspace.CurrentSolution; + var watch = new Stopwatch(); + watch.Start(); // Search each project with an independent threadpool task. var searchTasks = solution.Projects.Select( p => Task.Run(() => SearchAsync(p, priorityDocuments: ImmutableArray.Empty), CancellationToken.None)).ToArray(); var result = await Task.WhenAll(searchTasks).ConfigureAwait(false); + watch.Stop(); var sum = result.Sum(); + Console.WriteLine($"Found {sum} results in {watch.ElapsedMilliseconds}"); } private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) { var service = project.LanguageServices.GetService(); var results = new List(); + + var count = 0; await service.SearchProjectAsync( project, priorityDocuments, "Document", service.KindsProvided, r => { - lock (results) - results.Add(r); - + Interlocked.Increment(ref count); return Task.CompletedTask; }, CancellationToken.None); - return results.Count; + return count; } } } diff --git a/src/Tools/IdeCoreBenchmarks/Program.cs b/src/Tools/IdeCoreBenchmarks/Program.cs index 3b127855370dc..48238298f9325 100644 --- a/src/Tools/IdeCoreBenchmarks/Program.cs +++ b/src/Tools/IdeCoreBenchmarks/Program.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Running; @@ -37,10 +38,13 @@ public static string GetRoslynRootLocation([CallerFilePath] string sourceFilePat return Path.Combine(Path.GetDirectoryName(sourceFilePath), @"..\..\.."); } - private static void Main(string[] args) + private static async Task Main(string[] args) { - Environment.SetEnvironmentVariable(RoslynRootPathEnvVariableName, GetRoslynRootLocation()); - new BenchmarkSwitcher(typeof(Program).Assembly).Run(args); + var b = new NavigateToBenchmarks(); + b.Setup(); + await b.RunNavigateTo(); + //Environment.SetEnvironmentVariable(RoslynRootPathEnvVariableName, GetRoslynRootLocation()); + //new BenchmarkSwitcher(typeof(Program).Assembly).Run(args); } } } diff --git a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs index 75d04b04128e8..a8886ce92f93a 100644 --- a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs @@ -102,6 +102,7 @@ internal async ValueTask GetStorageWorkerAsync( } var storage = await CreatePersistentStorageAsync(solutionKey, workingFolder).ConfigureAwait(false); + Contract.ThrowIfTrue(storage is NoOpPersistentStorage); Contract.ThrowIfNull(storage); // Create and cache a new storage instance associated with this particular solution. @@ -159,12 +160,14 @@ await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureA private async ValueTask TryCreatePersistentStorageAsync(SolutionKey solutionKey, string workingFolderPath) { var databaseFilePath = GetDatabaseFilePath(workingFolderPath); + Console.WriteLine("DB path: " + workingFolderPath); try { return await TryOpenDatabaseAsync(solutionKey, workingFolderPath, databaseFilePath).ConfigureAwait(false); } catch (Exception ex) { + Console.WriteLine($"TryCreatePersistentStorageAsync: {ex}"); StorageDatabaseLogger.LogException(ex); if (ShouldDeleteDatabase(ex)) diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs index 3571e6369a217..e061ddfd17912 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs @@ -29,6 +29,7 @@ private static bool TryInitializeLibrariesLazy() } catch (Exception e) when (e is DllNotFoundException || e is EntryPointNotFoundException) { + Console.WriteLine($"TryInitializeLibrariesLazy: {e}"); StorageDatabaseLogger.LogException(e); return false; } From 87bfc80932070faea4d9e74e210e74d29ecaa6c0 Mon Sep 17 00:00:00 2001 From: Jason Malinowski Date: Fri, 26 Mar 2021 18:17:42 -0700 Subject: [PATCH 012/145] Delete AssertEx.Throws We're not entirely sure why this was added; it might have been due to lack of Assert.ThrowsAsync in whichever version of xUnit we were using, or something else. In any case, it's unnecessary today and was also broken: it would silently succeed if the passed function didn't throw any exceptions at all. --- src/Compilers/Test/Core/Assert/AssertEx.cs | 19 --- .../Simplification/SimplifierAPITests.vb | 148 ++++++++--------- .../MSBuildTest/MSBuildWorkspaceTests.cs | 152 ++++++++---------- 3 files changed, 136 insertions(+), 183 deletions(-) diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index aedcf9f43e783..833239de41661 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -732,25 +732,6 @@ IEnumerable GetLines(string str) => expectedValueSourceLine: expectedValueSourceLine); } - public static void Throws(Action action, Action checker = null) - where TException : Exception - { - try - { - action(); - } - catch (Exception e) - { - if (e is AggregateException agg && agg.InnerExceptions.Count == 1) - { - e = agg.InnerExceptions[0]; - } - - Assert.Equal(typeof(TException), e.GetType()); - checker?.Invoke((TException)e); - } - } - public static void Equal(bool[,] expected, Func getResult, int size) { Equal(expected, getResult, (b1, b2) => b1 == b2, b => b ? "true" : "false", "{0,-6:G}", size); diff --git a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb b/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb index 7f93613ef9f78..7ec0fc594a4b4 100644 --- a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb +++ b/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb @@ -11,142 +11,128 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Public Class SimplifierAPITests - Public Sub TestExpandAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(Of SyntaxNode)(Nothing, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "node")) - End Sub + Public Async Function TestExpandAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("node", + Function() + Return Simplifier.ExpandAsync(Of SyntaxNode)(Nothing, Nothing) + End Function) + End Function - Public Sub TestExpandAsync2() + Public Async Function TestExpandAsync2() As Task Dim node = GetSyntaxNode() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(node, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() As Task + Return Simplifier.ExpandAsync(node, Nothing) + End Function) + End Function Public Sub TestExpand() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("node", Sub() - Dim expandedNode = Simplifier.Expand(Of SyntaxNode)(Nothing, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "node")) + Simplifier.Expand(Of SyntaxNode)(Nothing, Nothing, Nothing) + End Sub) End Sub Public Sub TestExpand2() Dim node = GetSyntaxNode() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("semanticModel", Sub() - Dim expandedNode = Simplifier.Expand(node, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "semanticModel")) + Simplifier.Expand(node, Nothing, Nothing) + End Sub) End Sub Public Sub TestExpand3() Dim node = GetSyntaxNode() Dim semanticModel = GetSemanticModel() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("workspace", Sub() - Dim expandedNode = Simplifier.Expand(node, semanticModel, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "workspace")) + Simplifier.Expand(node, semanticModel, Nothing) + End Sub) End Sub - Public Sub TestTokenExpandAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(Nothing, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Public Async Function TestTokenExpandAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ExpandAsync(Nothing, Nothing) + End Function) + End Function Public Sub TestTokenExpand() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("semanticModel", Sub() Dim expandedNode = Simplifier.Expand(Nothing, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "semanticModel")) + End Sub) End Sub Public Sub TestTokenExpand2() Dim semanticModel = GetSemanticModel() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("workspace", Sub() Dim expandedNode = Simplifier.Expand(Nothing, semanticModel, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "workspace")) + End Sub) End Sub - Public Sub TestReduceAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Public Async Function TestReduceAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing) + End Function) + End Function - Public Sub TestReduceAsync2() + Public Async Function TestReduceAsync2() As Task Dim syntaxAnnotation As SyntaxAnnotation = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, syntaxAnnotation).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, syntaxAnnotation) + End Function) + End Function - Public Sub TestReduceAsync3() + Public Async Function TestReduceAsync3() As Task Dim syntaxAnnotation As SyntaxAnnotation = Nothing Dim document = GetDocument() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(document, syntaxAnnotation).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "annotation")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("annotation", + Function() + Return Simplifier.ReduceAsync(document, syntaxAnnotation) + End Function) + End Function - Public Sub TestReduceAsync4() + Public Async Function TestReduceAsync4() As Task Dim textSpan As TextSpan = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, textSpan).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, textSpan) + End Function) + End Function - Public Sub TestReduceAsync5() + Public Async Function TestReduceAsync5() As Task Dim spans As IEnumerable(Of TextSpan) = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, spans).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, spans) + End Function) + End Function - Public Sub TestReduceAsync6() + Public Async Function TestReduceAsync6() As Task Dim document = GetDocument() Dim spans As IEnumerable(Of TextSpan) = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(document, spans).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "spans")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("spans", + Function() As Task + Return Simplifier.ReduceAsync(document, spans) + End Function) + End Function Private Shared Function GetDocument() As Document Dim workspace = New AdhocWorkspace() diff --git a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs index 0606f9146f182..0e7713f1b7e99 100644 --- a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs +++ b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs @@ -807,42 +807,38 @@ public async Task TestOpenProject_WithDuplicateFile() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidFileExtension() + public async Task TestOpenProject_WithInvalidFileExtensionAsync() { // make sure the file does in fact exist, but with an unrecognized extension const string ProjFileName = @"CSharpProject\CSharpProject.csproj.nyi"; CreateFiles(GetSimpleCSharpSolutionFiles() .WithFile(ProjFileName, Resources.ProjectFiles.CSharp.CSharpProject)); - AssertEx.Throws(delegate + var e = await Assert.ThrowsAsync(async delegate { - MSBuildWorkspace.Create().OpenProjectAsync(GetSolutionFileName(ProjFileName)).Wait(); - }, - (e) => - { - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, GetSolutionFileName(ProjFileName), ".nyi"); - Assert.Equal(expected, e.Message); + await MSBuildWorkspace.Create().OpenProjectAsync(GetSolutionFileName(ProjFileName)); }); + + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, GetSolutionFileName(ProjFileName), ".nyi"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_ProjectFileExtensionAssociatedWithUnknownLanguage() + public async Task TestOpenProject_ProjectFileExtensionAssociatedWithUnknownLanguageAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); var language = "lingo"; - AssertEx.Throws(delegate + var e = await Assert.ThrowsAsync(async delegate { var ws = MSBuildWorkspace.Create(); ws.AssociateFileExtensionWithLanguage("csproj", language); // non-existent language - ws.OpenProjectAsync(projFileName).Wait(); - }, - (e) => - { - // the exception should tell us something about the language being unrecognized. - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projFileName, language); - Assert.Equal(expected, e.Message); + await ws.OpenProjectAsync(projFileName); }); + + // the exception should tell us something about the language being unrecognized. + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projFileName, language); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -883,28 +879,28 @@ public async Task TestOpenProject_WithAssociatedLanguageExtension2_IgnoreCase() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentSolutionFile_Fails() + public async Task TestOpenSolution_WithNonExistentSolutionFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName("NonExistentSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFilePath).Wait(); + await workspace.OpenSolutionAsync(solutionFilePath); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithInvalidSolutionFile_Fails() + public async Task TestOpenSolution_WithInvalidSolutionFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName(@"http://localhost/Invalid/InvalidSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFilePath).Wait(); + await workspace.OpenSolutionAsync(solutionFilePath); }); } @@ -999,7 +995,7 @@ public async Task HandleSolutionProjectTypeSolutionFolder() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() + public async Task TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() { // when not skipped we should get an exception for the invalid project @@ -1010,7 +1006,7 @@ public void TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - AssertEx.Throws(() => workspace.OpenSolutionAsync(solutionFilePath).Wait()); + await Assert.ThrowsAsync(() => workspace.OpenSolutionAsync(solutionFilePath)); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1029,7 +1025,7 @@ public async Task TestOpenSolution_WithNonExistentProject_SkipTrue_SucceedsWithF } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() + public async Task TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() { // when skipped we should see an exception for the non-existent project @@ -1040,7 +1036,7 @@ public void TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - AssertEx.Throws(() => workspace.OpenSolutionAsync(solutionFilePath).Wait()); + await Assert.ThrowsAsync(() => workspace.OpenSolutionAsync(solutionFilePath)); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1088,7 +1084,7 @@ public async Task TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognize } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExtension_WithSkipFalse_Fails() + public async Task TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExtension_WithSkipFalse_FailsAsync() { // proves that if both project type guid and file extension are unrecognized, then open project fails. const string NoProjFileName = @"CSharpProject\CSharpProject.noproj"; @@ -1098,42 +1094,38 @@ public void TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExten var solutionFilePath = GetSolutionFileName(@"TestSolution.sln"); - AssertEx.Throws(() => + var e = await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenSolutionAsync(solutionFilePath).Wait(); - }, - e => - { - var noProjFullFileName = GetSolutionFileName(NoProjFileName); - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, noProjFullFileName, ".noproj"); - Assert.Equal(expected, e.Message); + await workspace.OpenSolutionAsync(solutionFilePath); }); + + var noProjFullFileName = GetSolutionFileName(NoProjFileName); + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, noProjFullFileName, ".noproj"); + Assert.Equal(expected, e.Message); } private readonly IEnumerable _defaultAssembliesWithoutCSharp = MefHostServices.DefaultAssemblies.Where(a => !a.FullName.Contains("CSharp")); [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] [WorkItem(3931, "https://github.com/dotnet/roslyn/issues/3931")] - public void TestOpenSolution_WithMissingLanguageLibraries_WithSkipFalse_Throws() + public async Task TestOpenSolution_WithMissingLanguageLibraries_WithSkipFalse_ThrowsAsync() { // proves that if the language libraries are missing then the appropriate error occurs CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName(@"TestSolution.sln"); - AssertEx.Throws(() => + var e = await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(MefHostServices.Create(_defaultAssembliesWithoutCSharp)); workspace.SkipUnrecognizedProjects = false; - workspace.OpenSolutionAsync(solutionFilePath).Wait(); - }, - e => - { - var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projFileName, ".csproj"); - Assert.Equal(expected, e.Message); + await workspace.OpenSolutionAsync(solutionFilePath); }); + + var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projFileName, ".csproj"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1156,47 +1148,42 @@ public async Task TestOpenSolution_WithMissingLanguageLibraries_WithSkipTrue_Suc [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] [WorkItem(3931, "https://github.com/dotnet/roslyn/issues/3931")] - public void TestOpenProject_WithMissingLanguageLibraries_Throws() + public async Task TestOpenProject_WithMissingLanguageLibraries_Throws() { // proves that if the language libraries are missing then the appropriate error occurs CreateFiles(GetSimpleCSharpSolutionFiles()); var projectName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); using var workspace = MSBuildWorkspace.Create(MefHostServices.Create(_defaultAssembliesWithoutCSharp)); - AssertEx.Throws(() => - { - var project = workspace.OpenProjectAsync(projectName).Result; - }, - e => - { - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projectName, ".csproj"); - Assert.Equal(expected, e.Message); - }); + var e = await Assert.ThrowsAsync(() => workspace.OpenProjectAsync(projectName)); + + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projectName, ".csproj"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidFilePath_Fails() + public async Task TestOpenProject_WithInvalidFilePath_Fails() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projectFilePath = GetSolutionFileName(@"http://localhost/Invalid/InvalidProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectFile_Fails() + public async Task TestOpenProject_WithNonExistentProjectFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projectFilePath = GetSolutionFileName(@"CSharpProject\NonExistentProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1218,17 +1205,17 @@ public async Task TestOpenProject_WithInvalidProjectReference_SkipTrue_SucceedsW } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidProjectReference_SkipFalse_Fails() + public async Task TestOpenProject_WithInvalidProjectReference_SkipFalse_Fails() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.InvalidProjectReference)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1250,17 +1237,17 @@ public async Task TestOpenProject_WithNonExistentProjectReference_SkipTrue_Succe } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectReference_SkipFalse_Fails() + public async Task TestOpenProject_WithNonExistentProjectReference_SkipFalse_FailsAsync() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.NonExistentProjectReference)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1283,18 +1270,18 @@ public async Task TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_ } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_SkipFalse_Fails() + public async Task TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_SkipFalse_Fails() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.UnknownProjectExtension) .WithFile(@"CSharpProject\CSharpProject.noproj", Resources.ProjectFiles.CSharp.CSharpProject)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -2541,8 +2528,8 @@ public async Task TestOpenProject_CrossLanguageSkeletonReferenceHasDocComments() Assert.Equal(cscomment, vbcomment); } - [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithProjectFileLocked() + [ConditionalFact(typeof(VisualStudioMSBuildInstalled), typeof(IsEnglishLocal)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] + public async Task TestOpenProject_WithProjectFileLockedAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); @@ -2550,39 +2537,38 @@ public void TestOpenProject_WithProjectFileLocked() var projectFile = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); using (File.Open(projectFile, FileMode.Open, FileAccess.ReadWrite)) { - AssertEx.Throws(() => - { - using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFile).Wait(); - }); + using var workspace = CreateMSBuildWorkspace(); + await workspace.OpenProjectAsync(projectFile); + var diagnostic = Assert.Single(workspace.Diagnostics); + Assert.Contains("The process cannot access the file", diagnostic.Message); } } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectFile() + public async Task TestOpenProject_WithNonExistentProjectFileAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); // open for read-write so no-one else can read var projectFile = GetSolutionFileName(@"CSharpProject\NoProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFile).Wait(); + await workspace.OpenProjectAsync(projectFile); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentSolutionFile() + public async Task TestOpenSolution_WithNonExistentSolutionFileAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); // open for read-write so no-one else can read var solutionFile = GetSolutionFileName(@"NoSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFile).Wait(); + await workspace.OpenSolutionAsync(solutionFile); }); } From da10d5fb0bdc53734b851d2e1907a6f49a04ac31 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 19:42:32 -0700 Subject: [PATCH 013/145] Process source generated docs after other docs --- .../AbstractNavigateToSearchService.InProcess.cs | 16 +++++++++++++--- .../IdeCoreBenchmarks/NavigateToBenchmarks.cs | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index 861958153569c..b10095a3bff21 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs @@ -62,16 +62,26 @@ private static async Task FindSearchResultsAsync( { // If the user created a dotted pattern then we'll grab the last part of the name var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern); - // Prioritize the active documents if we have any. - var allDocs = await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + // Prioritize the active documents if we have any. var highPriDocs = priorityDocuments.Where(d => project.ContainsDocument(d.Id)).ToSet(); - var lowPriDocs = allDocs.Where(d => !highPriDocs.Contains(d)).ToSet(); + + // Then process non-priority documents. + var lowPriDocs = project.Documents.Where(d => !highPriDocs.Contains(d)).ToSet(); var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, highPriDocs, cancellationToken).ConfigureAwait(false); await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, lowPriDocs, cancellationToken).ConfigureAwait(false); + + // if the caller is only searching a single doc, and we already covered it above, don't bother computing + // source-generator docs. + if (searchDocument != null && (highPriDocs.Contains(searchDocument) || lowPriDocs.Contains(searchDocument))) + return; + + // Finally, generate and process and source-generated docs. + var generatedDocs = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocs, cancellationToken).ConfigureAwait(false); } private static async Task ProcessDocumentsAsync( diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 38ba8d4c90683..5315378a1103e 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -89,6 +89,7 @@ public async Task RunNavigateTo() watch.Stop(); var sum = result.Sum(); Console.WriteLine($"Found {sum} results in {watch.ElapsedMilliseconds}"); + Console.ReadLine(); } private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) From 504954e0cdd84ee09393523cc86c2ec5ed8b8955 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 19:59:11 -0700 Subject: [PATCH 014/145] doc --- .../AbstractNavigateToSearchService.InProcess.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index b10095a3bff21..cc8fa74091749 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs @@ -80,8 +80,15 @@ private static async Task FindSearchResultsAsync( return; // Finally, generate and process and source-generated docs. + var stopWatch = new Stopwatch(); + stopWatch.Start(); var generatedDocs = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); - await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocs, cancellationToken).ConfigureAwait(false); + stopWatch.Stop(); + + var generatedDocsSet = generatedDocs.ToSet(); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocsSet, cancellationToken).ConfigureAwait(false); + + Console.WriteLine($"SG time: {project.Name}, count:{generatedDocsSet.Count} - {stopWatch.ElapsedMilliseconds}"); } private static async Task ProcessDocumentsAsync( From 66ed602d4ab638b9371cd8b197b22205d81ef4ca Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 20:00:52 -0700 Subject: [PATCH 015/145] cleanup --- ...stractNavigateToSearchService.InProcess.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index cc8fa74091749..0e8d15787acbe 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs @@ -63,15 +63,14 @@ private static async Task FindSearchResultsAsync( // If the user created a dotted pattern then we'll grab the last part of the name var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern); + var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); + // Prioritize the active documents if we have any. var highPriDocs = priorityDocuments.Where(d => project.ContainsDocument(d.Id)).ToSet(); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, highPriDocs, cancellationToken).ConfigureAwait(false); // Then process non-priority documents. var lowPriDocs = project.Documents.Where(d => !highPriDocs.Contains(d)).ToSet(); - - var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); - - await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, highPriDocs, cancellationToken).ConfigureAwait(false); await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, lowPriDocs, cancellationToken).ConfigureAwait(false); // if the caller is only searching a single doc, and we already covered it above, don't bother computing @@ -79,16 +78,10 @@ private static async Task FindSearchResultsAsync( if (searchDocument != null && (highPriDocs.Contains(searchDocument) || lowPriDocs.Contains(searchDocument))) return; - // Finally, generate and process and source-generated docs. - var stopWatch = new Stopwatch(); - stopWatch.Start(); + // Finally, generate and process and source-generated docs. this may take some time, so we always want to + // do this after the other documents. var generatedDocs = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); - stopWatch.Stop(); - - var generatedDocsSet = generatedDocs.ToSet(); - await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocsSet, cancellationToken).ConfigureAwait(false); - - Console.WriteLine($"SG time: {project.Name}, count:{generatedDocsSet.Count} - {stopWatch.ElapsedMilliseconds}"); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocs.ToSet(), cancellationToken).ConfigureAwait(false); } private static async Task ProcessDocumentsAsync( From addf5d42087b156087f0ef4f18c9a4882ef53c8e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 20:02:05 -0700 Subject: [PATCH 016/145] revert --- .../IdeCoreBenchmarks/NavigateToBenchmarks.cs | 21 ++++++------------- src/Tools/IdeCoreBenchmarks/Program.cs | 10 +++------ .../AbstractPersistentStorageService.cs | 3 --- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 5315378a1103e..95d25ea3856d2 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -32,8 +31,8 @@ public class NavigateToBenchmarks public NavigateToBenchmarks() { - // var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); - _solutionPath = @"C:\github\roslyn\Roslyn.sln"; + var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); + _solutionPath = Path.Combine(roslynRoot, @"C:\github\roslyn\Compilers.sln"); if (!File.Exists(_solutionPath)) throw new ArgumentException("Couldn't find Roslyn.sln"); @@ -75,38 +74,30 @@ public void Cleanup() [Benchmark] public async Task RunNavigateTo() { - Console.WriteLine("Press enter"); - Console.ReadLine(); - var solution = _workspace.CurrentSolution; - var watch = new Stopwatch(); - watch.Start(); // Search each project with an independent threadpool task. var searchTasks = solution.Projects.Select( p => Task.Run(() => SearchAsync(p, priorityDocuments: ImmutableArray.Empty), CancellationToken.None)).ToArray(); var result = await Task.WhenAll(searchTasks).ConfigureAwait(false); - watch.Stop(); var sum = result.Sum(); - Console.WriteLine($"Found {sum} results in {watch.ElapsedMilliseconds}"); - Console.ReadLine(); } private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) { var service = project.LanguageServices.GetService(); var results = new List(); - - var count = 0; await service.SearchProjectAsync( project, priorityDocuments, "Document", service.KindsProvided, r => { - Interlocked.Increment(ref count); + lock (results) + results.Add(r); + return Task.CompletedTask; }, CancellationToken.None); - return count; + return results.Count; } } } diff --git a/src/Tools/IdeCoreBenchmarks/Program.cs b/src/Tools/IdeCoreBenchmarks/Program.cs index 48238298f9325..3b127855370dc 100644 --- a/src/Tools/IdeCoreBenchmarks/Program.cs +++ b/src/Tools/IdeCoreBenchmarks/Program.cs @@ -8,7 +8,6 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; -using System.Threading.Tasks; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Running; @@ -38,13 +37,10 @@ public static string GetRoslynRootLocation([CallerFilePath] string sourceFilePat return Path.Combine(Path.GetDirectoryName(sourceFilePath), @"..\..\.."); } - private static async Task Main(string[] args) + private static void Main(string[] args) { - var b = new NavigateToBenchmarks(); - b.Setup(); - await b.RunNavigateTo(); - //Environment.SetEnvironmentVariable(RoslynRootPathEnvVariableName, GetRoslynRootLocation()); - //new BenchmarkSwitcher(typeof(Program).Assembly).Run(args); + Environment.SetEnvironmentVariable(RoslynRootPathEnvVariableName, GetRoslynRootLocation()); + new BenchmarkSwitcher(typeof(Program).Assembly).Run(args); } } } diff --git a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs index a8886ce92f93a..75d04b04128e8 100644 --- a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs @@ -102,7 +102,6 @@ internal async ValueTask GetStorageWorkerAsync( } var storage = await CreatePersistentStorageAsync(solutionKey, workingFolder).ConfigureAwait(false); - Contract.ThrowIfTrue(storage is NoOpPersistentStorage); Contract.ThrowIfNull(storage); // Create and cache a new storage instance associated with this particular solution. @@ -160,14 +159,12 @@ await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureA private async ValueTask TryCreatePersistentStorageAsync(SolutionKey solutionKey, string workingFolderPath) { var databaseFilePath = GetDatabaseFilePath(workingFolderPath); - Console.WriteLine("DB path: " + workingFolderPath); try { return await TryOpenDatabaseAsync(solutionKey, workingFolderPath, databaseFilePath).ConfigureAwait(false); } catch (Exception ex) { - Console.WriteLine($"TryCreatePersistentStorageAsync: {ex}"); StorageDatabaseLogger.LogException(ex); if (ShouldDeleteDatabase(ex)) From 045c50ca1ddf590833bab1f32ffbc6c55657f266 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 20:02:47 -0700 Subject: [PATCH 017/145] revert --- .../Storage/SQLite/AbstractSQLitePersistentStorageService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs index e061ddfd17912..3571e6369a217 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/AbstractSQLitePersistentStorageService.cs @@ -29,7 +29,6 @@ private static bool TryInitializeLibrariesLazy() } catch (Exception e) when (e is DllNotFoundException || e is EntryPointNotFoundException) { - Console.WriteLine($"TryInitializeLibrariesLazy: {e}"); StorageDatabaseLogger.LogException(e); return false; } From 352eb04857534cedd98faf25d674d7e31100682c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 26 Mar 2021 20:06:42 -0700 Subject: [PATCH 018/145] Extract method --- ...stractNavigateToSearchService.InProcess.cs | 73 +++++-------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index 0e8d15787acbe..01ab339092eec 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs @@ -96,71 +96,36 @@ private static async Task ProcessDocumentsAsync( continue; cancellationToken.ThrowIfCancellationRequested(); - tasks.Add(Task.Run(async () => - { - var containerMatcherOpt = patternContainerOpt != null - ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainerOpt) - : null; - - using var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); - using var _1 = containerMatcherOpt; - using var _2 = ArrayBuilder.GetInstance(out var nameMatches); - using var _3 = ArrayBuilder.GetInstance(out var containerMatches); - - var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); - - foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos) - { - await AddResultIfMatchAsync( - document, declaredSymbolInfo, - nameMatcher, containerMatcherOpt, - kinds, - nameMatches, containerMatches, - onResultFound, cancellationToken).ConfigureAwait(false); - } - }, cancellationToken)); + tasks.Add(Task.Run(() => + ProcessDocumentAsync(document, patternName, patternContainerOpt, kinds, onResultFound, cancellationToken), cancellationToken)); } await Task.WhenAll(tasks).ConfigureAwait(false); } - private static async Task ComputeSearchResultsAsync( - Project project, ImmutableArray priorityDocuments, Document searchDocument, - PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt, - DeclaredSymbolInfoKindSet kinds, - ArrayBuilder nameMatches, ArrayBuilder containerMatches, + private static async Task ProcessDocumentAsync( + Document document, string patternName, string patternContainerOpt, DeclaredSymbolInfoKindSet kinds, Func onResultFound, CancellationToken cancellationToken) { - // Prioritize the active documents if we have any. - var highPriDocs = priorityDocuments.WhereAsArray(d => project.ContainsDocument(d.Id)); - - var highPriDocsSet = highPriDocs.ToSet(); - var lowPriDocs = (await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false)) - .Where(d => !highPriDocsSet.Contains(d)); + var containerMatcherOpt = patternContainerOpt != null + ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainerOpt) + : null; - var orderedDocs = highPriDocs.AddRange(lowPriDocs); + using var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); + using var _1 = containerMatcherOpt; + using var _2 = ArrayBuilder.GetInstance(out var nameMatches); + using var _3 = ArrayBuilder.GetInstance(out var containerMatches); - Debug.Assert(priorityDocuments.All(d => project.ContainsDocument(d.Id)), "Priority docs included doc not from project."); - Debug.Assert(orderedDocs.Distinct().Length == orderedDocs.Length, "Ordered list contained a duplicate!"); - Debug.Assert(project.Documents.All(d => orderedDocs.Contains(d)), "At least one document from the project was missing from the ordered list!"); + var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); - foreach (var document in orderedDocs) + foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos) { - if (searchDocument != null && document != searchDocument) - continue; - - cancellationToken.ThrowIfCancellationRequested(); - var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); - - foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos) - { - await AddResultIfMatchAsync( - document, declaredSymbolInfo, - nameMatcher, containerMatcherOpt, - kinds, - nameMatches, containerMatches, - onResultFound, cancellationToken).ConfigureAwait(false); - } + await AddResultIfMatchAsync( + document, declaredSymbolInfo, + nameMatcher, containerMatcherOpt, + kinds, + nameMatches, containerMatches, + onResultFound, cancellationToken).ConfigureAwait(false); } } From a0cb6713e417f263495355809b844976375f1582 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sat, 27 Mar 2021 00:01:45 -0700 Subject: [PATCH 019/145] use set equality --- .../Symbols/WorkspaceSymbolsTests.cs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs index 6355eaa3a6487..13713c94431b0 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs @@ -3,10 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Roslyn.Test.Utilities; using Xunit; @@ -16,6 +16,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Symbols { public class WorkspaceSymbolsTests : AbstractLanguageServerProtocolTests { + private static void AssertSetEquals(LSP.SymbolInformation[] expected, LSP.SymbolInformation[] results) + => Assert.True(expected.ToHashSet().SetEquals(results)); + [Fact] public async Task TestGetWorkspaceSymbolsAsync_Class() { @@ -33,7 +36,7 @@ void M() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "A").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -59,8 +62,7 @@ void M() Assert.Null(results); results = progress.GetValues().ToArray(); - - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -80,7 +82,7 @@ public async Task TestGetWorkspaceSymbolsAsync_Method() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "M").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact(Skip = "GetWorkspaceSymbolsAsync does not yet support locals.")] @@ -103,7 +105,7 @@ void M() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "i").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -131,7 +133,7 @@ class {|class:F|} }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "F").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -161,7 +163,7 @@ public async Task TestGetWorkspaceSymbolsAsync_MultipleDocuments() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "M").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -195,7 +197,7 @@ End Sub }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "A").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } private static async Task RunGetWorkspaceSymbolsAsync(TestLspServer testLspServer, string query, IProgress? progress = null) From fa8bb76b3ba60ee1020acb4229b41960347a259c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sat, 27 Mar 2021 13:10:33 -0700 Subject: [PATCH 020/145] Fix conversion completion with a following variable declaration. --- .../ConversionCompletionProviderTests.cs | 5 ++--- .../CSharpRecommendationServiceRunner.cs | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs index 043bdd78b4f23..3e34ea5c568b2 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; using Microsoft.CodeAnalysis.Test.Utilities; @@ -147,12 +146,12 @@ public static void Main() [InlineData("c?.$$", true)] [InlineData("((C)c).$$", true)] [InlineData("(true ? c : c).$$", true)] - [InlineData("c.$$ var x=0;", false)] + [InlineData("c.$$ var x=0;", true)] public async Task ExplicitUserDefinedConversionDifferentExpressions(string expression, bool shouldSuggestConversion) { Func verifyFunc = shouldSuggestConversion ? (markup, expectedItem) => VerifyItemExistsAsync(markup, expectedItem, displayTextPrefix: "(", displayTextSuffix: ")") - : (markup, expectedItem) => VerifyItemIsAbsentAsync(markup, expectedItem); + : (markup, expectedItem) => VerifyItemIsAbsentAsync(markup, expectedItem, displayTextPrefix: "(", displayTextSuffix: ")"); await verifyFunc(@$" public class C diff --git a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs index 12d497e6061eb..d6f046528d5a2 100644 --- a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs +++ b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs @@ -273,9 +273,7 @@ private RecommendedSymbols GetSymbolsOffOfName(NameSyntax name) // // Here "stringList.await" is thought of as the return type of a local function. - if (name.IsFoundUnder(d => d.ReturnType) || - name.IsFoundUnder(d => d.Declaration.Type) || - name.IsFoundUnder(d => d.Declaration.Type)) + if (ShouldBeTreatedAsTypeInsteadOfExpression(name)) { var speculativeBinding = _context.SemanticModel.GetSpeculativeSymbolInfo( name.SpanStart, name, SpeculativeBindingOption.BindAsExpression); @@ -330,6 +328,13 @@ private RecommendedSymbols GetSymbolsOffOfName(NameSyntax name) return default; } + private static bool ShouldBeTreatedAsTypeInsteadOfExpression(ExpressionSyntax name) + { + return name.IsFoundUnder(d => d.ReturnType) || + name.IsFoundUnder(d => d.Declaration.Type) || + name.IsFoundUnder(d => d.Declaration.Type); + } + private RecommendedSymbols GetSymbolsOffOfExpression(ExpressionSyntax? originalExpression) { if (originalExpression == null) @@ -500,7 +505,7 @@ private ImmutableArray GetUnnamedSymbols(ExpressionSyntax originalExpre using var _ = ArrayBuilder.GetInstance(out var symbols); var semanticModel = _context.SemanticModel; - var container = semanticModel.GetTypeInfo(originalExpression, _cancellationToken).Type; + var container = GetContainerForUnnamedSymbols(semanticModel, originalExpression); if (container == null) return ImmutableArray.Empty; @@ -517,6 +522,13 @@ private ImmutableArray GetUnnamedSymbols(ExpressionSyntax originalExpre return symbols.ToImmutable(); } + private ITypeSymbol? GetContainerForUnnamedSymbols(SemanticModel semanticModel, ExpressionSyntax originalExpression) + { + return ShouldBeTreatedAsTypeInsteadOfExpression(originalExpression) + ? _context.SemanticModel.GetSpeculativeTypeInfo(originalExpression.SpanStart, originalExpression, SpeculativeBindingOption.BindAsExpression).Type + : semanticModel.GetTypeInfo(originalExpression, _cancellationToken).Type; + } + private void AddIndexers(ITypeSymbol container, ArrayBuilder symbols) { var containingType = _context.SemanticModel.GetEnclosingNamedType(_context.Position, _cancellationToken); From c4bee72e607e0a32422c1c008fa66ad3afb7947e Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Sun, 28 Mar 2021 08:52:12 -0700 Subject: [PATCH 021/145] Remove obsolete test helpers (#52195) --- .../Test/Semantic/Semantics/LambdaTests.cs | 10 +++--- .../Utilities/CSharp/CompilingTestBase.cs | 24 ------------- .../CSharp/DiagnosticTestUtilities.cs | 35 ------------------- 3 files changed, 5 insertions(+), 64 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 4e1e3a02e33f6..b8b457c0e01bb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class LambdaTests : CompilingTestBase + public class LambdaTests : CSharpTestBase { [Fact, WorkItem(37456, "https://github.com/dotnet/roslyn/issues/37456")] public void Verify37456() @@ -568,10 +568,10 @@ static void Main() "; var vbMetadata = vbProject.EmitToArray(options: new EmitOptions(metadataOnly: true)); var csProject = CreateCompilation(Parse(csSource), new[] { MetadataReference.CreateFromImage(vbMetadata) }); - - var diagnostics = csProject.GetDiagnostics().Select(DumpDiagnostic); - Assert.Equal(1, diagnostics.Count()); - Assert.Equal("'x' error CS0721: 'GC': static types cannot be used as parameters", diagnostics.First()); + csProject.VerifyDiagnostics( + // (6,15): error CS0721: 'GC': static types cannot be used as parameters + // M.F = x=>{}; + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "x").WithArguments("System.GC").WithLocation(6, 15)); } [WorkItem(540251, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540251")] diff --git a/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs index 55d03fb0613dd..d9896abd7721c 100644 --- a/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs @@ -5,11 +5,9 @@ #nullable disable using System; -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Roslyn.Test.Utilities; @@ -43,28 +41,6 @@ internal static BoundBlock ParseAndBindMethodBody(string program, string typeNam return block; } - public static string DumpDiagnostic(Diagnostic diagnostic) - { - return string.Format("'{0}' {1}", - diagnostic.Location.SourceTree.GetText().ToString(diagnostic.Location.SourceSpan), - DiagnosticFormatter.Instance.Format(diagnostic.WithLocation(Location.None), EnsureEnglishUICulture.PreferredOrNull)); - } - - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnostics(IEnumerable diagnostics, params string[] diagStrings) - { - AssertEx.SetEqual(diagStrings, diagnostics.Select(DumpDiagnostic)); - } - - // Do a full compilation and check all the errors. - [Obsolete("Use VerifyDiagnostics", true)] - public void TestAllErrors(string code, params string[] errors) - { - var compilation = CreateCompilation(code); - var diagnostics = compilation.GetDiagnostics(); - AssertEx.SetEqual(errors, diagnostics.Select(DumpDiagnostic)); - } - public const string LINQ = #region the string LINQ defines a complete LINQ API called List1 (for instance method) and List2 (for extension methods) @"using System; diff --git a/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs b/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs index e074dc75115b7..586c80e12437c 100644 --- a/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs +++ b/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs @@ -7,10 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -33,38 +30,6 @@ public override string ToString() public abstract class DiagnosticsUtils { - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - public static void VerifyErrorCodes(CSharpCompilation comp, params ErrorDescription[] expectedErrors) - { - var actualErrors = comp.GetDiagnostics(); - DiagnosticsUtils.VerifyErrorCodes(actualErrors, expectedErrors); - } - - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnostics(string source, params string[] diagStrings) - { - var comp = CSharpTestBase.CreateCompilation(source); - var diagnostics = comp.GetDiagnostics(); - CompilingTestBase.TestDiagnostics(diagnostics, diagStrings); - } - - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnosticsExact(string source, params string[] diagStrings) - { - var comp = CSharpTestBase.CreateCompilation(source); - var diagnostics = comp.GetDiagnostics(); - Assert.Equal(diagStrings.Length, diagnostics.Length); - CompilingTestBase.TestDiagnostics(diagnostics, diagStrings); - } - /// /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. /// From faf7c13acd548e6b9fc913f2349c3c07030cb113 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Tue, 5 Jan 2021 16:27:42 -0800 Subject: [PATCH 022/145] Add UI for editorconfig files --- .gitignore | 1 + .../InternalUtilities/ConcurrentLruCache.cs | 2 +- src/Compilers/Test/Core/Traits/Traits.cs | 1 + .../CSharp/CSharpEditorResources.resx | 252 ++++++++ ...CodeStyleSettingsLanguageServiceFactory.cs | 30 + .../CSharpCodeStyleSettingsProvider.cs | 226 +++++++ .../CSharpCodeStyleSettingsProviderFactory.cs | 21 + ...ormattingSettingsLanguageServiceFactory.cs | 30 + .../CSharpFormattingSettingsProvider.cs | 108 ++++ ...CSharpFormattingSettingsProviderFactory.cs | 27 + .../CSharp/xlf/CSharpEditorResources.cs.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.de.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.es.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.fr.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.it.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.ja.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.ko.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.pl.xlf | 420 +++++++++++++ .../xlf/CSharpEditorResources.pt-BR.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.ru.xlf | 420 +++++++++++++ .../CSharp/xlf/CSharpEditorResources.tr.xlf | 420 +++++++++++++ .../xlf/CSharpEditorResources.zh-Hans.xlf | 420 +++++++++++++ .../xlf/CSharpEditorResources.zh-Hant.xlf | 420 +++++++++++++ .../SettingsUpdater/SettingsUpdaterTests.cs | 323 ++++++++++ ...oft.CodeAnalysis.EditorFeatures.Wpf.csproj | 2 - .../Aggregator/ISettingsAggregator.cs | 14 + .../Aggregator/SettingsAggregator.cs | 99 ++++ .../Aggregator/SettingsAggregatorFactory.cs | 25 + .../Data/AnalyzerSetting.cs | 56 ++ ...odeStyleSetting.BooleanCodeStyleSetting.cs | 57 ++ ...tyleSetting.BooleanCodeStyleSettingBase.cs | 39 ++ .../CodeStyleSetting.EnumCodeStyleSetting.cs | 58 ++ ...deStyleSetting.EnumCodeStyleSettingBase.cs | 41 ++ ...ting.PerLanguageBooleanCodeStyleSetting.cs | 57 ++ ...Setting.PerLanguageEnumCodeStyleSetting.cs | 60 ++ .../Data/CodeStyle/CodeStyleSetting.cs | 96 +++ .../Data/Formatting/FormattingSetting.cs | 52 ++ .../Data/Formatting/FormattingSetting`1.cs | 59 ++ .../PerLanguageFormattingSetting.cs | 59 ++ .../Analyzer/AnalyzerSettingsProvider.cs | 90 +++ .../AnalyzerSettingsProviderFactory.cs | 28 + ...AnalyzerSettingsWorkspaceServiceFactory.cs | 29 + .../CommonCodeStyleSettingsProvider.cs | 190 ++++++ .../CommonCodeStyleSettingsProviderFactory.cs | 19 + ...odeStyleSettingsWorkspaceServiceFactory.cs | 23 + .../CombinedOptionsProviderFactory.cs | 30 + .../DataProvider/CombinedProvider.cs | 59 ++ .../CommonFormattingSettingsProvider.cs | 40 ++ ...CommonFormattingSettingsProviderFactory.cs | 20 + ...rmattingSettingsWorkspaceServiceFactory.cs | 23 + .../ILanguageSettingsProviderFactory.cs | 12 + .../DataProvider/ISettingsProvider.cs | 18 + .../DataProvider/ISettingsProviderFactory.cs | 11 + .../IWorkspaceSettingsProviderFactory.cs | 12 + .../DataProvider/SettingsProviderBase.cs | 103 ++++ .../Extensions/EnumerableExtensions.cs | 24 + .../Extensions/SolutionExtensions.cs | 54 ++ .../ISettingsEditorViewModel.cs | 16 + .../Core/EditorConfigSettings/Language.cs | 15 + .../Updater/AnalyzerSettingsUpdater.cs | 24 + .../Updater/ISettingUpdater.cs | 17 + .../Updater/OptionUpdater.cs | 26 + .../Updater/SettingsUpdateHelper.cs | 374 ++++++++++++ .../Updater/SettingsUpdaterBase.cs | 66 +++ .../Core/EditorFeaturesResources.resx | 120 ++++ .../Core/xlf/EditorFeaturesResources.cs.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.de.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.es.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.fr.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.it.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.ja.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.ko.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.pl.xlf | 200 +++++++ .../xlf/EditorFeaturesResources.pt-BR.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.ru.xlf | 200 +++++++ .../Core/xlf/EditorFeaturesResources.tr.xlf | 200 +++++++ .../xlf/EditorFeaturesResources.zh-Hans.xlf | 200 +++++++ .../xlf/EditorFeaturesResources.zh-Hant.xlf | 200 +++++++ .../BinaryOperatorSpacingOptionsViewModel.cs | 44 ++ ...yOperatorSpacingOptionsViewModelFactory.cs | 32 + .../LabelPositionOptionsViewModel.cs | 67 +++ ...isualStudio.LanguageServices.CSharp.csproj | 15 +- .../Analyzers/View/AnalyzerSettingsView.xaml | 17 + .../View/AnalyzerSettingsView.xaml.cs | 49 ++ .../AnalyzerCategoryColumnDefinition.cs | 56 ++ .../AnalyzerDescriptionColumnDefinition.cs | 29 + .../AnalyzerEnabledColumnDefinition.cs | 44 ++ .../AnalyzerIdColumnDefinition.cs | 29 + .../AnalyzerSeverityColumnDefinition.cs | 45 ++ .../AnalyzerTitleColumnDefinition.cs | 30 + .../Analyzers/View/SeverityControl.xaml | 10 + .../Analyzers/View/SeverityControl.xaml.cs | 119 ++++ ...ttingsViewModel.SettingsEntriesSnapshot.cs | 37 ++ ...ttingsViewModel.SettingsSnapshotFactory.cs | 25 + .../ViewModel/AnalyzerSettingsViewModel.cs | 53 ++ .../CodeStyle/View/CodeStyleSettingsView.xaml | 16 + .../View/CodeStyleSettingsView.xaml.cs | 50 ++ .../View/CodeStyleSeverityControl.xaml | 10 + .../View/CodeStyleSeverityControl.xaml.cs | 119 ++++ .../CodeStyle/View/CodeStyleValueControl.xaml | 10 + .../View/CodeStyleValueControl.xaml.cs | 39 ++ .../CodeStyleCategoryColumnDefinition.cs | 55 ++ .../CodeStyleDescriptionColumnDefinition.cs | 29 + .../CodeStyleSeverityColumnDefinition.cs | 46 ++ .../CodeStyleValueColumnDefinition.cs | 46 ++ ...ttingsViewModel.SettingsEntriesSnapshot.cs | 32 + ...ttingsViewModel.SettingsSnapshotFactory.cs | 22 + .../ViewModel/CodeStyleSettingsViewModel.cs | 49 ++ .../Common/ColumnDefinitions.cs | 39 ++ .../Common/EditorTextUpdater.cs | 37 ++ .../Common/EnumPropertyView.xaml | 11 + .../Common/EnumPropertyView.xaml.cs | 45 ++ .../Common/EnumSettingViewModel.cs | 42 ++ .../Common/IEnumSettingViewModel.cs | 14 + .../Common/IEnumSettingViewModelFactory.cs | 15 + .../Common/RemoveSinkWhenDisposed.cs | 29 + .../Common/SettingsEntriesSnapshotBase.cs | 55 ++ .../Common/SettingsSnapshotFactoryBase.cs | 73 +++ .../Common/SettingsViewModelBase.cs | 82 +++ .../FormattingCategoryColumnDefinition.cs | 56 ++ .../FormattingDescriptionColumnDefinition.cs | 29 + .../FormattingValueColumnDefinition.cs | 66 +++ .../View/FormattingBoolSettingView.xaml | 10 + .../View/FormattingBoolSettingView.xaml.cs | 41 ++ .../View/FormattingSettingsView.xaml | 18 + .../View/FormattingSettingsView.xaml.cs | 49 ++ ...attingViewModel.SettingsEntriesSnapshot.cs | 31 + ...attingViewModel.SettingsSnapshotFactory.cs | 22 + .../ViewModel/FormattingViewModel.cs | 47 ++ .../ViewModel/IndentationSizeViewModel.cs | 125 ++++ .../Formatting/ViewModel/NewLineViewModel.cs | 97 +++ .../Formatting/ViewModel/TabSizeViewModel.cs | 124 ++++ .../ISettingsEditorView.cs | 16 + .../IWpfSettingsEditorViewModel.cs | 14 + .../ServiceProviderExtensions.cs | 33 ++ .../SettingsEditorControl.xaml | 26 + .../SettingsEditorControl.xaml.cs | 52 ++ .../SettingsEditorFactory.cs | 161 +++++ .../SettingsEditorPane.cs | 556 ++++++++++++++++++ .../Styles/FontSizeConverter.cs | 20 + .../Styles/ThemedDialogResources.xaml | 85 +++ ...osoft.VisualStudio.LanguageServices.csproj | 5 +- .../Core/Def/PackageRegistration.pkgdef | 11 + src/VisualStudio/Core/Def/RoslynPackage.cs | 4 + .../Core/Def/ServicesVSResources.resx | 51 ++ .../Core/Def/xlf/ServicesVSResources.cs.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.de.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.es.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.fr.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.it.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.ja.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.ko.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.pl.xlf | 85 +++ .../Def/xlf/ServicesVSResources.pt-BR.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.ru.xlf | 85 +++ .../Core/Def/xlf/ServicesVSResources.tr.xlf | 85 +++ .../Def/xlf/ServicesVSResources.zh-Hans.xlf | 85 +++ .../Def/xlf/ServicesVSResources.zh-Hant.xlf | 85 +++ .../Workspace/Solution/ProjectState.cs | 8 +- .../DiagnosticDescriptorExtensions.cs | 44 ++ 160 files changed, 15851 insertions(+), 19 deletions(-) create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs create mode 100644 src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/CSharpTest/SettingsUpdater/SettingsUpdaterTests.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Language.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs create mode 100644 src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs create mode 100644 src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs create mode 100644 src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs create mode 100644 src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerCategoryColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerDescriptionColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerEnabledColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerIdColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerTitleColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsSnapshotFactory.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleCategoryColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleDescriptionColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleSeverityColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleValueColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsSnapshotFactory.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/ColumnDefinitions.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModelFactory.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/RemoveSinkWhenDisposed.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsEntriesSnapshotBase.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsSnapshotFactoryBase.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingCategoryColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingDescriptionColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingValueColumnDefinition.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsEntriesSnapshot.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsSnapshotFactory.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/IndentationSizeViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/NewLineViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/TabSizeViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/ISettingsEditorView.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/IWpfSettingsEditorViewModel.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/ServiceProviderExtensions.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorFactory.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorPane.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Styles/FontSizeConverter.cs create mode 100644 src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml diff --git a/.gitignore b/.gitignore index 834c624643c68..c099dad0050ec 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # User-specific files *.suo +*.svclog *.user *.userprefs *.sln.docstates diff --git a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs index 579c982671bf0..15fe814d1144b 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs @@ -87,7 +87,7 @@ public void Add(K key, V value) private void MoveNodeToTop(LinkedListNode node) { - if (!object.ReferenceEquals(_nodeList.First, node)) + if (!ReferenceEquals(_nodeList.First, node)) { _nodeList.Remove(node); _nodeList.AddFirst(node); diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index 2b72c0685c0ab..b21f3558c22ba 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -227,6 +227,7 @@ public static class Features public const string DocCommentFormatting = nameof(DocCommentFormatting); public const string DocumentationComments = nameof(DocumentationComments); public const string EditorConfig = nameof(EditorConfig); + public const string EditorConfigUI = nameof(EditorConfigUI); public const string EncapsulateField = nameof(EncapsulateField); public const string EndConstructGeneration = nameof(EndConstructGeneration); public const string ErrorList = nameof(ErrorList); diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx index dc934ab12dff9..0ef15f4bbb662 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx @@ -182,4 +182,256 @@ Add Missing Usings on Paste "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + + + Avoid unused value assignments + + + Discard + + + Elsewhere + + + For built-in types + + + Ignore spaces in declaration statements + + + Indent block contents + + + Indent case contents + + + Indent case contents (when block) + + + Indent case labels + + + Indent open and close braces + + + Insert spaces within parentheses of control flow statements + + + Insert spaces within square brackets + + + Insert space after cast + + + Insert space after colon for base or interface in type declaration + + + Insert space after comma + + + Insert space after dot + + + Insert space after keywords in control flow statements + + + Insert space after semicolon in "for" statement + + + Insert space before colon for base or interface in type declaration + + + Insert space before comma + + + Insert space before dot + + + Insert space before open square bracket + + + Insert space before semicolon in "for" statement + + + Insert space between method name and its opening parenthesis + + + Insert space between method name and its opening parenthesis + + + Insert space within argument list parentheses + + + Insert space within empty argument list parentheses + + + Insert space within empty parameter list parentheses + + + Insert space within empty square brackets + + + Insert space within parameter list parentheses + + + Insert space within parentheses of expressions + + + Insert space within parentheses of type casts + + + Inside namespace + + + Label Indentation + + + Leave block on single line + + + Leave statements and member declarations on the same line + + + Never + + + Place "catch" on new line + + + Place "else" on new line + + + Place "finally" on new line + + + Place members in anonymous types on new line + + + Place members in object initializers on new line + + + Place open brace on new line for anonymous methods + + + Place open brace on new line for anonymous types + + + Place open brace on new line for control blocks + + + Place open brace on new line for lambda expression + + + Place open brace on new line for methods and local functions + + + Place open brace on new line for object, collection, array, and with initializers + + + Place open brace on new line for properties, indexers, and events + + + Place open brace on new line for property, indexer, and event accessors + + + Place open brace on new line for types + + + Place query expression clauses on new line + + + Preferred 'using' directive placement + + + Prefer conditional delegate call + + + Prefer deconstructed variable declaration + + + Prefer explicit type + + + Prefer index operator + + + Prefer inlined variable declaration + + + Prefer local function over anonymous function + + + Prefer pattern matching + + + Prefer pattern matching over 'as' with 'null' check + + + Prefer pattern matching over 'is' with 'cast' check + + + Prefer pattern matching over mixed type check + + + Prefer range operator + + + Prefer simple 'default' expression + + + Prefer simple 'using' statement + + + Prefer static local functions + + + Prefer switch expression + + + Prefer throw-expression + + + Prefer 'var' + + + Set spacing for operators + + + Unused local + + + Use expression body for accessors + + + Use expression body for constructors + + + Use expression body for indexers + + + Use expression body for lambdas + + + Use expression body for local functions + + + Use expression body for methods + + + Use expression body for operators + + + Use expression body for properties + + + When on single line + + + When possible + + + When variable type is apparent + \ No newline at end of file diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs new file mode 100644 index 0000000000000..b4ffb45e574f0 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] + internal class CSharpCodeStyleSettingsLanguageServiceFactory : ILanguageServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpCodeStyleSettingsLanguageServiceFactory() + { + } + + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + { + var workspace = languageServices.WorkspaceServices.Workspace; + return new CSharpCodeStyleSettingsProviderFactory(workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs new file mode 100644 index 0000000000000..b0011a4a84499 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -0,0 +1,226 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CSharpCodeStyleSettingsProvider : SettingsProviderBase + { + public CSharpCodeStyleSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) + : base(fileName, settingsUpdater, workspace) + { + } + + protected override Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + return Task.Run(() => + { + var varSettings = GetVarCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(varSettings); + + var usingSettings = GetUsingsCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(usingSettings); + + var modifierSettings = GetModifierCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(modifierSettings); + + var codeBlockSettings = GetCodeBlockCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(codeBlockSettings); + + var nullCheckingSettings = GetNullCheckingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(nullCheckingSettings); + + var expressionSettings = GetExpressionCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionSettings); + + var patternMatchingSettings = GetPatternMatchingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(patternMatchingSettings); + + var variableSettings = GetVariableCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(variableSettings); + + var expressionBodySettings = GetExpressionBodyCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionBodySettings); + + var unusedValueSettings = GetUnusedValueCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(unusedValueSettings); + }); + } + + private static IEnumerable GetVarCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarForBuiltInTypes, + description: CSharpEditorResources.For_built_in_types, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarWhenTypeIsApparent, + description: CSharpEditorResources.When_variable_type_is_apparent, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarElsewhere, + description: CSharpEditorResources.Elsewhere, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetUsingsCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create( + option: CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, + description: CSharpEditorResources.Preferred_using_directive_placement, + enumValues: new[] { AddImportPlacement.InsideNamespace, AddImportPlacement.OutsideNamespace }, + valueDescriptions: new[] { CSharpEditorResources.Inside_namespace }, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetNullCheckingCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferThrowExpression, + description: CSharpEditorResources.Prefer_throw_expression, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferConditionalDelegateCall, + description: CSharpEditorResources.Prefer_conditional_delegate_call, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetModifierCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferStaticLocalFunction, + description: CSharpEditorResources.Prefer_static_local_functions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetCodeBlockCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferSimpleUsingStatement, + description: CSharpEditorResources.Prefer_simple_using_statement, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetExpressionCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSwitchExpression, description: CSharpEditorResources.Prefer_switch_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, description: CSharpEditorResources.Prefer_simple_default_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction, description: CSharpEditorResources.Prefer_local_function_over_anonymous_function, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferIndexOperator, description: CSharpEditorResources.Prefer_index_operator, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferRangeOperator, description: CSharpEditorResources.Prefer_range_operator, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetPatternMatchingCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatching, description: CSharpEditorResources.Prefer_pattern_matching, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, description: CSharpEditorResources.Prefer_pattern_matching_over_is_with_cast_check, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, description: CSharpEditorResources.Prefer_pattern_matching_over_as_with_null_check, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferNotPattern, description: CSharpEditorResources.Prefer_pattern_matching_over_mixed_type_check, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetVariableCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration, description: CSharpEditorResources.Prefer_inlined_variable_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration, description: CSharpEditorResources.Prefer_deconstructed_variable_declaration, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetExpressionBodyCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + var enumValues = new[] { ExpressionBodyPreference.Never, ExpressionBodyPreference.WhenPossible, ExpressionBodyPreference.WhenOnSingleLine }; + var valueDescriptions = new[] { CSharpEditorResources.Never, CSharpEditorResources.When_possible, CSharpEditorResources.When_on_single_line }; + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedMethods, + description: CSharpEditorResources.Use_expression_body_for_methods, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, + description: CSharpEditorResources.Use_expression_body_for_constructors, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedOperators, + description: CSharpEditorResources.Use_expression_body_for_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedProperties, + description: CSharpEditorResources.Use_expression_body_for_properties, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, + description: CSharpEditorResources.Use_expression_body_for_indexers, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, + description: CSharpEditorResources.Use_expression_body_for_accessors, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, + description: CSharpEditorResources.Use_expression_body_for_lambdas, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions, + description: CSharpEditorResources.Use_expression_body_for_local_functions, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetUnusedValueCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + var enumValues = new[] + { + UnusedValuePreference.UnusedLocalVariable, + UnusedValuePreference.DiscardVariable + }; + + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueAssignment, + description: CSharpEditorResources.Avoid_unused_value_assignments, + enumValues, + new[] { CSharpEditorResources.Unused_local, CSharpEditorResources.Discard }, + editorConfigOptions, + visualStudioOptions, + updaterService); + + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueExpressionStatement, + description: CSharpEditorResources.Avoid_expression_statements_that_implicitly_ignore_value, + enumValues, + new[] { CSharpEditorResources.Unused_local, CSharpEditorResources.Discard }, + editorConfigOptions, + visualStudioOptions, + updaterService); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs new file mode 100644 index 0000000000000..1af8c72ade4d0 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CSharpCodeStyleSettingsProviderFactory : ILanguageSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CSharpCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CSharpCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs new file mode 100644 index 0000000000000..550c7bf77b32a --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] + internal class CSharpFormattingSettingsLanguageServiceFactory : ILanguageServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpFormattingSettingsLanguageServiceFactory() + { + } + + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + { + var workspace = languageServices.WorkspaceServices.Workspace; + return new CSharpFormattingSettingsProviderFactory(workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs new file mode 100644 index 0000000000000..faad3e4f0b221 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + internal class CSharpFormattingSettingsProvider : SettingsProviderBase + { + public CSharpFormattingSettingsProvider(string filePath, OptionUpdater updaterService, Workspace workspace) + : base(filePath, updaterService, workspace) + { + } + + protected override Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + return Task.Run(() => + { + var spacingOptions = GetSpacingOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(spacingOptions.ToImmutableArray()); + var newLineOptions = GetNewLineOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(newLineOptions.ToImmutableArray()); + var indentationOptions = GetIndentationOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(indentationOptions.ToImmutableArray()); + var wrappingOptions = GetWrappingOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(wrappingOptions.ToImmutableArray()); + }); + } + + private static IEnumerable GetSpacingOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, CSharpEditorResources.Insert_space_between_method_name_and_its_opening_parenthesis2, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis, CSharpEditorResources.Insert_space_within_parameter_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses, CSharpEditorResources.Insert_space_within_empty_parameter_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterMethodCallName, CSharpEditorResources.Insert_space_between_method_name_and_its_opening_parenthesis1, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, CSharpEditorResources.Insert_space_within_argument_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, CSharpEditorResources.Insert_space_within_empty_argument_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, CSharpEditorResources.Insert_space_after_keywords_in_control_flow_statements, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinExpressionParentheses, CSharpEditorResources.Insert_space_within_parentheses_of_expressions, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinCastParentheses, CSharpEditorResources.Insert_space_within_parentheses_of_type_casts, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinOtherParentheses, CSharpEditorResources.Insert_spaces_within_parentheses_of_control_flow_statements, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterCast, CSharpEditorResources.Insert_space_after_cast, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, CSharpEditorResources.Ignore_spaces_in_declaration_statements, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, CSharpEditorResources.Insert_space_before_open_square_bracket, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, CSharpEditorResources.Insert_space_within_empty_square_brackets, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinSquareBrackets, CSharpEditorResources.Insert_spaces_within_square_brackets, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration, CSharpEditorResources.Insert_space_after_colon_for_base_or_interface_in_type_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterComma, CSharpEditorResources.Insert_space_after_comma, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterDot, CSharpEditorResources.Insert_space_after_dot, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, CSharpEditorResources.Insert_space_after_semicolon_in_for_statement, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration, CSharpEditorResources.Insert_space_before_colon_for_base_or_interface_in_type_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeComma, CSharpEditorResources.Insert_space_before_comma, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeDot, CSharpEditorResources.Insert_space_before_dot, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, CSharpEditorResources.Insert_space_before_semicolon_in_for_statement, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacingAroundBinaryOperator, CSharpEditorResources.Set_spacing_for_operators, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetNewLineOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInTypes, CSharpEditorResources.Place_open_brace_on_new_line_for_types, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInMethods, CSharpEditorResources.Place_open_brace_on_new_line_for_methods_local_functions, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInProperties, CSharpEditorResources.Place_open_brace_on_new_line_for_properties_indexers_and_events, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAccessors, CSharpEditorResources.Place_open_brace_on_new_line_for_property_indexer_and_event_accessors, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, CSharpEditorResources.Place_open_brace_on_new_line_for_anonymous_methods, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, CSharpEditorResources.Place_open_brace_on_new_line_for_control_blocks, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, CSharpEditorResources.Place_open_brace_on_new_line_for_anonymous_types, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, CSharpEditorResources.Place_open_brace_on_new_line_for_object_collection_array_and_with_initializers, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody, CSharpEditorResources.Place_open_brace_on_new_line_for_lambda_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForElse, CSharpEditorResources.Place_else_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForCatch, CSharpEditorResources.Place_catch_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForFinally, CSharpEditorResources.Place_finally_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForMembersInObjectInit, CSharpEditorResources.Place_members_in_object_initializers_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, CSharpEditorResources.Place_members_in_anonymous_types_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForClausesInQuery, CSharpEditorResources.Place_query_expression_clauses_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetIndentationOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentBlock, CSharpEditorResources.Indent_block_contents, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentBraces, CSharpEditorResources.Indent_open_and_close_braces, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchCaseSection, CSharpEditorResources.Indent_case_contents, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock, CSharpEditorResources.Indent_case_contents_when_block, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchSection, CSharpEditorResources.Indent_case_labels, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.LabelPositioning, CSharpEditorResources.Label_Indentation, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetWrappingOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.WrappingPreserveSingleLine, CSharpEditorResources.Leave_block_on_single_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, CSharpEditorResources.Leave_statements_and_member_declarations_on_the_same_line, editorConfigOptions, visualStudioOptions, updaterService); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs new file mode 100644 index 0000000000000..543617276493a --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + internal class CSharpFormattingSettingsProviderFactory : ILanguageSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CSharpFormattingSettingsProviderFactory(Workspace workspace) + { + _workspace = workspace; + } + + public ISettingsProvider GetForFile(string filePath) + { + var updaterService = new OptionUpdater(_workspace, filePath); + return new CSharpFormattingSettingsProvider(filePath, updaterService, _workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf index a53460dd12507..1ecce93bffca1 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf @@ -12,6 +12,16 @@ Přidávají se chybějící direktivy using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Zvolená verze: {0} @@ -32,11 +42,26 @@ Protokol o dekompilaci + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Opravit interpolovaný doslovný řetězec + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Pro {1} se našlo několik ({0}) sestavení: @@ -62,6 +87,166 @@ Generovat odběr událostí + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Načíst z {0} @@ -72,6 +257,176 @@ Modul se nenašel! + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Pro vložení stiskněte TAB.) @@ -87,6 +442,11 @@ Přeložit modul: {0} z {1} + + Set spacing for operators + Set spacing for operators + + Smart Indenting Chytré odsazování @@ -97,11 +457,71 @@ Rozdělit řetězec + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' UPOZORNĚNÍ: Neshoda verzí. Očekáváno: {0}, získáno: {1} + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Počet položek v mezipaměti: {0} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf index 59b46f4f98c59..b7f4cfbedc988 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf @@ -12,6 +12,16 @@ Fehlende using-Anweisungen werden hinzugefügt... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Ausgewählte Version: {0} @@ -32,11 +42,26 @@ Dekompilierungsprotokoll + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Interpolierte ausführliche Zeichenfolge korrigieren + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': {0} Assemblys für "{1}" gefunden: @@ -62,6 +87,166 @@ Ereignisabonnement generieren + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Laden von: {0} @@ -72,6 +257,176 @@ Das Modul wurde nicht gefunden. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Zum Einfügen TAB-TASTE drücken) @@ -87,6 +442,11 @@ Modul auflösen: {0} von {1} + + Set spacing for operators + Set spacing for operators + + Smart Indenting Intelligenter Einzug @@ -97,11 +457,71 @@ Zeichenfolge teilen + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' WARNUNG: Versionskonflikt. Erwartet: "{0}", erhalten: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache {0} Elemente im Cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf index ac2c95c4042de..ac16e8d7f28f6 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf @@ -12,6 +12,16 @@ Agregando los valores using que faltan... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versión elegida: "{0}" @@ -32,11 +42,26 @@ Registro de descompilación + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corregir cadena textual interpolada + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Se encontraron "{0}" ensamblados para "{1}": @@ -62,6 +87,166 @@ Generar suscripción de eventos + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Cargar desde: "{0}" @@ -72,6 +257,176 @@ No se encontró el módulo. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Presione TAB para insertar) @@ -87,6 +442,11 @@ Resolver el módulo: "{0}" de "{1}" + + Set spacing for operators + Set spacing for operators + + Smart Indenting Sangría inteligente @@ -97,11 +457,71 @@ Dividir cadena + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVISO: No coinciden las versiones. Se esperaba "{0}", se obtuvo "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache "{0}" elementos en caché diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf index 507debfc81da8..69b966b155e4b 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf @@ -12,6 +12,16 @@ Ajout des usings manquants... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Version choisie : '{0}' @@ -32,11 +42,26 @@ Journal de décompilation + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corriger la chaîne verbatim interpolée + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{0}' assemblys trouvés pour '{1}' : @@ -62,6 +87,166 @@ Générer un abonnement à des événements + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Charger à partir de : '{0}' @@ -72,6 +257,176 @@ Module introuvable ! + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Appuyez sur TAB pour insérer) @@ -87,6 +442,11 @@ Résoudre le module '{0}' sur '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Retrait intelligent @@ -97,11 +457,71 @@ Fractionner la chaîne + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVERTISSEMENT : Incompatibilité de version. Attendu : '{0}'. Reçu : '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' éléments dans le cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf index b79f46f23136b..653caea88801f 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf @@ -12,6 +12,16 @@ Aggiunta di using mancanti... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versione selezionata: '{0}' @@ -32,11 +42,26 @@ Log di decompilazione + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Correggi stringa verbatim interpolata + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Sono stati trovati '{0}' assembly per '{1}': @@ -62,6 +87,166 @@ Genera sottoscrizione di eventi + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Carica da: '{0}' @@ -72,6 +257,176 @@ Modulo non trovato. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Premere TAB per inserire) @@ -87,6 +442,11 @@ Risolvi il modulo: '{0}' di '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Rientro automatico @@ -97,11 +457,71 @@ Dividi stringa + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVVISO: versione non corrispondente. Prevista: '{0}'. Ottenuta: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' elementi nella cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf index 3a15f023b5aa7..460ac93ec5332 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf @@ -12,6 +12,16 @@ 欠落している usings を追加しています... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 選択されたバージョン: '{0}' @@ -32,11 +42,26 @@ 逆コンパイルのログ + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 挿入された逐語的文字列を修正します + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}' の '{0}' 個のアセンブリが見つかりました: @@ -62,6 +87,166 @@ イベント サブスクリプションの生成 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 読み込み元: '{0}' @@ -72,6 +257,176 @@ モジュールが見つかりません + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Tab キーを押して挿入) @@ -87,6 +442,11 @@ モジュールの解決: '{1}' の '{0}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting スマート インデント @@ -97,11 +457,71 @@ 文字列を分割します + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: バージョンが一致しません。必要なバージョン: '{0}'、現在のバージョン: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache キャッシュ内の '{0}' 個の項目 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf index bd89b0cb2c745..e30f7380a154e 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf @@ -12,6 +12,16 @@ 누락된 using 추가 중... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 선택한 버전: '{0}' @@ -32,11 +42,26 @@ 디컴파일 로그 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 보간된 축자 문자열 수정 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}'의 어셈블리를 '{0}'개 찾았습니다. @@ -62,6 +87,166 @@ 이벤트 구독 생성 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 로드 위치: '{0}' @@ -72,6 +257,176 @@ 모듈을 찾을 수 없습니다. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (삽입하려면 <Tab> 키 누름) @@ -87,6 +442,11 @@ 모듈 확인: '{0}'/'{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting 스마트 들여쓰기 @@ -97,11 +457,71 @@ 문자열 분할 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' WARN: 버전이 일치하지 않습니다. 예상: '{0}', 실제: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 캐시의 '{0}'개 항목 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf index f00d3e310b8f7..9b1ab5a0a411b 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf @@ -12,6 +12,16 @@ Trwa dodawanie brakujących dyrektyw using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Wybrana wersja: „{0}” @@ -32,11 +42,26 @@ Dziennik dekompilacji + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Napraw interpolowany ciąg dosłowny wyrażenia + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Znaleziono zestawy („{0}”) dla elementu „{1}”: @@ -62,6 +87,166 @@ Generuj subskrypcję zdarzenia + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Załaduj z: „{0}” @@ -72,6 +257,176 @@ Nie znaleziono modułu. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Naciśnij klawisz TAB, aby wstawić) @@ -87,6 +442,11 @@ Rozpoznaj moduł: „{0}” z „{1}” + + Set spacing for operators + Set spacing for operators + + Smart Indenting Inteligentne tworzenie wcięć @@ -97,11 +457,71 @@ Rozdziel ciąg + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' OSTRZEŻENIE: niezgodność wersji. Oczekiwano: „{0}”, uzyskano: „{1}” + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Elementy w pamięci podręcznej: „{0}” diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf index 231aca00a20ae..f877b9c36c9d2 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf @@ -12,6 +12,16 @@ Adicionando as usings ausentes... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versão escolhida: '{0}' @@ -32,11 +42,26 @@ Log de descompilação + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corrigir cadeia de caracteres verbatim interpolada + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Foram encontrados '{0}' assemblies para '{1}': @@ -62,6 +87,166 @@ Gerar Assinatura de Evento + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Carregar de: '{0}' @@ -72,6 +257,176 @@ Módulo não encontrado. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Pressione TAB para inserir) @@ -87,6 +442,11 @@ Resolver o módulo: '{0}' de '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Recuo Inteligente @@ -97,11 +457,71 @@ Dividir cadeia de caracteres + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVISO: incompatibilidade de versão. Esperado: '{0}', Obtido: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' itens no cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf index b1a1ee7d0a8d7..3cab608fb016d 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf @@ -12,6 +12,16 @@ Добавление недостающих директив using… Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Выбранная версия: "{0}" @@ -32,11 +42,26 @@ Журнал декомпиляции + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Исправить интерполированную буквальную строку + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Обнаружены сборки ("{0}") для "{1}": @@ -62,6 +87,166 @@ Создать подписку на события + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Загрузить из: "{0}" @@ -72,6 +257,176 @@ Модуль не найден. + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Нажмите клавишу TAB для вставки) @@ -87,6 +442,11 @@ Разрешить модуль: "{0}" из "{1}" + + Set spacing for operators + Set spacing for operators + + Smart Indenting Интеллектуальные отступы @@ -97,11 +457,71 @@ Разделить строку + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' Внимание! Несовпадение версий. Ожидалось: "{0}", получено: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Элементов в кэше: "{0}" diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf index 0710b15a98b3a..2ecb41501934a 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf @@ -12,6 +12,16 @@ Eksik using yönergeleri ekleniyor... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Seçilen sürüm: '{0}' @@ -32,11 +42,26 @@ Kaynak koda dönüştürme günlüğü + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Ara değer olarak eklenmiş tam dizeyi düzelt + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}' için '{0}' bütünleştirilmiş kod bulundu: @@ -62,6 +87,166 @@ Olay Aboneliği Oluştur + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Şuradan yükle: '{0}' @@ -72,6 +257,176 @@ Modül bulunamadı! + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Eklemek için TAB tuşuna basın) @@ -87,6 +442,11 @@ '{1}' modül içinden '{0}' modülü çözümle + + Set spacing for operators + Set spacing for operators + + Smart Indenting Akıllı Girintileme @@ -97,11 +457,71 @@ Dizeyi böl + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' UYARI: Sürüm uyumsuzluğu. Beklenen: '{0}', Alınan: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Önbellekteki '{0}' öğe diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf index ec33113284dae..a725eb3507205 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf @@ -12,6 +12,16 @@ 正在添加缺少的 usings… Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 所选版本: "{0}" @@ -32,11 +42,26 @@ 反编译日志 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 修复插值的逐字字符串 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': 找到 “{1}”的“{0}”个程序集: @@ -62,6 +87,166 @@ 生成事件订阅 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 从以下位置加载: "{0}" @@ -72,6 +257,176 @@ 找不到模块! + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (按 Tab 插入) @@ -87,6 +442,11 @@ 解析模块: "{0}" 个(共 "{1}" 个) + + Set spacing for operators + Set spacing for operators + + Smart Indenting 智能缩进 @@ -97,11 +457,71 @@ 拆分字符串 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: 版本不匹配。应为: "{0}",实际为: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 缓存中的 {0} 项 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf index 82cf331bbb813..c46f13bf07e09 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf @@ -12,6 +12,16 @@ 正在新增缺少的 using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 選擇的版本: '{0}' @@ -32,11 +42,26 @@ 反向組譯記錄檔 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 修正插入的逐字字串 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': 找到 '{0}' 個 '{1}' 的組件: @@ -62,6 +87,166 @@ 產生事件訂閱 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 載入來源: '{0}' @@ -72,6 +257,176 @@ 找不到模組! + + Never + Never + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (按 TAB 鍵插入) @@ -87,6 +442,11 @@ 解析模組: '{0}' 之 '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting 智慧縮排 @@ -97,11 +457,71 @@ 分割字串 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: 版本不符。應為: '{0}',但取得: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 快取中有 '{0}' 個項目 diff --git a/src/EditorFeatures/CSharpTest/SettingsUpdater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/SettingsUpdater/SettingsUpdaterTests.cs new file mode 100644 index 0000000000000..e26c34b2bd224 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/SettingsUpdater/SettingsUpdaterTests.cs @@ -0,0 +1,323 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests +{ + [UseExportProvider] + public class SettingsUpdaterTests : TestBase + { + public static Workspace CreateWorkspace(Type[]? additionalParts = null) + => new AdhocWorkspace(FeaturesTestCompositions.Features.AddParts(additionalParts).GetHostServices()); + + private static Workspace CreateWorkspaceWithProjectAndDocuments() + { + var projectId = ProjectId.CreateNewId(); + + var workspace = CreateWorkspace(); + + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution + .AddProject(projectId, "proj1", "proj1.dll", LanguageNames.CSharp) + .AddDocument(DocumentId.CreateNewId(projectId), "goo.cs", "public class Goo { }") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId), "add.txt", "text") + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), "editorcfg", SourceText.From("config"), filePath: "/a/b"))); + + return workspace; + } + + private static AnalyzerConfigDocument CreateAnalyzerConfigDocument(Workspace workspace, string contents) + { + var solution = workspace.CurrentSolution; + var documentId = solution.Projects.Single().State.AnalyzerConfigDocumentStates.Ids.First(); + var text = SourceText.From(contents); + var newSolution1 = solution.WithAnalyzerConfigDocumentText(documentId, text, PreservationMode.PreserveIdentity); + var analyzerConfigDocument = newSolution1.GetAnalyzerConfigDocument(documentId); + Assert.True(analyzerConfigDocument!.TryGetText(out var actualText)); + Assert.Same(text, actualText); + return analyzerConfigDocument; + } + + private static async Task TestAsync(string initialEditorConfig, string updatedEditorConfig, params (IOption2, object)[] options) + { + using var workspace = CreateWorkspaceWithProjectAndDocuments(); + var analyzerConfigDocument = CreateAnalyzerConfigDocument(workspace, initialEditorConfig); + var result = await SettingsUpdateHelper.TryUpdateAnalyzerConfigDocumentAsync(analyzerConfigDocument, options, default); + Assert.Equal(updatedEditorConfig, result?.ToString()); + } + + private static async Task TestAsync(string initialEditorConfig, string updatedEditorConfig, params (AnalyzerSetting, DiagnosticSeverity)[] options) + { + using var workspace = CreateWorkspaceWithProjectAndDocuments(); + var analyzerConfigDocument = CreateAnalyzerConfigDocument(workspace, initialEditorConfig); + var result = await SettingsUpdateHelper.TryUpdateAnalyzerConfigDocumentAsync(analyzerConfigDocument, options, default); + Assert.Equal(updatedEditorConfig, result?.ToString()); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionAsync() + { + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_new_line_before_else=true", + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewBoolCodeStyleOptionWithSeverityAsync() + { + var option = CSharpCodeStyleOptions.PreferThrowExpression.DefaultValue; + option.Value = true; + option.Notification = CodeStyle.NotificationOption2.Suggestion; + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_style_throw_expression=true:suggestion", + (CSharpCodeStyleOptions.PreferThrowExpression, option)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewEnumCodeStyleOptionWithSeverityAsync() + { + var option = CSharpCodeStyleOptions.PreferredUsingDirectivePlacement.DefaultValue; + option.Value = AddImportPlacement.InsideNamespace; + option.Notification = CodeStyle.NotificationOption2.Warning; + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_using_directive_placement=inside_namespace:warning", + (CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, option)); + } + + [Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + internal async Task TestAddNewAnalyzerOptionOptionAsync( + [CombinatorialValues(Language.CSharp, Language.VisualBasic, (Language.CSharp | Language.VisualBasic))] + Language language, + [CombinatorialValues(DiagnosticSeverity.Warning, DiagnosticSeverity.Error, DiagnosticSeverity.Info, DiagnosticSeverity.Hidden)] + DiagnosticSeverity severity) + { + var expectedHeader = ""; + if (language.HasFlag(Language.CSharp) && language.HasFlag(Language.VisualBasic)) + { + expectedHeader = "[*.{cs,vb}]"; + } + else if (language.HasFlag(Language.CSharp)) + { + expectedHeader = "[*.cs]"; + } + else if (language.HasFlag(Language.VisualBasic)) + { + expectedHeader = "[*.vb]"; + } + + var expectedSeverity = severity.ToEditorConfigString(); + + var id = "Test001"; + var descriptor = new DiagnosticDescriptor(id: id, title: "", messageFormat: "", category: "Naming", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: false); + var analyzerSetting = new AnalyzerSetting(descriptor, ReportDiagnostic.Suppress, null!, language); + + await TestAsync( + string.Empty, + $"{expectedHeader}\r\ndotnet_diagnostic.{id}.severity={expectedSeverity}", + (analyzerSetting, severity)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestUpdateExistingWhitespaceOptionAsync() + { + await TestAsync( + "[*.cs]\r\ncsharp_new_line_before_else=true", + "[*.cs]\r\ncsharp_new_line_before_else=false", + (CSharpFormattingOptions2.NewLineForElse, false)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionToExistingFileAsync() + { + var initialEditorConfig = @" +[*.{cs,vb}] + +# CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1000.severity=false + +"; + + var updatedEditorConfig = @" +[*.{cs,vb}] + +# CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1000.severity=false + + +[*.cs] +csharp_new_line_before_else=true"; + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionToWithNonMathcingGroupsAsync() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 +[*.cs] +csharp_new_line_before_else=true"; + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionWithStarGroup() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs] +csharp_new_line_before_else=true"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddMultimpleNewWhitespaceOptions() + { + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_new_line_before_else=true\r\ncsharp_new_line_before_catch=true\r\ncsharp_new_line_before_finally=true", + (CSharpFormattingOptions2.NewLineForElse, true), + (CSharpFormattingOptions2.NewLineForCatch, true), + (CSharpFormattingOptions2.NewLineForFinally, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddOptionThatAppliesToBothLanguages() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +dotnet_sort_system_directives_first=true + +# CSharp code style settings: +[*.cs]"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (GenerationOptions.PlaceSystemNamespaceFirst, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddOptionWithRelativePathGroupingPresent() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# Test CSharp code style settings: +[*Test.cs] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# Test CSharp code style settings: +[*Test.cs] + +# CSharp code style settings: +[*.cs] +csharp_new_line_before_else=true"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj b/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj index 4211ba99baff2..20b9352283106 100644 --- a/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj +++ b/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj @@ -68,8 +68,6 @@ - - diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs new file mode 100644 index 0000000000000..74520e4ac98dc --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + internal interface ISettingsAggregator : IWorkspaceService + { + ISettingsProvider? GetSettingsProvider(string fileName); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs new file mode 100644 index 0000000000000..144b853d9abd9 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + internal partial class SettingsAggregator : ISettingsAggregator + { + private readonly Workspace _workspace; + private readonly ISettingsProviderFactory _analyzerProvider; + private ISettingsProviderFactory _formattingProvider; + private ISettingsProviderFactory _codeStyleProvider; + + public SettingsAggregator(Workspace workspace) + { + _workspace = workspace; + _workspace.WorkspaceChanged += UpdateProviders; + _formattingProvider = GetOptionsProviderFactory(_workspace); + _codeStyleProvider = GetOptionsProviderFactory(_workspace); + _analyzerProvider = GetOptionsProviderFactory(_workspace); + } + + private void UpdateProviders(object? sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectAdded: + case WorkspaceChangeKind.ProjectRemoved: + case WorkspaceChangeKind.ProjectChanged: + _formattingProvider = GetOptionsProviderFactory(_workspace); + _codeStyleProvider = GetOptionsProviderFactory(_workspace); + break; + default: + break; + } + } + + public ISettingsProvider? GetSettingsProvider(string fileName) + { + if (typeof(TData) == typeof(AnalyzerSetting)) + { + return (ISettingsProvider)_analyzerProvider.GetForFile(fileName); + } + + if (typeof(TData) == typeof(FormattingSetting)) + { + return (ISettingsProvider)_formattingProvider.GetForFile(fileName); + } + + if (typeof(TData) == typeof(CodeStyleSetting)) + { + return (ISettingsProvider)_codeStyleProvider.GetForFile(fileName); + } + + return null; + } + + private static ISettingsProviderFactory GetOptionsProviderFactory(Workspace workspace) + { + var providers = new List>(); + var commonProvider = workspace.Services.GetRequiredService>(); + providers.Add(commonProvider); + var solution = workspace.CurrentSolution; + var supportsCSharp = solution.Projects.Any(p => p.Language.Equals(LanguageNames.CSharp, StringComparison.OrdinalIgnoreCase)); + var supportsVisualBasic = solution.Projects.Any(p => p.Language.Equals(LanguageNames.VisualBasic, StringComparison.OrdinalIgnoreCase)); + if (supportsCSharp) + { + TryAddProviderForLanguage(LanguageNames.CSharp, workspace, providers); + } + if (supportsVisualBasic) + { + TryAddProviderForLanguage(LanguageNames.VisualBasic, workspace, providers); + } + + return new CombinedOptionsProviderFactory(providers.ToImmutableArray()); + + static void TryAddProviderForLanguage(string language, Workspace workspace, List> providers) + { + var provider = workspace.Services.GetLanguageServices(language).GetService>(); + if (provider is not null) + { + providers.Add(provider); + } + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs new file mode 100644 index 0000000000000..87a8598b69e32 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + + [ExportWorkspaceServiceFactory(typeof(ISettingsAggregator), ServiceLayer.Default), Shared] + internal class SettingsAggregatorFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public SettingsAggregatorFactory() + { + } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new SettingsAggregator(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs new file mode 100644 index 0000000000000..42a9ed62ce94c --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Globalization; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal class AnalyzerSetting + { + private readonly DiagnosticDescriptor _descriptor; + private readonly AnalyzerSettingsUpdater _settingsUpdater; + + public AnalyzerSetting(DiagnosticDescriptor descriptor, + ReportDiagnostic effectiveSeverity, + AnalyzerSettingsUpdater settingsUpdater, + Language language) + { + _descriptor = descriptor; + _settingsUpdater = settingsUpdater; + DiagnosticSeverity severity = default; + if (effectiveSeverity == ReportDiagnostic.Default) + { + severity = descriptor.DefaultSeverity; + } + else if (effectiveSeverity.ToDiagnosticSeverity() is DiagnosticSeverity severity1) + { + severity = severity1; + } + + var enabled = effectiveSeverity != ReportDiagnostic.Suppress; + IsEnabled = enabled; + Severity = severity; + Language = language; + } + + public string Id => _descriptor.Id; + public string Title => _descriptor.Title.ToString(CultureInfo.CurrentCulture); + public string Description => _descriptor.Description.ToString(CultureInfo.CurrentCulture); + public string Category => _descriptor.Category; + public DiagnosticSeverity Severity { get; private set; } + public bool IsEnabled { get; private set; } + public Language Language { get; } + + internal void ChangeSeverity(DiagnosticSeverity severity) + { + if (severity == Severity) + return; + + _ = _settingsUpdater.QueueUpdateAsync(this, severity); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs new file mode 100644 index 0000000000000..907245d073918 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class BooleanCodeStyleSetting : BooleanCodeStyleSettingBase + { + private readonly Option2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public BooleanCodeStyleSetting(Option2> option, + string description, + string? trueValueDescription, + string? falseValueDescription, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, option.Group.Description, trueValueDescription, falseValueDescription, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var value = valueIndex == 0; + var option = GetOption(); + option.Value = value; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption(_option); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs new file mode 100644 index 0000000000000..14d3638eb63a1 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private abstract class BooleanCodeStyleSettingBase : CodeStyleSetting + { + private readonly string _trueValueDescription; + private readonly string _falseValueDescription; + + public BooleanCodeStyleSettingBase(string description, + string category, + string? trueValueDescription, + string? falseValueDescription, + OptionUpdater updater) + : base(description, updater) + { + Category = category; + _trueValueDescription = trueValueDescription ?? EditorFeaturesResources.Yes; + _falseValueDescription = falseValueDescription ?? EditorFeaturesResources.No; + } + + public override string Category { get; } + public override Type Type => typeof(bool); + public override ReportDiagnostic Severity => GetOption().Notification.Severity; + public override string GetCurrentValue() => GetOption().Value ? _trueValueDescription : _falseValueDescription; + public override object? Value => GetOption().Value; + public override string[] GetValues() => new[] { _trueValueDescription, _falseValueDescription }; + protected abstract CodeStyleOption2 GetOption(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs new file mode 100644 index 0000000000000..8506d092f0315 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class EnumCodeStyleSetting : EnumCodeStyleSettingBase + where T : Enum + { + private readonly Option2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public EnumCodeStyleSetting(Option2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, enumValues, valueDescriptions, option.Group.Description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var option = GetOption(); + option.Value = _enumValues[valueIndex]; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption(_option); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs new file mode 100644 index 0000000000000..e723c9e9eb604 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private abstract class EnumCodeStyleSettingBase : CodeStyleSetting + where T : Enum + { + protected readonly T[] _enumValues; + private readonly string[] _valueDescriptions; + + public EnumCodeStyleSettingBase(string description, + T[] enumValues, + string[] valueDescriptions, + string category, + OptionUpdater updater) + : base(description, updater) + { + _enumValues = enumValues; + _valueDescriptions = valueDescriptions; + Category = category; + } + + public override string Category { get; } + public override Type Type => typeof(T); + public override string GetCurrentValue() => _valueDescriptions[_enumValues.IndexOf(GetOption().Value)]; + public override object? Value => GetOption().Value; + public override ReportDiagnostic Severity => GetOption().Notification.Severity; + public override string[] GetValues() => _valueDescriptions; + protected abstract CodeStyleOption2 GetOption(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs new file mode 100644 index 0000000000000..b71d06986e1a5 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class PerLanguageBooleanCodeStyleSetting : BooleanCodeStyleSettingBase + { + private readonly PerLanguageOption2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageBooleanCodeStyleSetting(PerLanguageOption2> option, + string description, + string? trueValueDescription, + string? falseValueDescription, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, option.Group.Description, trueValueDescription, falseValueDescription, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var value = valueIndex == 0; + var option = GetOption(); + option.Value = value; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption>(new OptionKey2(_option, LanguageNames.CSharp)); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs new file mode 100644 index 0000000000000..df33ae0c833e6 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class PerLanguageEnumCodeStyleSetting : EnumCodeStyleSettingBase + where T : Enum + { + private readonly PerLanguageOption2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageEnumCodeStyleSetting(PerLanguageOption2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, enumValues, valueDescriptions, option.Group.Description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var option = GetOption(); + option.Value = _enumValues[valueIndex]; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + // TODO(jmarolf): Should we expose duplicate options if the user has a different setting in VB vs. C#? + // Today this code will choose whatever option is set for C# as the default. + : _visualStudioOptions.GetOption>(new OptionKey2(_option, LanguageNames.CSharp)); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs new file mode 100644 index 0000000000000..4bd4673f9674a --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + public string Description { get; } + + protected readonly OptionUpdater Updater; + + public abstract string Category { get; } + public abstract object? Value { get; } + public abstract Type Type { get; } + public abstract string[] GetValues(); + public abstract string GetCurrentValue(); + public abstract ReportDiagnostic Severity { get; } + public abstract bool IsDefinedInEditorConfig { get; } + + public CodeStyleSetting(string description, OptionUpdater updater) + { + Description = description; + Updater = updater; + } + + public void ChangeSeverity(DiagnosticSeverity severity) + { + var notification = severity switch + { + DiagnosticSeverity.Hidden => NotificationOption2.Silent, + DiagnosticSeverity.Info => NotificationOption2.Suggestion, + DiagnosticSeverity.Warning => NotificationOption2.Warning, + DiagnosticSeverity.Error => NotificationOption2.Error, + _ => NotificationOption2.None, + }; + + ChangeSeverity(notification); + } + + protected abstract void ChangeSeverity(NotificationOption2 severity); + public abstract void ChangeValue(int valueIndex); + + internal static CodeStyleSetting Create(Option2> option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater, + string? trueValueDescription = null, + string? falseValueDescription = null) + { + return new BooleanCodeStyleSetting(option, description, trueValueDescription, falseValueDescription, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(PerLanguageOption2> option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater, + string? trueValueDescription = null, + string? falseValueDescription = null) + { + return new PerLanguageBooleanCodeStyleSetting(option, description, trueValueDescription, falseValueDescription, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(Option2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where T : Enum + { + return new EnumCodeStyleSetting(option, description, enumValues, valueDescriptions, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(PerLanguageOption2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where T : Enum + { + return new PerLanguageEnumCodeStyleSetting(option, description, enumValues, valueDescriptions, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs new file mode 100644 index 0000000000000..a013f3ad40551 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract class FormattingSetting + { + protected OptionUpdater Updater { get; } + protected string? Language { get; } + + protected FormattingSetting(string description, OptionUpdater updater, string? language = null) + { + Description = description ?? throw new ArgumentNullException(nameof(description)); + Updater = updater; + Language = language; + } + + public string Description { get; } + public abstract string Category { get; } + public abstract Type Type { get; } + public abstract OptionKey2 Key { get; } + public abstract void SetValue(object value); + public abstract object? GetValue(); + public abstract bool IsDefinedInEditorConfig { get; } + + public static PerLanguageFormattingSetting Create(PerLanguageOption2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where TOption : notnull + { + return new PerLanguageFormattingSetting(option, description, editorConfigOptions, visualStudioOptions, updater); + } + + public static FormattingSetting Create(Option2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where TOption : struct + { + return new FormattingSetting(option, description, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs new file mode 100644 index 0000000000000..3346fba87715b --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal sealed class FormattingSetting : FormattingSetting + where T : notnull + { + public override bool IsDefinedInEditorConfig => _options.TryGetEditorConfigOption(_option, out _); + + public T Value + { + get + { + if (_options.TryGetEditorConfigOption(_option, out T? value) && + value is not null) + { + return value; + } + + return _visualStudioOptions.GetOption(_option); + } + } + + public override Type Type => typeof(T); + public override string Category => _option.Group.Description; + + public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + + private readonly Option2 _option; + private readonly AnalyzerConfigOptions _options; + private readonly OptionSet _visualStudioOptions; + + public FormattingSetting(Option2 option, + string description, + AnalyzerConfigOptions options, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, updater) + { + _option = option; + _options = options; + _visualStudioOptions = visualStudioOptions; + } + + public override void SetValue(object value) + { + _ = Updater.QueueUpdateAsync(_option, value); + } + + public override object? GetValue() => Value; + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs new file mode 100644 index 0000000000000..89075ed47dc56 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal sealed class PerLanguageFormattingSetting : FormattingSetting + where T : notnull + { + public T? Value + { + get + { + if (_editorConfigOptions.TryGetEditorConfigOption(_option, out T? value) && + value is not null) + { + return value; + } + + return (T?)_visualStudioOptions.GetOption(Key); + } + } + + private readonly PerLanguageOption2 _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageFormattingSetting(PerLanguageOption2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override string Category => _option.Group.Description; + public override Type Type => typeof(T); + + public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption(_option, out _); + + public override void SetValue(object value) + { + _ = Updater.QueueUpdateAsync(_option, value); + } + + public override object? GetValue() => Value; + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs new file mode 100644 index 0000000000000..08d6f148d7db2 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + internal class AnalyzerSettingsProvider : SettingsProviderBase + { + private readonly IDiagnosticAnalyzerService _analyzerService; + + public AnalyzerSettingsProvider(string fileName, AnalyzerSettingsUpdater settingsUpdater, Workspace workspace, IDiagnosticAnalyzerService analyzerService) + : base(fileName, settingsUpdater, workspace) + { + _analyzerService = analyzerService; + } + + protected override Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet _) + { + return Task.Run(() => + { + var solution = Workspace.CurrentSolution; + var projects = solution.GetProjectsForPath(FileName); + var analyzerReferences = projects.SelectMany(p => p.AnalyzerReferences).DistinctBy(a => a.Id).ToImmutableArray(); + foreach (var analyzerReference in analyzerReferences) + { + var configSettings = GetSettings(analyzerReference, editorConfigOptions); + AddRange(configSettings); + } + }); + } + + private IEnumerable GetSettings(AnalyzerReference analyzerReference, AnalyzerConfigOptions editorConfigOptions) + { + IEnumerable csharpAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.CSharp); + IEnumerable visualBasicAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.VisualBasic); + var dotnetAnalyzers = csharpAnalyzers.Intersect(visualBasicAnalyzers, DiagnosticAnalyzerComparer.Instance); + csharpAnalyzers = csharpAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); + visualBasicAnalyzers = visualBasicAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); + + var csharpSettings = ToAnalyzerSetting(csharpAnalyzers, Language.CSharp); + var csharpAndVisualBasicSettings = csharpSettings.Concat(ToAnalyzerSetting(visualBasicAnalyzers, Language.VisualBasic)); + return csharpAndVisualBasicSettings.Concat(ToAnalyzerSetting(dotnetAnalyzers, Language.CSharp | Language.VisualBasic)); + + IEnumerable ToAnalyzerSetting(IEnumerable analyzers, + Language language) + { + return analyzers + .SelectMany(a => _analyzerService.AnalyzerInfoCache.GetDiagnosticDescriptors(a)) + .GroupBy(d => d.Id) + .OrderBy(g => g.Key, StringComparer.CurrentCulture) + .Select(g => + { + var selectedDiagnostic = g.First(); + var severity = selectedDiagnostic.GetEffectiveSeverity(editorConfigOptions); + return new AnalyzerSetting(selectedDiagnostic, severity, SettingsUpdater, language); + }); + } + } + + private class DiagnosticAnalyzerComparer : IEqualityComparer + { + public static readonly DiagnosticAnalyzerComparer Instance = new(); + + public bool Equals(DiagnosticAnalyzer? x, DiagnosticAnalyzer? y) + { + if (x is null && y is null) + return true; + + if (x is null || y is null) + return false; + + return x.GetAnalyzerIdAndVersion().GetHashCode() == y.GetAnalyzerIdAndVersion().GetHashCode(); + } + + public int GetHashCode(DiagnosticAnalyzer obj) => obj.GetAnalyzerIdAndVersion().GetHashCode(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs new file mode 100644 index 0000000000000..9f145c3f021d0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + internal class AnalyzerSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + private readonly IDiagnosticAnalyzerService _analyzerService; + + public AnalyzerSettingsProviderFactory(Workspace workspace, IDiagnosticAnalyzerService analyzerService) + { + _workspace = workspace; + _analyzerService = analyzerService; + } + + public ISettingsProvider GetForFile(string filePath) + { + var updater = new AnalyzerSettingsUpdater(_workspace, filePath); + return new AnalyzerSettingsProvider(filePath, updater, _workspace, _analyzerService); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..5b7ed248bf9d8 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class AnalyzerSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + private readonly IDiagnosticAnalyzerService _analyzerService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerSettingsWorkspaceServiceFactory(IDiagnosticAnalyzerService analyzerService) + { + _analyzerService = analyzerService; + } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, _analyzerService); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs new file mode 100644 index 0000000000000..682c675fd73ff --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs @@ -0,0 +1,190 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CommonCodeStyleSettingsProvider : SettingsProviderBase + { + public CommonCodeStyleSettingsProvider(string filePath, OptionUpdater settingsUpdater, Workspace workspace) + : base(filePath, settingsUpdater, workspace) + { + } + + protected override Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + return Task.Run(() => + { + var qualifySettings = GetQualifyCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(qualifySettings); + + var predefinedTypesSettings = GetPredefinedTypesCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(predefinedTypesSettings); + + var nullCheckingSettings = GetNullCheckingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(nullCheckingSettings); + + var modifierSettings = GetModifierCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(modifierSettings); + + var codeBlockSettings = GetCodeBlockCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(codeBlockSettings); + + var expressionSettings = GetExpressionCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionSettings); + + var parameterSettings = GetParameterCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(parameterSettings); + + var parenthesesSettings = GetParenthesesCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(parenthesesSettings); + }); + } + + private static IEnumerable GetQualifyCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyFieldAccess, + description: EditorFeaturesResources.Qualify_field_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyPropertyAccess, + description: EditorFeaturesResources.Qualify_property_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyMethodAccess, + description: EditorFeaturesResources.Qualify_method_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyEventAccess, + description: EditorFeaturesResources.Qualify_event_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetPredefinedTypesCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, + description: EditorFeaturesResources.For_locals_parameters_and_members, + trueValueDescription: EditorFeaturesResources.Prefer_predefined_type, + falseValueDescription: EditorFeaturesResources.Prefer_framework_type, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, + description: EditorFeaturesResources.For_member_access_expressions, + trueValueDescription: EditorFeaturesResources.Prefer_predefined_type, + falseValueDescription: EditorFeaturesResources.Prefer_framework_type, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetNullCheckingCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferCoalesceExpression, + description: EditorFeaturesResources.Prefer_coalesce_expression, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferNullPropagation, + description: EditorFeaturesResources.Prefer_null_propagation, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, + description: EditorFeaturesResources.Prefer_is_null_for_reference_equality_checks, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetModifierCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferReadonly, + description: EditorFeaturesResources.Prefer_readonly_fields, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetCodeBlockCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferAutoProperties, + description: EditorFeaturesResources.analyzer_Prefer_auto_properties, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferSystemHashCode, + description: EditorFeaturesResources.Prefer_System_HashCode_in_GetHashCode, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetExpressionCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferObjectInitializer, description: EditorFeaturesResources.Prefer_object_initializer, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferCollectionInitializer, description: EditorFeaturesResources.Prefer_collection_initializer, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferSimplifiedBooleanExpressions, description: EditorFeaturesResources.Prefer_simplified_boolean_expressions, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferConditionalExpressionOverAssignment, description: EditorFeaturesResources.Prefer_conditional_expression_over_if_with_assignments, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferConditionalExpressionOverReturn, description: EditorFeaturesResources.Prefer_conditional_expression_over_if_with_returns, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferExplicitTupleNames, description: EditorFeaturesResources.Prefer_explicit_tuple_name, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferInferredTupleNames, description: EditorFeaturesResources.Prefer_inferred_tuple_names, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferInferredAnonymousTypeMemberNames, description: EditorFeaturesResources.Prefer_inferred_anonymous_type_member_names, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferCompoundAssignment, description: EditorFeaturesResources.Prefer_compound_assignments, options, visualStudioOptions, updater); + } + + private static IEnumerable GetParenthesesCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + var enumValues = new[] { ParenthesesPreference.AlwaysForClarity, ParenthesesPreference.NeverIfUnnecessary }; + var valueDescriptions = new[] { EditorFeaturesResources.Always_for_clarity, EditorFeaturesResources.Never_if_unnecessary }; + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.ArithmeticBinaryParentheses, + description: EditorFeaturesResources.In_arithmetic_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.OtherBinaryParentheses, + description: EditorFeaturesResources.In_other_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.RelationalBinaryParentheses, + description: EditorFeaturesResources.In_relational_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.OtherParentheses, + description: EditorFeaturesResources.In_other_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + } + + private static IEnumerable GetParameterCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create( + option: CodeStyleOptions2.UnusedParameters, + description: EditorFeaturesResources.Avoid_unused_parameters, + enumValues: new[] { UnusedParametersPreference.NonPublicMethods, UnusedParametersPreference.AllMethods }, + new[] { EditorFeaturesResources.Non_public_methods }, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs new file mode 100644 index 0000000000000..2477ecf668c1c --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CommonCodeStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CommonCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CommonCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..2a34627f74a2d --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class CommonCodeStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommonCodeStyleSettingsWorkspaceServiceFactory() { } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new CommonCodeStyleSettingsProviderFactory(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs new file mode 100644 index 0000000000000..1000896c6a68e --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Shared.Collections; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal class CombinedOptionsProviderFactory : ISettingsProviderFactory + { + private ImmutableArray> _factories; + + public CombinedOptionsProviderFactory(ImmutableArray> factories) + { + _factories = factories; + } + + public ISettingsProvider GetForFile(string filePath) + { + var providers = TemporaryArray>.Empty; + foreach (var factory in _factories) + { + providers.Add(factory.GetForFile(filePath)); + } + + return new CombinedProvider(providers.ToImmutableAndClear()); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs new file mode 100644 index 0000000000000..d63659f0e6a4f --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal class CombinedProvider : ISettingsProvider + { + private readonly ImmutableArray> _providers; + + public CombinedProvider(ImmutableArray> providers) + { + _providers = providers; + } + + public async Task?> GetChangedEditorConfigAsync() + { + var changes = await Task.WhenAll(_providers.Select(x => x.GetChangedEditorConfigAsync())).ConfigureAwait(false); + + changes = changes.Where(x => x is not null).ToArray(); + if (!changes.Any()) + return null; + + var result = new List(); + foreach (var change in changes) + { + result.AddRange(change!); // compiler does not see through linq in nullable yet + } + + return result; + } + + public ImmutableArray GetCurrentDataSnapshot() + { + var snapShot = ImmutableArray.Empty; + foreach (var provider in _providers) + { + snapShot = snapShot.Concat(provider.GetCurrentDataSnapshot()); + } + + return snapShot; + } + + public void RegisterViewModel(ISettingsEditorViewModel model) + { + foreach (var provider in _providers) + { + provider.RegisterViewModel(model); + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs new file mode 100644 index 0000000000000..2f372a625c054 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + internal class CommonFormattingSettingsProvider : SettingsProviderBase + { + public CommonFormattingSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) + : base(fileName, settingsUpdater, workspace) + { + } + + protected override Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + return Task.Run(() => + { + var defaultOptions = GetDefaultOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(defaultOptions); + }); + } + + private static IEnumerable GetDefaultOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return FormattingSetting.Create(FormattingOptions2.UseTabs, EditorFeaturesResources.Use_Tabs, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.TabSize, EditorFeaturesResources.Tab_Size, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.IndentationSize, EditorFeaturesResources.Indentation_Size, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.NewLine, EditorFeaturesResources.New_Line, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.InsertFinalNewLine, EditorFeaturesResources.Insert_Final_Newline, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs new file mode 100644 index 0000000000000..21d130c599f42 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + internal class CommonFormattingSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CommonFormattingSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CommonFormattingSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..878bd1198987d --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class CommonFormattingSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommonFormattingSettingsWorkspaceServiceFactory() { } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new CommonFormattingSettingsProviderFactory(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs new file mode 100644 index 0000000000000..800df15d4f056 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ILanguageSettingsProviderFactory : ISettingsProviderFactory, ILanguageService + { + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs new file mode 100644 index 0000000000000..60058fde5e776 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ISettingsProvider + { + void RegisterViewModel(ISettingsEditorViewModel model); + ImmutableArray GetCurrentDataSnapshot(); + Task?> GetChangedEditorConfigAsync(); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs new file mode 100644 index 0000000000000..4c87bfb021ae3 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ISettingsProviderFactory + { + ISettingsProvider GetForFile(string filePath); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs new file mode 100644 index 0000000000000..a241256ac0d26 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface IWorkspaceSettingsProviderFactory : ISettingsProviderFactory, IWorkspaceService + { + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs new file mode 100644 index 0000000000000..d439492f4da89 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using static Microsoft.CodeAnalysis.ProjectState; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal abstract class SettingsProviderBase : ISettingsProvider, IDisposable + where TOptionsUpdater : ISettingUpdater + { + private readonly List _snapshot = new(); + private static readonly object s_gate = new(); + private ISettingsEditorViewModel? _viewModel; + protected readonly string FileName; + protected readonly TOptionsUpdater SettingsUpdater; + protected readonly Workspace Workspace; + + protected abstract Task UpdateOptionsAsync(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions); + + protected SettingsProviderBase(string fileName, TOptionsUpdater settingsUpdater, Workspace workspace) + { + FileName = fileName; + SettingsUpdater = settingsUpdater; + Workspace = workspace; + Workspace.WorkspaceChanged += OnWorkspaceChanged; + Update(); + } + + private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectAdded: + case WorkspaceChangeKind.ProjectRemoved: + case WorkspaceChangeKind.ProjectChanged: + case WorkspaceChangeKind.ProjectReloaded: + case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: + case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: + case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: + case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: + Update(); + break; + default: + break; + } + } + + private void Update() + { + var givenFolder = new DirectoryInfo(FileName).Parent; + var solution = Workspace.CurrentSolution; + var projects = solution.GetProjectsForPath(FileName); + var project = projects.First(); + var configOptionsProvider = new WorkspaceAnalyzerConfigOptionsProvider(project.State); + var options = configOptionsProvider.GetOptionsForSourcePath(givenFolder.FullName); + _ = UpdateOptionsAsync(options, Workspace.Options); + } + + public Task?> GetChangedEditorConfigAsync() + => SettingsUpdater.GetChangedEditorConfigAsync(default); + + public ImmutableArray GetCurrentDataSnapshot() + { + lock (s_gate) + { + return _snapshot.ToImmutableArray(); + } + } + + protected void AddRange(IEnumerable items) + { + lock (s_gate) + { + _snapshot.AddRange(items); + } + + _ = _viewModel?.NotifyOfUpdateAsync(); + } + + public void RegisterViewModel(ISettingsEditorViewModel viewModel) + => _viewModel = viewModel ?? throw new ArgumentNullException(nameof(viewModel)); + + public void Dispose() + => Workspace.WorkspaceChanged -= OnWorkspaceChanged; + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000000000..6ef0a5228cda0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions +{ + internal static class EnumerableExtensions + { + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + var seenKeys = new HashSet(); + foreach (var element in source) + { + if (seenKeys.Add(keySelector(element))) + { + yield return element; + } + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs new file mode 100644 index 0000000000000..25e30f598e5e0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions +{ + internal static class SolutionExtensions + { + public static ImmutableArray GetProjectsForPath(this Solution solution, string givenPath) + { + var givenFolder = new DirectoryInfo(givenPath).Parent; + var solutionFolder = new DirectoryInfo(solution.FilePath).Parent; + if (givenFolder.FullName == solutionFolder.FullName) + { + return solution.Projects.ToImmutableArray(); + } + + var builder = ArrayBuilder.GetInstance(); + foreach (var (projectDirectoryPath, project) in solution.Projects.Select(p => (new DirectoryInfo(p.FilePath).Parent, p))) + { + if (ContainsPath(givenFolder, projectDirectoryPath)) + { + builder.Add(project); + } + } + + return builder.ToImmutableAndFree(); + + static bool ContainsPath(DirectoryInfo givenPath, DirectoryInfo projectPath) + { + if (projectPath.FullName == givenPath.FullName) + { + return true; + } + + while (projectPath.Parent is not null) + { + if (projectPath.Parent.FullName == givenPath.FullName) + { + return true; + } + projectPath = projectPath.Parent; + } + + return false; + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs b/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs new file mode 100644 index 0000000000000..e822f6d668dfb --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor +{ + internal interface ISettingsEditorViewModel + { + Task NotifyOfUpdateAsync(); + Task?> GetChangesAsync(); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Language.cs b/src/EditorFeatures/Core/EditorConfigSettings/Language.cs new file mode 100644 index 0000000000000..54002e7c301c0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Language.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + [Flags] + internal enum Language + { + CSharp = 1, + VisualBasic = 2, + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs new file mode 100644 index 0000000000000..092ebdd305fe8 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal class AnalyzerSettingsUpdater : SettingsUpdaterBase + { + public AnalyzerSettingsUpdater(Workspace workspace, string editorconfigPath) : base(workspace, editorconfigPath) + { + } + + protected override Task GetNewTextAsync(AnalyzerConfigDocument analyzerConfigDocument, + IReadOnlyList<(AnalyzerSetting option, DiagnosticSeverity value)> settingsToUpdate, + CancellationToken token) + => SettingsUpdateHelper.TryUpdateAnalyzerConfigDocumentAsync(analyzerConfigDocument, settingsToUpdate, token); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs new file mode 100644 index 0000000000000..85e8cf498015c --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal interface ISettingUpdater + { + Task QueueUpdateAsync(TSetting setting, TValue value); + Task?> GetChangedEditorConfigAsync(CancellationToken token); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs new file mode 100644 index 0000000000000..883fbd8be4a3f --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + + internal class OptionUpdater : SettingsUpdaterBase + { + public OptionUpdater(Workspace workspace, string editorconfigPath) + : base(workspace, editorconfigPath) + { + } + + protected override Task GetNewTextAsync(AnalyzerConfigDocument analyzerConfigDocument, + IReadOnlyList<(IOption2 option, object value)> settingsToUpdate, + CancellationToken token) + => SettingsUpdateHelper.TryUpdateAnalyzerConfigDocumentAsync(analyzerConfigDocument, settingsToUpdate, token); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs new file mode 100644 index 0000000000000..ce046eb93ec11 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs @@ -0,0 +1,374 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal static partial class SettingsUpdateHelper + { + private const string DiagnosticOptionPrefix = "dotnet_diagnostic."; + private const string SeveritySuffix = ".severity"; + + public static async Task TryUpdateAnalyzerConfigDocumentAsync(AnalyzerConfigDocument analyzerConfigDocument, + IReadOnlyList<(AnalyzerSetting option, DiagnosticSeverity value)> settingsToUpdate, + CancellationToken token) + { + if (analyzerConfigDocument is null) + throw new ArgumentNullException(nameof(analyzerConfigDocument)); + if (settingsToUpdate is null) + throw new ArgumentNullException(nameof(settingsToUpdate)); + + var originalText = await analyzerConfigDocument.GetTextAsync(token).ConfigureAwait(false); + var filePath = analyzerConfigDocument.FilePath; + if (filePath is null) + return null; + + var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value)).ToList(); + + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); + + static (string option, string value, Language language) TryGetOptionValueAndLanguage(AnalyzerSetting diagnostic, DiagnosticSeverity severity) + { + var optionName = $"{DiagnosticOptionPrefix}{diagnostic.Id}{SeveritySuffix}"; + var optionValue = severity.ToEditorConfigString(); + var language = diagnostic.Language; + return (optionName, optionValue, language); + } + } + + public static async Task TryUpdateAnalyzerConfigDocumentAsync(AnalyzerConfigDocument analyzerConfigDocument, + IReadOnlyList<(IOption2 option, object value)> settingsToUpdate, + CancellationToken token) + { + if (analyzerConfigDocument is null) + throw new ArgumentNullException(nameof(analyzerConfigDocument)); + if (settingsToUpdate is null) + throw new ArgumentNullException(nameof(settingsToUpdate)); + + var originalText = await analyzerConfigDocument.GetTextAsync(token).ConfigureAwait(false); + var filePath = analyzerConfigDocument.FilePath; + if (filePath is null) + return null; + + var optionSet = analyzerConfigDocument.Project.Solution.Workspace.Options; + var updatedText = originalText; + var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value, analyzerConfigDocument)) + .Where(x => x.success) + .Select(x => (x.option, x.value, x.language)) + .ToList(); + + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); + + static (bool success, string option, string value, Language language) TryGetOptionValueAndLanguage(IOption2 option, object value, AnalyzerConfigDocument document) + { + var optionSet = document.Project.Solution.Workspace.Options; + if (option.StorageLocations.FirstOrDefault(x => x is IEditorConfigStorageLocation2) is not IEditorConfigStorageLocation2 storageLocation) + { + return (false, null!, null!, default); + } + + var optionName = storageLocation.KeyName; + var optionValue = storageLocation.GetEditorConfigStringValue(value, optionSet); + if (value is ICodeStyleOption codeStyleOption) + { + var severity = codeStyleOption.Notification switch + { + { Severity: ReportDiagnostic.Hidden } => "refactoring", + { Severity: ReportDiagnostic.Info } => "suggestion", + { Severity: ReportDiagnostic.Warn } => "warning", + { Severity: ReportDiagnostic.Error } => "error", + _ => string.Empty + }; + optionValue = $"{optionValue}:{severity}"; + } + + Language language = default; + if (option.IsPerLanguage) + { + language = Language.CSharp | Language.VisualBasic; + } + else if (document.Project.Language.Equals(LanguageNames.CSharp, StringComparison.Ordinal)) + { + language = Language.CSharp; + } + else if (document.Project.Language.Equals(LanguageNames.VisualBasic, StringComparison.Ordinal)) + { + language = Language.VisualBasic; + } + + return (true, optionName, optionValue, language); + } + } + + public static SourceText? TryUpdateAnalyzerConfigDocument(SourceText originalText, + string filePath, + IReadOnlyList<(string option, string value, Language language)> settingsToUpdate) + { + if (originalText is null) + throw new ArgumentNullException(nameof(originalText)); + if (filePath is null) + throw new ArgumentNullException(nameof(filePath)); + if (settingsToUpdate is null) + throw new ArgumentNullException(nameof(settingsToUpdate)); + + var updatedText = originalText; + TextLine? lastValidHeaderSpanEnd; + TextLine? lastValidSpecificHeaderSpanEnd; + foreach (var (option, value, language) in settingsToUpdate) + { + SourceText? newText; + (newText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd) = UpdateIfExistsInFile(updatedText, filePath, option, value, language); + if (newText != null) + { + updatedText = newText; + continue; + } + + (newText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd) = AddMissingRule(updatedText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd, option, value, language); + if (newText != null) + { + updatedText = newText; + } + } + + return updatedText.Equals(originalText) ? null : updatedText; + } + + /// + /// Regular expression for .editorconfig header. + /// For example: "[*.cs] # Optional comment" + /// "[*.{vb,cs}]" + /// "[*] ; Optional comment" + /// "[ConsoleApp/Program.cs]" + /// + private static readonly Regex s_headerPattern = new(@"\[(\*|[^ #;\[\]]+\.({[^ #;{}\.\[\]]+}|[^ #;{}\.\[\]]+))\]\s*([#;].*)?"); + + /// + /// Regular expression for .editorconfig code style option entry. + /// For example: + /// 1. "dotnet_style_object_initializer = true # Optional comment" + /// 2. "dotnet_style_object_initializer = true:suggestion ; Optional comment" + /// 3. "dotnet_diagnostic.CA2000.severity = suggestion # Optional comment" + /// 4. "dotnet_analyzer_diagnostic.category-Security.severity = suggestion # Optional comment" + /// 5. "dotnet_analyzer_diagnostic.severity = suggestion # Optional comment" + /// Regex groups: + /// 1. Option key + /// 2. Option value + /// 3. Optional severity suffix in option value, i.e. ':severity' suffix + /// 4. Optional comment suffix + /// + private static readonly Regex s_optionEntryPattern = new($@"(.*)=([\w, ]*)(:[\w]+)?([ ]*[;#].*)?"); + + private static (SourceText? newText, TextLine? lastValidHeaderSpanEnd, TextLine? lastValidSpecificHeaderSpanEnd) UpdateIfExistsInFile(SourceText editorConfigText, + string filePath, + string optionName, + string optionValue, + Language language) + { + var editorConfigDirectory = PathUtilities.GetDirectoryName(filePath); + Assumes.NotNull(editorConfigDirectory); + var relativePath = PathUtilities.GetRelativePath(editorConfigDirectory.ToLowerInvariant(), filePath); + + TextLine? mostRecentHeader = null; + TextLine? lastValidHeader = null; + TextLine? lastValidHeaderSpanEnd = null; + + TextLine? lastValidSpecificHeader = null; + TextLine? lastValidSpecificHeaderSpanEnd = null; + + var textChange = new TextChange(); + foreach (var curLine in editorConfigText.Lines) + { + var curLineText = curLine.ToString(); + if (s_optionEntryPattern.IsMatch(curLineText)) + { + var groups = s_optionEntryPattern.Match(curLineText).Groups; + var (untrimmedKey, key, value, severity, comment) = GetGroups(groups); + + // Verify the most recent header is a valid header + if (IsValidHeader(mostRecentHeader, lastValidHeader) && + string.Equals(key, optionName, StringComparison.OrdinalIgnoreCase)) + { + // We found the rule in the file -- replace it with updated option value. + textChange = new TextChange(curLine.Span, $"{untrimmedKey}={optionValue}{comment}"); + } + } + else if (s_headerPattern.IsMatch(curLineText.Trim())) + { + mostRecentHeader = curLine; + if (ShouldSetAsLastValidHeader(curLineText, out var mostRecentHeaderText)) + { + lastValidHeader = mostRecentHeader; + } + else + { + var (fileName, splicedFileExtensions) = ParseHeaderParts(mostRecentHeaderText); + if ((relativePath.IsEmpty() || new Regex(fileName).IsMatch(relativePath)) && + HeaderMatchesLanguageRequirements(language, splicedFileExtensions)) + { + lastValidHeader = mostRecentHeader; + } + } + } + + // We want to keep track of how far this (valid) section spans. + if (IsValidHeader(mostRecentHeader, lastValidHeader) && IsNotEmptyOrComment(curLineText)) + { + lastValidHeaderSpanEnd = curLine; + if (lastValidSpecificHeader != null && mostRecentHeader.Equals(lastValidSpecificHeader)) + { + lastValidSpecificHeaderSpanEnd = curLine; + } + } + } + + // We return only the last text change in case of duplicate entries for the same rule. + if (textChange != default) + { + return (editorConfigText.WithChanges(textChange), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + + // Rule not found. + return (null, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + + static (string untrimmedKey, string key, string value, string severitySuffixInValue, string commentValue) GetGroups(GroupCollection groups) + { + var untrimmedKey = groups[1].Value.ToString(); + var key = untrimmedKey.Trim(); + var value = groups[2].Value.ToString(); + var severitySuffixInValue = groups[3].Value.ToString(); + var commentValue = groups[4].Value.ToString(); + return (untrimmedKey, key, value, severitySuffixInValue, commentValue); + } + + static bool IsValidHeader(TextLine? mostRecentHeader, TextLine? lastValidHeader) + { + return mostRecentHeader is not null && + lastValidHeader is not null && + mostRecentHeader.Equals(lastValidHeader); + } + + static bool ShouldSetAsLastValidHeader(string curLineText, out string mostRecentHeaderText) + { + var groups = s_headerPattern.Match(curLineText.Trim()).Groups; + mostRecentHeaderText = groups[1].Value.ToString().ToLowerInvariant(); + return mostRecentHeaderText.Equals("*", StringComparison.Ordinal); + } + + static (string fileName, string[] splicedFileExtensions) ParseHeaderParts(string mostRecentHeaderText) + { + // We splice on the last occurrence of '.' to account for filenames containing periods. + var nameExtensionSplitIndex = mostRecentHeaderText.LastIndexOf('.'); + var fileName = mostRecentHeaderText.Substring(0, nameExtensionSplitIndex); + var splicedFileExtensions = mostRecentHeaderText[(nameExtensionSplitIndex + 1)..].Split(',', ' ', '{', '}'); + + // Replacing characters in the header with the regex equivalent. + fileName = fileName.Replace(".", @"\."); + fileName = fileName.Replace("*", ".*"); + fileName = fileName.Replace("/", @"\/"); + + return (fileName, splicedFileExtensions); + } + + static bool IsNotEmptyOrComment(string currentLineText) + { + return !string.IsNullOrWhiteSpace(currentLineText) && !currentLineText.Trim().StartsWith("#", StringComparison.OrdinalIgnoreCase); + } + + static bool HeaderMatchesLanguageRequirements(Language language, string[] splicedFileExtensions) + { + return IsCSharpOnly(language, splicedFileExtensions) || IsVisualBasicOnly(language, splicedFileExtensions) || IsBothVisualBasicAndCSharp(language, splicedFileExtensions); + } + + static bool IsCSharpOnly(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.CSharp) && !language.HasFlag(Language.VisualBasic) && splicedFileExtensions.Contains("cs") && splicedFileExtensions.Length == 1; + } + + static bool IsVisualBasicOnly(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.VisualBasic) && !language.HasFlag(Language.CSharp) && splicedFileExtensions.Contains("vb") && splicedFileExtensions.Length == 1; + } + + static bool IsBothVisualBasicAndCSharp(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.VisualBasic) && language.HasFlag(Language.CSharp) && splicedFileExtensions.Contains("vb") && splicedFileExtensions.Contains("cs"); + } + } + + private static (SourceText? newText, TextLine? lastValidHeaderSpanEnd, TextLine? lastValidSpecificHeaderSpanEnd) AddMissingRule(SourceText editorConfigText, + TextLine? lastValidHeaderSpanEnd, + TextLine? lastValidSpecificHeaderSpanEnd, + string optionName, + string optionValue, + Language language) + { + var newEntry = $"{optionName}={optionValue}"; + if (lastValidSpecificHeaderSpanEnd.HasValue) + { + if (lastValidSpecificHeaderSpanEnd.Value.ToString().Trim().Length != 0) + { + newEntry = "\r\n" + newEntry; // TODO(jmarolf): do we need to read in the users newline settings? + } + + return (editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(lastValidSpecificHeaderSpanEnd.Value.Span.End, 0), newEntry)), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + else if (lastValidHeaderSpanEnd.HasValue) + { + if (lastValidHeaderSpanEnd.Value.ToString().Trim().Length != 0) + { + newEntry = "\r\n" + newEntry; // TODO(jmarolf): do we need to read in the users newline settings? + } + + return (editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(lastValidHeaderSpanEnd.Value.Span.End, 0), newEntry)), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + + // We need to generate a new header such as '[*.cs]' or '[*.vb]': + // - For compiler diagnostic entries and code style entries which have per-language option = false, generate only [*.cs] or [*.vb]. + // - For the remainder, generate [*.{cs,vb}] + // Insert a newline if not already present + var lines = editorConfigText.Lines; + var lastLine = lines.Count > 0 ? lines[^1] : default; + var prefix = string.Empty; + if (lastLine.ToString().Trim().Length != 0) + { + prefix = "\r\n"; + } + + // Insert newline if file is not empty + if (lines.Count > 1 && lastLine.ToString().Trim().Length == 0) + { + prefix += "\r\n"; + } + + if (language.HasFlag(Language.CSharp) && language.HasFlag(Language.VisualBasic)) + { + prefix += "[*.{cs,vb}]\r\n"; + } + else if (language.HasFlag(Language.CSharp)) + { + prefix += "[*.cs]\r\n"; + } + else if (language.HasFlag(Language.VisualBasic)) + { + prefix += "[*.vb]\r\n"; + } + + var result = editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(editorConfigText.Length, 0), prefix + newEntry)); + return (result, lastValidHeaderSpanEnd, result.Lines[^2]); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs new file mode 100644 index 0000000000000..30055852de7a8 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal abstract class SettingsUpdaterBase : ISettingUpdater + { + private readonly List<(TOption option, TValue value)> _queue = new(); + private readonly SemaphoreSlim _guard = new(1); + private readonly Workspace _workspace; + private readonly string _editorconfigPath; + + protected abstract Task GetNewTextAsync(AnalyzerConfigDocument analyzerConfigDocument, IReadOnlyList<(TOption option, TValue value)> settingsToUpdate, CancellationToken token); + + protected SettingsUpdaterBase(Workspace workspace, string editorconfigPath) + { + _workspace = workspace; + _editorconfigPath = editorconfigPath; + } + + public async Task QueueUpdateAsync(TOption setting, TValue value) + { + using (await _guard.DisposableWaitAsync().ConfigureAwait(false)) + { + _queue.Add((setting, value)); + } + + return true; + } + + public async Task?> GetChangedEditorConfigAsync(CancellationToken token) + { + var solution = _workspace.CurrentSolution; + var analyzerConfigDocument = solution.Projects + .SelectMany(p => p.AnalyzerConfigDocuments) + .FirstOrDefault(d => d.FilePath == _editorconfigPath); + + if (analyzerConfigDocument is null) + return null; + + var originalText = await analyzerConfigDocument.GetTextAsync(token).ConfigureAwait(false); + using (await _guard.DisposableWaitAsync(token).ConfigureAwait(false)) + { + var newText = await GetNewTextAsync(analyzerConfigDocument, _queue, token).ConfigureAwait(false); + if (newText is null || newText.Equals(originalText)) + { + _queue.Clear(); + return null; + } + else + { + _queue.Clear(); + return newText.GetTextChanges(originalText); + } + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorFeaturesResources.resx b/src/EditorFeatures/Core/EditorFeaturesResources.resx index 78f79c7e0045c..9ab5fe8ca5240 100644 --- a/src/EditorFeatures/Core/EditorFeaturesResources.resx +++ b/src/EditorFeatures/Core/EditorFeaturesResources.resx @@ -951,4 +951,124 @@ Do you want to proceed? Gathering Suggestions - Waiting for the solution to fully load + + No + + + Yes + + + Always for clarity + + + Prefer auto properties + + + Avoid unused parameters + + + Do not prefer 'this.' or 'Me.' + + + For locals, parameters and members + + + For member access expressions + + + In arithmetic operators + + + In other binary operators + + + In other operators + + + In relational operators + + + Never if unnecessary + + + Non-public methods + + + Prefer coalesce expression + + + Prefer collection initializer + + + Prefer compound assignments + + + Prefer conditional expression over 'if' with assignments + + + Prefer conditional expression over 'if' with returns + + + Prefer explicit tuple name + + + Prefer framework type + + + Prefer inferred anonymous type member names + + + Prefer inferred tuple element names + + + Prefer 'is null' for reference equality checks + + + Prefer null propagation + + + Prefer object initializer + + + Prefer predefined type + + + Prefer readonly fields + + + Prefer simplified boolean expressions + + + Prefer 'System.HashCode' in 'GetHashCode' + + + Prefer 'this.' or 'Me.' + + + Qualify event access with 'this' or 'Me' + + + Qualify field access with 'this' or 'Me' + + + Qualify method access with 'this' or 'Me' + + + Qualify property access with 'this' or 'Me' + + + Indentation Size + + + Insert Final Newline + + + New Line + + + Tab Size + + + Use Tabs + \ No newline at end of file diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index f021a47cec7e1..f18312bb356a4 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Relace přejmenování na řádku je pro identifikátor {0} aktivní. Pokud chcete získat přístup k dalším možnostem, znovu volejte přejmenování na řádku. Můžete kdykoli pokračovat v úpravách identifikátoru, který se přejmenovává. @@ -12,6 +17,11 @@ Aplikují se změny. + + Avoid unused parameters + Avoid unused parameters + + Change configuration Změnit konfiguraci @@ -27,6 +37,11 @@ Nakonfigurovat teď + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Tuto zprávu už příště nezobrazovat @@ -57,6 +72,16 @@ Filtr Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Příkaz Formátovat dokument provedl další čištění. @@ -87,11 +112,41 @@ Přejít na základní typ + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Vložené nápovědy + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Neplatný název sestavení @@ -112,6 +167,26 @@ Hledají se báze... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operátor – přetížení @@ -122,6 +197,91 @@ Sledování vkládání + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Text preprocesoru @@ -132,6 +292,26 @@ Interpunkce + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Přejmenovat _soubor (typ neodpovídá názvu souboru) @@ -162,6 +342,11 @@ Symbol – statický + + Tab Size + Tab Size + + The symbol has no base. Tento symbol nemá žádný základ. @@ -187,6 +372,11 @@ Přepíná se komentář k řádku... + + Use Tabs + Use Tabs + + User Members - Constants Uživatelské členy – konstanty @@ -412,6 +602,11 @@ Při přejmenování dojde k aktualizaci {0} odkazů v {1} souborech. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Tento element nejde přejmenovat, protože je obsažen v souboru jen pro čtení. @@ -632,6 +827,11 @@ Už se sleduje dokument se shodným klíčem. + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Dokument se aktuálně nesleduje. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index d95dac708cd4a..70c7fa502c3a9 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Für den Bezeichner "{0}" ist eine Inline-Umbenennungssitzung aktiv. Rufen Sie die Inline-Umbenennung erneut auf, um auf zusätzliche Optionen zuzugreifen. Sie können den Bezeichner, der gerade umbenannt wird, jederzeit weiterbearbeiten. @@ -12,6 +17,11 @@ Änderungen werden übernommen + + Avoid unused parameters + Avoid unused parameters + + Change configuration Konfiguration ändern @@ -27,6 +37,11 @@ Jetzt konfigurieren + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Diese Meldung nicht mehr anzeigen @@ -57,6 +72,16 @@ Filter Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Bei der Dokumentformatierung wurde eine zusätzliche Bereinigung durchgeführt. @@ -87,11 +112,41 @@ Zu Basis wechseln + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Inlinehinweise + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Ungültiger Assemblyname. @@ -112,6 +167,26 @@ Basen werden gesucht... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operator - überladen @@ -122,6 +197,91 @@ Nachverfolgung von Einfügevorgängen + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Präprozessortext @@ -132,6 +292,26 @@ Interpunktion + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) _Datei umbenennen (Typ entspricht nicht dem Dateinamen) @@ -162,6 +342,11 @@ Symbol – statisch + + Tab Size + Tab Size + + The symbol has no base. Das Symbol verfügt über keine Basis. @@ -187,6 +372,11 @@ Kommentarzeile wird ein-/ausgeschaltet... + + Use Tabs + Use Tabs + + User Members - Constants Benutzermember – Konstanten @@ -412,6 +602,11 @@ Durch das Umbenennen werden {0} Verweise in {1} Dateien aktualisiert. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Dieses Element kann nicht umbenannt werden, weil es in einer schreibgeschützten Datei enthalten ist. @@ -632,6 +827,11 @@ Dokument mit identischem Schlüssel wird bereits verfolgt + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Dokument wird aktuell nicht verfolgt diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 1851eb7accc6d..c766c0ead40a2 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Hay una sesión de cambio de nombre insertado que está activa para el identificador "{0}". Vuelva a invocar el cambio de nombre insertado para acceder a más opciones. Puede continuar editando el identificador cuyo nombre se va a cambiar en cualquier momento. @@ -12,6 +17,11 @@ Aplicando cambios + + Avoid unused parameters + Avoid unused parameters + + Change configuration Configuración de cambio @@ -27,6 +37,11 @@ Configúrela ahora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again No volver a mostrar este mensaje @@ -57,6 +72,16 @@ Filtrar Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup El formateo del documento realizó una limpieza adicional @@ -87,11 +112,41 @@ Ir a base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Sugerencias insertadas + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nombre de ensamblado no válido @@ -112,6 +167,26 @@ Buscando las bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operador: sobrecargado @@ -122,6 +197,91 @@ Seguimiento de pegado + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texto del preprocesador @@ -132,6 +292,26 @@ Puntuación + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Ca_mbiar nombre de archivo (el tipo no coincide con el nombre de archivo) @@ -162,6 +342,11 @@ Símbolo: estático + + Tab Size + Tab Size + + The symbol has no base. El símbolo no tiene base. @@ -187,6 +372,11 @@ Alternando comentario de línea... + + Use Tabs + Use Tabs + + User Members - Constants Usuarios miembros: constantes @@ -412,6 +602,11 @@ Al cambiar el nombre se actualizarán {0} referencias en {1} archivos. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. No se puede cambiar el nombre de este elemento porque está incluido en un archivo de solo lectura. @@ -632,6 +827,11 @@ Ya se está siguiendo un documento con una clave idéntica + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked el documento no es objeto de seguimiento actualmente diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index 9f7a1b08820e4..6dbedb6fd2017 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Une session de renommage inline est active pour l'identificateur '{0}'. Appelez à nouveau le renommage inline pour accéder à des options supplémentaires. Vous pouvez continuer à modifier l'identificateur renommé à tout moment. @@ -12,6 +17,11 @@ Application des changements + + Avoid unused parameters + Avoid unused parameters + + Change configuration Changer la configuration @@ -27,6 +37,11 @@ Configurer maintenant + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Ne plus afficher ce message @@ -57,6 +72,16 @@ Filtrer Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup L'opération Mettre en forme le document a effectué un nettoyage supplémentaire @@ -87,11 +112,41 @@ Accéder à la base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Indicateurs inline + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nom d'assembly non valide @@ -112,6 +167,26 @@ Localisation des bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Opérateur - surchargé @@ -122,6 +197,91 @@ Suivi du collage + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texte du préprocesseur @@ -132,6 +292,26 @@ Ponctuation + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Renommer le _fichier (le type ne correspond pas au nom du fichier) @@ -162,6 +342,11 @@ Symbole - statique + + Tab Size + Tab Size + + The symbol has no base. Le symbole n'a pas de base. @@ -187,6 +372,11 @@ Activation/désactivation du commentaire de ligne... + + Use Tabs + Use Tabs + + User Members - Constants Membres utilisateurs - constantes @@ -412,6 +602,11 @@ Le renommage va entraîner la mise à jour de {0} références dans {1} fichiers. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Vous ne pouvez pas renommer cet élément, car il est contenu dans un fichier en lecture seule. @@ -632,6 +827,11 @@ Suivi du document déjà initié avec une clé identique + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Le document ne fait pas actuellement l'objet d'un suivi diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index 9f33e8372d21d..c7631334ffa41 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Per l'identificatore '{0}' è attiva una sessione di ridenominazione inline. Richiamare nuovamente la ridenominazione inline per accedere alle opzioni aggiuntive. È possibile continuare a modificare l'identificatore da rinominare in qualsiasi momento. @@ -12,6 +17,11 @@ Applicazione delle modifiche in corso + + Avoid unused parameters + Avoid unused parameters + + Change configuration Cambia la configurazione @@ -27,6 +37,11 @@ Configura ora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Non visualizzare più questo messaggio @@ -57,6 +72,16 @@ Filtro Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Formatta documento ha eseguito una pulizia aggiuntiva @@ -87,11 +112,41 @@ Vai a base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Suggerimenti inline + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nome di assembly non valido @@ -112,6 +167,26 @@ Individuazione delle basi... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operatore - Overload @@ -122,6 +197,91 @@ Verifica Incolla + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Testo preprocessore @@ -132,6 +292,26 @@ Punteggiatura + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Rinomina _file (il tipo non corrisponde al nome file) @@ -162,6 +342,11 @@ Simbolo - Statico + + Tab Size + Tab Size + + The symbol has no base. Non è presente alcuna base per il simbolo. @@ -187,6 +372,11 @@ Attivazione/disattivazione del commento per la riga... + + Use Tabs + Use Tabs + + User Members - Constants Membri utente - Costanti @@ -412,6 +602,11 @@ Con la ridenominazione verranno aggiornati {0} riferimenti in {1} file. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Non è possibile rinominare questo elemento perché è contenuto in un file di sola lettura. @@ -632,6 +827,11 @@ La verifica del documento con chiave identica è già in corso + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked al momento il documento non è sottoposto a verifica diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index c8db7e1a59d4a..290649d3d017e 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 識別子 '{0}' のインラインの名前変更セッションがアクティブです。追加オプションにアクセスするには、インラインの名前変更をもう一度呼び出します。名前を変更する識別子はいつでも引き続き編集できます。 @@ -12,6 +17,11 @@ 変更の適用 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 構成の変更 @@ -27,6 +37,11 @@ 今すぐ構成する + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 今後、このメッセージを表示しない @@ -57,6 +72,16 @@ フィルター Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup ドキュメントのフォーマットで追加のクリーンアップが実行されました @@ -87,11 +112,41 @@ 基本へ移動 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints インラインのヒント + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 無効なアセンブリ名 @@ -112,6 +167,26 @@ ベースを検索しています... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 演算子 - オーバーロード @@ -122,6 +197,91 @@ 追跡の貼り付け + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text プリプロセッサ テキスト @@ -132,6 +292,26 @@ 句読点 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) ファイル名の変更 (種類がファイル名と一致しません)(_F) @@ -162,6 +342,11 @@ シンボル - 静的 + + Tab Size + Tab Size + + The symbol has no base. シンボルにベースがありません。 @@ -187,6 +372,11 @@ 行コメントを切り替えています... + + Use Tabs + Use Tabs + + User Members - Constants ユーザー メンバー - 定数 @@ -412,6 +602,11 @@ 名前を変更すると、{1} 個のファイル内の {0} 個の参照が更新されます。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. この要素は、読み取り専用ファイルに含まれているため、名前を変更できません。 @@ -632,6 +827,11 @@ 同じキーを持つドキュメントを既に追跡しています + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked ドキュメントが現在追跡されていません diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index 2c53542b5f05f..0a4c2a7a09fd2 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 식별자 '{0}'의 인라인 이름 바꾸기 세션이 활성 상태입니다. 추가 옵션에 액세스하려면 인라인 이름 바꾸기를 다시 호출하세요. 언제든지 이름을 바꾸려는 식별자를 계속 편집할 수 있습니다. @@ -12,6 +17,11 @@ 변경 내용 적용 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 구성 변경 @@ -27,6 +37,11 @@ 지금 구성 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 이 메시지를 다시 표시하지 않음 @@ -57,6 +72,16 @@ 필터 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 추가 정리를 수행 하는 문서 @@ -87,11 +112,41 @@ 기본으로 이동 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 인라인 힌트 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 잘못된 어셈블리 이름 @@ -112,6 +167,26 @@ 베이스를 찾는 중... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 연산자 - 오버로드됨 @@ -122,6 +197,91 @@ 붙여넣기 추적 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 전처리기 텍스트 @@ -132,6 +292,26 @@ 문장 부호 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 파일 이름 바꾸기(형식이 파일 이름과 일치하지 않음)(_F) @@ -162,6 +342,11 @@ 기호 - 정적 + + Tab Size + Tab Size + + The symbol has no base. 기호에 베이스가 없습니다. @@ -187,6 +372,11 @@ 줄 주석을 토글하는 중... + + Use Tabs + Use Tabs + + User Members - Constants 사용자 멤버 - 상수 @@ -412,6 +602,11 @@ 이름 바꾸기로 {1}개의 파일에서 {0}개의 참조가 업데이트됩니다. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 이 요소는 읽기 전용 파일에 포함되어 있으므로 이름을 바꿀 수 없습니다. @@ -632,6 +827,11 @@ 동일한 키로 이미 문서를 추적하는 중 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 문서를 현재 추적하고 있지 않습니다. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index d4635cf956c79..4cffdb16a91fb 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Wbudowana sesja zmieniania nazwy jest aktywna dla identyfikatora „{0}”. Wywołaj ponownie wbudowane zmienianie nazwy, aby uzyskać dostęp do dodatkowych opcji. W dowolnym momencie możesz kontynuować edytowanie identyfikatora, którego nazwa jest zmieniana. @@ -12,6 +17,11 @@ Stosowanie zmian + + Avoid unused parameters + Avoid unused parameters + + Change configuration Zmień konfigurację @@ -27,6 +37,11 @@ Skonfiguruj je teraz + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Nie pokazuj tego komunikatu ponownie @@ -57,6 +72,16 @@ Filtr Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Funkcja formatowania dokumentu wykonała dodatkowe czyszczenie @@ -87,11 +112,41 @@ Przejdź do podstawy + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Wskazówki w tekście + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nieprawidłowa nazwa zestawu @@ -112,6 +167,26 @@ Trwa lokalizowanie baz... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operator — przeciążony @@ -122,6 +197,91 @@ Śledzenie wklejania + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Tekst preprocesora @@ -132,6 +292,26 @@ Interpunkcja + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Zmień nazwę _pliku (typ nie zgadza się z nazwą pliku) @@ -162,6 +342,11 @@ Symbol — statyczny + + Tab Size + Tab Size + + The symbol has no base. Symbol nie ma wartości podstawowej. @@ -187,6 +372,11 @@ Trwa przełączanie komentarza wiersza... + + Use Tabs + Use Tabs + + User Members - Constants Składowe użytkowników — stałe @@ -412,6 +602,11 @@ Zmiana nazwy spowoduje zaktualizowanie odwołań ({0}) w plikach ({1}). + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Nie możesz zmienić nazwy tego elementu, ponieważ jest on zawarty w pliku tylko do odczytu. @@ -632,6 +827,11 @@ Dokument z identycznym kluczem jest już śledzony + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked dokument obecnie nie jest śledzony diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index 7e76a95441135..8944312186a26 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Uma sessão de renomeação embutida está ativa para o identificador '{0}'. Invoque a renomeação embutida novamente para acessar opções adicionais. Você pode continuar a editar o identificador que está sendo renomeado a qualquer momento. @@ -12,6 +17,11 @@ Aplicando mudanças + + Avoid unused parameters + Avoid unused parameters + + Change configuration Alterar configuração @@ -27,6 +37,11 @@ Configurar agora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Não mostrar esta mensagem novamente @@ -57,6 +72,16 @@ Filtrar Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup A Formatação do Documento executou uma limpeza adicional @@ -87,11 +112,41 @@ Ir Para a Base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Dicas Embutidas + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nome do assembly inválido @@ -112,6 +167,26 @@ Localizando as bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operador – Sobrecarregado @@ -122,6 +197,91 @@ Colar Acompanhamento + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texto de Pré-Processador @@ -132,6 +292,26 @@ Pontuação + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Renomear _arquivo (o tipo não corresponde ao nome do arquivo) @@ -162,6 +342,11 @@ Símbolo – Estático + + Tab Size + Tab Size + + The symbol has no base. O símbolo não tem nenhuma base. @@ -187,6 +372,11 @@ Ativando/desativando o comentário de linha... + + Use Tabs + Use Tabs + + User Members - Constants Membros de Usuário – Constantes @@ -412,6 +602,11 @@ Renomear atualizará {0} referências em {1} arquivos. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Você não pode renomear este elemento porque ele está contido em um arquivo somente leitura. @@ -632,6 +827,11 @@ Já está a rastrear o documento com chave idêntica + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked documento não está sendo rastreado no momento diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index 9ca80001bed53..45e49a2419350 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Встроенный сеанс переименования активен для идентификатора "{0}". Снова вызовите встроенное переименование, чтобы получить доступ к дополнительным параметрам. Вы можете в любое время продолжить изменение переименованного идентификатора. @@ -12,6 +17,11 @@ Применение изменений + + Avoid unused parameters + Avoid unused parameters + + Change configuration Изменить конфигурацию @@ -27,6 +37,11 @@ Настройте ее сейчас + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Больше не показывать это сообщение @@ -57,6 +72,16 @@ Фильтр Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup При форматировании документа была выполнена дополнительная очистка @@ -87,11 +112,41 @@ Перейти к базовому + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Встроенные подсказки + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Недопустимое имя сборки @@ -112,6 +167,26 @@ Обнаружение баз… + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Оператор — перегружен @@ -122,6 +197,91 @@ Вставить отслеживание + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Текст препроцессора @@ -132,6 +292,26 @@ Пунктуация + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Переименовать фай_л (тип не соответствует имени файла) @@ -162,6 +342,11 @@ Символ — статический + + Tab Size + Tab Size + + The symbol has no base. У этого символа нет основания. @@ -187,6 +372,11 @@ Переключение комментария строки... + + Use Tabs + Use Tabs + + User Members - Constants Участники-пользователи — константы @@ -412,6 +602,11 @@ При переименовании будут обновлены ссылки в количестве {0} шт. в следующем числе файлов: {1}. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Невозможно переименовать этот элемент, так как он содержится в файле, доступном только для чтения. @@ -632,6 +827,11 @@ Документ с идентичным ключом уже отслеживается. + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Документ в настоящее время не отслеживается. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index 0d35b1572e24f..819fc7270940f 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. '{0}' tanımlayıcısı için bir satır içi yeniden adlandırma oturumu etkin. Ek seçeneklere erişmek için satır içi yeniden adlandırmayı tekrar çağırın. İstediğiniz zaman yeniden adlandırılan tanımlayıcıyı düzenlemeye devam edebilirsiniz. @@ -12,6 +17,11 @@ Değişiklikler uygulanıyor + + Avoid unused parameters + Avoid unused parameters + + Change configuration Değiştir yapılandırma @@ -27,6 +37,11 @@ Hemen yapılandırın + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Bu iletiyi bir daha gösterme @@ -57,6 +72,16 @@ Filtre Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Biçimi belge ek temizleme işlemi @@ -87,11 +112,41 @@ Tabana Git + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Satır İçi İpuçları + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Geçersiz derleme adı @@ -112,6 +167,26 @@ Tabanlar bulunuyor... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded İşleç - Aşırı Yüklenmiş @@ -122,6 +197,91 @@ İzleme Yapıştır + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Ön İşlemci Metni @@ -132,6 +292,26 @@ Noktalama İşareti + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) _Dosyayı yeniden adlandır (tür, dosya adıyla eşleşmiyor) @@ -162,6 +342,11 @@ Sembol - statik + + Tab Size + Tab Size + + The symbol has no base. Sembolde taban yok. @@ -187,6 +372,11 @@ Satır açıklaması değiştiriliyor... + + Use Tabs + Use Tabs + + User Members - Constants Kullanıcı Üyeler - Sabitler @@ -412,6 +602,11 @@ Yeniden adlandırma işlemi {1} dosyadaki {0} başvuruyu güncelleştirecek. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Salt okunur bir dosyada bulunduğundan bu öğeyi yeniden adlandıramazsınız. @@ -632,6 +827,11 @@ Belge zaten özdeş anahtar ile izleniyor + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Belge şu anda izlenmiyor diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 30322875c1dff..4e22e9caf209c 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 标识符“{0}”的内联重命名会话处于活动状态。再次调用内联重命名以访问其他选项。可随时继续编辑正在重命名的标识符。 @@ -12,6 +17,11 @@ 应用更改 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 更改配置 @@ -27,6 +37,11 @@ 立即配置 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 不再显示此消息 @@ -57,6 +72,16 @@ 筛选 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 格式文档执行了额外的清理 @@ -87,11 +112,41 @@ 转到基础映像 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 内联提示 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 程序集名称无效 @@ -112,6 +167,26 @@ 正在查找基... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 运算符-重载 @@ -122,6 +197,91 @@ 粘贴跟踪信息 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 预处理器文本 @@ -132,6 +292,26 @@ 标点 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 重命名文件(类型与文件名不匹配)(_F) @@ -162,6 +342,11 @@ 符号-静态 + + Tab Size + Tab Size + + The symbol has no base. 符号没有基数。 @@ -187,6 +372,11 @@ 正在切换为行注释... + + Use Tabs + Use Tabs + + User Members - Constants 用户成员-常量 @@ -412,6 +602,11 @@ 重命名将更新 {1} 个文件中的 {0} 个引用。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 无法重命名此元素,因为它包含在只读文件中。 @@ -632,6 +827,11 @@ 已使用等价键跟踪文档 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 当前未跟踪文档 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 75f00e8d42a2b..ca9eea1295267 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -2,6 +2,11 @@ + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 識別碼 '{0}' 有正在使用的內嵌重新命名工作階段。再次叫用內嵌重新命名可存取其他選項。您隨時可以繼續編輯正在重新命名的識別碼。 @@ -12,6 +17,11 @@ 正在套用變更 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 變更組態 @@ -27,6 +37,11 @@ 立即設定 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 不再顯示此訊息 @@ -57,6 +72,16 @@ 篩選 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 執行額外清除的格式化文件 @@ -87,11 +112,41 @@ 移至基底 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 內嵌提示 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 組件名稱無效 @@ -112,6 +167,26 @@ 正在尋找基底... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 運算子 - 多載 @@ -122,6 +197,91 @@ 貼上追蹤 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 前置處理器文字 @@ -132,6 +292,26 @@ 標點符號 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 重新命名檔案 (類型不符合檔案名稱)(_F) @@ -162,6 +342,11 @@ 符號 - 靜態 + + Tab Size + Tab Size + + The symbol has no base. 該符號沒有任何基底。 @@ -187,6 +372,11 @@ 正在切換行註解... + + Use Tabs + Use Tabs + + User Members - Constants 使用者成員 - 常數 @@ -412,6 +602,11 @@ 重新命名會更新 {1} 個檔案中的 {0} 個參考。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 因為此項目包含在唯讀檔案中,所以無法重新命名。 @@ -632,6 +827,11 @@ 已追蹤具有相同索引鍵的文件 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 文件目前未加以追蹤 diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs new file mode 100644 index 0000000000000..18186ed974e12 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + internal class BinaryOperatorSpacingOptionsViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public BinaryOperatorSpacingOptionsViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(BinaryOperatorSpacingOptions newValue) + { + _setting.SetValue(newValue); + } + + protected override BinaryOperatorSpacingOptions GetCurrentValue() + { + return (BinaryOperatorSpacingOptions)_setting.GetValue()!; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, BinaryOperatorSpacingOptions value)> EnumerateOptions() + { + yield return (CSharpVSResources.Ignore_spaces_around_binary_operators, BinaryOperatorSpacingOptions.Ignore); + yield return (CSharpVSResources.Remove_spaces_before_and_after_binary_operators, BinaryOperatorSpacingOptions.Remove); + yield return (CSharpVSResources.Insert_space_before_and_after_binary_operators, BinaryOperatorSpacingOptions.Single); + } + } + } +} diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs new file mode 100644 index 0000000000000..6a5085101a91b --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class BinaryOperatorSpacingOptionsViewModelFactory : IEnumSettingViewModelFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public BinaryOperatorSpacingOptionsViewModelFactory() + { + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new BinaryOperatorSpacingOptionsViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) + => key.Option.Type == typeof(BinaryOperatorSpacingOptions); + } +} diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs new file mode 100644 index 0000000000000..bbbfcda4f07d9 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class LabelPositionOptionsViewModelFactory : IEnumSettingViewModelFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LabelPositionOptionsViewModelFactory() + { + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new LabelPositionOptionsViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) + => key.Option.Type == typeof(LabelPositionOptions); + } + + internal class LabelPositionOptionsViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public LabelPositionOptionsViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(LabelPositionOptions newValue) + { + _setting.SetValue(newValue); + } + + protected override LabelPositionOptions GetCurrentValue() + { + return (LabelPositionOptions)_setting.GetValue()!; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, LabelPositionOptions value)> EnumerateOptions() + { + yield return ("place goto labels in leftmost column", LabelPositionOptions.LeftMost); + yield return ("indent labels normally", LabelPositionOptions.NoIndent); + yield return ("place goto labels one indent less than current", LabelPositionOptions.OneLess); + } + } + } +} diff --git a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj index 8eb596e8f12be..3a8ea68c1b12b 100644 --- a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj +++ b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj @@ -15,18 +15,9 @@ false - - - + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml new file mode 100644 index 0000000000000..4111d4fb1be9b --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml @@ -0,0 +1,17 @@ + + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml.cs new file mode 100644 index 0000000000000..6f49fdcbb29f8 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/AnalyzerSettingsView.xaml.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.TextManager.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View +{ + /// + /// Interaction logic for AnalyzerSettingsView.xaml + /// + internal partial class AnalyzerSettingsView : UserControl, ISettingsEditorView + { + private readonly IVsTextLines _vsTextLines; + private readonly IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService; + private readonly IThreadingContext _threadingContext; + private readonly IWpfSettingsEditorViewModel _viewModel; + + public AnalyzerSettingsView(IVsTextLines vsTextLines, + IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService, + IThreadingContext threadingContext, + IWpfSettingsEditorViewModel viewModel) + { + InitializeComponent(); + _vsTextLines = vsTextLines; + _vsEditorAdaptersFactoryService = vsEditorAdaptersFactoryService; + _threadingContext = threadingContext; + _viewModel = viewModel; + TableControl = _viewModel.GetTableControl(); + AnalyzerTable.Child = TableControl.Control; + } + + public UserControl SettingControl => this; + public IWpfTableControl TableControl { get; } + + public void Synchronize() + { + if (IsKeyboardFocusWithin) + { + EditorTextUpdater.UpdateText(_threadingContext, _vsEditorAdaptersFactoryService, _vsTextLines, _viewModel); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerCategoryColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerCategoryColumnDefinition.cs new file mode 100644 index 0000000000000..c02f32eb7cb08 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerCategoryColumnDefinition.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + [Export(typeof(IDefaultColumnGroup))] + [Name(nameof(AnalyzerCategoryGroupingSet))] // Required, name of the default group + [GroupColumns(Category)] // Required, the names of the columns in the grouping + internal class AnalyzerCategoryGroupingSet : IDefaultColumnGroup + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerCategoryGroupingSet() + { + } + } + + [Export(typeof(ITableColumnDefinition))] + [Name(Category)] // TODO(jmarolf): make sure all columns have ToString implementation + internal class AnalyzerCategoryColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerCategoryColumnDefinition() + { + } + + public override string Name => Category; + public override string DisplayName => ServicesVSResources.Category; + public override double MinWidth => 80; + public override bool DefaultVisible => false; + public override bool IsFilterable => true; + public override TextWrapping TextWrapping => TextWrapping.NoWrap; + + private static string? GetCategoryName(ITableEntryHandle entry) + => entry.TryGetValue(Category, out string? categoryName) + ? categoryName + : null; + + public override IEntryBucket? CreateBucketForEntry(ITableEntryHandle entry) + { + var categoryName = GetCategoryName(entry); + return categoryName is not null ? new StringEntryBucket(categoryName) : null; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerDescriptionColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerDescriptionColumnDefinition.cs new file mode 100644 index 0000000000000..8dd9c8d563347 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerDescriptionColumnDefinition.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Description)] + internal class AnalyzerDescriptionColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerDescriptionColumnDefinition() + { + } + + public override string Name => Description; + public override string DisplayName => ServicesVSResources.Description; + public override bool IsFilterable => false; + public override double MinWidth => 350; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerEnabledColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerEnabledColumnDefinition.cs new file mode 100644 index 0000000000000..fc188c9d07b53 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerEnabledColumnDefinition.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Enabled)] + internal class AnalyzerEnabledColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerEnabledColumnDefinition() + { + } + + public override string Name => Enabled; + public override string DisplayName => ServicesVSResources.Enabled; + public override bool IsFilterable => true; + public override double MinWidth => 50; + + public override bool TryCreateColumnContent(ITableEntryHandle entry, bool singleColumnView, out FrameworkElement content) + { + var checkBox = new CheckBox(); + if (entry.TryGetValue(Name, out bool enabled)) + { + checkBox.IsChecked = enabled; + } + + content = checkBox; + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerIdColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerIdColumnDefinition.cs new file mode 100644 index 0000000000000..2f009398be4e7 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerIdColumnDefinition.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Id)] + internal class AnalyzerIdColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerIdColumnDefinition() + { + } + + public override string Name => Id; + public override string DisplayName => ServicesVSResources.Id; + public override bool IsFilterable => true; + public override double MinWidth => 50; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs new file mode 100644 index 0000000000000..d0bd12f1b0429 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerSeverityColumnDefinition.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Severity)] + internal class AnalyzerSeverityColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerSeverityColumnDefinition() + { + } + + public override string Name => Severity; + public override string DisplayName => ServicesVSResources.Severity; + public override bool IsFilterable => true; + public override double MinWidth => 120; + + public override bool TryCreateColumnContent(ITableEntryHandle entry, bool singleColumnView, out FrameworkElement? content) + { + if (!entry.TryGetValue(Severity, out AnalyzerSetting severity)) + { + content = null; + return false; + } + + var control = new SeverityControl(severity); + content = control; + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerTitleColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerTitleColumnDefinition.cs new file mode 100644 index 0000000000000..3fd42cab887e9 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/ColumnDefinitions/AnalyzerTitleColumnDefinition.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Analyzer; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View.ColumnDefinitions +{ + + [Export(typeof(ITableColumnDefinition))] + [Name(Title)] + internal class AnalyzerTitleColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerTitleColumnDefinition() + { + } + + public override string Name => Title; + public override string DisplayName => ServicesVSResources.Title; + public override bool IsFilterable => false; + public override double MinWidth => 350; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml new file mode 100644 index 0000000000000..77e8bb80fd63f --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml.cs new file mode 100644 index 0000000000000..37aa5938d5de4 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/View/SeverityControl.xaml.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Controls; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.Imaging.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View +{ + /// + /// Interaction logic for SeverityControl.xaml + /// + internal partial class SeverityControl : UserControl + { + private readonly ComboBox _comboBox; + private readonly AnalyzerSetting _setting; + + public SeverityControl(AnalyzerSetting setting) + { + InitializeComponent(); + var refactoring = CreateGridElement(KnownMonikers.None, ServicesVSResources.Disabled); + var suggestion = CreateGridElement(KnownMonikers.StatusInformation, ServicesVSResources.Suggestion); + var warning = CreateGridElement(KnownMonikers.StatusWarning, ServicesVSResources.Warning); + var error = CreateGridElement(KnownMonikers.StatusError, ServicesVSResources.Error); + _comboBox = new ComboBox() + { + ItemsSource = new[] + { + refactoring, + suggestion, + warning, + error + } + }; + + switch (setting.Severity) + { + case DiagnosticSeverity.Hidden: + _comboBox.SelectedIndex = 0; + break; + case DiagnosticSeverity.Info: + _comboBox.SelectedIndex = 1; + break; + case DiagnosticSeverity.Warning: + _comboBox.SelectedIndex = 2; + break; + case DiagnosticSeverity.Error: + _comboBox.SelectedIndex = 3; + break; + default: + break; + } + + _comboBox.SelectionChanged += ComboBox_SelectionChanged; + + _ = RootGrid.Children.Add(_comboBox); + _setting = setting; + } + + private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + switch (_comboBox.SelectedIndex) + { + case 0: + _setting.ChangeSeverity(DiagnosticSeverity.Hidden); + return; + case 1: + _setting.ChangeSeverity(DiagnosticSeverity.Info); + return; + case 2: + _setting.ChangeSeverity(DiagnosticSeverity.Warning); + return; + case 3: + _setting.ChangeSeverity(DiagnosticSeverity.Error); + return; + default: return; + } + } + + private static FrameworkElement CreateGridElement(ImageMoniker imageMoniker, string text) + { + var stackPanel = new StackPanel + { + Orientation = Orientation.Horizontal, + HorizontalAlignment = HorizontalAlignment.Stretch + }; + + var block = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + Text = text + }; + + if (!imageMoniker.IsNullImage()) + { + // If we have an image and text, then create some space between them. + block.Margin = new Thickness(5.0, 0.0, 0.0, 0.0); + + var image = new CrispImage + { + VerticalAlignment = VerticalAlignment.Center, + Moniker = imageMoniker + }; + image.Width = image.Height = 16.0; + + _ = stackPanel.Children.Add(image); + } + + // Always add the textblock last so it can follow the image. + _ = stackPanel.Children.Add(block); + + return stackPanel; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs new file mode 100644 index 0000000000000..9ff153d53e7ba --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.ViewModel +{ + internal partial class AnalyzerSettingsViewModel : SettingsViewModelBase< + AnalyzerSetting, + AnalyzerSettingsViewModel.SettingsSnapshotFactory, + AnalyzerSettingsViewModel.SettingsEntriesSnapshot> + { + internal sealed class SettingsEntriesSnapshot : SettingsEntriesSnapshotBase + { + public SettingsEntriesSnapshot(ImmutableArray data, int currentVersionNumber) : base(data, currentVersionNumber) { } + + protected override bool TryGetValue(AnalyzerSetting result, string keyName, out object? content) + { + content = keyName switch + { + ColumnDefinitions.Analyzer.Enabled => result.IsEnabled, + ColumnDefinitions.Analyzer.Id => result.Id, + ColumnDefinitions.Analyzer.Title => result.Title, + ColumnDefinitions.Analyzer.Description => result.Description, + ColumnDefinitions.Analyzer.Category => result.Category, + ColumnDefinitions.Analyzer.Severity => result, + _ => null, + }; + + return content is not null; + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsSnapshotFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsSnapshotFactory.cs new file mode 100644 index 0000000000000..e7d1880bcd3b3 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsSnapshotFactory.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.ViewModel +{ + internal partial class AnalyzerSettingsViewModel : SettingsViewModelBase< + AnalyzerSetting, + AnalyzerSettingsViewModel.SettingsSnapshotFactory, + AnalyzerSettingsViewModel.SettingsEntriesSnapshot> + { + internal sealed class SettingsSnapshotFactory : SettingsSnapshotFactoryBase + { + public SettingsSnapshotFactory(ISettingsProvider data) : base(data) { } + + protected override SettingsEntriesSnapshot CreateSnapshot(ImmutableArray data, int currentVersionNumber) + => new(data, currentVersionNumber); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs new file mode 100644 index 0000000000000..b7bd04325b264 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.ViewModel +{ + + internal partial class AnalyzerSettingsViewModel : SettingsViewModelBase< + AnalyzerSetting, + AnalyzerSettingsViewModel.SettingsSnapshotFactory, + AnalyzerSettingsViewModel.SettingsEntriesSnapshot> + { + + public AnalyzerSettingsViewModel(ISettingsProvider data, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider) + : base(data, controlProvider, tableMangerProvider) + { } + + public override string Identifier => "AnalyzerSettings"; + + protected override SettingsSnapshotFactory CreateSnapshotFactory(ISettingsProvider data) + => new(data); + + protected override IEnumerable GetInitialColumnStates() + => new[] + { + new ColumnState2(ColumnDefinitions.Analyzer.Id, isVisible: true, width: 0), + new ColumnState2(ColumnDefinitions.Analyzer.Title, isVisible: true, width: 0), + new ColumnState2(ColumnDefinitions.Analyzer.Description, isVisible: false, width: 0), + new ColumnState2(ColumnDefinitions.Analyzer.Category, isVisible: true, width: 0, groupingPriority: 1), + new ColumnState2(ColumnDefinitions.Analyzer.Severity, isVisible: true, width: 0) + }; + + protected override string[] GetFixedColumns() + => new[] + { + ColumnDefinitions.Analyzer.Category, + ColumnDefinitions.Analyzer.Id, + ColumnDefinitions.Analyzer.Title, + ColumnDefinitions.Analyzer.Description, + ColumnDefinitions.Analyzer.Severity + }; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml new file mode 100644 index 0000000000000..2f44eacd3d449 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml @@ -0,0 +1,16 @@ + + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml.cs new file mode 100644 index 0000000000000..95a0349fcc6f7 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSettingsView.xaml.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.TextManager.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View +{ + /// + /// Interaction logic for CodeStyleView.xaml + /// + internal partial class CodeStyleSettingsView : UserControl, ISettingsEditorView + { + private readonly IVsTextLines _vsTextLines; + private readonly IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService; + private readonly IThreadingContext _threadingContext; + private readonly IWpfSettingsEditorViewModel _viewModel; + + public CodeStyleSettingsView(IVsTextLines vsTextLines, + IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService, + IThreadingContext threadingContext, + IWpfSettingsEditorViewModel viewModel) + { + InitializeComponent(); + _vsTextLines = vsTextLines; + _vsEditorAdaptersFactoryService = vsEditorAdaptersFactoryService; + _threadingContext = threadingContext; + _viewModel = viewModel; + TableControl = _viewModel.GetTableControl(); + CodeStyleTable.Child = TableControl.Control; + DataContext = viewModel; + } + + public UserControl SettingControl => this; + public IWpfTableControl TableControl { get; } + + public void Synchronize() + { + if (IsKeyboardFocusWithin) + { + EditorTextUpdater.UpdateText(_threadingContext, _vsEditorAdaptersFactoryService, _vsTextLines, _viewModel); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml new file mode 100644 index 0000000000000..493fd35c7a695 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml.cs new file mode 100644 index 0000000000000..3c62590dc1d04 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleSeverityControl.xaml.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Controls; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.Imaging.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View +{ + /// + /// Interaction logic for CodeStyleSeverityControl.xaml + /// + internal partial class CodeStyleSeverityControl : UserControl + { + private readonly ComboBox _comboBox; + private readonly CodeStyleSetting _setting; + + public CodeStyleSeverityControl(CodeStyleSetting setting) + { + InitializeComponent(); + var refactoring = CreateGridElement(KnownMonikers.None, ServicesVSResources.Refactoring_Only); + var suggestion = CreateGridElement(KnownMonikers.StatusInformation, ServicesVSResources.Suggestion); + var warning = CreateGridElement(KnownMonikers.StatusWarning, ServicesVSResources.Warning); + var error = CreateGridElement(KnownMonikers.StatusError, ServicesVSResources.Error); + _comboBox = new ComboBox() + { + ItemsSource = new[] + { + refactoring, + suggestion, + warning, + error + } + }; + + switch (setting.Severity) + { + case ReportDiagnostic.Hidden: + _comboBox.SelectedIndex = 0; + break; + case ReportDiagnostic.Info: + _comboBox.SelectedIndex = 1; + break; + case ReportDiagnostic.Warn: + _comboBox.SelectedIndex = 2; + break; + case ReportDiagnostic.Error: + _comboBox.SelectedIndex = 3; + break; + default: + break; + } + + _comboBox.SelectionChanged += ComboBox_SelectionChanged; + + _ = RootGrid.Children.Add(_comboBox); + _setting = setting; + } + + private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + switch (_comboBox.SelectedIndex) + { + case 0: + _setting.ChangeSeverity(DiagnosticSeverity.Hidden); + return; + case 1: + _setting.ChangeSeverity(DiagnosticSeverity.Info); + return; + case 2: + _setting.ChangeSeverity(DiagnosticSeverity.Warning); + return; + case 3: + _setting.ChangeSeverity(DiagnosticSeverity.Error); + return; + default: return; + } + } + + private static FrameworkElement CreateGridElement(ImageMoniker imageMoniker, string text) + { + var stackPanel = new StackPanel + { + Orientation = Orientation.Horizontal, + HorizontalAlignment = HorizontalAlignment.Stretch + }; + + var block = new TextBlock + { + VerticalAlignment = VerticalAlignment.Center, + Text = text + }; + + if (!imageMoniker.IsNullImage()) + { + // If we have an image and text, then create some space between them. + block.Margin = new Thickness(5.0, 0.0, 0.0, 0.0); + + var image = new CrispImage + { + VerticalAlignment = VerticalAlignment.Center, + Moniker = imageMoniker + }; + image.Width = image.Height = 16.0; + + _ = stackPanel.Children.Add(image); + } + + // Always add the textblock last so it can follow the image. + _ = stackPanel.Children.Add(block); + + return stackPanel; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml new file mode 100644 index 0000000000000..8aa05eb16a41d --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml.cs new file mode 100644 index 0000000000000..266b65ff8f96c --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/CodeStyleValueControl.xaml.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View +{ + /// + /// Interaction logic for CodeStyleValueControl.xaml + /// + internal partial class CodeStyleValueControl : UserControl + { + private readonly ComboBox _comboBox; + private readonly CodeStyleSetting _setting; + + public CodeStyleValueControl(CodeStyleSetting setting) + { + InitializeComponent(); + var values = setting.GetValues().ToList(); + var index = values.IndexOf(setting.GetCurrentValue()); + _comboBox = new ComboBox() + { + ItemsSource = values + }; + _comboBox.SelectedIndex = index; + _comboBox.SelectionChanged += ComboBox_SelectionChanged; + _ = RootGrid.Children.Add(_comboBox); + _setting = setting; + } + + private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + _setting.ChangeValue(_comboBox.SelectedIndex); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleCategoryColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleCategoryColumnDefinition.cs new file mode 100644 index 0000000000000..0162348e5e4fd --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleCategoryColumnDefinition.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.CodeStyle; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View.ColumnDefinitions +{ + [Export(typeof(IDefaultColumnGroup))] + [Name(nameof(CodeStyleCategoryGroupingSet))] // Required, name of the default group + [GroupColumns(Category)] // Required, the names of the columns in the grouping + internal class CodeStyleCategoryGroupingSet : IDefaultColumnGroup + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CodeStyleCategoryGroupingSet() + { + } + } + + [Export(typeof(ITableColumnDefinition))] + [Name(Category)] + internal class CodeStyleCategoryColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CodeStyleCategoryColumnDefinition() + { + } + + public override string Name => Category; + public override string DisplayName => ServicesVSResources.Category; + public override double MinWidth => 80; + public override bool DefaultVisible => false; + public override bool IsFilterable => true; + public override TextWrapping TextWrapping => TextWrapping.NoWrap; + + private static string? GetCategoryName(ITableEntryHandle entry) + => entry.TryGetValue(Category, out var categoryName) + ? categoryName as string + : null; + + public override IEntryBucket? CreateBucketForEntry(ITableEntryHandle entry) + { + var categoryName = GetCategoryName(entry); + return categoryName is not null ? new StringEntryBucket(categoryName) : null; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleDescriptionColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleDescriptionColumnDefinition.cs new file mode 100644 index 0000000000000..3883a303de4ad --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleDescriptionColumnDefinition.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.CodeStyle; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Description)] + internal class CodeStyleDescriptionColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CodeStyleDescriptionColumnDefinition() + { + } + + public override string Name => Description; + public override string DisplayName => ServicesVSResources.Description; + public override bool IsFilterable => false; + public override double MinWidth => 350; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleSeverityColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleSeverityColumnDefinition.cs new file mode 100644 index 0000000000000..cdba689cd616d --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleSeverityColumnDefinition.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.CodeStyle; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Severity)] + internal class CodeStyleSeverityColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CodeStyleSeverityColumnDefinition() + { + } + + public override string Name => Severity; + public override string DisplayName => ServicesVSResources.Severity; + public override double MinWidth => 120; + public override bool DefaultVisible => false; + public override bool IsFilterable => true; + + public override bool TryCreateColumnContent(ITableEntryHandle entry, bool singleColumnView, out FrameworkElement? content) + { + if (!entry.TryGetValue(Severity, out CodeStyleSetting severity)) + { + content = null; + return false; + } + + var control = new CodeStyleSeverityControl(severity); + content = control; + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleValueColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleValueColumnDefinition.cs new file mode 100644 index 0000000000000..301576b5f5a73 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/View/ColumnDefinitions/CodeStyleValueColumnDefinition.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.CodeStyle; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View.ColumnDefinitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Value)] + internal class CodeStyleValueColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CodeStyleValueColumnDefinition() + { + } + + public override string Name => Value; + public override string DisplayName => ServicesVSResources.Value; + public override double MinWidth => 120; + public override bool DefaultVisible => false; + public override bool IsFilterable => false; + + public override bool TryCreateColumnContent(ITableEntryHandle entry, bool singleColumnView, out FrameworkElement? content) + { + if (!entry.TryGetValue(Value, out CodeStyleSetting severity)) + { + content = null; + return false; + } + + var control = new CodeStyleValueControl(severity); + content = control; + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs new file mode 100644 index 0000000000000..3df9aa19ef67d --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.ViewModel +{ + internal partial class CodeStyleSettingsViewModel + { + internal class SettingsEntriesSnapshot : SettingsEntriesSnapshotBase + { + public SettingsEntriesSnapshot(ImmutableArray data, int currentVersionNumber) : base(data, currentVersionNumber) { } + + protected override bool TryGetValue(CodeStyleSetting result, string keyName, out object? content) + { + content = keyName switch + { + ColumnDefinitions.CodeStyle.Description => result.Description, + ColumnDefinitions.CodeStyle.Category => result.Category, + ColumnDefinitions.CodeStyle.Severity => result, + ColumnDefinitions.CodeStyle.Value => result, + _ => null, + }; + + return content is not null; + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsSnapshotFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsSnapshotFactory.cs new file mode 100644 index 0000000000000..4521d19999ff2 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsSnapshotFactory.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.ViewModel +{ + internal partial class CodeStyleSettingsViewModel + { + internal sealed class SettingsSnapshotFactory : SettingsSnapshotFactoryBase + { + public SettingsSnapshotFactory(ISettingsProvider data) : base(data) { } + + protected override SettingsEntriesSnapshot CreateSnapshot(ImmutableArray data, int currentVersionNumber) + => new(data, currentVersionNumber); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs new file mode 100644 index 0000000000000..d64574e94cba7 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.ViewModel +{ + internal partial class CodeStyleSettingsViewModel : SettingsViewModelBase< + CodeStyleSetting, + CodeStyleSettingsViewModel.SettingsSnapshotFactory, + CodeStyleSettingsViewModel.SettingsEntriesSnapshot> + { + public CodeStyleSettingsViewModel(ISettingsProvider data, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider) + : base(data, controlProvider, tableMangerProvider) + { } + + public override string Identifier => "CodeStyleSettings"; + + protected override SettingsSnapshotFactory CreateSnapshotFactory(ISettingsProvider data) + => new(data); + + protected override IEnumerable GetInitialColumnStates() + => new[] + { + new ColumnState2(ColumnDefinitions.CodeStyle.Category, isVisible: false, width: 0, groupingPriority: 1), + new ColumnState2(ColumnDefinitions.CodeStyle.Description, isVisible: true, width: 0), + new ColumnState2(ColumnDefinitions.CodeStyle.Value, isVisible: true, width: 0), + new ColumnState2(ColumnDefinitions.CodeStyle.Severity, isVisible: true, width: 0) + }; + + protected override string[] GetFixedColumns() + => new[] + { + ColumnDefinitions.CodeStyle.Category, + ColumnDefinitions.CodeStyle.Description, + ColumnDefinitions.CodeStyle.Value, + ColumnDefinitions.CodeStyle.Severity + }; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/ColumnDefinitions.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/ColumnDefinitions.cs new file mode 100644 index 0000000000000..669d7b7c5f07c --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/ColumnDefinitions.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal static class ColumnDefinitions + { + private const string Prefix = "editorconfig."; + + internal static class Analyzer + { + private const string AnalyzerPrefix = "analyzer."; + public const string Category = Prefix + AnalyzerPrefix + "categoryname"; + public const string Enabled = Prefix + AnalyzerPrefix + "enabledname"; + public const string Description = Prefix + AnalyzerPrefix + "descriptionname"; + public const string Id = Prefix + AnalyzerPrefix + "idname"; + public const string Severity = Prefix + AnalyzerPrefix + "severityname"; + public const string Title = Prefix + AnalyzerPrefix + "titlename"; + } + + internal static class CodeStyle + { + private const string CodeStylePrefix = "codestyle."; + public const string Category = Prefix + CodeStylePrefix + "categoryname"; + public const string Description = Prefix + CodeStylePrefix + "descriptionname"; + public const string Value = Prefix + CodeStylePrefix + "valuename"; + public const string Severity = Prefix + CodeStylePrefix + "severityname"; + } + + internal static class Formatting + { + private const string FormattingPrefix = "Formatting."; + public const string Category = Prefix + FormattingPrefix + "categoryname"; + public const string Description = Prefix + FormattingPrefix + "descriptionname"; + public const string Value = Prefix + FormattingPrefix + "valuename"; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs new file mode 100644 index 0000000000000..ea46d14a3b4e3 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EditorTextUpdater.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.TextManager.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal static class EditorTextUpdater + { + public static void UpdateText(IThreadingContext threadingContext, + IVsEditorAdaptersFactoryService editorAdaptersFactoryService, + IVsTextLines textLines, + IWpfSettingsEditorViewModel viewModel) + => threadingContext.JoinableTaskFactory.Run(async () => + { + var buffer = editorAdaptersFactoryService.GetDocumentBuffer(textLines); + if (buffer is null) + { + return; + } + + var changes = await viewModel.GetChangesAsync().ConfigureAwait(true); + if (changes is null) + { + return; + } + + TextEditApplication.UpdateText(changes.ToImmutableArray(), buffer, EditOptions.DefaultMinimalChange); + }); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml new file mode 100644 index 0000000000000..eeee83644d8ac --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml @@ -0,0 +1,11 @@ + + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml.cs new file mode 100644 index 0000000000000..e1c080441f940 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumPropertyView.xaml.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + + /// + /// Interaction logic for EnumPropertyView.xaml + /// + internal partial class EnumSettingView : UserControl + { + private readonly IEnumSettingViewModel _model; + private readonly string[] _descriptions; + private readonly ComboBox _comboBox; + + public EnumSettingView(IEnumSettingViewModel model) + { + InitializeComponent(); + _model = model; + + _descriptions = _model.GetValueDescriptions(); + _comboBox = new ComboBox() + { + ItemsSource = _descriptions + }; + + _comboBox.SelectedIndex = model.GetValueIndex(); + _comboBox.SelectionChanged += ComboBox_SelectionChanged; + + _ = RootGrid.Children.Add(_comboBox); + } + + private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + var index = _comboBox.SelectedIndex; + if (_descriptions.Length < index && index >= 0) + { + _model.ChangeProperty(_descriptions[index]); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs new file mode 100644 index 0000000000000..53b21e40562aa --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/EnumSettingViewModel.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal abstract class EnumSettingViewModel : IEnumSettingViewModel + where T : Enum + { + private readonly IReadOnlyDictionary _mapping; + + protected EnumSettingViewModel() + { + _mapping = GetValuesAndDescriptions(); + } + + public void ChangeProperty(string propertyDescription) + { + if (_mapping.TryGetValue(propertyDescription, out var value)) + { + ChangePropertyTo(value); + } + } + + public string[] GetValueDescriptions() + => _mapping.Keys.ToArray(); + + public int GetValueIndex() + { + var value = GetCurrentValue(); + return _mapping.Values.ToList().IndexOf(value); + } + + protected abstract IReadOnlyDictionary GetValuesAndDescriptions(); + protected abstract void ChangePropertyTo(T newValue); + protected abstract T GetCurrentValue(); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModel.cs new file mode 100644 index 0000000000000..3f80a67b2b500 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModel.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + + internal interface IEnumSettingViewModel + { + string[] GetValueDescriptions(); + int GetValueIndex(); + void ChangeProperty(string v); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModelFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModelFactory.cs new file mode 100644 index 0000000000000..5e1ba1fe2c235 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/IEnumSettingViewModelFactory.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal interface IEnumSettingViewModelFactory + { + bool IsSupported(OptionKey2 key); + IEnumSettingViewModel CreateViewModel(FormattingSetting setting); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/RemoveSinkWhenDisposed.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/RemoveSinkWhenDisposed.cs new file mode 100644 index 0000000000000..83d27a9c2959a --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/RemoveSinkWhenDisposed.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal class RemoveSinkWhenDisposed : IDisposable + { + private readonly List _tableSinks; + private readonly ITableDataSink _sink; + + public RemoveSinkWhenDisposed(List tableSinks, ITableDataSink sink) + { + _tableSinks = tableSinks; + _sink = sink; + } + + public void Dispose() + { + // whoever subscribed is no longer interested in my data. + // Remove them from the list of sinks + _ = _tableSinks.Remove(_sink); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsEntriesSnapshotBase.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsEntriesSnapshotBase.cs new file mode 100644 index 0000000000000..822218aedebf3 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsEntriesSnapshotBase.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using Microsoft.VisualStudio.Shell.TableControl; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal abstract class SettingsEntriesSnapshotBase : WpfTableEntriesSnapshotBase + { + private readonly ImmutableArray _data; + private readonly int _currentVersionNumber; + + public SettingsEntriesSnapshotBase(ImmutableArray data, int currentVersionNumber) + { + _data = data; + _currentVersionNumber = currentVersionNumber; + } + + public override int VersionNumber => _currentVersionNumber; + public override int Count => _data.Length; + + public override bool TryGetValue(int index, string keyName, out object? content) + { + T? result; + try + { + if (index < 0 || index > _data.Length) + { + content = null; + return false; + } + + result = _data[index]; + + if (result == null) + { + content = null; + return false; + } + } + catch (Exception) + { + content = null; + return false; + } + + return TryGetValue(result, keyName, out content); + } + + protected abstract bool TryGetValue(T result, string keyName, out object? content); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsSnapshotFactoryBase.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsSnapshotFactoryBase.cs new file mode 100644 index 0000000000000..e18edd875cfb0 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsSnapshotFactoryBase.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal abstract class SettingsSnapshotFactoryBase : TableEntriesSnapshotFactoryBase + where TEntriesSnapshot : SettingsEntriesSnapshotBase + { + private readonly ISettingsProvider _data; + + // State + private int _currentVersionNumber; + private int _lastSnapshotVersionNumber = -1; + private TEntriesSnapshot? _lastSnapshot; + + // Disallow concurrent modification of state + private readonly object _gate = new(); + + public SettingsSnapshotFactoryBase(ISettingsProvider data) + { + _data = data; + } + + public override int CurrentVersionNumber => _currentVersionNumber; + + public override ITableEntriesSnapshot? GetCurrentSnapshot() => GetSnapshot(CurrentVersionNumber); + + internal void NotifyOfUpdate() => Interlocked.Increment(ref _currentVersionNumber); + + public override ITableEntriesSnapshot? GetSnapshot(int versionNumber) + { + lock (_gate) + { + if (versionNumber == _currentVersionNumber) + { + if (_lastSnapshotVersionNumber == _currentVersionNumber) + { + return _lastSnapshot; + } + else + { + var data = _data.GetCurrentDataSnapshot(); + var snapshot = CreateSnapshot(data, _currentVersionNumber); + + _lastSnapshot = snapshot; + _lastSnapshotVersionNumber = _currentVersionNumber; + + return snapshot; + } + } + else if (versionNumber < _currentVersionNumber) + { + // We can return null from this method. + // This will signal to Table Control to request current snapshot. + return null; + } + else // versionNumber > this.currentVersionNumber + { + throw new InvalidOperationException($"Invalid GetSnapshot request. Requested version: {versionNumber}. Current version: {_currentVersionNumber}"); + } + } + } + + protected abstract TEntriesSnapshot CreateSnapshot(ImmutableArray data, int currentVersionNumber); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs new file mode 100644 index 0000000000000..018a7ee1e68ea --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Common/SettingsViewModelBase.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common +{ + internal abstract partial class SettingsViewModelBase : IWpfSettingsEditorViewModel, ITableDataSource + where TSnapshotFactory : SettingsSnapshotFactoryBase + where TEntriesSnapshot : SettingsEntriesSnapshotBase + { + private readonly ISettingsProvider _data; + private readonly IWpfTableControlProvider _controlProvider; + private readonly TSnapshotFactory _snapshotFactory; + private readonly ITableManager _tableManager; + + private List TableSinks { get; } = new List(); + + protected SettingsViewModelBase(ISettingsProvider data, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider) + { + _data = data; + _controlProvider = controlProvider; + _data.RegisterViewModel(this); + _tableManager = tableMangerProvider.GetTableManager(Identifier); + _ = _tableManager.AddSource(this); + _snapshotFactory = CreateSnapshotFactory(_data); + } + + public abstract string Identifier { get; } + protected abstract TSnapshotFactory CreateSnapshotFactory(ISettingsProvider data); + protected abstract string[] GetFixedColumns(); + protected abstract IEnumerable GetInitialColumnStates(); + + public string SourceTypeIdentifier => "EditorConfigSettings"; + public string? DisplayName => null; + + public Task NotifyOfUpdateAsync() + { + _snapshotFactory.NotifyOfUpdate(); + + // Notify the sinks. Generally, VS Table Control will request data 500ms after the last notification. + foreach (var tableSink in TableSinks) + { + // Notify that an update is available + tableSink.FactorySnapshotChanged(null); + } + + return Task.CompletedTask; + } + + public IDisposable Subscribe(ITableDataSink sink) + { + sink.AddFactory(_snapshotFactory); + TableSinks.Add(sink); + return new RemoveSinkWhenDisposed(TableSinks, sink); + } + + public Task?> GetChangesAsync() + => _data.GetChangedEditorConfigAsync(); + + public IWpfTableControl4 GetTableControl() + { + var initialColumnStates = GetInitialColumnStates(); + var fixedColumns = GetFixedColumns(); + return (IWpfTableControl4)_controlProvider.CreateControl( + _tableManager, + true, + initialColumnStates, + fixedColumns); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingCategoryColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingCategoryColumnDefinition.cs new file mode 100644 index 0000000000000..294345ca5bfdf --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingCategoryColumnDefinition.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Formatting; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View.ColumnDefnitions +{ + [Export(typeof(IDefaultColumnGroup))] + [Name(nameof(FormattingCategoryGroupingSet))] // Required, name of the default group + [GroupColumns(Category)] // Required, the names of the columns in the grouping + internal class FormattingCategoryGroupingSet : IDefaultColumnGroup + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public FormattingCategoryGroupingSet() + { + } + } + + [Export(typeof(ITableColumnDefinition))] + [Name(Category)] + internal class FormattingCategoryColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public FormattingCategoryColumnDefinition() + { + } + + public override string Name => Category; + public override string DisplayName => ServicesVSResources.Category; + public override double MinWidth => 80; + public override bool DefaultVisible => false; + public override bool IsFilterable => true; + public override TextWrapping TextWrapping => TextWrapping.NoWrap; + + private static string? GetCategoryName(ITableEntryHandle entry) + => entry.TryGetValue(Category, out string? categoryName) + ? categoryName + : null; + + public override IEntryBucket? CreateBucketForEntry(ITableEntryHandle entry) + { + var categoryName = GetCategoryName(entry); + return categoryName is not null ? new StringEntryBucket(GetCategoryName(entry)) : null; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingDescriptionColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingDescriptionColumnDefinition.cs new file mode 100644 index 0000000000000..ea6fccf3eee36 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingDescriptionColumnDefinition.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Formatting; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View.ColumnDefnitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Description)] + internal class FormattingDescriptionColumnDefinition : TableColumnDefinitionBase + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public FormattingDescriptionColumnDefinition() + { + } + + public override string Name => Description; + public override string DisplayName => ServicesVSResources.Description; + public override bool IsFilterable => false; + public override double DefaultWidth => 350; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingValueColumnDefinition.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingValueColumnDefinition.cs new file mode 100644 index 0000000000000..0ba579e43f8a5 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/ColumnDefnitions/FormattingValueColumnDefinition.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Windows; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Utilities; +using static Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common.ColumnDefinitions.Formatting; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View.ColumnDefnitions +{ + [Export(typeof(ITableColumnDefinition))] + [Name(Value)] + internal class FormattingValueColumnDefinition : TableColumnDefinitionBase + { + private readonly IEnumerable _factories; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public FormattingValueColumnDefinition([ImportMany] IEnumerable factories) + { + _factories = factories; + } + + public override string Name => Value; + public override string DisplayName => ServicesVSResources.Value; + public override double MinWidth => 80; + public override bool DefaultVisible => false; + public override bool IsFilterable => true; + public override TextWrapping TextWrapping => TextWrapping.NoWrap; + + public override bool TryCreateColumnContent(ITableEntryHandle entry, bool singleColumnView, out FrameworkElement? content) + { + if (!entry.TryGetValue(Value, out FormattingSetting setting)) + { + content = null; + return false; + } + if (setting.Type == typeof(bool)) + { + content = new FormattingBoolSettingView(setting); + return true; + } + + foreach (var factory in _factories) + { + if (factory.IsSupported(setting.Key)) + { + var viewModel = factory.CreateViewModel(setting); + content = new EnumSettingView(viewModel); + return true; + } + } + + content = null; + return false; + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml new file mode 100644 index 0000000000000..a0261972dbf4e --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml.cs new file mode 100644 index 0000000000000..b8a6f2485cc50 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingBoolSettingView.xaml.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows; +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View +{ + /// + /// Interaction logic for WhitespaceValueSettingControl.xaml + /// + internal partial class FormattingBoolSettingView : UserControl + { + private readonly FormattingSetting _setting; + private readonly CheckBox _checkBox; + + public FormattingBoolSettingView(FormattingSetting setting) + { + InitializeComponent(); + _setting = setting; + _checkBox = new CheckBox(); + + if (setting.GetValue() is bool value) + { + _checkBox.IsChecked = value; + } + + _checkBox.Checked += CheckBoxChanged; + _checkBox.Unchecked += CheckBoxChanged; + + _ = RootGrid.Children.Add(_checkBox); + } + + private void CheckBoxChanged(object sender, RoutedEventArgs e) + { + _setting.SetValue(_checkBox.IsChecked == true); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml new file mode 100644 index 0000000000000..551ee98800b64 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml @@ -0,0 +1,18 @@ + + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml.cs new file mode 100644 index 0000000000000..910a8f8a8b6d5 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/View/FormattingSettingsView.xaml.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.TextManager.Interop; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View +{ + /// + /// Interaction logic for FormattingSettingsView.xaml + /// + internal partial class FormattingSettingsView : UserControl, ISettingsEditorView + { + private readonly IVsTextLines _vsTextLines; + private readonly IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService; + private readonly IThreadingContext _threadingContext; + private readonly IWpfSettingsEditorViewModel _viewModel; + + public FormattingSettingsView(IVsTextLines vsTextLines, + IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService, + IThreadingContext threadingContext, + IWpfSettingsEditorViewModel viewModel) + { + InitializeComponent(); + _vsTextLines = vsTextLines; + _vsEditorAdaptersFactoryService = vsEditorAdaptersFactoryService; + _threadingContext = threadingContext; + _viewModel = viewModel; + TableControl = _viewModel.GetTableControl(); + WhitespaceTable.Child = TableControl.Control; + } + + public UserControl SettingControl => this; + public IWpfTableControl TableControl { get; } + + public void Synchronize() + { + if (IsKeyboardFocusWithin) + { + EditorTextUpdater.UpdateText(_threadingContext, _vsEditorAdaptersFactoryService, _vsTextLines, _viewModel); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsEntriesSnapshot.cs new file mode 100644 index 0000000000000..efb58f722bd51 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsEntriesSnapshot.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + internal partial class FormattingViewModel + { + internal sealed class SettingsEntriesSnapshot : SettingsEntriesSnapshotBase + { + public SettingsEntriesSnapshot(ImmutableArray data, int currentVersionNumber) : base(data, currentVersionNumber) { } + + protected override bool TryGetValue(FormattingSetting result, string keyName, out object? content) + { + content = keyName switch + { + ColumnDefinitions.Formatting.Description => result.Description, + ColumnDefinitions.Formatting.Category => result.Category, + ColumnDefinitions.Formatting.Value => result, + _ => null, + }; + + return content is not null; + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsSnapshotFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsSnapshotFactory.cs new file mode 100644 index 0000000000000..c29473e1aa092 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.SettingsSnapshotFactory.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + internal partial class FormattingViewModel + { + internal sealed class SettingsSnapshotFactory : SettingsSnapshotFactoryBase + { + public SettingsSnapshotFactory(ISettingsProvider data) : base(data) { } + + protected override SettingsEntriesSnapshot CreateSnapshot(ImmutableArray data, int currentVersionNumber) + => new(data, currentVersionNumber); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.cs new file mode 100644 index 0000000000000..67c5de89a5bb6 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/FormattingViewModel.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + internal partial class FormattingViewModel : SettingsViewModelBase< + FormattingSetting, + FormattingViewModel.SettingsSnapshotFactory, + FormattingViewModel.SettingsEntriesSnapshot> + { + public FormattingViewModel(ISettingsProvider data, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider) + : base(data, controlProvider, tableMangerProvider) + { } + + public override string Identifier => "Whitespace"; + + protected override SettingsSnapshotFactory CreateSnapshotFactory(ISettingsProvider data) + => new(data); + + protected override IEnumerable GetInitialColumnStates() + => new[] + { + new ColumnState2(ColumnDefinitions.Formatting.Category, isVisible: false, width: 0, groupingPriority: 1), + new ColumnState2(ColumnDefinitions.Formatting.Description, isVisible: true, width: 0), + new ColumnState2(ColumnDefinitions.Formatting.Value, isVisible: true, width: 0) + }; + + protected override string[] GetFixedColumns() + => new[] + { + ColumnDefinitions.Formatting.Category, + ColumnDefinitions.Formatting.Description, + ColumnDefinitions.Formatting.Value + }; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/IndentationSizeViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/IndentationSizeViewModel.cs new file mode 100644 index 0000000000000..719fc1602945c --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/IndentationSizeViewModel.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class IndentationSizeVViewModelFactory : IEnumSettingViewModelFactory + { + private readonly OptionKey2 _key; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public IndentationSizeVViewModelFactory() + { + _key = new OptionKey2(FormattingOptions2.IndentationSize, LanguageNames.CSharp); + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new IndentationSizeViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) => _key == key; + } + + // TODO(jmarolf): do not do this thing + internal enum IndentationSizeSetting + { + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + } + + internal class IndentationSizeViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public IndentationSizeViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(IndentationSizeSetting newValue) + { + switch (newValue) + { + case IndentationSizeSetting._1: + _setting.SetValue(1); + break; + case IndentationSizeSetting._2: + _setting.SetValue(2); + break; + case IndentationSizeSetting._3: + _setting.SetValue(3); + break; + case IndentationSizeSetting._4: + _setting.SetValue(4); + break; + case IndentationSizeSetting._5: + _setting.SetValue(5); + break; + case IndentationSizeSetting._6: + _setting.SetValue(6); + break; + case IndentationSizeSetting._7: + _setting.SetValue(7); + break; + case IndentationSizeSetting._8: + _setting.SetValue(8); + break; + default: + break; + } + } + + protected override IndentationSizeSetting GetCurrentValue() + { + return _setting.GetValue() switch + { + 1 => IndentationSizeSetting._1, + 2 => IndentationSizeSetting._2, + 3 => IndentationSizeSetting._3, + 4 => IndentationSizeSetting._4, + 5 => IndentationSizeSetting._5, + 6 => IndentationSizeSetting._6, + 7 => IndentationSizeSetting._7, + _ => IndentationSizeSetting._8, + }; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, IndentationSizeSetting value)> EnumerateOptions() + { + yield return ("1", IndentationSizeSetting._1); + yield return ("2", IndentationSizeSetting._2); + yield return ("3", IndentationSizeSetting._3); + yield return ("4", IndentationSizeSetting._4); + yield return ("5", IndentationSizeSetting._5); + yield return ("6", IndentationSizeSetting._6); + yield return ("7", IndentationSizeSetting._7); + yield return ("8", IndentationSizeSetting._8); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/NewLineViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/NewLineViewModel.cs new file mode 100644 index 0000000000000..62e6c27f13087 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/NewLineViewModel.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class NewLineViewModelFactory : IEnumSettingViewModelFactory + { + private readonly OptionKey2 _key; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public NewLineViewModelFactory() + { + _key = new OptionKey2(FormattingOptions2.NewLine, LanguageNames.CSharp); + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + throw new NotImplementedException(); + } + + public bool IsSupported(OptionKey2 key) => _key == key; + } + + internal enum NewLineSetting + { + Newline, + CarrageReturn, + CarrageReturnNewline, + NotSet + } + + internal class NewLineViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public NewLineViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(NewLineSetting newValue) + { + switch (newValue) + { + case NewLineSetting.Newline: + _setting.SetValue("lf"); + break; + case NewLineSetting.CarrageReturn: + _setting.SetValue("cr"); + break; + case NewLineSetting.CarrageReturnNewline: + _setting.SetValue("crlf"); + break; + case NewLineSetting.NotSet: + default: + break; + } + } + + protected override NewLineSetting GetCurrentValue() + { + return _setting.GetValue() switch + { + "lf" => NewLineSetting.Newline, + "cr" => NewLineSetting.CarrageReturn, + "crlf" => NewLineSetting.CarrageReturnNewline, + _ => NewLineSetting.NotSet, + }; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, NewLineSetting value)> EnumerateOptions() + { + yield return (ServicesVSResources.Newline_n, NewLineSetting.Newline); + yield return (ServicesVSResources.Carrage_Return_r, NewLineSetting.CarrageReturn); + yield return (ServicesVSResources.Carrage_Return_Newline_rn, NewLineSetting.CarrageReturnNewline); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/TabSizeViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/TabSizeViewModel.cs new file mode 100644 index 0000000000000..64e3590c9d85f --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Formatting/ViewModel/TabSizeViewModel.cs @@ -0,0 +1,124 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel +{ + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class TabSizeViewModelFactory : IEnumSettingViewModelFactory + { + private readonly OptionKey2 _key; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public TabSizeViewModelFactory() + { + _key = new OptionKey2(FormattingOptions2.TabSize, LanguageNames.CSharp); + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new TabSizeViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) => _key == key; + } + + internal enum TabSizeSettings + { + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + } + + internal class TabSizeViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public TabSizeViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(TabSizeSettings newValue) + { + switch (newValue) + { + case TabSizeSettings._1: + _setting.SetValue(1); + break; + case TabSizeSettings._2: + _setting.SetValue(2); + break; + case TabSizeSettings._3: + _setting.SetValue(3); + break; + case TabSizeSettings._4: + _setting.SetValue(4); + break; + case TabSizeSettings._5: + _setting.SetValue(5); + break; + case TabSizeSettings._6: + _setting.SetValue(6); + break; + case TabSizeSettings._7: + _setting.SetValue(7); + break; + case TabSizeSettings._8: + _setting.SetValue(8); + break; + default: + break; + } + } + + protected override TabSizeSettings GetCurrentValue() + { + return _setting.GetValue() switch + { + 1 => TabSizeSettings._1, + 2 => TabSizeSettings._2, + 3 => TabSizeSettings._3, + 4 => TabSizeSettings._4, + 5 => TabSizeSettings._5, + 6 => TabSizeSettings._6, + 7 => TabSizeSettings._7, + _ => TabSizeSettings._8, + }; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, TabSizeSettings value)> EnumerateOptions() + { + yield return ("1", TabSizeSettings._1); + yield return ("2", TabSizeSettings._2); + yield return ("3", TabSizeSettings._3); + yield return ("4", TabSizeSettings._4); + yield return ("5", TabSizeSettings._5); + yield return ("6", TabSizeSettings._6); + yield return ("7", TabSizeSettings._7); + yield return ("8", TabSizeSettings._8); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/ISettingsEditorView.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/ISettingsEditorView.cs new file mode 100644 index 0000000000000..4e4aa8d2e1f24 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/ISettingsEditorView.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; +using Microsoft.VisualStudio.Shell.TableControl; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + internal interface ISettingsEditorView + { + UserControl SettingControl { get; } + IWpfTableControl TableControl { get; } + void Synchronize(); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/IWpfSettingsEditorViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/IWpfSettingsEditorViewModel.cs new file mode 100644 index 0000000000000..e46d2b9b9bdcd --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/IWpfSettingsEditorViewModel.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Editor; +using Microsoft.VisualStudio.Shell.TableControl; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + internal interface IWpfSettingsEditorViewModel : ISettingsEditorViewModel + { + IWpfTableControl4 GetTableControl(); + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/ServiceProviderExtensions.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/ServiceProviderExtensions.cs new file mode 100644 index 0000000000000..1c91e028422c3 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/ServiceProviderExtensions.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.VisualStudio.Shell; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + internal static class ServiceProviderExtensions + { + public static bool TryGetService(this IServiceProvider sp, [NotNullWhen(true)] out TInterface? @interface) + where TInterface : class + { + @interface = sp.GetService(throwOnFailure: false); + return @interface is not null; + } + + public static bool TryGetService(this IServiceProvider sp, [NotNullWhen(true)] out TInterface? @interface) + where TInterface : class + { + @interface = sp.GetService(throwOnFailure: false); + return @interface is not null; + } + + public static TInterface? GetService(this IServiceProvider sp) + where TInterface : class + { + return sp.GetService(throwOnFailure: false); + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml new file mode 100644 index 0000000000000..4e0c57c19e250 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs new file mode 100644 index 0000000000000..b9d59ade81c17 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Windows.Controls; +using Microsoft.VisualStudio.Shell.TableControl; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + /// + /// Interaction logic for SettingsEditorControl.xaml + /// + internal partial class SettingsEditorControl : UserControl + { + private readonly ISettingsEditorView _formattingView; + private readonly ISettingsEditorView _codeStyleView; + private readonly ISettingsEditorView _analyzerSettingsView; + + public static string Formatting => ServicesVSResources.Formatting; + public static string CodeStyle => ServicesVSResources.Code_Style; + public static string Analyzers => ServicesVSResources.Analyzers; + + public SettingsEditorControl(ISettingsEditorView formattingView, + ISettingsEditorView codeStyleView, + ISettingsEditorView analyzerSettingsView) + { + InitializeComponent(); + DataContext = this; + _formattingView = formattingView; + FormattingTab.Content = _formattingView.SettingControl; + _codeStyleView = codeStyleView; + CodeStyleTab.Content = _codeStyleView.SettingControl; + _analyzerSettingsView = analyzerSettingsView; + AnalyzersTab.Content = _analyzerSettingsView.SettingControl; + } + + internal void SynchronizeSettings() + { + _formattingView.Synchronize(); + _codeStyleView.Synchronize(); + _analyzerSettingsView.Synchronize(); + } + + internal IWpfTableControl[] GetTableControls() + => new[] + { + _formattingView.TableControl, + _codeStyleView.TableControl, + _analyzerSettingsView.TableControl, + }; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorFactory.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorFactory.cs new file mode 100644 index 0000000000000..a36e25a133555 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorFactory.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.TextManager.Interop; +using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + [Export(typeof(SettingsEditorFactory))] + [Guid(SettingsEditorFactoryGuidString)] + internal sealed class SettingsEditorFactory : IVsEditorFactory, IDisposable + { + public static readonly Guid SettingsEditorFactoryGuid = new(SettingsEditorFactoryGuidString); + public const string SettingsEditorFactoryGuidString = "68b46364-d378-42f2-9e72-37d86c5f4468"; + public const string Extension = ".editorconfig"; + + private readonly ISettingsAggregator _settingsDataProviderFactory; + private readonly IWpfTableControlProvider _controlProvider; + private readonly ITableManagerProvider _tableMangerProvider; + private readonly IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService; + private readonly IThreadingContext _threadingContext; + private ServiceProvider? _vsServiceProvider; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public SettingsEditorFactory(VisualStudioWorkspace workspace, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider, + IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService, + IThreadingContext threadingContext) + { + _settingsDataProviderFactory = workspace.Services.GetRequiredService(); + _controlProvider = controlProvider; + _tableMangerProvider = tableMangerProvider; + _vsEditorAdaptersFactoryService = vsEditorAdaptersFactoryService; + _threadingContext = threadingContext; + } + + public void Dispose() + { + if (_vsServiceProvider is not null) + { + _vsServiceProvider.Dispose(); + _vsServiceProvider = null; + } + } + + public int CreateEditorInstance(uint grfCreateDoc, + string pszMkDocument, + string pszPhysicalView, + IVsHierarchy pvHier, + uint itemid, + IntPtr punkDocDataExisting, + out IntPtr ppunkDocView, + out IntPtr ppunkDocData, + out string? pbstrEditorCaption, + out Guid pguidCmdUI, + out int pgrfCDW) + { + // Initialize to null + ppunkDocView = IntPtr.Zero; + ppunkDocData = IntPtr.Zero; + pguidCmdUI = SettingsEditorFactoryGuid; + pgrfCDW = 0; + pbstrEditorCaption = null; + + // Validate inputs + if ((grfCreateDoc & (VSConstants.CEF_OPENFILE | VSConstants.CEF_SILENT)) == 0) + { + return VSConstants.E_INVALIDARG; + } + + IVsTextLines? textBuffer = null; + if (punkDocDataExisting == IntPtr.Zero) + { + Assumes.NotNull(_vsServiceProvider); + if (_vsServiceProvider.TryGetService(out var localRegistry)) + { + var textLinesGuid = typeof(IVsTextLines).GUID; + _ = localRegistry.CreateInstance(typeof(VsTextBufferClass).GUID, null, ref textLinesGuid, 1 /*CLSCTX_INPROC_SERVER*/, out var ptr); + try + { + textBuffer = Marshal.GetObjectForIUnknown(ptr) as IVsTextLines; + } + finally + { + _ = Marshal.Release(ptr); // Release RefCount from CreateInstance call + } + + if (textBuffer is IObjectWithSite objectWithSite) + { + var oleServiceProvider = _vsServiceProvider.GetService(); + objectWithSite.SetSite(oleServiceProvider); + } + } + } + else + { + textBuffer = Marshal.GetObjectForIUnknown(punkDocDataExisting) as IVsTextLines; + if (textBuffer == null) + { + return VSConstants.VS_E_INCOMPATIBLEDOCDATA; + } + } + + if (textBuffer is null) + { + throw new InvalidOperationException("unable to acquire text buffer"); + } + + // Create the editor + var newEditor = new SettingsEditorPane(_vsEditorAdaptersFactoryService, + _threadingContext, + _settingsDataProviderFactory, + _controlProvider, + _tableMangerProvider, + pszMkDocument, + textBuffer); + ppunkDocView = Marshal.GetIUnknownForObject(newEditor); + ppunkDocData = Marshal.GetIUnknownForObject(textBuffer); + pbstrEditorCaption = ""; + return VSConstants.S_OK; + } + + public int SetSite(IOleServiceProvider psp) + { + _vsServiceProvider = new ServiceProvider(psp); + return VSConstants.S_OK; + } + + public int Close() => VSConstants.S_OK; + + public int MapLogicalView(ref Guid rguidLogicalView, out string? pbstrPhysicalView) + { + pbstrPhysicalView = null; // initialize out parameter + + // we support only a single physical view + if (VSConstants.LOGVIEWID_Primary == rguidLogicalView) + { + return VSConstants.S_OK; // primary view uses NULL as pbstrPhysicalView + } + else + { + return VSConstants.E_NOTIMPL; // you must return E_NOTIMPL for any unrecognized rguidLogicalView values + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorPane.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorPane.cs new file mode 100644 index 0000000000000..93684e04d9f40 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorPane.cs @@ -0,0 +1,556 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.Internal.VisualStudio.PlatformUI; +using Microsoft.Internal.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.View; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Analyzers.ViewModel; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.View; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.CodeStyle.ViewModel; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.View; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Formatting.ViewModel; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.PlatformUI; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Threading; +using static Microsoft.VisualStudio.VSConstants; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings +{ + internal sealed class SettingsEditorPane : WindowPane, IOleComponent, IVsDeferredDocView, IVsLinkedUndoClient, IVsWindowSearch + { + private readonly IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService; + private readonly IThreadingContext _threadingContext; + private readonly ISettingsAggregator _settingsDataProviderService; + private readonly IWpfTableControlProvider _controlProvider; + private readonly ITableManagerProvider _tableMangerProvider; + private readonly string _fileName; + private readonly IVsTextLines _textBuffer; + private uint _componentId; + private IOleUndoManager? _undoManager; + private SettingsEditorControl? _control; + + public SettingsEditorPane(IVsEditorAdaptersFactoryService vsEditorAdaptersFactoryService, + IThreadingContext threadingContext, + ISettingsAggregator settingsDataProviderService, + IWpfTableControlProvider controlProvider, + ITableManagerProvider tableMangerProvider, + string fileName, + IVsTextLines textBuffer) + : base(null) + { + _vsEditorAdaptersFactoryService = vsEditorAdaptersFactoryService; + _threadingContext = threadingContext; + _settingsDataProviderService = settingsDataProviderService; + _controlProvider = controlProvider; + _tableMangerProvider = tableMangerProvider; + _fileName = fileName; + _textBuffer = textBuffer; + } + + protected override void Initialize() + { + base.Initialize(); + + // Create and initialize the editor + if (_componentId == default && this.TryGetService(out var componentManager)) + { + var componentRegistrationInfo = new[] + { + new OLECRINFO + { + cbSize = (uint)Marshal.SizeOf(typeof(OLECRINFO)), + grfcrf = (uint)_OLECRF.olecrfNeedIdleTime | (uint)_OLECRF.olecrfNeedPeriodicIdleTime, + grfcadvf = (uint)_OLECADVF.olecadvfModal | (uint)_OLECADVF.olecadvfRedrawOff | (uint)_OLECADVF.olecadvfWarningsOff, + uIdleTimeInterval = 100 + } + }; + + var hr = componentManager.FRegisterComponent(this, componentRegistrationInfo, out _componentId); + _ = ErrorHandler.Succeeded(hr); + } + + if (this.TryGetService(out _undoManager)) + { + var linkCapableUndoMgr = (IVsLinkCapableUndoManager)_undoManager; + if (linkCapableUndoMgr is not null) + { + _ = linkCapableUndoMgr.AdviseLinkedUndoClient(this); + } + } + + // hook up our panel + _control = new SettingsEditorControl( + GetFormattingView(), + GetCodeStyleView(), + GetAnalyzerView()); + Content = _control; + + RegisterIndependentView(true); + if (this.TryGetService(out var menuCommandService)) + { + AddCommand(menuCommandService, GUID_VSStandardCommandSet97, (int)VSStd97CmdID.NewWindow, + new EventHandler(OnNewWindow), new EventHandler(OnQueryNewWindow)); + AddCommand(menuCommandService, GUID_VSStandardCommandSet97, (int)VSStd97CmdID.ViewCode, + new EventHandler(OnViewCode), new EventHandler(OnQueryViewCode)); + } + + ISettingsEditorView GetFormattingView() + { + var dataProvider = _settingsDataProviderService.GetSettingsProvider(_fileName); + if (dataProvider is null) + { + throw new InvalidOperationException("Unable to get formatter settings"); + } + var viewModel = new FormattingViewModel(dataProvider, _controlProvider, _tableMangerProvider); + return new FormattingSettingsView(_textBuffer, _vsEditorAdaptersFactoryService, _threadingContext, viewModel); + } + + ISettingsEditorView GetCodeStyleView() + { + var dataProvider = _settingsDataProviderService.GetSettingsProvider(_fileName); + if (dataProvider is null) + { + throw new InvalidOperationException("Unable to get code style settings"); + } + var viewModel = new CodeStyleSettingsViewModel(dataProvider, _controlProvider, _tableMangerProvider); + return new CodeStyleSettingsView(_textBuffer, _vsEditorAdaptersFactoryService, _threadingContext, viewModel); + } + + ISettingsEditorView GetAnalyzerView() + { + var dataProvider = _settingsDataProviderService.GetSettingsProvider(_fileName); + if (dataProvider is null) + { + throw new InvalidOperationException("Unable to get analyzer settings"); + } + + var viewModel = new AnalyzerSettingsViewModel(dataProvider, _controlProvider, _tableMangerProvider); + return new AnalyzerSettingsView(_textBuffer, _vsEditorAdaptersFactoryService, _threadingContext, viewModel); + } + } + + private void OnQueryNewWindow(object sender, EventArgs e) + { + var command = (OleMenuCommand)sender; + command.Enabled = true; + } + + private void OnNewWindow(object sender, EventArgs e) + { + NewWindow(); + } + + private void OnQueryViewCode(object sender, EventArgs e) + { + var command = (OleMenuCommand)sender; + command.Enabled = true; + } + + private void OnViewCode(object sender, EventArgs e) + { + ViewCode(); + } + + private void NewWindow() + { + if (this.TryGetService(out var uishellOpenDocument) && + this.TryGetService(out var windowFrameOrig)) + { + var logicalView = Guid.Empty; + var hr = uishellOpenDocument.OpenCopyOfStandardEditor(windowFrameOrig, ref logicalView, out var windowFrameNew); + if (windowFrameNew != null) + { + hr = windowFrameNew.Show(); + } + + _ = ErrorHandler.ThrowOnFailure(hr); + } + } + + private void ViewCode() + { + var sourceCodeTextEditorGuid = new Guid("8B382828-6202-11D1-8870-0000F87579D2"); + + // Open the referenced document using our editor. + VsShellUtilities.OpenDocumentWithSpecificEditor(this, _fileName, + sourceCodeTextEditorGuid, LOGVIEWID_Primary, out _, out _, out var frame); + _ = ErrorHandler.ThrowOnFailure(frame.Show()); + } + + protected override void OnClose() + { + // unhook from Undo related services + if (_undoManager != null) + { + var linkCapableUndoMgr = (IVsLinkCapableUndoManager)_undoManager; + if (linkCapableUndoMgr != null) + { + _ = linkCapableUndoMgr.UnadviseLinkedUndoClient(); + } + + // Throw away the undo stack etc. + // It is important to “zombify” the undo manager when the owning object is shutting down. + // This is done by calling IVsLifetimeControlledObject.SeverReferencesToOwner on the undoManager. + // This call will clear the undo and redo stacks. This is particularly important to do if + // your undo units hold references back to your object. It is also important if you use + // "mdtStrict" linked undo transactions as this sample does (see IVsLinkedUndoTransactionManager). + // When one object involved in linked undo transactions clears its undo/redo stacks, then + // the stacks of the other documents involved in the linked transaction will also be cleared. + var lco = (IVsLifetimeControlledObject)_undoManager; + _ = lco.SeverReferencesToOwner(); + _undoManager = null; + } + + if (this.TryGetService(out var componentManager)) + { + _ = componentManager.FRevokeComponent(_componentId); + } + + Dispose(true); + + base.OnClose(); + } + + public int FDoIdle(uint grfidlef) + { + if (_control is not null) + { + _control.SynchronizeSettings(); + } + return S_OK; + } + + /// + /// Registers an independent view with the IVsTextManager so that it knows + /// the user is working with a view over the text buffer. This will trigger + /// the text buffer to prompt the user whether to reload the file if it is + /// edited outside of the environment. + /// + /// True to subscribe, false to unsubscribe + private void RegisterIndependentView(bool subscribe) + { + if (this.TryGetService(out var textManager)) + { + _ = subscribe + ? textManager.RegisterIndependentView(this, _textBuffer) + : textManager.UnregisterIndependentView(this, _textBuffer); + } + } + + /// + /// Helper function used to add commands using IMenuCommandService + /// + /// The IMenuCommandService interface. + /// This guid represents the menu group of the command. + /// The command ID of the command. + /// An EventHandler which will be called whenever the command is invoked. + /// An EventHandler which will be called whenever we want to query the status of + /// the command. If null is passed in here then no EventHandler will be added. + private static void AddCommand(IMenuCommandService menuCommandService, + Guid menuGroup, + int cmdID, + EventHandler commandEvent, + EventHandler queryEvent) + { + // Create the OleMenuCommand from the menu group, command ID, and command event + var menuCommandID = new CommandID(menuGroup, cmdID); + var command = new OleMenuCommand(commandEvent, menuCommandID); + + // Add an event handler to BeforeQueryStatus if one was passed in + if (null != queryEvent) + { + command.BeforeQueryStatus += queryEvent; + } + + // Add the command using our IMenuCommandService instance + menuCommandService.AddCommand(command); + } + + public int get_DocView(out IntPtr ppUnkDocView) + { + ppUnkDocView = Marshal.GetIUnknownForObject(this); + return S_OK; + } + + public int get_CmdUIGuid(out Guid pGuidCmdId) + { + pGuidCmdId = SettingsEditorFactory.SettingsEditorFactoryGuid; + return S_OK; + } + + public int FReserved1(uint dwReserved, uint message, IntPtr wParam, IntPtr lParam) => S_OK; + public int FPreTranslateMessage(MSG[] pMsg) => S_OK; + public void OnEnterState(uint uStateID, int fEnter) { } + public void OnAppActivate(int fActive, uint dwOtherThreadID) { } + public void OnLoseActivation() { } + public void OnActivationChange(IOleComponent pic, int fSameComponent, OLECRINFO[] pcrinfo, int fHostIsActivating, OLECHOSTINFO[] pchostinfo, uint dwReserved) { } + public int FContinueMessageLoop(uint uReason, IntPtr pvLoopData, MSG[] pMsgPeeked) => S_OK; + public int FQueryTerminate(int fPromptUser) => 1; //true + public void Terminate() { } + public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved) => IntPtr.Zero; + public int OnInterveningUnitBlockingLinkedUndo() => E_FAIL; + + public IVsSearchTask? CreateSearch(uint dwCookie, IVsSearchQuery pSearchQuery, IVsSearchCallback pSearchCallback) + { + if (_control is not null) + { + var tables = _control.GetTableControls(); + return new SearchTask(dwCookie, pSearchQuery, pSearchCallback, tables, _threadingContext); + } + + return null; + } + + public void ClearSearch() + { + if (_control is not null) + { + var tables = _control.GetTableControls(); + // remove filter on tablar data controls + _ = _threadingContext.JoinableTaskFactory.RunAsync( + async () => + { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + foreach (var tableControl in tables) + { + _ = tableControl.SetFilter(string.Empty, null); + } + }); + } + } + + public void ProvideSearchSettings(IVsUIDataSource pSearchSettings) + { + SetIntValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.ControlMaxWidth, 200); + SetIntValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchStartType, (int)VSSEARCHSTARTTYPE.SST_DELAYED); + SetIntValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchStartDelay, 100); + SetBoolValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchUseMRU, true); + SetBoolValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.PrefixFilterMRUItems, false); + SetIntValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.MaximumMRUItems, 25); + SetStringValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchWatermark, ServicesVSResources.Search_Settings); + SetBoolValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchPopupAutoDropdown, false); + SetStringValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.ControlBorderThickness, "1"); + SetIntValue(pSearchSettings, SearchSettingsDataSource.PropertyNames.SearchProgressType, (int)VSSEARCHPROGRESSTYPE.SPT_INDETERMINATE); + + void SetBoolValue(IVsUIDataSource source, string property, bool value) + { + var valueProp = BuiltInPropertyValue.FromBool(value); + _ = source.SetValue(property, valueProp); + } + + void SetIntValue(IVsUIDataSource source, string property, int value) + { + var valueProp = BuiltInPropertyValue.Create(value); + _ = source.SetValue(property, valueProp); + } + + void SetStringValue(IVsUIDataSource source, string property, string value) + { + var valueProp = BuiltInPropertyValue.Create(value); + _ = source.SetValue(property, valueProp); + } + } + + public bool OnNavigationKeyDown(uint dwNavigationKey, uint dwModifiers) => false; + + public bool SearchEnabled { get; } = true; + + public Guid Category { get; } = new Guid("1BE8950F-AF27-4B71-8D54-1F7FFEFDC237"); + public IVsEnumWindowSearchFilters? SearchFiltersEnum => null; + public IVsEnumWindowSearchOptions? SearchOptionsEnum => null; + + internal class SearchTask : VsSearchTask + { + private readonly IThreadingContext _threadingContext; + private readonly IWpfTableControl[] _controls; + + public SearchTask(uint dwCookie, + IVsSearchQuery pSearchQuery, + IVsSearchCallback pSearchCallback, + IWpfTableControl[] controls, + IThreadingContext threadingContext) + : base(dwCookie, pSearchQuery, pSearchCallback) + { + _threadingContext = threadingContext; + _controls = controls; + } + + protected override void OnStartSearch() + { + _ = _threadingContext.JoinableTaskFactory.RunAsync( + async () => + { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + foreach (var control in _controls) + { + _ = control.SetFilter(string.Empty, new SearchFilter(SearchQuery, control)); + } + + await TaskScheduler.Default; + uint resultCount = 0; + foreach (var control in _controls) + { + var results = await control.ForceUpdateAsync().ConfigureAwait(false); + resultCount += (uint)results.FilteredAndSortedEntries.Count; + } + + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + SearchCallback.ReportComplete(this, dwResultsFound: resultCount); + }); + } + + protected override void OnStopSearch() + { + _ = _threadingContext.JoinableTaskFactory.RunAsync( + async () => + { + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + foreach (var control in _controls) + { + _ = control.SetFilter(string.Empty, null); + } + }); + } + } + + internal class SearchFilter : IEntryFilter + { + private readonly IEnumerable _searchTokens; + private readonly IReadOnlyList? _visibleColumns; + + public SearchFilter(IVsSearchQuery searchQuery, IWpfTableControl control) + { + _searchTokens = SearchUtilities.ExtractSearchTokens(searchQuery); + if (_searchTokens == null) + { + _searchTokens = Array.Empty(); + } + + var newVisibleColumns = new List(); + foreach (var c in control.ColumnStates) + { + if (c.IsVisible || ((c as ColumnState2)?.GroupingPriority > 0)) + { + var definition = control.ColumnDefinitionManager.GetColumnDefinition(c.Name); + if (definition != null) + { + newVisibleColumns.Add(definition); + } + } + } + + _visibleColumns = newVisibleColumns; + } + + public bool Match(ITableEntryHandle entry) + { + if (_visibleColumns is null) + { + return false; + } + + // An entry is considered matching a search query if all tokens in the search query are matching at least one of entry's columns. + // Reserve one more column for details content + var cachedColumnValues = new string[_visibleColumns.Count + 1]; + + foreach (var searchToken in _searchTokens) + { + // No support for filters yet + if (searchToken is IVsSearchFilterToken) + { + continue; + } + + if (!AtLeastOneColumnOrDetailsContentMatches(entry, searchToken, cachedColumnValues)) + { + return false; + } + } + + return true; + } + + private bool AtLeastOneColumnOrDetailsContentMatches(ITableEntryHandle entry, IVsSearchToken searchToken, string[] cachedColumnValues) + { + // Check details content for any matches + if (cachedColumnValues[0] == null) + { + cachedColumnValues[0] = GetDetailsContentAsString(entry); + } + + var detailsContent = cachedColumnValues[0]; + if (detailsContent != null && Match(detailsContent, searchToken)) + { + // Found match in details content + return true; + } + + if (_visibleColumns is null) + { + return false; + } + + // Check each column for any matches + for (var i = 0; i < _visibleColumns.Count; i++) + { + if (cachedColumnValues[i + 1] == null) + { + cachedColumnValues[i + 1] = GetColumnValueAsString(entry, _visibleColumns[i]); + } + + var columnValue = cachedColumnValues[i + 1]; + + if (columnValue != null && Match(columnValue, searchToken)) + { + // Found match in this column + return true; + } + } + + // No match found in this entry + return false; + } + + private static string GetColumnValueAsString(ITableEntryHandle entry, ITableColumnDefinition column) + { + return (entry.TryCreateStringContent(column, truncatedText: false, singleColumnView: false, content: out var columnValue) && (columnValue != null)) + ? columnValue : string.Empty; + } + + private static string GetDetailsContentAsString(ITableEntryHandle entry) + { + string? detailsString = null; + + if (entry.CanShowDetails) + { + if (entry is IWpfTableEntry wpfEntry) + { + _ = wpfEntry.TryCreateDetailsStringContent(out detailsString); + } + } + + return detailsString ?? string.Empty; + } + + private static bool Match(string columnValue, IVsSearchToken searchToken) + { + return (columnValue != null) && (columnValue.IndexOf(searchToken.ParsedTokenText, StringComparison.OrdinalIgnoreCase) >= 0); + } + } + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/FontSizeConverter.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/FontSizeConverter.cs new file mode 100644 index 0000000000000..c766f4f049a20 --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/FontSizeConverter.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Windows.Data; + +namespace Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Styles +{ + internal class FontSizeConverter : IValueConverter + { + // Scaling percentage. E.g. 122 means 122%. + public int Scale { get; set; } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => (double)value * Scale / 100.0; + + public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => null; + } +} diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml new file mode 100644 index 0000000000000..b75ed7e51d58f --- /dev/null +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml @@ -0,0 +1,85 @@ + + + + + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj index 5fab552e80282..1eb93e319b038 100644 --- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj +++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj @@ -33,7 +33,7 @@ 6cf2e545-6109-4730-8883-cf43d7aec3e1 - + @@ -199,8 +199,7 @@ - + diff --git a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef index 27e41b380e9ba..cf0c02e3f8465 100644 --- a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef +++ b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef @@ -24,3 +24,14 @@ "Value"=dword:00000000 "Title"="Enable experimental C#/VB LSP completion experience" "PreviewPaneChannels"="IntPreview,int.main" + +// 68b46364-d378-42f2-9e72-37d86c5f4468 is the guid for SettingsEditorFactory +// 6cf2e545-6109-4730-8883-cf43d7aec3e1 is the guid for RoslynPackage +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}] +"Package"="{6cf2e545-6109-4730-8883-cf43d7aec3e1}" +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}\Extensions] +// dword must be larger that 26 (the priority of the textmate editor) +// we set it to 100 (64 in hex) here +"editorconfig"=dword:00000064 +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}\LogicalViews] +"{7651a703-06e5-11d1-8ebd-00a0c90f26ea}"="" diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 7261ce5c45d59..2b80da67155e7 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -24,6 +24,7 @@ using Microsoft.CodeAnalysis.Versions; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.ColorSchemes; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings; using Microsoft.VisualStudio.LanguageServices.Experimentation; using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute; @@ -136,6 +137,9 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke _solutionEventMonitor = new SolutionEventMonitor(_workspace); TrackBulkFileOperations(); + + var settingsEditorFactory = _componentModel.GetService(); + RegisterEditorFactory(settingsEditorFactory); } private void InitializeColors() diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 46b3381616243..4b383c59a84d9 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1653,4 +1653,55 @@ I agree to all of the foregoing: This action cannot be undone. Do you wish to continue? + + Analyzers + + + Carrage Return + Newline (\\r\\n) + + + Carrage Return (\\r) + + + Category + + + Code Style + + + Disabled + + + Enabled + + + Error + + + Formatting + + + Id + + + Newline (\\n) + + + Refactoring Only + + + Suggestion + + + Title + + + Value + + + Warning + + + Search Settings + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index b5189e1a7fc45..78d2b64d74833 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -77,6 +77,11 @@ Vždy kvůli srozumitelnosti + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Lokalita volání + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Dokončila se analýza kódu pro {0}. @@ -217,6 +242,11 @@ Aktuální parametr + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Při podržení kláves Alt+F1 zobrazit všechny nápovědy @@ -267,6 +297,11 @@ Povolit diagnostiku pull (experimentální, vyžaduje restart) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Zadejte hodnotu místa volání, nebo zvolte jiný druh vložení hodnoty. @@ -282,6 +317,11 @@ Celé řešení + + Error + Error + + Evaluating ({0} tasks in queue) Vyhodnocování (počet úloh ve frontě: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Generovat soubor .editorconfig z nastavení @@ -312,6 +357,11 @@ Zvýrazňovat související komponenty pod kurzorem + + Id + Id + + In other operators V jiných operátorech @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Stáhnout členy + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Uložit soubor .editorconfig + + Search Settings + Search Settings + + Select destination Vybrat cíl @@ -917,6 +982,11 @@ Některé barvy barevného schématu se přepsaly změnami na stránce možností Prostředí > Písma a barvy. Pokud chcete zrušit všechna přizpůsobení, vyberte na stránce Písma a barvy možnost Použít výchozí. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Potlačit nápovědy, když název parametru odpovídá záměru metody @@ -967,6 +1037,11 @@ Toto je neplatný obor názvů. + + Title + Title + + Type name: Název typu: @@ -1027,6 +1102,11 @@ Použít pojmenovaný argument "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Zde přiřazená hodnota se nikdy nepoužije. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Upozornění: duplicitní název parametru diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 6bf8f12101348..e60716fd3d02b 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -77,6 +77,11 @@ Immer zur besseren Unterscheidung + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Aufrufsite + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Die Codeanalyse für "{0}" wurde abgeschlossen. @@ -217,6 +242,11 @@ Aktueller Parameter + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alle Hinweise beim Drücken von ALT+F1 anzeigen @@ -267,6 +297,11 @@ Pull-Diagnose aktivieren (experimentell, Neustart erforderlich) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Geben Sie einen Aufrufsitewert ein, oder wählen Sie eine andere Art der Werteingabe aus. @@ -282,6 +317,11 @@ Gesamte Projektmappe + + Error + Error + + Evaluating ({0} tasks in queue) Auswertung ({0} Tasks in der Warteschlange) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings EDITORCONFIG-Datei aus Einstellungen generieren @@ -312,6 +357,11 @@ Zugehörige Komponenten unter dem Cursor markieren + + Id + Id + + In other operators In anderen Operatoren @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Member nach oben ziehen + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ EDITORCONFIG-Datei speichern + + Search Settings + Search Settings + + Select destination Ziel auswählen @@ -917,6 +982,11 @@ Einige Farbschemafarben werden durch Änderungen überschrieben, die auf der Optionsseite "Umgebung" > "Schriftarten und Farben" vorgenommen wurden. Wählen Sie auf der Seite "Schriftarten und Farben" die Option "Standardwerte verwenden" aus, um alle Anpassungen rückgängig zu machen. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Hinweise unterdrücken, wenn der Parametername mit der Methodenabsicht übereinstimmt @@ -967,6 +1037,11 @@ Dies ist ein ungültiger Namespace. + + Title + Title + + Type name: Typenname: @@ -1027,6 +1102,11 @@ Benanntes Argument verwenden "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Der hier zugewiesene Wert wird nie verwendet. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Warnung: doppelter Parametername diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 0773ae1ab3d10..42add4119c7dd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -77,6 +77,11 @@ Siempre por claridad + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Sitio de llamada + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. El análisis de código se ha completado para "{0}". @@ -217,6 +242,11 @@ Parámetro actual + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Mostrar todas las sugerencias al presionar Alt+F1 @@ -267,6 +297,11 @@ Habilitar diagnósticos "pull" (experimental, requiere reiniciar) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Escriba un valor de sitio de llamada o elija otro tipo de inserción de valor. @@ -282,6 +317,11 @@ Toda la solución + + Error + Error + + Evaluating ({0} tasks in queue) Evaluando ({0} tareas en cola) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Generar archivo .editorconfig a partir de la configuración @@ -312,6 +357,11 @@ Resaltar componentes relacionados bajo el cursor + + Id + Id + + In other operators En otros operadores @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Extraer miembros + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Guardar archivo .editorconfig + + Search Settings + Search Settings + + Select destination Seleccionar destino @@ -917,6 +982,11 @@ Algunos de los colores de la combinación se reemplazan por los cambios realizados en la página de opciones de Entorno > Fuentes y colores. Elija "Usar valores predeterminados" en la página Fuentes y colores para revertir todas las personalizaciones. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Suprimir las sugerencias cuando el nombre del parámetro coincida con la intención del método @@ -967,6 +1037,11 @@ Este espacio de nombres no es válido + + Title + Title + + Type name: Nombre de tipo: @@ -1027,6 +1102,11 @@ Usar argumento con nombre "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used El valor asignado aquí no se usa nunca @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Advertencia: Nombre de parámetro duplicado diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 66ca64f575e7b..ce66c20ea3ed9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -77,6 +77,11 @@ Toujours pour plus de clarté + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Site d'appel + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Analyse du code effectuée pour '{0}'. @@ -217,6 +242,11 @@ Paramètre actuel + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Afficher tous les indicateurs en appuyant sur Alt+F1 @@ -267,6 +297,11 @@ Activer les diagnostics de 'tirage (pull)' (expérimental, nécessite un redémarrage) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Entrer une valeur de site d'appel ou choisir un autre type d'injection de valeur @@ -282,6 +317,11 @@ Solution complète + + Error + Error + + Evaluating ({0} tasks in queue) Évaluation ({0} tâches en file d'attente) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Générer le fichier .editorconfig à partir des paramètres @@ -312,6 +357,11 @@ Surligner les composants liés sous le curseur + + Id + Id + + In other operators Dans les autres opérateurs @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Élever les membres + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Enregistrer le fichier .editorconfig + + Search Settings + Search Settings + + Select destination Sélectionner la destination @@ -917,6 +982,11 @@ Certaines couleurs du modèle de couleurs sont substituées à la suite des changements apportés dans la page d'options Environnement > Polices et couleurs. Choisissez Utiliser les valeurs par défaut dans la page Polices et couleurs pour restaurer toutes les personnalisations. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Supprimer les indicateurs quand le nom de paramètre correspond à l'intention de la méthode @@ -967,6 +1037,11 @@ Ceci est un espace de noms non valide + + Title + Title + + Type name: Nom du type : @@ -1027,6 +1102,11 @@ Utiliser un argument nommé "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used La valeur affectée ici n'est jamais utilisée @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Avertissement : Nom de paramètre dupliqué diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 84d6b5b8418ce..72a65ec3d00c1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -77,6 +77,11 @@ Sempre per chiarezza + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Sito di chiamata + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Esecuzione di Code Analysis completata per '{0}'. @@ -217,6 +242,11 @@ Parametro corrente + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Visualizza tutti i suggerimenti quando si preme ALT+F1 @@ -267,6 +297,11 @@ Abilita diagnostica 'pull' (sperimentale, richiede il riavvio) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Immettere un valore per il sito di chiamata o scegliere un tipo di inserimento valori diverso @@ -282,6 +317,11 @@ Intera soluzione + + Error + Error + + Evaluating ({0} tasks in queue) In fase di valutazione ({0} attività in coda) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Genera file con estensione editorconfig dalle impostazioni @@ -312,6 +357,11 @@ Evidenzia i componenti correlati sotto il cursore + + Id + Id + + In other operators In altri operatori @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Recupera membri + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Salva file con estensione editorconfig + + Search Settings + Search Settings + + Select destination Seleziona destinazione @@ -917,6 +982,11 @@ Alcuni colori della combinazione colori sono sostituiti dalle modifiche apportate nella pagina di opzioni Ambiente > Tipi di carattere e colori. Scegliere `Usa impostazioni predefinite` nella pagina Tipi di carattere e colori per ripristinare tutte le personalizzazioni. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Non visualizzare suggerimenti quando il nome del parametro corrisponde alla finalità del metodo @@ -967,6 +1037,11 @@ Questo è uno spazio dei nomi non valido + + Title + Title + + Type name: Nome del tipo: @@ -1027,6 +1102,11 @@ Usa l'argomento denominato "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Il valore assegnato qui non viene mai usato @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Avviso: nome di parametro duplicato diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 0c2d35a055059..7f21ef693eaec 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -77,6 +77,11 @@ わかりやすくするために常に + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 呼び出しサイト + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' のコード分析が完了しました。 @@ -217,6 +242,11 @@ 現在のパラメーター + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1 を押しながらすべてのヒントを表示する @@ -267,6 +297,11 @@ 'pull' 診断を有効にする (試験段階、再起動が必要) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 呼び出しサイトの値を入力するか、別の値の挿入の種類を選択してください @@ -282,6 +317,11 @@ ソリューション全体 + + Error + Error + + Evaluating ({0} tasks in queue) 評価中 ({0} 個のタスクがキューにあります) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 設定から .editorconfig ファイルを生成 @@ -312,6 +357,11 @@ カーソルの下にある関連コンポーネントをハイライトする + + Id + Id + + In other operators その他の演算子内で @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ メンバーをプルアップ + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ .editorconfig ファイルの保存 + + Search Settings + Search Settings + + Select destination 宛先の選択 @@ -917,6 +982,11 @@ 一部の配色パターンの色は、[環境] > [フォントおよび色] オプション ページで行われた変更によって上書きされます。[フォントおよび色] オプション ページで [既定値を使用] を選択すると、すべてのカスタマイズが元に戻ります。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent パラメーター名がメソッドの意図と一致する場合にヒントを非表示にする @@ -967,6 +1037,11 @@ これは無効な名前空間です + + Title + Title + + Type name: 種類の名前: @@ -1027,6 +1102,11 @@ 名前付き引数を使用する "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used ここで割り当てた値は一度も使用されません @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: パラメーター名が重複しています diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index c9dffedffb7a8..2e500eba7fddc 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -77,6 +77,11 @@ 명확하게 하기 위해 항상 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 호출 사이트 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}'에 대한 코드 분석이 완료되었습니다. @@ -217,6 +242,11 @@ 현재 매개 변수 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1을 누른 채 모든 힌트 표시 @@ -267,6 +297,11 @@ '풀' 진단 사용(실험적, 다시 시작 필요) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 호출 사이트 값을 입력하거나 다른 값 삽입 종류를 선택하세요. @@ -282,6 +317,11 @@ 전체 솔루션 + + Error + Error + + Evaluating ({0} tasks in queue) 평가 중(큐의 {0}개 작업) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 설정에서 .editorconfig 파일 생성 @@ -312,6 +357,11 @@ 커서 아래의 관련 구성 요소 강조 + + Id + Id + + In other operators 기타 연산자 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 멤버 풀하기 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ editorconfig 파일 저장 + + Search Settings + Search Settings + + Select destination 대상 선택 @@ -917,6 +982,11 @@ 색 구성표의 일부 색이 [환경] > [글꼴 및 색] 옵션 페이지에서 변경한 내용에 따라 재정의됩니다. 모든 사용자 지정을 되돌리려면 [글꼴 및 색] 페이지에서 '기본값 사용'을 선택하세요. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 매개 변수 이름이 메서드의 의도와 일치하는 경우 힌트 표시 안 함 @@ -967,6 +1037,11 @@ 잘못된 네임스페이스입니다. + + Title + Title + + Type name: 형식 이름: @@ -1027,6 +1102,11 @@ 명명된 인수 사용 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 여기에 할당된 값은 사용되지 않습니다. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 경고: 매개 변수 이름이 중복되었습니다. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 7ec15693ddf5f..b5b68596d83b9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -77,6 +77,11 @@ Zawsze w celu zachowania jednoznaczności + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Miejsce wywołania + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Ukończono analizę kodu dla elementu „{0}”. @@ -217,6 +242,11 @@ Bieżący parametr + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Wyświetl wszystkie wskazówki po naciśnięciu klawiszy Alt+F1 @@ -267,6 +297,11 @@ Włącz diagnostykę operacji „pull” (eksperymentalne, wymaga ponownego uruchomienia) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Wprowadź wartość lokalizacji wywołania lub wybierz inny rodzaj iniekcji wartości @@ -282,6 +317,11 @@ Całe rozwiązanie + + Error + Error + + Evaluating ({0} tasks in queue) Szacowanie (zadania w kolejce: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Wygeneruj plik .editorconfig na podstawie ustawień @@ -312,6 +357,11 @@ Wyróżnij powiązane składniki pod kursorem + + Id + Id + + In other operators W innych operatorach @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Podciągnij składowe w górę + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Zapisz plik .editorconfig + + Search Settings + Search Settings + + Select destination Wybierz miejsce docelowe @@ -917,6 +982,11 @@ Niektóre kolory w schemacie kolorów są przesłaniane przez zmiany wprowadzone na stronie opcji Środowisko > Czcionki i kolory. Wybierz pozycję „Użyj ustawień domyślnych” na stronie Czcionki i kolory, aby wycofać wszystkie dostosowania. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Pomiń wskazówki, gdy nazwa parametru pasuje do intencji metody @@ -967,6 +1037,11 @@ To jest nieprawidłowa przestrzeń nazw + + Title + Title + + Type name: Nazwa typu: @@ -1027,6 +1102,11 @@ Użyj nazwanego argumentu "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Przypisana tu wartość nigdy nie jest używana @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Ostrzeżenie: zduplikowana nazwa parametru diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index e81125728c3a4..ca39ce2664ea6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -77,6 +77,11 @@ Sempre para esclarecimento + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Chamar site + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Análise de código concluída para '{0}'. @@ -217,6 +242,11 @@ Parâmetro atual + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Exibir todas as dicas ao pressionar Alt+F1 @@ -267,6 +297,11 @@ Habilitar o diagnóstico de 'pull' (experimental, exige uma reinicialização) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Insira um valor de site de chamada ou escolha um tipo de injeção de valor diferente @@ -282,6 +317,11 @@ Solução Inteira + + Error + Error + + Evaluating ({0} tasks in queue) Avaliando ({0} tarefas na fila) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Gerar o arquivo .editorconfig das configurações @@ -312,6 +357,11 @@ Realçar componentes relacionados usando o cursor + + Id + Id + + In other operators Em outros operadores @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Levantar os membros + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Salvar arquivo .editorconfig + + Search Settings + Search Settings + + Select destination Selecionar destino @@ -917,6 +982,11 @@ Algumas cores do esquema de cores estão sendo substituídas pelas alterações feitas na página de Ambiente > Opções de Fontes e Cores. Escolha 'Usar Padrões' na página Fontes e Cores para reverter todas as personalizações. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Suprimir as dicas quando o nome do parâmetro corresponder à intenção do método @@ -967,6 +1037,11 @@ Este é um namespace inválido + + Title + Title + + Type name: Nome do tipo: @@ -1027,6 +1102,11 @@ Usar argumento nomeado "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used O valor atribuído aqui nunca é usado @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Aviso: nome de parâmetro duplicado diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index e69cabe68805d..185ab2ad080a5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -77,6 +77,11 @@ Всегда использовать для ясности + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Место вызова + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Анализ кода для "{0}" выполнен. @@ -217,6 +242,11 @@ Текущий параметр + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Отображать все подсказки при нажатии клавиш ALT+F1 @@ -267,6 +297,11 @@ Включить диагностику "pull" (экспериментальная функция, требуется перезапуск) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Введите значение места вызова или выберите другой тип введения значения @@ -282,6 +317,11 @@ Все решение + + Error + Error + + Evaluating ({0} tasks in queue) Оценка (задач в очереди: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Создать файл EDITORCONFIG на основе параметров @@ -312,6 +357,11 @@ Выделить связанные компоненты под курсором + + Id + Id + + In other operators В других операторах @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Повышение элементов + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Сохранить файл EDITORCONFIG + + Search Settings + Search Settings + + Select destination Выбрать место назначения @@ -917,6 +982,11 @@ Некоторые цвета цветовой схемы переопределяются изменениями, сделанными на странице "Среда" > "Шрифты и цвета". Выберите "Использовать значения по умолчанию" на странице "Шрифты и цвета", чтобы отменить все настройки. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Скрывать подсказки, если имя параметра соответствует намерению метода. @@ -967,6 +1037,11 @@ Это недопустимое пространство имен. + + Title + Title + + Type name: Имя типа: @@ -1027,6 +1102,11 @@ Использовать именованный аргумент "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Заданное здесь значение не используется. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Предупреждение: повторяющееся имя параметра. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 0fb7479558408..72f968d5f2ff6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -77,6 +77,11 @@ Açıklık sağlamak için her zaman + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Çağrı konumu + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' için kod analizi tamamlandı. @@ -217,6 +242,11 @@ Geçerli parametre + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1 tuşlarına basılırken tüm ipuçlarını görüntüle @@ -267,6 +297,11 @@ 'Pull' tanılamasını etkinleştir (deneysel, yeniden başlatma gerekir) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Bir çağrı sitesi değeri girin veya farklı bir değer yerleştirme tipi seçin @@ -282,6 +317,11 @@ Tüm çözüm + + Error + Error + + Evaluating ({0} tasks in queue) Değerlendiriliyor (kuyrukta {0} görev var) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Ayarlardan .editorconfig dosyası oluştur @@ -312,6 +357,11 @@ İmlecin altında ilgili bileşenleri vurgula + + Id + Id + + In other operators Diğer işleçlerde @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Üyeleri Yukarı Çek + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ .editorconfig dosyasını kaydet + + Search Settings + Search Settings + + Select destination Hedef seçin @@ -917,6 +982,11 @@ Bazı renk düzeni renkleri, Ortam > Yazı Tipleri ve Renkler seçenek sayfasında yapılan değişiklikler tarafından geçersiz kılınıyor. Tüm özelleştirmeleri geri döndürmek için Yazı Tipleri ve Renkler sayfasında `Varsayılanları Kullan` seçeneğini belirleyin. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Parametre adı metodun hedefi ile eşleştiğinde ipuçlarını gizle @@ -967,6 +1037,11 @@ Bu geçersiz bir ad alanı + + Title + Title + + Type name: Tür adı: @@ -1027,6 +1102,11 @@ Adlandırılmış bağımsız değişken kullan "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Burada atanan değer hiçbir zaman kullanılmadı @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Uyarı: Yinelenen parametre adı diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 444999fa40114..81c3fdd8502ae 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -77,6 +77,11 @@ 为始终保持清楚起见 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 调用站点 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. “{0}”的代码分析已完成。 @@ -217,6 +242,11 @@ 当前参数 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 按 Alt+F1 时显示所有提示 @@ -267,6 +297,11 @@ 启用“拉取”诊断(实验性,需要重启) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 输入调用站点值或选择其他值注入类型 @@ -282,6 +317,11 @@ 整个解决方案 + + Error + Error + + Evaluating ({0} tasks in queue) 正在评估(队列中有 {0} 个任务) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 基于设置生成 .editorconfig 文件 @@ -312,6 +357,11 @@ 突出显示光标下的相关组件 + + Id + Id + + In other operators 在其他运算符中 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 拉取成员 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ 保存 .editorconfig 文件 + + Search Settings + Search Settings + + Select destination 选择目标 @@ -917,6 +982,11 @@ 在“环境”>“字体和颜色”选项页中所做的更改将替代某些配色方案颜色。在“字体和颜色”页中选择“使用默认值”,还原所有自定义项。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 当参数名称与方法的意图匹配时禁止显示提示 @@ -967,6 +1037,11 @@ 这是一个无效的命名空间 + + Title + Title + + Type name: 类型名称: @@ -1027,6 +1102,11 @@ 使用命名参数 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 此处分配的值从未使用过 @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: 参数名重复 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index b4e5db7539867..eafb48be3a897 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -77,6 +77,11 @@ 一律使用以明確表示 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 呼叫網站 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' 的程式碼分析已完成。 @@ -217,6 +242,11 @@ 目前的參數 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 按 Alt+F1 時顯示所有提示 @@ -267,6 +297,11 @@ 啟用 'pull' 診斷 (實驗性,需要重新啟動) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 請輸入呼叫位置值,或選擇其他值插入種類 @@ -282,6 +317,11 @@ 整個解決方案 + + Error + Error + + Evaluating ({0} tasks in queue) 正在評估 (佇列中的 {0} 工作) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 從設定產生 .editorconfig 檔案 @@ -312,6 +357,11 @@ 反白資料指標下的相關元件 + + Id + Id + + In other operators 其他運算子中 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 提升成員 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ 儲存 .editorconfig 檔案 + + Search Settings + Search Settings + + Select destination 選取目的地 @@ -917,6 +982,11 @@ [環境] > [字型和色彩選項] 頁面中所做的變更覆寫了某些色彩配置的色彩。請選擇 [字型和色彩] 頁面中的 [使用預設] 來還原所有自訂。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 當參數名稱符合方法的意圖時,不出現提示 @@ -967,6 +1037,11 @@ 這是無效的命名空間 + + Title + Title + + Type name: 類型名稱: @@ -1027,6 +1102,11 @@ 使用具名引數 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 這裡指派的值從未使用過 @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: 參數名稱重複 diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index d5533c1114d22..07f90e4508131 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -284,7 +284,7 @@ public async Task> GetAnalyzerOptionsForPath return _lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(sourceFilePath); } - private sealed class WorkspaceAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider + internal sealed class WorkspaceAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider { private readonly ProjectState _projectState; @@ -303,6 +303,12 @@ public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) return new WorkspaceAnalyzerConfigOptions(_projectState._lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(textFile.Path)); } + public AnalyzerConfigOptions GetOptionsForSourcePath(string path) + { + // TODO: correctly find the file path, since it looks like we give this the document's .Name under the covers if we don't have one + return new WorkspaceAnalyzerConfigOptions(_projectState._lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(path)); + } + private sealed class WorkspaceAnalyzerConfigOptions : AnalyzerConfigOptions { private readonly ImmutableDictionary _backing; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs index 3afb0f2b755e8..63c3322d77652 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs @@ -6,12 +6,14 @@ using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Shared.Extensions { internal static class DiagnosticDescriptorExtensions { private const string DotnetAnalyzerDiagnosticPrefix = "dotnet_analyzer_diagnostic"; + private const string DotnetDiagnosticPrefix = "dotnet_diagnostic"; private const string CategoryPrefix = "category"; private const string SeveritySuffix = "severity"; @@ -43,6 +45,48 @@ public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor de return effectiveSeverity; } + public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor descriptor, AnalyzerConfigOptions analyzerConfigOptions) + { + // Check if the option is defined explicitly in the editorconfig + var diagnosticKey = $"{DotnetDiagnosticPrefix}.{descriptor.Id}.{SeveritySuffix}"; + if (analyzerConfigOptions.TryGetValue(diagnosticKey, out var value) && + EditorConfigSeverityStrings.TryParse(value, out var severity)) + { + return severity; + } + + // Check if the option is defined as part of a bulk configuration + // Analyzer bulk configuration does not apply to: + // 1. Disabled by default diagnostics + // 2. Compiler diagnostics + // 3. Non-configurable diagnostics + if (!descriptor.IsEnabledByDefault || + descriptor.CustomTags.Any(tag => tag == WellKnownDiagnosticTags.Compiler || tag == WellKnownDiagnosticTags.NotConfigurable)) + { + return ReportDiagnostic.Default; + } + + // If user has explicitly configured default severity for the diagnostic category, that should be respected. + // For example, 'dotnet_analyzer_diagnostic.category-security.severity = error' + var categoryBasedKey = $"{DotnetAnalyzerDiagnosticPrefix}.{CategoryPrefix}-{descriptor.Category}.{SeveritySuffix}"; + if (analyzerConfigOptions.TryGetValue(categoryBasedKey, out value) && + EditorConfigSeverityStrings.TryParse(value, out severity)) + { + return severity; + } + + // Otherwise, if user has explicitly configured default severity for all analyzer diagnostics, that should be respected. + // For example, 'dotnet_analyzer_diagnostic.severity = error' + if (analyzerConfigOptions.TryGetValue(DotnetAnalyzerDiagnosticSeverityKey, out value) && + EditorConfigSeverityStrings.TryParse(value, out severity)) + { + return severity; + } + + // option not defined in editorconfig, assumed to be the default + return ReportDiagnostic.Default; + } + /// /// Tries to get configured severity for the given /// from bulk configuration analyzer config options, i.e. From bab8e5d4c6904e4a9f4cd44dcc7e8682aa28f3e3 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 19 Mar 2021 11:52:35 -0700 Subject: [PATCH 023/145] update settings helper values for IOption2 writer --- .../Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs index ce046eb93ec11..bd146de26ad1a 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs @@ -86,7 +86,7 @@ internal static partial class SettingsUpdateHelper { var severity = codeStyleOption.Notification switch { - { Severity: ReportDiagnostic.Hidden } => "refactoring", + { Severity: ReportDiagnostic.Hidden } => "silent", { Severity: ReportDiagnostic.Info } => "suggestion", { Severity: ReportDiagnostic.Warn } => "warning", { Severity: ReportDiagnostic.Error } => "error", From 0cc4b9e81a6dfedbf0b2aa2709e6c09ceb6b407a Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Thu, 18 Mar 2021 12:15:55 -0700 Subject: [PATCH 024/145] Update .gitignore Co-authored-by: Sam Harwell --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index c099dad0050ec..834c624643c68 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ # User-specific files *.suo -*.svclog *.user *.userprefs *.sln.docstates From c4ff7f30dd537005c787c65c11c378b249cb769b Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 19 Mar 2021 11:51:23 -0700 Subject: [PATCH 025/145] Update src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs Co-authored-by: Joey Robichaud --- .../Core/EditorConfigSettings/Extensions/SolutionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs index 25e30f598e5e0..27a805e034d43 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs @@ -13,7 +13,7 @@ internal static class SolutionExtensions { public static ImmutableArray GetProjectsForPath(this Solution solution, string givenPath) { - var givenFolder = new DirectoryInfo(givenPath).Parent; + var givenFolder = new DirectoryInfo(Path.GetDirectoryName(givenPath)); var solutionFolder = new DirectoryInfo(solution.FilePath).Parent; if (givenFolder.FullName == solutionFolder.FullName) { From c1ec753a7321cbdab56a8602dc097d7957365433 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 19 Mar 2021 12:02:53 -0700 Subject: [PATCH 026/145] use WhereNotNull --- .../EditorConfigSettings/DataProvider/CombinedProvider.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs index d63659f0e6a4f..808925d64c70e 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider { @@ -24,14 +25,14 @@ public CombinedProvider(ImmutableArray> providers) { var changes = await Task.WhenAll(_providers.Select(x => x.GetChangedEditorConfigAsync())).ConfigureAwait(false); - changes = changes.Where(x => x is not null).ToArray(); + changes = changes.WhereNotNull().ToArray(); if (!changes.Any()) return null; var result = new List(); foreach (var change in changes) { - result.AddRange(change!); // compiler does not see through linq in nullable yet + result.AddRange(change); } return result; From 837c00fcefb251dee8771e088806001b6f5c2fe1 Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 19 Mar 2021 12:25:27 -0700 Subject: [PATCH 027/145] simplify null checking of array --- .../EditorConfigSettings/DataProvider/CombinedProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs index 808925d64c70e..8a521c2360d02 100644 --- a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs @@ -23,9 +23,9 @@ public CombinedProvider(ImmutableArray> providers) public async Task?> GetChangedEditorConfigAsync() { - var changes = await Task.WhenAll(_providers.Select(x => x.GetChangedEditorConfigAsync())).ConfigureAwait(false); + var changesArray = await Task.WhenAll(_providers.Select(x => x.GetChangedEditorConfigAsync())).ConfigureAwait(false); - changes = changes.WhereNotNull().ToArray(); + var changes = changesArray.WhereNotNull(); if (!changes.Any()) return null; From b619aef36ad12672ba453b8ed6d8647a64ba7f7c Mon Sep 17 00:00:00 2001 From: Jonathon Marolf Date: Fri, 19 Mar 2021 13:59:04 -0700 Subject: [PATCH 028/145] fix tab backgound color in some themes --- .../Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml index b75ed7e51d58f..7959ca6ae556e 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Styles/ThemedDialogResources.xaml @@ -37,7 +37,7 @@