mirror of
https://github.com/ergrelet/resym
synced 2026-06-08 14:04:27 +00:00
Merge pull request #71 from ergrelet/symbol_kind_filtering
Allow filtering types and symbols by kind in resym
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
- Add 4 commands to `resymc`: `list-symbols`, `dump-symbol`, `dump-all-symbols` and `diff-symbol`
|
||||
- Add a `MSVC` primitive type representations (@HaydnTrigg)
|
||||
- Add a setting to switch display of integer values between decimal and hexadecimal (@HaydnTrigg)
|
||||
- Add new `classes`, `unions` and `enums` filters for type searches
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
Generated
+189
-2
@@ -127,6 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"const-random",
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"serde",
|
||||
@@ -143,6 +144,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.0"
|
||||
@@ -230,6 +237,17 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_type_match"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
@@ -489,6 +507,81 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bevy_macro_utils"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090371a2cd85574989febff6063a21d1fbbc2939e80f00fe075f62aa8e616136"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_ptr"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4da2111eefa2000ea8c9dc1beee2eb7283b29b5ef90a29fe43c748df549f84ad"
|
||||
|
||||
[[package]]
|
||||
name = "bevy_reflect"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82af24a68fd8feff476d9672ff34d220d3f45e95ef2f2324e7cb674614d18138"
|
||||
dependencies = [
|
||||
"assert_type_match",
|
||||
"bevy_ptr",
|
||||
"bevy_reflect_derive",
|
||||
"bevy_utils",
|
||||
"derive_more",
|
||||
"disqualified",
|
||||
"downcast-rs",
|
||||
"erased-serde",
|
||||
"serde",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_reflect_derive"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8369e6e779ab3540f9dcd93d062139f62551b3d2fe1ab451c6ddf74757e22ccd"
|
||||
dependencies = [
|
||||
"bevy_macro_utils",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_utils"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2993cac374b3f88cfaf59506c71f8e3e7ad8b4961f4e9864bc76e1c9e1e4400c"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bevy_utils_proc_macros",
|
||||
"getrandom 0.2.15",
|
||||
"hashbrown 0.14.5",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_utils_proc_macros"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2606f79dfe359a88e2a59bb6cd632cd42e9d4bcd250ac8bc3a4e7657e82f4f39"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -791,6 +884,26 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"once_cell",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@@ -938,6 +1051,27 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -965,6 +1099,12 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "disqualified"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd"
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.2"
|
||||
@@ -1240,6 +1380,16 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
@@ -1576,8 +1726,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1797,6 +1949,11 @@ name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
@@ -3199,6 +3356,7 @@ version = "0.4.0"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
"bevy_reflect",
|
||||
"console_error_panic_hook",
|
||||
"crossbeam-channel",
|
||||
"eframe",
|
||||
@@ -3218,6 +3376,7 @@ dependencies = [
|
||||
name = "resym_core"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"bevy_reflect",
|
||||
"crossbeam-channel",
|
||||
"dashmap",
|
||||
"ehttp",
|
||||
@@ -3829,6 +3988,16 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.9.1"
|
||||
@@ -3871,6 +4040,15 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.11.4"
|
||||
@@ -4005,6 +4183,12 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
@@ -4093,9 +4277,12 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.13.1"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0"
|
||||
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
|
||||
@@ -39,6 +39,7 @@ ahash = { version = "0.8", default-features = false, features = [
|
||||
"no-rng", # we don't need DOS-protection, so we let users opt-in to it instead
|
||||
"std",
|
||||
] }
|
||||
bevy_reflect = "0.15"
|
||||
|
||||
# Non-Web
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
|
||||
+97
-58
@@ -2,7 +2,7 @@ use anyhow::Result;
|
||||
use eframe::egui;
|
||||
use memory_logger::blocking::MemoryLogger;
|
||||
use resym_core::{
|
||||
backend::{Backend, BackendCommand, PDBSlot},
|
||||
backend::{Backend, BackendCommand, PDBSlot, SymbolFilters, TypeFilters},
|
||||
frontend::FrontendCommand,
|
||||
pdb_file::{SymbolIndex, TypeIndex},
|
||||
};
|
||||
@@ -20,7 +20,7 @@ use crate::{
|
||||
settings::ResymAppSettings,
|
||||
ui_components::{
|
||||
CodeViewComponent, ConsoleComponent, IndexListComponent, IndexListOrdering,
|
||||
ModuleTreeComponent, SettingsComponent, TextSearchComponent,
|
||||
ModuleTreeComponent, SearchFiltersComponent, SettingsComponent, TextSearchComponent,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,9 +64,11 @@ pub struct ResymApp {
|
||||
// Components used in the left-side panel
|
||||
left_panel_selected_tab: LeftPanelTab,
|
||||
type_search: TextSearchComponent,
|
||||
type_filters: SearchFiltersComponent<TypeFilters>,
|
||||
type_list: IndexListComponent<TypeIndex>,
|
||||
selected_type_index: Option<TypeIndex>,
|
||||
symbol_search: TextSearchComponent,
|
||||
symbol_filters: SearchFiltersComponent<SymbolFilters>,
|
||||
symbol_list: IndexListComponent<SymbolIndex>,
|
||||
selected_symbol_index: Option<SymbolIndex>,
|
||||
module_search: TextSearchComponent,
|
||||
@@ -164,9 +166,11 @@ impl ResymApp {
|
||||
current_mode: ResymAppMode::Idle,
|
||||
left_panel_selected_tab: LeftPanelTab::TypeSearch,
|
||||
type_search: TextSearchComponent::new(),
|
||||
type_filters: SearchFiltersComponent::new("Search filters"),
|
||||
type_list: IndexListComponent::new(IndexListOrdering::Alphabetical),
|
||||
selected_type_index: None,
|
||||
symbol_search: TextSearchComponent::new(),
|
||||
symbol_filters: SearchFiltersComponent::new("Search filters"),
|
||||
symbol_list: IndexListComponent::new(IndexListOrdering::Alphabetical),
|
||||
selected_symbol_index: None,
|
||||
module_search: TextSearchComponent::new(),
|
||||
@@ -232,37 +236,53 @@ impl ResymApp {
|
||||
|
||||
match self.left_panel_selected_tab {
|
||||
LeftPanelTab::TypeSearch => {
|
||||
let update_type_list =
|
||||
|search_query: &str, search_filters: &TypeFilters| {
|
||||
// Update filtered list if filter has changed
|
||||
let result = if let ResymAppMode::Comparing(..) = self.current_mode
|
||||
{
|
||||
self.backend.send_command(BackendCommand::ListTypesMerged(
|
||||
vec![
|
||||
ResymPDBSlots::Main as usize,
|
||||
ResymPDBSlots::Diff as usize,
|
||||
],
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
search_filters.clone(),
|
||||
))
|
||||
} else {
|
||||
self.backend.send_command(BackendCommand::ListTypes(
|
||||
ResymPDBSlots::Main as usize,
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
search_filters.clone(),
|
||||
))
|
||||
};
|
||||
if let Err(err) = result {
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
}
|
||||
};
|
||||
|
||||
// Callback run when the search query changes
|
||||
let on_query_update = |search_query: &str| {
|
||||
// Update filtered list if filter has changed
|
||||
let result = if let ResymAppMode::Comparing(..) = self.current_mode {
|
||||
self.backend.send_command(BackendCommand::ListTypesMerged(
|
||||
vec![
|
||||
ResymPDBSlots::Main as usize,
|
||||
ResymPDBSlots::Diff as usize,
|
||||
],
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
))
|
||||
} else {
|
||||
self.backend.send_command(BackendCommand::ListTypes(
|
||||
ResymPDBSlots::Main as usize,
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
))
|
||||
};
|
||||
if let Err(err) = result {
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
}
|
||||
let search_filters = self.type_filters.filters();
|
||||
update_type_list(search_query, search_filters);
|
||||
};
|
||||
|
||||
// Update the type search bar
|
||||
ui.label("Search");
|
||||
self.type_search.update(ui, &on_query_update);
|
||||
|
||||
// Callback run when the search filter is updated
|
||||
let on_filter_update = |search_filters: &TypeFilters| {
|
||||
let search_query = self.type_search.search_filter();
|
||||
update_type_list(search_query, search_filters);
|
||||
};
|
||||
self.type_filters.update(ui, &on_filter_update);
|
||||
ui.separator();
|
||||
ui.add_space(4.0);
|
||||
|
||||
@@ -313,37 +333,53 @@ impl ResymApp {
|
||||
}
|
||||
|
||||
LeftPanelTab::SymbolSearch => {
|
||||
// Callback run when the search query changes
|
||||
let on_query_update = |search_query: &str| {
|
||||
// Update filtered list if filter has changed
|
||||
let result = if let ResymAppMode::Comparing(..) = self.current_mode {
|
||||
self.backend.send_command(BackendCommand::ListSymbolsMerged(
|
||||
vec![
|
||||
let update_symbol_list =
|
||||
|search_query: &str, search_filters: &SymbolFilters| {
|
||||
// Update filtered list if filter has changed
|
||||
let result = if let ResymAppMode::Comparing(..) = self.current_mode
|
||||
{
|
||||
self.backend.send_command(BackendCommand::ListSymbolsMerged(
|
||||
vec![
|
||||
ResymPDBSlots::Main as usize,
|
||||
ResymPDBSlots::Diff as usize,
|
||||
],
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
search_filters.clone(),
|
||||
))
|
||||
} else {
|
||||
self.backend.send_command(BackendCommand::ListSymbols(
|
||||
ResymPDBSlots::Main as usize,
|
||||
ResymPDBSlots::Diff as usize,
|
||||
],
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
))
|
||||
} else {
|
||||
self.backend.send_command(BackendCommand::ListSymbols(
|
||||
ResymPDBSlots::Main as usize,
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
))
|
||||
search_query.to_string(),
|
||||
self.settings.app_settings.search_case_insensitive,
|
||||
self.settings.app_settings.search_use_regex,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
search_filters.clone(),
|
||||
))
|
||||
};
|
||||
if let Err(err) = result {
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
}
|
||||
};
|
||||
if let Err(err) = result {
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
}
|
||||
|
||||
// Callback run when the search query is updated
|
||||
let on_query_update = |search_query: &str| {
|
||||
let search_filters = self.symbol_filters.filters();
|
||||
update_symbol_list(search_query, search_filters);
|
||||
};
|
||||
|
||||
// Update the symbol search bar
|
||||
ui.label("Search");
|
||||
self.symbol_search.update(ui, &on_query_update);
|
||||
|
||||
// Callback run when the search filter is updated
|
||||
let on_filter_update = |search_filters: &SymbolFilters| {
|
||||
let search_query = self.symbol_search.search_filter();
|
||||
update_symbol_list(search_query, search_filters);
|
||||
};
|
||||
self.symbol_filters.update(ui, &on_filter_update);
|
||||
ui.separator();
|
||||
ui.add_space(4.0);
|
||||
|
||||
@@ -659,10 +695,11 @@ impl ResymApp {
|
||||
// Request a type list update
|
||||
if let Err(err) = self.backend.send_command(BackendCommand::ListTypes(
|
||||
ResymPDBSlots::Main as usize,
|
||||
String::default(),
|
||||
Default::default(),
|
||||
false,
|
||||
false,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
Default::default(),
|
||||
)) {
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
}
|
||||
@@ -670,10 +707,11 @@ impl ResymApp {
|
||||
if let Err(err) =
|
||||
self.backend.send_command(BackendCommand::ListSymbols(
|
||||
ResymPDBSlots::Main as usize,
|
||||
String::default(),
|
||||
Default::default(),
|
||||
false,
|
||||
false,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
Default::default(),
|
||||
))
|
||||
{
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
@@ -682,7 +720,7 @@ impl ResymApp {
|
||||
if let Err(err) =
|
||||
self.backend.send_command(BackendCommand::ListModules(
|
||||
ResymPDBSlots::Main as usize,
|
||||
String::default(),
|
||||
Default::default(),
|
||||
false,
|
||||
false,
|
||||
))
|
||||
@@ -692,11 +730,11 @@ impl ResymApp {
|
||||
} else if pdb_slot == ResymPDBSlots::Diff as usize {
|
||||
// Reset current mode
|
||||
self.current_mode = ResymAppMode::Comparing(
|
||||
String::default(),
|
||||
String::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
0,
|
||||
vec![],
|
||||
String::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
// Reset selected type
|
||||
self.selected_type_index = None;
|
||||
@@ -711,10 +749,11 @@ impl ResymApp {
|
||||
ResymPDBSlots::Main as usize,
|
||||
ResymPDBSlots::Diff as usize,
|
||||
],
|
||||
String::default(),
|
||||
Default::default(),
|
||||
false,
|
||||
false,
|
||||
self.settings.app_settings.ignore_std_types,
|
||||
Default::default(),
|
||||
))
|
||||
{
|
||||
log::error!("Failed to update type filter value: {}", err);
|
||||
|
||||
@@ -4,6 +4,7 @@ mod index_list;
|
||||
mod module_tree;
|
||||
#[cfg(feature = "http")]
|
||||
mod open_url;
|
||||
mod search_filters;
|
||||
mod settings;
|
||||
mod text_search;
|
||||
|
||||
@@ -13,5 +14,6 @@ pub use index_list::*;
|
||||
pub use module_tree::*;
|
||||
#[cfg(feature = "http")]
|
||||
pub use open_url::*;
|
||||
pub use search_filters::*;
|
||||
pub use settings::*;
|
||||
pub use text_search::*;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
use bevy_reflect::{Reflect, Struct};
|
||||
use eframe::egui;
|
||||
|
||||
pub struct SearchFiltersComponent<FilterType> {
|
||||
header: String,
|
||||
filters: FilterType,
|
||||
}
|
||||
|
||||
impl<FilterType: Default + Clone + Reflect + Struct> SearchFiltersComponent<FilterType> {
|
||||
pub fn new(header: &str) -> Self {
|
||||
Self {
|
||||
header: header.into(),
|
||||
filters: FilterType::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filters(&self) -> &FilterType {
|
||||
&self.filters
|
||||
}
|
||||
|
||||
/// Update/render the UI component
|
||||
pub fn update<CB: Fn(&FilterType)>(&mut self, ui: &mut egui::Ui, on_filter_update: &CB) {
|
||||
ui.collapsing(&self.header, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
let field_count = self.filters.field_len();
|
||||
// Iterate over the struct's fields
|
||||
for i in 0..field_count {
|
||||
// Get current field name as a string
|
||||
let field_name = self
|
||||
.filters
|
||||
.name_at(i)
|
||||
.expect("name_at should succeed")
|
||||
.to_string();
|
||||
// Get mutable ref (as bool) to the current field
|
||||
let field_value = self
|
||||
.filters
|
||||
.field_at_mut(i)
|
||||
.expect("field_at_mut should succeed")
|
||||
.try_downcast_mut::<bool>()
|
||||
.expect("filter field should be bool");
|
||||
|
||||
if ui.checkbox(field_value, field_name).changed() {
|
||||
on_filter_update(&self.filters);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,14 @@ impl TextSearchComponent {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_filter(&self) -> &str {
|
||||
self.search_filter.as_str()
|
||||
}
|
||||
|
||||
/// Update/render the UI component
|
||||
pub fn update<CB: Fn(&str)>(&mut self, ui: &mut egui::Ui, on_query_update: &CB) {
|
||||
if ui.text_edit_singleline(&mut self.search_filter).changed() {
|
||||
on_query_update(self.search_filter.as_str());
|
||||
on_query_update(self.search_filter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ similar = "2.4"
|
||||
ehttp = { version = "0.5", optional = true }
|
||||
url = { version = "2.5", optional = true }
|
||||
msvc-demangler = "0.10"
|
||||
bevy_reflect = "0.15"
|
||||
|
||||
# Web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
|
||||
+166
-69
@@ -1,3 +1,4 @@
|
||||
use bevy_reflect::Reflect;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use instant::Instant;
|
||||
@@ -7,6 +8,8 @@ use rayon::{
|
||||
prelude::ParallelSliceMut,
|
||||
ThreadPool,
|
||||
};
|
||||
#[cfg(all(not(feature = "rayon"), target_arch = "wasm32"))]
|
||||
use wasm_thread::{self as thread, JoinHandle};
|
||||
|
||||
use core::fmt;
|
||||
#[cfg(all(not(feature = "rayon"), not(target_arch = "wasm32")))]
|
||||
@@ -18,15 +21,16 @@ use std::{
|
||||
};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::{path::PathBuf, time::Instant};
|
||||
#[cfg(all(not(feature = "rayon"), target_arch = "wasm32"))]
|
||||
use wasm_thread::{self as thread, JoinHandle};
|
||||
|
||||
use crate::{
|
||||
diffing::{diff_module_by_path, diff_symbol_by_name, diff_type_by_name},
|
||||
error::{Result, ResymCoreError},
|
||||
frontend::{FrontendCommand, FrontendController, ReconstructedType},
|
||||
par_iter_if_available, par_sort_by_if_available,
|
||||
pdb_file::{self, ModuleList, PDBDataSource, PdbFile, SymbolList, SymbolListView, TypeList},
|
||||
pdb_file::{
|
||||
self, ModuleInfo, ModuleList, PDBDataSource, PdbFile, SymbolInfoEx, SymbolKind, SymbolList,
|
||||
SymbolListExView, TypeInfoEx, TypeKind, TypeList, TypeListExView,
|
||||
},
|
||||
pdb_types::{include_headers_for_flavor, PrimitiveReconstructionFlavor},
|
||||
PKG_VERSION,
|
||||
};
|
||||
@@ -78,16 +82,16 @@ pub enum BackendCommand {
|
||||
bool,
|
||||
),
|
||||
/// Retrieve a list of types that match the given filter for a given PDB.
|
||||
ListTypes(PDBSlot, String, bool, bool, bool),
|
||||
ListTypes(PDBSlot, String, bool, bool, bool, TypeFilters),
|
||||
/// Retrieve a list of types that match the given filter for multiple PDBs
|
||||
/// and merge the result.
|
||||
ListTypesMerged(Vec<PDBSlot>, String, bool, bool, bool),
|
||||
ListTypesMerged(Vec<PDBSlot>, String, bool, bool, bool, TypeFilters),
|
||||
/// Retrieve a list of symbols that match the given filter for multiple PDBs
|
||||
/// and merge the result.
|
||||
ListSymbols(PDBSlot, String, bool, bool, bool),
|
||||
ListSymbols(PDBSlot, String, bool, bool, bool, SymbolFilters),
|
||||
/// Retrieve a list of symbols that match the given filter for multiple PDBs
|
||||
/// and merge the result.
|
||||
ListSymbolsMerged(Vec<PDBSlot>, String, bool, bool, bool),
|
||||
ListSymbolsMerged(Vec<PDBSlot>, String, bool, bool, bool, SymbolFilters),
|
||||
/// Reconstruct a symbol given its index for a given PDB.
|
||||
ReconstructSymbolByIndex(
|
||||
PDBSlot,
|
||||
@@ -139,6 +143,42 @@ pub enum BackendCommand {
|
||||
ListTypeCrossReferences(PDBSlot, pdb_file::TypeIndex),
|
||||
}
|
||||
|
||||
/// Search filters for types
|
||||
#[derive(Clone, Reflect)]
|
||||
pub struct TypeFilters {
|
||||
classes: bool,
|
||||
unions: bool,
|
||||
enums: bool,
|
||||
}
|
||||
|
||||
impl Default for TypeFilters {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
classes: true,
|
||||
unions: true,
|
||||
enums: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Search filters for symbols
|
||||
#[derive(Clone, Reflect)]
|
||||
pub struct SymbolFilters {
|
||||
functions: bool,
|
||||
variables: bool,
|
||||
types: bool,
|
||||
}
|
||||
|
||||
impl Default for SymbolFilters {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
functions: true,
|
||||
variables: true,
|
||||
types: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct that represents the backend. The backend is responsible
|
||||
/// for the actual PDB processing (e.g., type listing and reconstruction).
|
||||
pub struct Backend {
|
||||
@@ -394,19 +434,21 @@ fn worker_thread_routine(
|
||||
|
||||
BackendCommand::ListTypes(
|
||||
pdb_slot,
|
||||
search_filter,
|
||||
search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters,
|
||||
) => {
|
||||
if let Some(pdb_file) = pdb_files.get(&pdb_slot) {
|
||||
let filtered_type_list = update_type_filter_command(
|
||||
pdb_file,
|
||||
&search_filter,
|
||||
&search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
true,
|
||||
search_filters,
|
||||
);
|
||||
frontend_controller
|
||||
.send_command(FrontendCommand::ListTypesResult(filtered_type_list))?;
|
||||
@@ -415,21 +457,23 @@ fn worker_thread_routine(
|
||||
|
||||
BackendCommand::ListTypesMerged(
|
||||
pdb_slots,
|
||||
search_filter,
|
||||
search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters,
|
||||
) => {
|
||||
let mut filtered_type_set = BTreeSet::default();
|
||||
for pdb_slot in pdb_slots {
|
||||
if let Some(pdb_file) = pdb_files.get(&pdb_slot) {
|
||||
let filtered_type_list = update_type_filter_command(
|
||||
pdb_file,
|
||||
&search_filter,
|
||||
&search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
false,
|
||||
search_filters.clone(),
|
||||
);
|
||||
filtered_type_set.extend(filtered_type_list.into_iter().map(|(s, _)| {
|
||||
// Collapse all type indices to `default`. When merging
|
||||
@@ -446,18 +490,20 @@ fn worker_thread_routine(
|
||||
|
||||
BackendCommand::ListSymbols(
|
||||
pdb_slot,
|
||||
search_filter,
|
||||
search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters,
|
||||
) => {
|
||||
if let Some(pdb_file) = pdb_files.get_mut(&pdb_slot) {
|
||||
let filtered_symbol_list = update_symbol_filter_command(
|
||||
pdb_file,
|
||||
&search_filter,
|
||||
&search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters,
|
||||
);
|
||||
frontend_controller
|
||||
.send_command(FrontendCommand::ListSymbolsResult(filtered_symbol_list))?;
|
||||
@@ -466,20 +512,22 @@ fn worker_thread_routine(
|
||||
|
||||
BackendCommand::ListSymbolsMerged(
|
||||
pdb_slots,
|
||||
search_filter,
|
||||
search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters,
|
||||
) => {
|
||||
let mut filtered_symbol_set = BTreeSet::default();
|
||||
for pdb_slot in pdb_slots {
|
||||
if let Some(pdb_file) = pdb_files.get_mut(&pdb_slot) {
|
||||
let filtered_symbol_list = update_symbol_filter_command(
|
||||
pdb_file,
|
||||
&search_filter,
|
||||
&search_query,
|
||||
case_insensitive_search,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
search_filters.clone(),
|
||||
);
|
||||
filtered_symbol_set.extend(filtered_symbol_list.into_iter().map(
|
||||
|(s, _)| {
|
||||
@@ -891,33 +939,41 @@ where
|
||||
|
||||
fn update_type_filter_command<T>(
|
||||
pdb_file: &PdbFile<T>,
|
||||
search_filter: &str,
|
||||
search_query: &str,
|
||||
case_insensitive_search: bool,
|
||||
use_regex: bool,
|
||||
ignore_std_types: bool,
|
||||
sort_by_index: bool,
|
||||
search_filters: TypeFilters,
|
||||
) -> TypeList
|
||||
where
|
||||
T: io::Seek + io::Read,
|
||||
T: io::Seek + io::Read + std::fmt::Debug,
|
||||
{
|
||||
let filter_start = Instant::now();
|
||||
|
||||
// Filter out std types if needed
|
||||
let filtered_type_list = if ignore_std_types {
|
||||
filter_std_types(&pdb_file.complete_type_list)
|
||||
} else {
|
||||
pdb_file.complete_type_list.clone()
|
||||
};
|
||||
// Retrieve view to the type list
|
||||
let type_list: TypeListExView = pdb_file.type_list();
|
||||
|
||||
// Filter types following the search filter
|
||||
let mut filtered_type_list = if search_filter.is_empty() {
|
||||
let filtered_type_list = if search_query.is_empty() {
|
||||
// No need to filter
|
||||
filtered_type_list
|
||||
type_list
|
||||
} else if use_regex {
|
||||
filter_types_regex(&filtered_type_list, search_filter, case_insensitive_search)
|
||||
filter_types_regex(&type_list, search_query, case_insensitive_search)
|
||||
} else {
|
||||
filter_types_regular(&filtered_type_list, search_filter, case_insensitive_search)
|
||||
filter_types_regular(&type_list, search_query, case_insensitive_search)
|
||||
};
|
||||
|
||||
// Apply filters by type kind
|
||||
let filtered_type_list = filter_types_kind(&filtered_type_list, &search_filters);
|
||||
|
||||
// Filter out std types if needed
|
||||
let mut filtered_type_list = if ignore_std_types {
|
||||
filter_std_types(&filtered_type_list)
|
||||
} else {
|
||||
filtered_type_list
|
||||
};
|
||||
|
||||
if sort_by_index {
|
||||
// Order types by type index, so the order is deterministic
|
||||
// (i.e., independent from DashMap's hash function)
|
||||
@@ -929,15 +985,18 @@ where
|
||||
filter_start.elapsed().as_millis()
|
||||
);
|
||||
|
||||
filtered_type_list
|
||||
// Convert refs to symbol info into clones and return it
|
||||
par_iter_if_available!(filtered_type_list)
|
||||
.map(|type_info| (type_info.0.clone(), type_info.1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Filter type list with a regular expression
|
||||
fn filter_types_regex(
|
||||
type_list: &[(String, u32)],
|
||||
fn filter_types_regex<'s>(
|
||||
type_list: &'s [&TypeInfoEx],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> TypeList {
|
||||
) -> TypeListExView<'s> {
|
||||
match regex::RegexBuilder::new(search_filter)
|
||||
.case_insensitive(case_insensitive_search)
|
||||
.build()
|
||||
@@ -952,11 +1011,11 @@ fn filter_types_regex(
|
||||
}
|
||||
|
||||
/// Filter type list with a plain (sub-)string
|
||||
fn filter_types_regular(
|
||||
type_list: &[(String, u32)],
|
||||
fn filter_types_regular<'s>(
|
||||
type_list: &'s [&TypeInfoEx],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> TypeList {
|
||||
) -> TypeListExView<'s> {
|
||||
if case_insensitive_search {
|
||||
let search_filter = search_filter.to_lowercase();
|
||||
par_iter_if_available!(type_list)
|
||||
@@ -972,19 +1031,42 @@ fn filter_types_regular(
|
||||
}
|
||||
|
||||
/// Filter type list to remove types in the `std` namespace
|
||||
fn filter_std_types(type_list: &[(String, pdb_file::TypeIndex)]) -> TypeList {
|
||||
fn filter_std_types<'s>(type_list: &'s [&TypeInfoEx]) -> TypeListExView<'s> {
|
||||
par_iter_if_available!(type_list)
|
||||
.filter(|r| !r.0.starts_with("std::"))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Filter type list with a regular expression
|
||||
#[allow(clippy::if_same_then_else, clippy::needless_bool)]
|
||||
fn filter_types_kind<'s>(
|
||||
type_list: &'s [&TypeInfoEx],
|
||||
type_filters: &TypeFilters,
|
||||
) -> TypeListExView<'s> {
|
||||
par_iter_if_available!(type_list)
|
||||
.filter(|(_, _, type_kind)| {
|
||||
if !type_filters.classes && *type_kind == TypeKind::Class {
|
||||
false
|
||||
} else if !type_filters.unions && *type_kind == TypeKind::Union {
|
||||
false
|
||||
} else if !type_filters.enums && *type_kind == TypeKind::Enum {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn update_symbol_filter_command<T>(
|
||||
pdb_file: &mut PdbFile<T>,
|
||||
search_filter: &str,
|
||||
search_query: &str,
|
||||
case_insensitive_search: bool,
|
||||
use_regex: bool,
|
||||
ignore_std_symbols: bool,
|
||||
search_filters: SymbolFilters,
|
||||
) -> SymbolList
|
||||
where
|
||||
T: io::Seek + io::Read + fmt::Debug,
|
||||
@@ -992,30 +1074,25 @@ where
|
||||
let filter_start = Instant::now();
|
||||
|
||||
match pdb_file.symbol_list() {
|
||||
Err(_) => SymbolList::default(),
|
||||
Err(_) => Default::default(),
|
||||
Ok(symbol_list) => {
|
||||
// Filter out std types if needed
|
||||
let filtered_symbol_list = if ignore_std_symbols {
|
||||
filter_std_symbols(&symbol_list)
|
||||
} else {
|
||||
let filtered_symbol_list = if search_query.is_empty() {
|
||||
// No need to filter
|
||||
symbol_list
|
||||
} else if use_regex {
|
||||
filter_symbols_regex(&symbol_list, search_query, case_insensitive_search)
|
||||
} else {
|
||||
filter_symbols_regular(&symbol_list, search_query, case_insensitive_search)
|
||||
};
|
||||
|
||||
let filtered_symbol_list = if search_filter.is_empty() {
|
||||
// No need to filter
|
||||
filtered_symbol_list
|
||||
} else if use_regex {
|
||||
filter_symbols_regex(
|
||||
&filtered_symbol_list,
|
||||
search_filter,
|
||||
case_insensitive_search,
|
||||
)
|
||||
// Apply filters by symbol kind
|
||||
let filtered_symbol_list = filter_symbols_type(&filtered_symbol_list, &search_filters);
|
||||
|
||||
// Filter out std types if needed
|
||||
let filtered_symbol_list = if ignore_std_symbols {
|
||||
filter_std_symbols(&filtered_symbol_list)
|
||||
} else {
|
||||
filter_symbols_regular(
|
||||
&filtered_symbol_list,
|
||||
search_filter,
|
||||
case_insensitive_search,
|
||||
)
|
||||
filtered_symbol_list
|
||||
};
|
||||
|
||||
log::debug!(
|
||||
@@ -1025,28 +1102,26 @@ where
|
||||
|
||||
// Convert refs to symbol info into clones and return it
|
||||
par_iter_if_available!(filtered_symbol_list)
|
||||
.map(|e| (e.0.clone(), e.1))
|
||||
.map(|symbol_info| (symbol_info.0.clone(), symbol_info.1))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter symbol list to remove types in the `std` namespace
|
||||
fn filter_std_symbols<'s>(
|
||||
symbol_list: &'s [&(String, pdb_file::SymbolIndex)],
|
||||
) -> SymbolListView<'s> {
|
||||
fn filter_std_symbols<'s>(symbol_list: &'s [&SymbolInfoEx]) -> SymbolListExView<'s> {
|
||||
par_iter_if_available!(symbol_list)
|
||||
.filter(|r| !r.0.starts_with("std::"))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Filter type list with a regular expression
|
||||
/// Filter symbol list with a regular expression
|
||||
fn filter_symbols_regex<'s>(
|
||||
symbol_list: &'s [&(String, pdb_file::SymbolIndex)],
|
||||
symbol_list: &'s [&SymbolInfoEx],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> SymbolListView<'s> {
|
||||
) -> SymbolListExView<'s> {
|
||||
match regex::RegexBuilder::new(search_filter)
|
||||
.case_insensitive(case_insensitive_search)
|
||||
.build()
|
||||
@@ -1060,12 +1135,12 @@ fn filter_symbols_regex<'s>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter type list with a plain (sub-)string
|
||||
/// Filter symbol list with a plain (sub-)string
|
||||
fn filter_symbols_regular<'s>(
|
||||
symbol_list: &'s [&(String, pdb_file::SymbolIndex)],
|
||||
symbol_list: &'s [&SymbolInfoEx],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> SymbolListView<'s> {
|
||||
) -> SymbolListExView<'s> {
|
||||
if case_insensitive_search {
|
||||
let search_filter = search_filter.to_lowercase();
|
||||
par_iter_if_available!(symbol_list)
|
||||
@@ -1080,6 +1155,28 @@ fn filter_symbols_regular<'s>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter symbol list by type
|
||||
#[allow(clippy::if_same_then_else, clippy::needless_bool)]
|
||||
fn filter_symbols_type<'s>(
|
||||
symbol_list: &'s [&SymbolInfoEx],
|
||||
symbol_filters: &SymbolFilters,
|
||||
) -> SymbolListExView<'s> {
|
||||
par_iter_if_available!(symbol_list)
|
||||
.filter(|(_, _, symbol_kind)| {
|
||||
if !symbol_filters.functions && *symbol_kind == SymbolKind::Function {
|
||||
false
|
||||
} else if !symbol_filters.variables && *symbol_kind == SymbolKind::Variable {
|
||||
false
|
||||
} else if !symbol_filters.types && *symbol_kind == SymbolKind::Type {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn list_modules_command<'p, T>(
|
||||
pdb_file: &PdbFile<'p, T>,
|
||||
search_filter: &str,
|
||||
@@ -1118,10 +1215,10 @@ where
|
||||
|
||||
/// Filter module list with a regular expression
|
||||
fn filter_modules_regex(
|
||||
module_list: &[(String, usize)],
|
||||
module_list: &[ModuleInfo],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> Vec<(String, usize)> {
|
||||
) -> ModuleList {
|
||||
match regex::RegexBuilder::new(search_filter)
|
||||
.case_insensitive(case_insensitive_search)
|
||||
.build()
|
||||
@@ -1137,10 +1234,10 @@ fn filter_modules_regex(
|
||||
|
||||
/// Filter module list with a plain (sub-)string
|
||||
fn filter_modules_regular(
|
||||
module_list: &[(String, usize)],
|
||||
module_list: &[ModuleInfo],
|
||||
search_filter: &str,
|
||||
case_insensitive_search: bool,
|
||||
) -> Vec<(String, usize)> {
|
||||
) -> ModuleList {
|
||||
if case_insensitive_search {
|
||||
let search_filter = search_filter.to_lowercase();
|
||||
par_iter_if_available!(module_list)
|
||||
|
||||
+164
-78
@@ -24,14 +24,45 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
// Type
|
||||
pub type TypeIndex = u32;
|
||||
pub type TypeList = Vec<(String, TypeIndex)>;
|
||||
/// Minimal symbol info (used by frontends)
|
||||
pub type TypeInfo = (String, TypeIndex);
|
||||
pub type TypeList = Vec<TypeInfo>;
|
||||
/// Extended symbol info (used by the backend)
|
||||
pub type TypeInfoEx = (String, TypeIndex, TypeKind);
|
||||
pub type TypeListEx = Vec<TypeInfoEx>;
|
||||
pub type TypeListExView<'t> = Vec<&'t TypeInfoEx>;
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum TypeKind {
|
||||
Class,
|
||||
Union,
|
||||
Enum,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
// Symbol
|
||||
/// `SymbolIndex` have two parts: a module index and a symbol index
|
||||
pub type SymbolIndex = (ModuleIndex, u32);
|
||||
pub type SymbolList = Vec<(String, SymbolIndex)>;
|
||||
pub type SymbolListView<'t> = Vec<&'t (String, SymbolIndex)>;
|
||||
/// Minimal symbol info (used by frontends)
|
||||
pub type SymbolInfo = (String, SymbolIndex);
|
||||
pub type SymbolList = Vec<SymbolInfo>;
|
||||
/// Extended symbol info (used by the backend)
|
||||
pub type SymbolInfoEx = (String, SymbolIndex, SymbolKind);
|
||||
pub type SymbolListEx = Vec<SymbolInfoEx>;
|
||||
pub type SymbolListExView<'t> = Vec<&'t SymbolInfoEx>;
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum SymbolKind {
|
||||
Function,
|
||||
Variable,
|
||||
Type,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
// Module
|
||||
pub type ModuleIndex = usize;
|
||||
pub type ModuleList = Vec<(String, ModuleIndex)>;
|
||||
pub type ModuleInfo = (String, ModuleIndex);
|
||||
pub type ModuleList = Vec<ModuleInfo>;
|
||||
|
||||
const GLOBAL_MODULE_INDEX: usize = usize::MAX;
|
||||
|
||||
@@ -67,8 +98,9 @@ impl Read for PDBDataSource {
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct PrioritizedSymbol {
|
||||
priority: u16,
|
||||
index: SymbolIndex,
|
||||
name: String,
|
||||
index: SymbolIndex,
|
||||
kind: SymbolKind,
|
||||
}
|
||||
|
||||
impl PartialOrd for PrioritizedSymbol {
|
||||
@@ -87,9 +119,9 @@ pub struct PdbFile<'p, T>
|
||||
where
|
||||
T: io::Seek + io::Read + 'p,
|
||||
{
|
||||
pub complete_type_list: Vec<(String, TypeIndex)>,
|
||||
pub complete_type_list: TypeListEx,
|
||||
pub forwarder_to_complete_type: Arc<DashMap<pdb::TypeIndex, pdb::TypeIndex>>,
|
||||
pub symbol_list: SymbolList,
|
||||
pub symbol_list: SymbolListEx,
|
||||
pub machine_type: pdb::MachineType,
|
||||
pub type_information: pdb::TypeInformation<'p>,
|
||||
pub debug_information: pdb::DebugInformation<'p>,
|
||||
@@ -228,7 +260,8 @@ where
|
||||
if is_unnamed_type(&class_name) {
|
||||
class_name = format!("_unnamed_{type_index}");
|
||||
}
|
||||
self.complete_type_list.push((class_name, type_index.0));
|
||||
self.complete_type_list
|
||||
.push((class_name, type_index.0, TypeKind::Class));
|
||||
}
|
||||
pdb::TypeData::Union(data) => {
|
||||
let mut class_name = data.name.to_string().into_owned();
|
||||
@@ -244,7 +277,8 @@ where
|
||||
if is_unnamed_type(&class_name) {
|
||||
class_name = format!("_unnamed_{type_index}");
|
||||
}
|
||||
self.complete_type_list.push((class_name, type_index.0));
|
||||
self.complete_type_list
|
||||
.push((class_name, type_index.0, TypeKind::Union));
|
||||
}
|
||||
pdb::TypeData::Enumeration(data) => {
|
||||
let mut class_name = data.name.to_string().into_owned();
|
||||
@@ -260,7 +294,8 @@ where
|
||||
if is_unnamed_type(&class_name) {
|
||||
class_name = format!("_unnamed_{type_index}");
|
||||
}
|
||||
self.complete_type_list.push((class_name, type_index.0));
|
||||
self.complete_type_list
|
||||
.push((class_name, type_index.0, TypeKind::Enum));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -417,7 +452,11 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
pub fn symbol_list(&mut self) -> Result<SymbolListView> {
|
||||
pub fn type_list(&self) -> TypeListExView {
|
||||
self.complete_type_list.iter().collect()
|
||||
}
|
||||
|
||||
pub fn symbol_list(&mut self) -> Result<SymbolListExView> {
|
||||
// If cache is populated, return the cached list
|
||||
if !self.symbol_list.is_empty() {
|
||||
return Ok(self.symbol_list.iter().collect());
|
||||
@@ -439,12 +478,15 @@ where
|
||||
|
||||
let mut module_symbols = module_info.symbols()?;
|
||||
while let Some(symbol) = module_symbols.next()? {
|
||||
if let Some(symbol_name) = get_symbol_name(&symbol) {
|
||||
symbol_heap.push(PrioritizedSymbol {
|
||||
priority: symbol_priority(&symbol),
|
||||
index: (module_index, symbol.index().0),
|
||||
name: symbol_name.clone(),
|
||||
});
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if let Some(symbol_name) = get_symbol_name(&symbol_data) {
|
||||
symbol_heap.push(PrioritizedSymbol {
|
||||
priority: symbol_priority(&symbol_data),
|
||||
name: symbol_name.clone(),
|
||||
index: (module_index, symbol.index().0),
|
||||
kind: get_symbol_type(&symbol_data),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,12 +495,15 @@ where
|
||||
// Global symbols
|
||||
let mut symbol_table = self.global_symbols.iter();
|
||||
while let Some(symbol) = symbol_table.next()? {
|
||||
if let Some(symbol_name) = get_symbol_name(&symbol) {
|
||||
symbol_heap.push(PrioritizedSymbol {
|
||||
priority: symbol_priority(&symbol),
|
||||
index: (GLOBAL_MODULE_INDEX, symbol.index().0),
|
||||
name: symbol_name.clone(),
|
||||
});
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if let Some(symbol_name) = get_symbol_name(&symbol_data) {
|
||||
symbol_heap.push(PrioritizedSymbol {
|
||||
priority: symbol_priority(&symbol_data),
|
||||
name: symbol_name.clone(),
|
||||
index: (GLOBAL_MODULE_INDEX, symbol.index().0),
|
||||
kind: get_symbol_type(&symbol_data),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,7 +515,8 @@ where
|
||||
.filter_map(|s| {
|
||||
if !symbol_names.contains(&s.name) {
|
||||
symbol_names.insert(s.name.clone());
|
||||
Some((s.name, s.index))
|
||||
|
||||
Some((s.name, s.index, s.kind))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -565,16 +611,18 @@ where
|
||||
// Global symbols
|
||||
let mut symbol_table = self.global_symbols.iter();
|
||||
while let Some(symbol) = symbol_table.next()? {
|
||||
if let Some(current_symbol_name) = get_symbol_name(&symbol) {
|
||||
if current_symbol_name == symbol_name {
|
||||
return Ok(self
|
||||
.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
)
|
||||
.unwrap_or_default());
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if let Some(current_symbol_name) = get_symbol_name(&symbol_data) {
|
||||
if current_symbol_name == symbol_name {
|
||||
return Ok(self
|
||||
.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
)
|
||||
.unwrap_or_default());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,16 +635,18 @@ where
|
||||
if let Some(module_info) = pdb.module_info(&module)? {
|
||||
let mut module_symbols = module_info.symbols()?;
|
||||
while let Some(symbol) = module_symbols.next()? {
|
||||
if let Some(current_symbol_name) = get_symbol_name(&symbol) {
|
||||
if current_symbol_name == symbol_name {
|
||||
return Ok(self
|
||||
.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
)
|
||||
.unwrap_or_default());
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if let Some(current_symbol_name) = get_symbol_name(&symbol_data) {
|
||||
if current_symbol_name == symbol_name {
|
||||
return Ok(self
|
||||
.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
)
|
||||
.unwrap_or_default());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -629,14 +679,16 @@ where
|
||||
// Global symbols
|
||||
let mut symbol_table = self.global_symbols.iter();
|
||||
while let Some(symbol) = symbol_table.next()? {
|
||||
if get_symbol_name(&symbol).is_some() {
|
||||
if let Some(reconstructed_symbol) = self.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
) {
|
||||
writeln!(&mut reconstruction_output, "{}", reconstructed_symbol)?;
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if get_symbol_name(&symbol_data).is_some() {
|
||||
if let Some(reconstructed_symbol) = self.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
) {
|
||||
writeln!(&mut reconstruction_output, "{}", reconstructed_symbol)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,14 +701,20 @@ where
|
||||
if let Some(module_info) = pdb.module_info(&module)? {
|
||||
let mut module_symbols = module_info.symbols()?;
|
||||
while let Some(symbol) = module_symbols.next()? {
|
||||
if get_symbol_name(&symbol).is_some() {
|
||||
if let Some(reconstructed_symbol) = self.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
) {
|
||||
writeln!(&mut reconstruction_output, "{}", reconstructed_symbol)?;
|
||||
if let Ok(symbol_data) = symbol.parse() {
|
||||
if get_symbol_name(&symbol_data).is_some() {
|
||||
if let Some(reconstructed_symbol) = self.reconstruct_symbol(
|
||||
&type_finder,
|
||||
&symbol,
|
||||
primitives_flavor,
|
||||
print_access_specifiers,
|
||||
) {
|
||||
writeln!(
|
||||
&mut reconstruction_output,
|
||||
"{}",
|
||||
reconstructed_symbol
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1020,7 +1078,7 @@ where
|
||||
|
||||
fn type_list_from_type_indices(&self, type_indices: &[TypeIndex]) -> TypeList {
|
||||
par_iter_if_available!(self.complete_type_list)
|
||||
.filter_map(|(type_name, type_index)| {
|
||||
.filter_map(|(type_name, type_index, _)| {
|
||||
if type_indices.contains(type_index) {
|
||||
Some((type_name.clone(), *type_index))
|
||||
} else {
|
||||
@@ -1236,11 +1294,11 @@ fn compute_type_depth_map(
|
||||
inverted_type_depth_map
|
||||
}
|
||||
|
||||
fn get_symbol_name(symbol: &pdb::Symbol) -> Option<String> {
|
||||
fn get_symbol_name(symbol_data: &pdb::SymbolData) -> Option<String> {
|
||||
const UNNAMED_CONSTANT_PREFIXES: [&str; 5] = ["`", "??_", "__@@_PchSym_", "__real@", "__xmm@"];
|
||||
const UNNAMED_CONSTANT_SUFFIXES: [&str; 1] = ["@@9@9"];
|
||||
|
||||
match symbol.parse().ok()? {
|
||||
match symbol_data {
|
||||
pdb::SymbolData::UserDefinedType(udt) => Some(udt.name.to_string().to_string()),
|
||||
|
||||
// Functions and methods
|
||||
@@ -1277,6 +1335,38 @@ fn get_symbol_name(symbol: &pdb::Symbol) -> Option<String> {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_symbol_type(symbol_data: &pdb::SymbolData) -> SymbolKind {
|
||||
match symbol_data {
|
||||
pdb::SymbolData::UserDefinedType(_) => SymbolKind::Type,
|
||||
|
||||
// Functions and methods
|
||||
pdb::SymbolData::Procedure(_) => SymbolKind::Function,
|
||||
|
||||
// Global variables
|
||||
pdb::SymbolData::Data(_) => SymbolKind::Variable,
|
||||
|
||||
// Public symbols
|
||||
pdb::SymbolData::Public(data) => {
|
||||
if data.function {
|
||||
SymbolKind::Function
|
||||
} else {
|
||||
SymbolKind::Variable
|
||||
}
|
||||
}
|
||||
|
||||
// Exported symbols
|
||||
pdb::SymbolData::Export(data) => {
|
||||
if data.flags.data {
|
||||
SymbolKind::Variable
|
||||
} else {
|
||||
SymbolKind::Function
|
||||
}
|
||||
}
|
||||
|
||||
_ => SymbolKind::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_rva(
|
||||
symbol_offset: &pdb::PdbInternalSectionOffset,
|
||||
sections: &[pdb::ImageSectionHeader],
|
||||
@@ -1314,20 +1404,16 @@ fn demangle_symbol_name(
|
||||
.ok()
|
||||
}
|
||||
|
||||
fn symbol_priority(symbol: &pdb::Symbol) -> u16 {
|
||||
if let Ok(symbol) = symbol.parse() {
|
||||
match symbol {
|
||||
// Functions and methods, user types, global variables
|
||||
pdb::SymbolData::Procedure(_)
|
||||
| pdb::SymbolData::UserDefinedType(_)
|
||||
| pdb::SymbolData::Data(_) => 0,
|
||||
// Public symbols
|
||||
pdb::SymbolData::Public(_) => 1,
|
||||
// Exported symbols
|
||||
pdb::SymbolData::Export(_) => 2,
|
||||
_ => 10,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
fn symbol_priority(symbol_data: &pdb::SymbolData) -> u16 {
|
||||
match symbol_data {
|
||||
// Functions and methods, user types, global variables
|
||||
pdb::SymbolData::Procedure(_)
|
||||
| pdb::SymbolData::UserDefinedType(_)
|
||||
| pdb::SymbolData::Data(_) => 0,
|
||||
// Public symbols
|
||||
pdb::SymbolData::Public(_) => 1,
|
||||
// Exported symbols
|
||||
pdb::SymbolData::Export(_) => 2,
|
||||
_ => 10,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ impl ResymcApp {
|
||||
case_insensitive,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
// TODO(ergrelet): allow users to control these filters
|
||||
Default::default(),
|
||||
))?;
|
||||
// Wait for the backend to finish filtering types
|
||||
if let FrontendCommand::ListTypesResult(type_list) =
|
||||
@@ -491,6 +493,8 @@ impl ResymcApp {
|
||||
case_insensitive,
|
||||
use_regex,
|
||||
ignore_std_types,
|
||||
// TODO(ergrelet): allow users to control these filters
|
||||
Default::default(),
|
||||
))?;
|
||||
// Wait for the backend to finish listing modules
|
||||
if let FrontendCommand::ListSymbolsResult(symbol_list) =
|
||||
|
||||
Reference in New Issue
Block a user