Skip to content

Commit

Permalink
Add configuration for display options (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenneth-marut-work authored Sep 19, 2023
1 parent 527a3f2 commit a7a357d
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 37 deletions.
56 changes: 54 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@
"items": {
"type": "string"
},
"default": [ "gdb", "embedded-debug", "arm-debug" ],
"default": [
"gdb",
"embedded-debug",
"arm-debug"
],
"description": "C-based debuggers to activate (requires debug session restart)"
},
"memory-inspector.refreshOnStop": {
Expand All @@ -137,6 +141,54 @@
],
"default": "on",
"description": "Refresh memory views when debugger stops"
},
"memory-inspector.groupings.wordsPerGroup": {
"type": "number",
"enum": [
1,
2,
4,
8,
16
],
"default": 1,
"description": "Default words per group"
},
"memory-inspector.groupings.groupsPerRow": {
"type": "number",
"enum": [
1,
2,
4,
8,
16,
32
],
"default": 4,
"description": "Default groups per row"
},
"memory-inspector.columns.variables": {
"type": "boolean",
"default": false,
"description": "Show variables column?"
},
"memory-inspector.columns.ascii": {
"type": "boolean",
"default": false,
"description": "Show ASCII column?"
},
"memory-inspector.scrollingBehavior": {
"type": "string",
"enum": [
"Paginate",
"Infinite"
],
"default": "Paginate",
"enumDescriptions": [
"Maintains a consistent memory size, replacing the previous request.",
"Appends new memory to bounds of current request, resulting in a growing list."
],
"description": "Behavior when adding more memory beyond the current view."
}
}
}
Expand All @@ -148,4 +200,4 @@
"extensionKind": [
"ui"
]
}
}
4 changes: 4 additions & 0 deletions src/common/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
import type { DebugProtocol } from '@vscode/debugprotocol';
import type { NotificationType, RequestType } from 'vscode-messenger-common';
import type { VariableRange } from './memory-range';
import { ColumnVisibilityStatus, MemoryDisplayConfiguration, MemoryDisplayConfigurationChangeRequest } from '../webview/utils/view-types';

export type MemoryReadResult = DebugProtocol.ReadMemoryResponse['body'];
export type MemoryWriteResult = DebugProtocol.WriteMemoryResponse['body'];

export const readyType: NotificationType<void> = { method: 'ready' };
export const logMessageType: RequestType<string, void> = { method: 'logMessage' };
export const setMemoryDisplayConfigurationType: NotificationType<MemoryDisplayConfigurationChangeRequest> = { method: 'setMemoryDisplayConfiguration' };
export const memoryDisplayConfigurationChangedType: NotificationType<MemoryDisplayConfiguration> = { method: 'memoryDisplayConfigurationChanged' };
export const columnVisibilityType: NotificationType<ColumnVisibilityStatus> = { method: 'columnVisibility' };
export const setOptionsType: RequestType<Partial<DebugProtocol.ReadMemoryArguments | undefined>, void> = { method: 'setOptions' };
export const readMemoryType: RequestType<DebugProtocol.ReadMemoryArguments, MemoryReadResult> = { method: 'readMemory' };
export const writeMemoryType: RequestType<DebugProtocol.WriteMemoryArguments, MemoryWriteResult> = { method: 'writeMemory' };
Expand Down
10 changes: 10 additions & 0 deletions src/plugin/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,13 @@ export const CONFIG_DEBUG_TYPES = 'debugTypes';
export const DEFAULT_DEBUG_TYPES = [ 'gdb', 'embedded-debug', 'arm-debug' ];
export const CONFIG_REFRESH_ON_STOP = 'refreshOnStop';
export const DEFAULT_REFRESH_ON_STOP = 'on';

export const CONFIG_WORDS_PER_GROUP = 'groupings.wordsPerGroup';
export const DEFAULT_WORDS_PER_GROUP = 1;
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_SHOW_VARIABLES_COLUMN = 'columns.variables';
export const CONFIG_SHOW_ASCII_COLUMN = 'columns.ascii';
80 changes: 75 additions & 5 deletions src/plugin/memory-webview-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as vscode from 'vscode';
import type { DebugProtocol } from '@vscode/debugprotocol';
import * as manifest from './manifest';
import { Messenger } from 'vscode-messenger';
import { WebviewIdMessageParticipant } from 'vscode-messenger-common';
import { MessageParticipant, WebviewIdMessageParticipant } from 'vscode-messenger-common';
import {
readyType,
logMessageType,
Expand All @@ -27,11 +27,15 @@ import {
writeMemoryType,
MemoryReadResult,
MemoryWriteResult,
getVariables
getVariables,
memoryDisplayConfigurationChangedType,
columnVisibilityType,
setMemoryDisplayConfigurationType,
} from '../common/messaging';
import { MemoryProvider } from './memory-provider';
import { outputChannelLogger } from './logger';
import { VariableRange } from '../common/memory-range';
import { ColumnVisibilityStatus, MemoryDisplayConfiguration as MemoryDisplayConfiguration, ScrollingBehavior } from '../webview/utils/view-types';

interface Variable {
name: string;
Expand All @@ -46,6 +50,10 @@ enum RefreshEnum {
}

const isMemoryVariable = (variable: Variable): variable is Variable => variable && !!(variable as Variable).memoryReference;
const columnConfigurations = [
manifest.CONFIG_SHOW_ASCII_COLUMN,
manifest.CONFIG_SHOW_VARIABLES_COLUMN,
];

export class MemoryWebview {
public static ViewType = `${manifest.PACKAGE_NAME}.memory`;
Expand Down Expand Up @@ -138,23 +146,85 @@ export class MemoryWebview {
const participant = this.messenger.registerWebviewPanel(panel);

const disposables = [
this.messenger.onNotification(readyType, () => this.refresh(participant, options), { sender: participant }),
this.messenger.onNotification(readyType, () => {
this.refresh(participant, options);
}, { sender: participant }),
this.messenger.onRequest(logMessageType, message => outputChannelLogger.info('[webview]:', message), { sender: participant }),
this.messenger.onRequest(readMemoryType, request => this.readMemory(request), { sender: participant }),
this.messenger.onRequest(writeMemoryType, request => this.writeMemory(request), { sender: participant }),
this.messenger.onRequest(getVariables, request => this.getVariables(request), { sender: participant }),
this.messenger.onNotification(setMemoryDisplayConfigurationType, request => this.setConfiguration(request), { sender: participant }),
this.messenger.onNotification(columnVisibilityType, request => this.handleColumnToggled(request), { sender: participant }),

this.memoryProvider.onDidStopDebug(() => {
if (this.refreshOnStop === RefreshEnum.on) {
this.refresh(participant);
}
})
}),
this.onMemoryDisplayConfigurationChanged(participant),
this.onColumnVisibilityConfigurationChanged(participant),
];

panel.onDidChangeViewState(newState => {
if (newState.webviewPanel.visible) {
this.refresh(participant, options);
}
});
panel.onDidDispose(() => disposables.forEach(disposible => disposible.dispose()));
}

protected handleColumnToggled(request: ColumnVisibilityStatus): void {
const { id, active: visible } = request;
vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).update(`columns.${id}`, visible, vscode.ConfigurationTarget.Global);
}

protected setConfiguration(request: { id: string, value: unknown }): void {
const { id, value } = request;
vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).update(id, value, vscode.ConfigurationTarget.Global);
}

protected async refresh(participant: WebviewIdMessageParticipant, options?: Partial<DebugProtocol.ReadMemoryArguments>): Promise<void> {
this.messenger.sendRequest(setOptionsType, participant, options);
const memoryDisplayConfiguration = this.getMemoryDisplayConfiguration();
this.messenger.sendNotification(memoryDisplayConfigurationChangedType, participant, memoryDisplayConfiguration);
columnConfigurations.forEach(columnConfiguration => {
const [, id] = columnConfiguration.split('.');
const active = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).get<boolean>(columnConfiguration) ?? true;
this.messenger.sendNotification(columnVisibilityType, participant, { id, active });
});
}

protected getMemoryDisplayConfiguration(): MemoryDisplayConfiguration {
const memoryInspectorConfiguration = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME);
const wordsPerGroup = memoryInspectorConfiguration.get<number>(manifest.CONFIG_WORDS_PER_GROUP) || manifest.DEFAULT_WORDS_PER_GROUP;
const groupsPerRow = memoryInspectorConfiguration.get<number>(manifest.CONFIG_GROUPS_PER_ROW) || manifest.DEFAULT_GROUPS_PER_ROW;
const scrollingBehavior = memoryInspectorConfiguration.get<ScrollingBehavior>(manifest.CONFIG_SCROLLING_BEHAVIOR) || manifest.DEFAULT_SCROLLING_BEHAVIOR;
return { wordsPerGroup, groupsPerRow, scrollingBehavior };
}

protected onMemoryDisplayConfigurationChanged(participant: MessageParticipant): vscode.Disposable {
const memoryDisplayConfigurations = [
manifest.CONFIG_WORDS_PER_GROUP,
manifest.CONFIG_GROUPS_PER_ROW,
manifest.CONFIG_SCROLLING_BEHAVIOR,
];
return vscode.workspace.onDidChangeConfiguration(e => {
if (memoryDisplayConfigurations.some(configurationOption => e.affectsConfiguration(`${manifest.PACKAGE_NAME}.${configurationOption}`))) {
const configuration = this.getMemoryDisplayConfiguration();
this.messenger.sendNotification(memoryDisplayConfigurationChangedType, participant, configuration);
}
});
}

protected onColumnVisibilityConfigurationChanged(participant: MessageParticipant): vscode.Disposable {
return vscode.workspace.onDidChangeConfiguration(e => {
columnConfigurations.forEach(configuration => {
if (e.affectsConfiguration(`${manifest.PACKAGE_NAME}.${configuration}`)) {
const [, id] = configuration.split('.');
const active = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).get<boolean>(configuration) ?? true;
this.messenger.sendNotification(columnVisibilityType, participant, { id, active });
}
});
});
}

protected async readMemory(request: DebugProtocol.ReadMemoryArguments): Promise<MemoryReadResult> {
Expand Down
2 changes: 1 addition & 1 deletion src/webview/columns/ascii-column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

import { ReactNode } from 'react';
import { BigIntMemoryRange, toOffset } from '../../common/memory-range';
import { Memory } from '../utils/view-types';
import { ColumnContribution, TableRenderOptions } from './column-contribution-service';
import { Memory } from '../utils/view-types';

function isPrintableAsAscii(input: number): boolean {
return input >= 32 && input < (128 - 1);
Expand Down
19 changes: 14 additions & 5 deletions src/webview/components/memory-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
VSCodeDataGridRow,
VSCodeDataGridCell
} from '@vscode/webview-ui-toolkit/react';
import { Decoration, Memory, StylableNodeAttributes, isTrigger } from '../utils/view-types';
import { Decoration, Memory, MemoryDisplayConfiguration, ScrollingBehavior, StylableNodeAttributes, isTrigger } from '../utils/view-types';
import { toHexStringWithRadixMarker } from '../../common/memory-range';
import { TableRenderOptions } from '../columns/column-contribution-service';
import { DebugProtocol } from '@vscode/debugprotocol';
Expand All @@ -30,10 +30,11 @@ export interface MoreMemorySelectProps {
offset: number;
options: number[];
direction: 'above' | 'below';
scrollingBehavior: ScrollingBehavior;
fetchMemory(partialOptions?: Partial<DebugProtocol.ReadMemoryArguments>): Promise<void>;
}

export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ count, offset, options, fetchMemory, direction }) => {
export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ count, offset, options, fetchMemory, direction, scrollingBehavior }) => {
const [numBytes, setNumBytes] = React.useState<number>(options[0]);
const containerRef = React.createRef<HTMLDivElement>();
const onSelectChange = (e: React.ChangeEvent<HTMLSelectElement>): void => {
Expand All @@ -50,7 +51,13 @@ export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ count, offse
if (direction === 'above') {
newOffset = offset - numBytes;
}
newCount = count + numBytes;
if (scrollingBehavior === 'Infinite') {
newCount = count + numBytes;
} else {
if (direction === 'below') {
newOffset = offset + numBytes;
}
}
fetchMemory({ offset: newOffset, count: newCount });
}
};
Expand Down Expand Up @@ -85,7 +92,7 @@ export const MoreMemorySelect: React.FC<MoreMemorySelectProps> = ({ count, offse
);
};

interface MemoryTableProps extends TableRenderOptions {
interface MemoryTableProps extends TableRenderOptions, MemoryDisplayConfiguration {
memory?: Memory;
decorations: Decoration[];
offset: number;
Expand All @@ -96,7 +103,7 @@ interface MemoryTableProps extends TableRenderOptions {
export class MemoryTable extends React.Component<MemoryTableProps> {
public render(): React.ReactNode {
const rows = this.getTableRows();
const { offset, count, memory, fetchMemory } = this.props;
const { offset, count, memory, fetchMemory, scrollingBehavior } = this.props;
const showMoreMemoryButton = !!memory?.bytes.length;
return (
<div>
Expand All @@ -115,6 +122,7 @@ export class MemoryTable extends React.Component<MemoryTableProps> {
count={count}
options={[128, 256, 512]}
direction='above'
scrollingBehavior={scrollingBehavior}
fetchMemory={fetchMemory}
/>)}
{rows}
Expand All @@ -123,6 +131,7 @@ export class MemoryTable extends React.Component<MemoryTableProps> {
count={count}
options={[128, 256, 512]}
direction='below'
scrollingBehavior={scrollingBehavior}
fetchMemory={fetchMemory}
/>)}
</VSCodeDataGrid>
Expand Down
20 changes: 13 additions & 7 deletions src/webview/components/memory-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import { DebugProtocol } from '@vscode/debugprotocol';
import React from 'react';
import { MemoryTable } from './memory-table';
import { OptionsWidget } from './options-widget';
import { Decoration, Endianness, Memory } from '../utils/view-types';
import { Decoration, Endianness, Memory, MemoryDisplayConfiguration } from '../utils/view-types';
import { messenger } from '../view-messenger';
import { memoryDisplayConfigurationChangedType } from '../../common/messaging';
import { ColumnStatus } from '../columns/column-contribution-service';

interface MemoryWidgetProps {
Expand All @@ -34,18 +36,17 @@ interface MemoryWidgetProps {
fetchMemory(partialOptions?: Partial<DebugProtocol.ReadMemoryArguments>): Promise<void>
}

interface MemoryWidgetState {
interface MemoryWidgetState extends MemoryDisplayConfiguration {
endianness: Endianness;
wordSize: number;
bytesPerGroup: number;
groupsPerRow: number;
}

const defaultOptions: MemoryWidgetState = {
endianness: Endianness.Little,
wordSize: 8,
bytesPerGroup: 1,
wordsPerGroup: 1,
groupsPerRow: 4,
scrollingBehavior: 'Paginate',
};

export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidgetState> {
Expand All @@ -54,6 +55,10 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
this.state = { ...defaultOptions };
}

public componentDidMount(): void {
messenger.onNotification(memoryDisplayConfigurationChangedType, configuration => this.setState(configuration));
}

override render(): React.ReactNode {
return <>
<OptionsWidget
Expand All @@ -63,7 +68,7 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
count={this.props.count}
endianness={this.state.endianness}
wordSize={this.state.wordSize}
wordsPerGroup={this.state.bytesPerGroup}
wordsPerGroup={this.state.wordsPerGroup}
groupsPerRow={this.state.groupsPerRow}
updateMemoryArguments={this.props.updateMemoryArguments}
updateRenderOptions={this.updateRenderOptions}
Expand All @@ -76,11 +81,12 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
memory={this.props.memory}
endianness={this.state.endianness}
wordSize={this.state.wordSize}
wordsPerGroup={this.state.bytesPerGroup}
wordsPerGroup={this.state.wordsPerGroup}
groupsPerRow={this.state.groupsPerRow}
offset={this.props.offset}
count={this.props.count}
fetchMemory={this.props.fetchMemory}
scrollingBehavior={this.state.scrollingBehavior}
/>
</>;
}
Expand Down
Loading

0 comments on commit a7a357d

Please sign in to comment.