@ -20,10 +20,8 @@ using System;
using System.Collections.Concurrent ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.Collections.ObjectModel ;
using System.Collections.Specialized ;
using System.ComponentModel.Composition ;
using System.ComponentModel.Composition ;
using System.Diagnostics ;
using System.Diagnostics ;
using System.Linq ;
using System.Text.RegularExpressions ;
using System.Text.RegularExpressions ;
using System.Threading ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Threading.Tasks ;
@ -34,13 +32,14 @@ using System.Windows.Media;
using System.Windows.Threading ;
using System.Windows.Threading ;
using ICSharpCode.ILSpy.AppEnv ;
using ICSharpCode.ILSpy.AppEnv ;
using ICSharpCode.ILSpy.Docking ;
using ICSharpCode.ILSpy.Util ;
using ICSharpCode.ILSpy.Util ;
using ICSharpCode.ILSpy.ViewModels ;
using ICSharpCode.ILSpy.ViewModels ;
using ICSharpCode.ILSpyX ;
using ICSharpCode.ILSpyX ;
using ICSharpCode.ILSpyX.Extensions ;
using ICSharpCode.ILSpyX.Extensions ;
using ICSharpCode.ILSpyX.Search ;
using ICSharpCode.ILSpyX.Search ;
using TomsToolbox.Essentials ;
using TomsToolbox.Wpf ;
using TomsToolbox.Wpf.Composition.Mef ;
using TomsToolbox.Wpf.Composition.Mef ;
namespace ICSharpCode.ILSpy.Search
namespace ICSharpCode.ILSpy.Search
@ -49,48 +48,31 @@ namespace ICSharpCode.ILSpy.Search
/// Search pane
/// Search pane
/// </summary>
/// </summary>
[DataTemplate(typeof(SearchPaneModel))]
[DataTemplate(typeof(SearchPaneModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export]
public partial class SearchPane
public partial class SearchPane : UserControl
{
{
const int MAX_RESULTS = 1 0 0 0 ;
const int MAX_RESULTS = 1 0 0 0 ;
const int MAX_REFRESH_TIME_MS = 1 0 ; // More means quicker forward of data, less means better responsibility
const int MAX_REFRESH_TIME_MS = 1 0 ; // More means quicker forward of data, fewer means better responsibility
RunningSearch currentSearch ;
RunningSearch currentSearch ;
bool runSearchOnNextShow ;
bool runSearchOnNextShow ;
IComparer < SearchResult > resultsComparer ;
IComparer < SearchResult > resultsComparer ;
public static readonly DependencyProperty ResultsProperty =
public ObservableCollection < SearchResult > Results { get ; } = [ ] ;
DependencyProperty . Register ( "Results" , typeof ( ObservableCollection < SearchResult > ) , typeof ( SearchPane ) ,
new PropertyMetadata ( new ObservableCollection < SearchResult > ( ) ) ) ;
string SearchTerm = > searchBox . Text ;
public ObservableCollection < SearchResult > Results {
get { return ( ObservableCollection < SearchResult > ) GetValue ( ResultsProperty ) ; }
}
public SearchPane ( )
public SearchPane ( )
{
{
InitializeComponent ( ) ;
InitializeComponent ( ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Library , Name = "Types and Members" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Class , Name = "Type" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Property , Name = "Member" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Method , Name = "Method" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Field , Name = "Field" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Property , Name = "Property" } ) ;
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 . Resource , Name = "Resource" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Assembly , Name = "Assembly" } ) ;
searchModeComboBox . Items . Add ( new { Image = Images . Namespace , Name = "Namespace" } ) ;
ContextMenuProvider . Add ( listBox ) ;
ContextMenuProvider . Add ( listBox ) ;
MessageBus < CurrentAssemblyListChangedEventArgs > . Subscribers + = ( sender , e ) = > MainWindow_Instance_ CurrentAssemblyListChanged( sender , e ) ;
MessageBus < CurrentAssemblyListChangedEventArgs > . Subscribers + = ( sender , e ) = > CurrentAssemblyList_Changed ( ) ;
CompositionTarget . Rendering + = UpdateResults ;
MessageBus < LanguageSettingsChangedEventArgs > . Subscribers + = ( sender , e ) = > LanguageSettings_PropertyChanged ( ) ;
// This starts empty search right away, so do at the end (we're still in ctor)
CompositionTarget . Rendering + = UpdateResults ;
searchModeComboBox . SelectedIndex = ( int ) SettingsService . Instance . SessionSettings . SelectedSearchMode ;
}
}
void MainWindow_Instance_ CurrentAssemblyListChanged( object sender , NotifyCollectionChangedEventArgs e )
void CurrentAssemblyList_Changed ( )
{
{
if ( IsVisible )
if ( IsVisible )
{
{
@ -103,7 +85,12 @@ namespace ICSharpCode.ILSpy.Search
}
}
}
}
internal void UpdateFilter ( )
void LanguageSettings_PropertyChanged ( )
{
UpdateFilter ( ) ;
}
void UpdateFilter ( )
{
{
if ( IsVisible )
if ( IsVisible )
{
{
@ -116,43 +103,48 @@ namespace ICSharpCode.ILSpy.Search
}
}
}
}
public void Show ( )
protected override void OnPropertyChanged ( DependencyPropertyChangedEventArgs e )
{
if ( ! IsVisible )
{
{
DockWorkspace . Instance . ToolPanes . Single ( p = > p . ContentId = = SearchPaneModel . PaneContentId ) . IsVisible = true ;
base . OnPropertyChanged ( e ) ;
if ( runSearchOnNextShow )
if ( e . Property = = IsVisibleProperty )
{
{
if ( e . NewValue as bool? ! = true )
return ;
if ( ! runSearchOnNextShow )
return ;
runSearchOnNextShow = false ;
runSearchOnNextShow = false ;
StartSearch ( this . SearchTerm ) ;
StartSearch ( this . SearchTerm ) ;
}
}
else if ( e . Property = = Pane . IsActiveProperty )
{
if ( e . NewValue as bool? ! = true )
return ;
if ( IsMouseOver & & Mouse . LeftButton = = MouseButtonState . Pressed & & ! SearchTerm . IsNullOrEmpty ( ) )
return ;
FocusSearchBox ( ) ;
}
}
Dispatcher . BeginInvoke (
DispatcherPriority . Background ,
new Action (
delegate {
searchBox . Focus ( ) ;
searchBox . SelectAll ( ) ;
} ) ) ;
}
}
public static readonly DependencyProperty SearchTermProperty =
void FocusSearchBox ( )
DependencyProperty . Register ( "SearchTerm" , typeof ( string ) , typeof ( SearchPane ) ,
{
new FrameworkPropertyMetadata ( string . Empty , OnSearchTermChanged ) ) ;
this . BeginInvoke ( DispatcherPriority . Background , ( ) = > {
searchBox . Focus ( ) ;
public string SearchTerm {
searchBox . SelectAll ( ) ;
get { return ( string ) GetValue ( SearchTermProperty ) ; }
} ) ;
set { SetValue ( SearchTermProperty , value ) ; }
}
}
static void OnSearchTermChanged ( DependencyObject o , DependencyProperty ChangedEventArgs e )
void SearchBox_TextChanged ( object sender , Text ChangedEventArgs e )
{
{
( ( SearchPane ) o ) . StartSearch ( ( string ) e . NewValue ) ;
StartSearch ( searchBox . Text ) ;
}
}
void SearchModeComboBox_SelectionChanged ( object sender , SelectionChangedEventArgs e )
void SearchModeComboBox_SelectionChanged ( object sender , SelectionChangedEventArgs e )
{
{
SettingsService . Instance . SessionSettings . SelectedSearchMode = ( SearchMode ) searchModeComboBox . SelectedIndex ;
StartSearch ( this . SearchTerm ) ;
StartSearch ( this . SearchTerm ) ;
}
}
@ -180,32 +172,36 @@ namespace ICSharpCode.ILSpy.Search
protected override void OnKeyDown ( KeyEventArgs e )
protected override void OnKeyDown ( KeyEventArgs e )
{
{
base . OnKeyDown ( e ) ;
base . OnKeyDown ( e ) ;
if ( e . Key = = Key . T & & e . KeyboardDevice . Modifiers = = ModifierKeys . Control )
if ( e . KeyboardDevice . Modifiers ! = ModifierKeys . Control )
return ;
switch ( e . Key )
{
{
searchModeComboBox . SelectedIndex = ( int ) SearchMode . Type ;
case Key . T :
searchModeComboBox . SelectedValue = SearchMode . Type ;
e . Handled = true ;
e . Handled = true ;
}
break ;
else if ( e . Key = = Key . M & & e . KeyboardDevice . Modifiers = = ModifierKeys . Control )
case Key . M :
{
searchModeComboBox . SelectedValue = SearchMode . Member ;
searchModeComboBox . SelectedIndex = ( int ) SearchMode . Member ;
e . Handled = true ;
e . Handled = true ;
}
break ;
else if ( e . Key = = Key . S & & e . KeyboardDevice . Modifiers = = ModifierKeys . Control )
case Key . S :
{
searchModeComboBox . SelectedValue = SearchMode . Literal ;
searchModeComboBox . SelectedIndex = ( int ) SearchMode . Literal ;
e . Handled = true ;
e . Handled = true ;
break ;
}
}
}
}
void SearchBox_PreviewKeyDown ( object sender , KeyEventArgs e )
void SearchBox_PreviewKeyDown ( object sender , KeyEventArgs e )
{
{
if ( e . Key = = Key . Down & & listBox . HasItems )
if ( e . Key ! = Key . Down | | ! listBox . HasItems )
{
return ;
e . Handled = true ;
e . Handled = true ;
listBox . MoveFocus ( new TraversalRequest ( FocusNavigationDirection . First ) ) ;
listBox . MoveFocus ( new ( FocusNavigationDirection . First ) ) ;
listBox . SelectedIndex = 0 ;
listBox . SelectedIndex = 0 ;
}
}
}
void UpdateResults ( object sender , EventArgs e )
void UpdateResults ( object sender , EventArgs e )
{
{
@ -220,9 +216,10 @@ namespace ICSharpCode.ILSpy.Search
+ + resultsAdded ;
+ + resultsAdded ;
}
}
if ( resultsAdded > 0 & & Results . Count = = MAX_RESULTS )
if ( resultsAdded < = 0 | | Results . Count ! = MAX_RESULTS )
{
return ;
Results . Add ( new SearchResult {
Results . Add ( new ( ) {
Name = Properties . Resources . SearchAbortedMoreThan1000ResultsFound ,
Name = Properties . Resources . SearchAbortedMoreThan1000ResultsFound ,
Location = null ! ,
Location = null ! ,
Assembly = null ! ,
Assembly = null ! ,
@ -230,9 +227,9 @@ namespace ICSharpCode.ILSpy.Search
LocationImage = null ! ,
LocationImage = null ! ,
AssemblyImage = null ! ,
AssemblyImage = null ! ,
} ) ;
} ) ;
currentSearch . Cancel ( ) ;
currentSearch . Cancel ( ) ;
}
}
}
async void StartSearch ( string searchTerm )
async void StartSearch ( string searchTerm )
{
{
@ -253,7 +250,7 @@ namespace ICSharpCode.ILSpy.Search
{
{
searchProgressBar . IsIndeterminate = true ;
searchProgressBar . IsIndeterminate = true ;
startedSearch = new RunningSearch ( await mainWindow . CurrentAssemblyList . GetAllAssemblies ( ) , searchTerm ,
startedSearch = new ( await mainWindow . CurrentAssemblyList . GetAllAssemblies ( ) , searchTerm ,
( SearchMode ) searchModeComboBox . SelectedIndex , mainWindow . CurrentLanguage ,
( SearchMode ) searchModeComboBox . SelectedIndex , mainWindow . CurrentLanguage ,
SettingsService . Instance . SessionSettings . LanguageSettings . ShowApiLevel ) ;
SettingsService . Instance . SessionSettings . LanguageSettings . ShowApiLevel ) ;
currentSearch = startedSearch ;
currentSearch = startedSearch ;
@ -262,7 +259,8 @@ namespace ICSharpCode.ILSpy.Search
}
}
if ( currentSearch = = startedSearch )
if ( currentSearch = = startedSearch )
{ //are we still running the same search
{
//are we still running the same search
searchProgressBar . IsIndeterminate = false ;
searchProgressBar . IsIndeterminate = false ;
}
}
}
}
@ -277,7 +275,7 @@ namespace ICSharpCode.ILSpy.Search
sealed class RunningSearch
sealed class RunningSearch
{
{
readonly CancellationTokenSource cts = new CancellationTokenSource ( ) ;
readonly CancellationTokenSource cts = new ( ) ;
readonly IList < LoadedAssembly > assemblies ;
readonly IList < LoadedAssembly > assemblies ;
readonly SearchRequest searchRequest ;
readonly SearchRequest searchRequest ;
readonly SearchMode searchMode ;
readonly SearchMode searchMode ;
@ -299,8 +297,8 @@ namespace ICSharpCode.ILSpy.Search
{
{
string [ ] parts = CommandLineTools . CommandLineToArgumentArray ( input ) ;
string [ ] parts = CommandLineTools . CommandLineToArgumentArray ( input ) ;
SearchRequest request = new SearchRequest ( ) ;
SearchRequest request = new ( ) ;
List < string > keywords = new List < string > ( ) ;
List < string > keywords = new ( ) ;
Regex regex = null ;
Regex regex = null ;
request . Mode = searchMode ;
request . Mode = searchMode ;
@ -350,7 +348,6 @@ namespace ICSharpCode.ILSpy.Search
// then we do not interpret it as prefix, but as searchTerm.
// then we do not interpret it as prefix, but as searchTerm.
searchTerm = part ;
searchTerm = part ;
prefix = null ;
prefix = null ;
prefixLength = - 1 ;
}
}
if ( prefix = = null | | prefix . Length < = 2 )
if ( prefix = = null | | prefix . Length < = 2 )
@ -442,7 +439,7 @@ namespace ICSharpCode.ILSpy.Search
{
{
try
try
{
{
return new Regex ( s , RegexOptions . Compiled ) ;
return new ( s , RegexOptions . Compiled ) ;
}
}
catch ( ArgumentException )
catch ( ArgumentException )
{
{
@ -540,9 +537,11 @@ namespace ICSharpCode.ILSpy.Search
public ShowSearchCommand ( )
public ShowSearchCommand ( )
: base ( NavigationCommands . Search )
: base ( NavigationCommands . Search )
{
{
NavigationCommands . Search . InputGestures . Clear ( ) ;
var gestures = NavigationCommands . Search . InputGestures ;
NavigationCommands . Search . InputGestures . Add ( new KeyGesture ( Key . F , ModifierKeys . Control | ModifierKeys . Shift ) ) ;
NavigationCommands . Search . InputGestures . Add ( new KeyGesture ( Key . E , ModifierKeys . Control ) ) ;
gestures . Clear ( ) ;
gestures . Add ( new KeyGesture ( Key . F , ModifierKeys . Control | ModifierKeys . Shift ) ) ;
gestures . Add ( new KeyGesture ( Key . E , ModifierKeys . Control ) ) ;
}
}
}
}
}
}