Skip to content

Commit

Permalink
Enhance Memory Address Formatting in Memory view (#79)
Browse files Browse the repository at this point in the history
* Add setting for visibility of base prefix (radix) in memory address
* Add setting for memory address format (binary, hex, ...)
* Initialize based on settings for new views
* Add UI to allow changing both options for each view instance
* Style radix prefix with slight opacity for easier reading
* Prepare for adding 0s in the beginning for 32b or 64b systems
  but switch padding off by default as we don't know whether debuggee
  is 32b or 64b

Fixes #62
  • Loading branch information
planger authored Feb 22, 2024
1 parent 02d77b7 commit caafbb4
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 13 deletions.
4 changes: 4 additions & 0 deletions media/memory-table.css
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,7 @@
.more-memory-select select:hover {
background: var(--vscode-dropdown-background);
}

.radix-prefix {
opacity: .6;
}
2 changes: 1 addition & 1 deletion media/multi-select.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
}

.multi-select-label {
font-weight: bold;
font-size: small;
}
7 changes: 6 additions & 1 deletion media/options-widget.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,19 @@
align-self: start;
}

.advanced-options-content h2 {
font-size: 120%;
margin: 0.5rem 0 0 0;
}

.advanced-options-toggle {
margin-left: auto;
align-self: start;
margin-top: 1rem;
}

.advanced-options-content {
width: 160px;
width: 180px;
text-align: left;
display: flex;
flex-direction: column;
Expand Down
24 changes: 23 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,28 @@
"Appends new memory to bounds of current request, resulting in a growing list."
],
"description": "Behavior when adding more memory beyond the current view."
},
"memory-inspector.addressRadix": {
"type": "number",
"enum": [
2,
8,
10,
16
],
"default": 16,
"enumDescriptions": [
"Binary format (base 2)",
"Octal format (base 8)",
"Decimal format (base 10)",
"Hexadecimal format (base 16)"
],
"description": "Specifies the numerical base (radix) for displaying memory addresses."
},
"memory-inspector.showRadixPrefix": {
"type": "boolean",
"default": true,
"description": "Display the radix prefix (e.g., '0x' for hexadecimal, '0b' for binary) before memory addresses."
}
}
}
Expand All @@ -217,4 +239,4 @@
"extensionKind": [
"ui"
]
}
}
27 changes: 26 additions & 1 deletion src/common/memory-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,33 @@ export function determineRelationship(candidate: bigint, range?: BigIntMemoryRan
return RangeRelationship.Within;
}

export enum Radix {
Binary = 2,
Octal = 8,
Decimal = 10,
Hexadecimal = 16,
}

export type Architecture = 32 | 64;

const radixPrefixMap: { [key: number]: string } = {
[Radix.Binary]: '0b',
[Radix.Octal]: '0o',
[Radix.Decimal]: '0d',
[Radix.Hexadecimal]: '0x',
};

export function getRadixMarker(radix: Radix): string {
return radixPrefixMap[radix];
}

export function getAddressString(address: bigint, radix: Radix, architecture: Architecture = 32, addPadding = false): string {
const paddedLength = addPadding ? Math.ceil(architecture / Math.log2(radix)) : 0;
return address.toString(radix).padStart(paddedLength, '0');
}

export function toHexStringWithRadixMarker(target: bigint): string {
return `0x${target.toString(16)}`;
return `${getRadixMarker(Radix.Hexadecimal)}${getAddressString(target, Radix.Hexadecimal)}`;
}

export interface VariableMetadata {
Expand Down
6 changes: 5 additions & 1 deletion src/plugin/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const EDITOR_NAME = `${PACKAGE_NAME}.inspect`;
export const CONFIG_LOGGING_VERBOSITY = 'loggingVerbosity';
export const DEFAULT_LOGGING_VERBOSITY = 'warn';
export const CONFIG_DEBUG_TYPES = 'debugTypes';
export const DEFAULT_DEBUG_TYPES = [ 'gdb', 'embedded-debug', 'arm-debugger' ];
export const DEFAULT_DEBUG_TYPES = ['gdb', 'embedded-debug', 'arm-debugger'];
export const CONFIG_REFRESH_ON_STOP = 'refreshOnStop';
export const DEFAULT_REFRESH_ON_STOP = 'on';

Expand All @@ -31,6 +31,10 @@ export const CONFIG_GROUPS_PER_ROW = 'groupings.groupsPerRow';
export const DEFAULT_GROUPS_PER_ROW = 4;
export const CONFIG_SCROLLING_BEHAVIOR = 'scrollingBehavior';
export const DEFAULT_SCROLLING_BEHAVIOR = 'Paginate';
export const CONFIG_ADDRESS_RADIX = 'addressRadix';
export const DEFAULT_ADDRESS_RADIX = 16;
export const CONFIG_SHOW_RADIX_PREFIX = 'showRadixPrefix';
export const DEFAULT_SHOW_RADIX_PREFIX = true;

export const CONFIG_SHOW_VARIABLES_COLUMN = 'columns.variables';
export const CONFIG_SHOW_ASCII_COLUMN = 'columns.ascii';
4 changes: 3 additions & 1 deletion src/plugin/memory-webview-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,9 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
const visibleColumns = CONFIGURABLE_COLUMNS
.filter(column => vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).get<boolean>(column, false))
.map(columnId => columnId.replace('columns.', ''));
return { title, wordsPerGroup, groupsPerRow, scrollingBehavior, visibleColumns };
const addressRadix = memoryInspectorConfiguration.get<number>(manifest.CONFIG_ADDRESS_RADIX, manifest.DEFAULT_ADDRESS_RADIX);
const showRadixPrefix = memoryInspectorConfiguration.get<boolean>(manifest.CONFIG_SHOW_RADIX_PREFIX, manifest.DEFAULT_SHOW_RADIX_PREFIX);
return { title, wordsPerGroup, groupsPerRow, scrollingBehavior, visibleColumns, addressRadix, showRadixPrefix };
}

protected async readMemory(request: DebugProtocol.ReadMemoryArguments): Promise<MemoryReadResult> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { ReactNode } from 'react';
import { BigIntMemoryRange, toHexStringWithRadixMarker } from '../../common/memory-range';
import React, { ReactNode } from 'react';
import { BigIntMemoryRange, getAddressString, getRadixMarker } from '../../common/memory-range';
import { ColumnContribution } from './column-contribution-service';
import { Memory, MemoryDisplayConfiguration } from '../utils/view-types';

export class AddressColumn implements ColumnContribution {
static ID = 'address';
Expand All @@ -25,7 +26,10 @@ export class AddressColumn implements ColumnContribution {
readonly label = 'Address';
readonly priority = 0;

render(range: BigIntMemoryRange): ReactNode {
return toHexStringWithRadixMarker(range.startAddress);
render(range: BigIntMemoryRange, _: Memory, options: MemoryDisplayConfiguration): ReactNode {
return <span className='memory-start-address'>
{options.showRadixPrefix && <span className='radix-prefix'>{getRadixMarker(options.addressRadix)}</span>}
<span className='address'>{getAddressString(range.startAddress, options.addressRadix)}</span>
</span>;
}
}
4 changes: 4 additions & 0 deletions src/webview/components/memory-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
updateRenderOptions={this.props.updateMemoryDisplayConfiguration}
resetRenderOptions={this.props.resetMemoryDisplayConfiguration}
refreshMemory={this.props.refreshMemory}
addressRadix={this.props.addressRadix}
showRadixPrefix={this.props.showRadixPrefix}
toggleColumn={this.props.toggleColumn}
/>
<MemoryTable
Expand All @@ -87,6 +89,8 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
fetchMemory={this.props.fetchMemory}
isMemoryFetching={this.props.isMemoryFetching}
scrollingBehavior={this.props.scrollingBehavior}
addressRadix={this.props.addressRadix}
showRadixPrefix={this.props.showRadixPrefix}
/>
</div>);
}
Expand Down
2 changes: 1 addition & 1 deletion src/webview/components/multi-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const MultiSelectBar: React.FC<MultiSelectProps> = ({ items, onSelectionChanged,

export const MultiSelectWithLabel: React.FC<MultiSelectProps> = ({ id, label, items, onSelectionChanged }) => (
<div className='flex flex-column'>
<label className='multi-select-label mb-2'>{label}</label>
<h2 className='multi-select-label mb-2 mt-0'>{label}</h2>
<MultiSelectBar id={id} items={items} onSelectionChanged={onSelectionChanged} label={label} />
</div>
);
38 changes: 38 additions & 0 deletions src/webview/components/options-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
SerializedTableRenderOptions,
} from '../utils/view-types';
import { MultiSelectWithLabel } from './multi-select';
import { Checkbox } from 'primereact/checkbox';

export interface OptionsWidgetProps
extends Omit<TableRenderOptions, 'scrollingBehavior'>,
Expand All @@ -52,6 +53,8 @@ const enum InputId {
Length = 'length',
WordsPerGroup = 'words-per-group',
GroupsPerRow = 'groups-per-row',
AddressRadix = 'address-radix',
ShowRadixPrefix = 'show-radix-prefix',
}

interface OptionsForm {
Expand Down Expand Up @@ -260,6 +263,7 @@ export class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWi
onSelectionChanged={this.handleColumnActivationChange}
/>
)}
<h2>Memory Format</h2>
<label
htmlFor={InputId.WordsPerGroup}
className='advanced-options-label mt-1'
Expand All @@ -283,7 +287,35 @@ export class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWi
value={this.props.groupsPerRow}
onChange={this.handleAdvancedOptionsDropdownChange}
options={allowedGroupsPerRow}
className='advanced-options-dropdown' />

<h2>Address Format</h2>
<label
htmlFor={InputId.AddressRadix}
className='advanced-options-label'
>
Format (Radix)
</label>
<Dropdown
id={InputId.AddressRadix}
value={Number(this.props.addressRadix)}
onChange={this.handleAdvancedOptionsDropdownChange}
options={[
{ label: '2 - Binary', value: 2 },
{ label: '8 - Octal', value: 8 },
{ label: '10 - Decimal', value: 10 },
{ label: '16 - Hexadecimal', value: 16 }
]}
className="advanced-options-dropdown" />

<div className='flex align-items-center'>
<Checkbox
id={InputId.ShowRadixPrefix}
onChange={this.handleAdvancedOptionsDropdownChange}
checked={!!this.props.showRadixPrefix}
/>
<label htmlFor={InputId.ShowRadixPrefix} className='ml-2'>Display Radix Prefix</label>
</div>
</div>
</OverlayPanel>
</div>
Expand Down Expand Up @@ -350,6 +382,12 @@ export class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWi
case InputId.GroupsPerRow:
this.props.updateRenderOptions({ groupsPerRow: Number(value) });
break;
case InputId.AddressRadix:
this.props.updateRenderOptions({ addressRadix: Number(value) });
break;
case InputId.ShowRadixPrefix:
this.props.updateRenderOptions({ showRadixPrefix: !!event.target.checked });
break;
default: {
throw new Error(`${id} can not be handled. Did you call the correct method?`);
}
Expand Down
6 changes: 5 additions & 1 deletion src/webview/memory-webview-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ export interface MemoryAppState extends MemoryState, MemoryDisplayConfiguration
const MEMORY_DISPLAY_CONFIGURATION_DEFAULTS: MemoryDisplayConfiguration = {
wordsPerGroup: 1,
groupsPerRow: 4,
scrollingBehavior: 'Paginate'
scrollingBehavior: 'Paginate',
addressRadix: 16,
showRadixPrefix: true,
};

class App extends React.Component<{}, MemoryAppState> {
Expand Down Expand Up @@ -107,6 +109,8 @@ class App extends React.Component<{}, MemoryAppState> {
groupsPerRow={this.state.groupsPerRow}
wordsPerGroup={this.state.wordsPerGroup}
scrollingBehavior={this.state.scrollingBehavior}
addressRadix={this.state.addressRadix}
showRadixPrefix={this.state.showRadixPrefix}
/>
</PrimeReactProvider>;
}
Expand Down
4 changes: 3 additions & 1 deletion src/webview/utils/view-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import type { DebugProtocol } from '@vscode/debugprotocol';
import deepequal from 'fast-deep-equal';
import type * as React from 'react';
import { areRangesEqual, BigIntMemoryRange } from '../../common/memory-range';
import { areRangesEqual, BigIntMemoryRange, Radix } from '../../common/memory-range';

export enum Endianness {
Little = 'Little Endian',
Expand Down Expand Up @@ -82,6 +82,8 @@ export interface MemoryDisplayConfiguration {
wordsPerGroup: number;
groupsPerRow: number;
scrollingBehavior: ScrollingBehavior;
addressRadix: Radix;
showRadixPrefix: boolean;
}
export type ScrollingBehavior = 'Paginate' | 'Infinite';

Expand Down

0 comments on commit caafbb4

Please sign in to comment.