Skip to content

Commit cf71e6d

Browse files
committed
Enable extenders to overwrite default settings
Extenders can use the `AdapterCapabilities` to specify their own default settings, including the visible columns (see `MemoryDisplaySettings` interface). If an extension specifies such settings for a specific debug session (or type), those settings take priority over the user's VS Code settings of the Memory Inspector. To indicate that default settings are overwritten by an extension, an additional message is shown in the hover of the reset button in the options overlay. Extenders can specify this message to give more specific reasons for overwriting the settings. Users can prevent extenders from overwriting the default settings via a dedicated VS Code setting (`allowSettingsExtension`). Fixes #77
1 parent 835ef75 commit cf71e6d

12 files changed

Lines changed: 154 additions & 69 deletions

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,11 @@
371371
"type": "boolean",
372372
"default": true,
373373
"description": "Display the radix prefix (e.g., '0x' for hexadecimal, '0b' for binary) before memory addresses."
374+
},
375+
"memory-inspector.allowSettingsExtension": {
376+
"type": "boolean",
377+
"default": true,
378+
"description": "Allow other extensions to overwrite the default memory display settings."
374379
}
375380
}
376381
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/********************************************************************************
2+
* Copyright (C) 2024 EclipseSource and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the Eclipse
10+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
* with the GNU Classpath Exception which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
********************************************************************************/
16+
17+
import { Endianness, Radix } from './memory-range';
18+
19+
/** Specifies the settings for displaying memory addresses in the memory data table. */
20+
export interface MemoryAddressDisplaySettings {
21+
addressPadding: AddressPadding;
22+
addressRadix: Radix;
23+
showRadixPrefix: boolean;
24+
}
25+
26+
export type AddressPadding = 'Min' | 0 | 32 | 64;
27+
28+
/** Specifies the settings for displaying memory data in the memory data table, including the memory addresses. */
29+
export interface MemoryDataDisplaySettings extends MemoryAddressDisplaySettings {
30+
bytesPerMau: number;
31+
mausPerGroup: number;
32+
groupsPerRow: 'Autofit' | number;
33+
endianness: Endianness;
34+
scrollingBehavior: ScrollingBehavior;
35+
}
36+
37+
export type ScrollingBehavior = 'Paginate' | 'Grow' | 'Auto-Append';
38+
39+
/** Specifies the display settings of the memory data table, including the memory data and addresses. */
40+
export interface MemoryDisplaySettings extends MemoryDataDisplaySettings {
41+
visibleColumns: string[];
42+
}
43+
44+
/** An extender's contribution to the `MemoryDisplaySettings` via the `AdapterCapabilities`. */
45+
export interface MemoryDisplaySettingsContribution {
46+
message?: string;
47+
settings?: Partial<MemoryDisplaySettings>;
48+
}

src/plugin/adapter-registry/adapter-capabilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { DebugProtocol } from '@vscode/debugprotocol';
1818
import * as vscode from 'vscode';
1919
import { isDebugRequest, isDebugResponse } from '../../common/debug-requests';
20+
import { MemoryDisplaySettingsContribution } from '../../common/memory-display-settings';
2021
import { VariableRange } from '../../common/memory-range';
2122
import { Logger } from '../logger';
2223

@@ -30,6 +31,9 @@ export interface AdapterCapabilities {
3031
getAddressOfVariable?(session: vscode.DebugSession, variableName: string): Promise<string | undefined>;
3132
/** Resolves the size of a given variable in bytes within the current context. */
3233
getSizeOfVariable?(session: vscode.DebugSession, variableName: string): Promise<bigint | undefined>;
34+
/** Retrieve the enforced default display settings for the memory view. */
35+
getMemoryDisplaySettings?(session: vscode.DebugSession): Promise<Partial<MemoryDisplaySettingsContribution>>;
36+
/** Initialize the trackers of this adapter's for the debug session. */
3337
initializeAdapterTracker?(session: vscode.DebugSession): vscode.DebugAdapterTracker | undefined;
3438
}
3539

src/plugin/manifest.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,6 @@ export const DEFAULT_SHOW_RADIX_PREFIX = true;
6464
// Columns
6565
export const CONFIG_SHOW_VARIABLES_COLUMN = 'columns.variables';
6666
export const CONFIG_SHOW_ASCII_COLUMN = 'columns.ascii';
67+
68+
// Extension Settings
69+
export const CONFIG_ALLOW_SETTINGS_EXTENSION = 'allowSettingsExtension';

src/plugin/memory-provider.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { DebugProtocol } from '@vscode/debugprotocol';
1818
import * as vscode from 'vscode';
1919
import { isDebugEvent, isDebugRequest, isDebugResponse, sendRequest } from '../common/debug-requests';
2020
import { stringToBytesMemory } from '../common/memory';
21+
import { MemoryDisplaySettingsContribution } from '../common/memory-display-settings';
2122
import { VariableRange, WrittenMemory } from '../common/memory-range';
2223
import { ReadMemoryResult, SessionContext, WriteMemoryResult } from '../common/messaging';
2324
import { AdapterRegistry } from './adapter-registry/adapter-registry';
@@ -183,4 +184,11 @@ export class MemoryProvider {
183184
const handler = this.adapterRegistry?.getHandlerForSession(session.type);
184185
return handler?.getSizeOfVariable?.(session, variableName);
185186
}
187+
188+
public async getMemoryDisplaySettingsContribution(): Promise<MemoryDisplaySettingsContribution> {
189+
const session = this.assertActiveSession('get settings of variable');
190+
const handler = this.adapterRegistry?.getHandlerForSession(session.type);
191+
return handler?.getMemoryDisplaySettings?.(session) ?? {};
192+
}
193+
186194
}

src/plugin/memory-webview-main.ts

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import * as vscode from 'vscode';
1818
import { Messenger } from 'vscode-messenger';
1919
import { WebviewIdMessageParticipant } from 'vscode-messenger-common';
20+
import { MemoryDisplaySettings, MemoryDisplaySettingsContribution, ScrollingBehavior } from '../common/memory-display-settings';
2021
import { Endianness, VariableRange } from '../common/memory-range';
2122
import {
2223
applyMemoryType,
@@ -44,7 +45,7 @@ import {
4445
writeMemoryType,
4546
} from '../common/messaging';
4647
import { getVisibleColumns, WebviewContext } from '../common/webview-context';
47-
import { AddressPaddingOptions, MemoryViewSettings, ScrollingBehavior } from '../webview/utils/view-types';
48+
import { AddressPaddingOptions, MemoryViewSettings } from '../webview/utils/view-types';
4849
import { isVariablesContext } from './external-views';
4950
import { outputChannelLogger } from './logger';
5051
import * as manifest from './manifest';
@@ -204,9 +205,9 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
204205
const participant = this.messenger.registerWebviewPanel(panel);
205206

206207
const disposables = [
207-
this.messenger.onNotification(readyType, () => {
208-
this.setInitialSettings(participant, panel.title);
208+
this.messenger.onNotification(readyType, async () => {
209209
this.setSessionContext(participant, this.memoryProvider.createContext());
210+
await this.setMemoryDisplaySettings(participant, panel.title);
210211
this.refresh(participant, options);
211212
}, { sender: participant }),
212213
this.messenger.onRequest(setOptionsType, o => {
@@ -216,7 +217,7 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
216217
this.messenger.onRequest(readMemoryType, request => this.readMemory(request), { sender: participant }),
217218
this.messenger.onRequest(writeMemoryType, request => this.writeMemory(request), { sender: participant }),
218219
this.messenger.onRequest(getVariablesType, request => this.getVariables(request), { sender: participant }),
219-
this.messenger.onNotification(resetMemoryViewSettingsType, () => this.setInitialSettings(participant, panel.title), { sender: participant }),
220+
this.messenger.onNotification(resetMemoryViewSettingsType, () => this.setMemoryDisplaySettings(participant), { sender: participant }),
220221
this.messenger.onNotification(setTitleType, title => { panel.title = title; }, { sender: participant }),
221222
this.messenger.onRequest(storeMemoryType, args => this.storeMemory(args), { sender: participant }),
222223
this.messenger.onRequest(applyMemoryType, () => this.applyMemory(), { sender: participant }),
@@ -237,39 +238,59 @@ export class MemoryWebview implements vscode.CustomReadonlyEditorProvider {
237238
panel.onDidDispose(() => disposables.forEach(disposable => disposable.dispose()));
238239
}
239240

240-
protected async refresh(participant: WebviewIdMessageParticipant, options: MemoryOptions = {}): Promise<void> {
241-
this.messenger.sendRequest(setOptionsType, participant, options);
241+
protected async setMemoryDisplaySettings(participant: WebviewIdMessageParticipant, title?: string): Promise<void> {
242+
const defaultSettings = this.getDefaultMemoryDisplaySettings();
243+
const settingsContribution = await this.getSettingsContribution();
244+
this.messenger.sendNotification(setMemoryViewSettingsType, participant, {
245+
title,
246+
...defaultSettings,
247+
...settingsContribution.settings,
248+
contributionMessage: settingsContribution.message
249+
});
242250
}
243251

244-
protected setInitialSettings(webviewParticipant: WebviewIdMessageParticipant, title: string): void {
245-
this.setMemoryViewSettings(webviewParticipant, this.getMemoryViewSettings(webviewParticipant, title));
252+
protected async refresh(participant: WebviewIdMessageParticipant, options: MemoryOptions = {}): Promise<void> {
253+
this.messenger.sendRequest(setOptionsType, participant, options);
246254
}
247255

248256
protected setMemoryViewSettings(webviewParticipant: WebviewIdMessageParticipant, settings: Partial<MemoryViewSettings>): void {
249257
this.messenger.sendNotification(setMemoryViewSettingsType, webviewParticipant, settings);
250258
}
251259

260+
protected applyDisplaySettingContributions(webviewParticipant: WebviewIdMessageParticipant, settingsContribution: Partial<MemoryDisplaySettingsContribution>): void {
261+
const { settings, message } = settingsContribution;
262+
if (settings && Object.keys(settings).length) {
263+
this.messenger.sendNotification(setMemoryViewSettingsType, webviewParticipant, { ...settings, contributionMessage: message });
264+
}
265+
}
266+
252267
protected setSessionContext(webviewParticipant: WebviewIdMessageParticipant, context: SessionContext): void {
253268
this.messenger.sendNotification(sessionContextChangedType, webviewParticipant, context);
254269
}
255270

256-
protected getMemoryViewSettings(messageParticipant: WebviewIdMessageParticipant, title: string): MemoryViewSettings {
257-
const memoryInspectorConfiguration = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME);
258-
const bytesPerMau = memoryInspectorConfiguration.get<number>(manifest.CONFIG_BYTES_PER_MAU, manifest.DEFAULT_BYTES_PER_MAU);
259-
const mausPerGroup = memoryInspectorConfiguration.get<number>(manifest.CONFIG_MAUS_PER_GROUP, manifest.DEFAULT_MAUS_PER_GROUP);
260-
const groupsPerRow = memoryInspectorConfiguration.get<manifest.GroupsPerRowOption>(manifest.CONFIG_GROUPS_PER_ROW, manifest.DEFAULT_GROUPS_PER_ROW);
261-
const endianness = memoryInspectorConfiguration.get<Endianness>(manifest.CONFIG_ENDIANNESS, manifest.DEFAULT_ENDIANNESS);
262-
const scrollingBehavior = memoryInspectorConfiguration.get<ScrollingBehavior>(manifest.CONFIG_SCROLLING_BEHAVIOR, manifest.DEFAULT_SCROLLING_BEHAVIOR);
271+
protected getDefaultMemoryDisplaySettings(): MemoryDisplaySettings {
272+
const memoryInspectorSettings = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME);
273+
const bytesPerMau = memoryInspectorSettings.get<number>(manifest.CONFIG_BYTES_PER_MAU, manifest.DEFAULT_BYTES_PER_MAU);
274+
const mausPerGroup = memoryInspectorSettings.get<number>(manifest.CONFIG_MAUS_PER_GROUP, manifest.DEFAULT_MAUS_PER_GROUP);
275+
const groupsPerRow = memoryInspectorSettings.get<manifest.GroupsPerRowOption>(manifest.CONFIG_GROUPS_PER_ROW, manifest.DEFAULT_GROUPS_PER_ROW);
276+
const endianness = memoryInspectorSettings.get<Endianness>(manifest.CONFIG_ENDIANNESS, manifest.DEFAULT_ENDIANNESS);
277+
const scrollingBehavior = memoryInspectorSettings.get<ScrollingBehavior>(manifest.CONFIG_SCROLLING_BEHAVIOR, manifest.DEFAULT_SCROLLING_BEHAVIOR);
263278
const visibleColumns = CONFIGURABLE_COLUMNS
264-
.filter(column => vscode.workspace.getConfiguration(manifest.PACKAGE_NAME).get<boolean>(column, false))
279+
.filter(column => memoryInspectorSettings.get<boolean>(column, false))
265280
.map(columnId => columnId.replace('columns.', ''));
266-
const addressPadding = AddressPaddingOptions[memoryInspectorConfiguration.get(manifest.CONFIG_ADDRESS_PADDING, manifest.DEFAULT_ADDRESS_PADDING)];
267-
const addressRadix = memoryInspectorConfiguration.get<number>(manifest.CONFIG_ADDRESS_RADIX, manifest.DEFAULT_ADDRESS_RADIX);
268-
const showRadixPrefix = memoryInspectorConfiguration.get<boolean>(manifest.CONFIG_SHOW_RADIX_PREFIX, manifest.DEFAULT_SHOW_RADIX_PREFIX);
269-
return {
270-
messageParticipant, title, bytesPerMau, mausPerGroup, groupsPerRow,
271-
endianness, scrollingBehavior, visibleColumns, addressPadding, addressRadix, showRadixPrefix
272-
};
281+
const addressPadding = AddressPaddingOptions[memoryInspectorSettings.get(manifest.CONFIG_ADDRESS_PADDING, manifest.DEFAULT_ADDRESS_PADDING)];
282+
const addressRadix = memoryInspectorSettings.get<number>(manifest.CONFIG_ADDRESS_RADIX, manifest.DEFAULT_ADDRESS_RADIX);
283+
const showRadixPrefix = memoryInspectorSettings.get<boolean>(manifest.CONFIG_SHOW_RADIX_PREFIX, manifest.DEFAULT_SHOW_RADIX_PREFIX);
284+
return { bytesPerMau, mausPerGroup, groupsPerRow, endianness, scrollingBehavior, visibleColumns, addressPadding, addressRadix, showRadixPrefix };
285+
}
286+
287+
protected async getSettingsContribution(): Promise<MemoryDisplaySettingsContribution> {
288+
const memoryInspectorSettings = vscode.workspace.getConfiguration(manifest.PACKAGE_NAME);
289+
const allowSettingsExtension = memoryInspectorSettings.get<boolean>(manifest.CONFIG_ALLOW_SETTINGS_EXTENSION, true);
290+
if (allowSettingsExtension) {
291+
return this.memoryProvider.getMemoryDisplaySettingsContribution();
292+
}
293+
return { settings: {}, message: '' };
273294
}
274295

275296
protected async readMemory(request: ReadMemoryArguments): Promise<ReadMemoryResult> {

src/webview/components/memory-table.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@ import { TooltipEvent } from 'primereact/tooltip/tooltipoptions';
2525
import { classNames } from 'primereact/utils';
2626
import React from 'react';
2727
import { Memory } from '../../common/memory';
28+
import { MemoryDataDisplaySettings, ScrollingBehavior } from '../../common/memory-display-settings';
2829
import { WebviewSelection } from '../../common/messaging';
2930
import { MemoryOptions, ReadMemoryArguments } from '../../common/messaging';
3031
import { tryToNumber } from '../../common/typescript';
3132
import { TableRenderOptions } from '../columns/column-contribution-service';
3233
import { DataColumn } from '../columns/data-column';
3334
import type { HoverService } from '../hovers/hover-service';
34-
import { Decoration, isTrigger, MemoryDisplayConfiguration, ScrollingBehavior } from '../utils/view-types';
35+
import { Decoration, isTrigger } from '../utils/view-types';
3536
import { createColumnVscodeContext, createSectionVscodeContext } from '../utils/vscode-contexts';
3637

3738
export interface MoreMemorySelectProps {
@@ -128,7 +129,7 @@ export const MoreMemorySelect: React.FC<MoreMemoryAboveSelectProps | MoreMemoryB
128129
);
129130
};
130131

131-
interface MemoryTableProps extends TableRenderOptions, MemoryDisplayConfiguration {
132+
interface MemoryTableProps extends TableRenderOptions, MemoryDataDisplaySettings {
132133
configuredReadArguments: Required<ReadMemoryArguments>;
133134
activeReadArguments: Required<ReadMemoryArguments>;
134135
memory?: Memory;

src/webview/components/memory-widget.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
import React from 'react';
1818
import { WebviewIdMessageParticipant } from 'vscode-messenger-common';
1919
import { Memory } from '../../common/memory';
20-
import { WebviewSelection } from '../../common/messaging';
21-
import { MemoryOptions, ReadMemoryArguments, SessionContext } from '../../common/messaging';
20+
import { MemoryDataDisplaySettings } from '../../common/memory-display-settings';
21+
import { MemoryOptions, ReadMemoryArguments, SessionContext, WebviewSelection } from '../../common/messaging';
2222
import { ColumnStatus } from '../columns/column-contribution-service';
2323
import { HoverService } from '../hovers/hover-service';
24-
import { Decoration, MemoryDisplayConfiguration, MemoryState } from '../utils/view-types';
24+
import { Decoration, MemoryState } from '../utils/view-types';
2525
import { createAppVscodeContext, VscodeContext } from '../utils/vscode-contexts';
2626
import { MemoryTable } from './memory-table';
2727
import { OptionsWidget } from './options-widget';
2828

29-
interface MemoryWidgetProps extends MemoryDisplayConfiguration {
29+
interface MemoryWidgetProps extends MemoryDataDisplaySettings {
3030
messageParticipant: WebviewIdMessageParticipant;
3131
sessionContext: SessionContext;
3232
configuredReadArguments: Required<ReadMemoryArguments>;
@@ -38,12 +38,13 @@ interface MemoryWidgetProps extends MemoryDisplayConfiguration {
3838
columns: ColumnStatus[];
3939
effectiveAddressLength: number;
4040
isMemoryFetching: boolean;
41+
settingsContributionMessage?: string;
4142
updateMemoryState: (state: Partial<MemoryState>) => void;
4243
toggleColumn(id: string, active: boolean): void;
4344
isFrozen: boolean;
4445
toggleFrozen: () => void;
45-
updateMemoryDisplayConfiguration: (memoryArguments: Partial<MemoryDisplayConfiguration>) => void;
46-
resetMemoryDisplayConfiguration: () => void;
46+
updateMemoryDisplaySettings: (memoryArguments: Partial<MemoryDataDisplaySettings>) => void;
47+
resetMemoryDisplaySettings: () => void;
4748
updateTitle: (title: string) => void;
4849
fetchMemory(partialOptions?: MemoryOptions): Promise<void>;
4950
storeMemory(): void;
@@ -91,11 +92,12 @@ export class MemoryWidget extends React.Component<MemoryWidgetProps, MemoryWidge
9192
mausPerGroup={this.props.mausPerGroup}
9293
groupsPerRow={this.props.groupsPerRow}
9394
updateMemoryState={this.props.updateMemoryState}
94-
updateRenderOptions={this.props.updateMemoryDisplayConfiguration}
95-
resetRenderOptions={this.props.resetMemoryDisplayConfiguration}
95+
updateRenderOptions={this.props.updateMemoryDisplaySettings}
96+
resetRenderOptions={this.props.resetMemoryDisplaySettings}
9697
addressPadding={this.props.addressPadding}
9798
addressRadix={this.props.addressRadix}
9899
showRadixPrefix={this.props.showRadixPrefix}
100+
settingsContributionMessage={this.props.settingsContributionMessage}
99101
fetchMemory={this.props.fetchMemory}
100102
toggleColumn={this.props.toggleColumn}
101103
toggleFrozen={this.props.toggleFrozen}

0 commit comments

Comments
 (0)