Skip to content

Commit 5e3e646

Browse files
committed
Add support for enabling individual experimental features
1 parent d3228bb commit 5e3e646

File tree

15 files changed

+189
-38
lines changed

15 files changed

+189
-38
lines changed

RetailCoder.VBE/Navigation/CodeExplorer/CodeExplorerViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ private void ExecuteRemoveComand(object param)
558558

559559
public Visibility ExportAllVisibility => CanExecuteExportAllCommand ? Visibility.Visible : Visibility.Collapsed;
560560

561-
public bool EnableExperimentalFeatures => _generalSettings.EnableExperimentalFeatures;
561+
public bool EnableSourceControl => _generalSettings.EnableExperimentalFeatures.Any(a => a.Key == RubberduckUI.GeneralSettings_EnableSourceControl);
562562

563563
public Visibility TreeViewVisibility => Projects == null || Projects.Count == 0 ? Visibility.Collapsed : Visibility.Visible;
564564

RetailCoder.VBE/Root/RubberduckIoCInstaller.cs

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
using Rubberduck.VBEditor.SafeComWrappers.Office.Core.Abstract;
4545
using Component = Castle.MicroKernel.Registration.Component;
4646
using Rubberduck.UI.CodeMetrics;
47-
using Rubberduck.Navigation.CodeMetrics;
4847
using Rubberduck.Parsing.Common;
4948

5049
namespace Rubberduck.Root
@@ -157,7 +156,14 @@ private void RegisterConfiguration(IWindsorContainer container, Assembly[] assem
157156
foreach (var assembly in assembliesToRegister)
158157
{
159158
var assemblyTypes = assembly.DefinedTypes
160-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
159+
.Where(w =>
160+
{
161+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
162+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string) attribute.ConstructorArguments.First().Value : string.Empty;
163+
164+
return attribute == null ||
165+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled);
166+
});
161167

162168
container.Register(Classes.From(assemblyTypes)
163169
.InSameNamespaceAs<Configuration>()
@@ -190,7 +196,14 @@ private void ApplyDefaultInterfaceConvention(IWindsorContainer container, Assemb
190196
foreach (var assembly in assembliesToRegister)
191197
{
192198
var assemblyTypes = assembly.DefinedTypes
193-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
199+
.Where(w =>
200+
{
201+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
202+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string)attribute.ConstructorArguments.First().Value : string.Empty;
203+
204+
return attribute == null ||
205+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled);
206+
});
194207

195208
assemblyTypes.Any(t => t.Name == nameof(IMessageBox));
196209

@@ -212,7 +225,14 @@ private void RegisterFactories(IWindsorContainer container, Assembly[] assemblie
212225
foreach (var assembly in assembliesToRegister)
213226
{
214227
var assemblyTypes = assembly.DefinedTypes
215-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
228+
.Where(w =>
229+
{
230+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
231+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string)attribute.ConstructorArguments.First().Value : string.Empty;
232+
233+
return attribute == null ||
234+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled);
235+
});
216236

217237
container.Register(Types.From(assemblyTypes)
218238
.Where(type => type.IsInterface && type.Name.EndsWith("Factory"))
@@ -236,7 +256,14 @@ private void RegisterQuickFixes(IWindsorContainer container, Assembly[] assembli
236256
foreach (var assembly in assembliesToRegister)
237257
{
238258
var assemblyTypes = assembly.DefinedTypes
239-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
259+
.Where(w =>
260+
{
261+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
262+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string)attribute.ConstructorArguments.First().Value : string.Empty;
263+
264+
return attribute == null ||
265+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled);
266+
});
240267

241268
container.Register(Classes.From(assemblyTypes)
242269
.BasedOn<IQuickFix>()
@@ -251,7 +278,14 @@ private void RegisterInspections(IWindsorContainer container, Assembly[] assembl
251278
foreach (var assembly in assembliesToRegister)
252279
{
253280
var assemblyTypes = assembly.DefinedTypes
254-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
281+
.Where(w =>
282+
{
283+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
284+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string)attribute.ConstructorArguments.First().Value : string.Empty;
285+
286+
return attribute == null ||
287+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled && a.IsEnabled);
288+
});
255289

256290
container.Register(Classes.From(assemblyTypes)
257291
.BasedOn<IInspection>()
@@ -265,8 +299,15 @@ private void RegisterParseTreeInspections(IWindsorContainer container, Assembly[
265299
foreach (var assembly in assembliesToRegister)
266300
{
267301
var assemblyTypes = assembly.DefinedTypes
268-
.Where(w => _initialSettings.EnableExperimentalFeatures || !Attribute.IsDefined(w, typeof(ExperimentalAttribute)));
269-
302+
.Where(w =>
303+
{
304+
var attribute = w.CustomAttributes.FirstOrDefault(f => f.AttributeType == typeof(ExperimentalAttribute));
305+
var ctorArg = attribute?.ConstructorArguments.Any() == true ? (string)attribute.ConstructorArguments.First().Value : string.Empty;
306+
307+
return attribute == null ||
308+
_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == ctorArg && a.IsEnabled);
309+
});
310+
270311
container.Register(Classes.From(assemblyTypes)
271312
.BasedOn<IParseTreeInspection>()
272313
.WithService.Base()
@@ -514,7 +555,7 @@ private Type[] ToolsMenuItems()
514555
typeof(ExportAllCommandMenuItem)
515556
};
516557

517-
if (_initialSettings.EnableExperimentalFeatures)
558+
if (_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == nameof(RubberduckUI.GeneralSettings_EnableSourceControl) && a.IsEnabled))
518559
{
519560
items.Add(typeof(SourceControlCommandMenuItem));
520561
}
@@ -581,7 +622,7 @@ private void RegisterCommands(IWindsorContainer container)
581622

582623
private void RegisterCommandsWithPresenters(IWindsorContainer container)
583624
{
584-
if (_initialSettings.EnableExperimentalFeatures)
625+
if (_initialSettings.EnableExperimentalFeatures.Any(a => a.Key == nameof(RubberduckUI.GeneralSettings_EnableSourceControl) && a.IsEnabled))
585626
{
586627
container.Register(Component.For<CommandBase>()
587628
.ImplementedBy<SourceControlCommand>()
@@ -811,7 +852,7 @@ private void RegisterCustomDeclarationLoadersToParser(IWindsorContainer containe
811852
.LifestyleSingleton());
812853
}
813854

814-
private IEnumerable<Assembly> AssembliesToRegister()
855+
public static IEnumerable<Assembly> AssembliesToRegister()
815856
{
816857
var assemblies = new[]
817858
{
@@ -824,7 +865,7 @@ private IEnumerable<Assembly> AssembliesToRegister()
824865
return assemblies;
825866
}
826867

827-
private IEnumerable<Assembly> FindPlugins()
868+
private static IEnumerable<Assembly> FindPlugins()
828869
{
829870
var assemblies = new List<Assembly>();
830871
var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@
367367
<Compile Include="RubberduckGuid.cs" />
368368
<Compile Include="RubberduckProgId.cs" />
369369
<Compile Include="Settings\CodeInspectionConfigProvider.cs" />
370+
<Compile Include="Settings\ExperimentalFeatures.cs" />
370371
<Compile Include="Settings\GeneralConfigProvider.cs" />
371372
<Compile Include="Settings\HotkeySettings.cs" />
372373
<Compile Include="Settings\HotkeyConfigProvider.cs" />
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Xml.Serialization;
2+
using Rubberduck.UI;
3+
4+
namespace Rubberduck.Settings
5+
{
6+
public class ExperimentalFeatures : ViewModelBase
7+
{
8+
private bool _isEnabled;
9+
public bool IsEnabled
10+
{
11+
get { return _isEnabled; }
12+
set
13+
{
14+
_isEnabled = value;
15+
OnPropertyChanged();
16+
}
17+
}
18+
19+
private string _key;
20+
public string Key
21+
{
22+
get { return _key; }
23+
set
24+
{
25+
_key = value;
26+
OnPropertyChanged();
27+
OnPropertyChanged(nameof(DisplayValue));
28+
}
29+
}
30+
31+
[XmlIgnore]
32+
public string DisplayValue => Key == null ? string.Empty : RubberduckUI.ResourceManager.GetString(Key);
33+
34+
public override string ToString()
35+
{
36+
return Key;
37+
}
38+
}
39+
}

RetailCoder.VBE/Settings/GeneralSettings.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using NLog;
35
using System.Xml.Serialization;
46
using Rubberduck.Common;
@@ -14,7 +16,7 @@ public interface IGeneralSettings
1416
bool IsAutoSaveEnabled { get; set; }
1517
int AutoSavePeriod { get; set; }
1618
int MinimumLogLevel { get; set; }
17-
bool EnableExperimentalFeatures { get; set; }
19+
List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; }
1820
}
1921

2022
[XmlType(AnonymousType = true)]
@@ -48,7 +50,7 @@ public int MinimumLogLevel
4850
}
4951
}
5052

51-
public bool EnableExperimentalFeatures { get; set; }
53+
public List<ExperimentalFeatures> EnableExperimentalFeatures { get; set; }
5254

5355
public GeneralSettings()
5456
{
@@ -59,7 +61,7 @@ public GeneralSettings()
5961
IsAutoSaveEnabled = false;
6062
AutoSavePeriod = 10;
6163
MinimumLogLevel = LogLevel.Off.Ordinal;
62-
EnableExperimentalFeatures = false;
64+
EnableExperimentalFeatures = new List<ExperimentalFeatures>();
6365
}
6466

6567
public bool Equals(GeneralSettings other)
@@ -72,7 +74,8 @@ public bool Equals(GeneralSettings other)
7274
IsAutoSaveEnabled == other.IsAutoSaveEnabled &&
7375
AutoSavePeriod == other.AutoSavePeriod &&
7476
MinimumLogLevel == other.MinimumLogLevel &&
75-
EnableExperimentalFeatures == other.EnableExperimentalFeatures;
77+
EnableExperimentalFeatures.All(a => other.EnableExperimentalFeatures.Contains(a)) &&
78+
EnableExperimentalFeatures.Count == other.EnableExperimentalFeatures.Count;
7679
}
7780
}
7881
}

RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@
271271
</Image>
272272
</MenuItem.Icon>
273273
</MenuItem>
274-
<MenuItem Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=SourceControlPanel_Caption}" Visibility="{Binding EnableExperimentalFeatures, Converter={StaticResource BoolToVisibility}}" >
274+
<MenuItem Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=SourceControlPanel_Caption}" Visibility="{Binding EnableSourceControl, Converter={StaticResource BoolToVisibility}}" >
275275
<MenuItem Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=CodeExplorer_Commit}"
276276
Command="{Binding CommitCommand}"
277277
CommandParameter="{Binding SelectedItem}" />

RetailCoder.VBE/UI/Command/MenuItems/SourceControlCommandMenuItem.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
using Rubberduck.UI.Command.MenuItems.ParentMenus;
1+
using Rubberduck.Parsing.Common;
2+
using Rubberduck.UI.Command.MenuItems.ParentMenus;
23

34
namespace Rubberduck.UI.Command.MenuItems
45
{
6+
[Experimental(nameof(RubberduckUI.GeneralSettings_EnableSourceControl))]
57
public class SourceControlCommandMenuItem : CommandMenuItemBase
68
{
79
public SourceControlCommandMenuItem(CommandBase command)

RetailCoder.VBE/UI/RubberduckUI.Designer.cs

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RetailCoder.VBE/UI/RubberduckUI.resx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,14 +2052,14 @@ Would you like to import them to Rubberduck?</value>
20522052
<value>Method '{0}' is an implementation of event '{1}.{2}'. Rename event '{2}' instead?</value>
20532053
<comment>0: Selected target Identifier; 1: Event Parent; 2: Event name</comment>
20542054
</data>
2055-
<data name="GeneralSettings_EnableExperimentalFeatures" xml:space="preserve">
2056-
<value>Enable experimental features. Requires a restart to take effect.</value>
2055+
<data name="GeneralSettings_EnableSourceControl" xml:space="preserve">
2056+
<value>Enable Source Control.</value>
20572057
</data>
20582058
<data name="GeneralSettings_ExperimentalFeaturesWarning" xml:space="preserve">
20592059
<value>Only enable these if you know what you're doing. Enabling and/or using features from this section may result in things breaking unexpectedly and irrevocable data loss.</value>
20602060
</data>
20612061
<data name="GeneralSettings_ExperimentalFeatures" xml:space="preserve">
2062-
<value>Experimental Features:</value>
2062+
<value>Experimental Features (Requires a restart to take effect):</value>
20632063
</data>
20642064
<data name="ToolsMenu_ExportProject" xml:space="preserve">
20652065
<value>Export Active Project...</value>

RetailCoder.VBE/UI/Settings/GeneralSettings.xaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,17 @@
214214
<AccessText TextWrapping="Wrap" Text="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=GeneralSettings_ExperimentalFeaturesWarning}"/>
215215
</Label.Content>
216216
</Label>
217-
<CheckBox Margin="5,0,0,5" Content="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=GeneralSettings_EnableExperimentalFeatures}"
218-
IsChecked="{Binding SourceControlEnabled}" />
219-
217+
<ListView ItemsSource="{Binding ExperimentalFeatures}"
218+
HorizontalAlignment="Stretch"
219+
BorderThickness="0">
220+
<ListView.ItemTemplate>
221+
<DataTemplate>
222+
<StackPanel Orientation="Horizontal">
223+
<CheckBox IsChecked="{Binding IsEnabled}" Content="{Binding DisplayValue}" />
224+
</StackPanel>
225+
</DataTemplate>
226+
</ListView.ItemTemplate>
227+
</ListView>
220228
</StackPanel>
221229
</Grid>
222230
</ScrollViewer>

0 commit comments

Comments
 (0)