Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce 'Endianness' in UI and honor it during group rendering #93

Merged
merged 1 commit into from Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions package.json
Expand Up @@ -200,6 +200,19 @@
"default": 4,
"description": "Default groups per row"
},
"memory-inspector.endianness": {
"type": "string",
"enum": [
"Big Endian",
"Little Endian"
],
"enumDescriptions": [
"Most significant byte stored at smallest memory address",
"Least significant byte stored at smallest memory address"
],
"default": "Little Endian",
"description": "Order of bytes within a group"
},
"memory-inspector.columns.variables": {
"type": "boolean",
"default": false,
Expand Down
5 changes: 5 additions & 0 deletions src/common/memory-range.ts
Expand Up @@ -119,3 +119,8 @@ export function areVariablesEqual(one: BigIntVariableRange, other: BigIntVariabl
export function toOffset(startAddress: bigint, targetAddress: bigint, wordSize: number): number {
return Number(targetAddress - startAddress) * (wordSize / 8);
}

export enum Endianness {
Little = 'Little Endian',
Big = 'Big Endian'
}
6 changes: 6 additions & 0 deletions src/plugin/manifest.ts
Expand Up @@ -14,6 +14,8 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { Endianness } from '../common/memory-range';

// Common
export const PACKAGE_NAME = 'memory-inspector';
export const DISPLAY_NAME = 'Memory Inspector';
Expand Down Expand Up @@ -45,6 +47,10 @@ export const CONFIG_GROUPS_PER_ROW_CHOICES = ['Autofit', ...CONFIG_GROUPS_PER_RO
export type GroupsPerRowOption = (typeof CONFIG_GROUPS_PER_ROW_CHOICES)[number];
export const DEFAULT_GROUPS_PER_ROW: GroupsPerRowOption = 4;

// - Group Endianness
export const CONFIG_ENDIANNESS = 'endianness';
export const DEFAULT_ENDIANNESS = Endianness.Little;

// Scroll
export const CONFIG_SCROLLING_BEHAVIOR = 'scrollingBehavior';
export const DEFAULT_SCROLLING_BEHAVIOR = 'Paginate';
Expand Down
5 changes: 3 additions & 2 deletions src/plugin/memory-webview-main.ts
Expand Up @@ -34,7 +34,7 @@ import {
} from '../common/messaging';
import { MemoryProvider } from './memory-provider';
import { outputChannelLogger } from './logger';
import { VariableRange } from '../common/memory-range';
import { Endianness, VariableRange } from '../common/memory-range';
import { AddressPaddingOptions, MemoryViewSettings, ScrollingBehavior } from '../webview/utils/view-types';

interface Variable {
Expand Down Expand Up @@ -221,14 +221,15 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
const bytesPerWord = memoryInspectorConfiguration.get<number>(manifest.CONFIG_BYTES_PER_WORD, manifest.DEFAULT_BYTES_PER_WORD);
const wordsPerGroup = memoryInspectorConfiguration.get<number>(manifest.CONFIG_WORDS_PER_GROUP, manifest.DEFAULT_WORDS_PER_GROUP);
const groupsPerRow = memoryInspectorConfiguration.get<manifest.GroupsPerRowOption>(manifest.CONFIG_GROUPS_PER_ROW, manifest.DEFAULT_GROUPS_PER_ROW);
const endianness = memoryInspectorConfiguration.get<Endianness>(manifest.CONFIG_ENDIANNESS, manifest.DEFAULT_ENDIANNESS);
const scrollingBehavior = memoryInspectorConfiguration.get<ScrollingBehavior>(manifest.CONFIG_SCROLLING_BEHAVIOR, manifest.DEFAULT_SCROLLING_BEHAVIOR);
const visibleColumns = CONFIGURABLE_COLUMNS
.filter(column => vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).get<boolean>(column, false))
.map(columnId => columnId.replace('columns.', ''));
const addressPadding = AddressPaddingOptions[memoryInspectorConfiguration.get(manifest.CONFIG_ADDRESS_PADDING, manifest.DEFAULT_ADDRESS_PADDING)];
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, bytesPerWord, wordsPerGroup, groupsPerRow, scrollingBehavior, visibleColumns, addressPadding, addressRadix, showRadixPrefix };
return { title, bytesPerWord, wordsPerGroup, groupsPerRow, endianness, scrollingBehavior, visibleColumns, addressPadding, addressRadix, showRadixPrefix };
}

protected async readMemory(request: DebugProtocol.ReadMemoryArguments): Promise<MemoryReadResult> {
Expand Down
22 changes: 14 additions & 8 deletions src/webview/columns/data-column.tsx
Expand Up @@ -15,7 +15,7 @@
********************************************************************************/

import * as React from 'react';
import { BigIntMemoryRange, toOffset } from '../../common/memory-range';
import { BigIntMemoryRange, Endianness, toOffset } from '../../common/memory-range';
import { FullNodeAttributes, Memory } from '../utils/view-types';
import { ColumnContribution, TableRenderOptions } from './column-contribution-service';
import { decorationService } from '../decorations/decoration-service';
Expand All @@ -40,14 +40,14 @@ export class DataColumn implements ColumnContribution {

protected renderGroups(range: BigIntMemoryRange, memory: Memory, options: TableRenderOptions): React.ReactNode {
const groups = [];
let words = [];
for (let i = range.startAddress; i < range.endAddress; i++) {
words.push(this.renderWord(memory, options, i));
let words: React.ReactNode[] = [];
for (let address = range.startAddress; address < range.endAddress; address++) {
words.push(this.renderWord(memory, options, address));
if (words.length % options.wordsPerGroup === 0) {
const isLast = i + 1n >= range.endAddress;
this.applyEndianness(words, options);
colin-grant-work marked this conversation as resolved.
Show resolved Hide resolved
const isLast = address + 1n >= range.endAddress;
const style: React.CSSProperties | undefined = isLast ? undefined : this.byteGroupStyle;

groups.push(<span className='byte-group' style={style} key={i.toString(16)}>{words}</span>);
groups.push(<span className='byte-group' style={style} key={address.toString(16)}>{words}</span>);
words = [];
}
}
Expand All @@ -58,13 +58,19 @@ export class DataColumn implements ColumnContribution {
protected renderWord(memory: Memory, options: TableRenderOptions, currentAddress: bigint): React.ReactNode {
const initialOffset = toOffset(memory.address, currentAddress, options.bytesPerWord * 8);
const finalOffset = initialOffset + options.bytesPerWord;
const bytes = [];
const bytes: React.ReactNode[] = [];
for (let i = initialOffset; i < finalOffset; i++) {
bytes.push(this.renderEightBits(memory, currentAddress, i));
}
this.applyEndianness(bytes, options);
return <span className='single-word' key={currentAddress.toString(16)}>{bytes}</span>;
}

protected applyEndianness<T>(group: T[], options: TableRenderOptions): T[] {
// Assume data from the DAP comes in Big Endian so we need to revert the order if we use Little Endian
return options.endianness === Endianness.Big ? group : group.reverse();
}

protected renderEightBits(memory: Memory, currentAddress: bigint, offset: number): React.ReactNode {
const { content, className, style, title } = this.getBitAttributes(memory, currentAddress, offset);
return <span
Expand Down
8 changes: 3 additions & 5 deletions src/webview/components/memory-widget.tsx
Expand Up @@ -17,7 +17,7 @@
import { DebugProtocol } from '@vscode/debugprotocol';
import React from 'react';
import { ColumnStatus } from '../columns/column-contribution-service';
import { Decoration, Endianness, Memory, MemoryDisplayConfiguration, MemoryState } from '../utils/view-types';
import { Decoration, Memory, MemoryDisplayConfiguration, MemoryState } from '../utils/view-types';
import { MemoryTable } from './memory-table';
import { OptionsWidget } from './options-widget';

Expand All @@ -41,11 +41,9 @@ interface MemoryWidgetProps extends MemoryDisplayConfiguration {
}

interface MemoryWidgetState {
endianness: Endianness;
}

const defaultOptions: MemoryWidgetState = {
endianness: Endianness.Little,
};

export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidgetState> {
Expand All @@ -62,7 +60,7 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
columnOptions={this.props.columns}
configuredReadArguments={this.props.configuredReadArguments}
activeReadArguments={this.props.activeReadArguments}
endianness={this.state.endianness}
endianness={this.props.endianness}
bytesPerWord={this.props.bytesPerWord}
wordsPerGroup={this.props.wordsPerGroup}
groupsPerRow={this.props.groupsPerRow}
Expand All @@ -83,7 +81,7 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
decorations={this.props.decorations}
columnOptions={this.props.columns.filter(candidate => candidate.active)}
memory={this.props.memory}
endianness={this.state.endianness}
endianness={this.props.endianness}
bytesPerWord={this.props.bytesPerWord}
wordsPerGroup={this.props.wordsPerGroup}
groupsPerRow={this.props.groupsPerRow}
Expand Down
18 changes: 18 additions & 0 deletions src/webview/components/options-widget.tsx
Expand Up @@ -28,6 +28,7 @@ import { MultiSelectWithLabel } from './multi-select';
import { CONFIG_BYTES_PER_WORD_CHOICES, CONFIG_GROUPS_PER_ROW_CHOICES, CONFIG_WORDS_PER_GROUP_CHOICES } from '../../plugin/manifest';
import { tryToNumber } from '../../common/typescript';
import { Checkbox } from 'primereact/checkbox';
import { Endianness } from '../../common/memory-range';

export interface OptionsWidgetProps
extends Omit<TableRenderOptions, 'scrollingBehavior' | 'effectiveAddressLength'> {
Expand Down Expand Up @@ -55,6 +56,7 @@ const enum InputId {
BytesPerWord = 'word-size',
WordsPerGroup = 'words-per-group',
GroupsPerRow = 'groups-per-row',
EndiannessId = 'endianness',
AddressPadding = 'address-padding',
AddressRadix = 'address-radix',
ShowRadixPrefix = 'show-radix-prefix',
Expand Down Expand Up @@ -326,6 +328,19 @@ export class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWi
options={[...CONFIG_GROUPS_PER_ROW_CHOICES]}
className='advanced-options-dropdown' />

<label
htmlFor={InputId.EndiannessId}
className='advanced-options-label mt-1'
>
Group Endianness
</label>
<Dropdown
id={InputId.EndiannessId}
value={this.props.endianness}
onChange={this.handleAdvancedOptionsDropdownChange}
options={Object.values(Endianness)}
className='advanced-options-dropdown' />

<h2>Address Format</h2>

<label
Expand Down Expand Up @@ -445,6 +460,9 @@ export class OptionsWidget extends React.Component<OptionsWidgetProps, OptionsWi
case InputId.GroupsPerRow:
this.props.updateRenderOptions({ groupsPerRow: tryToNumber(value) ?? value });
break;
case InputId.EndiannessId:
this.props.updateRenderOptions({ endianness: value });
break;
case InputId.AddressPadding:
this.props.updateRenderOptions({ addressPadding: value });
break;
Expand Down
3 changes: 3 additions & 0 deletions src/webview/memory-webview-view.tsx
Expand Up @@ -39,6 +39,7 @@ import { DataColumn } from './columns/data-column';
import { PrimeReactProvider } from 'primereact/api';
import 'primeflex/primeflex.css';
import { getAddressLength, getAddressString } from '../common/memory-range';
import { Endianness } from '../common/memory-range';

export interface MemoryAppState extends MemoryState, MemoryDisplayConfiguration {
title: string;
Expand All @@ -52,6 +53,7 @@ const MEMORY_DISPLAY_CONFIGURATION_DEFAULTS: MemoryDisplayConfiguration = {
bytesPerWord: 1,
wordsPerGroup: 1,
groupsPerRow: 4,
endianness: Endianness.Little,
scrollingBehavior: 'Paginate',
addressPadding: 'Min',
addressRadix: 16,
Expand Down Expand Up @@ -132,6 +134,7 @@ class App extends React.Component<{}, MemoryAppState> {
isMemoryFetching={this.state.isMemoryFetching}
bytesPerWord={this.state.bytesPerWord}
groupsPerRow={this.state.groupsPerRow}
endianness={this.state.endianness}
wordsPerGroup={this.state.wordsPerGroup}
scrollingBehavior={this.state.scrollingBehavior}
addressPadding={this.state.addressPadding}
Expand Down
8 changes: 2 additions & 6 deletions src/webview/utils/view-types.ts
Expand Up @@ -17,14 +17,9 @@
import type { DebugProtocol } from '@vscode/debugprotocol';
import deepequal from 'fast-deep-equal';
import type * as React from 'react';
import { areRangesEqual, BigIntMemoryRange, Radix } from '../../common/memory-range';
import { areRangesEqual, BigIntMemoryRange, Endianness, Radix } from '../../common/memory-range';
import { GroupsPerRowOption } from '../../plugin/manifest';

export enum Endianness {
Little = 'Little Endian',
Big = 'Big Endian'
}

export interface Memory {
address: bigint;
bytes: Uint8Array;
Expand Down Expand Up @@ -91,6 +86,7 @@ export interface MemoryDisplayConfiguration {
bytesPerWord: number;
wordsPerGroup: number;
groupsPerRow: GroupsPerRowOption;
endianness: Endianness;
scrollingBehavior: ScrollingBehavior;
addressPadding: AddressPadding;
addressRadix: Radix;
Expand Down