From 209e2de6d0be288c4bdfb26e1f71620c19245fa9 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 2 May 2021 10:37:09 +0200 Subject: [PATCH 1/2] First part of #1175 and #828: Add 'innamespace' and 'inassembly' predicates to allow scoping search to a specific assembly/namespace. --- ILSpy/Search/AbstractEntitySearchStrategy.cs | 53 ++++- ILSpy/Search/AbstractSearchStrategy.cs | 91 +++---- ILSpy/Search/AssemblySearchStrategy.cs | 38 +-- ILSpy/Search/LiteralSearchStrategy.cs | 31 ++- ILSpy/Search/MemberSearchStrategy.cs | 39 ++- ILSpy/Search/MetadataTokenSearchStrategy.cs | 35 ++- ILSpy/Search/NamespaceSearchStrategy.cs | 34 +-- ILSpy/Search/ResourceSearchStrategy.cs | 33 ++- ILSpy/Search/SearchPane.cs | 237 ++++++++++++++----- 9 files changed, 398 insertions(+), 193 deletions(-) diff --git a/ILSpy/Search/AbstractEntitySearchStrategy.cs b/ILSpy/Search/AbstractEntitySearchStrategy.cs index 2bf9cc47e..7fab2dea6 100644 --- a/ILSpy/Search/AbstractEntitySearchStrategy.cs +++ b/ILSpy/Search/AbstractEntitySearchStrategy.cs @@ -1,10 +1,25 @@ -using System; +// 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.Concurrent; -using System.Text.RegularExpressions; -using System.Threading; using System.Windows.Media; -using ICSharpCode.Decompiler.Metadata; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Search @@ -16,8 +31,9 @@ namespace ICSharpCode.ILSpy.Search protected readonly Language language; protected readonly ApiVisibility apiVisibility; - protected AbstractEntitySearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, params string[] terms) - : base(resultQueue, terms) + protected AbstractEntitySearchStrategy(Language language, ApiVisibility apiVisibility, + SearchRequest searchRequest, IProducerConsumerCollection resultQueue) + : base(searchRequest, resultQueue) { this.language = language; this.apiVisibility = apiVisibility; @@ -49,6 +65,31 @@ namespace ICSharpCode.ILSpy.Search return true; } + protected bool IsInNamespaceOrAssembly(IEntity entity) + { + if (searchRequest.InAssembly != null) + { + if (!entity.ParentModule.FullAssemblyName.Contains(searchRequest.InAssembly)) + { + return false; + } + } + + if (searchRequest.InNamespace != null) + { + if (searchRequest.InNamespace.Length == 0) + { + return entity.Namespace.Length == 0; + } + else if (!entity.Namespace.Contains(searchRequest.InNamespace)) + { + return false; + } + } + + return true; + } + protected void OnFoundResult(IEntity entity) { var result = ResultFromEntity(entity); diff --git a/ILSpy/Search/AbstractSearchStrategy.cs b/ILSpy/Search/AbstractSearchStrategy.cs index bae4330eb..987f6fe45 100644 --- a/ILSpy/Search/AbstractSearchStrategy.cs +++ b/ILSpy/Search/AbstractSearchStrategy.cs @@ -1,41 +1,60 @@ -using System; +// 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.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 { + struct SearchRequest + { + public SearchMode Mode; + public AssemblySearchKind AssemblySearchKind; + public MemberSearchKind MemberSearchKind; + public string[] Keywords; + public Regex RegEx; + public bool FullNameSearch; + public bool OmitGenerics; + public string InNamespace; + public string InAssembly; + } + abstract class AbstractSearchStrategy { protected readonly string[] searchTerm; protected readonly Regex regex; protected readonly bool fullNameSearch; protected readonly bool omitGenerics; + protected readonly SearchRequest searchRequest; private readonly IProducerConsumerCollection resultQueue; - protected AbstractSearchStrategy(IProducerConsumerCollection resultQueue, params string[] terms) + protected AbstractSearchStrategy(SearchRequest request, IProducerConsumerCollection resultQueue) { this.resultQueue = resultQueue; - - if (terms.Length == 1 && terms[0].Length > 2) - { - string search = terms[0]; - omitGenerics = !(search.Contains("<") || search.Contains("`")); - if (TryParseRegex(search, out regex)) - { - fullNameSearch = search.Contains("\\."); - } - else - { - fullNameSearch = search.Contains("."); - } - } - searchTerm = terms; + this.searchTerm = request.Keywords; + this.regex = request.RegEx; + this.searchRequest = request; + this.fullNameSearch = request.FullNameSearch; + this.omitGenerics = request.OmitGenerics; } public abstract void Search(PEFile module, CancellationToken cancellationToken); @@ -123,37 +142,5 @@ namespace ICSharpCode.ILSpy.Search { resultQueue.TryAdd(result); } - - bool TryParseRegex(string input, out Regex pattern) - { - pattern = null; - if (!input.StartsWith("/", StringComparison.Ordinal)) - { - return false; - } - input = input.Substring(1); - if (input.EndsWith("/", StringComparison.Ordinal)) - { - input = input.Remove(input.Length - 1); - } - if (string.IsNullOrWhiteSpace(input)) - { - return false; - } - pattern = SafeNewRegex(input); - return pattern != null; - - static Regex SafeNewRegex(string unsafePattern) - { - try - { - return new Regex(unsafePattern, RegexOptions.Compiled); - } - catch (ArgumentException) - { - return null; - } - } - } } } diff --git a/ILSpy/Search/AssemblySearchStrategy.cs b/ILSpy/Search/AssemblySearchStrategy.cs index d13d658ba..c15a48a6c 100644 --- a/ILSpy/Search/AssemblySearchStrategy.cs +++ b/ILSpy/Search/AssemblySearchStrategy.cs @@ -1,18 +1,26 @@ -using System; +// 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.Concurrent; -using System.Collections.Generic; using System.IO; -using System.Reflection; -using System.Reflection.Metadata; 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 { @@ -20,13 +28,9 @@ namespace ICSharpCode.ILSpy.Search { readonly AssemblySearchKind searchKind; - public AssemblySearchStrategy(string term, IProducerConsumerCollection resultQueue, AssemblySearchKind searchKind) - : this(resultQueue, new[] { term }, searchKind) - { - } - - public AssemblySearchStrategy(IProducerConsumerCollection resultQueue, string[] terms, AssemblySearchKind searchKind) - : base(resultQueue, terms) + public AssemblySearchStrategy(SearchRequest request, + IProducerConsumerCollection resultQueue, AssemblySearchKind searchKind) + : base(request, resultQueue) { this.searchKind = searchKind; } diff --git a/ILSpy/Search/LiteralSearchStrategy.cs b/ILSpy/Search/LiteralSearchStrategy.cs index 78b51db33..57f0a3f28 100644 --- a/ILSpy/Search/LiteralSearchStrategy.cs +++ b/ILSpy/Search/LiteralSearchStrategy.cs @@ -1,7 +1,23 @@ -using System; +// 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.Concurrent; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using System.Threading; using ICSharpCode.Decompiler; @@ -13,7 +29,6 @@ using ICSharpCode.Decompiler.Util; using static System.Reflection.Metadata.PEReaderExtensions; using ILOpCode = System.Reflection.Metadata.ILOpCode; -using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.Search { @@ -22,9 +37,11 @@ namespace ICSharpCode.ILSpy.Search readonly TypeCode searchTermLiteralType; readonly object searchTermLiteralValue; - public LiteralSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, params string[] terms) - : base(language, apiVisibility, resultQueue, terms) + public LiteralSearchStrategy(Language language, ApiVisibility apiVisibility, SearchRequest request, + IProducerConsumerCollection resultQueue) + : base(language, apiVisibility, request, resultQueue) { + var terms = request.Keywords; if (terms.Length == 1) { var lexer = new Lexer(new LATextReader(new System.IO.StringReader(terms[0]))); @@ -72,7 +89,7 @@ namespace ICSharpCode.ILSpy.Search if (!md.HasBody() || !MethodIsLiteralMatch(module, md)) continue; var method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(method)) + if (!CheckVisibility(method) || !IsInNamespaceOrAssembly(method)) continue; OnFoundResult(method); } @@ -91,7 +108,7 @@ namespace ICSharpCode.ILSpy.Search if (!IsLiteralMatch(metadata, blob.ReadConstant(constant.TypeCode))) continue; IField field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(field)) + if (!CheckVisibility(field) || !IsInNamespaceOrAssembly(field)) continue; OnFoundResult(field); } diff --git a/ILSpy/Search/MemberSearchStrategy.cs b/ILSpy/Search/MemberSearchStrategy.cs index 65e7ca374..1ff3d5c3a 100644 --- a/ILSpy/Search/MemberSearchStrategy.cs +++ b/ILSpy/Search/MemberSearchStrategy.cs @@ -1,4 +1,21 @@ -using System; +// 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.Concurrent; using System.Threading; @@ -11,13 +28,9 @@ namespace ICSharpCode.ILSpy.Search { readonly MemberSearchKind searchKind; - public MemberSearchStrategy(Language language, ApiVisibility apiVisibility, string term, IProducerConsumerCollection resultQueue, MemberSearchKind searchKind = MemberSearchKind.All) - : this(language, apiVisibility, resultQueue, new[] { term }, searchKind) - { - } - - public MemberSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, string[] terms, MemberSearchKind searchKind = MemberSearchKind.All) - : base(language, apiVisibility, resultQueue, terms) + public MemberSearchStrategy(Language language, ApiVisibility apiVisibility, SearchRequest searchRequest, + IProducerConsumerCollection resultQueue, MemberSearchKind searchKind = MemberSearchKind.All) + : base(language, apiVisibility, searchRequest, resultQueue) { this.searchKind = searchKind; } @@ -39,7 +52,7 @@ namespace ICSharpCode.ILSpy.Search if (languageSpecificName != null && !IsMatch(languageSpecificName)) continue; var type = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(type)) + if (!CheckVisibility(type) || !IsInNamespaceOrAssembly(type)) continue; OnFoundResult(type); } @@ -54,7 +67,7 @@ namespace ICSharpCode.ILSpy.Search if (languageSpecificName != null && !IsMatch(languageSpecificName)) continue; var method = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(method)) + if (!CheckVisibility(method) || !IsInNamespaceOrAssembly(method)) continue; OnFoundResult(method); } @@ -69,7 +82,7 @@ namespace ICSharpCode.ILSpy.Search if (languageSpecificName != null && !IsMatch(languageSpecificName)) continue; var field = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(field)) + if (!CheckVisibility(field) || !IsInNamespaceOrAssembly(field)) continue; OnFoundResult(field); } @@ -84,7 +97,7 @@ namespace ICSharpCode.ILSpy.Search if (languageSpecificName != null && !IsMatch(languageSpecificName)) continue; var property = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(property)) + if (!CheckVisibility(property) || !IsInNamespaceOrAssembly(property)) continue; OnFoundResult(property); } @@ -99,7 +112,7 @@ namespace ICSharpCode.ILSpy.Search if (!IsMatch(languageSpecificName)) continue; var @event = ((MetadataModule)typeSystem.MainModule).GetDefinition(handle); - if (!CheckVisibility(@event)) + if (!CheckVisibility(@event) || !IsInNamespaceOrAssembly(@event)) continue; OnFoundResult(@event); } diff --git a/ILSpy/Search/MetadataTokenSearchStrategy.cs b/ILSpy/Search/MetadataTokenSearchStrategy.cs index ae1fa33e1..278e26a40 100644 --- a/ILSpy/Search/MetadataTokenSearchStrategy.cs +++ b/ILSpy/Search/MetadataTokenSearchStrategy.cs @@ -1,4 +1,21 @@ -using System; +// 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.Concurrent; using System.Globalization; using System.Reflection.Metadata; @@ -14,9 +31,11 @@ namespace ICSharpCode.ILSpy.Search { readonly EntityHandle searchTermToken; - public MetadataTokenSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection resultQueue, params string[] terms) - : base(language, apiVisibility, resultQueue, terms) + public MetadataTokenSearchStrategy(Language language, ApiVisibility apiVisibility, SearchRequest request, + IProducerConsumerCollection resultQueue) + : base(language, apiVisibility, request, resultQueue) { + var terms = request.Keywords; if (terms.Length == 1) { int.TryParse(terms[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var token); @@ -41,7 +60,7 @@ namespace ICSharpCode.ILSpy.Search if (row < 1 || row > module.Metadata.TypeDefinitions.Count) break; var type = metadataModule.GetDefinition((TypeDefinitionHandle)searchTermToken); - if (!CheckVisibility(type)) + if (!CheckVisibility(type) || !IsInNamespaceOrAssembly(type)) break; OnFoundResult(type); break; @@ -49,7 +68,7 @@ namespace ICSharpCode.ILSpy.Search if (row < 1 || row > module.Metadata.MethodDefinitions.Count) break; var method = metadataModule.GetDefinition((MethodDefinitionHandle)searchTermToken); - if (!CheckVisibility(method)) + if (!CheckVisibility(method) || !IsInNamespaceOrAssembly(method)) break; OnFoundResult(method); break; @@ -57,7 +76,7 @@ namespace ICSharpCode.ILSpy.Search if (row < 1 || row > module.Metadata.FieldDefinitions.Count) break; var field = metadataModule.GetDefinition((FieldDefinitionHandle)searchTermToken); - if (!CheckVisibility(field)) + if (!CheckVisibility(field) || !IsInNamespaceOrAssembly(field)) break; OnFoundResult(field); break; @@ -65,7 +84,7 @@ namespace ICSharpCode.ILSpy.Search if (row < 1 || row > module.Metadata.PropertyDefinitions.Count) break; var property = metadataModule.GetDefinition((PropertyDefinitionHandle)searchTermToken); - if (!CheckVisibility(property)) + if (!CheckVisibility(property) || !IsInNamespaceOrAssembly(property)) break; OnFoundResult(property); break; @@ -73,7 +92,7 @@ namespace ICSharpCode.ILSpy.Search if (row < 1 || row > module.Metadata.EventDefinitions.Count) break; var @event = metadataModule.GetDefinition((EventDefinitionHandle)searchTermToken); - if (!CheckVisibility(@event)) + if (!CheckVisibility(@event) || !IsInNamespaceOrAssembly(@event)) break; OnFoundResult(@event); break; diff --git a/ILSpy/Search/NamespaceSearchStrategy.cs b/ILSpy/Search/NamespaceSearchStrategy.cs index d9ee18227..8da1ce3cc 100644 --- a/ILSpy/Search/NamespaceSearchStrategy.cs +++ b/ILSpy/Search/NamespaceSearchStrategy.cs @@ -1,13 +1,24 @@ -using System; +// 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.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; -using System.Reflection.Metadata; using System.Threading; -using System.Windows.Media; -using System.Windows.Media.Imaging; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; @@ -17,13 +28,8 @@ namespace ICSharpCode.ILSpy.Search { class NamespaceSearchStrategy : AbstractSearchStrategy { - public NamespaceSearchStrategy(string term, IProducerConsumerCollection resultQueue) - : this(resultQueue, new[] { term }) - { - } - - public NamespaceSearchStrategy(IProducerConsumerCollection resultQueue, string[] terms) - : base(resultQueue, terms) + public NamespaceSearchStrategy(SearchRequest request, IProducerConsumerCollection resultQueue) + : base(request, resultQueue) { } diff --git a/ILSpy/Search/ResourceSearchStrategy.cs b/ILSpy/Search/ResourceSearchStrategy.cs index c42516a59..39967538d 100644 --- a/ILSpy/Search/ResourceSearchStrategy.cs +++ b/ILSpy/Search/ResourceSearchStrategy.cs @@ -1,15 +1,27 @@ -using System; +// 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.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; @@ -20,13 +32,8 @@ namespace ICSharpCode.ILSpy.Search 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) + public ResourceSearchStrategy(ApiVisibility apiVisibility, SearchRequest request, IProducerConsumerCollection resultQueue) + : base(request, resultQueue) { this.apiVisibility = apiVisibility; this.searchInside = true; diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index cb63a675d..20e5f1a9d 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -24,6 +24,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -32,7 +33,6 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; -using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.Search; @@ -283,19 +283,170 @@ namespace ICSharpCode.ILSpy { readonly CancellationTokenSource cts = new CancellationTokenSource(); readonly IList assemblies; - readonly string[] searchTerm; + readonly SearchRequest searchRequest; readonly SearchMode searchMode; readonly Language language; readonly ApiVisibility apiVisibility; public readonly IProducerConsumerCollection resultQueue = new ConcurrentQueue(); - public RunningSearch(IList assemblies, string searchTerm, SearchMode searchMode, Language language, ApiVisibility apiVisibility) + public RunningSearch(IList assemblies, string searchTerm, SearchMode searchMode, + Language language, ApiVisibility apiVisibility) { this.assemblies = assemblies; - this.searchTerm = NativeMethods.CommandLineToArgumentArray(searchTerm); this.language = language; this.searchMode = searchMode; this.apiVisibility = apiVisibility; + this.searchRequest = Parse(searchTerm); + } + + SearchRequest Parse(string input) + { + string[] parts = NativeMethods.CommandLineToArgumentArray(input); + + SearchRequest request = new SearchRequest(); + List keywords = new List(); + Regex regex = null; + request.Mode = searchMode; + + foreach (string part in parts) + { + // Parse: [prefix:|@]["]searchTerm["] + // Find quotes used for escaping + int prefixLength = part.IndexOfAny(new[] { '"', '/' }); + if (prefixLength < 0) + { + // no quotes + prefixLength = part.Length; + } + + // Find end of prefix + if (part.StartsWith("@", StringComparison.Ordinal)) + { + prefixLength = 1; + } + else + { + prefixLength = part.IndexOf(':', 0, prefixLength); + } + string prefix; + if (prefixLength <= 0) + { + prefix = null; + prefixLength = -1; + } + else + { + prefix = part.Substring(0, prefixLength); + } + + // unescape quotes + string searchTerm = part.Substring(prefixLength + 1).Trim(); + if (searchTerm.Length > 0) + { + searchTerm = NativeMethods.CommandLineToArgumentArray(searchTerm)[0]; + } + + if (prefix == null || prefix.Length <= 2) + { + if (regex == null && searchTerm.StartsWith("/", StringComparison.Ordinal) && searchTerm.Length > 1) + { + int searchTermLength = searchTerm.Length - 1; + if (searchTerm.EndsWith("/", StringComparison.Ordinal)) + { + searchTermLength--; + } + + request.FullNameSearch |= searchTerm.Contains("\\."); + + regex = CreateRegex(searchTerm.Substring(1, searchTermLength)); + } + else + { + request.FullNameSearch |= searchTerm.Contains("."); + keywords.Add(searchTerm); + } + request.OmitGenerics |= !(searchTerm.Contains("<") || searchTerm.Contains("`")); + } + + switch (prefix?.ToUpperInvariant()) + { + case "@": + request.Mode = SearchMode.Token; + break; + case "INNAMESPACE": + request.InNamespace ??= searchTerm; + break; + case "INASSEMBLY": + request.InAssembly ??= searchTerm; + break; + case "A": + request.AssemblySearchKind = AssemblySearchKind.NameOrFileName; + request.Mode = SearchMode.Assembly; + break; + case "AF": + request.AssemblySearchKind = AssemblySearchKind.FilePath; + request.Mode = SearchMode.Assembly; + break; + case "AN": + request.AssemblySearchKind = AssemblySearchKind.FullName; + request.Mode = SearchMode.Assembly; + break; + case "N": + request.Mode = SearchMode.Namespace; + break; + case "TM": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.All; + break; + case "T": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Type; + break; + case "M": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Member; + break; + case "MD": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Method; + break; + case "F": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Field; + break; + case "P": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Property; + break; + case "E": + request.Mode = SearchMode.Member; + request.MemberSearchKind = MemberSearchKind.Event; + break; + case "C": + request.Mode = SearchMode.Literal; + break; + case "R": + request.Mode = SearchMode.Resource; + break; + } + } + + Regex CreateRegex(string s) + { + try + { + return new Regex(s, RegexOptions.Compiled); + } + catch (ArgumentException) + { + return null; + } + } + + request.Keywords = keywords.ToArray(); + request.RegEx = regex; + + return request; } public void Cancel() @@ -308,7 +459,9 @@ namespace ICSharpCode.ILSpy try { await Task.Factory.StartNew(() => { - var searcher = GetSearchStrategy(); + var searcher = GetSearchStrategy(searchRequest); + if (searcher == null) + return; try { foreach (var loadedAssembly in assemblies) @@ -332,79 +485,37 @@ namespace ICSharpCode.ILSpy } } - AbstractSearchStrategy GetSearchStrategy() + AbstractSearchStrategy GetSearchStrategy(SearchRequest request) { - if (searchTerm.Length == 1) - { - if (searchTerm[0].StartsWith("tm:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(3), resultQueue); - - if (searchTerm[0].StartsWith("t:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(2), resultQueue, MemberSearchKind.Type); - - if (searchTerm[0].StartsWith("m:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(2), resultQueue, MemberSearchKind.Member); - - if (searchTerm[0].StartsWith("md:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(3), resultQueue, MemberSearchKind.Method); - - if (searchTerm[0].StartsWith("f:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(2), resultQueue, MemberSearchKind.Field); - - if (searchTerm[0].StartsWith("p:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(2), resultQueue, MemberSearchKind.Property); - - if (searchTerm[0].StartsWith("e:", StringComparison.Ordinal)) - return new MemberSearchStrategy(language, apiVisibility, searchTerm[0].Substring(2), resultQueue, MemberSearchKind.Event); - - if (searchTerm[0].StartsWith("c:", StringComparison.Ordinal)) - return new LiteralSearchStrategy(language, apiVisibility, resultQueue, searchTerm[0].Substring(2)); - - 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)); - - if (searchTerm[0].StartsWith("a:", StringComparison.Ordinal)) - return new AssemblySearchStrategy(searchTerm[0].Substring(2), resultQueue, AssemblySearchKind.NameOrFileName); - - if (searchTerm[0].StartsWith("af:", StringComparison.Ordinal)) - return new AssemblySearchStrategy(searchTerm[0].Substring(3), resultQueue, AssemblySearchKind.FilePath); - - if (searchTerm[0].StartsWith("an:", StringComparison.Ordinal)) - return new AssemblySearchStrategy(searchTerm[0].Substring(3), resultQueue, AssemblySearchKind.FullName); - - if (searchTerm[0].StartsWith("n:", StringComparison.Ordinal)) - return new NamespaceSearchStrategy(searchTerm[0].Substring(2), resultQueue); - } + if (request.Keywords.Length == 0 && request.RegEx == null) + return null; - switch (searchMode) + switch (request.Mode) { case SearchMode.TypeAndMember: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue); case SearchMode.Type: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Type); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Type); case SearchMode.Member: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Member); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, request.MemberSearchKind); case SearchMode.Literal: - return new LiteralSearchStrategy(language, apiVisibility, resultQueue, searchTerm); + return new LiteralSearchStrategy(language, apiVisibility, request, resultQueue); case SearchMode.Method: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Method); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Method); case SearchMode.Field: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Field); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Field); case SearchMode.Property: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Property); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Property); case SearchMode.Event: - return new MemberSearchStrategy(language, apiVisibility, resultQueue, searchTerm, MemberSearchKind.Event); + return new MemberSearchStrategy(language, apiVisibility, request, resultQueue, MemberSearchKind.Event); case SearchMode.Token: - return new MetadataTokenSearchStrategy(language, apiVisibility, resultQueue, searchTerm); + return new MetadataTokenSearchStrategy(language, apiVisibility, request, resultQueue); case SearchMode.Resource: - return new ResourceSearchStrategy(apiVisibility, resultQueue, searchTerm); + return new ResourceSearchStrategy(apiVisibility, request, resultQueue); case SearchMode.Assembly: - return new AssemblySearchStrategy(resultQueue, searchTerm, AssemblySearchKind.NameOrFileName); + return new AssemblySearchStrategy(request, resultQueue, AssemblySearchKind.NameOrFileName); case SearchMode.Namespace: - return new NamespaceSearchStrategy(resultQueue, searchTerm); + return new NamespaceSearchStrategy(request, resultQueue); } return null; From fe2adcd8872b4829b05a01cf1b61f01b9d72d7ea Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 5 Dec 2021 23:47:36 +0100 Subject: [PATCH 2/2] Add context menu entries to allow setting "inassembly:" and "innamespace:" prefixes from tree nodes and search results. --- .../CopyFullyQualifiedNameContextMenuEntry.cs | 21 ++++- ILSpy/Commands/ScopeSearchToAssembly.cs | 82 +++++++++++++++++++ ILSpy/Commands/ScopeSearchToNamespace.cs | 82 +++++++++++++++++++ ILSpy/Properties/Resources.Designer.cs | 18 ++++ ILSpy/Properties/Resources.resx | 6 ++ 5 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 ILSpy/Commands/ScopeSearchToAssembly.cs create mode 100644 ILSpy/Commands/ScopeSearchToNamespace.cs diff --git a/ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs b/ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs index 020fc76b3..0a197035c 100644 --- a/ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs +++ b/ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs @@ -1,9 +1,22 @@ -using System; +// 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.Windows; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Metadata; -using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; diff --git a/ILSpy/Commands/ScopeSearchToAssembly.cs b/ILSpy/Commands/ScopeSearchToAssembly.cs new file mode 100644 index 000000000..89512a2c9 --- /dev/null +++ b/ILSpy/Commands/ScopeSearchToAssembly.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2021 Siegfried Pammer +// +// 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 ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Properties; +using ICSharpCode.ILSpy.TreeNodes; + +namespace ICSharpCode.ILSpy +{ + [ExportContextMenuEntry(Header = nameof(Resources.ScopeSearchToThisAssembly), Category = nameof(Resources.Analyze), Order = 9999)] + public class ScopeSearchToAssembly : IContextMenuEntry + { + public void Execute(TextViewContext context) + { + string asmName = GetAssembly(context); + string searchTerm = MainWindow.Instance.SearchPane.SearchTerm; + string[] args = NativeMethods.CommandLineToArgumentArray(searchTerm); + bool replaced = false; + for (int i = 0; i < args.Length; i++) + { + if (args[i].StartsWith("inassembly:", StringComparison.OrdinalIgnoreCase)) + { + args[i] = "inassembly:" + asmName; + replaced = true; + break; + } + } + if (!replaced) + { + searchTerm += " inassembly:" + asmName; + } + else + { + searchTerm = NativeMethods.ArgumentArrayToCommandLine(args); + } + MainWindow.Instance.SearchPane.SearchTerm = searchTerm; + } + + public bool IsEnabled(TextViewContext context) + { + return GetAssembly(context) != null; + } + + public bool IsVisible(TextViewContext context) + { + return GetAssembly(context) != null; + } + + string GetAssembly(TextViewContext context) + { + if (context.Reference?.Reference is IEntity entity) + return entity.ParentModule.AssemblyName; + if (context.SelectedTreeNodes?.Length != 1) + return null; + switch (context.SelectedTreeNodes[0]) + { + case AssemblyTreeNode tn: + return tn.LoadedAssembly.ShortName; + case IMemberTreeNode member: + return member.Member.ParentModule.AssemblyName; + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/ILSpy/Commands/ScopeSearchToNamespace.cs b/ILSpy/Commands/ScopeSearchToNamespace.cs new file mode 100644 index 000000000..b1f194183 --- /dev/null +++ b/ILSpy/Commands/ScopeSearchToNamespace.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2021 Siegfried Pammer +// +// 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 ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Properties; +using ICSharpCode.ILSpy.TreeNodes; + +namespace ICSharpCode.ILSpy +{ + [ExportContextMenuEntry(Header = nameof(Resources.ScopeSearchToThisNamespace), Category = nameof(Resources.Analyze), Order = 9999)] + public class ScopeSearchToNamespace : IContextMenuEntry + { + public void Execute(TextViewContext context) + { + string ns = GetNamespace(context); + string searchTerm = MainWindow.Instance.SearchPane.SearchTerm; + string[] args = NativeMethods.CommandLineToArgumentArray(searchTerm); + bool replaced = false; + for (int i = 0; i < args.Length; i++) + { + if (args[i].StartsWith("innamespace:", StringComparison.OrdinalIgnoreCase)) + { + args[i] = "innamespace:" + ns; + replaced = true; + break; + } + } + if (!replaced) + { + searchTerm += " innamespace:" + ns; + } + else + { + searchTerm = NativeMethods.ArgumentArrayToCommandLine(args); + } + MainWindow.Instance.SearchPane.SearchTerm = searchTerm; + } + + public bool IsEnabled(TextViewContext context) + { + return GetNamespace(context) != null; + } + + public bool IsVisible(TextViewContext context) + { + return GetNamespace(context) != null; + } + + string GetNamespace(TextViewContext context) + { + if (context.Reference?.Reference is IEntity entity) + return entity.Namespace; + if (context.SelectedTreeNodes?.Length != 1) + return null; + switch (context.SelectedTreeNodes[0]) + { + case NamespaceTreeNode tn: + return tn.Name; + case IMemberTreeNode member: + return member.Member.Namespace; + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index 1fdc2e2cf..ffa968765 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -2194,6 +2194,24 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to Scope search to this assembly. + /// + public static string ScopeSearchToThisAssembly { + get { + return ResourceManager.GetString("ScopeSearchToThisAssembly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Scope search to this namespace. + /// + public static string ScopeSearchToThisNamespace { + get { + return ResourceManager.GetString("ScopeSearchToThisNamespace", resourceCulture); + } + } + /// /// Looks up a localized string similar to Search.... /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index b01f6a5ba..81a874de8 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -755,6 +755,12 @@ Do you want to continue? Save Code + + Scope search to this assembly + + + Scope search to this namespace + Search...