未验证 提交 e7e481cc 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #49887 from ryzngard/issue/import_on_paste_setting

Add experimentation to "Usings on Paste" 
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
......@@ -40,7 +41,10 @@ public CommandState GetCommandState(PasteCommandArgs args, Func<CommandState> ne
public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext)
{
// Check that the feature is enabled before doing any work
if (!args.SubjectBuffer.GetFeatureOnOffOption(FeatureOnOffOptions.AddImportsOnPaste))
var optionValue = args.SubjectBuffer.GetOptionalFeatureOnOffOption(FeatureOnOffOptions.AddImportsOnPaste);
// If the feature is explicitly disabled we can exit early
if (optionValue.HasValue && !optionValue.Value)
{
nextCommandHandler();
return;
......@@ -87,6 +91,15 @@ public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, Com
return;
}
var experimentationService = document.Project.Solution.Workspace.Services.GetRequiredService<IExperimentationService>();
var enabled = optionValue.HasValue && optionValue.Value
|| experimentationService.IsExperimentEnabled(WellKnownExperimentNames.ImportsOnPasteDefaultEnabled);
if (!enabled)
{
return;
}
using var _ = executionContext.OperationContext.AddScope(allowCancellation: true, DialogText);
var cancellationToken = executionContext.OperationContext.UserCancellationToken;
......
......@@ -48,6 +48,26 @@ internal static bool GetFeatureOnOffOption(this ITextBuffer buffer, PerLanguageO
}
}
internal static bool? GetOptionalFeatureOnOffOption(this ITextBuffer buffer, PerLanguageOption2<bool?> option)
{
// Add a FailFast to help diagnose 984249. Hopefully this will let us know what the issue is.
try
{
var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document != null)
{
return document.Project.Solution.Options.GetOption(option, document.Project.Language);
}
return option.DefaultValue;
}
catch (Exception e) when (FatalError.ReportAndPropagate(e))
{
throw ExceptionUtilities.Unreachable;
}
}
internal static bool IsInLspEditorContext(this ITextBuffer buffer)
{
if (buffer.TryGetWorkspace(out var workspace))
......
......@@ -80,8 +80,9 @@ internal static class FeatureOnOffOptions
nameof(FeatureOnOffOptions), nameof(UseEnhancedColors), defaultValue: 1,
storageLocations: new RoamingProfileStorageLocation("WindowManagement.Options.UseEnhancedColorsForManagedLanguages"));
public static readonly PerLanguageOption2<bool> AddImportsOnPaste = new(
nameof(FeatureOnOffOptions), nameof(AddImportsOnPaste), defaultValue: false);
public static readonly PerLanguageOption2<bool?> AddImportsOnPaste = new(
nameof(FeatureOnOffOptions), nameof(AddImportsOnPaste), defaultValue: null,
storageLocations: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{nameof(AddImportsOnPaste)}"));
}
[ExportOptionProvider, Shared]
......
......@@ -6,6 +6,7 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.Options;
......@@ -17,7 +18,8 @@ internal class AdvancedOptionPage : AbstractOptionPage
protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider serviceProvider, OptionStore optionStore)
{
var componentModel = (IComponentModel)this.Site.GetService(typeof(SComponentModel));
return new AdvancedOptionPageControl(optionStore, componentModel);
var workspace = componentModel.GetService<VisualStudioWorkspace>();
return new AdvancedOptionPageControl(optionStore, componentModel, workspace.Services.GetService<IExperimentationService>());
}
}
}
......@@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.Editor.Options;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.ExtractMethod;
using Microsoft.CodeAnalysis.Fading;
using Microsoft.CodeAnalysis.ImplementType;
......@@ -33,7 +34,7 @@ internal partial class AdvancedOptionPageControl : AbstractOptionPageControl
{
private readonly ColorSchemeApplier _colorSchemeApplier;
public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel componentModel) : base(optionStore)
public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel componentModel, IExperimentationService experimentationService) : base(optionStore)
{
_colorSchemeApplier = componentModel.GetService<ColorSchemeApplier>();
......@@ -49,7 +50,13 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon
BindToOption(SeparateImportGroups, GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp);
BindToOption(SuggestForTypesInReferenceAssemblies, SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp);
BindToOption(SuggestForTypesInNuGetPackages, SymbolSearchOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp);
BindToOption(AddUsingsOnPaste, FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp);
BindToOption(AddUsingsOnPaste, FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.CSharp, () =>
{
// If the option has not been set by the user, check if the option to enable imports on paste
// is enabled from experimentation. If so, default to that. Otherwise default to disabled
return experimentationService?.IsExperimentEnabled(WellKnownExperimentNames.ImportsOnPasteDefaultEnabled) ?? false;
});
BindToOption(Split_string_literals_on_enter, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp);
BindToOption(EnterOutliningMode, FeatureOnOffOptions.Outlining, LanguageNames.CSharp);
......
......@@ -13,6 +13,7 @@
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.LanguageServices.Implementation.Options.Converters;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options
{
......@@ -76,6 +77,20 @@ private protected void BindToOption(CheckBox checkbox, Option2<bool> optionKey)
_bindingExpressions.Add(bindingExpression);
}
private protected void BindToOption(CheckBox checkbox, Option2<bool?> nullableOptionKey, Func<bool> onNullValue)
{
var binding = new Binding()
{
Source = new OptionBinding<bool?>(OptionStore, nullableOptionKey),
Path = new PropertyPath("Value"),
UpdateSourceTrigger = UpdateSourceTrigger.Default,
Converter = new NullableBoolOptionConverter(onNullValue)
};
var bindingExpression = checkbox.SetBinding(CheckBox.IsCheckedProperty, binding);
_bindingExpressions.Add(bindingExpression);
}
private protected void BindToOption(CheckBox checkbox, PerLanguageOption2<bool> optionKey, string languageName)
{
var binding = new Binding()
......@@ -89,6 +104,20 @@ private protected void BindToOption(CheckBox checkbox, PerLanguageOption2<bool>
_bindingExpressions.Add(bindingExpression);
}
private protected void BindToOption(CheckBox checkbox, PerLanguageOption2<bool?> nullableOptionKey, string languageName, Func<bool> onNullValue)
{
var binding = new Binding()
{
Source = new PerLanguageOptionBinding<bool?>(OptionStore, nullableOptionKey, languageName),
Path = new PropertyPath("Value"),
UpdateSourceTrigger = UpdateSourceTrigger.Default,
Converter = new NullableBoolOptionConverter(onNullValue)
};
var bindingExpression = checkbox.SetBinding(CheckBox.IsCheckedProperty, binding);
_bindingExpressions.Add(bindingExpression);
}
private protected void BindToOption(TextBox textBox, Option2<int> optionKey)
{
var binding = new Binding()
......
// 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.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options.Converters
{
internal class NullableBoolOptionConverter : IValueConverter
{
private readonly Func<bool> _onNullValue;
public NullableBoolOptionConverter(Func<bool> onNullValue)
{
_onNullValue = onNullValue;
}
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not null or bool)
{
return null;
}
if (value is null)
{
return _onNullValue();
}
return (bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> value;
}
}
......@@ -23,11 +23,11 @@ public CSharpAddMissingUsingsOnPaste(VisualStudioInstanceFactory instanceFactory
protected override string LanguageName => LanguageNames.CSharp;
[WpfFact, Trait(Traits.Feature, Traits.Features.AddMissingImports)]
public void VerifyMissingByDefault()
public void VerifyDisabled()
{
var project = new Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils.Project(ProjectName);
VisualStudio.SolutionExplorer.AddFile(project, "Foo.cs", contents: @"
public class Foo
VisualStudio.SolutionExplorer.AddFile(project, "Example.cs", contents: @"
public class Example
{
}
");
......@@ -42,6 +42,44 @@ static void Main(string[] args)
$$
}");
VisualStudio.Workspace.SetFeatureOption(FeatureOnOffOptions.AddImportsOnPaste.Feature, FeatureOnOffOptions.AddImportsOnPaste.Name, LanguageNames.CSharp, "False");
VisualStudio.Editor.Paste(@"Task DoThingAsync() => Task.CompletedTask;");
VisualStudio.Editor.Verify.TextContains(@"
using System;
class Program
{
static void Main(string[] args)
{
}
Task DoThingAsync() => Task.CompletedTask;
}");
}
[WpfFact, Trait(Traits.Feature, Traits.Features.AddMissingImports)]
public void VerifyDisabledWithNull()
{
var project = new Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils.Project(ProjectName);
VisualStudio.SolutionExplorer.AddFile(project, "Example.cs", contents: @"
public class Example
{
}
");
SetUpEditor(@"
using System;
class Program
{
static void Main(string[] args)
{
}
$$
}");
VisualStudio.Workspace.SetFeatureOption(FeatureOnOffOptions.AddImportsOnPaste.Feature, FeatureOnOffOptions.AddImportsOnPaste.Name, LanguageNames.CSharp, valueString: null);
VisualStudio.Editor.Paste(@"Task DoThingAsync() => Task.CompletedTask;");
......@@ -62,8 +100,8 @@ static void Main(string[] args)
public void VerifyAddImportsOnPaste()
{
var project = new Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils.Project(ProjectName);
VisualStudio.SolutionExplorer.AddFile(project, "Foo.cs", contents: @"
public class Foo
VisualStudio.SolutionExplorer.AddFile(project, "Example.cs", contents: @"
public class Example
{
}
");
......
......@@ -3,6 +3,7 @@
' See the LICENSE file in the project root for more information.
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.Experiments
Imports Microsoft.VisualStudio.ComponentModelHost
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options
......@@ -13,8 +14,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Protected Overrides Function CreateOptionPage(serviceProvider As IServiceProvider, optionStore As OptionStore) As AbstractOptionPageControl
Dim componentModel = DirectCast(Me.Site.GetService(GetType(SComponentModel)), IComponentModel)
Return New AdvancedOptionPageControl(optionStore, componentModel)
Dim workspace = componentModel.GetService(Of VisualStudioWorkspace)()
Return New AdvancedOptionPageControl(optionStore, componentModel, workspace.Services.GetService(Of IExperimentationService)())
End Function
End Class
End Namespace
......@@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Editor.Implementation.SplitComment
Imports Microsoft.CodeAnalysis.Editor.Options
Imports Microsoft.CodeAnalysis.Editor.Shared.Options
Imports Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions
Imports Microsoft.CodeAnalysis.Experiments
Imports Microsoft.CodeAnalysis.ExtractMethod
Imports Microsoft.CodeAnalysis.Fading
Imports Microsoft.CodeAnalysis.ImplementType
......@@ -29,7 +30,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Friend Class AdvancedOptionPageControl
Private ReadOnly _colorSchemeApplier As ColorSchemeApplier
Public Sub New(optionStore As OptionStore, componentModel As IComponentModel)
Public Sub New(optionStore As OptionStore, componentModel As IComponentModel, experimentationService As IExperimentationService)
MyBase.New(optionStore)
_colorSchemeApplier = componentModel.GetService(Of ColorSchemeApplier)()
......@@ -45,7 +46,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
BindToOption(SeparateImportGroups, GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.VisualBasic)
BindToOption(SuggestForTypesInReferenceAssemblies, SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic)
BindToOption(SuggestForTypesInNuGetPackages, SymbolSearchOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic)
BindToOption(AddMissingImportsOnPaste, FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.VisualBasic)
BindToOption(AddMissingImportsOnPaste, FeatureOnOffOptions.AddImportsOnPaste, LanguageNames.VisualBasic, Function()
' If the option has Not been set by the user, check if the option to enable imports on paste
' Is enabled from experimentation. If so, default to that. Otherwise default to disabled
If experimentationService Is Nothing Then
Return False
End If
Return experimentationService.IsExperimentEnabled(WellKnownExperimentNames.ImportsOnPasteDefaultEnabled)
End Function)
BindToOption(EnableOutlining, FeatureOnOffOptions.Outlining, LanguageNames.VisualBasic)
BindToOption(Show_outlining_for_declaration_level_constructs, BlockStructureOptions.ShowOutliningForDeclarationLevelConstructs, LanguageNames.VisualBasic)
......
......@@ -33,5 +33,6 @@ internal static class WellKnownExperimentNames
public const string TargetTypedCompletionFilter = "Roslyn.TargetTypedCompletionFilter";
public const string TriggerCompletionInArgumentLists = "Roslyn.TriggerCompletionInArgumentLists";
public const string OOPServerGC = "Roslyn.OOPServerGC";
public const string ImportsOnPasteDefaultEnabled = "Roslyn.ImportsOnPasteDefaultEnabled";
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册