From 48305e0380ff8260738cadd59eb125d30e8d4907 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 2 Mar 2025 21:51:47 -0700 Subject: [PATCH] Add hover/context APIs to wasm component --- objdiff-wasm/src/api.rs | 157 +++++++++++++++++++++++++++++++++-- objdiff-wasm/wit/objdiff.wit | 62 ++++++++++---- 2 files changed, 194 insertions(+), 25 deletions(-) diff --git a/objdiff-wasm/src/api.rs b/objdiff-wasm/src/api.rs index 591891a..6b886e2 100644 --- a/objdiff-wasm/src/api.rs +++ b/objdiff-wasm/src/api.rs @@ -25,10 +25,11 @@ use exports::objdiff::core::{ GuestObjectDiff, Object, ObjectBorrow, ObjectDiff, ObjectDiffBorrow, }, display::{ - ContextMenuItem, DiffText, DiffTextColor, DiffTextOpcode, DiffTextSegment, DiffTextSymbol, - DisplayConfig, Guest as GuestDisplay, HoverItem, InstructionDiffKind, InstructionDiffRow, - SectionDisplay, SectionDisplaySymbol, SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind, - SymbolRef, + ContextItem, ContextItemCopy, ContextItemNavigate, DiffText, DiffTextColor, DiffTextOpcode, + DiffTextSegment, DiffTextSymbol, DisplayConfig, Guest as GuestDisplay, HoverItem, + HoverItemColor, HoverItemText, InstructionDiffKind, InstructionDiffRow, SectionDisplay, + SectionDisplaySymbol, SymbolDisplay, SymbolFilter, SymbolFlags, SymbolKind, + SymbolNavigationKind, SymbolRef, }, }; @@ -86,10 +87,6 @@ impl GuestDiff for Component { } impl GuestDisplay for Component { - fn symbol_context(_obj: ObjectBorrow, _symbol: SymbolRef) -> Vec { todo!() } - - fn symbol_hover(_obj: ObjectBorrow, _symbol: SymbolRef) -> Vec { todo!() } - fn display_sections( diff: ObjectDiffBorrow, filter: SymbolFilter, @@ -202,6 +199,102 @@ impl GuestDisplay for Component { .unwrap(); InstructionDiffRow { segments, diff_kind: InstructionDiffKind::from(row.kind) } } + + fn symbol_context( + diff: ObjectDiffBorrow, + symbol_display: SectionDisplaySymbol, + ) -> Vec { + let obj_diff = diff.get::(); + let obj = obj_diff.0.as_ref(); + diff::display::symbol_context(obj, symbol_display.symbol as usize) + .into_iter() + .map(|item| ContextItem::from(item)) + .collect() + } + + fn symbol_hover( + diff: ObjectDiffBorrow, + symbol_display: SectionDisplaySymbol, + ) -> Vec { + let obj_diff = diff.get::(); + let obj = obj_diff.0.as_ref(); + diff::display::symbol_hover(obj, symbol_display.symbol as usize, 0 /* TODO */) + .into_iter() + .map(|item| HoverItem::from(item)) + .collect() + } + + fn instruction_context( + diff: ObjectDiffBorrow, + symbol_display: SectionDisplaySymbol, + row_index: u32, + diff_config: DiffConfigBorrow, + ) -> Result, String> { + let obj_diff = diff.get::(); + let obj = obj_diff.0.as_ref(); + let obj_diff = &obj_diff.1; + let symbol_idx = symbol_display.symbol as usize; + let symbol_diff = if symbol_display.is_mapping_symbol { + obj_diff + .mapping_symbols + .iter() + .find(|s| s.symbol_index == symbol_idx) + .map(|s| &s.symbol_diff) + .unwrap() + } else { + &obj_diff.symbols[symbol_idx] + }; + let row = &symbol_diff.instruction_rows[row_index as usize]; + let Some(ins_ref) = row.ins_ref else { + return Ok(Vec::new()); + }; + let diff_config = diff_config.get::().0.borrow(); + let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else { + return Err("Failed to resolve instruction".into()); + }; + let ins = + obj.arch.process_instruction(resolved, &diff_config).map_err(|e| e.to_string())?; + Ok(diff::display::instruction_context(obj, resolved, &ins) + .into_iter() + .map(|item| ContextItem::from(item)) + .collect()) + } + + fn instruction_hover( + diff: ObjectDiffBorrow, + symbol_display: SectionDisplaySymbol, + row_index: u32, + diff_config: DiffConfigBorrow, + ) -> Result, String> { + let obj_diff = diff.get::(); + let obj = obj_diff.0.as_ref(); + let obj_diff = &obj_diff.1; + let symbol_idx = symbol_display.symbol as usize; + let symbol_diff = if symbol_display.is_mapping_symbol { + obj_diff + .mapping_symbols + .iter() + .find(|s| s.symbol_index == symbol_idx) + .map(|s| &s.symbol_diff) + .unwrap() + } else { + &obj_diff.symbols[symbol_idx] + }; + let row = &symbol_diff.instruction_rows[row_index as usize]; + let Some(ins_ref) = row.ins_ref else { + return Ok(Vec::new()); + }; + let diff_config = diff_config.get::().0.borrow(); + let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else { + return Err("Failed to resolve instruction".into()); + }; + let ins = + obj.arch.process_instruction(resolved, &diff_config).map_err(|e| e.to_string())?; + Ok(diff::display::instruction_hover(obj, resolved, &ins) + .into_iter() + .map(|item| HoverItem::from(item)) + .collect()) + } } impl From for SymbolKind { @@ -342,4 +435,52 @@ impl GuestObjectDiff for ResourceObjectDiff { } } +impl From for HoverItem { + fn from(item: diff::display::HoverItem) -> Self { + match item { + diff::display::HoverItem::Text { label, value, color } => { + HoverItem::Text(HoverItemText { label, value, color: HoverItemColor::from(color) }) + } + diff::display::HoverItem::Separator => HoverItem::Separator, + } + } +} + +impl From for HoverItemColor { + fn from(color: diff::display::HoverItemColor) -> Self { + match color { + diff::display::HoverItemColor::Normal => HoverItemColor::Normal, + diff::display::HoverItemColor::Emphasized => HoverItemColor::Emphasized, + diff::display::HoverItemColor::Special => HoverItemColor::Special, + } + } +} + +impl From for ContextItem { + fn from(item: diff::display::ContextItem) -> Self { + match item { + diff::display::ContextItem::Copy { value, label } => { + ContextItem::Copy(ContextItemCopy { value, label }) + } + diff::display::ContextItem::Navigate { label, symbol_index, kind } => { + ContextItem::Navigate(ContextItemNavigate { + label, + symbol: symbol_index as SymbolRef, + kind: SymbolNavigationKind::from(kind), + }) + } + diff::display::ContextItem::Separator => ContextItem::Separator, + } + } +} + +impl From for SymbolNavigationKind { + fn from(kind: diff::display::SymbolNavigationKind) -> Self { + match kind { + diff::display::SymbolNavigationKind::Normal => SymbolNavigationKind::Normal, + diff::display::SymbolNavigationKind::Extab => SymbolNavigationKind::Extab, + } + } +} + export!(Component); diff --git a/objdiff-wasm/wit/objdiff.wit b/objdiff-wasm/wit/objdiff.wit index 5386f3b..c9fed13 100644 --- a/objdiff-wasm/wit/objdiff.wit +++ b/objdiff-wasm/wit/objdiff.wit @@ -108,18 +108,26 @@ interface display { row-count: u32, } - record context-menu-item-copy { + enum symbol-navigation-kind { + normal, + extab, + } + + record context-item-copy { value: string, label: option, } - record context-menu-item-navigate { + record context-item-navigate { label: string, + symbol: symbol-ref, + kind: symbol-navigation-kind, } - variant context-menu-item { - copy(context-menu-item-copy), - navigate(context-menu-item-navigate), + variant context-item { + copy(context-item-copy), + navigate(context-item-navigate), + separator, } enum hover-item-color { @@ -128,11 +136,17 @@ interface display { special, } - record hover-item { - text: string, + record hover-item-text { + label: string, + value: string, color: hover-item-color, } + variant hover-item { + text(hover-item-text), + separator, + } + record diff-text-opcode { mnemonic: string, opcode: u16, @@ -216,22 +230,36 @@ interface display { symbol: section-display-symbol, ) -> symbol-display; - symbol-context: func( - object: borrow, - symbol: symbol-ref, - ) -> list; - - symbol-hover: func( - object: borrow, - symbol: symbol-ref, - ) -> list; - display-instruction-row: func( diff: borrow, symbol: section-display-symbol, row-index: u32, config: borrow, ) -> instruction-diff-row; + + symbol-context: func( + diff: borrow, + symbol: section-display-symbol, + ) -> list; + + symbol-hover: func( + diff: borrow, + symbol: section-display-symbol, + ) -> list; + + instruction-context: func( + diff: borrow, + symbol: section-display-symbol, + row-index: u32, + config: borrow, + ) -> result, string>; + + instruction-hover: func( + diff: borrow, + symbol: section-display-symbol, + row-index: u32, + config: borrow, + ) -> result, string>; } world api {