Skip to content

Commit dadb2e4

Browse files
committed
non-nestable custom folders are now supported in Code Explorer. better than no custom folders at all!
1 parent 283f2e2 commit dadb2e4

File tree

9 files changed

+118
-49
lines changed

9 files changed

+118
-49
lines changed

RetailCoder.VBE/Inspections/InspectionsUI.Designer.cs

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

RetailCoder.VBE/Inspections/InspectionsUI.resx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,14 @@
201201
<data name="MultipleDeclarationsInspectionName" xml:space="preserve">
202202
<value>Instruction contains multiple declarations</value>
203203
</data>
204-
<data name="MultipleNamespaceDeclarationInspection" xml:space="preserve">
204+
<data name="MultipleFolderAnnotationsInspection" xml:space="preserve">
205205
<value>'{0}' has more than one namespace declaration.</value>
206206
</data>
207-
<data name="MultipleNamespaceDeclarationInspectionMeta" xml:space="preserve">
208-
<value>Rubberduck only uses the first '@Namespace' annotation in a code module; consider removing extraneous ones.</value>
207+
<data name="MultipleFolderAnnotationsInspectionMeta" xml:space="preserve">
208+
<value>Rubberduck only uses the first '@Folder' annotation in a code module; consider removing extraneous ones.</value>
209209
</data>
210-
<data name="MultipleNamespaceDeclarationInspectionName" xml:space="preserve">
211-
<value>Component has more than one namespace annotation.</value>
210+
<data name="MultipleFolderAnnotationsInspectionName" xml:space="preserve">
211+
<value>Component has more than one folder annotation.</value>
212212
</data>
213213
<data name="NonReturningFunctionInspectionMeta" xml:space="preserve">
214214
<value>This is likely a bug. The return value of a function or property getter must be assigned before exiting, otherwise the program will not be working with expected results. If a function has no meaningful return value, consider declaring it as a 'Sub' procedure instead.</value>

RetailCoder.VBE/Inspections/MultipleNamespaceDeclarationInspection.cs renamed to RetailCoder.VBE/Inspections/MultipleFolderAnnotationsInspection.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
namespace Rubberduck.Inspections
77
{
8-
public sealed class MultipleNamespaceDeclarationInspection : InspectionBase
8+
public sealed class MultipleFolderAnnotationsInspection : InspectionBase
99
{
10-
public MultipleNamespaceDeclarationInspection(RubberduckParserState state)
10+
public MultipleFolderAnnotationsInspection(RubberduckParserState state)
1111
: base(state)
1212
{
1313
Severity = CodeInspectionSeverity.Warning;
1414
}
1515

16-
public override string Description { get { return InspectionsUI.MultipleNamespaceDeclarationInspection; } }
16+
public override string Description { get { return InspectionsUI.MultipleFolderAnnotationsInspection; } }
1717
public override CodeInspectionType InspectionType { get { return CodeInspectionType.MaintainabilityAndReadabilityIssues; } }
1818

1919
public override IEnumerable<CodeInspectionResultBase> GetInspectionResults()
@@ -23,15 +23,15 @@ public override IEnumerable<CodeInspectionResultBase> GetInspectionResults()
2323
|| declaration.DeclarationType == DeclarationType.Module)
2424
&& declaration.Annotations.Split('\n').Count(annotation =>
2525
annotation.StartsWith(Parsing.Grammar.Annotations.AnnotationMarker +
26-
Parsing.Grammar.Annotations.Namespace)) > 1);
26+
Parsing.Grammar.Annotations.Folder)) > 1);
2727
return issues.Select(issue =>
28-
new MultipleNamespaceDeclarationInspectionResult(this, string.Format(Description, issue.ComponentName), issue));
28+
new MultipleFolderAnnotationsInspectionResult(this, string.Format(Description, issue.ComponentName), issue));
2929
}
3030
}
3131

32-
public class MultipleNamespaceDeclarationInspectionResult : CodeInspectionResultBase
32+
public class MultipleFolderAnnotationsInspectionResult : CodeInspectionResultBase
3333
{
34-
public MultipleNamespaceDeclarationInspectionResult(IInspection inspection, string result, Declaration target)
34+
public MultipleFolderAnnotationsInspectionResult(IInspection inspection, string result, Declaration target)
3535
: base(inspection, result, target)
3636
{
3737
}

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@
304304
<DesignTime>True</DesignTime>
305305
<DependentUpon>InspectionsUI.resx</DependentUpon>
306306
</Compile>
307-
<Compile Include="Inspections\MultipleNamespaceDeclarationInspection.cs" />
307+
<Compile Include="Inspections\MultipleFolderAnnotationsInspection.cs" />
308308
<Compile Include="Inspections\UntypedFunctionUsageInspectionResult.cs" />
309309
<Compile Include="Inspections\UseMeaningfulNameInspection.cs" />
310310
<Compile Include="Inspections\UseMeaningfulNameInspectionResult.cs" />

RetailCoder.VBE/UI/CodeExplorer/CodeExplorerComponentViewModel.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,12 @@ public CodeExplorerComponentViewModel(Declaration declaration, IEnumerable<Decla
3131
_declaration = declaration;
3232
_members = declarations.GroupBy(item => item.Scope)
3333
.SelectMany(grouping =>
34-
grouping.Where(item => item.ParentDeclaration.Equals(declaration) && MemberTypes.Contains(item.DeclarationType))
34+
grouping.Where(item => item.ParentDeclaration != null && item.ParentDeclaration.Equals(declaration) && MemberTypes.Contains(item.DeclarationType))
3535
.Select(item => new CodeExplorerMemberViewModel(item, grouping)))
3636
.OrderBy(item => item.Name)
3737
.ToList();
3838

39-
var ns = _declaration.Annotations
40-
.Split('\n')
41-
.FirstOrDefault(annotation => annotation.StartsWith(Parsing.Grammar.Annotations.AnnotationMarker + Parsing.Grammar.Annotations.Namespace));
42-
43-
if (ns != null)
44-
{
45-
46-
var value = ns.Split(' ');
47-
_namespace = value.Length == 1 ? string.Empty : value[1];
48-
}
49-
else
50-
{
51-
_namespace = string.Empty;
52-
}
39+
_customFolder = declaration.CustomFolder;
5340
}
5441

5542
public IEnumerable<CodeExplorerMemberViewModel> Members { get { return _members; } }
@@ -68,8 +55,10 @@ public bool IsTestModule
6855

6956
public string Name { get { return _declaration.IdentifierName; } }
7057

71-
private readonly string _namespace;
72-
public string Namespace { get { return _namespace; } }
58+
private readonly string _customFolder;
59+
public string CustomFolder { get { return _customFolder; } }
60+
61+
public string TypeFolder { get { return DeclarationType.ToString(); } }
7362

7463
private vbext_ComponentType ComponentType { get { return _declaration.QualifiedName.QualifiedModuleName.Component.Type; } }
7564

RetailCoder.VBE/UI/CodeExplorer/CodeExplorerControl.xaml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
xmlns:symbols="clr-namespace:Rubberduck.Parsing.Symbols;assembly=Rubberduck.Parsing"
88
xmlns:resx="clr-namespace:Rubberduck.UI"
99
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
10+
xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
1011
mc:Ignorable="d"
1112
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance explorer:CodeExplorerViewModel}">
1213
<UserControl.Resources>
@@ -94,6 +95,13 @@
9495
ItemTemplate="{StaticResource MemberItemTemplate}">
9596
<TextBlock Text="{Binding Name}" />
9697
</HierarchicalDataTemplate>
98+
99+
<HierarchicalDataTemplate x:Key="CustomFolderItemTemplate"
100+
DataType="explorer:CodeExplorerCustomFolderViewModel"
101+
ItemsSource="{Binding Components}"
102+
ItemTemplate="{StaticResource ComponentItemTemplate}">
103+
<TextBlock Text="{Binding Name}" />
104+
</HierarchicalDataTemplate>
97105

98106
<HierarchicalDataTemplate x:Key="ProjectItemTemplate"
99107
DataType="explorer:CodeExplorerComponentViewModel"
@@ -102,17 +110,20 @@
102110
<TextBlock Text="{Binding Name}" />
103111
</HierarchicalDataTemplate>
104112

105-
<HierarchicalDataTemplate x:Key="CodeExplorerTreeViewTemplate"
113+
<HierarchicalDataTemplate x:Key="CodeExplorerComponentsTemplate"
106114
DataType="explorer:CodeExplorerProjectViewModel"
107115
ItemsSource="{Binding Components}"
108116
ItemTemplate="{StaticResource ProjectItemTemplate}">
109117
<TextBlock Text="{Binding Name}" />
110118
</HierarchicalDataTemplate>
111-
112-
<HierarchicalDataTemplate x:Key="CodeExplorerNamespacesTemplate">
113-
119+
120+
<HierarchicalDataTemplate x:Key="CodeExplorerCustomFoldersTemplate"
121+
DataType="explorer:CodeExplorerProjectViewModel"
122+
ItemsSource="{Binding CustomFolders}"
123+
ItemTemplate="{StaticResource CustomFolderItemTemplate}">
124+
<TextBlock Text="{Binding Name}" />
114125
</HierarchicalDataTemplate>
115-
126+
116127
</UserControl.Resources>
117128

118129
<Grid>
@@ -137,7 +148,7 @@
137148
<Image Height="16" Source="../../Resources/Microsoft/PNG/DisplayFullSignature_13393_32.png" />
138149
</ToggleButton>
139150

140-
<ToggleButton IsEnabled="{Binding CanRefresh}" ToolTip="Toggle namespace folders">
151+
<ToggleButton IsEnabled="{Binding CanRefresh}" ToolTip="Toggle custom folders">
141152
<Image Height="16" Source="../../Resources/blue-folder-horizontal.png" />
142153
</ToggleButton>
143154

@@ -154,7 +165,7 @@
154165
HorizontalContentAlignment="Stretch"
155166
MouseDoubleClick="TreeView_OnMouseDoubleClick"
156167
ItemsSource="{Binding Projects}"
157-
ItemTemplate="{StaticResource CodeExplorerTreeViewTemplate}">
168+
ItemTemplate="{StaticResource CodeExplorerCustomFoldersTemplate}">
158169
<i:Interaction.Behaviors>
159170
<resx:BindableSelectedItemBehavior SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
160171
</i:Interaction.Behaviors>

RetailCoder.VBE/UI/CodeExplorer/CodeExplorerProjectViewModel.cs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public class CodeExplorerProjectViewModel : ViewModelBase
1212
{
1313
private readonly Declaration _declaration;
1414
private readonly IEnumerable<CodeExplorerComponentViewModel> _components;
15+
private readonly IEnumerable<CodeExplorerCustomFolderViewModel> _customFolders;
16+
1517
private readonly BitmapImage _icon;
1618

1719
private static readonly DeclarationType[] ComponentTypes =
@@ -25,20 +27,60 @@ public class CodeExplorerProjectViewModel : ViewModelBase
2527
public CodeExplorerProjectViewModel(Declaration declaration, IEnumerable<Declaration> declarations)
2628
{
2729
_declaration = declaration;
28-
_components = declarations.GroupBy(item => item.ComponentName)
30+
var items = declarations.ToList();
31+
32+
_components = items.GroupBy(item => item.ComponentName)
2933
.SelectMany(grouping =>
3034
grouping.Where(item => ComponentTypes.Contains(item.DeclarationType))
3135
.Select(item => new CodeExplorerComponentViewModel(item, grouping)))
3236
.OrderBy(item => item.Name)
3337
.ToList();
3438

39+
_customFolders = items.GroupBy(item => item.CustomFolder)
40+
.Select(grouping => new CodeExplorerCustomFolderViewModel(grouping.Key, grouping))
41+
.OrderBy(item => item.Name)
42+
.ToList();
43+
3544
var isProtected = _declaration.Project.Protection == vbext_ProjectProtection.vbext_pp_locked;
3645
_icon = GetImageSource(resx.folder_horizontal);
3746
}
3847

3948
public IEnumerable<CodeExplorerComponentViewModel> Components { get { return _components; } }
49+
public IEnumerable<CodeExplorerCustomFolderViewModel> CustomFolders { get { return _customFolders; } }
4050

41-
public string Name { get { return _declaration.IdentifierName; } }
51+
public string Name { get { return _declaration.CustomFolder; } }
4252
public BitmapImage Icon { get { return _icon; } }
4353
}
54+
55+
public class CodeExplorerCustomFolderViewModel : ViewModelBase
56+
{
57+
private readonly string _name;
58+
private readonly IEnumerable<CodeExplorerComponentViewModel> _components;
59+
60+
private static readonly DeclarationType[] ComponentTypes =
61+
{
62+
DeclarationType.Class,
63+
DeclarationType.Document,
64+
DeclarationType.Module,
65+
DeclarationType.UserForm,
66+
};
67+
68+
public CodeExplorerCustomFolderViewModel(string name, IEnumerable<Declaration> declarations)
69+
{
70+
_name = name;
71+
72+
var items = declarations.ToList();
73+
74+
_components = items.GroupBy(item => item.ComponentName)
75+
.SelectMany(grouping =>
76+
grouping.Where(item => ComponentTypes.Contains(item.DeclarationType))
77+
.Select(item => new CodeExplorerComponentViewModel(item, grouping)))
78+
.OrderBy(item => item.Name)
79+
.ToList();
80+
}
81+
82+
public string Name { get { return _name; } }
83+
84+
public IEnumerable<CodeExplorerComponentViewModel> Components { get { return _components; } }
85+
}
4486
}

Rubberduck.Parsing/Grammar/Annotations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ public static class Annotations
66
public static readonly string TestModule = "TestModule";
77
public static readonly string TestMethod = "TestMethod";
88
public static readonly string IgnoreInspection = "Ignore";
9-
public static readonly string Namespace = "Namespace";
9+
public static readonly string Folder = "Folder";
1010
}
1111
}

Rubberduck.Parsing/Symbols/Declaration.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,23 @@ public Declaration(QualifiedMemberName qualifiedName, Declaration parentDeclarat
4040
_context = context;
4141
_isBuiltIn = isBuiltIn;
4242
_annotations = annotations;
43+
44+
_projectName = _qualifiedName.QualifiedModuleName.ProjectName;
45+
46+
var ns = Annotations.Split('\n')
47+
.FirstOrDefault(annotation => annotation.StartsWith(Grammar.Annotations.AnnotationMarker + Grammar.Annotations.Folder));
48+
49+
string result;
50+
if (string.IsNullOrEmpty(ns))
51+
{
52+
result = _projectName;
53+
}
54+
else
55+
{
56+
var value = ns.Split(' ')[1];
57+
result = value;
58+
}
59+
_customFolder = result;
4360
}
4461

4562
/// <summary>
@@ -160,10 +177,11 @@ public void AddMemberCall(IdentifierReference reference)
160177
/// </remarks>
161178
public VBProject Project { get { return _qualifiedName.QualifiedModuleName.Project; } }
162179

180+
private readonly string _projectName;
163181
/// <summary>
164182
/// Gets the name of the VBProject the declaration is made in.
165183
/// </summary>
166-
public string ProjectName { get { return _qualifiedName.QualifiedModuleName.ProjectName; } }
184+
public string ProjectName { get { return _projectName; } }
167185

168186
/// <summary>
169187
/// Gets the name of the VBComponent the declaration is made in.
@@ -317,6 +335,15 @@ public string Scope
317335
}
318336
}
319337

338+
private readonly string _customFolder;
339+
public string CustomFolder
340+
{
341+
get
342+
{
343+
return _customFolder;
344+
}
345+
}
346+
320347
public bool Equals(Declaration other)
321348
{
322349
return other.Project == Project

0 commit comments

Comments
 (0)