Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 9ea9c90

Browse files
committed
add "sugar-free search"
1 parent acc00c5 commit 9ea9c90

File tree

12 files changed

+403
-1
lines changed

12 files changed

+403
-1
lines changed

dnSpy.Extension.Cpp2IL/References/Cpp2ILReference.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
using Cpp2IL.Core.Model.Contexts;
22
using Cpp2ILAdapter.PseudoC;
3+
using Cpp2ILAdapter.TreeView;
34
using LibCpp2IL;
45
using LibCpp2IL.BinaryStructures;
56
using LibCpp2IL.Metadata;
67

78
namespace Cpp2ILAdapter.References;
89

910
public abstract record Cpp2ILReference;
11+
12+
public sealed record Cpp2ILDirectReference(TypeNode Node) : Cpp2ILReference;
1013
public sealed record Cpp2ILTypeReference(Il2CppType? Type) : Cpp2ILReference;
1114
public sealed record Cpp2ILTypeDefReference(Il2CppTypeDefinition? Type) : Cpp2ILReference;
1215
public sealed record Cpp2ILMethodReference(MethodAnalysisContext Method) : Cpp2ILReference;

dnSpy.Extension.Cpp2IL/References/Cpp2ILTreeNodeDataFinder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ sealed class Cpp2ILTreeNodeDataFinder : IDocumentTreeNodeDataFinder
2828

2929
switch (@ref)
3030
{
31+
case Cpp2ILDirectReference directReference:
32+
{
33+
return directReference.Node;
34+
}
3135
case Cpp2ILTypeDefReference typeDefReference:
3236
{
3337
if (typeDefReference.Type == null)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System.ComponentModel.Composition;
2+
using System.Windows;
3+
using System.Windows.Input;
4+
using Cpp2IL.Core;
5+
using dnSpy.Contracts.Controls;
6+
using dnSpy.Contracts.Documents.Tabs;
7+
using dnSpy.Contracts.Extension;
8+
using dnSpy.Contracts.Images;
9+
using dnSpy.Contracts.ToolBars;
10+
using dnSpy.Contracts.ToolWindows;
11+
using dnSpy.Contracts.ToolWindows.App;
12+
13+
namespace Cpp2ILAdapter.Search;
14+
15+
[ExportToolBarButton(Header = "IL2Cpp Search", Icon = DsImagesAttribute.Search, Group = "10000,FEFB775B-7999-4A48-BE1C-C4314D00971F", Order = 0)]
16+
sealed class CreateSearchWindow : ToolBarButtonCommand
17+
{
18+
public CreateSearchWindow() : base(CreateSearchWindowCommand.SearchRoutedCommand)
19+
{
20+
}
21+
22+
//public override bool IsVisible(IToolBarItemContext context) => true;
23+
}
24+
25+
[ExportAutoLoaded]
26+
sealed class CreateSearchWindowCommand : IAutoLoaded
27+
{
28+
public static readonly RoutedCommand SearchRoutedCommand;
29+
public static IDocumentTabService SharedDocumentTabService = null!;
30+
31+
static CreateSearchWindowCommand() {
32+
SearchRoutedCommand = new RoutedCommand("CreateSearchWindowCommand", typeof(CreateSearchWindowCommand));
33+
SearchRoutedCommand.InputGestures.Add(new KeyGesture(Key.K, ModifierKeys.Control | ModifierKeys.Shift));
34+
}
35+
36+
readonly IDsToolWindowService toolWindowService;
37+
38+
[ImportingConstructor]
39+
CreateSearchWindowCommand(IDsToolWindowService toolWindowService, IWpfCommandService wpfCommandService, IDocumentTabService documentTabService) {
40+
this.toolWindowService = toolWindowService;
41+
SharedDocumentTabService = documentTabService;
42+
43+
var cmds = wpfCommandService.GetCommands(ControlConstants.GUID_MAINWINDOW);
44+
cmds.Add(SearchRoutedCommand, Search, CanSearch);
45+
}
46+
47+
void CanSearch(object? sender, CanExecuteRoutedEventArgs e) => e.CanExecute = true;
48+
49+
void Search(object? sender, ExecutedRoutedEventArgs e) => toolWindowService.Show(SearchWindowTool.THE_GUID);
50+
}
51+
52+
[Export(typeof(IToolWindowContentProvider))]
53+
sealed class SearchWindowToolContentProvider : IToolWindowContentProvider {
54+
SearchWindowTool SearchToolWindowContent => searchToolWindowContent ??= new SearchWindowTool();
55+
SearchWindowTool? searchToolWindowContent;
56+
57+
public IEnumerable<ToolWindowContentInfo> ContentInfos {
58+
get { yield return new ToolWindowContentInfo(SearchWindowTool.THE_GUID, SearchWindowTool.DEFAULT_LOCATION, AppToolWindowConstants.DEFAULT_CONTENT_ORDER_TOP_SEARCH, false); }
59+
}
60+
61+
public ToolWindowContent? GetOrCreate(Guid guid) {
62+
if (guid == SearchWindowTool.THE_GUID)
63+
return SearchToolWindowContent;
64+
return null;
65+
}
66+
}
67+
68+
internal sealed class SearchWindowTool : ToolWindowContent, IFocusable
69+
{
70+
public static readonly Guid THE_GUID = new("589eb17e-e4f0-4fde-ac2e-3679e7c26cb3");
71+
public const AppToolWindowLocation DEFAULT_LOCATION = AppToolWindowLocation.DefaultHorizontal;
72+
73+
public SearchWindowTool()
74+
{
75+
_control = new SearchControl();
76+
_controlVm = new SearchControlVM(_control);
77+
_control.DataContext = _controlVm;
78+
}
79+
80+
private readonly SearchControl _control;
81+
private readonly SearchControlVM _controlVm;
82+
public override object? UIObject => _control;
83+
public override IInputElement? FocusedElement => _control.searchTextBox;
84+
public override FrameworkElement? ZoomElement => _control;
85+
public override Guid Guid => THE_GUID;
86+
public override string Title => "Il2Cpp Search";
87+
public bool CanFocus => true;
88+
public void Focus() => _control.Focus();
89+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<UserControl x:Class="Cpp2ILAdapter.Search.SearchControl"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:local="clr-namespace:Cpp2ILAdapter.Search"
7+
xmlns:mvvm="clr-namespace:dnSpy.Contracts.MVVM;assembly=dnSpy.Contracts.DnSpy"
8+
xmlns:images="clr-namespace:dnSpy.Contracts.Images;assembly=dnSpy.Contracts.DnSpy">
9+
<UserControl.Resources>
10+
<DataTemplate DataType="{x:Type local:SearchTypeVM}">
11+
<Grid ToolTip="{Binding ToolTip}" Background="Transparent">
12+
<Grid.ColumnDefinitions>
13+
<ColumnDefinition Width="Auto" />
14+
<ColumnDefinition Width="*" />
15+
</Grid.ColumnDefinitions>
16+
<images:DsImage Grid.Column="0" Margin="0 0 4 0" ImageReference="{Binding Image}" />
17+
<TextBlock Grid.Column="1" Text="{Binding Name}" HorizontalAlignment="Stretch" />
18+
</Grid>
19+
</DataTemplate>
20+
</UserControl.Resources>
21+
<Grid>
22+
<Grid.RowDefinitions>
23+
<RowDefinition Height="Auto" />
24+
<RowDefinition Height="*" />
25+
</Grid.RowDefinitions>
26+
<Grid Grid.Row="0">
27+
<Grid.ColumnDefinitions>
28+
<ColumnDefinition Width="*" />
29+
<ColumnDefinition Width="Auto" />
30+
<ColumnDefinition Width="Auto" />
31+
<ColumnDefinition Width="Auto" />
32+
<ColumnDefinition Width="Auto" />
33+
</Grid.ColumnDefinitions>
34+
<Grid.RowDefinitions>
35+
<RowDefinition Height="Auto" />
36+
<RowDefinition Height="Auto" />
37+
</Grid.RowDefinitions>
38+
<TextBox Grid.Row="0" Grid.Column="0" Name="searchTextBox" VerticalAlignment="Stretch" Margin="0 0 5 0" Text="{Binding SearchText, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}" />
39+
<Expander Grid.Row="0" Grid.Column="1" Name="Expander" VerticalContentAlignment="Center" IsExpanded="False" Header="Options" />
40+
<Label Grid.Row="0" Grid.Column="2" VerticalContentAlignment="Center" Content="Search For"/>
41+
<ComboBox Grid.Row="0" Grid.Column="3" Width="130" Margin="1 1 0 1" ItemsSource="{Binding SearchTypeVMs}" SelectedItem="{Binding SelectedSearchTypeVM}" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" images:DsImage.BackgroundBrush="{Binding Background, RelativeSource={RelativeSource Self}}" />
42+
<WrapPanel Grid.Row="1" Grid.ColumnSpan="5" Margin="2 0 2 2" Orientation="Horizontal" Visibility="{Binding IsExpanded, ElementName=Expander, Converter={StaticResource BooleanToVisibilityConverter}}">
43+
<CheckBox Margin="0 5 5 0" Content="Match Whole Words" IsChecked="{Binding SearchSettings.MatchWholeWords}" />
44+
<CheckBox Margin="0 5 5 0" Content="Case Sensitive Search" IsChecked="{Binding SearchSettings.CaseSensitive}" />
45+
<CheckBox Margin="0 5 5 0" Content="Match Any" IsChecked="{Binding SearchSettings.MatchAnySearchTerm}" />
46+
<CheckBox Margin="0 5 5 0" Content="Search Compiler Generated Members" IsChecked="{Binding SearchSettings.SearchCompilerGeneratedMembers}" />
47+
</WrapPanel>
48+
</Grid>
49+
<ListBox Grid.Row="1"
50+
Name="searchListBox"
51+
SelectionMode="Single"
52+
VirtualizingStackPanel.IsVirtualizing="True"
53+
VirtualizingStackPanel.VirtualizationMode="Standard"
54+
mvvm:AutomationPeerMemoryLeakWorkaround.Initialize="True"
55+
BorderBrush="{DynamicResource CommonControlsTextBoxBorderError}"
56+
images:DsImage.BackgroundBrush="{Binding Background, RelativeSource={RelativeSource Self}}"
57+
HorizontalContentAlignment="Stretch"
58+
MouseDoubleClick="searchListBox_MouseDoubleClick"
59+
ItemsSource="{Binding SearchResultsCollectionView}"
60+
SelectedItem="{Binding SelectedSearchResult}"
61+
DisplayMemberPath="DisplayName"/>
62+
</Grid>
63+
</UserControl>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Windows.Controls;
2+
using System.Windows.Input;
3+
using dnSpy.Contracts.Utilities;
4+
5+
namespace Cpp2ILAdapter.Search;
6+
7+
public partial class SearchControl : UserControl
8+
{
9+
public TextBox SearchTextBox => searchTextBox;
10+
public ListBox ListBox => searchListBox;
11+
12+
public SearchControl()
13+
{
14+
InitializeComponent();
15+
}
16+
17+
void searchListBox_MouseDoubleClick(object? sender, MouseButtonEventArgs e) {
18+
if (!UIUtilities.IsLeftDoubleClick<ListBoxItem>(searchListBox, e))
19+
return;
20+
e.Handled = true;
21+
SearchListBoxDoubleClick?.Invoke(this, EventArgs.Empty);
22+
}
23+
24+
public event EventHandler? SearchListBoxDoubleClick;
25+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
using System.Collections.ObjectModel;
2+
using System.Linq;
3+
using System.Windows.Controls;
4+
using System.Windows.Input;
5+
using Cpp2ILAdapter.TreeView;
6+
using dnSpy.Contracts.Documents.Tabs;
7+
using dnSpy.Contracts.Documents.TreeView;
8+
using dnSpy.Contracts.Images;
9+
using dnSpy.Contracts.MVVM;
10+
using dnSpy.Contracts.Search;
11+
using FieldNode = Cpp2ILAdapter.TreeView.FieldNode;
12+
using MethodNode = Cpp2ILAdapter.TreeView.MethodNode;
13+
14+
namespace Cpp2ILAdapter.Search;
15+
16+
internal sealed class SearchControlVM : ViewModelBase
17+
{
18+
public class SearchSettingsContainer
19+
{
20+
SearchType SearchType { get; set; }
21+
public bool SyntaxHighlight { get; set; }
22+
public bool MatchWholeWords { get; set; }
23+
public bool CaseSensitive { get; set; }
24+
public bool MatchAnySearchTerm { get; set; }
25+
public bool SearchDecompiledData { get; set; }
26+
public bool SearchFrameworkAssemblies { get; set; }
27+
public bool SearchCompilerGeneratedMembers { get; set; }
28+
}
29+
30+
private readonly SearchControl _control;
31+
32+
public SearchSettingsContainer SearchSettings { get; set; } = new();
33+
34+
public SearchControlVM(SearchControl control)
35+
{
36+
_control = control;
37+
SearchTypeVMs = new();
38+
39+
Add(SearchType.TypeDef, "Type", DsImages.ClassPublic, "Type_Key", VisibleMembersFlags.TypeDef);
40+
Add(SearchType.FieldDef, "Field", DsImages.FieldPublic, "Field_Key", VisibleMembersFlags.FieldDef);
41+
Add(SearchType.MethodDef, "Method", DsImages.MethodPublic, "Method_Key", VisibleMembersFlags.MethodDef);
42+
//Add(SearchType.PropertyDef, Property, DsImages.Property, Property_Key, VisibleMembersFlags.PropertyDef);
43+
//Add(SearchType.EventDef, Event, DsImages.EventPublic, Event_Key, VisibleMembersFlags.EventDef);
44+
//Add(SearchType.ParamDef, Parameter, DsImages.Parameter, Parameter_Key, VisibleMembersFlags.ParamDef);
45+
//Add(SearchType.Local, Local, DsImages.LocalVariable, Local_Key, VisibleMembersFlags.Local);
46+
//Add(SearchType.ParamLocal, ParameterLocal, DsImages.LocalVariable, ParameterLocal_Key, VisibleMembersFlags.ParamDef | VisibleMembersFlags.Local);
47+
//Add(SearchType.AssemblyRef, AssemblyRef, DsImages.Reference, null, VisibleMembersFlags.AssemblyRef);
48+
//Add(SearchType.ModuleRef, ModuleRef, DsImages.Reference, null, VisibleMembersFlags.ModuleRef);
49+
//Add(SearchType.Resource, Resource, DsImages.Dialog, Resource_Key, VisibleMembersFlags.Resource | VisibleMembersFlags.ResourceElement);
50+
//Add(SearchType.GenericTypeDef, Generic, DsImages.Template, null, VisibleMembersFlags.GenericTypeDef);
51+
//Add(SearchType.NonGenericTypeDef, NonGeneric, DsImages.ClassPublic, null, VisibleMembersFlags.NonGenericTypeDef);
52+
Add(SearchType.EnumTypeDef, "Enum", DsImages.EnumerationPublic, null, VisibleMembersFlags.EnumTypeDef);
53+
Add(SearchType.InterfaceTypeDef, "Interface", DsImages.InterfacePublic, null, VisibleMembersFlags.InterfaceTypeDef);
54+
Add(SearchType.ClassTypeDef, "Class", DsImages.ClassPublic, null, VisibleMembersFlags.ClassTypeDef);
55+
Add(SearchType.StructTypeDef, "Struct", DsImages.StructurePublic, null, VisibleMembersFlags.StructTypeDef);
56+
//Add(SearchType.DelegateTypeDef, Delegate, DsImages.DelegatePublic, null, VisibleMembersFlags.DelegateTypeDef);
57+
//Add(SearchType.Member, Member, DsImages.Property, Member_Key, VisibleMembersFlags.MethodDef | VisibleMembersFlags.FieldDef | VisibleMembersFlags.PropertyDef | VisibleMembersFlags.EventDef);
58+
Add(SearchType.Any, "AllAbove", DsImages.ClassPublic, "AllAbove_Key", VisibleMembersFlags.TreeViewAll | VisibleMembersFlags.ParamDef | VisibleMembersFlags.Local);
59+
//Add(SearchType.Literal, Literal, DsImages.ConstantPublic, Literal_Key, VisibleMembersFlags.MethodBody | VisibleMembersFlags.FieldDef | VisibleMembersFlags.ParamDef | VisibleMembersFlags.PropertyDef | VisibleMembersFlags.Resource | VisibleMembersFlags.ResourceElement | VisibleMembersFlags.Attributes);
60+
61+
_control.SearchListBoxDoubleClick += FollowSelectedReference;
62+
63+
_control.SearchTextBox.TextChanged += TextChanged;
64+
}
65+
66+
private void TextChanged(object sender, TextChangedEventArgs e)
67+
{
68+
var selectedItem = CreateSearchWindowCommand.SharedDocumentTabService.DocumentTreeView.TreeView.SelectedItem;
69+
if (selectedItem.GetTopNode() is not Cpp2ILDocumentNode documentNode)
70+
return;
71+
72+
var list = _control.ListBox;
73+
74+
var searchType = selectedSearchTypeVM.SearchType;
75+
if (searchType == SearchType.TypeDef)
76+
{
77+
if (SearchSettings.MatchWholeWords)
78+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.FullName == _control.SearchTextBox.Text);
79+
else
80+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.FullName.Contains(_control.SearchTextBox.Text));
81+
}
82+
if (searchType == SearchType.ClassTypeDef)
83+
{
84+
if (SearchSettings.MatchWholeWords)
85+
list.ItemsSource = documentNode.AllTypes.Where(t => !t.Context.IsValueType && t.Context.FullName == _control.SearchTextBox.Text);
86+
else
87+
list.ItemsSource = documentNode.AllTypes.Where(t => !t.Context.IsValueType && t.Context.FullName.Contains(_control.SearchTextBox.Text));
88+
}
89+
if (searchType == SearchType.StructTypeDef)
90+
{
91+
if (SearchSettings.MatchWholeWords)
92+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsValueType && t.Context.FullName == _control.SearchTextBox.Text);
93+
else
94+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsValueType && t.Context.FullName.Contains(_control.SearchTextBox.Text));
95+
}
96+
if (searchType == SearchType.InterfaceTypeDef)
97+
{
98+
if (SearchSettings.MatchWholeWords)
99+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsInterface && t.Context.FullName == _control.SearchTextBox.Text);
100+
else
101+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsInterface && t.Context.FullName.Contains(_control.SearchTextBox.Text));
102+
}
103+
if (searchType == SearchType.EnumTypeDef)
104+
{
105+
if (SearchSettings.MatchWholeWords)
106+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsEnumType && t.Context.FullName == _control.SearchTextBox.Text);
107+
else
108+
list.ItemsSource = documentNode.AllTypes.Where(t => t.Context.IsEnumType && t.Context.FullName.Contains(_control.SearchTextBox.Text));
109+
}
110+
else if (searchType == SearchType.FieldDef)
111+
{
112+
var source = documentNode.AllTypes.SelectMany(_ => _.GetTreeNodeData.OfType<FieldNode>());
113+
if (SearchSettings.MatchWholeWords)
114+
list.ItemsSource = source.Where(t => t.Context.Name == _control.SearchTextBox.Text);
115+
else
116+
list.ItemsSource = source.Where(t => t.Context.Name.Contains(_control.SearchTextBox.Text));
117+
}
118+
else if (searchType == SearchType.MethodDef)
119+
{
120+
var source = documentNode.AllTypes.SelectMany(_ => _.GetTreeNodeData.OfType<MethodNode>());
121+
if (SearchSettings.MatchWholeWords)
122+
list.ItemsSource = source.Where(t => t.Context.Name == _control.SearchTextBox.Text);
123+
else
124+
list.ItemsSource = source.Where(t => t.Context.Name.Contains(_control.SearchTextBox.Text));
125+
}
126+
}
127+
128+
private void FollowSelectedReference(object? sender, EventArgs e)
129+
{
130+
bool newTab = Keyboard.Modifiers == ModifierKeys.Control || Keyboard.Modifiers == ModifierKeys.Shift;
131+
var @ref = _control.searchListBox.SelectedItem;
132+
CreateSearchWindowCommand.SharedDocumentTabService.FollowReference(@ref, newTab, true);
133+
}
134+
135+
public ObservableCollection<SearchTypeVM> SearchTypeVMs { get; }
136+
137+
public SearchTypeVM SelectedSearchTypeVM {
138+
get => selectedSearchTypeVM;
139+
set {
140+
if (selectedSearchTypeVM != value) {
141+
selectedSearchTypeVM = value;
142+
OnPropertyChanged(nameof(SelectedSearchTypeVM));
143+
}
144+
}
145+
}
146+
SearchTypeVM selectedSearchTypeVM;
147+
148+
void Add(SearchType searchType, string name, ImageReference icon, string? toolTip, VisibleMembersFlags flags) =>
149+
SearchTypeVMs.Add(new SearchTypeVM(searchType, name, toolTip, icon, flags));
150+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace Cpp2ILAdapter.Search;
2+
3+
enum SearchType {
4+
AssemblyDef,
5+
ModuleDef,
6+
Namespace,
7+
TypeDef,
8+
FieldDef,
9+
MethodDef,
10+
PropertyDef,
11+
EventDef,
12+
ParamDef,
13+
Local,
14+
ParamLocal,
15+
AssemblyRef,
16+
ModuleRef,
17+
Resource,
18+
GenericTypeDef,
19+
NonGenericTypeDef,
20+
EnumTypeDef,
21+
InterfaceTypeDef,
22+
ClassTypeDef,
23+
StructTypeDef,
24+
DelegateTypeDef,
25+
Member,
26+
Any,
27+
Literal,
28+
}

0 commit comments

Comments
 (0)