2025-02-20 17:48:00 -07:00
|
|
|
use std::mem::take;
|
2023-08-12 14:18:09 -04:00
|
|
|
|
2022-09-08 17:19:20 -04:00
|
|
|
use egui::{
|
2025-02-02 17:32:08 -07:00
|
|
|
style::ScrollAnimation, text::LayoutJob, CollapsingHeader, Color32, Id, OpenUrl, ScrollArea,
|
|
|
|
|
SelectableLabel, Ui, Widget,
|
2022-09-08 17:19:20 -04:00
|
|
|
};
|
2024-03-18 18:10:18 -06:00
|
|
|
use objdiff_core::{
|
2025-02-20 17:48:00 -07:00
|
|
|
diff::{
|
|
|
|
|
display::{
|
|
|
|
|
display_sections, symbol_context, symbol_hover, ContextMenuItem, HighlightKind,
|
|
|
|
|
HoverItem, HoverItemColor, SectionDisplay, SymbolFilter,
|
|
|
|
|
},
|
|
|
|
|
ObjectDiff, SymbolDiff,
|
2024-10-28 17:54:49 -06:00
|
|
|
},
|
2025-02-20 17:48:00 -07:00
|
|
|
jobs::{create_scratch::CreateScratchResult, objdiff::ObjDiffResult, Job, JobQueue, JobResult},
|
|
|
|
|
obj::{Object, Section, SectionKind, Symbol, SymbolFlag},
|
2024-03-18 18:10:18 -06:00
|
|
|
};
|
2024-07-21 23:01:58 -06:00
|
|
|
use regex::{Regex, RegexBuilder};
|
2022-09-08 17:19:20 -04:00
|
|
|
|
|
|
|
|
use crate::{
|
2024-09-28 10:55:22 -06:00
|
|
|
app::AppStateRef,
|
2024-12-02 23:51:37 -05:00
|
|
|
hotkeys,
|
2024-10-11 18:37:14 -06:00
|
|
|
jobs::{is_create_scratch_available, start_create_scratch},
|
2025-02-02 17:32:08 -07:00
|
|
|
views::{appearance::Appearance, function_diff::FunctionViewState, write_text},
|
2022-09-08 17:19:20 -04:00
|
|
|
};
|
|
|
|
|
|
2025-02-02 17:32:08 -07:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
2024-03-18 18:10:18 -06:00
|
|
|
pub struct SymbolRefByName {
|
2023-08-09 21:53:04 -04:00
|
|
|
pub symbol_name: String,
|
2024-10-09 21:44:18 -06:00
|
|
|
pub section_name: Option<String>,
|
2023-08-09 21:53:04 -04:00
|
|
|
}
|
|
|
|
|
|
2024-10-09 21:44:18 -06:00
|
|
|
impl SymbolRefByName {
|
2025-02-20 17:48:00 -07:00
|
|
|
pub fn new(symbol: &Symbol, section: Option<&Section>) -> Self {
|
2024-10-09 21:44:18 -06:00
|
|
|
Self { symbol_name: symbol.name.clone(), section_name: section.map(|s| s.name.clone()) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[expect(clippy::enum_variant_names)]
|
|
|
|
|
#[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Hash)]
|
2023-08-09 21:53:04 -04:00
|
|
|
pub enum View {
|
|
|
|
|
#[default]
|
|
|
|
|
SymbolDiff,
|
|
|
|
|
FunctionDiff,
|
|
|
|
|
DataDiff,
|
2024-07-22 00:25:54 -04:00
|
|
|
ExtabDiff,
|
2023-08-09 21:53:04 -04:00
|
|
|
}
|
|
|
|
|
|
2024-10-09 21:44:18 -06:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum DiffViewAction {
|
|
|
|
|
/// Queue a rebuild of the current object(s)
|
|
|
|
|
Build,
|
|
|
|
|
/// Navigate to a new diff view
|
|
|
|
|
Navigate(DiffViewNavigation),
|
2024-12-02 23:51:37 -05:00
|
|
|
/// Set the highlighted symbols in the symbols view, optionally scrolling them into view.
|
2025-02-20 17:48:00 -07:00
|
|
|
SetSymbolHighlight(Option<usize>, Option<usize>, bool),
|
2024-10-09 21:44:18 -06:00
|
|
|
/// Set the symbols view search filter
|
|
|
|
|
SetSearch(String),
|
|
|
|
|
/// Submit the current function to decomp.me
|
|
|
|
|
CreateScratch(String),
|
|
|
|
|
/// Open the source path of the current object
|
|
|
|
|
OpenSourcePath,
|
|
|
|
|
/// Set the highlight for a diff column
|
|
|
|
|
SetDiffHighlight(usize, HighlightKind),
|
|
|
|
|
/// Clear the highlight for all diff columns
|
|
|
|
|
ClearDiffHighlight,
|
|
|
|
|
/// Start selecting a left symbol for mapping.
|
|
|
|
|
/// The symbol reference is the right symbol to map to.
|
|
|
|
|
SelectingLeft(SymbolRefByName),
|
|
|
|
|
/// Start selecting a right symbol for mapping.
|
|
|
|
|
/// The symbol reference is the left symbol to map to.
|
|
|
|
|
SelectingRight(SymbolRefByName),
|
|
|
|
|
/// Set a symbol mapping.
|
|
|
|
|
SetMapping(View, SymbolRefByName, SymbolRefByName),
|
|
|
|
|
/// Set the show_mapped_symbols flag
|
|
|
|
|
SetShowMappedSymbols(bool),
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-02 17:32:08 -07:00
|
|
|
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
2024-10-09 21:44:18 -06:00
|
|
|
pub struct DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
pub view: View,
|
2024-10-09 21:44:18 -06:00
|
|
|
pub left_symbol: Option<SymbolRefByName>,
|
|
|
|
|
pub right_symbol: Option<SymbolRefByName>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DiffViewNavigation {
|
|
|
|
|
pub fn symbol_diff() -> Self {
|
2025-02-02 17:32:08 -07:00
|
|
|
Self { view: View::SymbolDiff, left_symbol: None, right_symbol: None }
|
2024-10-09 21:44:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_symbols(
|
|
|
|
|
view: View,
|
|
|
|
|
other_ctx: Option<SymbolDiffContext<'_>>,
|
2025-02-20 17:48:00 -07:00
|
|
|
symbol: &Symbol,
|
|
|
|
|
section: &Section,
|
|
|
|
|
symbol_diff: &SymbolDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
column: usize,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let symbol1 = Some(SymbolRefByName::new(symbol, Some(section)));
|
|
|
|
|
let symbol2 = symbol_diff.target_symbol.and_then(|symbol_ref| {
|
|
|
|
|
other_ctx.map(|ctx| {
|
2025-02-20 17:48:00 -07:00
|
|
|
let symbol = &ctx.obj.symbols[symbol_ref];
|
|
|
|
|
let section =
|
|
|
|
|
symbol.section.and_then(|section_idx| ctx.obj.sections.get(section_idx));
|
2024-10-09 21:44:18 -06:00
|
|
|
SymbolRefByName::new(symbol, section)
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
match column {
|
2025-02-02 17:32:08 -07:00
|
|
|
0 => Self { view, left_symbol: symbol1, right_symbol: symbol2 },
|
|
|
|
|
1 => Self { view, left_symbol: symbol2, right_symbol: symbol1 },
|
|
|
|
|
_ => unreachable!("Invalid column index"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
pub fn data_diff(section: &Section, column: usize) -> Self {
|
2025-02-02 17:32:08 -07:00
|
|
|
let symbol = Some(SymbolRefByName {
|
|
|
|
|
symbol_name: "".to_string(),
|
|
|
|
|
section_name: Some(section.name.clone()),
|
|
|
|
|
});
|
|
|
|
|
match column {
|
|
|
|
|
0 => Self {
|
|
|
|
|
view: View::DataDiff,
|
|
|
|
|
left_symbol: symbol.clone(),
|
|
|
|
|
right_symbol: symbol.clone(),
|
|
|
|
|
},
|
|
|
|
|
1 => Self { view: View::DataDiff, left_symbol: symbol.clone(), right_symbol: symbol },
|
2024-10-09 21:44:18 -06:00
|
|
|
_ => unreachable!("Invalid column index"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 21:53:04 -04:00
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct DiffViewState {
|
|
|
|
|
pub build: Option<Box<ObjDiffResult>>,
|
2024-01-20 22:53:40 -07:00
|
|
|
pub scratch: Option<Box<CreateScratchResult>>,
|
2023-08-09 21:53:04 -04:00
|
|
|
pub current_view: View,
|
2023-08-12 14:18:09 -04:00
|
|
|
pub symbol_state: SymbolViewState,
|
2023-10-05 23:40:45 -04:00
|
|
|
pub function_state: FunctionViewState,
|
2023-08-12 14:18:09 -04:00
|
|
|
pub search: String,
|
2024-07-21 23:01:58 -06:00
|
|
|
pub search_regex: Option<Regex>,
|
2023-08-12 14:18:09 -04:00
|
|
|
pub build_running: bool,
|
2024-01-20 22:53:40 -07:00
|
|
|
pub scratch_available: bool,
|
|
|
|
|
pub scratch_running: bool,
|
2024-09-28 10:55:25 -06:00
|
|
|
pub source_path_available: bool,
|
2024-10-09 21:44:18 -06:00
|
|
|
pub post_build_nav: Option<DiffViewNavigation>,
|
|
|
|
|
pub object_name: String,
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct SymbolViewState {
|
2025-02-20 17:48:00 -07:00
|
|
|
pub highlighted_symbol: (Option<usize>, Option<usize>),
|
2024-12-02 23:51:37 -05:00
|
|
|
pub autoscroll_to_highlighted_symbols: bool,
|
2024-10-09 21:44:18 -06:00
|
|
|
pub left_symbol: Option<SymbolRefByName>,
|
|
|
|
|
pub right_symbol: Option<SymbolRefByName>,
|
2023-08-12 14:18:09 -04:00
|
|
|
pub reverse_fn_order: bool,
|
|
|
|
|
pub disable_reverse_fn_order: bool,
|
2023-10-07 13:27:12 -04:00
|
|
|
pub show_hidden_symbols: bool,
|
2024-10-09 21:44:18 -06:00
|
|
|
pub show_mapped_symbols: bool,
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DiffViewState {
|
2024-09-28 10:55:22 -06:00
|
|
|
pub fn pre_update(&mut self, jobs: &mut JobQueue, state: &AppStateRef) {
|
2024-01-20 22:53:40 -07:00
|
|
|
jobs.results.retain_mut(|result| match result {
|
|
|
|
|
JobResult::ObjDiff(result) => {
|
2023-08-12 14:18:09 -04:00
|
|
|
self.build = take(result);
|
2024-10-09 21:44:18 -06:00
|
|
|
|
|
|
|
|
// TODO: where should this go?
|
|
|
|
|
if let Some(result) = self.post_build_nav.take() {
|
2025-02-02 17:32:08 -07:00
|
|
|
self.current_view = result.view;
|
2024-10-09 21:44:18 -06:00
|
|
|
self.symbol_state.left_symbol = result.left_symbol;
|
|
|
|
|
self.symbol_state.right_symbol = result.right_symbol;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 14:18:09 -04:00
|
|
|
false
|
|
|
|
|
}
|
2024-01-20 22:53:40 -07:00
|
|
|
JobResult::CreateScratch(result) => {
|
|
|
|
|
self.scratch = take(result);
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
_ => true,
|
2023-08-12 14:18:09 -04:00
|
|
|
});
|
|
|
|
|
self.build_running = jobs.is_running(Job::ObjDiff);
|
2024-01-20 22:53:40 -07:00
|
|
|
self.scratch_running = jobs.is_running(Job::CreateScratch);
|
2023-08-12 14:18:09 -04:00
|
|
|
|
|
|
|
|
self.symbol_state.disable_reverse_fn_order = false;
|
2024-09-28 10:55:22 -06:00
|
|
|
if let Ok(state) = state.read() {
|
|
|
|
|
if let Some(obj_config) = &state.config.selected_obj {
|
2023-09-03 09:28:22 -04:00
|
|
|
if let Some(value) = obj_config.reverse_fn_order {
|
|
|
|
|
self.symbol_state.reverse_fn_order = value;
|
|
|
|
|
self.symbol_state.disable_reverse_fn_order = true;
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
2024-09-28 10:55:25 -06:00
|
|
|
self.source_path_available = obj_config.source_path.is_some();
|
|
|
|
|
} else {
|
|
|
|
|
self.source_path_available = false;
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
2024-10-11 18:37:14 -06:00
|
|
|
self.scratch_available = is_create_scratch_available(&state.config);
|
2024-10-09 21:44:18 -06:00
|
|
|
self.object_name =
|
|
|
|
|
state.config.selected_obj.as_ref().map(|o| o.name.clone()).unwrap_or_default();
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-09 21:44:18 -06:00
|
|
|
pub fn post_update(
|
|
|
|
|
&mut self,
|
|
|
|
|
action: Option<DiffViewAction>,
|
|
|
|
|
ctx: &egui::Context,
|
|
|
|
|
jobs: &mut JobQueue,
|
|
|
|
|
state: &AppStateRef,
|
|
|
|
|
) {
|
2024-01-20 22:53:40 -07:00
|
|
|
if let Some(result) = take(&mut self.scratch) {
|
|
|
|
|
ctx.output_mut(|o| o.open_url = Some(OpenUrl::new_tab(result.scratch_url)));
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-02 23:51:37 -05:00
|
|
|
// Clear the autoscroll flag so that it doesn't scroll continuously.
|
|
|
|
|
self.symbol_state.autoscroll_to_highlighted_symbols = false;
|
|
|
|
|
|
2024-10-09 21:44:18 -06:00
|
|
|
let Some(action) = action else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
match action {
|
|
|
|
|
DiffViewAction::Build => {
|
|
|
|
|
if let Ok(mut state) = state.write() {
|
|
|
|
|
state.queue_build = true;
|
|
|
|
|
}
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
2024-10-09 21:44:18 -06:00
|
|
|
DiffViewAction::Navigate(nav) => {
|
|
|
|
|
if self.post_build_nav.is_some() {
|
|
|
|
|
// Ignore action if we're already navigating
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let Ok(mut state) = state.write() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
if (nav.left_symbol.is_some() && nav.right_symbol.is_some())
|
|
|
|
|
|| (nav.left_symbol.is_none() && nav.right_symbol.is_none())
|
2025-02-02 17:32:08 -07:00
|
|
|
|| nav.view != View::FunctionDiff
|
2024-10-09 21:44:18 -06:00
|
|
|
{
|
|
|
|
|
// Regular navigation
|
|
|
|
|
if state.is_selecting_symbol() {
|
|
|
|
|
// Cancel selection and reload
|
|
|
|
|
state.clear_selection();
|
|
|
|
|
self.post_build_nav = Some(nav);
|
|
|
|
|
} else {
|
|
|
|
|
// Navigate immediately
|
2025-02-02 17:32:08 -07:00
|
|
|
self.current_view = nav.view;
|
2024-10-09 21:44:18 -06:00
|
|
|
self.symbol_state.left_symbol = nav.left_symbol;
|
|
|
|
|
self.symbol_state.right_symbol = nav.right_symbol;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Enter selection mode
|
|
|
|
|
match (&nav.left_symbol, &nav.right_symbol) {
|
|
|
|
|
(Some(left_ref), None) => {
|
|
|
|
|
state.set_selecting_right(&left_ref.symbol_name);
|
2024-01-20 22:53:40 -07:00
|
|
|
}
|
2024-10-09 21:44:18 -06:00
|
|
|
(None, Some(right_ref)) => {
|
|
|
|
|
state.set_selecting_left(&right_ref.symbol_name);
|
|
|
|
|
}
|
|
|
|
|
(Some(_), Some(_)) => unreachable!(),
|
|
|
|
|
(None, None) => unreachable!(),
|
|
|
|
|
}
|
|
|
|
|
self.post_build_nav = Some(nav);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-02 23:51:37 -05:00
|
|
|
DiffViewAction::SetSymbolHighlight(left, right, autoscroll) => {
|
2024-10-09 21:44:18 -06:00
|
|
|
self.symbol_state.highlighted_symbol = (left, right);
|
2024-12-02 23:51:37 -05:00
|
|
|
self.symbol_state.autoscroll_to_highlighted_symbols = autoscroll;
|
2024-10-09 21:44:18 -06:00
|
|
|
}
|
|
|
|
|
DiffViewAction::SetSearch(search) => {
|
|
|
|
|
self.search_regex = if search.is_empty() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
2025-02-07 00:15:21 -07:00
|
|
|
RegexBuilder::new(&search).case_insensitive(true).build().ok()
|
2024-10-09 21:44:18 -06:00
|
|
|
};
|
|
|
|
|
self.search = search;
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::CreateScratch(function_name) => {
|
|
|
|
|
let Ok(state) = state.read() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
2024-10-11 18:37:14 -06:00
|
|
|
start_create_scratch(ctx, jobs, &state, function_name);
|
2024-01-20 22:53:40 -07:00
|
|
|
}
|
2024-10-09 21:44:18 -06:00
|
|
|
DiffViewAction::OpenSourcePath => {
|
|
|
|
|
let Ok(state) = state.read() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
2025-02-07 00:10:49 -07:00
|
|
|
if let Some(source_path) =
|
|
|
|
|
state.config.selected_obj.as_ref().and_then(|obj| obj.source_path.as_ref())
|
|
|
|
|
{
|
|
|
|
|
log::info!("Opening file {}", source_path);
|
2025-02-09 11:11:09 -07:00
|
|
|
open::that_detached(source_path.as_str()).unwrap_or_else(|err| {
|
2024-09-28 10:55:25 -06:00
|
|
|
log::error!("Failed to open source file: {err}");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-09 21:44:18 -06:00
|
|
|
DiffViewAction::SetDiffHighlight(column, kind) => {
|
|
|
|
|
self.function_state.set_highlight(column, kind);
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::ClearDiffHighlight => {
|
|
|
|
|
self.function_state.clear_highlight();
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::SelectingLeft(right_ref) => {
|
|
|
|
|
if self.post_build_nav.is_some() {
|
|
|
|
|
// Ignore action if we're already navigating
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let Ok(mut state) = state.write() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
state.set_selecting_left(&right_ref.symbol_name);
|
|
|
|
|
self.post_build_nav = Some(DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
view: View::FunctionDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
left_symbol: None,
|
|
|
|
|
right_symbol: Some(right_ref),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::SelectingRight(left_ref) => {
|
|
|
|
|
if self.post_build_nav.is_some() {
|
|
|
|
|
// Ignore action if we're already navigating
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let Ok(mut state) = state.write() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
state.set_selecting_right(&left_ref.symbol_name);
|
|
|
|
|
self.post_build_nav = Some(DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
view: View::FunctionDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
left_symbol: Some(left_ref),
|
|
|
|
|
right_symbol: None,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::SetMapping(view, left_ref, right_ref) => {
|
|
|
|
|
if self.post_build_nav.is_some() {
|
|
|
|
|
// Ignore action if we're already navigating
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let Ok(mut state) = state.write() else {
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
state.set_symbol_mapping(
|
|
|
|
|
left_ref.symbol_name.clone(),
|
|
|
|
|
right_ref.symbol_name.clone(),
|
|
|
|
|
);
|
|
|
|
|
if view == View::SymbolDiff {
|
|
|
|
|
self.post_build_nav = Some(DiffViewNavigation::symbol_diff());
|
|
|
|
|
} else {
|
|
|
|
|
self.post_build_nav = Some(DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
view,
|
2024-10-09 21:44:18 -06:00
|
|
|
left_symbol: Some(left_ref),
|
|
|
|
|
right_symbol: Some(right_ref),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DiffViewAction::SetShowMappedSymbols(value) => {
|
|
|
|
|
self.symbol_state.show_mapped_symbols = value;
|
|
|
|
|
}
|
2024-09-28 10:55:25 -06:00
|
|
|
}
|
2023-08-12 14:18:09 -04:00
|
|
|
}
|
2023-08-09 21:53:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Color32 {
|
2022-12-06 17:53:32 -05:00
|
|
|
if match_percent == 100.0 {
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance.insert_color
|
2022-12-06 17:53:32 -05:00
|
|
|
} else if match_percent >= 50.0 {
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance.replace_color
|
2022-09-08 17:19:20 -04:00
|
|
|
} else {
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance.delete_color
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-22 00:25:54 -04:00
|
|
|
fn symbol_context_menu_ui(
|
|
|
|
|
ui: &mut Ui,
|
2024-10-09 21:44:18 -06:00
|
|
|
ctx: SymbolDiffContext<'_>,
|
|
|
|
|
other_ctx: Option<SymbolDiffContext<'_>>,
|
2025-02-20 17:48:00 -07:00
|
|
|
symbol: &Symbol,
|
|
|
|
|
symbol_diff: &SymbolDiff,
|
|
|
|
|
section: Option<&Section>,
|
2024-10-09 21:44:18 -06:00
|
|
|
column: usize,
|
|
|
|
|
) -> Option<DiffViewNavigation> {
|
2024-09-09 19:43:10 -06:00
|
|
|
let mut ret = None;
|
2022-09-14 13:12:45 -04:00
|
|
|
ui.scope(|ui| {
|
|
|
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
2024-09-09 19:26:46 -06:00
|
|
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
2022-09-14 13:12:45 -04:00
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
for item in symbol_context(ctx.obj, symbol) {
|
|
|
|
|
match item {
|
|
|
|
|
ContextMenuItem::Copy { value, label } => {
|
|
|
|
|
let label = if let Some(extra) = label {
|
|
|
|
|
format!("Copy \"{value}\" ({extra})")
|
|
|
|
|
} else {
|
|
|
|
|
format!("Copy \"{value}\"")
|
|
|
|
|
};
|
|
|
|
|
if ui.button(label).clicked() {
|
|
|
|
|
ui.output_mut(|output| output.copied_text = value);
|
|
|
|
|
ui.close_menu();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ContextMenuItem::Navigate { label } => {
|
|
|
|
|
if ui.button(label).clicked() {
|
|
|
|
|
// TODO other navigation
|
|
|
|
|
ret = Some(DiffViewNavigation::with_symbols(
|
|
|
|
|
View::ExtabDiff,
|
|
|
|
|
other_ctx,
|
|
|
|
|
symbol,
|
|
|
|
|
section.unwrap(),
|
|
|
|
|
symbol_diff,
|
|
|
|
|
column,
|
|
|
|
|
));
|
|
|
|
|
ui.close_menu();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-14 13:12:45 -04:00
|
|
|
}
|
|
|
|
|
}
|
2024-10-09 21:44:18 -06:00
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
if let Some(section) = section {
|
2024-10-09 21:44:18 -06:00
|
|
|
if ui.button("Map symbol").clicked() {
|
|
|
|
|
let symbol_ref = SymbolRefByName::new(symbol, Some(section));
|
|
|
|
|
if column == 0 {
|
|
|
|
|
ret = Some(DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
view: View::FunctionDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
left_symbol: Some(symbol_ref),
|
|
|
|
|
right_symbol: None,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
ret = Some(DiffViewNavigation {
|
2025-02-02 17:32:08 -07:00
|
|
|
view: View::FunctionDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
left_symbol: None,
|
|
|
|
|
right_symbol: Some(symbol_ref),
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-07-22 00:25:54 -04:00
|
|
|
ui.close_menu();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-14 13:12:45 -04:00
|
|
|
});
|
2024-09-09 19:43:10 -06:00
|
|
|
ret
|
2022-09-14 13:12:45 -04:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
fn symbol_hover_ui(
|
|
|
|
|
ui: &mut Ui,
|
|
|
|
|
ctx: SymbolDiffContext<'_>,
|
|
|
|
|
symbol: &Symbol,
|
|
|
|
|
appearance: &Appearance,
|
|
|
|
|
) {
|
2022-09-14 13:12:45 -04:00
|
|
|
ui.scope(|ui| {
|
|
|
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
2024-09-09 19:26:46 -06:00
|
|
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
2022-09-14 13:12:45 -04:00
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
for HoverItem { text, color } in symbol_hover(ctx.obj, symbol) {
|
|
|
|
|
let color = match color {
|
|
|
|
|
HoverItemColor::Normal => appearance.text_color,
|
|
|
|
|
HoverItemColor::Emphasized => appearance.highlight_color,
|
|
|
|
|
HoverItemColor::Special => appearance.replace_color,
|
|
|
|
|
};
|
|
|
|
|
ui.colored_label(color, text);
|
2024-07-22 00:25:54 -04:00
|
|
|
}
|
2022-09-14 13:12:45 -04:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 14:18:09 -04:00
|
|
|
#[must_use]
|
2022-09-08 17:19:20 -04:00
|
|
|
fn symbol_ui(
|
|
|
|
|
ui: &mut Ui,
|
2024-10-09 21:44:18 -06:00
|
|
|
ctx: SymbolDiffContext<'_>,
|
|
|
|
|
other_ctx: Option<SymbolDiffContext<'_>>,
|
2025-02-20 17:48:00 -07:00
|
|
|
symbol: &Symbol,
|
|
|
|
|
symbol_diff: &SymbolDiff,
|
|
|
|
|
symbol_idx: usize,
|
|
|
|
|
section: Option<&Section>,
|
2024-10-09 21:44:18 -06:00
|
|
|
state: &SymbolViewState,
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance: &Appearance,
|
2024-10-09 21:44:18 -06:00
|
|
|
column: usize,
|
|
|
|
|
) -> Option<DiffViewAction> {
|
2023-08-12 14:18:09 -04:00
|
|
|
let mut ret = None;
|
2022-09-08 17:19:20 -04:00
|
|
|
let mut job = LayoutJob::default();
|
|
|
|
|
let name: &str =
|
|
|
|
|
if let Some(demangled) = &symbol.demangled_name { demangled } else { &symbol.name };
|
|
|
|
|
let mut selected = false;
|
2024-05-20 23:52:59 -06:00
|
|
|
if let Some(sym_ref) =
|
2024-10-09 21:44:18 -06:00
|
|
|
if column == 0 { state.highlighted_symbol.0 } else { state.highlighted_symbol.1 }
|
2024-05-20 23:52:59 -06:00
|
|
|
{
|
2025-02-20 17:48:00 -07:00
|
|
|
selected = symbol_idx == sym_ref;
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
if !symbol.flags.is_empty() {
|
2024-08-11 14:27:27 -06:00
|
|
|
write_text("[", appearance.text_color, &mut job, appearance.code_font.clone());
|
2025-02-20 17:48:00 -07:00
|
|
|
if symbol.flags.contains(SymbolFlag::Common) {
|
2024-08-11 14:27:27 -06:00
|
|
|
write_text("c", appearance.replace_color, &mut job, appearance.code_font.clone());
|
2025-02-20 17:48:00 -07:00
|
|
|
} else if symbol.flags.contains(SymbolFlag::Global) {
|
2024-08-11 14:27:27 -06:00
|
|
|
write_text("g", appearance.insert_color, &mut job, appearance.code_font.clone());
|
2025-02-20 17:48:00 -07:00
|
|
|
} else if symbol.flags.contains(SymbolFlag::Local) {
|
2024-08-11 14:27:27 -06:00
|
|
|
write_text("l", appearance.text_color, &mut job, appearance.code_font.clone());
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
if symbol.flags.contains(SymbolFlag::Weak) {
|
2024-08-11 14:27:27 -06:00
|
|
|
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
if symbol.flags.contains(SymbolFlag::HasExtra) {
|
2024-09-09 19:43:10 -06:00
|
|
|
write_text("e", appearance.text_color, &mut job, appearance.code_font.clone());
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
if symbol.flags.contains(SymbolFlag::Hidden) {
|
2024-08-11 14:29:58 -06:00
|
|
|
write_text(
|
|
|
|
|
"h",
|
|
|
|
|
appearance.deemphasized_text_color,
|
|
|
|
|
&mut job,
|
|
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
);
|
2024-08-11 14:27:27 -06:00
|
|
|
}
|
|
|
|
|
write_text("] ", appearance.text_color, &mut job, appearance.code_font.clone());
|
2022-09-11 13:52:55 -04:00
|
|
|
}
|
2024-03-18 18:10:18 -06:00
|
|
|
if let Some(match_percent) = symbol_diff.match_percent {
|
2023-08-09 21:53:04 -04:00
|
|
|
write_text("(", appearance.text_color, &mut job, appearance.code_font.clone());
|
2023-07-15 11:17:59 -04:00
|
|
|
write_text(
|
2024-10-07 20:17:56 -06:00
|
|
|
&format!("{:.0}%", match_percent.floor()),
|
2023-08-09 21:53:04 -04:00
|
|
|
match_color_for_symbol(match_percent, appearance),
|
2023-07-15 11:17:59 -04:00
|
|
|
&mut job,
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance.code_font.clone(),
|
2023-07-15 11:17:59 -04:00
|
|
|
);
|
2023-08-09 21:53:04 -04:00
|
|
|
write_text(") ", appearance.text_color, &mut job, appearance.code_font.clone());
|
2023-07-15 11:17:59 -04:00
|
|
|
}
|
2023-08-09 21:53:04 -04:00
|
|
|
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
|
2025-02-20 17:48:00 -07:00
|
|
|
let response = SelectableLabel::new(selected, job)
|
|
|
|
|
.ui(ui)
|
|
|
|
|
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, ctx, symbol, appearance));
|
2024-09-09 19:43:10 -06:00
|
|
|
response.context_menu(|ui| {
|
2024-10-09 21:44:18 -06:00
|
|
|
if let Some(result) =
|
|
|
|
|
symbol_context_menu_ui(ui, ctx, other_ctx, symbol, symbol_diff, section, column)
|
|
|
|
|
{
|
|
|
|
|
ret = Some(DiffViewAction::Navigate(result));
|
|
|
|
|
}
|
2024-09-09 19:43:10 -06:00
|
|
|
});
|
2024-12-02 23:51:37 -05:00
|
|
|
if selected && state.autoscroll_to_highlighted_symbols {
|
|
|
|
|
// Automatically scroll the view to encompass the selected symbol in case the user selected
|
|
|
|
|
// an offscreen symbol by using a keyboard shortcut.
|
|
|
|
|
ui.scroll_to_rect_animation(response.rect, None, ScrollAnimation::none());
|
|
|
|
|
// This autoscroll state flag will be reset in DiffViewState::post_update at the end of
|
|
|
|
|
// every frame so that we don't continuously scroll the view back when the user is trying to
|
|
|
|
|
// manually scroll away.
|
|
|
|
|
}
|
|
|
|
|
if response.clicked() || (selected && hotkeys::enter_pressed(ui.ctx())) {
|
2022-12-10 20:28:01 -05:00
|
|
|
if let Some(section) = section {
|
2024-10-09 21:44:18 -06:00
|
|
|
match section.kind {
|
2025-02-20 17:48:00 -07:00
|
|
|
SectionKind::Code => {
|
2024-10-09 21:44:18 -06:00
|
|
|
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::with_symbols(
|
|
|
|
|
View::FunctionDiff,
|
|
|
|
|
other_ctx,
|
|
|
|
|
symbol,
|
|
|
|
|
section,
|
|
|
|
|
symbol_diff,
|
|
|
|
|
column,
|
|
|
|
|
)));
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
SectionKind::Data => {
|
2025-02-02 17:32:08 -07:00
|
|
|
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::data_diff(
|
|
|
|
|
section, column,
|
2024-10-09 21:44:18 -06:00
|
|
|
)));
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
_ => {}
|
2022-11-06 00:49:46 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-08 17:19:20 -04:00
|
|
|
} else if response.hovered() {
|
2024-12-02 23:51:37 -05:00
|
|
|
ret = Some(if column == 0 {
|
2025-02-20 17:48:00 -07:00
|
|
|
DiffViewAction::SetSymbolHighlight(Some(symbol_idx), symbol_diff.target_symbol, false)
|
2024-05-20 23:52:59 -06:00
|
|
|
} else {
|
2025-02-20 17:48:00 -07:00
|
|
|
DiffViewAction::SetSymbolHighlight(symbol_diff.target_symbol, Some(symbol_idx), false)
|
2024-10-09 21:44:18 -06:00
|
|
|
});
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
2023-08-12 14:18:09 -04:00
|
|
|
ret
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
fn find_prev_symbol(section_display: &[SectionDisplay], current: usize) -> Option<usize> {
|
|
|
|
|
section_display
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|s| s.symbols.iter())
|
|
|
|
|
.rev()
|
|
|
|
|
.skip_while(|s| s.symbol != current)
|
|
|
|
|
.nth(1)
|
|
|
|
|
.map(|s| s.symbol)
|
|
|
|
|
// Wrap around to the last symbol if we're at the beginning of the list
|
|
|
|
|
.or_else(|| find_last_symbol(section_display))
|
2022-09-20 18:19:44 -04:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
fn find_next_symbol(section_display: &[SectionDisplay], current: usize) -> Option<usize> {
|
|
|
|
|
section_display
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|s| s.symbols.iter())
|
|
|
|
|
.skip_while(|s| s.symbol != current)
|
|
|
|
|
.nth(1)
|
|
|
|
|
.map(|s| s.symbol)
|
|
|
|
|
// Wrap around to the first symbol if we're at the end of the list
|
|
|
|
|
.or_else(|| find_first_symbol(section_display))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_first_symbol(section_display: &[SectionDisplay]) -> Option<usize> {
|
|
|
|
|
section_display.iter().flat_map(|s| s.symbols.iter()).next().map(|s| s.symbol)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_last_symbol(section_display: &[SectionDisplay]) -> Option<usize> {
|
|
|
|
|
section_display.iter().flat_map(|s| s.symbols.iter()).next_back().map(|s| s.symbol)
|
2024-10-09 21:44:18 -06:00
|
|
|
}
|
|
|
|
|
|
2023-08-12 14:18:09 -04:00
|
|
|
#[must_use]
|
2024-10-09 21:44:18 -06:00
|
|
|
pub fn symbol_list_ui(
|
2022-09-08 17:19:20 -04:00
|
|
|
ui: &mut Ui,
|
2024-10-09 21:44:18 -06:00
|
|
|
ctx: SymbolDiffContext<'_>,
|
|
|
|
|
other_ctx: Option<SymbolDiffContext<'_>>,
|
|
|
|
|
state: &SymbolViewState,
|
|
|
|
|
filter: SymbolFilter<'_>,
|
2023-08-09 21:53:04 -04:00
|
|
|
appearance: &Appearance,
|
2024-10-09 21:44:18 -06:00
|
|
|
column: usize,
|
2025-01-01 22:48:25 -05:00
|
|
|
open_sections: Option<bool>,
|
2024-10-09 21:44:18 -06:00
|
|
|
) -> Option<DiffViewAction> {
|
2023-08-12 14:18:09 -04:00
|
|
|
let mut ret = None;
|
2022-09-08 17:19:20 -04:00
|
|
|
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
|
2025-02-20 17:48:00 -07:00
|
|
|
let mut show_mapped_symbols = state.show_mapped_symbols;
|
2025-02-02 17:32:08 -07:00
|
|
|
if let SymbolFilter::Mapping(_, _) = filter {
|
2024-10-09 21:44:18 -06:00
|
|
|
if ui.checkbox(&mut show_mapped_symbols, "Show mapped symbols").changed() {
|
|
|
|
|
ret = Some(DiffViewAction::SetShowMappedSymbols(show_mapped_symbols));
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
let section_display = display_sections(
|
|
|
|
|
ctx.obj,
|
|
|
|
|
ctx.diff,
|
|
|
|
|
filter,
|
|
|
|
|
state.show_hidden_symbols,
|
|
|
|
|
show_mapped_symbols,
|
|
|
|
|
state.reverse_fn_order,
|
|
|
|
|
);
|
2024-10-09 21:44:18 -06:00
|
|
|
|
2024-12-02 23:51:37 -05:00
|
|
|
hotkeys::check_scroll_hotkeys(ui, false);
|
|
|
|
|
|
|
|
|
|
let mut new_key_value_to_highlight = None;
|
|
|
|
|
if let Some(sym_ref) =
|
|
|
|
|
if column == 0 { state.highlighted_symbol.0 } else { state.highlighted_symbol.1 }
|
|
|
|
|
{
|
|
|
|
|
let up = if hotkeys::consume_up_key(ui.ctx()) {
|
|
|
|
|
Some(true)
|
|
|
|
|
} else if hotkeys::consume_down_key(ui.ctx()) {
|
|
|
|
|
Some(false)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2025-02-20 17:48:00 -07:00
|
|
|
if let Some(up) = up {
|
2024-12-02 23:51:37 -05:00
|
|
|
new_key_value_to_highlight = if up {
|
2025-02-20 17:48:00 -07:00
|
|
|
find_prev_symbol(§ion_display, sym_ref)
|
2024-12-02 23:51:37 -05:00
|
|
|
} else {
|
2025-02-20 17:48:00 -07:00
|
|
|
find_next_symbol(§ion_display, sym_ref)
|
2024-12-02 23:51:37 -05:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
// No symbol is highlighted in this column. Select the topmost symbol instead.
|
|
|
|
|
// Note that we intentionally do not consume the up/down key presses in this case, but
|
|
|
|
|
// we do when a symbol is highlighted. This is so that if only one column has a symbol
|
|
|
|
|
// highlighted, that one takes precedence over the one with nothing highlighted.
|
|
|
|
|
if hotkeys::up_pressed(ui.ctx()) || hotkeys::down_pressed(ui.ctx()) {
|
2025-02-20 17:48:00 -07:00
|
|
|
new_key_value_to_highlight = find_first_symbol(§ion_display);
|
2024-12-02 23:51:37 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 17:48:00 -07:00
|
|
|
if let Some(new_sym_ref) = new_key_value_to_highlight {
|
|
|
|
|
let target_symbol = ctx.diff.symbols[new_sym_ref].target_symbol;
|
2024-12-02 23:51:37 -05:00
|
|
|
ret = Some(if column == 0 {
|
2025-02-20 17:48:00 -07:00
|
|
|
DiffViewAction::SetSymbolHighlight(Some(new_sym_ref), target_symbol, true)
|
2024-12-02 23:51:37 -05:00
|
|
|
} else {
|
2025-02-20 17:48:00 -07:00
|
|
|
DiffViewAction::SetSymbolHighlight(target_symbol, Some(new_sym_ref), true)
|
2024-12-02 23:51:37 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-08 17:19:20 -04:00
|
|
|
ui.scope(|ui| {
|
|
|
|
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
2024-09-09 19:26:46 -06:00
|
|
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
2022-09-08 17:19:20 -04:00
|
|
|
|
2025-02-20 17:48:00 -07:00
|
|
|
for section_display in section_display {
|
2024-05-21 12:02:00 -06:00
|
|
|
let mut header = LayoutJob::simple_singleline(
|
2025-02-20 17:48:00 -07:00
|
|
|
section_display.name.clone(),
|
2024-05-21 12:02:00 -06:00
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
Color32::PLACEHOLDER,
|
|
|
|
|
);
|
2025-02-20 17:48:00 -07:00
|
|
|
if section_display.size > 0 {
|
|
|
|
|
write_text(
|
|
|
|
|
&format!(" ({:x})", section_display.size),
|
|
|
|
|
Color32::PLACEHOLDER,
|
|
|
|
|
&mut header,
|
|
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if let Some(match_percent) = section_display.match_percent {
|
2024-05-21 12:02:00 -06:00
|
|
|
write_text(
|
|
|
|
|
" (",
|
|
|
|
|
Color32::PLACEHOLDER,
|
|
|
|
|
&mut header,
|
|
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
);
|
|
|
|
|
write_text(
|
2024-10-07 20:17:56 -06:00
|
|
|
&format!("{:.0}%", match_percent.floor()),
|
2024-05-21 12:02:00 -06:00
|
|
|
match_color_for_symbol(match_percent, appearance),
|
|
|
|
|
&mut header,
|
|
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
);
|
|
|
|
|
write_text(
|
|
|
|
|
")",
|
|
|
|
|
Color32::PLACEHOLDER,
|
|
|
|
|
&mut header,
|
|
|
|
|
appearance.code_font.clone(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
CollapsingHeader::new(header)
|
2025-02-20 17:48:00 -07:00
|
|
|
.id_salt(Id::new(§ion_display.id))
|
2022-09-08 17:19:20 -04:00
|
|
|
.default_open(true)
|
2025-01-01 22:48:25 -05:00
|
|
|
.open(open_sections)
|
2022-09-08 17:19:20 -04:00
|
|
|
.show(ui, |ui| {
|
2025-02-20 17:48:00 -07:00
|
|
|
for symbol_display in §ion_display.symbols {
|
|
|
|
|
let symbol = &ctx.obj.symbols[symbol_display.symbol];
|
|
|
|
|
let section = symbol
|
|
|
|
|
.section
|
|
|
|
|
.and_then(|section_idx| ctx.obj.sections.get(section_idx));
|
|
|
|
|
let symbol_diff = if symbol_display.is_mapping_symbol {
|
|
|
|
|
ctx.diff
|
|
|
|
|
.mapping_symbols
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|d| d.symbol_index == symbol_display.symbol)
|
|
|
|
|
.map(|d| &d.symbol_diff)
|
|
|
|
|
.unwrap()
|
|
|
|
|
} else {
|
|
|
|
|
&ctx.diff.symbols[symbol_display.symbol]
|
|
|
|
|
};
|
|
|
|
|
if let Some(result) = symbol_ui(
|
|
|
|
|
ui,
|
|
|
|
|
ctx,
|
|
|
|
|
other_ctx,
|
|
|
|
|
symbol,
|
|
|
|
|
symbol_diff,
|
|
|
|
|
symbol_display.symbol,
|
|
|
|
|
section,
|
|
|
|
|
state,
|
|
|
|
|
appearance,
|
|
|
|
|
column,
|
|
|
|
|
) {
|
|
|
|
|
ret = Some(result);
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
2023-08-12 14:18:09 -04:00
|
|
|
ret
|
2022-09-08 17:19:20 -04:00
|
|
|
}
|
|
|
|
|
|
2024-10-09 21:44:18 -06:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
pub struct SymbolDiffContext<'a> {
|
2025-02-20 17:48:00 -07:00
|
|
|
pub obj: &'a Object,
|
|
|
|
|
pub diff: &'a ObjectDiff,
|
2024-10-09 21:44:18 -06:00
|
|
|
}
|