diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs
index ce1f104d6..9b0bbe36d 100644
--- a/ILSpy/ContextMenuEntry.cs
+++ b/ILSpy/ContextMenuEntry.cs
@@ -78,7 +78,7 @@ namespace ICSharpCode.ILSpy
if (textView != null)
reference = textView.GetReferenceSegmentAtMousePosition();
else if (listBox?.SelectedItem is SearchResult result)
- reference = new ReferenceSegment { Reference = result.Member };
+ reference = new ReferenceSegment { Reference = result.Reference };
else
reference = null;
var position = textView != null ? textView.GetPositionFromMousePosition() : null;
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index 224a13594..07a789a4a 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -167,6 +167,10 @@
True
Resources.resx
+
+ Code
+ MSBuild:Compile
+
@@ -204,6 +208,10 @@
+
+ Code
+ MSBuild:Compile
+
SearchPane.xaml
diff --git a/ILSpy/Search/AbstractEntitySearchStrategy.cs b/ILSpy/Search/AbstractEntitySearchStrategy.cs
new file mode 100644
index 000000000..57382846b
--- /dev/null
+++ b/ILSpy/Search/AbstractEntitySearchStrategy.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Concurrent;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Windows.Media;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.ILSpy.TreeNodes;
+
+namespace ICSharpCode.ILSpy.Search
+{
+ abstract class AbstractEntitySearchStrategy : AbstractSearchStrategy
+ {
+ protected readonly Language language;
+ protected readonly ApiVisibility apiVisibility;
+
+ protected AbstractEntitySearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, params string[] terms)
+ : base(resultQueue, terms)
+ {
+ this.language = language;
+ this.apiVisibility = apiVisibility;
+ }
+
+ protected bool CheckVisibility(IEntity entity)
+ {
+ if (apiVisibility == ApiVisibility.All)
+ return true;
+
+ do {
+ if (apiVisibility == ApiVisibility.PublicOnly) {
+ if (!(entity.Accessibility == Accessibility.Public ||
+ entity.Accessibility == Accessibility.Protected ||
+ entity.Accessibility == Accessibility.ProtectedOrInternal))
+ return false;
+ } else if (apiVisibility == ApiVisibility.PublicAndInternal) {
+ if (!language.ShowMember(entity))
+ return false;
+ }
+ entity = entity.DeclaringTypeDefinition;
+ }
+ while (entity != null);
+
+ return true;
+ }
+
+ protected void OnFoundResult(IEntity entity)
+ {
+ var result = ResultFromEntity(entity);
+ OnFoundResult(result);
+ }
+
+ SearchResult ResultFromEntity(IEntity item)
+ {
+ var declaringType = item.DeclaringTypeDefinition;
+ return new SearchResult {
+ Reference = item,
+ Fitness = CalculateFitness(item),
+ Image = GetIcon(item),
+ Name = GetLanguageSpecificName(item),
+ LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace,
+ Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : item.Namespace,
+ AssemblyImage = Images.Assembly,
+ Assembly = item.ParentModule.FullAssemblyName,
+ ToolTip = item.ParentModule.PEFile?.FileName
+ };
+ }
+
+ float CalculateFitness(IEntity member)
+ {
+ string text = member.Name;
+
+ // Probably compiler generated types without meaningful names, show them last
+ if (text.StartsWith("<")) {
+ return 0;
+ }
+
+ // Constructors always have the same name in IL:
+ // Use type name instead
+ if (text == ".cctor" || text == ".ctor") {
+ text = member.DeclaringType.Name;
+ }
+
+ // Ignore generic arguments, it not possible to search based on them either
+ text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text);
+
+ return 1.0f / text.Length;
+ }
+
+ string GetLanguageSpecificName(IEntity member)
+ {
+ switch (member) {
+ case ITypeDefinition t:
+ return language.TypeToString(t, false);
+ case IField f:
+ return language.FieldToString(f, true, false, false);
+ case IProperty p:
+ return language.PropertyToString(p, true, false, false);
+ case IMethod m:
+ return language.MethodToString(m, true, false, false);
+ case IEvent e:
+ return language.EventToString(e, true, false, false);
+ default:
+ throw new NotSupportedException(member?.GetType() + " not supported!");
+ }
+ }
+
+ ImageSource GetIcon(IEntity member)
+ {
+ switch (member) {
+ case ITypeDefinition t:
+ return TypeTreeNode.GetIcon(t);
+ case IField f:
+ return FieldTreeNode.GetIcon(f);
+ case IProperty p:
+ return PropertyTreeNode.GetIcon(p);
+ case IMethod m:
+ return MethodTreeNode.GetIcon(m);
+ case IEvent e:
+ return EventTreeNode.GetIcon(e);
+ default:
+ throw new NotSupportedException(member?.GetType() + " not supported!");
+ }
+ }
+ }
+}
diff --git a/ILSpy/Search/AbstractSearchStrategy.cs b/ILSpy/Search/AbstractSearchStrategy.cs
index 80291ae31..b87bc3aed 100644
--- a/ILSpy/Search/AbstractSearchStrategy.cs
+++ b/ILSpy/Search/AbstractSearchStrategy.cs
@@ -15,14 +15,10 @@ namespace ICSharpCode.ILSpy.Search
protected readonly Regex regex;
protected readonly bool fullNameSearch;
protected readonly bool omitGenerics;
- protected readonly Language language;
- protected readonly ApiVisibility apiVisibility;
private readonly IProducerConsumerCollection resultQueue;
- protected AbstractSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, params string[] terms)
+ protected AbstractSearchStrategy(IProducerConsumerCollection resultQueue, params string[] terms)
{
- this.language = language;
- this.apiVisibility = apiVisibility;
this.resultQueue = resultQueue;
if (terms.Length == 1 && terms[0].Length > 2) {
@@ -87,28 +83,6 @@ namespace ICSharpCode.ILSpy.Search
return true;
}
- protected bool CheckVisibility(IEntity entity)
- {
- if (apiVisibility == ApiVisibility.All)
- return true;
-
- do {
- if (apiVisibility == ApiVisibility.PublicOnly) {
- if (!(entity.Accessibility == Accessibility.Public ||
- entity.Accessibility == Accessibility.Protected ||
- entity.Accessibility == Accessibility.ProtectedOrInternal))
- return false;
- } else if (apiVisibility == ApiVisibility.PublicAndInternal) {
- if (!language.ShowMember(entity))
- return false;
- }
- entity = entity.DeclaringTypeDefinition;
- }
- while (entity != null);
-
- return true;
- }
-
bool IsNoncontiguousMatch(string text, string searchTerm)
{
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(searchTerm)) {
@@ -135,10 +109,9 @@ namespace ICSharpCode.ILSpy.Search
}
return false;
}
-
- protected void OnFoundResult(IEntity entity)
+
+ protected void OnFoundResult(SearchResult result)
{
- var result = ResultFromEntity(entity);
resultQueue.TryAdd(result);
}
@@ -150,75 +123,5 @@ namespace ICSharpCode.ILSpy.Search
return null;
}
}
-
- SearchResult ResultFromEntity(IEntity item)
- {
- var declaringType = item.DeclaringTypeDefinition;
- return new SearchResult {
- Member = item,
- Fitness = CalculateFitness(item),
- Name = GetLanguageSpecificName(item),
- Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : item.Namespace,
- Assembly = item.ParentModule.FullAssemblyName,
- ToolTip = item.ParentModule.PEFile?.FileName
- };
- }
-
- float CalculateFitness(IEntity member)
- {
- string text = member.Name;
-
- // Probably compiler generated types without meaningful names, show them last
- if (text.StartsWith("<")) {
- return 0;
- }
-
- // Constructors always have the same name in IL:
- // Use type name instead
- if (text == ".cctor" || text == ".ctor") {
- text = member.DeclaringType.Name;
- }
-
- // Ignore generic arguments, it not possible to search based on them either
- text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text);
-
- return 1.0f / text.Length;
- }
-
- string GetLanguageSpecificName(IEntity member)
- {
- switch (member) {
- case ITypeDefinition t:
- return language.TypeToString(t, false);
- case IField f:
- return language.FieldToString(f, true, false, false);
- case IProperty p:
- return language.PropertyToString(p, true, false, false);
- case IMethod m:
- return language.MethodToString(m, true, false, false);
- case IEvent e:
- return language.EventToString(e, true, false, false);
- default:
- throw new NotSupportedException(member?.GetType() + " not supported!");
- }
- }
-
- internal static ImageSource GetIcon(IEntity member)
- {
- switch (member) {
- case ITypeDefinition t:
- return TypeTreeNode.GetIcon(t);
- case IField f:
- return FieldTreeNode.GetIcon(f);
- case IProperty p:
- return PropertyTreeNode.GetIcon(p);
- case IMethod m:
- return MethodTreeNode.GetIcon(m);
- case IEvent e:
- return EventTreeNode.GetIcon(e);
- default:
- throw new NotSupportedException(member?.GetType() + " not supported!");
- }
- }
}
}
diff --git a/ILSpy/Search/LiteralSearchStrategy.cs b/ILSpy/Search/LiteralSearchStrategy.cs
index 83c802d6a..c369d8f6f 100644
--- a/ILSpy/Search/LiteralSearchStrategy.cs
+++ b/ILSpy/Search/LiteralSearchStrategy.cs
@@ -15,7 +15,7 @@ using System.Collections.Concurrent;
namespace ICSharpCode.ILSpy.Search
{
- class LiteralSearchStrategy : AbstractSearchStrategy
+ class LiteralSearchStrategy : AbstractEntitySearchStrategy
{
readonly TypeCode searchTermLiteralType;
readonly object searchTermLiteralValue;
diff --git a/ILSpy/Search/MemberSearchStrategy.cs b/ILSpy/Search/MemberSearchStrategy.cs
index 4a631986b..fa1a11662 100644
--- a/ILSpy/Search/MemberSearchStrategy.cs
+++ b/ILSpy/Search/MemberSearchStrategy.cs
@@ -6,7 +6,7 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Search
{
- class MemberSearchStrategy : AbstractSearchStrategy
+ class MemberSearchStrategy : AbstractEntitySearchStrategy
{
readonly MemberSearchKind searchKind;
diff --git a/ILSpy/Search/MetadataTokenSearchStrategy.cs b/ILSpy/Search/MetadataTokenSearchStrategy.cs
index 7ccec19b2..b2eec37df 100644
--- a/ILSpy/Search/MetadataTokenSearchStrategy.cs
+++ b/ILSpy/Search/MetadataTokenSearchStrategy.cs
@@ -9,7 +9,7 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.Search
{
- class MetadataTokenSearchStrategy : AbstractSearchStrategy
+ class MetadataTokenSearchStrategy : AbstractEntitySearchStrategy
{
readonly EntityHandle searchTermToken;
diff --git a/ILSpy/Search/ResourceSearchStrategy.cs b/ILSpy/Search/ResourceSearchStrategy.cs
new file mode 100644
index 000000000..b3da8b8f7
--- /dev/null
+++ b/ILSpy/Search/ResourceSearchStrategy.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.Util;
+using ICSharpCode.ILSpy.TreeNodes;
+using ICSharpCode.TreeView;
+
+namespace ICSharpCode.ILSpy.Search
+{
+ class ResourceSearchStrategy : AbstractSearchStrategy
+ {
+ protected readonly bool searchInside;
+ protected readonly ApiVisibility apiVisibility;
+
+ public ResourceSearchStrategy(ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, string term)
+ : this(apiVisibility, resultQueue, new[] { term })
+ {
+ }
+
+ public ResourceSearchStrategy(ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, string[] terms)
+ : base(resultQueue, terms)
+ {
+ this.apiVisibility = apiVisibility;
+ this.searchInside = true;
+ }
+
+ protected bool CheckVisibility(Resource resource)
+ {
+ if (apiVisibility == ApiVisibility.All)
+ return true;
+
+ if (apiVisibility == ApiVisibility.PublicOnly && (resource.Attributes & ManifestResourceAttributes.VisibilityMask) == ManifestResourceAttributes.Private)
+ return false;
+
+ return true;
+ }
+
+ public override void Search(PEFile module, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ var resourcesNode = new ResourceListTreeNode(module);
+
+ resourcesNode.EnsureLazyChildren();
+ foreach (var node in resourcesNode.Children)
+ Search(module, null, resourcesNode, node, cancellationToken);
+ return;
+ }
+
+ void Search(PEFile module, object reference, SharpTreeNode parent, SharpTreeNode node, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (node is ResourceTreeNode treeNode) {
+ if (!CheckVisibility(treeNode.Resource))
+ return;
+ reference = treeNode.Resource;
+ }
+
+ if (node.Text != null && IsMatch((string)node.Text))
+ OnFoundResult(module, reference, node, parent);
+
+ if (!searchInside)
+ return;
+
+ node.EnsureLazyChildren();
+ foreach (var child in node.Children)
+ Search(module, reference, node, child, cancellationToken);
+ }
+
+ void OnFoundResult(PEFile module, object reference, SharpTreeNode node, SharpTreeNode parent)
+ {
+ var result = new SearchResult {
+ Reference = reference,
+ Fitness = 1f,
+ Image = (ImageSource)node.Icon,
+ Name = (string)node.Text,
+ LocationImage = (ImageSource)parent.Icon,
+ Location = (string)parent.Text,
+ AssemblyImage = Images.Assembly,
+ Assembly = module.Name,
+ ToolTip = module.FileName,
+ };
+ OnFoundResult(result);
+ }
+ }
+}
diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs
index 3eb492740..5901b47ca 100644
--- a/ILSpy/Search/SearchPane.cs
+++ b/ILSpy/Search/SearchPane.cs
@@ -76,6 +76,7 @@ namespace ICSharpCode.ILSpy
searchModeComboBox.Items.Add(new { Image = Images.Event, Name = "Event" });
searchModeComboBox.Items.Add(new { Image = Images.Literal, Name = "Constant" });
searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Metadata Token" });
+ searchModeComboBox.Items.Add(new { Image = Images.ResourceResourcesFile, Name = "Resource" });
ContextMenuProvider.Add(listBox);
MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged;
@@ -263,7 +264,7 @@ namespace ICSharpCode.ILSpy
void JumpToSelectedItem()
{
if (listBox.SelectedItem is SearchResult result) {
- MainWindow.Instance.JumpToReference(result.Member);
+ MainWindow.Instance.JumpToReference(result.Reference);
}
}
@@ -342,6 +343,9 @@ namespace ICSharpCode.ILSpy
if (searchTerm[0].StartsWith("@", StringComparison.Ordinal))
return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm[0].Substring(1));
+
+ if (searchTerm[0].StartsWith("r:", StringComparison.Ordinal))
+ return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm[0].Substring(2));
}
switch (searchMode)
@@ -364,6 +368,8 @@ namespace ICSharpCode.ILSpy
return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Event);
case SearchMode.Token:
return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm);
+ case SearchMode.Resource:
+ return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm);
}
return null;
@@ -371,14 +377,16 @@ namespace ICSharpCode.ILSpy
}
}
- public sealed class SearchResult : IMemberTreeNode
+ public sealed class SearchResult // : IMemberTreeNode
{
+ public static readonly System.Collections.Generic.IComparer Comparer = new SearchResultComparer();
+
ImageSource image;
ImageSource locationImage;
public static readonly IComparer Comparer = new SearchResultComparer();
- public IEntity Member { get; set; }
+ public object Reference { get; set; }
public float Fitness { get; set; }
public string Assembly { get; set; }
@@ -447,6 +455,7 @@ namespace ICSharpCode.ILSpy
Property,
Event,
Literal,
- Token
+ Token,
+ Resource
}
}
\ No newline at end of file