diff --git a/ILSpy/Options/DisplaySettings.cs b/ILSpy/Options/DisplaySettings.cs index 0ecd46676..3ab05f5f5 100644 --- a/ILSpy/Options/DisplaySettings.cs +++ b/ILSpy/Options/DisplaySettings.cs @@ -107,5 +107,30 @@ namespace ICSharpCode.ILSpy.Options } } } + + bool sortResults; + + public bool SortResults + { + get { return sortResults; } + set + { + if (sortResults != value) + { + sortResults = value; + OnPropertyChanged(); + } + } + } + + public void CopyValues(DisplaySettings s) + { + this.SelectedFont = s.selectedFont; + this.SelectedFontSize = s.selectedFontSize; + this.ShowLineNumbers = s.showLineNumbers; + this.ShowMetadataTokens = s.showMetadataTokens; + this.EnableWordWrap = s.enableWordWrap; + this.SortResults = s.sortResults; + } } } diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml b/ILSpy/Options/DisplaySettingsPanel.xaml index d14bb0dd7..5a56bafbd 100644 --- a/ILSpy/Options/DisplaySettingsPanel.xaml +++ b/ILSpy/Options/DisplaySettingsPanel.xaml @@ -62,6 +62,7 @@ <CheckBox IsChecked="{Binding ShowLineNumbers}">Show line numbers</CheckBox> <CheckBox IsChecked="{Binding ShowMetadataTokens}">Show metadata tokens</CheckBox> <CheckBox IsChecked="{Binding EnableWordWrap}">Enable word wrap</CheckBox> + <CheckBox IsChecked="{Binding SortResults}">Sort results by fitness</CheckBox> </StackPanel> </GroupBox> </Grid> diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml.cs b/ILSpy/Options/DisplaySettingsPanel.xaml.cs index cce85daa7..ab07113ff 100644 --- a/ILSpy/Options/DisplaySettingsPanel.xaml.cs +++ b/ILSpy/Options/DisplaySettingsPanel.xaml.cs @@ -102,6 +102,7 @@ namespace ICSharpCode.ILSpy.Options s.ShowLineNumbers = (bool?)e.Attribute("ShowLineNumbers") ?? false; s.ShowMetadataTokens = (bool?) e.Attribute("ShowMetadataTokens") ?? false; s.EnableWordWrap = (bool?)e.Attribute("EnableWordWrap") ?? false; + s.SortResults = (bool?)e.Attribute("SortResults") ?? false; return s; } @@ -116,6 +117,7 @@ namespace ICSharpCode.ILSpy.Options section.SetAttributeValue("ShowLineNumbers", s.ShowLineNumbers); section.SetAttributeValue("ShowMetadataTokens", s.ShowMetadataTokens); section.SetAttributeValue("EnableWordWrap", s.EnableWordWrap); + section.SetAttributeValue("SortResults", s.SortResults); XElement existingElement = root.Element("DisplaySettings"); if (existingElement != null) diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs index 658400281..c7218697b 100644 --- a/ILSpy/SearchPane.cs +++ b/ILSpy/SearchPane.cs @@ -249,8 +249,26 @@ namespace ICSharpCode.ILSpy void InsertResult(ObservableCollection<SearchResult> results, SearchResult result) { - int index = results.BinarySearch(result, 0, results.Count - 1, SearchResult.Comparer); - results.Insert(index < 0 ? ~index : index, result); + if (Options.DisplaySettingsPanel.CurrentDisplaySettings.SortResults) + { + // Keep results collection sorted by "Fitness" by inserting result into correct place + // Inserts in the beginning shifts all elements, but there can be no more than 1000 items. + for (int i = 0; i < results.Count; i++) + { + if (results[i].Fitness < result.Fitness) + { + results.Insert(i, result); + return; + } + } + results.Insert(results.Count - 1, result); + } + else + { + // Original Code + int index = results.BinarySearch(result, 0, results.Count - 1, SearchResult.Comparer); + results.Insert(index < 0 ? ~index : index, result); + } } AbstractSearchStrategy GetSearchStrategy(SearchMode mode, string[] terms) @@ -316,6 +334,7 @@ namespace ICSharpCode.ILSpy public static readonly System.Collections.Generic.IComparer<SearchResult> Comparer = new SearchResultComparer(); public MemberReference Member { get; set; } + public float Fitness { get; set; } public string Location { get; set; } public string Name { get; set; } diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index 2f1f1ff69..a339b346b 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -36,6 +36,29 @@ namespace ICSharpCode.ILSpy searchTerm = terms; } + protected float CalculateFitness(MemberReference member, string text) + { + // Probably compiler generated types without meaningful names, show them last + if (text.StartsWith("<")) + { + return 0; + } + + // Ignore generic arguments, it not possible to search based on them either + int length = 0; + int generics = 0; + for (int i = 0; i < text.Length; i++) + { + if (text[i] == '<') + generics++; + else if (text[i] == '>') + generics--; + else if (generics == 0) + length++; + } + return 1.0f / length; + } + protected virtual bool IsMatch(FieldDefinition field, Language language) { return false; @@ -124,6 +147,7 @@ namespace ICSharpCode.ILSpy addResult(new SearchResult { Member = item, + Fitness = CalculateFitness(item, item.Name), Image = image(item), Name = GetLanguageSpecificName(language, (IMemberDefinition)item), LocationImage = TypeTreeNode.GetIcon(type), @@ -392,10 +416,12 @@ namespace ICSharpCode.ILSpy public override void Search(TypeDefinition type, Language language, Action<SearchResult> addResult) { if (MatchName(type, language)) { + string name = language.TypeToString(type, includeNamespace: false); addResult(new SearchResult { Member = type, + Fitness = CalculateFitness(type, name), Image = TypeTreeNode.GetIcon(type), - Name = language.TypeToString(type, includeNamespace: false), + Name = name, LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace }); @@ -418,11 +444,13 @@ namespace ICSharpCode.ILSpy { if (MatchName(type, language)) { + string name = language.TypeToString(type, includeNamespace: false); addResult(new SearchResult { Member = type, Image = TypeTreeNode.GetIcon(type), - Name = language.TypeToString(type, includeNamespace: false), + Fitness = CalculateFitness(type, name), + Name = name, LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace });