From 146b3e7f4b276cd02813dc799634a75cf82393cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ku=C4=8Dera?= Date: Sun, 22 Sep 2019 14:13:17 +0100 Subject: [PATCH] Accomodate result image caching, split search result, jump to resource children, clean-up --- ILSpy/ILSpy.csproj | 11 +-- ILSpy/MainWindow.xaml.cs | 2 + ILSpy/Search/AbstractEntitySearchStrategy.cs | 9 +- ILSpy/Search/AbstractSearchStrategy.cs | 6 +- ILSpy/Search/ResourceSearchStrategy.cs | 25 +++-- ILSpy/Search/SearchPane.cs | 58 +----------- ILSpy/Search/SearchResult.cs | 97 ++++++++++++++++++++ ILSpy/TreeNodes/AssemblyListTreeNode.cs | 12 ++- 8 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 ILSpy/Search/SearchResult.cs diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 07a789a4a..072b2c3ea 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -167,10 +167,7 @@ True Resources.resx - - Code - MSBuild:Compile - + @@ -208,15 +205,13 @@ - - Code - MSBuild:Compile - + SearchPane.xaml + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 059d9ec14..d388d2887 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -713,6 +713,8 @@ namespace ICSharpCode.ILSpy return assemblyListTreeNode.FindAssemblyNode(asm); case Resource res: return assemblyListTreeNode.FindResourceNode(res); + case ValueTuple resName: + return assemblyListTreeNode.FindResourceNode(resName.Item1, resName.Item2); case ITypeDefinition type: return assemblyListTreeNode.FindTypeNode(type); case IField fd: diff --git a/ILSpy/Search/AbstractEntitySearchStrategy.cs b/ILSpy/Search/AbstractEntitySearchStrategy.cs index 57382846b..e969c69c3 100644 --- a/ILSpy/Search/AbstractEntitySearchStrategy.cs +++ b/ILSpy/Search/AbstractEntitySearchStrategy.cs @@ -52,14 +52,11 @@ namespace ICSharpCode.ILSpy.Search SearchResult ResultFromEntity(IEntity item) { var declaringType = item.DeclaringTypeDefinition; - return new SearchResult { - Reference = item, + return new MemberSearchResult { + Member = 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 }; @@ -104,7 +101,7 @@ namespace ICSharpCode.ILSpy.Search } } - ImageSource GetIcon(IEntity member) + static internal ImageSource GetIcon(IEntity member) { switch (member) { case ITypeDefinition t: diff --git a/ILSpy/Search/AbstractSearchStrategy.cs b/ILSpy/Search/AbstractSearchStrategy.cs index b87bc3aed..7af565262 100644 --- a/ILSpy/Search/AbstractSearchStrategy.cs +++ b/ILSpy/Search/AbstractSearchStrategy.cs @@ -40,17 +40,17 @@ namespace ICSharpCode.ILSpy.Search public abstract void Search(PEFile module, CancellationToken cancellationToken); - protected virtual bool IsMatch(string entityName) + protected virtual bool IsMatch(string name) { if (regex != null) { - return regex.IsMatch(entityName); + return regex.IsMatch(name); } for (int i = 0; i < searchTerm.Length; ++i) { // How to handle overlapping matches? var term = searchTerm[i]; if (string.IsNullOrEmpty(term)) continue; - string text = entityName; + string text = name; switch (term[0]) { case '+': // must contain term = term.Substring(1); diff --git a/ILSpy/Search/ResourceSearchStrategy.cs b/ILSpy/Search/ResourceSearchStrategy.cs index 5faea4ba4..5824afd96 100644 --- a/ILSpy/Search/ResourceSearchStrategy.cs +++ b/ILSpy/Search/ResourceSearchStrategy.cs @@ -46,46 +46,43 @@ namespace ICSharpCode.ILSpy.Search { cancellationToken.ThrowIfCancellationRequested(); var resourcesNode = new ResourceListTreeNode(module); - - resourcesNode.EnsureLazyChildren(); - foreach (var node in resourcesNode.Children) - Search(module, null, resourcesNode, node, cancellationToken); - return; + + foreach (Resource resource in module.Resources) + Search(module, resource, resourcesNode, ResourceTreeNode.Create(resource), cancellationToken); } - void Search(PEFile module, object reference, SharpTreeNode parent, SharpTreeNode node, CancellationToken cancellationToken) + void Search(PEFile module, Resource resource, SharpTreeNode parent, SharpTreeNode node, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (node is ResourceTreeNode treeNode) { if (!CheckVisibility(treeNode.Resource)) return; - reference = treeNode.Resource; + resource = treeNode.Resource; } if (node.Text != null && IsMatch((string)node.Text)) - OnFoundResult(module, reference, node, parent); + OnFoundResult(module, resource, node, parent); if (!searchInside) return; node.EnsureLazyChildren(); foreach (var child in node.Children) - Search(module, reference, node, child, cancellationToken); + Search(module, resource, node, child, cancellationToken); } - void OnFoundResult(PEFile module, object reference, SharpTreeNode node, SharpTreeNode parent) + void OnFoundResult(PEFile module, Resource resource, SharpTreeNode node, SharpTreeNode parent) { var name = (string)node.Text; - var result = new SearchResult { - Reference = reference, + var result = new ResourceSearchResult { + Resource = resource, Fitness = 1.0f / name.Length, Image = (ImageSource)node.Icon, Name = name, LocationImage = (ImageSource)parent.Icon, Location = (string)parent.Text, - AssemblyImage = Images.Assembly, - Assembly = module.Name, + Assembly = module.FullName, ToolTip = module.FileName, }; OnFoundResult(result); diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index 5901b47ca..f911fd3a6 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -32,7 +32,6 @@ using System.Windows.Media; using System.Windows.Threading; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Search; -using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy { @@ -76,7 +75,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" }); + searchModeComboBox.Items.Add(new { Image = Images.Resource, Name = "Resource" }); ContextMenuProvider.Add(listBox); MainWindow.Instance.CurrentAssemblyListChanged += MainWindow_Instance_CurrentAssemblyListChanged; @@ -377,61 +376,6 @@ namespace ICSharpCode.ILSpy } } - 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 object Reference { get; set; } - public float Fitness { get; set; } - - public string Assembly { get; set; } - public string Location { get; set; } - public string Name { get; set; } - public object ToolTip { get; set; } - - public ImageSource Image { - get { - if (image == null) { - image = AbstractSearchStrategy.GetIcon(Member); - } - return image; - } - } - - public ImageSource LocationImage { - get { - if (locationImage == null) { - locationImage = Member.DeclaringTypeDefinition != null ? TypeTreeNode.GetIcon(Member.DeclaringTypeDefinition) : Images.Namespace; - } - return locationImage; - } - } - - public ImageSource AssemblyImage { - get { - return Images.Assembly; - } - } - - public override string ToString() - { - return Name; - } - - class SearchResultComparer : System.Collections.Generic.IComparer - { - public int Compare(SearchResult x, SearchResult y) - { - return StringComparer.Ordinal.Compare(x?.Name ?? "", y?.Name ?? ""); - } - } - } - [ExportMainMenuCommand(Menu = nameof(Properties.Resources._View), Header =nameof(Properties.Resources.Search), MenuIcon = "Images/Search", MenuCategory = nameof(Properties.Resources.View), MenuOrder = 100)] [ExportToolbarCommand(ToolTip = nameof(Properties.Resources.SearchCtrlShiftFOrCtrlE), ToolbarIcon = "Images/Search", ToolbarCategory = nameof(Properties.Resources.View), ToolbarOrder = 100)] sealed class ShowSearchCommand : CommandWrapper diff --git a/ILSpy/Search/SearchResult.cs b/ILSpy/Search/SearchResult.cs new file mode 100644 index 000000000..eb78c0bef --- /dev/null +++ b/ILSpy/Search/SearchResult.cs @@ -0,0 +1,97 @@ +// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Windows.Media; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Search; +using ICSharpCode.ILSpy.TreeNodes; + +namespace ICSharpCode.ILSpy +{ + public class SearchResult + { + public static readonly IComparer Comparer = new SearchResultComparer(); + + public virtual object Reference { + get { + return null; + } + } + + public float Fitness { get; set; } + + public string Name { get; set; } + public string Location { get; set; } + public string Assembly { get; set; } + public object ToolTip { get; set; } + public virtual ImageSource Image { get; set; } + public virtual ImageSource LocationImage { get; set; } + + public ImageSource AssemblyImage { + get { + return Images.Assembly; + } + } + + public override string ToString() + { + return Name; + } + + class SearchResultComparer : IComparer + { + public int Compare(SearchResult x, SearchResult y) + { + return StringComparer.Ordinal.Compare(x?.Name ?? "", y?.Name ?? ""); + } + } + } + + public class MemberSearchResult : SearchResult + { + public IEntity Member { get; set; } + public override object Reference => Member; + + public override ImageSource Image { + get { + if (base.Image == null) { + base.Image = AbstractEntitySearchStrategy.GetIcon(Member); + } + return base.Image; + } + } + + public override ImageSource LocationImage { + get { + if (base.LocationImage == null) { + base.LocationImage = Member.DeclaringTypeDefinition != null ? TypeTreeNode.GetIcon(Member.DeclaringTypeDefinition) : Images.Namespace; + } + return base.LocationImage; + } + } + } + + public class ResourceSearchResult : SearchResult + { + public Resource Resource { get; set; } + public override object Reference => ValueTuple.Create(Resource, Name); + } +} \ No newline at end of file diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index e53a3a883..b579b2930 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -155,7 +155,7 @@ namespace ICSharpCode.ILSpy.TreeNodes #region Find*Node public ILSpyTreeNode FindResourceNode(Resource resource) { - if (resource == null) + if (resource == null || resource.IsNil) return null; foreach (AssemblyTreeNode node in this.Children) { @@ -177,6 +177,16 @@ namespace ICSharpCode.ILSpy.TreeNodes return null; } + public ILSpyTreeNode FindResourceNode(Resource resource, string name) + { + var resourceNode = FindResourceNode(resource); + if (resourceNode == null || name == null || name.Equals(resourceNode.Text)) + return resourceNode; + + resourceNode.EnsureLazyChildren(); + return resourceNode.Children.OfType().Where(x => name.Equals(x.Text)).FirstOrDefault() ?? resourceNode; + } + public AssemblyTreeNode FindAssemblyNode(IModule module) { return FindAssemblyNode(module.PEFile);