Merge pull request #127162 from microsoft/isidorn/setExpression
set value for variable and watch
This commit is contained in:
commit
664201582e
13 changed files with 108 additions and 41 deletions
|
@ -160,8 +160,9 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
|||
data.toDispose = Disposable.None;
|
||||
const { element } = node;
|
||||
this.renderExpression(element, data, createMatches(node.filterData));
|
||||
if (element === this.debugService.getViewModel().getSelectedExpression() || (element instanceof Variable && element.errorMessage)) {
|
||||
const options = this.getInputBoxOptions(element);
|
||||
const selectedExpression = this.debugService.getViewModel().getSelectedExpression();
|
||||
if (element === selectedExpression?.expression || (element instanceof Variable && element.errorMessage)) {
|
||||
const options = this.getInputBoxOptions(element, !!selectedExpression?.settingWatch);
|
||||
if (options) {
|
||||
data.toDispose = this.renderInputBox(data.name, data.value, data.inputBoxContainer, options);
|
||||
return;
|
||||
|
@ -189,7 +190,7 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
|||
dispose(toDispose);
|
||||
|
||||
if (finishEditing) {
|
||||
this.debugService.getViewModel().setSelectedExpression(undefined);
|
||||
this.debugService.getViewModel().setSelectedExpression(undefined, false);
|
||||
options.onFinish(value, success);
|
||||
}
|
||||
});
|
||||
|
@ -222,7 +223,7 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
|||
}
|
||||
|
||||
protected abstract renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void;
|
||||
protected abstract getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined;
|
||||
protected abstract getInputBoxOptions(expression: IExpression, settingValue: boolean): IInputBoxOptions | undefined;
|
||||
|
||||
disposeElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, templateData: IExpressionTemplateData): void {
|
||||
templateData.toDispose.dispose();
|
||||
|
|
|
@ -16,11 +16,11 @@ import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'
|
|||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import {
|
||||
IDebugService, VIEWLET_ID, DEBUG_PANEL_ID, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA,
|
||||
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX, BREAKPOINT_EDITOR_CONTRIBUTION_ID, REPL_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, EDITOR_CONTRIBUTION_ID, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, getStateLabel, State, CONTEXT_WATCH_ITEM_TYPE, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, DISASSEMBLY_VIEW_ID,
|
||||
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX, BREAKPOINT_EDITOR_CONTRIBUTION_ID, REPL_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST, EDITOR_CONTRIBUTION_ID, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, getStateLabel, State, CONTEXT_WATCH_ITEM_TYPE, CONTEXT_STACK_FRAME_SUPPORTS_RESTART, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, DISASSEMBLY_VIEW_ID, CONTEXT_SET_EXPRESSION_SUPPORTED,
|
||||
} from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
|
||||
import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService';
|
||||
import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
|
||||
import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
|
||||
import { isMacintosh, isWeb } from 'vs/base/common/platform';
|
||||
|
@ -140,7 +140,7 @@ registerDebugViewMenuItem(MenuId.DebugCallStackContext, TERMINATE_THREAD_ID, nls
|
|||
registerDebugViewMenuItem(MenuId.DebugCallStackContext, RESTART_FRAME_ID, nls.localize('restartFrame', "Restart Frame"), 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_RESTART_FRAME_SUPPORTED), CONTEXT_STACK_FRAME_SUPPORTS_RESTART);
|
||||
registerDebugViewMenuItem(MenuId.DebugCallStackContext, COPY_STACK_TRACE_ID, nls.localize('copyStackTrace', "Copy Call Stack"), 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), undefined, '3_modification');
|
||||
|
||||
registerDebugViewMenuItem(MenuId.DebugVariablesContext, SET_VARIABLE_ID, nls.localize('setValue', "Set Value"), 10, CONTEXT_SET_VARIABLE_SUPPORTED, undefined, '3_modification');
|
||||
registerDebugViewMenuItem(MenuId.DebugVariablesContext, SET_VARIABLE_ID, nls.localize('setValue', "Set Value"), 10, ContextKeyExpr.or(CONTEXT_SET_VARIABLE_SUPPORTED, ContextKeyExpr.and(CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, CONTEXT_SET_EXPRESSION_SUPPORTED)), undefined, '3_modification');
|
||||
registerDebugViewMenuItem(MenuId.DebugVariablesContext, COPY_VALUE_ID, nls.localize('copyValue', "Copy Value"), 10, undefined, undefined, '5_cutcopypaste');
|
||||
registerDebugViewMenuItem(MenuId.DebugVariablesContext, COPY_EVALUATE_PATH_ID, nls.localize('copyAsExpression', "Copy as Expression"), 20, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, undefined, '5_cutcopypaste');
|
||||
registerDebugViewMenuItem(MenuId.DebugVariablesContext, ADD_TO_WATCH_ID, nls.localize('addToWatchExpressions', "Add to Watch"), 100, CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT, undefined, 'z_commands');
|
||||
|
@ -150,7 +150,8 @@ registerDebugViewMenuItem(MenuId.DebugVariablesContext, BREAK_WHEN_VALUE_IS_ACCE
|
|||
|
||||
registerDebugViewMenuItem(MenuId.DebugWatchContext, ADD_WATCH_ID, ADD_WATCH_LABEL, 10, undefined, undefined, '3_modification');
|
||||
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, COPY_VALUE_ID, nls.localize('copyValue', "Copy Value"), 30, ContextKeyExpr.or(CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), CONTEXT_WATCH_ITEM_TYPE.isEqualTo('variable')), CONTEXT_IN_DEBUG_MODE, '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)), undefined, '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');
|
||||
registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_EXPRESSION_COMMAND_ID, nls.localize('removeWatchExpression', "Remove Expression"), 10, CONTEXT_WATCH_ITEM_TYPE.isEqualTo('expression'), undefined, 'z_commands');
|
||||
registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_WATCH_EXPRESSIONS_COMMAND_ID, REMOVE_WATCH_EXPRESSIONS_LABEL, 20, undefined, undefined, 'z_commands');
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ export const DEBUG_CONFIGURE_COMMAND_ID = 'workbench.action.debug.configure';
|
|||
export const DEBUG_START_COMMAND_ID = 'workbench.action.debug.start';
|
||||
export const DEBUG_RUN_COMMAND_ID = 'workbench.action.debug.run';
|
||||
export const EDIT_EXPRESSION_COMMAND_ID = 'debug.renameWatchExpression';
|
||||
export const SET_EXPRESSION_COMMAND_ID = 'debug.setWatchExpression';
|
||||
export const REMOVE_EXPRESSION_COMMAND_ID = 'debug.removeWatchExpression';
|
||||
|
||||
export const RESTART_LABEL = nls.localize('restartDebug', "Restart");
|
||||
|
@ -501,7 +502,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
}
|
||||
|
||||
if (expression instanceof Expression) {
|
||||
debugService.getViewModel().setSelectedExpression(expression);
|
||||
debugService.getViewModel().setSelectedExpression(expression, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: SET_EXPRESSION_COMMAND_ID,
|
||||
handler: async (accessor: ServicesAccessor, expression: Expression | unknown) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
if (expression instanceof Expression || expression instanceof Variable) {
|
||||
debugService.getViewModel().setSelectedExpression(expression, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -520,7 +531,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
if (focused) {
|
||||
const elements = focused.getFocus();
|
||||
if (Array.isArray(elements) && elements[0] instanceof Variable) {
|
||||
debugService.getViewModel().setSelectedExpression(elements[0]);
|
||||
debugService.getViewModel().setSelectedExpression(elements[0], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -877,7 +877,7 @@ export class DebugService implements IDebugService {
|
|||
addWatchExpression(name?: string): void {
|
||||
const we = this.model.addWatchExpression(name);
|
||||
if (!name) {
|
||||
this.viewModel.setSelectedExpression(we);
|
||||
this.viewModel.setSelectedExpression(we, false);
|
||||
}
|
||||
this.debugStorage.storeWatchExpressions(this.model.getWatchExpressions());
|
||||
}
|
||||
|
|
|
@ -650,6 +650,14 @@ export class DebugSession implements IDebugSession {
|
|||
return this.raw.setVariable({ variablesReference, name, value });
|
||||
}
|
||||
|
||||
setExpression(frameId: number, expression: string, value: string): Promise<DebugProtocol.SetExpressionResponse | undefined> {
|
||||
if (!this.raw) {
|
||||
throw new Error(localize('noDebugAdapter', "No debugger available, can not send '{0}'", 'setExpression'));
|
||||
}
|
||||
|
||||
return this.raw.setExpression({ expression, value, frameId });
|
||||
}
|
||||
|
||||
gotoTargets(source: DebugProtocol.Source, line: number, column?: number): Promise<DebugProtocol.GotoTargetsResponse | undefined> {
|
||||
if (!this.raw) {
|
||||
throw new Error(localize('noDebugAdapter', "No debugger available, can not send '{0}'", 'gotoTargets'));
|
||||
|
|
|
@ -358,6 +358,13 @@ export class RawDebugSession implements IDisposable {
|
|||
return Promise.reject(new Error('setVariable not supported'));
|
||||
}
|
||||
|
||||
setExpression(args: DebugProtocol.SetExpressionArguments): Promise<DebugProtocol.SetExpressionResponse | undefined> {
|
||||
if (this.capabilities.supportsSetExpression) {
|
||||
return this.send<DebugProtocol.SetExpressionResponse>('setExpression', args);
|
||||
}
|
||||
return Promise.reject(new Error('setExpression not supported'));
|
||||
}
|
||||
|
||||
async restartFrame(args: DebugProtocol.RestartFrameArguments, threadId: number): Promise<DebugProtocol.RestartFrameResponse | undefined> {
|
||||
if (this.capabilities.supportsRestartFrame) {
|
||||
const response = await this.send('restartFrame', args);
|
||||
|
|
|
@ -164,13 +164,14 @@ export class VariablesView extends ViewPane {
|
|||
}));
|
||||
let horizontalScrolling: boolean | undefined;
|
||||
this._register(this.debugService.getViewModel().onDidSelectExpression(e => {
|
||||
if (e instanceof Variable) {
|
||||
const variable = e?.expression;
|
||||
if (variable instanceof Variable && !e?.settingWatch) {
|
||||
horizontalScrolling = this.tree.options.horizontalScrolling;
|
||||
if (horizontalScrolling) {
|
||||
this.tree.updateOptions({ horizontalScrolling: false });
|
||||
}
|
||||
|
||||
this.tree.rerender(e);
|
||||
this.tree.rerender(variable);
|
||||
} else if (!e && horizontalScrolling !== undefined) {
|
||||
this.tree.updateOptions({ horizontalScrolling: horizontalScrolling });
|
||||
horizontalScrolling = undefined;
|
||||
|
@ -198,7 +199,7 @@ export class VariablesView extends ViewPane {
|
|||
private onMouseDblClick(e: ITreeMouseEvent<IExpression | IScope>): void {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
if (session && e.element instanceof Variable && session.capabilities.supportsSetVariable) {
|
||||
this.debugService.getViewModel().setSelectedExpression(e.element);
|
||||
this.debugService.getViewModel().setSelectedExpression(e.element, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,8 +375,9 @@ export class VariablesRenderer extends AbstractExpressionsRenderer {
|
|||
},
|
||||
onFinish: (value: string, success: boolean) => {
|
||||
variable.errorMessage = undefined;
|
||||
if (success && variable.value !== value) {
|
||||
variable.setVariable(value)
|
||||
const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (success && variable.value !== value && focusedStackFrame) {
|
||||
variable.setVariable(value, focusedStackFrame)
|
||||
// Need to force watch expressions and variables to update since a variable change can have an effect on both
|
||||
.then(() => {
|
||||
// Do not refresh scopes due to a node limitation #15520
|
||||
|
@ -411,7 +413,7 @@ CommandsRegistry.registerCommand({
|
|||
id: SET_VARIABLE_ID,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
debugService.getViewModel().setSelectedExpression(variableInternalContext);
|
||||
debugService.getViewModel().setSelectedExpression(variableInternalContext, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ export class WatchExpressionsView extends ViewPane {
|
|||
identityProvider: { getId: (element: IExpression) => element.getId() },
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (e: IExpression) => {
|
||||
if (e === this.debugService.getViewModel().getSelectedExpression()) {
|
||||
if (e === this.debugService.getViewModel().getSelectedExpression()?.expression) {
|
||||
// Don't filter input box
|
||||
return undefined;
|
||||
}
|
||||
|
@ -146,17 +146,18 @@ export class WatchExpressionsView extends ViewPane {
|
|||
}));
|
||||
let horizontalScrolling: boolean | undefined;
|
||||
this._register(this.debugService.getViewModel().onDidSelectExpression(e => {
|
||||
if (e instanceof Expression) {
|
||||
const expression = e?.expression;
|
||||
if (expression instanceof Expression || (expression instanceof Variable && e?.settingWatch)) {
|
||||
horizontalScrolling = this.tree.options.horizontalScrolling;
|
||||
if (horizontalScrolling) {
|
||||
this.tree.updateOptions({ horizontalScrolling: false });
|
||||
}
|
||||
|
||||
if (e.name) {
|
||||
if (expression.name) {
|
||||
// Only rerender if the input is already done since otherwise the tree is not yet aware of the new element
|
||||
this.tree.rerender(e);
|
||||
this.tree.rerender(expression);
|
||||
}
|
||||
} else if (!e && horizontalScrolling !== undefined) {
|
||||
} else if (!expression && horizontalScrolling !== undefined) {
|
||||
this.tree.updateOptions({ horizontalScrolling: horizontalScrolling });
|
||||
horizontalScrolling = undefined;
|
||||
}
|
||||
|
@ -184,8 +185,9 @@ export class WatchExpressionsView extends ViewPane {
|
|||
|
||||
const element = e.element;
|
||||
// double click on primitive value: open input box to be able to select and copy value.
|
||||
if (element instanceof Expression && element !== this.debugService.getViewModel().getSelectedExpression()) {
|
||||
this.debugService.getViewModel().setSelectedExpression(element);
|
||||
const selectedExpression = this.debugService.getViewModel().getSelectedExpression();
|
||||
if (element instanceof Expression && element !== selectedExpression?.expression) {
|
||||
this.debugService.getViewModel().setSelectedExpression(element, false);
|
||||
} else if (!element) {
|
||||
// Double click in watch panel triggers to add a new watch expression
|
||||
this.debugService.addWatchExpression();
|
||||
|
@ -269,7 +271,27 @@ export class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
|
|||
});
|
||||
}
|
||||
|
||||
protected getInputBoxOptions(expression: IExpression): IInputBoxOptions {
|
||||
protected getInputBoxOptions(expression: IExpression, settingValue: boolean): IInputBoxOptions {
|
||||
if (settingValue) {
|
||||
return {
|
||||
initialValue: expression.value,
|
||||
ariaLabel: localize('typeNewValue', "Type new value"),
|
||||
onFinish: async (value: string, success: boolean) => {
|
||||
if (success && value) {
|
||||
const focusedSession = this.debugService.getViewModel().focusedSession;
|
||||
const focusedFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (focusedSession && focusedFrame) {
|
||||
const path = expression instanceof Variable && expression.evaluateName ? expression.evaluateName : expression.name;
|
||||
await focusedSession.setExpression(focusedFrame.frameId, path, value);
|
||||
ignoreViewUpdates = true;
|
||||
this.debugService.getViewModel().updateViews();
|
||||
ignoreViewUpdates = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
initialValue: expression.name ? expression.name : '',
|
||||
ariaLabel: localize('watchExpressionInputAriaLabel', "Type watch expression"),
|
||||
|
@ -318,7 +340,7 @@ class WatchExpressionsDragAndDrop implements ITreeDragAndDrop<IExpression> {
|
|||
}
|
||||
|
||||
getDragURI(element: IExpression): string | null {
|
||||
if (!(element instanceof Expression) || element === this.debugService.getViewModel().getSelectedExpression()) {
|
||||
if (!(element instanceof Expression) || element === this.debugService.getViewModel().getSelectedExpression()?.expression) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey<boolean>('breakpoints
|
|||
export const CONTEXT_DEBUGGERS_AVAILABLE = new RawContextKey<boolean>('debuggersAvailable', false, { type: 'boolean', description: nls.localize('debuggersAvailable', "True when there is at least one debug extensions active.") });
|
||||
export const CONTEXT_DEBUG_PROTOCOL_VARIABLE_MENU_CONTEXT = new RawContextKey<string>('debugProtocolVariableMenuContext', undefined, { type: 'string', description: nls.localize('debugProtocolVariableMenuContext', "Represents the context the debug adapter sets on the focused variable in the VARIABLES view.") });
|
||||
export const CONTEXT_SET_VARIABLE_SUPPORTED = new RawContextKey<boolean>('debugSetVariableSupported', false, { type: 'boolean', description: nls.localize('debugSetVariableSupported', "True when the focused session supports 'setVariable' request.") });
|
||||
export const CONTEXT_SET_EXPRESSION_SUPPORTED = new RawContextKey<boolean>('debugSetExpressionSupported', false, { type: 'boolean', description: nls.localize('debugSetExpressionSupported', "True when the focused session supports 'setExpression' request.") });
|
||||
export const CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED = new RawContextKey<boolean>('breakWhenValueChangesSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueChangesSupported', "True when the focused session supports to break when value changes.") });
|
||||
export const CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED = new RawContextKey<boolean>('breakWhenValueIsAccessedSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueIsAccessedSupported', "True when the focused breakpoint supports to break when value is accessed.") });
|
||||
export const CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED = new RawContextKey<boolean>('breakWhenValueIsReadSupported', false, { type: 'boolean', description: nls.localize('breakWhenValueIsReadSupported', "True when the focused breakpoint supports to break when value is read.") });
|
||||
|
@ -290,6 +291,7 @@ export interface IDebugSession extends ITreeElement {
|
|||
|
||||
completions(frameId: number | undefined, threadId: number, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse | undefined>;
|
||||
setVariable(variablesReference: number | undefined, name: string, value: string): Promise<DebugProtocol.SetVariableResponse | undefined>;
|
||||
setExpression(frameId: number, expression: string, value: string): Promise<DebugProtocol.SetExpressionResponse | undefined>;
|
||||
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse | undefined>;
|
||||
getLoadedSources(): Promise<Source[]>;
|
||||
|
||||
|
@ -475,15 +477,15 @@ export interface IViewModel extends ITreeElement {
|
|||
*/
|
||||
readonly focusedStackFrame: IStackFrame | undefined;
|
||||
|
||||
getSelectedExpression(): IExpression | undefined;
|
||||
setSelectedExpression(expression: IExpression | undefined): void;
|
||||
getSelectedExpression(): { expression: IExpression; settingWatch: boolean } | undefined;
|
||||
setSelectedExpression(expression: IExpression | undefined, settingWatch: boolean): void;
|
||||
updateViews(): void;
|
||||
|
||||
isMultiSessionView(): boolean;
|
||||
|
||||
onDidFocusSession: Event<IDebugSession | undefined>;
|
||||
onDidFocusStackFrame: Event<{ stackFrame: IStackFrame | undefined, explicit: boolean }>;
|
||||
onDidSelectExpression: Event<IExpression | undefined>;
|
||||
onDidSelectExpression: Event<{ expression: IExpression; settingWatch: boolean } | undefined>;
|
||||
onWillUpdateViews: Event<void>;
|
||||
}
|
||||
|
||||
|
|
|
@ -241,13 +241,20 @@ export class Variable extends ExpressionContainer implements IExpression {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
async setVariable(value: string): Promise<any> {
|
||||
async setVariable(value: string, stackFrame: IStackFrame): Promise<any> {
|
||||
if (!this.session) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.session.setVariable((<ExpressionContainer>this.parent).reference, this.name, value);
|
||||
let response: DebugProtocol.SetExpressionResponse | DebugProtocol.SetVariableResponse | undefined;
|
||||
// Send out a setExpression for debug extensions that do not support set variables https://github.com/microsoft/vscode/issues/124679#issuecomment-869844437
|
||||
if (this.session.capabilities.supportsSetExpression && !this.session.capabilities.supportsSetVariable && this.evaluateName) {
|
||||
response = await this.session.setExpression(stackFrame.frameId, this.evaluateName, value);
|
||||
} else {
|
||||
response = await this.session.setVariable((<ExpressionContainer>this.parent).reference, this.name, value);
|
||||
}
|
||||
|
||||
if (response && response.body) {
|
||||
this.value = response.body.value || '';
|
||||
this.type = response.body.type || this.type;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_SET_EXPRESSION_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
|
||||
|
@ -15,10 +15,10 @@ export class ViewModel implements IViewModel {
|
|||
private _focusedStackFrame: IStackFrame | undefined;
|
||||
private _focusedSession: IDebugSession | undefined;
|
||||
private _focusedThread: IThread | undefined;
|
||||
private selectedExpression: IExpression | undefined;
|
||||
private selectedExpression: { expression: IExpression; settingWatch: boolean } | undefined;
|
||||
private readonly _onDidFocusSession = new Emitter<IDebugSession | undefined>();
|
||||
private readonly _onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame | undefined, explicit: boolean }>();
|
||||
private readonly _onDidSelectExpression = new Emitter<IExpression | undefined>();
|
||||
private readonly _onDidSelectExpression = new Emitter<{ expression: IExpression; settingWatch: boolean } | undefined>();
|
||||
private readonly _onWillUpdateViews = new Emitter<void>();
|
||||
private expressionSelectedContextKey!: IContextKey<boolean>;
|
||||
private loadedScriptsSupportedContextKey!: IContextKey<boolean>;
|
||||
|
@ -28,6 +28,7 @@ export class ViewModel implements IViewModel {
|
|||
private stepIntoTargetsSupported!: IContextKey<boolean>;
|
||||
private jumpToCursorSupported!: IContextKey<boolean>;
|
||||
private setVariableSupported!: IContextKey<boolean>;
|
||||
private setExpressionSupported!: IContextKey<boolean>;
|
||||
private multiSessionDebug!: IContextKey<boolean>;
|
||||
private terminateDebuggeeSuported!: IContextKey<boolean>;
|
||||
private disassembleRequestSupported!: IContextKey<boolean>;
|
||||
|
@ -43,6 +44,7 @@ export class ViewModel implements IViewModel {
|
|||
this.stepIntoTargetsSupported = CONTEXT_STEP_INTO_TARGETS_SUPPORTED.bindTo(contextKeyService);
|
||||
this.jumpToCursorSupported = CONTEXT_JUMP_TO_CURSOR_SUPPORTED.bindTo(contextKeyService);
|
||||
this.setVariableSupported = CONTEXT_SET_VARIABLE_SUPPORTED.bindTo(contextKeyService);
|
||||
this.setExpressionSupported = CONTEXT_SET_EXPRESSION_SUPPORTED.bindTo(contextKeyService);
|
||||
this.multiSessionDebug = CONTEXT_MULTI_SESSION_DEBUG.bindTo(contextKeyService);
|
||||
this.terminateDebuggeeSuported = CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED.bindTo(contextKeyService);
|
||||
this.disassembleRequestSupported = CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED.bindTo(contextKeyService);
|
||||
|
@ -81,6 +83,7 @@ export class ViewModel implements IViewModel {
|
|||
this.stepIntoTargetsSupported.set(session ? !!session.capabilities.supportsStepInTargetsRequest : false);
|
||||
this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false);
|
||||
this.setVariableSupported.set(session ? !!session.capabilities.supportsSetVariable : false);
|
||||
this.setExpressionSupported.set(session ? !!session.capabilities.supportsSetExpression : false);
|
||||
this.terminateDebuggeeSuported.set(session ? !!session.capabilities.supportTerminateDebuggee : false);
|
||||
this.disassembleRequestSupported.set(!!session?.capabilities.supportsDisassembleRequest);
|
||||
this.focusedStackFrameHasInstructionPointerReference.set(!!stackFrame?.instructionPointerReference);
|
||||
|
@ -104,17 +107,17 @@ export class ViewModel implements IViewModel {
|
|||
return this._onDidFocusStackFrame.event;
|
||||
}
|
||||
|
||||
getSelectedExpression(): IExpression | undefined {
|
||||
getSelectedExpression(): { expression: IExpression; settingWatch: boolean } | undefined {
|
||||
return this.selectedExpression;
|
||||
}
|
||||
|
||||
setSelectedExpression(expression: IExpression | undefined) {
|
||||
this.selectedExpression = expression;
|
||||
setSelectedExpression(expression: IExpression | undefined, settingWatch: boolean) {
|
||||
this.selectedExpression = expression ? { expression, settingWatch: settingWatch } : undefined;
|
||||
this.expressionSelectedContextKey.set(!!expression);
|
||||
this._onDidSelectExpression.fire(expression);
|
||||
this._onDidSelectExpression.fire(this.selectedExpression);
|
||||
}
|
||||
|
||||
get onDidSelectExpression(): Event<IExpression | undefined> {
|
||||
get onDidSelectExpression(): Event<{ expression: IExpression; settingWatch: boolean } | undefined> {
|
||||
return this._onDidSelectExpression.event;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ suite('Debug - View Model', () => {
|
|||
test('selected expression', () => {
|
||||
assert.strictEqual(model.getSelectedExpression(), undefined);
|
||||
const expression = new Expression('my expression');
|
||||
model.setSelectedExpression(expression);
|
||||
model.setSelectedExpression(expression, false);
|
||||
|
||||
assert.strictEqual(model.getSelectedExpression(), expression);
|
||||
assert.strictEqual(model.getSelectedExpression()?.expression, expression);
|
||||
});
|
||||
|
||||
test('multi session view and changed workbench state', () => {
|
||||
|
|
|
@ -392,6 +392,9 @@ export class MockSession implements IDebugSession {
|
|||
setVariable(variablesReference: number, name: string, value: string): Promise<DebugProtocol.SetVariableResponse> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
setExpression(frameId: number, expression: string, value: string): Promise<DebugProtocol.SetExpressionResponse | undefined> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue