Merge from vscode 817eb6b0c720a4ecbc13c020afbbebfed667aa09 (#7356)

This commit is contained in:
Anthony Dresser
2019-09-24 21:36:17 -07:00
committed by GitHub
parent a29ae4d3b9
commit 6a6048d40f
541 changed files with 7045 additions and 7287 deletions

View File

@@ -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;
}
}

View File

@@ -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)
});
}));
}

View File

@@ -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')));

View File

@@ -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));
}

View File

@@ -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,

View File

@@ -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')));
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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>();

View File

@@ -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 {

View File

@@ -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");
}

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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)
});
}
}

View File

@@ -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)
});
}
}

View File

@@ -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.

View File

@@ -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()) {

View File

@@ -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: [] },

View File

@@ -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 } {

View File

@@ -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 {

View File

@@ -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
})

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
});
});

View File

@@ -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');