|
|
@ -61,9 +61,15 @@ namespace ICSharpCode.ILSpy |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const int SearchMode_Type = 0; |
|
|
|
|
|
|
|
const int SearchMode_Member = 1; |
|
|
|
|
|
|
|
|
|
|
|
private SearchPane() |
|
|
|
private SearchPane() |
|
|
|
{ |
|
|
|
{ |
|
|
|
InitializeComponent(); |
|
|
|
InitializeComponent(); |
|
|
|
|
|
|
|
searchModeComboBox.Items.Add(new { Image = Images.Class, Name = "Type" }); |
|
|
|
|
|
|
|
searchModeComboBox.Items.Add(new { Image = Images.Property, Name = "Member" }); |
|
|
|
|
|
|
|
searchModeComboBox.SelectedIndex = SearchMode_Type; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void Show() |
|
|
|
public void Show() |
|
|
@ -89,6 +95,11 @@ namespace ICSharpCode.ILSpy |
|
|
|
((SearchPane)o).StartSearch((string)e.NewValue); |
|
|
|
((SearchPane)o).StartSearch((string)e.NewValue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SearchModeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
StartSearch(this.SearchTerm); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void StartSearch(string searchTerm) |
|
|
|
void StartSearch(string searchTerm) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (currentSearch != null) { |
|
|
|
if (currentSearch != null) { |
|
|
@ -99,7 +110,7 @@ namespace ICSharpCode.ILSpy |
|
|
|
listBox.ItemsSource = null; |
|
|
|
listBox.ItemsSource = null; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
MainWindow mainWindow = MainWindow.Instance; |
|
|
|
MainWindow mainWindow = MainWindow.Instance; |
|
|
|
currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, mainWindow.CurrentLanguage); |
|
|
|
currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, searchModeComboBox.SelectedIndex, mainWindow.CurrentLanguage); |
|
|
|
listBox.ItemsSource = currentSearch.Results; |
|
|
|
listBox.ItemsSource = currentSearch.Results; |
|
|
|
new Thread(currentSearch.Run).Start(); |
|
|
|
new Thread(currentSearch.Run).Start(); |
|
|
|
} |
|
|
|
} |
|
|
@ -118,7 +129,7 @@ namespace ICSharpCode.ILSpy |
|
|
|
|
|
|
|
|
|
|
|
void ListBox_KeyDown(object sender, KeyEventArgs e) |
|
|
|
void ListBox_KeyDown(object sender, KeyEventArgs e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (e.Key == Key.Space || e.Key == Key.Return) { |
|
|
|
if (e.Key == Key.Return) { |
|
|
|
e.Handled = true; |
|
|
|
e.Handled = true; |
|
|
|
JumpToSelectedItem(); |
|
|
|
JumpToSelectedItem(); |
|
|
|
} |
|
|
|
} |
|
|
@ -131,158 +142,191 @@ namespace ICSharpCode.ILSpy |
|
|
|
MainWindow.Instance.JumpToReference(result.Member); |
|
|
|
MainWindow.Instance.JumpToReference(result.Member); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sealed class RunningSearch |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
readonly Dispatcher dispatcher; |
|
|
|
|
|
|
|
readonly CancellationTokenSource cts = new CancellationTokenSource(); |
|
|
|
|
|
|
|
readonly LoadedAssembly[] assemblies; |
|
|
|
|
|
|
|
readonly string searchTerm; |
|
|
|
|
|
|
|
readonly Language language; |
|
|
|
|
|
|
|
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>(); |
|
|
|
|
|
|
|
int resultCount; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, Language language) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this.dispatcher = Dispatcher.CurrentDispatcher; |
|
|
|
|
|
|
|
this.assemblies = assemblies; |
|
|
|
|
|
|
|
this.searchTerm = searchTerm; |
|
|
|
|
|
|
|
this.language = language; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Cancel() |
|
|
|
protected override void OnKeyDown(KeyEventArgs e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
cts.Cancel(); |
|
|
|
base.OnKeyDown(e); |
|
|
|
} |
|
|
|
if (e.Key == Key.T && e.KeyboardDevice.Modifiers == ModifierKeys.Control) { |
|
|
|
|
|
|
|
searchModeComboBox.SelectedIndex = SearchMode_Type; |
|
|
|
public void Run() |
|
|
|
e.Handled = true; |
|
|
|
{ |
|
|
|
} else if (e.Key == Key.M && e.KeyboardDevice.Modifiers == ModifierKeys.Control) { |
|
|
|
try { |
|
|
|
searchModeComboBox.SelectedIndex = SearchMode_Member; |
|
|
|
foreach (var loadedAssembly in assemblies) { |
|
|
|
e.Handled = true; |
|
|
|
AssemblyDefinition asm = loadedAssembly.AssemblyDefinition; |
|
|
|
|
|
|
|
if (asm == null) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
CancellationToken cancellationToken = cts.Token; |
|
|
|
|
|
|
|
foreach (TypeDefinition type in asm.MainModule.Types) { |
|
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
|
|
|
|
PerformSearch(type); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (OperationCanceledException) { |
|
|
|
|
|
|
|
// ignore cancellation
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AddResult(SearchResult result) |
|
|
|
void SearchBox_PreviewKeyDown(object sender, KeyEventArgs e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (++resultCount == 1000) { |
|
|
|
if (e.Key == Key.Down && listBox.HasItems) { |
|
|
|
result = new SearchResult { Name = "Search aborted, more than 1000 results found." }; |
|
|
|
e.Handled = true; |
|
|
|
cts.Cancel(); |
|
|
|
listBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); |
|
|
|
|
|
|
|
listBox.SelectedIndex = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
dispatcher.BeginInvoke( |
|
|
|
|
|
|
|
DispatcherPriority.Normal, |
|
|
|
|
|
|
|
new Action(delegate { this.Results.Add(result); })); |
|
|
|
|
|
|
|
cts.Token.ThrowIfCancellationRequested(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IsMatch(string text) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void PerformSearch(TypeDefinition type) |
|
|
|
sealed class RunningSearch |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (IsMatch(type.Name)) { |
|
|
|
readonly Dispatcher dispatcher; |
|
|
|
AddResult(new SearchResult { |
|
|
|
readonly CancellationTokenSource cts = new CancellationTokenSource(); |
|
|
|
Member = type, |
|
|
|
readonly LoadedAssembly[] assemblies; |
|
|
|
Image = TypeTreeNode.GetIcon(type), |
|
|
|
readonly string searchTerm; |
|
|
|
Name = language.TypeToString(type, includeNamespace: false), |
|
|
|
readonly int searchMode; |
|
|
|
LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, |
|
|
|
readonly Language language; |
|
|
|
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace |
|
|
|
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>(); |
|
|
|
}); |
|
|
|
int resultCount; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, int searchMode, Language language) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this.dispatcher = Dispatcher.CurrentDispatcher; |
|
|
|
|
|
|
|
this.assemblies = assemblies; |
|
|
|
|
|
|
|
this.searchTerm = searchTerm; |
|
|
|
|
|
|
|
this.language = language; |
|
|
|
|
|
|
|
this.searchMode = searchMode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.Results.Add(new SearchResult { Name = "Searching..." }); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
foreach (TypeDefinition nestedType in type.NestedTypes) { |
|
|
|
public void Cancel() |
|
|
|
PerformSearch(nestedType); |
|
|
|
{ |
|
|
|
|
|
|
|
cts.Cancel(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
foreach (FieldDefinition field in type.Fields) { |
|
|
|
public void Run() |
|
|
|
if (IsMatch(field.Name)) { |
|
|
|
{ |
|
|
|
AddResult(new SearchResult { |
|
|
|
try { |
|
|
|
Member = field, |
|
|
|
foreach (var loadedAssembly in assemblies) { |
|
|
|
Image = FieldTreeNode.GetIcon(field), |
|
|
|
AssemblyDefinition asm = loadedAssembly.AssemblyDefinition; |
|
|
|
Name = field.Name, |
|
|
|
if (asm == null) |
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
continue; |
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
CancellationToken cancellationToken = cts.Token; |
|
|
|
}); |
|
|
|
foreach (TypeDefinition type in asm.MainModule.Types) { |
|
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
|
|
|
|
PerformSearch(type); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (OperationCanceledException) { |
|
|
|
|
|
|
|
// ignore cancellation
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// remove the 'Searching...' entry
|
|
|
|
|
|
|
|
dispatcher.BeginInvoke( |
|
|
|
|
|
|
|
DispatcherPriority.Normal, |
|
|
|
|
|
|
|
new Action(delegate { this.Results.RemoveAt(this.Results.Count - 1); })); |
|
|
|
} |
|
|
|
} |
|
|
|
foreach (PropertyDefinition property in type.Properties) { |
|
|
|
|
|
|
|
if (IsMatch(property.Name)) { |
|
|
|
void AddResult(SearchResult result) |
|
|
|
AddResult(new SearchResult { |
|
|
|
{ |
|
|
|
Member = property, |
|
|
|
if (++resultCount == 1000) { |
|
|
|
Image = PropertyTreeNode.GetIcon(property), |
|
|
|
result = new SearchResult { Name = "Search aborted, more than 1000 results found." }; |
|
|
|
Name = property.Name, |
|
|
|
cts.Cancel(); |
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
|
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
dispatcher.BeginInvoke( |
|
|
|
|
|
|
|
DispatcherPriority.Normal, |
|
|
|
|
|
|
|
new Action(delegate { this.Results.Insert(this.Results.Count - 1, result); })); |
|
|
|
|
|
|
|
cts.Token.ThrowIfCancellationRequested(); |
|
|
|
} |
|
|
|
} |
|
|
|
foreach (EventDefinition ev in type.Events) { |
|
|
|
|
|
|
|
if (IsMatch(ev.Name)) { |
|
|
|
bool IsMatch(string text) |
|
|
|
AddResult(new SearchResult { |
|
|
|
{ |
|
|
|
Member = ev, |
|
|
|
if (text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0) |
|
|
|
Image = EventTreeNode.GetIcon(ev), |
|
|
|
return true; |
|
|
|
Name = ev.Name, |
|
|
|
else |
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
return false; |
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
foreach (MethodDefinition method in type.Methods) { |
|
|
|
|
|
|
|
if (IsMatch(method.Name)) { |
|
|
|
void PerformSearch(TypeDefinition type) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (searchMode == SearchMode_Type && IsMatch(type.Name)) { |
|
|
|
AddResult(new SearchResult { |
|
|
|
AddResult(new SearchResult { |
|
|
|
Member = method, |
|
|
|
Member = type, |
|
|
|
Image = MethodTreeNode.GetIcon(method), |
|
|
|
Image = TypeTreeNode.GetIcon(type), |
|
|
|
Name = method.Name, |
|
|
|
Name = language.TypeToString(type, includeNamespace: false), |
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace, |
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (TypeDefinition nestedType in type.NestedTypes) { |
|
|
|
|
|
|
|
PerformSearch(nestedType); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (searchMode == SearchMode_Type) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (FieldDefinition field in type.Fields) { |
|
|
|
|
|
|
|
if (IsMatch(field.Name)) { |
|
|
|
|
|
|
|
AddResult(new SearchResult { |
|
|
|
|
|
|
|
Member = field, |
|
|
|
|
|
|
|
Image = FieldTreeNode.GetIcon(field), |
|
|
|
|
|
|
|
Name = field.Name, |
|
|
|
|
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
|
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
foreach (PropertyDefinition property in type.Properties) { |
|
|
|
|
|
|
|
if (IsMatch(property.Name)) { |
|
|
|
|
|
|
|
AddResult(new SearchResult { |
|
|
|
|
|
|
|
Member = property, |
|
|
|
|
|
|
|
Image = PropertyTreeNode.GetIcon(property), |
|
|
|
|
|
|
|
Name = property.Name, |
|
|
|
|
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
|
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
foreach (EventDefinition ev in type.Events) { |
|
|
|
|
|
|
|
if (IsMatch(ev.Name)) { |
|
|
|
|
|
|
|
AddResult(new SearchResult { |
|
|
|
|
|
|
|
Member = ev, |
|
|
|
|
|
|
|
Image = EventTreeNode.GetIcon(ev), |
|
|
|
|
|
|
|
Name = ev.Name, |
|
|
|
|
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
|
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
foreach (MethodDefinition method in type.Methods) { |
|
|
|
|
|
|
|
if (IsMatch(method.Name)) { |
|
|
|
|
|
|
|
AddResult(new SearchResult { |
|
|
|
|
|
|
|
Member = method, |
|
|
|
|
|
|
|
Image = MethodTreeNode.GetIcon(method), |
|
|
|
|
|
|
|
Name = method.Name, |
|
|
|
|
|
|
|
LocationImage = TypeTreeNode.GetIcon(type), |
|
|
|
|
|
|
|
Location = language.TypeToString(type, includeNamespace: true) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SearchResult : INotifyPropertyChanged |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { |
|
|
|
|
|
|
|
add { } |
|
|
|
|
|
|
|
remove { } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public MemberReference Member { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public string Location { get; set; } |
|
|
|
sealed class SearchResult : INotifyPropertyChanged, IMemberTreeNode |
|
|
|
public string Name { get; set; } |
|
|
|
|
|
|
|
public ImageSource Image { get; set; } |
|
|
|
|
|
|
|
public ImageSource LocationImage { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public override string ToString() |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
return Name; |
|
|
|
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { |
|
|
|
|
|
|
|
add { } |
|
|
|
|
|
|
|
remove { } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public MemberReference Member { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public string Location { get; set; } |
|
|
|
|
|
|
|
public string Name { get; set; } |
|
|
|
|
|
|
|
public ImageSource Image { get; set; } |
|
|
|
|
|
|
|
public ImageSource LocationImage { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public override string ToString() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return Name; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)] |
|
|
|
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)] |
|
|
|
sealed class ShowSearchCommand : SimpleCommand |
|
|
|
[ExportToolbarCommand(ToolTip = "Search (F3)", ToolbarIcon = "Images/Find.png", ToolbarCategory = "View", ToolbarOrder = 100)] |
|
|
|
|
|
|
|
sealed class ShowSearchCommand : CommandWrapper |
|
|
|
{ |
|
|
|
{ |
|
|
|
public override void Execute(object parameter) |
|
|
|
public ShowSearchCommand() |
|
|
|
|
|
|
|
: base(NavigationCommands.Search) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SearchPane.Instance.Show(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |