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

Add configuration for display options #34

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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