Merge from vscode 817eb6b0c720a4ecbc13c020afbbebfed667aa09 (#7356)
@@ -135,7 +135,7 @@ export interface IExpressionTemplateData {
|
||||
name: HTMLSpanElement;
|
||||
value: HTMLSpanElement;
|
||||
inputBoxContainer: HTMLElement;
|
||||
enableInputBox(expression: IExpression, options: IInputBoxOptions): void;
|
||||
enableInputBox(options: IInputBoxOptions): void;
|
||||
toDispose: IDisposable[];
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
@@ -159,15 +159,12 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
||||
const inputBoxContainer = dom.append(expression, $('.inputBoxContainer'));
|
||||
const toDispose: IDisposable[] = [];
|
||||
|
||||
const enableInputBox = (expression: IExpression, options: IInputBoxOptions) => {
|
||||
const enableInputBox = (options: IInputBoxOptions) => {
|
||||
name.style.display = 'none';
|
||||
value.style.display = 'none';
|
||||
inputBoxContainer.style.display = 'initial';
|
||||
|
||||
const inputBox = new InputBox(inputBoxContainer, this.contextViewService, {
|
||||
placeholder: options.placeholder,
|
||||
ariaLabel: options.ariaLabel
|
||||
});
|
||||
const inputBox = new InputBox(inputBoxContainer, this.contextViewService, options);
|
||||
const styler = attachInputBoxStyler(inputBox, this.themeService);
|
||||
|
||||
inputBox.value = replaceWhitespace(options.initialValue);
|
||||
@@ -217,10 +214,10 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
||||
|
||||
renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
|
||||
const { element } = node;
|
||||
if (element === this.debugService.getViewModel().getSelectedExpression()) {
|
||||
if (element === this.debugService.getViewModel().getSelectedExpression() || (element instanceof Variable && element.errorMessage)) {
|
||||
const options = this.getInputBoxOptions(element);
|
||||
if (options) {
|
||||
data.enableInputBox(element, options);
|
||||
data.enableInputBox(options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import * as env from 'vs/base/common/platform';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -166,11 +166,13 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
|
||||
const anchor = { x: e.event.posx, y: e.event.posy };
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
|
||||
const actions = this.getContextMenuActions(breakpoints, uri, lineNumber);
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
|
||||
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
} else {
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
|
||||
@@ -243,7 +245,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged()));
|
||||
}
|
||||
|
||||
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: uri, lineNumber: number, column?: number): Array<IAction | ContextSubMenu> {
|
||||
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: URI, lineNumber: number, column?: number): Array<IAction | ContextSubMenu> {
|
||||
const actions: Array<IAction | ContextSubMenu> = [];
|
||||
if (breakpoints.length === 1) {
|
||||
const breakpointType = breakpoints[0].logMessage ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
|
||||
@@ -371,7 +373,8 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
let inlineWidget: InlineBreakpointWidget | undefined = undefined;
|
||||
const breakpoint = breakpoints[index];
|
||||
if (breakpoint.column) {
|
||||
inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredBreakpointDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column));
|
||||
const contextMenuActions = () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column);
|
||||
inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredBreakpointDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, contextMenuActions);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -394,8 +397,12 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
});
|
||||
this.candidateDecorations = candidateDecorationIds.map((decorationId, index) => {
|
||||
const candidate = desiredCandidateDecorations[index];
|
||||
const cssClass = candidate.breakpoint ? undefined : 'debug-breakpoint-disabled';
|
||||
const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn));
|
||||
// Candidate decoration has a breakpoint attached when a breakpoint is already at that location and we did not yet set a decoration there
|
||||
// In practice this happens for the first breakpoint that was set on a line
|
||||
// We could have also rendered this first decoration as part of desiredBreakpointDecorations however at that moment we have no location information
|
||||
const cssClass = candidate.breakpoint ? getBreakpointMessageAndClassName(this.debugService, candidate.breakpoint).className : 'debug-breakpoint-disabled';
|
||||
const contextMenuActions = () => this.getContextMenuActions(candidate.breakpoint ? [candidate.breakpoint] : [], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn);
|
||||
const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, contextMenuActions);
|
||||
|
||||
return {
|
||||
decorationId,
|
||||
@@ -524,14 +531,15 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable {
|
||||
await this.debugService.addBreakpoints(this.editor.getModel().uri, [{ lineNumber: this.range!.startLineNumber, column: this.range!.startColumn }], 'debugEditorInlineWidget');
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CONTEXT_MENU, async e => {
|
||||
this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CONTEXT_MENU, e => {
|
||||
const event = new StandardMouseEvent(e);
|
||||
const anchor = { x: event.posx, y: event.posy };
|
||||
|
||||
const actions = this.getContextMenuActions();
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(),
|
||||
getActionsContext: () => this.breakpoint
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => this.breakpoint,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
|
||||
const value = this.getInputValue(this.breakpoint);
|
||||
this.input.getModel().setValue(value);
|
||||
this.input.focus();
|
||||
});
|
||||
|
||||
this.createBreakpointInput(dom.append(container, $('.inputContainer')));
|
||||
|
||||
@@ -196,7 +196,8 @@ export class BreakpointsView extends ViewletPanel {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element
|
||||
getActionsContext: () => element,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -654,9 +655,8 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
};
|
||||
}
|
||||
|
||||
const session = debugService.getViewModel().focusedSession;
|
||||
if (breakpoint instanceof FunctionBreakpoint) {
|
||||
if (session && !session.capabilities.supportsFunctionBreakpoints) {
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-function-breakpoint-unverified',
|
||||
message: nls.localize('functionBreakpointUnsupported', "Function breakpoints not supported by this debug type"),
|
||||
@@ -670,7 +670,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
}
|
||||
|
||||
if (breakpoint instanceof DataBreakpoint) {
|
||||
if (session && !session.capabilities.supportsDataBreakpoints) {
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-data-breakpoint-unverified',
|
||||
message: nls.localize('dataBreakpointUnsupported', "Data breakpoints not supported by this debug type"),
|
||||
@@ -685,30 +685,17 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
if (breakpoint.logMessage || breakpoint.condition || breakpoint.hitCondition) {
|
||||
const messages: string[] = [];
|
||||
if (breakpoint.logMessage) {
|
||||
if (session && !session.capabilities.supportsLogPoints) {
|
||||
return {
|
||||
className: 'debug-breakpoint-unsupported',
|
||||
message: nls.localize('logBreakpointUnsupported', "Logpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-breakpoint-unsupported',
|
||||
message: nls.localize('breakpointUnsupported', "Breakpoints of this type are not supported by the debugger"),
|
||||
};
|
||||
}
|
||||
|
||||
if (breakpoint.logMessage) {
|
||||
messages.push(nls.localize('logMessage', "Log Message: {0}", breakpoint.logMessage));
|
||||
}
|
||||
|
||||
if (session && breakpoint.condition && !session.capabilities.supportsConditionalBreakpoints) {
|
||||
return {
|
||||
className: 'debug-breakpoint-unsupported',
|
||||
message: nls.localize('conditionalBreakpointUnsupported', "Conditional breakpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
if (session && breakpoint.hitCondition && !session.capabilities.supportsHitConditionalBreakpoints) {
|
||||
return {
|
||||
className: 'debug-breakpoint-unsupported',
|
||||
message: nls.localize('hitBreakpointUnsupported', "Hit conditional breakpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
|
||||
if (breakpoint.condition) {
|
||||
messages.push(nls.localize('expression', "Expression: {0}", breakpoint.condition));
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ export class CallStackView extends ViewletPanel {
|
||||
}
|
||||
|
||||
const actions: IAction[] = [];
|
||||
const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: true }, actions, this.contextMenuService);
|
||||
const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: false }, actions, this.contextMenuService);
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
|
||||
@@ -128,11 +128,11 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
|
||||
const debugCategory = nls.localize('debugCategory', "Debug");
|
||||
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }), 'Debug: Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Without Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }), 'Debug: Start Without Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory);
|
||||
@@ -556,13 +556,13 @@ if (isMacintosh) {
|
||||
});
|
||||
};
|
||||
|
||||
registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png')));
|
||||
registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-tb.png')));
|
||||
registerTouchBarEntry(STEP_OVER_ID, STEP_OVER_LABEL, 2, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepover-tb.png')));
|
||||
registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepinto-tb.png')));
|
||||
registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepout-tb.png')));
|
||||
registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-tb.png')));
|
||||
registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-tb.png')));
|
||||
registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png')));
|
||||
registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/pause-tb.png')));
|
||||
registerTouchBarEntry(STEP_OVER_ID, STEP_OVER_LABEL, 2, CONTEXT_IN_DEBUG_MODE, URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/stepover-tb.png')));
|
||||
registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/stepinto-tb.png')));
|
||||
registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/stepout-tb.png')));
|
||||
registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/restart-tb.png')));
|
||||
registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, URI.parse(require.toUrl('vs/workbench/contrib/debug/browser/media/stop-tb.png')));
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
|
||||
this._register(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
|
||||
this._register(this.debugService.getViewModel().onDidFocusSession(() => {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
const session = this.getSelectedSession();
|
||||
if (session) {
|
||||
const index = this.getSessions().indexOf(session);
|
||||
this.select(index);
|
||||
@@ -222,11 +222,11 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
|
||||
}
|
||||
|
||||
protected getActionContext(_: string, index: number): any {
|
||||
return this.debugService.getModel().getSessions()[index];
|
||||
return this.getSessions()[index];
|
||||
}
|
||||
|
||||
private update() {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
const session = this.getSelectedSession();
|
||||
const sessions = this.getSessions();
|
||||
const names = sessions.map(s => {
|
||||
const label = s.getLabel();
|
||||
@@ -240,10 +240,23 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
|
||||
this.setOptions(names.map(data => <ISelectOptionItem>{ text: data }), session ? sessions.indexOf(session) : undefined);
|
||||
}
|
||||
|
||||
private getSelectedSession(): IDebugSession | undefined {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
return session ? this.mapFocusedSessionToSelected(session) : undefined;
|
||||
}
|
||||
|
||||
protected getSessions(): ReadonlyArray<IDebugSession> {
|
||||
const showSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
const sessions = this.debugService.getModel().getSessions();
|
||||
|
||||
return showSubSessions ? sessions : sessions.filter(s => !s.parentSession);
|
||||
}
|
||||
|
||||
protected mapFocusedSessionToSelected(focusedSession: IDebugSession): IDebugSession {
|
||||
const showSubSessions = this.configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
while (focusedSession.parentSession && !showSubSessions) {
|
||||
focusedSession = focusedSession.parentSession;
|
||||
}
|
||||
return focusedSession;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDebugService, State, IEnablement, IBreakpoint, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
|
||||
@@ -16,16 +15,16 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { startDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
export abstract class AbstractDebugAction extends Action {
|
||||
|
||||
protected toDispose: lifecycle.IDisposable[];
|
||||
protected toDispose: IDisposable[];
|
||||
|
||||
constructor(
|
||||
id: string, label: string, cssClass: string,
|
||||
@IDebugService protected debugService: IDebugService,
|
||||
@IKeybindingService protected keybindingService: IKeybindingService,
|
||||
public weight?: number
|
||||
) {
|
||||
super(id, label, cssClass, false);
|
||||
this.toDispose = [];
|
||||
@@ -35,11 +34,11 @@ export abstract class AbstractDebugAction extends Action {
|
||||
this.updateEnablement();
|
||||
}
|
||||
|
||||
public run(e?: any): Promise<any> {
|
||||
run(_: any): Promise<any> {
|
||||
throw new Error('implement me');
|
||||
}
|
||||
|
||||
public get tooltip(): string {
|
||||
get tooltip(): string {
|
||||
const keybinding = this.keybindingService.lookupKeybinding(this.id);
|
||||
const keybindingLabel = keybinding && keybinding.getLabel();
|
||||
|
||||
@@ -54,13 +53,13 @@ export abstract class AbstractDebugAction extends Action {
|
||||
this.enabled = this.isEnabled(state);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +78,7 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
this.updateClass();
|
||||
}
|
||||
|
||||
public get tooltip(): string {
|
||||
get tooltip(): string {
|
||||
if (this.debugService.getConfigurationManager().selectedConfiguration.name) {
|
||||
return ConfigureAction.LABEL;
|
||||
}
|
||||
@@ -93,7 +92,7 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
this.class = configurationCount > 0 ? 'debug-action configure' : 'debug-action configure notification';
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
run(event?: any): Promise<any> {
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
|
||||
this.notificationService.info(nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration."));
|
||||
return Promise.resolve();
|
||||
@@ -127,7 +126,7 @@ export class StartAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<boolean> {
|
||||
run(): Promise<boolean> {
|
||||
return startDebugging(this.debugService, this.historyService, this.isNoDebug());
|
||||
}
|
||||
|
||||
@@ -135,7 +134,7 @@ export class StartAction extends AbstractDebugAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static isEnabled(debugService: IDebugService) {
|
||||
static isEnabled(debugService: IDebugService) {
|
||||
const sessions = debugService.getModel().getSessions();
|
||||
|
||||
if (debugService.state === State.Initializing) {
|
||||
@@ -176,7 +175,7 @@ export class SelectAndStartAction extends AbstractDebugAction {
|
||||
super(id, label, '', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return this.quickOpenService.show('debug ');
|
||||
}
|
||||
}
|
||||
@@ -189,7 +188,7 @@ export class RemoveBreakpointAction extends Action {
|
||||
super(id, label, 'debug-action remove');
|
||||
}
|
||||
|
||||
public run(breakpoint: IBreakpoint): Promise<any> {
|
||||
run(breakpoint: IBreakpoint): Promise<any> {
|
||||
return breakpoint instanceof Breakpoint ? this.debugService.removeBreakpoints(breakpoint.getId())
|
||||
: breakpoint instanceof FunctionBreakpoint ? this.debugService.removeFunctionBreakpoints(breakpoint.getId()) : this.debugService.removeDataBreakpoints(breakpoint.getId());
|
||||
}
|
||||
@@ -204,13 +203,13 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return Promise.all([this.debugService.removeBreakpoints(), this.debugService.removeFunctionBreakpoints(), this.debugService.removeDataBreakpoints()]);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0 || model.getDataBreakpoints().length > 0);
|
||||
return (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0 || model.getDataBreakpoints().length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,13 +222,13 @@ export class EnableAllBreakpointsAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(true);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (<ReadonlyArray<IEnablement>>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => !bp.enabled);
|
||||
return (<ReadonlyArray<IEnablement>>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => !bp.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,13 +241,13 @@ export class DisableAllBreakpointsAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(false);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (<ReadonlyArray<IEnablement>>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => bp.enabled);
|
||||
return (<ReadonlyArray<IEnablement>>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => bp.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,11 +266,11 @@ export class ToggleBreakpointsActivatedAction extends AbstractDebugAction {
|
||||
}));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return this.debugService.setBreakpointsActivated(!this.debugService.getModel().areBreakpointsActivated());
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
return !!(this.debugService.getModel().getFunctionBreakpoints().length || this.debugService.getModel().getBreakpoints().length || this.debugService.getModel().getDataBreakpoints().length);
|
||||
}
|
||||
}
|
||||
@@ -285,13 +284,13 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
return this.debugService.setBreakpointsActivated(true);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (state === State.Running || state === State.Stopped) &&
|
||||
return (state === State.Running || state === State.Stopped) &&
|
||||
((model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getDataBreakpoints().length) > 0);
|
||||
}
|
||||
}
|
||||
@@ -305,12 +304,12 @@ export class AddFunctionBreakpointAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
this.debugService.addFunctionBreakpoint();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
return !this.debugService.getViewModel().getSelectedFunctionBreakpoint()
|
||||
&& this.debugService.getModel().getFunctionBreakpoints().every(fbp => !!fbp.name);
|
||||
}
|
||||
@@ -326,14 +325,14 @@ export class AddWatchExpressionAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
this.debugService.addWatchExpression();
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
protected isEnabled(_: State): boolean {
|
||||
const focusedExpression = this.debugService.getViewModel().getSelectedExpression();
|
||||
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().every(we => !!we.name && we !== focusedExpression);
|
||||
return this.debugService.getModel().getWatchExpressions().every(we => !!we.name && we !== focusedExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,13 +345,13 @@ export class RemoveAllWatchExpressionsAction extends AbstractDebugAction {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
run(): Promise<any> {
|
||||
this.debugService.removeWatchExpressions();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().length > 0;
|
||||
protected isEnabled(_: State): boolean {
|
||||
return this.debugService.getModel().getWatchExpressions().length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,10 +364,10 @@ export class FocusSessionAction extends AbstractDebugAction {
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IEditorService private readonly editorService: IEditorService
|
||||
) {
|
||||
super(id, label, '', debugService, keybindingService, 100);
|
||||
super(id, label, '', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(session: IDebugSession): Promise<any> {
|
||||
run(session: IDebugSession): Promise<any> {
|
||||
this.debugService.focusStackFrame(undefined, undefined, session, true);
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (stackFrame) {
|
||||
@@ -392,17 +391,19 @@ export class CopyValueAction extends Action {
|
||||
this._enabled = typeof this.value === 'string' || (this.value instanceof Variable && !!this.value.evaluateName);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
async run(): Promise<any> {
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
|
||||
if (this.value instanceof Variable && stackFrame && session && this.value.evaluateName) {
|
||||
return session.evaluate(this.value.evaluateName, stackFrame.frameId, this.context).then(result => {
|
||||
return this.clipboardService.writeText(result.body.result);
|
||||
}, err => this.clipboardService.writeText(this.value.value));
|
||||
try {
|
||||
const evaluation = await session.evaluate(this.value.evaluateName, stackFrame.frameId, this.context);
|
||||
this.clipboardService.writeText(evaluation.body.result);
|
||||
} catch (e) {
|
||||
this.clipboardService.writeText(this.value.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return this.clipboardService.writeText(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
private selectedName: string | undefined;
|
||||
private selectedLaunch: ILaunch | undefined;
|
||||
private toDispose: IDisposable[];
|
||||
private _onDidSelectConfigurationName = new Emitter<void>();
|
||||
private readonly _onDidSelectConfigurationName = new Emitter<void>();
|
||||
private configProviders: IDebugConfigurationProvider[];
|
||||
private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[];
|
||||
private debugAdapterFactories = new Map<string, IDebugAdapterFactory>();
|
||||
|
||||
@@ -137,7 +137,7 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
return this.domNode;
|
||||
}
|
||||
|
||||
showAt(range: Range, focus: boolean): Promise<void> {
|
||||
async showAt(range: Range, focus: boolean): Promise<void> {
|
||||
const pos = range.getStartPosition();
|
||||
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
@@ -153,63 +153,64 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
return Promise.resolve(this.hide());
|
||||
}
|
||||
|
||||
let promise: Promise<IExpression | undefined>;
|
||||
let expression;
|
||||
if (session.capabilities.supportsEvaluateForHovers) {
|
||||
const result = new Expression(matchingExpression);
|
||||
promise = result.evaluate(session, this.debugService.getViewModel().focusedStackFrame, 'hover').then(() => result);
|
||||
expression = new Expression(matchingExpression);
|
||||
await expression.evaluate(session, this.debugService.getViewModel().focusedStackFrame, 'hover');
|
||||
} else {
|
||||
promise = this.findExpressionInStackFrame(coalesce(matchingExpression.split('.').map(word => word.trim())));
|
||||
expression = await this.findExpressionInStackFrame(coalesce(matchingExpression.split('.').map(word => word.trim())));
|
||||
}
|
||||
|
||||
return promise.then(expression => {
|
||||
if (!expression || (expression instanceof Expression && !expression.available)) {
|
||||
this.hide();
|
||||
return undefined;
|
||||
}
|
||||
if (!expression || (expression instanceof Expression && !expression.available)) {
|
||||
this.hide();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
|
||||
range: new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length),
|
||||
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
|
||||
}]);
|
||||
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
|
||||
range: new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length),
|
||||
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
|
||||
}]);
|
||||
|
||||
return this.doShow(pos, expression, focus);
|
||||
});
|
||||
return this.doShow(pos, expression, focus);
|
||||
}
|
||||
|
||||
private static _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({
|
||||
className: 'hoverHighlight'
|
||||
});
|
||||
|
||||
private doFindExpression(container: IExpressionContainer, namesToFind: string[]): Promise<IExpression | null> {
|
||||
private async doFindExpression(container: IExpressionContainer, namesToFind: string[]): Promise<IExpression | null> {
|
||||
if (!container) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return container.getChildren().then(children => {
|
||||
// look for our variable in the list. First find the parents of the hovered variable if there are any.
|
||||
const filtered = children.filter(v => namesToFind[0] === v.name);
|
||||
if (filtered.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
const children = await container.getChildren();
|
||||
// look for our variable in the list. First find the parents of the hovered variable if there are any.
|
||||
const filtered = children.filter(v => namesToFind[0] === v.name);
|
||||
if (filtered.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (namesToFind.length === 1) {
|
||||
return filtered[0];
|
||||
} else {
|
||||
return this.doFindExpression(filtered[0], namesToFind.slice(1));
|
||||
}
|
||||
});
|
||||
if (namesToFind.length === 1) {
|
||||
return filtered[0];
|
||||
} else {
|
||||
return this.doFindExpression(filtered[0], namesToFind.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
private findExpressionInStackFrame(namesToFind: string[]): Promise<IExpression | undefined> {
|
||||
return this.debugService.getViewModel().focusedStackFrame!.getScopes()
|
||||
.then(scopes => scopes.filter(s => !s.expensive))
|
||||
.then(scopes => Promise.all(scopes.map(scope => this.doFindExpression(scope, namesToFind))))
|
||||
.then(coalesce)
|
||||
// only show if all expressions found have the same value
|
||||
.then(expressions => (expressions.length > 0 && expressions.every(e => e.value === expressions[0].value)) ? expressions[0] : undefined);
|
||||
private async findExpressionInStackFrame(namesToFind: string[]): Promise<IExpression | undefined> {
|
||||
const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (!focusedStackFrame) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const scopes = await focusedStackFrame.getScopes();
|
||||
const nonExpensive = scopes.filter(s => !s.expensive);
|
||||
const expressions = coalesce(await Promise.all(nonExpensive.map(scope => this.doFindExpression(scope, namesToFind))));
|
||||
// only show if all expressions found have the same value
|
||||
return expressions.length > 0 && expressions.every(e => e.value === expressions[0].value) ? expressions[0] : undefined;
|
||||
}
|
||||
|
||||
private doShow(position: Position, expression: IExpression, focus: boolean, forceValueHover = false): Promise<void> {
|
||||
private async doShow(position: Position, expression: IExpression, focus: boolean, forceValueHover = false): Promise<void> {
|
||||
if (!this.domNode) {
|
||||
this.create();
|
||||
}
|
||||
@@ -239,20 +240,19 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
this.valueContainer.hidden = true;
|
||||
this.complexValueContainer.hidden = false;
|
||||
|
||||
return this.tree.setInput(expression).then(() => {
|
||||
this.complexValueTitle.textContent = replaceWhitespace(expression.value);
|
||||
this.complexValueTitle.title = expression.value;
|
||||
this.layoutTreeAndContainer();
|
||||
this.editor.layoutContentWidget(this);
|
||||
this.scrollbar.scanDomNode();
|
||||
this.tree.scrollTop = 0;
|
||||
this.tree.scrollLeft = 0;
|
||||
await this.tree.setInput(expression);
|
||||
this.complexValueTitle.textContent = replaceWhitespace(expression.value);
|
||||
this.complexValueTitle.title = expression.value;
|
||||
this.layoutTreeAndContainer();
|
||||
this.editor.layoutContentWidget(this);
|
||||
this.scrollbar.scanDomNode();
|
||||
this.tree.scrollTop = 0;
|
||||
this.tree.scrollLeft = 0;
|
||||
|
||||
if (focus) {
|
||||
this.editor.render();
|
||||
this.tree.domFocus();
|
||||
}
|
||||
});
|
||||
if (focus) {
|
||||
this.editor.render();
|
||||
this.tree.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private layoutTreeAndContainer(): void {
|
||||
|
||||
@@ -21,19 +21,19 @@ class AddConfigEntry extends QuickOpenEntry {
|
||||
super(highlights);
|
||||
}
|
||||
|
||||
public getLabel(): string {
|
||||
getLabel(): string {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
public getDescription(): string {
|
||||
getDescription(): string {
|
||||
return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.name : '';
|
||||
}
|
||||
|
||||
public getAriaLabel(): string {
|
||||
getAriaLabel(): string {
|
||||
return nls.localize('entryAriaLabel', "{0}, debug", this.getLabel());
|
||||
}
|
||||
|
||||
public run(mode: Mode): boolean {
|
||||
run(mode: Mode): boolean {
|
||||
if (mode === Mode.PREVIEW) {
|
||||
return false;
|
||||
}
|
||||
@@ -49,19 +49,19 @@ class StartDebugEntry extends QuickOpenEntry {
|
||||
super(highlights);
|
||||
}
|
||||
|
||||
public getLabel(): string {
|
||||
getLabel(): string {
|
||||
return this.configurationName;
|
||||
}
|
||||
|
||||
public getDescription(): string {
|
||||
getDescription(): string {
|
||||
return this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? this.launch.name : '';
|
||||
}
|
||||
|
||||
public getAriaLabel(): string {
|
||||
getAriaLabel(): string {
|
||||
return nls.localize('entryAriaLabel', "{0}, debug", this.getLabel());
|
||||
}
|
||||
|
||||
public run(mode: Mode): boolean {
|
||||
run(mode: Mode): boolean {
|
||||
if (mode === Mode.PREVIEW || !StartAction.isEnabled(this.debugService)) {
|
||||
return false;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class StartDebugEntry extends QuickOpenEntry {
|
||||
|
||||
export class DebugQuickOpenHandler extends QuickOpenHandler {
|
||||
|
||||
public static readonly ID = 'workbench.picker.launch';
|
||||
static readonly ID = 'workbench.picker.launch';
|
||||
|
||||
private autoFocusIndex: number | undefined;
|
||||
|
||||
@@ -88,11 +88,11 @@ export class DebugQuickOpenHandler extends QuickOpenHandler {
|
||||
super();
|
||||
}
|
||||
|
||||
public getAriaLabel(): string {
|
||||
getAriaLabel(): string {
|
||||
return nls.localize('debugAriaLabel', "Type a name of a launch configuration to run.");
|
||||
}
|
||||
|
||||
public getResults(input: string, token: CancellationToken): Promise<QuickOpenModel> {
|
||||
getResults(input: string, token: CancellationToken): Promise<QuickOpenModel> {
|
||||
const configurations: QuickOpenEntry[] = [];
|
||||
|
||||
const configManager = this.debugService.getConfigurationManager();
|
||||
@@ -122,14 +122,14 @@ export class DebugQuickOpenHandler extends QuickOpenHandler {
|
||||
return Promise.resolve(new QuickOpenModel(configurations));
|
||||
}
|
||||
|
||||
public getAutoFocus(input: string): IAutoFocus {
|
||||
getAutoFocus(input: string): IAutoFocus {
|
||||
return {
|
||||
autoFocusFirstEntry: !!input,
|
||||
autoFocusIndex: this.autoFocusIndex
|
||||
};
|
||||
}
|
||||
|
||||
public getEmptyLabel(searchString: string): string {
|
||||
getEmptyLabel(searchString: string): string {
|
||||
if (searchString.length > 0) {
|
||||
return nls.localize('noConfigurationsMatching', "No debug configurations matching");
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { deepClone, equals } from 'vs/base/common/objects';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
@@ -167,9 +167,7 @@ export class DebugService implements IDebugService {
|
||||
this.toDispose.push(this.viewModel.onDidFocusStackFrame(() => {
|
||||
this.onStateChange();
|
||||
}));
|
||||
this.toDispose.push(this.viewModel.onDidFocusSession(session => {
|
||||
const id = session ? session.getId() : undefined;
|
||||
this.model.setBreakpointsSessionId(id);
|
||||
this.toDispose.push(this.viewModel.onDidFocusSession(() => {
|
||||
this.onStateChange();
|
||||
}));
|
||||
}
|
||||
@@ -255,7 +253,7 @@ export class DebugService implements IDebugService {
|
||||
* main entry point
|
||||
* properly manages compounds, checks for errors and handles the initializing state.
|
||||
*/
|
||||
startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, noDebug = false, parentSession?: IDebugSession): Promise<boolean> {
|
||||
startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise<boolean> {
|
||||
|
||||
this.startInitializingState();
|
||||
// make sure to save all files and that the configuration is up to date
|
||||
@@ -318,7 +316,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug, parentSession);
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), options);
|
||||
})).then(values => values.every(success => !!success)); // Compound launch is a success only if each configuration launched successfully
|
||||
}
|
||||
|
||||
@@ -328,7 +326,7 @@ export class DebugService implements IDebugService {
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
|
||||
return this.createSession(launch, config, noDebug, parentSession);
|
||||
return this.createSession(launch, config, options);
|
||||
});
|
||||
}));
|
||||
}).then(success => {
|
||||
@@ -344,7 +342,7 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* gets the debugger for the type, resolves configurations by providers, substitutes variables and runs prelaunch tasks
|
||||
*/
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean, parentSession?: IDebugSession): Promise<boolean> {
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, options?: IDebugSessionOptions): Promise<boolean> {
|
||||
// We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes.
|
||||
// Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config.
|
||||
let type: string | undefined;
|
||||
@@ -356,7 +354,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
const unresolvedConfig = deepClone(config);
|
||||
|
||||
if (noDebug) {
|
||||
if (options && options.noDebug) {
|
||||
config!.noDebug = true;
|
||||
}
|
||||
|
||||
@@ -390,7 +388,7 @@ export class DebugService implements IDebugService {
|
||||
const workspace = launch ? launch.workspace : undefined;
|
||||
return this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask).then(result => {
|
||||
if (result === TaskRunResult.Success) {
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, parentSession);
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -419,9 +417,9 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* instantiates the new session, initializes the session, registers session listeners and reports telemetry
|
||||
*/
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, parentSession?: IDebugSession): Promise<boolean> {
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, options?: IDebugSessionOptions): Promise<boolean> {
|
||||
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, parentSession);
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, options);
|
||||
this.model.addSession(session);
|
||||
// register listeners as the very first thing!
|
||||
this.registerSessionListeners(session);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CompletionItem, completionKindFromString } from 'vs/editor/common/modes';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
@@ -43,6 +43,7 @@ export class DebugSession implements IDebugSession {
|
||||
private _subId: string | undefined;
|
||||
private raw: RawDebugSession | undefined;
|
||||
private initialized = false;
|
||||
private _options: IDebugSessionOptions;
|
||||
|
||||
private sources = new Map<string, Source>();
|
||||
private threads = new Map<number, Thread>();
|
||||
@@ -66,7 +67,7 @@ export class DebugSession implements IDebugSession {
|
||||
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
|
||||
public root: IWorkspaceFolder,
|
||||
private model: DebugModel,
|
||||
private _parentSession: IDebugSession | undefined,
|
||||
options: IDebugSessionOptions | undefined,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
@@ -79,7 +80,12 @@ export class DebugSession implements IDebugSession {
|
||||
@IOpenerService private readonly openerService: IOpenerService
|
||||
) {
|
||||
this.id = generateUuid();
|
||||
this.repl = new ReplModel(this);
|
||||
this._options = options || {};
|
||||
if (this.hasSeparateRepl()) {
|
||||
this.repl = new ReplModel();
|
||||
} else {
|
||||
this.repl = (this.parentSession as DebugSession).repl;
|
||||
}
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
@@ -103,7 +109,7 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return this._parentSession;
|
||||
return this._options.parentSession;
|
||||
}
|
||||
|
||||
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig | undefined }) {
|
||||
@@ -307,7 +313,7 @@ export class DebugSession implements IDebugSession {
|
||||
data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]);
|
||||
}
|
||||
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -321,7 +327,7 @@ export class DebugSession implements IDebugSession {
|
||||
for (let i = 0; i < fbpts.length; i++) {
|
||||
data.set(fbpts[i].getId(), response.body.breakpoints[i]);
|
||||
}
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -361,7 +367,7 @@ export class DebugSession implements IDebugSession {
|
||||
for (let i = 0; i < dataBreakpoints.length; i++) {
|
||||
data.set(dataBreakpoints[i].getId(), response.body.breakpoints[i]);
|
||||
}
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -838,7 +844,7 @@ export class DebugSession implements IDebugSession {
|
||||
}], false);
|
||||
if (bps.length === 1) {
|
||||
const data = new Map<string, DebugProtocol.Breakpoint>([[bps[0].getId(), event.body.breakpoint]]);
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,11 +863,11 @@ export class DebugSession implements IDebugSession {
|
||||
event.body.breakpoint.column = undefined;
|
||||
}
|
||||
const data = new Map<string, DebugProtocol.Breakpoint>([[breakpoint.getId(), event.body.breakpoint]]);
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
if (functionBreakpoint) {
|
||||
const data = new Map<string, DebugProtocol.Breakpoint>([[functionBreakpoint.getId(), event.body.breakpoint]]);
|
||||
this.model.setBreakpointSessionData(this.getId(), data);
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -879,6 +885,7 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
this.rawListeners.push(this.raw.onDidExitAdapter(event => {
|
||||
this.initialized = true;
|
||||
this.model.setBreakpointSessionData(this.getId(), this.capabilities, undefined);
|
||||
this._onDidEndAdapter.fire(event);
|
||||
}));
|
||||
}
|
||||
@@ -954,13 +961,17 @@ export class DebugSession implements IDebugSession {
|
||||
return this.repl.getReplElements();
|
||||
}
|
||||
|
||||
hasSeparateRepl(): boolean {
|
||||
return !this.parentSession || this._options.repl !== 'mergeWithParent';
|
||||
}
|
||||
|
||||
removeReplExpressions(): void {
|
||||
this.repl.removeReplExpressions();
|
||||
this._onDidChangeREPLElements.fire();
|
||||
}
|
||||
|
||||
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
const expressionEvaluated = this.repl.addReplExpression(stackFrame, name);
|
||||
const expressionEvaluated = this.repl.addReplExpression(this, stackFrame, name);
|
||||
this._onDidChangeREPLElements.fire();
|
||||
await expressionEvaluated;
|
||||
this._onDidChangeREPLElements.fire();
|
||||
@@ -974,7 +985,7 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
|
||||
logToRepl(sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) {
|
||||
this.repl.logToRepl(sev, args, frame);
|
||||
this.repl.logToRepl(this, sev, args, frame);
|
||||
this._onDidChangeREPLElements.fire();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#848484"/>
|
||||
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 154 B After Width: | Height: | Size: 154 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4.84323L11.1365 7.97969L8 11.1161L4.86355 7.97969L8 4.84323Z" stroke="#848484" stroke-width="1.25"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.02039 7.97961L8 3L12.9796 7.97961L8 12.9592L3.02039 7.97961ZM8 10.7696L10.79 7.97961L8 5.18956L5.20996 7.97961L8 10.7696Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 295 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#E51400"/>
|
||||
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 154 B After Width: | Height: | Size: 154 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3259 10.2223C11.7654 9.56448 12 8.79112 12 8C12.0001 7.47467 11.8968 6.95447 11.6958 6.4691C11.4948 5.98374 11.2002 5.54273 10.8287 5.17126C10.4573 4.7998 10.0163 4.50517 9.5309 4.3042C9.04553 4.10323 8.52533 3.99986 8 4C7.20888 4 6.43552 4.2346 5.77772 4.67412C5.11992 5.11365 4.60723 5.73836 4.30448 6.46927C4.00173 7.20017 3.92252 8.00444 4.07686 8.78036C4.2312 9.55628 4.61216 10.269 5.17157 10.8284C5.73098 11.3878 6.44372 11.7688 7.21964 11.9231C7.99556 12.0775 8.79983 11.9983 9.53073 11.6955C10.2616 11.3928 10.8864 10.8801 11.3259 10.2223ZM8.4 9.6H7.6V10.4H8.4V9.6ZM7.6 8.8V5.6H8.4V8.8H7.6Z" fill="#E51400"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3259 10.2223C11.7654 9.56448 12 8.79112 12 8C12.0001 7.47467 11.8968 6.95447 11.6958 6.4691C11.4948 5.98374 11.2002 5.54273 10.8287 5.17126C10.4573 4.7998 10.0163 4.50517 9.5309 4.3042C9.04553 4.10323 8.52533 3.99986 8 4C7.20888 4 6.43552 4.2346 5.77772 4.67412C5.11992 5.11365 4.60723 5.73836 4.30448 6.46927C4.00173 7.20017 3.92252 8.00444 4.07686 8.78036C4.2312 9.55628 4.61216 10.269 5.17157 10.8284C5.73098 11.3878 6.44372 11.7688 7.21964 11.9231C7.99556 12.0775 8.79983 11.9983 9.53073 11.6955C10.2616 11.3928 10.8864 10.8801 11.3259 10.2223ZM8.65 10H7.4V11H8.65V10ZM7.4 9V5H8.65V9H7.4Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 774 B After Width: | Height: | Size: 767 B |
@@ -356,7 +356,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
|
||||
getActions(): IAction[] {
|
||||
const result: IAction[] = [];
|
||||
if (this.debugService.getModel().getSessions(true).filter(s => !sessionsToIgnore.has(s)).length > 1) {
|
||||
if (this.debugService.getModel().getSessions(true).filter(s => s.hasSeparateRepl() && !sessionsToIgnore.has(s)).length > 1) {
|
||||
result.push(this.selectReplAction);
|
||||
}
|
||||
result.push(this.clearReplAction);
|
||||
@@ -504,7 +504,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => e.element
|
||||
getActionsContext: () => e.element,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -968,12 +969,15 @@ registerEditorAction(FilterReplAction);
|
||||
|
||||
class SelectReplActionViewItem extends FocusSessionActionViewItem {
|
||||
|
||||
protected getActionContext(_: string, index: number): any {
|
||||
return this.debugService.getModel().getSessions(true)[index];
|
||||
protected getSessions(): ReadonlyArray<IDebugSession> {
|
||||
return this.debugService.getModel().getSessions(true).filter(s => s.hasSeparateRepl() && !sessionsToIgnore.has(s));
|
||||
}
|
||||
|
||||
protected getSessions(): ReadonlyArray<IDebugSession> {
|
||||
return this.debugService.getModel().getSessions(true).filter(s => !sessionsToIgnore.has(s));
|
||||
protected mapFocusedSessionToSelected(focusedSession: IDebugSession): IDebugSession {
|
||||
while (focusedSession.parentSession && !focusedSession.hasSeparateRepl()) {
|
||||
focusedSession = focusedSession.parentSession;
|
||||
}
|
||||
return focusedSession;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
const $ = dom.$;
|
||||
let forgetScopes = true;
|
||||
@@ -188,7 +189,8 @@ export class VariablesView extends ViewletPanel {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => variable
|
||||
getActionsContext: () => variable,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import { IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { variableSetEmitter, VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
|
||||
@@ -175,7 +176,8 @@ export class WatchExpressionsView extends ViewletPanel {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element
|
||||
getActionsContext: () => element,
|
||||
onHide: () => dispose(actions)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,14 @@ export interface LoadedSourceEvent {
|
||||
source: Source;
|
||||
}
|
||||
|
||||
export type IDebugSessionReplMode = 'separate' | 'mergeWithParent';
|
||||
|
||||
export interface IDebugSessionOptions {
|
||||
noDebug?: boolean;
|
||||
parentSession?: IDebugSession;
|
||||
repl?: IDebugSessionReplMode;
|
||||
}
|
||||
|
||||
export interface IDebugSession extends ITreeElement {
|
||||
|
||||
readonly configuration: IConfig;
|
||||
@@ -173,7 +181,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
clearThreads(removeThreads: boolean, reference?: number): void;
|
||||
|
||||
getReplElements(): IReplElement[];
|
||||
|
||||
hasSeparateRepl(): boolean;
|
||||
removeReplExpressions(): void;
|
||||
addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void>;
|
||||
appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void;
|
||||
@@ -311,7 +319,7 @@ export interface IStackFrame extends ITreeElement {
|
||||
forgetScopes(): void;
|
||||
restart(): Promise<any>;
|
||||
toString(): string;
|
||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise<ITextEditor | null>;
|
||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise<ITextEditor | undefined>;
|
||||
equals(other: IStackFrame): boolean;
|
||||
}
|
||||
|
||||
@@ -342,6 +350,7 @@ export interface IBaseBreakpoint extends IEnablement {
|
||||
readonly hitCondition?: string;
|
||||
readonly logMessage?: string;
|
||||
readonly verified: boolean;
|
||||
readonly supported: boolean;
|
||||
getIdFromAdapter(sessionId: string): number | undefined;
|
||||
}
|
||||
|
||||
@@ -815,7 +824,7 @@ export interface IDebugService {
|
||||
* Returns true if the start debugging was successfull. For compound launches, all configurations have to start successfuly for it to return success.
|
||||
* On errors the startDebugging will throw an error, however some error and cancelations are handled and in that case will simply return false.
|
||||
*/
|
||||
startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, noDebug?: boolean, parentSession?: IDebugSession): Promise<boolean>;
|
||||
startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Restarts a session or creates a new one if there is no active session.
|
||||
|
||||
@@ -23,6 +23,7 @@ import { posix } from 'vs/base/common/path';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextEditor } from 'vs/workbench/common/editor';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
||||
export class ExpressionContainer implements IExpressionContainer {
|
||||
|
||||
@@ -337,8 +338,8 @@ export class StackFrame implements IStackFrame {
|
||||
return sourceToString === UNKNOWN_SOURCE_LABEL ? this.name : `${this.name} (${sourceToString})`;
|
||||
}
|
||||
|
||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<ITextEditor | null> {
|
||||
return !this.source.available ? Promise.resolve(null) :
|
||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<ITextEditor | undefined> {
|
||||
return !this.source.available ? Promise.resolve(undefined) :
|
||||
this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned);
|
||||
}
|
||||
|
||||
@@ -498,10 +499,28 @@ export class Enablement implements IEnablement {
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseBreakpoint extends Enablement implements IBaseBreakpoint {
|
||||
interface IBreakpointSessionData extends DebugProtocol.Breakpoint {
|
||||
supportsConditionalBreakpoints: boolean;
|
||||
supportsHitConditionalBreakpoints: boolean;
|
||||
supportsLogPoints: boolean;
|
||||
supportsFunctionBreakpoints: boolean;
|
||||
supportsDataBreakpoints: boolean;
|
||||
}
|
||||
|
||||
private sessionData = new Map<string, DebugProtocol.Breakpoint>();
|
||||
private sessionId: string | undefined;
|
||||
function toBreakpointSessionData(data: DebugProtocol.Breakpoint, capabilities: DebugProtocol.Capabilities): IBreakpointSessionData {
|
||||
return mixin({
|
||||
supportsConditionalBreakpoints: !!capabilities.supportsConditionalBreakpoints,
|
||||
supportsHitConditionalBreakpoints: !!capabilities.supportsHitConditionalBreakpoints,
|
||||
supportsLogPoints: !!capabilities.supportsLogPoints,
|
||||
supportsFunctionBreakpoints: !!capabilities.supportsFunctionBreakpoints,
|
||||
supportsDataBreakpoints: !!capabilities.supportsDataBreakpoints
|
||||
}, data);
|
||||
}
|
||||
|
||||
export abstract class BaseBreakpoint extends Enablement implements IBaseBreakpoint {
|
||||
|
||||
private sessionData = new Map<string, IBreakpointSessionData>();
|
||||
protected data: IBreakpointSessionData | undefined;
|
||||
|
||||
constructor(
|
||||
enabled: boolean,
|
||||
@@ -516,32 +535,38 @@ export class BaseBreakpoint extends Enablement implements IBaseBreakpoint {
|
||||
}
|
||||
}
|
||||
|
||||
protected getSessionData(): DebugProtocol.Breakpoint | undefined {
|
||||
return this.sessionId ? this.sessionData.get(this.sessionId) : undefined;
|
||||
}
|
||||
setSessionData(sessionId: string, data: IBreakpointSessionData | undefined): void {
|
||||
if (!data) {
|
||||
this.sessionData.delete(sessionId);
|
||||
} else {
|
||||
this.sessionData.set(sessionId, data);
|
||||
}
|
||||
|
||||
setSessionData(sessionId: string, data: DebugProtocol.Breakpoint): void {
|
||||
this.sessionData.set(sessionId, data);
|
||||
}
|
||||
|
||||
setSessionId(sessionId: string | undefined): void {
|
||||
this.sessionId = sessionId;
|
||||
const allData = Array.from(this.sessionData.values());
|
||||
const verifiedData = distinct(allData.filter(d => d.verified), d => `${d.line}:${d.column}`);
|
||||
if (verifiedData.length) {
|
||||
// In case multiple session verified the breakpoint and they provide different data show the intial data that the user set (corner case)
|
||||
this.data = verifiedData.length === 1 ? verifiedData[0] : undefined;
|
||||
} else {
|
||||
// No session verified the breakpoint
|
||||
this.data = allData.length ? allData[0] : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
get message(): string | undefined {
|
||||
const data = this.getSessionData();
|
||||
if (!data) {
|
||||
if (!this.data) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return data.message;
|
||||
return this.data.message;
|
||||
}
|
||||
|
||||
get verified(): boolean {
|
||||
const data = this.getSessionData();
|
||||
return data ? data.verified : true;
|
||||
return this.data ? this.data.verified : true;
|
||||
}
|
||||
|
||||
abstract get supported(): boolean;
|
||||
|
||||
getIdFromAdapter(sessionId: string): number | undefined {
|
||||
const data = this.sessionData.get(sessionId);
|
||||
return data ? data.id : undefined;
|
||||
@@ -576,23 +601,20 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
}
|
||||
|
||||
get lineNumber(): number {
|
||||
const data = this.getSessionData();
|
||||
return this.verified && data && typeof data.line === 'number' ? data.line : this._lineNumber;
|
||||
return this.verified && this.data && typeof this.data.line === 'number' ? this.data.line : this._lineNumber;
|
||||
}
|
||||
|
||||
get verified(): boolean {
|
||||
const data = this.getSessionData();
|
||||
if (data) {
|
||||
return data.verified && !this.textFileService.isDirty(this.uri);
|
||||
if (this.data) {
|
||||
return this.data.verified && !this.textFileService.isDirty(this.uri);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
get column(): number | undefined {
|
||||
const data = this.getSessionData();
|
||||
// Only respect the column if the user explictly set the column to have an inline breakpoint
|
||||
return data && typeof data.column === 'number' && typeof this._column === 'number' ? data.column : this._column;
|
||||
return this.verified && this.data && typeof this.data.column === 'number' && typeof this._column === 'number' ? this.data.column : this._column;
|
||||
}
|
||||
|
||||
get message(): string | undefined {
|
||||
@@ -604,18 +626,15 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
}
|
||||
|
||||
get adapterData(): any {
|
||||
const data = this.getSessionData();
|
||||
return data && data.source && data.source.adapterData ? data.source.adapterData : this._adapterData;
|
||||
return this.data && this.data.source && this.data.source.adapterData ? this.data.source.adapterData : this._adapterData;
|
||||
}
|
||||
|
||||
get endLineNumber(): number | undefined {
|
||||
const data = this.getSessionData();
|
||||
return data ? data.endLine : undefined;
|
||||
return this.verified && this.data ? this.data.endLine : undefined;
|
||||
}
|
||||
|
||||
get endColumn(): number | undefined {
|
||||
const data = this.getSessionData();
|
||||
return data ? data.endColumn : undefined;
|
||||
return this.verified && this.data ? this.data.endColumn : undefined;
|
||||
}
|
||||
|
||||
get sessionAgnosticData(): { lineNumber: number, column: number | undefined } {
|
||||
@@ -625,7 +644,25 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
};
|
||||
}
|
||||
|
||||
setSessionData(sessionId: string, data: DebugProtocol.Breakpoint): void {
|
||||
get supported(): boolean {
|
||||
if (!this.data) {
|
||||
return true;
|
||||
}
|
||||
if (this.logMessage && !this.data.supportsLogPoints) {
|
||||
return false;
|
||||
}
|
||||
if (this.condition && !this.data.supportsConditionalBreakpoints) {
|
||||
return false;
|
||||
}
|
||||
if (this.hitCondition && !this.data.supportsHitConditionalBreakpoints) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
setSessionData(sessionId: string, data: IBreakpointSessionData | undefined): void {
|
||||
super.setSessionData(sessionId, data);
|
||||
if (!this._adapterData) {
|
||||
this._adapterData = this.adapterData;
|
||||
@@ -685,6 +722,14 @@ export class FunctionBreakpoint extends BaseBreakpoint implements IFunctionBreak
|
||||
return result;
|
||||
}
|
||||
|
||||
get supported(): boolean {
|
||||
if (!this.data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.data.supportsFunctionBreakpoints;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.name;
|
||||
}
|
||||
@@ -713,6 +758,14 @@ export class DataBreakpoint extends BaseBreakpoint implements IDataBreakpoint {
|
||||
return result;
|
||||
}
|
||||
|
||||
get supported(): boolean {
|
||||
if (!this.data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.data.supportsDataBreakpoints;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.label;
|
||||
}
|
||||
@@ -751,7 +804,6 @@ export class DebugModel implements IDebugModel {
|
||||
private sessions: IDebugSession[];
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private schedulers = new Map<string, RunOnceScheduler>();
|
||||
private breakpointsSessionId: string | undefined;
|
||||
private breakpointsActivated = true;
|
||||
private readonly _onDidChangeBreakpoints: Emitter<IBreakpointsChangeEvent | undefined>;
|
||||
private readonly _onDidChangeCallStack: Emitter<void>;
|
||||
@@ -945,7 +997,6 @@ export class DebugModel implements IDebugModel {
|
||||
|
||||
addBreakpoints(uri: uri, rawData: IBreakpointData[], fireEvent = true): IBreakpoint[] {
|
||||
const newBreakpoints = rawData.map(rawBp => new Breakpoint(uri, rawBp.lineNumber, rawBp.column, rawBp.enabled === false ? false : true, rawBp.condition, rawBp.hitCondition, rawBp.logMessage, undefined, this.textFileService, rawBp.id));
|
||||
newBreakpoints.forEach(bp => bp.setSessionId(this.breakpointsSessionId));
|
||||
this.breakpoints = this.breakpoints.concat(newBreakpoints);
|
||||
this.breakpointsActivated = true;
|
||||
this.sortAndDeDup();
|
||||
@@ -975,23 +1026,35 @@ export class DebugModel implements IDebugModel {
|
||||
this._onDidChangeBreakpoints.fire({ changed: updated });
|
||||
}
|
||||
|
||||
setBreakpointSessionData(sessionId: string, data: Map<string, DebugProtocol.Breakpoint>): void {
|
||||
setBreakpointSessionData(sessionId: string, capabilites: DebugProtocol.Capabilities, data: Map<string, DebugProtocol.Breakpoint> | undefined): void {
|
||||
this.breakpoints.forEach(bp => {
|
||||
const bpData = data.get(bp.getId());
|
||||
if (bpData) {
|
||||
bp.setSessionData(sessionId, bpData);
|
||||
if (!data) {
|
||||
bp.setSessionData(sessionId, undefined);
|
||||
} else {
|
||||
const bpData = data.get(bp.getId());
|
||||
if (bpData) {
|
||||
bp.setSessionData(sessionId, toBreakpointSessionData(bpData, capabilites));
|
||||
}
|
||||
}
|
||||
});
|
||||
this.functionBreakpoints.forEach(fbp => {
|
||||
const fbpData = data.get(fbp.getId());
|
||||
if (fbpData) {
|
||||
fbp.setSessionData(sessionId, fbpData);
|
||||
if (!data) {
|
||||
fbp.setSessionData(sessionId, undefined);
|
||||
} else {
|
||||
const fbpData = data.get(fbp.getId());
|
||||
if (fbpData) {
|
||||
fbp.setSessionData(sessionId, toBreakpointSessionData(fbpData, capabilites));
|
||||
}
|
||||
}
|
||||
});
|
||||
this.dataBreakopints.forEach(dbp => {
|
||||
const dbpData = data.get(dbp.getId());
|
||||
if (dbpData) {
|
||||
dbp.setSessionData(sessionId, dbpData);
|
||||
if (!data) {
|
||||
dbp.setSessionData(sessionId, undefined);
|
||||
} else {
|
||||
const dbpData = data.get(dbp.getId());
|
||||
if (dbpData) {
|
||||
dbp.setSessionData(sessionId, toBreakpointSessionData(dbpData, capabilites));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1000,17 +1063,6 @@ export class DebugModel implements IDebugModel {
|
||||
});
|
||||
}
|
||||
|
||||
setBreakpointsSessionId(sessionId: string | undefined): void {
|
||||
this.breakpointsSessionId = sessionId;
|
||||
this.breakpoints.forEach(bp => bp.setSessionId(sessionId));
|
||||
this.functionBreakpoints.forEach(fbp => fbp.setSessionId(sessionId));
|
||||
this.dataBreakopints.forEach(dbp => dbp.setSessionId(sessionId));
|
||||
|
||||
this._onDidChangeBreakpoints.fire({
|
||||
sessionOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
private sortAndDeDup(): void {
|
||||
this.breakpoints = this.breakpoints.sort((first, second) => {
|
||||
if (first.uri.toString() !== second.uri.toString()) {
|
||||
|
||||
@@ -137,7 +137,7 @@ export const launchSchema: IJSONSchema = {
|
||||
id: launchSchemaId,
|
||||
type: 'object',
|
||||
title: nls.localize('app.launch.json.title', "Launch"),
|
||||
allowsTrailingCommas: true,
|
||||
allowTrailingCommas: true,
|
||||
allowComments: true,
|
||||
required: [],
|
||||
default: { version: '0.2.0', configurations: [], compounds: [] },
|
||||
|
||||
@@ -13,7 +13,6 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { ITextEditor } from 'vs/workbench/common/editor';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
|
||||
export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
||||
|
||||
@@ -32,9 +31,9 @@ export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Sourc
|
||||
|
||||
export class Source {
|
||||
|
||||
public readonly uri: uri;
|
||||
public available: boolean;
|
||||
public raw: DebugProtocol.Source;
|
||||
readonly uri: uri;
|
||||
available: boolean;
|
||||
raw: DebugProtocol.Source;
|
||||
|
||||
constructor(raw_: DebugProtocol.Source | undefined, sessionId: string) {
|
||||
let path: string;
|
||||
@@ -94,8 +93,8 @@ export class Source {
|
||||
return this.uri.scheme === DEBUG_SCHEME;
|
||||
}
|
||||
|
||||
openInEditor(editorService: IEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<ITextEditor | null> {
|
||||
return !this.available ? Promise.resolve(null) : editorService.openEditor({
|
||||
openInEditor(editorService: IEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<ITextEditor | undefined> {
|
||||
return !this.available ? Promise.resolve(undefined) : editorService.openEditor({
|
||||
resource: this.uri,
|
||||
description: this.origin,
|
||||
options: {
|
||||
@@ -105,7 +104,7 @@ export class Source {
|
||||
revealInCenterIfOutsideViewport: true,
|
||||
pinned: pinned || (!preserveFocus && !this.inMemory)
|
||||
}
|
||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(withUndefinedAsNull);
|
||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
}
|
||||
|
||||
static getEncodedDebugData(modelUri: uri): { name: string, path: string, sessionId?: string, sourceReference?: number } {
|
||||
|
||||
@@ -27,7 +27,7 @@ export function startDebugging(debugService: IDebugService, historyService: IHis
|
||||
configurationManager.selectConfiguration(launch);
|
||||
}
|
||||
|
||||
return debugService.startDebugging(launch, undefined, noDebug);
|
||||
return debugService.startDebugging(launch, undefined, { noDebug });
|
||||
}
|
||||
|
||||
export function formatPII(value: string, excludePII: boolean, args: { [key: string]: string }): string {
|
||||
|
||||
@@ -108,16 +108,14 @@ export class ReplEvaluationResult extends ExpressionContainer implements IReplEl
|
||||
export class ReplModel {
|
||||
private replElements: IReplElement[] = [];
|
||||
|
||||
constructor(private session: IDebugSession) { }
|
||||
|
||||
getReplElements(): IReplElement[] {
|
||||
return this.replElements;
|
||||
}
|
||||
|
||||
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
async addReplExpression(session: IDebugSession, stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
this.addReplElement(new ReplEvaluationInput(name));
|
||||
const result = new ReplEvaluationResult();
|
||||
await result.evaluateExpression(name, this.session, stackFrame, 'repl');
|
||||
await result.evaluateExpression(name, session, stackFrame, 'repl');
|
||||
this.addReplElement(result);
|
||||
}
|
||||
|
||||
@@ -153,14 +151,14 @@ export class ReplModel {
|
||||
}
|
||||
}
|
||||
|
||||
logToRepl(sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) {
|
||||
logToRepl(session: IDebugSession, sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) {
|
||||
|
||||
let source: IReplElementSource | undefined;
|
||||
if (frame) {
|
||||
source = {
|
||||
column: frame.column,
|
||||
lineNumber: frame.line,
|
||||
source: this.session.getSource({
|
||||
source: session.getSource({
|
||||
name: basenameOrAuthority(frame.uri),
|
||||
path: frame.uri.fsPath
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } f
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService';
|
||||
|
||||
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
|
||||
@@ -22,7 +23,7 @@ export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
|
||||
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
|
||||
// TODO@Isidor use debug IPC channel
|
||||
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
|
||||
return (this.windowsService as WindowsService).openExtensionDevelopmentHostWindow(args, env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,6 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
export class NodeDebugHelperService implements IDebugHelperService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
}
|
||||
|
||||
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
|
||||
|
||||
const client = new TelemetryClient(
|
||||
@@ -41,4 +37,4 @@ export class NodeDebugHelperService implements IDebugHelperService {
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IDebugHelperService, NodeDebugHelperService);
|
||||
registerSingleton(IDebugHelperService, NodeDebugHelperService);
|
||||
|
||||
@@ -12,11 +12,11 @@ import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IBreakpointUpdateData, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession {
|
||||
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService);
|
||||
function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession {
|
||||
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService);
|
||||
}
|
||||
|
||||
suite('Debug - Model', () => {
|
||||
@@ -110,6 +110,44 @@ suite('Debug - Model', () => {
|
||||
assert.equal(model.getFunctionBreakpoints().length, 0);
|
||||
});
|
||||
|
||||
test('breakpoints multiple sessions', () => {
|
||||
const modelUri = uri.file('/myfolder/myfile.js');
|
||||
const breakpoints = model.addBreakpoints(modelUri, [{ lineNumber: 5, enabled: true, condition: 'x > 5' }, { lineNumber: 10, enabled: false }]);
|
||||
const session = createMockSession(model);
|
||||
const data = new Map<string, DebugProtocol.Breakpoint>();
|
||||
|
||||
assert.equal(breakpoints[0].lineNumber, 5);
|
||||
assert.equal(breakpoints[1].lineNumber, 10);
|
||||
|
||||
data.set(breakpoints[0].getId(), { verified: false, line: 10 });
|
||||
data.set(breakpoints[1].getId(), { verified: true, line: 50 });
|
||||
model.setBreakpointSessionData(session.getId(), {}, data);
|
||||
assert.equal(breakpoints[0].lineNumber, 5);
|
||||
assert.equal(breakpoints[1].lineNumber, 50);
|
||||
|
||||
const session2 = createMockSession(model);
|
||||
const data2 = new Map<string, DebugProtocol.Breakpoint>();
|
||||
data2.set(breakpoints[0].getId(), { verified: true, line: 100 });
|
||||
data2.set(breakpoints[1].getId(), { verified: true, line: 500 });
|
||||
model.setBreakpointSessionData(session2.getId(), {}, data2);
|
||||
|
||||
// Breakpoint is verified only once, show that line
|
||||
assert.equal(breakpoints[0].lineNumber, 100);
|
||||
// Breakpoint is verified two times, show the original line
|
||||
assert.equal(breakpoints[1].lineNumber, 10);
|
||||
|
||||
model.setBreakpointSessionData(session.getId(), {}, undefined);
|
||||
// No more double session verification
|
||||
assert.equal(breakpoints[0].lineNumber, 100);
|
||||
assert.equal(breakpoints[1].lineNumber, 500);
|
||||
|
||||
assert.equal(breakpoints[0].supported, false);
|
||||
const data3 = new Map<string, DebugProtocol.Breakpoint>();
|
||||
data3.set(breakpoints[0].getId(), { verified: true, line: 500 });
|
||||
model.setBreakpointSessionData(session2.getId(), { supportsConditionalBreakpoints: true }, data2);
|
||||
assert.equal(breakpoints[0].supported, true);
|
||||
});
|
||||
|
||||
// Threads
|
||||
|
||||
test('threads simple', () => {
|
||||
@@ -341,10 +379,10 @@ suite('Debug - Model', () => {
|
||||
session['raw'] = <any>rawSession;
|
||||
const thread = new Thread(session, 'mockthread', 1);
|
||||
const stackFrame = new StackFrame(thread, 1, <any>undefined, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1);
|
||||
const replModel = new ReplModel(session);
|
||||
replModel.addReplExpression(stackFrame, 'myVariable').then();
|
||||
replModel.addReplExpression(stackFrame, 'myVariable').then();
|
||||
replModel.addReplExpression(stackFrame, 'myVariable').then();
|
||||
const replModel = new ReplModel();
|
||||
replModel.addReplExpression(session, stackFrame, 'myVariable').then();
|
||||
replModel.addReplExpression(session, stackFrame, 'myVariable').then();
|
||||
replModel.addReplExpression(session, stackFrame, 'myVariable').then();
|
||||
|
||||
assert.equal(replModel.getReplElements().length, 3);
|
||||
replModel.getReplElements().forEach(re => {
|
||||
@@ -405,13 +443,13 @@ suite('Debug - Model', () => {
|
||||
model.addSession(session);
|
||||
const secondSession = createMockSession(model, 'mockSession2');
|
||||
model.addSession(secondSession);
|
||||
const firstChild = createMockSession(model, 'firstChild', session);
|
||||
const firstChild = createMockSession(model, 'firstChild', { parentSession: session });
|
||||
model.addSession(firstChild);
|
||||
const secondChild = createMockSession(model, 'secondChild', session);
|
||||
const secondChild = createMockSession(model, 'secondChild', { parentSession: session });
|
||||
model.addSession(secondChild);
|
||||
const thirdSession = createMockSession(model, 'mockSession3');
|
||||
model.addSession(thirdSession);
|
||||
const anotherChild = createMockSession(model, 'secondChild', secondSession);
|
||||
const anotherChild = createMockSession(model, 'secondChild', { parentSession: secondSession });
|
||||
model.addSession(anotherChild);
|
||||
|
||||
const sessions = model.getSessions();
|
||||
@@ -426,8 +464,7 @@ suite('Debug - Model', () => {
|
||||
// Repl output
|
||||
|
||||
test('repl output', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService);
|
||||
const repl = new ReplModel(session);
|
||||
const repl = new ReplModel();
|
||||
repl.appendToRepl('first line\n', severity.Error);
|
||||
repl.appendToRepl('second line ', severity.Error);
|
||||
repl.appendToRepl('third line ', severity.Error);
|
||||
@@ -466,4 +503,41 @@ suite('Debug - Model', () => {
|
||||
assert.equal(elements[1], '23\n45\n');
|
||||
assert.equal(elements[2], '6');
|
||||
});
|
||||
|
||||
test('repl merging', () => {
|
||||
// 'mergeWithParent' should be ignored when there is no parent.
|
||||
const parent = createMockSession(model, 'parent', { repl: 'mergeWithParent' });
|
||||
const child1 = createMockSession(model, 'child1', { parentSession: parent, repl: 'separate' });
|
||||
const child2 = createMockSession(model, 'child2', { parentSession: parent, repl: 'mergeWithParent' });
|
||||
const grandChild = createMockSession(model, 'grandChild', { parentSession: child2, repl: 'mergeWithParent' });
|
||||
const child3 = createMockSession(model, 'child3', { parentSession: parent });
|
||||
|
||||
parent.appendToRepl('1\n', severity.Info);
|
||||
assert.equal(parent.getReplElements().length, 1);
|
||||
assert.equal(child1.getReplElements().length, 0);
|
||||
assert.equal(child2.getReplElements().length, 1);
|
||||
assert.equal(grandChild.getReplElements().length, 1);
|
||||
assert.equal(child3.getReplElements().length, 0);
|
||||
|
||||
grandChild.appendToRepl('1\n', severity.Info);
|
||||
assert.equal(parent.getReplElements().length, 2);
|
||||
assert.equal(child1.getReplElements().length, 0);
|
||||
assert.equal(child2.getReplElements().length, 2);
|
||||
assert.equal(grandChild.getReplElements().length, 2);
|
||||
assert.equal(child3.getReplElements().length, 0);
|
||||
|
||||
child3.appendToRepl('1\n', severity.Info);
|
||||
assert.equal(parent.getReplElements().length, 2);
|
||||
assert.equal(child1.getReplElements().length, 0);
|
||||
assert.equal(child2.getReplElements().length, 2);
|
||||
assert.equal(grandChild.getReplElements().length, 2);
|
||||
assert.equal(child3.getReplElements().length, 1);
|
||||
|
||||
child1.appendToRepl('1\n', severity.Info);
|
||||
assert.equal(parent.getReplElements().length, 2);
|
||||
assert.equal(child1.getReplElements().length, 1);
|
||||
assert.equal(child2.getReplElements().length, 2);
|
||||
assert.equal(grandChild.getReplElements().length, 2);
|
||||
assert.equal(child3.getReplElements().length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { URI as uri } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource, IDataBreakpoint, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { CompletionItem } from 'vs/editor/common/modes';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -102,7 +102,7 @@ export class MockDebugService implements IDebugService {
|
||||
|
||||
public removeWatchExpressions(id?: string): void { }
|
||||
|
||||
public startDebugging(launch: ILaunch, configOrName?: IConfig | string, noDebug?: boolean): Promise<boolean> {
|
||||
public startDebugging(launch: ILaunch, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
@@ -159,6 +159,10 @@ export class MockSession implements IDebugSession {
|
||||
return [];
|
||||
}
|
||||
|
||||
hasSeparateRepl(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
removeReplExpressions(): void { }
|
||||
get onDidChangeReplElements(): Event<void> {
|
||||
throw new Error('not implemented');
|
||||
|
||||