Add symbol and instruction context menus

This commit is contained in:
Luke Street
2025-03-11 21:46:44 -06:00
parent df258e40bd
commit ec5d3481ff
8 changed files with 406 additions and 60 deletions
+59 -22
View File
@@ -9,6 +9,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList, areEqual } from 'react-window';
import type { ListChildComponentProps } from 'react-window';
import { useShallow } from 'zustand/react/shallow';
import { createContextMenu, renderContextItems } from '../common/ContextMenu';
import TooltipShared from '../common/TooltipShared';
import {
buildDiffConfig,
@@ -36,6 +37,11 @@ const ROTATION_CLASSES = [
styles.rotation8,
];
const { ContextMenuProvider, useContextMenu } = createContextMenu<{
column: number;
row: number;
}>();
const AsmCell = ({
obj,
config,
@@ -53,6 +59,7 @@ const AsmCell = ({
highlight: HighlightState;
setHighlight: (highlight: HighlightState) => void;
}) => {
const onContextMenu = useContextMenu();
if (!obj || !symbol) {
return <div className={styles.instructionCell} />;
}
@@ -197,6 +204,7 @@ const AsmCell = ({
className={clsx(classes)}
data-tooltip-id="instruction-tooltip"
data-tooltip-content={JSON.stringify(tooltipContent)}
onContextMenu={(e) => onContextMenu(e, { column, row })}
>
{out}
</div>
@@ -413,28 +421,57 @@ const FunctionView = ({
</div>
</div>
<div className={styles.instructionList}>
<AutoSizer>
{({ height, width }) => (
<FixedSizeList
height={height}
itemCount={itemData.itemCount}
itemSize={itemSize}
width={width}
itemData={itemData}
overscanCount={20}
onScroll={(e) => {
setSymbolScrollOffset(
currentUnitName,
itemData.symbolName,
e.scrollOffset,
);
}}
initialScrollOffset={initialScrollOffset}
>
{AsmRow}
</FixedSizeList>
)}
</AutoSizer>
<ContextMenuProvider
render={({ data }, close) => {
let obj: diff.ObjectDiff | undefined;
let symbol: display.SectionDisplaySymbol | undefined;
switch (data.column) {
case 0:
obj = diff.left;
symbol = itemData.left ?? undefined;
break;
case 1:
obj = diff.right;
symbol = itemData.right ?? undefined;
break;
default:
break;
}
if (!obj || !symbol) {
return null;
}
const items = display.instructionContext(
obj,
symbol,
data.row,
itemData.config,
);
return renderContextItems(items, close);
}}
>
<AutoSizer>
{({ height, width }) => (
<FixedSizeList
height={height}
itemCount={itemData.itemCount}
itemSize={itemSize}
width={width}
itemData={itemData}
overscanCount={20}
onScroll={(e) => {
setSymbolScrollOffset(
currentUnitName,
itemData.symbolName,
e.scrollOffset,
);
}}
initialScrollOffset={initialScrollOffset}
>
{AsmRow}
</FixedSizeList>
)}
</AutoSizer>
</ContextMenuProvider>
</div>
<TooltipShared
id="instruction-tooltip"
+42 -19
View File
@@ -12,6 +12,7 @@ import {
areEqual,
} from 'react-window';
import { useShallow } from 'zustand/react/shallow';
import { createContextMenu, renderContextItems } from '../common/ContextMenu';
import TooltipShared from '../common/TooltipShared';
import {
type UnitScrollOffsets,
@@ -22,6 +23,14 @@ import {
} from '../state';
import { percentClass, useFontSize } from '../util/util';
type SymbolTooltipContent = {
symbolRef: display.SectionDisplaySymbol;
side: keyof UnitScrollOffsets;
};
const { ContextMenuProvider, useContextMenu } =
createContextMenu<SymbolTooltipContent>();
const SectionRow = ({
section,
style,
@@ -70,6 +79,7 @@ const SymbolRow = ({
style?: React.CSSProperties;
}) => {
const setSelectedSymbol = useAppStore((state) => state.setSelectedSymbol);
const onContextMenu = useContextMenu();
const symbol = display.displaySymbol(obj, symbolRef);
const flags = [];
if (symbol.flags.global) {
@@ -136,14 +146,11 @@ const SymbolRow = ({
},
);
}}
data-vscode-context={JSON.stringify({
contextType: 'symbol',
preventDefaultContextMenuItems: true,
symbolName: symbol.name,
symbolDemangledName: symbol.demangledName,
})}
data-tooltip-id="symbol-tooltip"
data-tooltip-content={JSON.stringify(tooltipContent)}
onContextMenu={(e) => {
onContextMenu(e, tooltipContent);
}}
>
{flagsElem}
{percentElem}
@@ -154,11 +161,6 @@ const SymbolRow = ({
);
};
type SymbolTooltipContent = {
symbolRef: display.SectionDisplaySymbol;
side: keyof UnitScrollOffsets;
};
type SectionData = display.SectionDisplay & { collapsed: boolean };
type ItemData = {
@@ -434,14 +436,35 @@ const SymbolsView = ({ diff }: { diff: diff.DiffResult }) => {
</div>
</div>
<div className={styles.symbols}>
<AutoSizer className={styles.symbols}>
{({ height, width }) => (
<>
{renderList(height, width, leftItemData, 'left')}
{renderList(height, width, rightItemData, 'right')}
</>
)}
</AutoSizer>
<ContextMenuProvider
render={({ data }, close) => {
let obj: diff.ObjectDiff | undefined;
switch (data.side) {
case 'left':
obj = diff.left;
break;
case 'right':
obj = diff.right;
break;
default:
break;
}
if (!obj) {
return null;
}
const items = display.symbolContext(obj, data.symbolRef);
return renderContextItems(items, close);
}}
>
<AutoSizer className={styles.symbols}>
{({ height, width }) => (
<>
{renderList(height, width, leftItemData, 'left')}
{renderList(height, width, rightItemData, 'right')}
</>
)}
</AutoSizer>
</ContextMenuProvider>
</div>
<TooltipShared
id="symbol-tooltip"