Change:
I'm not sure of the correct place for this question but given mock-debug includes a MemoryEvent I thought I'd try here. The VSCode January 2022 update stated that VSCode supported memory events and indicates this by including supportsMemoryEvent in its capabilities. I don't see this when running Mock-Debug (or my own debug adapter work) and I don't see any effects from sending a memory event, again either in Mock-Debug or my own work. Are memory events currently supported and working? Edit (10/8/2022): I've found that VSCode will respond to a memory event when a memoryReference is being displayed in a hex editor window and it's doing this without indicating it supportsMemoryEvent. Other areas that may be affected by the changed memory however are not updated, like the value of the paged variable summarizing the memory range. It seems as if a variablesRequest would be appropriate in addition to the readMemoryRequest. Is there a way to force VSCode to issue such a request? I've attached a screenshot showing the updated memory value (0xEA at location 0 in ) while the corresponding value at HW: and 1: under Variables: in the debug view have not been updated. ! Edit (10/12/2022): I found the answer. The variables UI can be updated by sending a InvalidatedEvent specifying variables. Mock-Debug has an example of this. Edit (10/18/2022): The memoryReference "View Binary Data" icon isn't appearing in the Watch pane (or perhaps it's being hidden by the X "Remove Expression" icon). You can see in the image below that the view binary data icon appears for the HW item in the Variables area but doesn't appear for the KEYBOARD_BUFFER item in the Watch area. ! Testing on Mock-Debug we find that the view binary data icon only appears in a paged view of a Watched item. See the two views of o, has the view binary data icon. The second, as a standalone item, either doesn't display it in preference for the remove expression icon, or is hidden by it. This is even though both have the same memoryReference value. !
Since this issue is more about VS Code's support for memory-related DAP requests, I will move it over to the VS Code repo.
I think mock-debug is probably not actually returning a memoryReference on that expression. Our "evaluate" is a mock and is not really evaluating. You can see that it didn't actually return a string.
I wasn't very clear. When I said "This is even though both have the same memoryReference value" I meant that I had manually changed the memoryReference of the $o.fString Watch item to be the same as that of the fString Watch item above that has the View Binary Data icon, '1006' in my case. Confirming that this approach works, I set the fSring memoryReference to undefined, and its View Binary Data icon doesn't appear, as expected. I'm ok with this behavior, it's just odd that this works in the Variables pane as expected, as shown in my first image. So, the Watch pane behavior isn't consistent.
If the bug here is essentially just "the View Binary Data button doesn't show up at the top level of the watch view", I see that it's missing- it should show up in the context menu but isn't set up correctly.
I see. I suppose the difference from the Variables view is to avoid overlap with the "Remove Expression" button. Since we're talking about bugs, I'll just mention again the minor bug that prompted my original question. VS Code supports DAP memory events but doesn't include the supportsMemoryEvent in initializeRequest per the DAP. I had originally modeled this similar to how Mock-Debug handles supportsInvalidatedEvent and so wasn't sending memory events because VS Code didn't indicate that it supported it. It's a minor bug given we know that VS Code does and don't need to verify it. From a generic debug adapter viewpoint, it does raise the question of what's the problem if non-supported events are sent to the UI.
Adding that supports flag, I think that's all that we need to do for that cc And keeping this open for the menubar item. I guess so, I'd be fine with both showing up. I started the refactoring to make this work but got a little bogged down, will try to continue it another time.

Discussion:
registerDebugViewMenuItem(MenuId.DebugWatchContext, EDIT_EXPRESSION_COMMAND_ID, nls.localize('editWatchExpression', "Edit Expression"), 20, CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), undefined, '3_modification'); registerDebugViewMenuItem(MenuId.DebugWatchContext, SET_EXPRESSION_COMMAND_ID, nls.localize('setValue', "Set Value"), 30, ContextKeyExpr.or(ContextKeyExpr.and(CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), CONTEXT_SET_EXPRESSION_SUPPORTED), ContextKeyExpr.and(CONTEXT_WATCH_ITEM_TYPE.isEqualTo('variable'), CONTEXT_SET_VARIABLE_SUPPORTED)), CONTEXT_VARIABLE_IS_READONLY.toNegated(), '3_modification'); registerDebugViewMenuItem(MenuId.DebugWatchContext, COPY_VALUE_ID, nls.localize('copyValue', "Copy Value"), 40, ContextKeyExpr.or(CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), CONTEXT_WATCH_ITEM_TYPE.isEqualTo('variable')), CONTEXT_IN_DEBUG_MODE, '3_modification'); <del> registerDebugViewMenuItem(MenuId.DebugWatchContext, VIEW_MEMORY_ID, nls.localize('viewMemory', "View Binary Data"), 50, CONTEXT_CAN_VIEW_MEMORY, CONTEXT_IN_DEBUG_MODE, '3_modification'); registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_EXPRESSION_COMMAND_ID, nls.localize('removeWatchExpression', "Remove Expression"), 10, CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), undefined, 'inline', icons.watchExpressionRemove); </del> <ins> registerDebugViewMenuItem(MenuId.DebugWatchContext, VIEW_MEMORY_ID, nls.localize('viewMemory', "View Binary Data"), 10, CONTEXT_CAN_VIEW_MEMORY, undefined, 'inline', icons.debugInspectMemory); registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_EXPRESSION_COMMAND_ID, nls.localize('removeWatchExpression', "Remove Expression"), 20, CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), undefined, 'inline', icons.watchExpressionRemove); </ins> registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_WATCH_EXPRESSIONS_COMMAND_ID, REMOVE_WATCH_EXPRESSIONS_LABEL, 20, undefined, undefined, 'z_commands'); // Touch Bar

supportsInvalidatedEvent: true, // #106745 supportsMemoryReferences: true, //#129684 supportsArgsCanBeInterpretedByShell: true, // #149910 <del> supportsMemoryEvent: true </del> <ins> supportsMemoryEvent: true, // #133643 </ins> }); this.initialized = true;

CommandsRegistry.registerCommand({ id: VIEW_MEMORY_ID, <del> handler: async (accessor: ServicesAccessor, arg: IVariablesContext, ctx?: (Variable | Expression)[]) => { if (!arg.sessionId || !arg.variable.memoryReference) { return; </del> <ins> handler: async (accessor: ServicesAccessor, arg: IVariablesContext | IExpression, ctx?: (Variable | Expression)[]) => { const debugService = accessor.get(IDebugService); let sessionId: string; let memoryReference: string; if ('sessionId' in arg) { // IVariablesContext if (!arg.sessionId || !arg.variable.memoryReference) { return; } sessionId = arg.sessionId; memoryReference = arg.variable.memoryReference; } else { // IExpression if (!arg.memoryReference) { return; } const focused = debugService.getViewModel().focusedSession; if (!focused) { return; } sessionId = focused.getId(); memoryReference = arg.memoryReference; </ins> } const commandService = accessor.get(ICommandService);

const progressService = accessor.get(IProgressService); const extensionService = accessor.get(IExtensionService); const telemetryService = accessor.get(ITelemetryService); <del> const debugService = accessor.get(IDebugService); </del> const ext = await extensionService.getExtension(HEX_EDITOR_EXTENSION_ID); if (ext || await tryInstallHexEditor(notifications, progressService, extensionService, commandService)) {

} */ telemetryService.publicLog('debug/didViewMemory', { <del> debugType: debugService.getModel().getSession(arg.sessionId)?.configuration.type, </del> <ins> debugType: debugService.getModel().getSession(sessionId)?.configuration.type, </ins> }); await editorService.openEditor({ <del> resource: getUriForDebugMemory(arg.sessionId, arg.variable.memoryReference), </del> <ins> resource: getUriForDebugMemory(sessionId, memoryReference), </ins> options: { revealIfOpened: true, override: HEX_EDITOR_EDITOR_ID,

import { RunOnceScheduler } from 'vs/base/common/async'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; <del> import { IDebugService, IExpression, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, WATCH_VIEW_ID, CONTEXT_WATCH_EXPRESSIONS_EXIST, CONTEXT_WATCH_ITEM_TYPE, CONTEXT_VARIABLE_IS_READONLY } from 'vs/workbench/contrib/debug/common/debug'; </del> <ins> import { IDebugService, IExpression, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, WATCH_VIEW_ID, CONTEXT_WATCH_EXPRESSIONS_EXIST, CONTEXT_WATCH_ITEM_TYPE, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_CAN_VIEW_MEMORY } from 'vs/workbench/contrib/debug/common/debug'; </ins> import { Expression, Variable } from 'vs/workbench/contrib/debug/common/debugModel'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';

} protected override renderActionBar(actionBar: ActionBar, expression: IExpression) { <del> const contextKeyService = getContextForWatchExpressionMenu(this.contextKeyService); </del> <ins> const contextKeyService = getContextForWatchExpressionMenu(this.contextKeyService, expression); </ins> const menu = this.menuService.createMenu(MenuId.DebugWatchContext, contextKeyService); const primary: IAction[] = [];

/** * Gets a context key overlay that has context for the given expression. */ <del> function getContextForWatchExpressionMenu(parentContext: IContextKeyService) { </del> <ins> function getContextForWatchExpressionMenu(parentContext: IContextKeyService, expression: IExpression) { </ins> return parentContext.createOverlay([ <ins> [CONTEXT_CAN_VIEW_MEMORY.key, expression.memoryReference !== undefined], </ins> [CONTEXT_WATCH_ITEM_TYPE.key, 'expression'] ]); }

evaluateLazy(): Promise<void>; getChildren(): Promise<IExpression[]>; readonly reference?: number; <ins> readonly memoryReference?: string; </ins> readonly value: string; readonly type?: string; valueChanged?: boolean;