Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f (#7282)

* Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f

* fix various icon issues

* fix preview features
This commit is contained in:
Anthony Dresser
2019-09-19 21:50:52 -07:00
committed by GitHub
parent 9d3d64eef3
commit db498db0a8
459 changed files with 10195 additions and 7528 deletions

View File

@@ -0,0 +1,567 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
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 severity from 'vs/base/common/severity';
import { IAction, Action } from 'vs/base/common/actions';
import { Range } from 'vs/editor/common/core/range';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView';
import { generateUuid } from 'vs/base/common/uuid';
import { memoize } from 'vs/base/common/decorators';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { distinct } from 'vs/base/common/arrays';
import { RunOnceScheduler } from 'vs/base/common/async';
const $ = dom.$;
interface IBreakpointDecoration {
decorationId: string;
breakpoint: IBreakpoint;
range: Range;
inlineWidget?: InlineBreakpointWidget;
}
const breakpointHelperDecoration: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-hint',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
};
function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray<IBreakpoint>, debugService: IDebugService): { range: Range; options: IModelDecorationOptions; }[] {
const result: { range: Range; options: IModelDecorationOptions; }[] = [];
breakpoints.forEach((breakpoint) => {
if (breakpoint.lineNumber <= model.getLineCount()) {
const column = model.getLineFirstNonWhitespaceColumn(breakpoint.lineNumber);
const range = model.validateRange(
breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1)
: new Range(breakpoint.lineNumber, column, breakpoint.lineNumber, column + 1) // Decoration has to have a width #20688
);
result.push({
options: getBreakpointDecorationOptions(model, breakpoint, debugService),
range
});
}
});
return result;
}
function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService): IModelDecorationOptions {
const { className, message } = getBreakpointMessageAndClassName(debugService, breakpoint);
let glyphMarginHoverMessage: MarkdownString | undefined;
if (message) {
if (breakpoint.condition || breakpoint.hitCondition) {
const modeId = model.getLanguageIdentifier().language;
glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, message);
} else {
glyphMarginHoverMessage = new MarkdownString().appendText(message);
}
}
return {
glyphMarginClassName: className,
glyphMarginHoverMessage,
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined
};
}
async function createCandidateDecorations(model: ITextModel, breakpointDecorations: IBreakpointDecoration[], debugService: IDebugService): Promise<{ range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[]> {
const lineNumbers = distinct(breakpointDecorations.map(bpd => bpd.range.startLineNumber));
const result: { range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[] = [];
const session = debugService.getViewModel().focusedSession;
if (session && session.capabilities.supportsBreakpointLocationsRequest) {
await Promise.all(lineNumbers.map(async lineNumber => {
const positions = await session.breakpointsLocations(model.uri, lineNumber);
if (positions.length > 1) {
// Do not render candidates if there is only one, since it is already covered by the line breakpoint
positions.forEach(p => {
const range = new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1);
const breakpointAtPosition = breakpointDecorations.filter(bpd => bpd.range.equalsRange(range)).pop();
if (breakpointAtPosition && breakpointAtPosition.inlineWidget) {
// Space already occupied, do not render candidate.
return;
}
result.push({
range,
options: {
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
beforeContentClassName: `debug-breakpoint-placeholder`
},
breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined
});
});
}
}));
}
return result;
}
class BreakpointEditorContribution implements IBreakpointEditorContribution {
private breakpointHintDecoration: string[] = [];
private breakpointWidget: BreakpointWidget | undefined;
private breakpointWidgetVisible: IContextKey<boolean>;
private toDispose: IDisposable[] = [];
private ignoreDecorationsChangedEvent = false;
private ignoreBreakpointsChangeEvent = false;
private breakpointDecorations: IBreakpointDecoration[] = [];
private candidateDecorations: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = [];
private setDecorationsScheduler: RunOnceScheduler;
constructor(
private readonly editor: ICodeEditor,
@IDebugService private readonly debugService: IDebugService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService contextKeyService: IContextKeyService,
@IDialogService private readonly dialogService: IDialogService,
) {
this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService);
this.registerListeners();
this.setDecorationsScheduler = new RunOnceScheduler(() => this.setDecorations(), 30);
}
getId(): string {
return BREAKPOINT_EDITOR_CONTRIBUTION_ID;
}
private registerListeners(): void {
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
const data = e.target.detail as IMarginData;
const model = this.editor.getModel();
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
return;
}
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(model);
const lineNumber = e.target.position.lineNumber;
const uri = model.uri;
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
if (!canSetBreakpoints) {
return;
}
const anchor = { x: e.event.posx, y: e.event.posy };
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
});
} else {
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
if (breakpoints.length) {
// Show the dialog if there is a potential condition to be accidently lost.
// Do not show dialog on linux due to electron issue freezing the mouse #50026
if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition)) {
const logPoint = breakpoints.every(bp => !!bp.logMessage);
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
const disable = breakpoints.some(bp => bp.enabled);
const enabling = nls.localize('breakpointHasConditionDisabled',
"This {0} has a {1} that will get lost on remove. Consider enabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
const disabling = nls.localize('breakpointHasConditionEnabled',
"This {0} has a {1} that will get lost on remove. Consider disabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [
nls.localize('removeLogPoint', "Remove {0}", breakpointType),
nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType),
nls.localize('cancel', "Cancel")
], { cancelId: 2 });
if (choice === 0) {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
if (choice === 1) {
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
}
} else {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
} else if (canSetBreakpoints) {
this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorGutter`);
}
}
}));
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
let showBreakpointHintAtLineNumber = -1;
const model = this.editor.getModel();
if (model && e.target.position && e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
const data = e.target.detail as IMarginData;
if (!data.isAfterLines) {
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
}
}
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
}));
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
this.ensureBreakpointHintDecoration(-1);
}));
this.toDispose.push(this.editor.onDidChangeModel(async () => {
this.closeBreakpointWidget();
await this.setDecorations();
}));
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => {
if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) {
this.setDecorationsScheduler.schedule();
}
}));
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged()));
}
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");
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService));
actions.push(new Action(
'workbench.debug.action.editBreakpointAction',
nls.localize('editBreakpoint', "Edit {0}...", breakpointType),
undefined,
true,
() => Promise.resolve(this.showBreakpointWidget(breakpoints[0].lineNumber, breakpoints[0].column))
));
actions.push(new Action(
`workbench.debug.viewlet.action.toggleBreakpoint`,
breakpoints[0].enabled ? nls.localize('disableBreakpoint', "Disable {0}", breakpointType) : nls.localize('enableBreakpoint', "Enable {0}", breakpointType),
undefined,
true,
() => this.debugService.enableOrDisableBreakpoints(!breakpoints[0].enabled, breakpoints[0])
));
} else if (breakpoints.length > 1) {
const sorted = breakpoints.slice().sort((first, second) => (first.column && second.column) ? first.column - second.column : 1);
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
'removeInlineBreakpoint',
bp.column ? nls.localize('removeInlineBreakpointOnColumn', "Remove Inline Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
undefined,
true,
() => this.debugService.removeBreakpoints(bp.getId())
))));
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
new Action('editBreakpoint',
bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
undefined,
true,
() => Promise.resolve(this.showBreakpointWidget(bp.lineNumber, bp.column))
)
)));
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
bp.enabled ? (bp.column ? nls.localize('disableInlineColumnBreakpoint', "Disable Inline Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
: (bp.column ? nls.localize('enableBreakpoints', "Enable Inline Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
undefined,
true,
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
))));
} else {
actions.push(new Action(
'addBreakpoint',
nls.localize('addBreakpoint', "Add Breakpoint"),
undefined,
true,
() => this.debugService.addBreakpoints(uri, [{ lineNumber, column }], `debugEditorContextMenu`)
));
actions.push(new Action(
'addConditionalBreakpoint',
nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."),
undefined,
true,
() => Promise.resolve(this.showBreakpointWidget(lineNumber, column))
));
actions.push(new Action(
'addLogPoint',
nls.localize('addLogPoint', "Add Logpoint..."),
undefined,
true,
() => Promise.resolve(this.showBreakpointWidget(lineNumber, column, BreakpointWidgetContext.LOG_MESSAGE))
));
}
return actions;
}
private marginFreeFromNonDebugDecorations(line: number): boolean {
const decorations = this.editor.getLineDecorations(line);
if (decorations) {
for (const { options } of decorations) {
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
return false;
}
}
}
return true;
}
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
const newDecoration: IModelDeltaDecoration[] = [];
if (showBreakpointHintAtLineNumber !== -1) {
newDecoration.push({
options: breakpointHelperDecoration,
range: {
startLineNumber: showBreakpointHintAtLineNumber,
startColumn: 1,
endLineNumber: showBreakpointHintAtLineNumber,
endColumn: 1
}
});
}
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
}
private async setDecorations(): Promise<void> {
if (!this.editor.hasModel()) {
return;
}
const activeCodeEditor = this.editor;
const model = activeCodeEditor.getModel();
const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri });
const desiredBreakpointDecorations = createBreakpointDecorations(model, breakpoints, this.debugService);
try {
this.ignoreDecorationsChangedEvent = true;
// Set breakpoint decorations
const decorationIds = activeCodeEditor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredBreakpointDecorations);
this.breakpointDecorations.forEach(bpd => {
if (bpd.inlineWidget) {
bpd.inlineWidget.dispose();
}
});
this.breakpointDecorations = decorationIds.map((decorationId, index) => {
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));
}
return {
decorationId,
breakpoint,
range: desiredBreakpointDecorations[index].range,
inlineWidget
};
});
} finally {
this.ignoreDecorationsChangedEvent = false;
}
// Set breakpoint candidate decorations
const desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), this.breakpointDecorations, this.debugService);
const candidateDecorationIds = this.editor.deltaDecorations(this.candidateDecorations.map(c => c.decorationId), desiredCandidateDecorations);
this.candidateDecorations.forEach(candidate => {
candidate.inlineWidget.dispose();
});
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));
return {
decorationId,
inlineWidget
};
});
}
private async onModelDecorationsChanged(): Promise<void> {
if (this.breakpointDecorations.length === 0 || this.ignoreDecorationsChangedEvent || !this.editor.hasModel()) {
// I have no decorations
return;
}
let somethingChanged = false;
const model = this.editor.getModel();
this.breakpointDecorations.forEach(breakpointDecoration => {
if (somethingChanged) {
return;
}
const newBreakpointRange = model.getDecorationRange(breakpointDecoration.decorationId);
if (newBreakpointRange && (!breakpointDecoration.range.equalsRange(newBreakpointRange))) {
somethingChanged = true;
}
});
if (!somethingChanged) {
// nothing to do, my decorations did not change.
return;
}
const data = new Map<string, IBreakpointUpdateData>();
for (let i = 0, len = this.breakpointDecorations.length; i < len; i++) {
const breakpointDecoration = this.breakpointDecorations[i];
const decorationRange = model.getDecorationRange(breakpointDecoration.decorationId);
// check if the line got deleted.
if (decorationRange) {
// since we know it is collapsed, it cannot grow to multiple lines
if (breakpointDecoration.breakpoint) {
data.set(breakpointDecoration.breakpoint.getId(), {
lineNumber: decorationRange.startLineNumber,
column: breakpointDecoration.breakpoint.column ? decorationRange.startColumn : undefined,
});
}
}
}
try {
this.ignoreBreakpointsChangeEvent = true;
await this.debugService.updateBreakpoints(model.uri, data, true);
} finally {
this.ignoreBreakpointsChangeEvent = false;
}
}
// breakpoint widget
showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
}
this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, column, context);
this.breakpointWidget.show({ lineNumber, column: 1 });
this.breakpointWidgetVisible.set(true);
}
closeBreakpointWidget(): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
this.breakpointWidget = undefined;
this.breakpointWidgetVisible.reset();
this.editor.focus();
}
}
dispose(): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
}
this.editor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), []);
dispose(this.toDispose);
}
}
class InlineBreakpointWidget implements IContentWidget, IDisposable {
// editor.IContentWidget.allowEditorOverflow
allowEditorOverflow = false;
suppressMouseDown = true;
private domNode!: HTMLElement;
private range: Range | null;
private toDispose: IDisposable[] = [];
constructor(
private readonly editor: IActiveCodeEditor,
private readonly decorationId: string,
cssClass: string | null | undefined,
private readonly breakpoint: IBreakpoint | undefined,
private readonly debugService: IDebugService,
private readonly contextMenuService: IContextMenuService,
private readonly getContextMenuActions: () => ReadonlyArray<IAction | ContextSubMenu>
) {
this.range = this.editor.getModel().getDecorationRange(decorationId);
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => {
const model = this.editor.getModel();
const range = model.getDecorationRange(this.decorationId);
if (this.range && !this.range.equalsRange(range)) {
this.range = range;
this.editor.layoutContentWidget(this);
}
}));
this.create(cssClass);
this.editor.addContentWidget(this);
this.editor.layoutContentWidget(this);
}
private create(cssClass: string | null | undefined): void {
this.domNode = $('.inline-breakpoint-widget');
if (cssClass) {
this.domNode.classList.add(cssClass);
}
this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CLICK, async e => {
if (this.breakpoint) {
await this.debugService.removeBreakpoints(this.breakpoint.getId());
} else {
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 => {
const event = new StandardMouseEvent(e);
const anchor = { x: event.posx, y: event.posy };
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.getContextMenuActions(),
getActionsContext: () => this.breakpoint
});
}));
}
@memoize
getId(): string {
return generateUuid();
}
getDomNode(): HTMLElement {
return this.domNode;
}
getPosition(): IContentWidgetPosition | null {
if (!this.range) {
return null;
}
// Workaround: since the content widget can not be placed before the first column we need to force the left position
dom.toggleClass(this.domNode, 'line-start', this.range.startColumn === 1);
return {
position: { lineNumber: this.range.startLineNumber, column: this.range.startColumn - 1 },
preference: [ContentWidgetPositionPreference.EXACT]
};
}
dispose(): void {
this.editor.removeContentWidget(this);
dispose(this.toDispose);
}
}
registerEditorContribution(BreakpointEditorContribution);

View File

@@ -13,7 +13,7 @@ import { Position, IPosition } from 'vs/editor/common/core/position';
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_IN_BREAKPOINT_WIDGET, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, CONTEXT_IN_BREAKPOINT_WIDGET, IBreakpointUpdateData, IBreakpointEditorContribution, BREAKPOINT_EDITOR_CONTRIBUTION_ID } from 'vs/workbench/contrib/debug/common/debug';
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -37,7 +37,7 @@ import { IRange, Range } from 'vs/editor/common/core/range';
import { onUnexpectedError } from 'vs/base/common/errors';
const $ = dom.$;
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakpointWidgetService');
export interface IPrivateBreakpointWidgetService {
_serviceBrand: undefined;
close(success: boolean): void;
@@ -55,7 +55,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
private logMessageInput = '';
private breakpoint: IBreakpoint | undefined;
constructor(editor: ICodeEditor, private lineNumber: number, private context: Context,
constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, private context: Context,
@IContextViewService private readonly contextViewService: IContextViewService,
@IDebugService private readonly debugService: IDebugService,
@IThemeService private readonly themeService: IThemeService,
@@ -70,7 +70,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
const model = this.editor.getModel();
if (model) {
const uri = model.uri;
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, uri });
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, column: this.column, uri });
this.breakpoint = breakpoints.length ? breakpoints[0] : undefined;
}
@@ -130,12 +130,12 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
}
}
show(rangeOrPos: IRange | IPosition, heightInLines: number) {
show(rangeOrPos: IRange | IPosition): void {
const lineNum = this.input.getModel().getLineCount();
super.show(rangeOrPos, lineNum + 1);
}
fitHeightToContent() {
fitHeightToContent(): void {
const lineNum = this.input.getModel().getLineCount();
this._relayout(lineNum + 1);
}
@@ -293,6 +293,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
if (model) {
this.debugService.addBreakpoints(model.uri, [{
lineNumber: this.lineNumber,
column: this.column,
enabled: true,
condition,
hitCondition,
@@ -348,7 +349,7 @@ class CloseBreakpointWidgetCommand extends EditorCommand {
}
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
const debugContribution = editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID);
const debugContribution = editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID);
if (debugContribution) {
// if focus is in outer editor we need to use the debug contribution to close
return debugContribution.closeBreakpointWidget();

View File

@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import * as resources from 'vs/base/common/resources';
import * as dom from 'vs/base/browser/dom';
import { IAction, Action } from 'vs/base/common/actions';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, EDITOR_CONTRIBUTION_ID, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
import { AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction, RemoveBreakpointAction, EnableAllBreakpointsAction, DisableAllBreakpointsAction, ReapplyBreakpointsAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
@@ -167,7 +167,7 @@ export class BreakpointsView extends ViewletPanel {
if (editor) {
const codeEditor = editor.getControl();
if (isCodeEditor(codeEditor)) {
codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column);
codeEditor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column);
}
}
});
@@ -180,7 +180,7 @@ export class BreakpointsView extends ViewletPanel {
actions.push(new Separator());
}
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService));
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService));
if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) {
actions.push(new RemoveAllBreakpointsAction(RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL, this.debugService, this.keybindingService));

View File

@@ -24,7 +24,6 @@ import {
} from 'vs/workbench/contrib/debug/common/debug';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { DebugEditorModelManager } from 'vs/workbench/contrib/debug/browser/debugEditorModelManager';
import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
import * as service from 'vs/workbench/contrib/debug/browser/debugService';
@@ -49,6 +48,7 @@ import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView'
import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
import { DebugCallStackContribution } from 'vs/workbench/contrib/debug/browser/debugCallStackContribution';
class OpenDebugViewletAction extends ShowViewletAction {
public static readonly ID = VIEWLET_ID;
@@ -121,7 +121,7 @@ const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryEx
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugCallStackContribution, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Eventually);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually);

View File

@@ -181,12 +181,12 @@ export class SelectAndStartAction extends AbstractDebugAction {
}
}
export class RemoveBreakpointAction extends AbstractDebugAction {
export class RemoveBreakpointAction extends Action {
static readonly ID = 'workbench.debug.viewlet.action.removeBreakpoint';
static LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint");
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
super(id, label, 'debug-action remove', debugService, keybindingService);
constructor(id: string, label: string, @IDebugService private readonly debugService: IDebugService) {
super(id, label, 'debug-action remove');
}
public run(breakpoint: IBreakpoint): Promise<any> {

View File

@@ -0,0 +1,182 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Constants } from 'vs/editor/common/core/uint';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDebugService, State } from 'vs/workbench/contrib/debug/common/debug';
import { IModelService } from 'vs/editor/common/services/modelService';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
interface IDebugEditorModelData {
model: ITextModel;
currentStackDecorations: string[];
topStackFrameRange: Range | undefined;
}
const stickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
export class DebugCallStackContribution implements IWorkbenchContribution {
private modelDataMap = new Map<string, IDebugEditorModelData>();
private toDispose: IDisposable[] = [];
constructor(
@IModelService private readonly modelService: IModelService,
@IDebugService private readonly debugService: IDebugService,
) {
this.registerListeners();
}
private registerListeners(): void {
this.toDispose.push(this.modelService.onModelAdded(this.onModelAdded, this));
this.modelService.getModels().forEach(model => this.onModelAdded(model));
this.toDispose.push(this.modelService.onModelRemoved(this.onModelRemoved, this));
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame()));
this.toDispose.push(this.debugService.onDidChangeState(state => {
if (state === State.Inactive) {
this.modelDataMap.forEach(modelData => {
modelData.topStackFrameRange = undefined;
});
}
}));
}
private onModelAdded(model: ITextModel): void {
const modelUriStr = model.uri.toString();
const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUriStr));
this.modelDataMap.set(modelUriStr, {
model: model,
currentStackDecorations: currentStackDecorations,
topStackFrameRange: undefined
});
}
private onModelRemoved(model: ITextModel): void {
const modelUriStr = model.uri.toString();
const data = this.modelDataMap.get(modelUriStr);
if (data) {
this.modelDataMap.delete(modelUriStr);
}
}
private onFocusStackFrame(): void {
this.modelDataMap.forEach((modelData, uri) => {
modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri));
});
}
private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] {
const result: IModelDeltaDecoration[] = [];
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) {
return result;
}
// only show decorations for the currently focused thread.
const columnUntilEOLRange = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);
const range = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, stackFrame.range.startColumn + 1);
// compute how to decorate the editor. Different decorations are used if this is a top stack frame, focused stack frame,
// an exception or a stack frame that did not change the line number (we only decorate the columns, not the whole line).
const callStack = stackFrame.thread.getCallStack();
if (callStack && callStack.length && stackFrame === callStack[0]) {
result.push({
options: DebugCallStackContribution.TOP_STACK_FRAME_MARGIN,
range
});
result.push({
options: DebugCallStackContribution.TOP_STACK_FRAME_DECORATION,
range: columnUntilEOLRange
});
const modelData = this.modelDataMap.get(modelUriStr);
if (modelData) {
if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) {
result.push({
options: DebugCallStackContribution.TOP_STACK_FRAME_INLINE_DECORATION,
range: columnUntilEOLRange
});
}
modelData.topStackFrameRange = columnUntilEOLRange;
}
} else {
result.push({
options: DebugCallStackContribution.FOCUSED_STACK_FRAME_MARGIN,
range
});
result.push({
options: DebugCallStackContribution.FOCUSED_STACK_FRAME_DECORATION,
range: columnUntilEOLRange
});
}
return result;
}
// editor decorations
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
glyphMarginClassName: 'debug-top-stack-frame',
stickiness
};
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
glyphMarginClassName: 'debug-focused-stack-frame',
stickiness
};
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
isWholeLine: true,
inlineClassName: 'debug-remove-token-colors',
className: 'debug-top-stack-frame-line',
stickiness
};
private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = {
beforeContentClassName: 'debug-top-stack-frame-column'
};
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
isWholeLine: true,
inlineClassName: 'debug-remove-token-colors',
className: 'debug-focused-stack-frame-line',
stickiness
};
dispose(): void {
this.modelDataMap.forEach(modelData => {
modelData.model.deltaDecorations(modelData.currentStackDecorations, []);
});
this.toDispose = dispose(this.toDispose);
this.modelDataMap.clear();
}
}
registerThemingParticipant((theme, collector) => {
const topStackFrame = theme.getColor(topStackFrameColor);
if (topStackFrame) {
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
}
const focusedStackFrame = theme.getColor(focusedStackFrameColor);
if (focusedStackFrame) {
collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`);
}
});
const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));

View File

@@ -9,7 +9,7 @@ import { Range } from 'vs/editor/common/core/range';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ServicesAccessor, registerEditorAction, EditorAction, IActionOptions } from 'vs/editor/browser/editorExtensions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -75,7 +75,7 @@ class ConditionalBreakpointAction extends EditorAction {
const position = editor.getPosition();
if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, position.column);
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, undefined);
}
}
}
@@ -97,7 +97,7 @@ class LogPointAction extends EditorAction {
const position = editor.getPosition();
if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, position.column, BreakpointWidgetContext.LOG_MESSAGE);
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, BreakpointWidgetContext.LOG_MESSAGE);
}
}
}

View File

@@ -5,13 +5,9 @@
import * as nls from 'vs/nls';
import { RunOnceScheduler } from 'vs/base/common/async';
import * as lifecycle from 'vs/base/common/lifecycle';
import * as env from 'vs/base/common/platform';
import { URI as uri } from 'vs/base/common/uri';
import { visit } from 'vs/base/common/json';
import severity from 'vs/base/common/severity';
import { Constants } from 'vs/editor/common/core/uint';
import { IAction, Action } from 'vs/base/common/actions';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { StandardTokenType } from 'vs/editor/common/modes';
@@ -19,32 +15,25 @@ import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { Range } from 'vs/editor/common/core/range';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IDebugEditorContribution, IDebugService, State, IBreakpoint, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo, BreakpointWidgetContext } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugEditorContribution, IDebugService, State, EDITOR_CONTRIBUTION_ID, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo } from 'vs/workbench/contrib/debug/common/debug';
import { ExceptionWidget } from 'vs/workbench/contrib/debug/browser/exceptionWidget';
import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets';
import { Position } from 'vs/editor/common/core/position';
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
import { first } from 'vs/base/common/arrays';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { memoize } from 'vs/base/common/decorators';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { getHover } from 'vs/editor/contrib/hover/getHover';
import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
import { CancellationToken } from 'vs/base/common/cancellation';
import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget';
import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover';
import { ITextModel } from 'vs/editor/common/model';
import { getHover } from 'vs/editor/contrib/hover/getHover';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
const HOVER_DELAY = 300;
const LAUNCH_JSON_REGEX = /launch\.json$/;
@@ -53,17 +42,14 @@ const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We
const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added
const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped
export class DebugEditorContribution implements IDebugEditorContribution {
class DebugEditorContribution implements IDebugEditorContribution {
private toDispose: lifecycle.IDisposable[];
private toDispose: IDisposable[];
private hoverWidget: DebugHoverWidget;
private nonDebugHoverPosition: Position | undefined;
private hoverRange: Range | null = null;
private mouseDown = false;
private breakpointHintDecoration: string[];
private breakpointWidget: BreakpointWidget | undefined;
private breakpointWidgetVisible: IContextKey<boolean>;
private wordToLineNumbersMap: Map<string, Position[]> | undefined;
private exceptionWidget: ExceptionWidget | undefined;
@@ -73,182 +59,21 @@ export class DebugEditorContribution implements IDebugEditorContribution {
constructor(
private editor: ICodeEditor,
@IDebugService private readonly debugService: IDebugService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService contextKeyService: IContextKeyService,
@ICommandService private readonly commandService: ICommandService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IDialogService private readonly dialogService: IDialogService,
) {
this.breakpointHintDecoration = [];
this.hoverWidget = this.instantiationService.createInstance(DebugHoverWidget, this.editor);
this.toDispose = [];
this.registerListeners();
this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService);
this.updateConfigurationWidgetVisibility();
this.codeEditorService.registerDecorationType(INLINE_VALUE_DECORATION_KEY, {});
this.toggleExceptionWidget();
}
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: uri, lineNumber: 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");
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService));
actions.push(new Action(
'workbench.debug.action.editBreakpointAction',
nls.localize('editBreakpoint', "Edit {0}...", breakpointType),
undefined,
true,
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(breakpoints[0].lineNumber, breakpoints[0].column))
));
actions.push(new Action(
`workbench.debug.viewlet.action.toggleBreakpoint`,
breakpoints[0].enabled ? nls.localize('disableBreakpoint', "Disable {0}", breakpointType) : nls.localize('enableBreakpoint', "Enable {0}", breakpointType),
undefined,
true,
() => this.debugService.enableOrDisableBreakpoints(!breakpoints[0].enabled, breakpoints[0])
));
} else if (breakpoints.length > 1) {
const sorted = breakpoints.slice().sort((first, second) => (first.column && second.column) ? first.column - second.column : 1);
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
'removeInlineBreakpoint',
bp.column ? nls.localize('removeInlineBreakpointOnColumn', "Remove Inline Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
undefined,
true,
() => this.debugService.removeBreakpoints(bp.getId())
))));
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
new Action('editBreakpoint',
bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
undefined,
true,
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(bp.lineNumber, bp.column))
)
)));
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
bp.enabled ? (bp.column ? nls.localize('disableInlineColumnBreakpoint', "Disable Inline Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
: (bp.column ? nls.localize('enableBreakpoints', "Enable Inline Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
undefined,
true,
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
))));
} else {
actions.push(new Action(
'addBreakpoint',
nls.localize('addBreakpoint', "Add Breakpoint"),
undefined,
true,
() => this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorContextMenu`)
));
actions.push(new Action(
'addConditionalBreakpoint',
nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."),
undefined,
true,
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(lineNumber, undefined))
));
actions.push(new Action(
'addLogPoint',
nls.localize('addLogPoint', "Add Logpoint..."),
undefined,
true,
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(lineNumber, undefined, BreakpointWidgetContext.LOG_MESSAGE))
));
}
return actions;
}
private registerListeners(): void {
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
const data = e.target.detail as IMarginData;
const model = this.editor.getModel();
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
return;
}
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(model);
const lineNumber = e.target.position.lineNumber;
const uri = model.uri;
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
if (!canSetBreakpoints) {
return;
}
const anchor = { x: e.event.posx, y: e.event.posy };
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
});
} else {
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
if (breakpoints.length) {
// Show the dialog if there is a potential condition to be accidently lost.
// Do not show dialog on linux due to electron issue freezing the mouse #50026
if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition)) {
const logPoint = breakpoints.every(bp => !!bp.logMessage);
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
const disable = breakpoints.some(bp => bp.enabled);
const enabling = nls.localize('breakpointHasConditionDisabled',
"This {0} has a {1} that will get lost on remove. Consider enabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
const disabling = nls.localize('breakpointHasConditionEnabled',
"This {0} has a {1} that will get lost on remove. Consider disabling the {0} instead.",
breakpointType.toLowerCase(),
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
);
const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [
nls.localize('removeLogPoint', "Remove {0}", breakpointType),
nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType),
nls.localize('cancel', "Cancel")
], { cancelId: 2 });
if (choice === 0) {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
if (choice === 1) {
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
}
} else {
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
}
} else if (canSetBreakpoints) {
this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorGutter`);
}
}
}));
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
let showBreakpointHintAtLineNumber = -1;
const model = this.editor.getModel();
if (model && e.target.position && e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
const data = e.target.detail as IMarginData;
if (!data.isAfterLines) {
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
}
}
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
}));
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
this.ensureBreakpointHintDecoration(-1);
}));
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(e => this.onFocusStackFrame(e.stackFrame)));
// hover listeners & hover widget
@@ -279,7 +104,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
if (model) {
this._applyHoverConfiguration(model, stackFrame);
}
this.closeBreakpointWidget();
this.toggleExceptionWidget();
this.hideHoverWidget();
this.updateConfigurationWidgetVisibility();
@@ -317,11 +141,11 @@ export class DebugEditorContribution implements IDebugEditorContribution {
}
}
public getId(): string {
getId(): string {
return EDITOR_CONTRIBUTION_ID;
}
public showHover(range: Range, focus: boolean): Promise<void> {
showHover(range: Range, focus: boolean): Promise<void> {
const sf = this.debugService.getViewModel().focusedStackFrame;
const model = this.editor.getModel();
if (sf && model && sf.source.uri.toString() === model.uri.toString()) {
@@ -331,36 +155,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
return Promise.resolve();
}
private marginFreeFromNonDebugDecorations(line: number): boolean {
const decorations = this.editor.getLineDecorations(line);
if (decorations) {
for (const { options } of decorations) {
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
return false;
}
}
}
return true;
}
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
const newDecoration: IModelDeltaDecoration[] = [];
if (showBreakpointHintAtLineNumber !== -1) {
newDecoration.push({
options: DebugEditorContribution.BREAKPOINT_HELPER_DECORATION,
range: {
startLineNumber: showBreakpointHintAtLineNumber,
startColumn: 1,
endLineNumber: showBreakpointHintAtLineNumber,
endColumn: 1
}
});
}
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
}
private onFocusStackFrame(sf: IStackFrame | undefined): void {
const model = this.editor.getModel();
if (model) {
@@ -464,29 +258,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
this.hideHoverWidget();
}
}
// end hover business
// breakpoint widget
public showBreakpointWidget(lineNumber: number, column: number, context?: BreakpointWidgetContext): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
}
this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, context);
this.breakpointWidget.show({ lineNumber, column: 1 }, 2);
this.breakpointWidgetVisible.set(true);
}
public closeBreakpointWidget(): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
this.breakpointWidget = undefined;
this.breakpointWidgetVisible.reset();
this.editor.focus();
}
}
// exception widget
private toggleExceptionWidget(): void {
// Toggles exception widget based on the state of the current editor model and debug stack frame
@@ -547,7 +320,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
}
}
public addLaunchConfiguration(): Promise<any> {
addLaunchConfiguration(): Promise<any> {
/* __GDPR__
"debug/addLaunchConfiguration" : {}
*/
@@ -594,11 +367,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
return insertLine(configurationsArrayPosition).then(() => this.commandService.executeCommand('editor.action.triggerSuggest'));
}
private static BREAKPOINT_HELPER_DECORATION: IModelDecorationOptions = {
glyphMarginClassName: 'debug-breakpoint-hint',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
};
// Inline Decorations
@memoize
@@ -768,17 +536,14 @@ export class DebugEditorContribution implements IDebugEditorContribution {
return this.wordToLineNumbersMap;
}
public dispose(): void {
if (this.breakpointWidget) {
this.breakpointWidget.dispose();
}
dispose(): void {
if (this.hoverWidget) {
this.hoverWidget.dispose();
}
if (this.configurationWidget) {
this.configurationWidget.dispose();
}
this.toDispose = lifecycle.dispose(this.toDispose);
this.toDispose = dispose(this.toDispose);
}
}

View File

@@ -1,334 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as lifecycle from 'vs/base/common/lifecycle';
import { Constants } from 'vs/editor/common/core/uint';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDebugService, IBreakpoint, State, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
import { IModelService } from 'vs/editor/common/services/modelService';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { onUnexpectedError } from 'vs/base/common/errors';
interface IBreakpointDecoration {
decorationId: string;
modelId: string;
range: Range;
}
interface IDebugEditorModelData {
model: ITextModel;
toDispose: lifecycle.IDisposable[];
breakpointDecorations: IBreakpointDecoration[];
currentStackDecorations: string[];
topStackFrameRange: Range | undefined;
}
export class DebugEditorModelManager implements IWorkbenchContribution {
static readonly ID = 'breakpointManager';
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
private modelDataMap: Map<string, IDebugEditorModelData>;
private toDispose: lifecycle.IDisposable[];
private ignoreDecorationsChangedEvent = false;
constructor(
@IModelService private readonly modelService: IModelService,
@IDebugService private readonly debugService: IDebugService,
) {
this.modelDataMap = new Map<string, IDebugEditorModelData>();
this.toDispose = [];
this.registerListeners();
}
public dispose(): void {
this.modelDataMap.forEach(modelData => {
lifecycle.dispose(modelData.toDispose);
modelData.model.deltaDecorations(modelData.breakpointDecorations.map(bpd => bpd.decorationId), []);
modelData.model.deltaDecorations(modelData.currentStackDecorations, []);
});
this.toDispose = lifecycle.dispose(this.toDispose);
this.modelDataMap.clear();
}
private registerListeners(): void {
this.toDispose.push(this.modelService.onModelAdded(this.onModelAdded, this));
this.modelService.getModels().forEach(model => this.onModelAdded(model));
this.toDispose.push(this.modelService.onModelRemoved(this.onModelRemoved, this));
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame()));
this.toDispose.push(this.debugService.onDidChangeState(state => {
if (state === State.Inactive) {
this.modelDataMap.forEach(modelData => {
modelData.topStackFrameRange = undefined;
});
}
}));
}
private onModelAdded(model: ITextModel): void {
const modelUriStr = model.uri.toString();
const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri });
const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUriStr));
const desiredDecorations = this.createBreakpointDecorations(model, breakpoints);
const breakpointDecorationIds = model.deltaDecorations([], desiredDecorations);
const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUriStr))];
this.modelDataMap.set(modelUriStr, {
model: model,
toDispose: toDispose,
breakpointDecorations: breakpointDecorationIds.map((decorationId, index) => ({ decorationId, modelId: breakpoints[index].getId(), range: desiredDecorations[index].range })),
currentStackDecorations: currentStackDecorations,
topStackFrameRange: undefined
});
}
private onModelRemoved(model: ITextModel): void {
const modelUriStr = model.uri.toString();
const data = this.modelDataMap.get(modelUriStr);
if (data) {
lifecycle.dispose(data.toDispose);
this.modelDataMap.delete(modelUriStr);
}
}
// call stack management. Represent data coming from the debug service.
private onFocusStackFrame(): void {
this.modelDataMap.forEach((modelData, uri) => {
modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri));
});
}
private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] {
const result: IModelDeltaDecoration[] = [];
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) {
return result;
}
// only show decorations for the currently focused thread.
const columnUntilEOLRange = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);
const range = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, stackFrame.range.startColumn + 1);
// compute how to decorate the editor. Different decorations are used if this is a top stack frame, focused stack frame,
// an exception or a stack frame that did not change the line number (we only decorate the columns, not the whole line).
const callStack = stackFrame.thread.getCallStack();
if (callStack && callStack.length && stackFrame === callStack[0]) {
result.push({
options: DebugEditorModelManager.TOP_STACK_FRAME_MARGIN,
range
});
result.push({
options: DebugEditorModelManager.TOP_STACK_FRAME_DECORATION,
range: columnUntilEOLRange
});
const modelData = this.modelDataMap.get(modelUriStr);
if (modelData) {
if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) {
result.push({
options: DebugEditorModelManager.TOP_STACK_FRAME_INLINE_DECORATION,
range: columnUntilEOLRange
});
}
modelData.topStackFrameRange = columnUntilEOLRange;
}
} else {
result.push({
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_MARGIN,
range
});
result.push({
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_DECORATION,
range: columnUntilEOLRange
});
}
return result;
}
// breakpoints management. Represent data coming from the debug service and also send data back.
private onModelDecorationsChanged(modelUrlStr: string): void {
const modelData = this.modelDataMap.get(modelUrlStr);
if (!modelData || modelData.breakpointDecorations.length === 0 || this.ignoreDecorationsChangedEvent) {
// I have no decorations
return;
}
let somethingChanged = false;
modelData.breakpointDecorations.forEach(breakpointDecoration => {
if (somethingChanged) {
return;
}
const newBreakpointRange = modelData.model.getDecorationRange(breakpointDecoration.decorationId);
if (newBreakpointRange && (!breakpointDecoration.range.equalsRange(newBreakpointRange))) {
somethingChanged = true;
}
});
if (!somethingChanged) {
// nothing to do, my decorations did not change.
return;
}
const data = new Map<string, IBreakpointUpdateData>();
const breakpoints = this.debugService.getModel().getBreakpoints();
const modelUri = modelData.model.uri;
for (let i = 0, len = modelData.breakpointDecorations.length; i < len; i++) {
const breakpointDecoration = modelData.breakpointDecorations[i];
const decorationRange = modelData.model.getDecorationRange(breakpointDecoration.decorationId);
// check if the line got deleted.
if (decorationRange) {
const breakpoint = breakpoints.filter(bp => bp.getId() === breakpointDecoration.modelId).pop();
// since we know it is collapsed, it cannot grow to multiple lines
if (breakpoint) {
data.set(breakpoint.getId(), {
lineNumber: decorationRange.startLineNumber,
column: breakpoint.column ? decorationRange.startColumn : undefined,
});
}
}
}
this.debugService.updateBreakpoints(modelUri, data, true).then(undefined, onUnexpectedError);
}
private onBreakpointsChange(): void {
const breakpointsMap = new Map<string, IBreakpoint[]>();
this.debugService.getModel().getBreakpoints().forEach(bp => {
const uriStr = bp.uri.toString();
const breakpoints = breakpointsMap.get(uriStr);
if (breakpoints) {
breakpoints.push(bp);
} else {
breakpointsMap.set(uriStr, [bp]);
}
});
breakpointsMap.forEach((bps, uri) => {
const data = this.modelDataMap.get(uri);
if (data) {
this.updateBreakpoints(data, breakpointsMap.get(uri)!);
}
});
this.modelDataMap.forEach((modelData, uri) => {
if (!breakpointsMap.has(uri)) {
this.updateBreakpoints(modelData, []);
}
});
}
private updateBreakpoints(modelData: IDebugEditorModelData, newBreakpoints: IBreakpoint[]): void {
const desiredDecorations = this.createBreakpointDecorations(modelData.model, newBreakpoints);
try {
this.ignoreDecorationsChangedEvent = true;
const breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorations.map(bpd => bpd.decorationId), desiredDecorations);
modelData.breakpointDecorations = breakpointDecorationIds.map((decorationId, index) => ({
decorationId,
modelId: newBreakpoints[index].getId(),
range: desiredDecorations[index].range
}));
} finally {
this.ignoreDecorationsChangedEvent = false;
}
}
private createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray<IBreakpoint>): { range: Range; options: IModelDecorationOptions; }[] {
const result: { range: Range; options: IModelDecorationOptions; }[] = [];
breakpoints.forEach((breakpoint) => {
if (breakpoint.lineNumber <= model.getLineCount()) {
const column = model.getLineFirstNonWhitespaceColumn(breakpoint.lineNumber);
const range = model.validateRange(
breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1)
: new Range(breakpoint.lineNumber, column, breakpoint.lineNumber, column + 1) // Decoration has to have a width #20688
);
result.push({
options: this.getBreakpointDecorationOptions(breakpoint),
range
});
}
});
return result;
}
private getBreakpointDecorationOptions(breakpoint: IBreakpoint): IModelDecorationOptions {
const { className, message } = getBreakpointMessageAndClassName(this.debugService, breakpoint);
let glyphMarginHoverMessage: MarkdownString | undefined;
if (message) {
if (breakpoint.condition || breakpoint.hitCondition) {
const modelData = this.modelDataMap.get(breakpoint.uri.toString());
const modeId = modelData ? modelData.model.getLanguageIdentifier().language : '';
glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, message);
} else {
glyphMarginHoverMessage = new MarkdownString().appendText(message);
}
}
return {
glyphMarginClassName: className,
glyphMarginHoverMessage,
stickiness: DebugEditorModelManager.STICKINESS,
beforeContentClassName: breakpoint.column ? `debug-breakpoint-column ${className}-column` : undefined
};
}
// editor decorations
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
glyphMarginClassName: 'debug-top-stack-frame',
stickiness: DebugEditorModelManager.STICKINESS
};
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
glyphMarginClassName: 'debug-focused-stack-frame',
stickiness: DebugEditorModelManager.STICKINESS
};
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
isWholeLine: true,
inlineClassName: 'debug-remove-token-colors',
className: 'debug-top-stack-frame-line',
stickiness: DebugEditorModelManager.STICKINESS
};
private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = {
beforeContentClassName: 'debug-top-stack-frame-column'
};
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
isWholeLine: true,
inlineClassName: 'debug-remove-token-colors',
className: 'debug-focused-stack-frame-line',
stickiness: DebugEditorModelManager.STICKINESS
};
}
registerThemingParticipant((theme, collector) => {
const topStackFrame = theme.getColor(topStackFrameColor);
if (topStackFrame) {
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
}
const focusedStackFrame = theme.getColor(focusedStackFrameColor);
if (focusedStackFrame) {
collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`);
}
});
const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));

View File

@@ -10,19 +10,20 @@ import * as platform from 'vs/base/common/platform';
import severity from 'vs/base/common/severity';
import { Event, Emitter } from 'vs/base/common/event';
import { CompletionItem, completionKindFromString } from 'vs/editor/common/modes';
import { Position } from 'vs/editor/common/core/position';
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 { 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';
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { generateUuid } from 'vs/base/common/uuid';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { Range } from 'vs/editor/common/core/range';
@@ -34,6 +35,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { distinct } from 'vs/base/common/arrays';
export class DebugSession implements IDebugSession {
@@ -73,7 +75,7 @@ export class DebugSession implements IDebugSession {
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@INotificationService private readonly notificationService: INotificationService,
@IProductService private readonly productService: IProductService,
@IWindowsService private readonly windowsService: IWindowsService,
@IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService,
@IOpenerService private readonly openerService: IOpenerService
) {
this.id = generateUuid();
@@ -185,7 +187,7 @@ export class DebugSession implements IDebugSession {
return dbgr.createDebugAdapter(this).then(debugAdapter => {
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService, this.openerService);
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService);
return this.raw.start().then(() => {
@@ -284,15 +286,7 @@ export class DebugSession implements IDebugSession {
return Promise.resolve(undefined);
}
const source = this.getSourceForUri(modelUri);
let rawSource: DebugProtocol.Source;
if (source) {
rawSource = source.raw;
} else {
const data = Source.getEncodedDebugData(modelUri);
rawSource = { name: data.name, path: data.path, sourceReference: data.sourceReference };
}
const rawSource = this.getRawSource(modelUri);
if (breakpointsToSend.length && !rawSource.adapterData) {
rawSource.adapterData = breakpointsToSend[0].adapterData;
}
@@ -376,6 +370,17 @@ export class DebugSession implements IDebugSession {
return Promise.reject(new Error('no debug adapter'));
}
async breakpointsLocations(uri: URI, lineNumber: number): Promise<IPosition[]> {
if (this.raw) {
const source = this.getRawSource(uri);
const response = await this.raw.breakpointLocations({ source, line: lineNumber });
const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 }));
return distinct(positions, p => `${p.lineNumber}:${p.column}`);
}
return Promise.reject(new Error('no debug adapter'));
}
customRequest(request: string, args: any): Promise<DebugProtocol.Response> {
if (this.raw) {
return this.raw.custom(request, args);
@@ -914,6 +919,16 @@ export class DebugSession implements IDebugSession {
return source;
}
private getRawSource(uri: URI): DebugProtocol.Source {
const source = this.getSourceForUri(uri);
if (source) {
return source.raw;
} else {
const data = Source.getEncodedDebugData(uri);
return { name: data.name, path: data.path, sourceReference: data.sourceReference };
}
}
private getNewCancellationToken(threadId: number): CancellationToken {
const tokenSource = new CancellationTokenSource();
const tokens = this.cancellationMap.get(threadId) || [];

View File

@@ -5,7 +5,7 @@
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
@@ -13,8 +13,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService {
constructor(
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@@ -45,6 +47,52 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
}
}));
}
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
// we pass the "ParsedArgs" as query parameters of the URL
let newAddress = `${document.location.origin}${document.location.pathname}?`;
let gotFolder = false;
const addQueryParameter = (key: string, value: string) => {
const lastChar = newAddress.charAt(newAddress.length - 1);
if (lastChar !== '?' && lastChar !== '&') {
newAddress += '&';
}
newAddress += `${key}=${encodeURIComponent(value)}`;
};
const f = args['folder-uri'];
if (f) {
const u = URI.parse(f[0]);
gotFolder = true;
addQueryParameter('folder', u.path);
}
if (!gotFolder) {
// request empty window
addQueryParameter('ew', 'true');
}
const ep = args['extensionDevelopmentPath'];
if (ep) {
let u = ep[0];
addQueryParameter('edp', u);
}
const di = args['debugId'];
if (di) {
addQueryParameter('di', di);
}
const ibe = args['inspect-brk-extensions'];
if (ibe) {
addQueryParameter('ibe', ibe);
}
window.open(newAddress);
return Promise.resolve();
}
}
registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService);

View File

@@ -1,7 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#C5C5C5"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#C5C5C5"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#C5C5C5"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#C5C5C5"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#C5C5C5"/>
</svg>

Before

Width:  |  Height:  |  Size: 484 B

View File

@@ -1,7 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="white"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="white"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="white"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="white"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 474 B

View File

@@ -1,7 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#424242"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#424242"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#424242"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#424242"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 484 B

View File

@@ -17,12 +17,20 @@
}
.debug-breakpoint-disabled,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-disabled-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled {
background: url('breakpoint-disabled.svg') center center no-repeat;
}
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled:hover {
background: url('breakpoint-hint.svg') center center no-repeat;
}
.monaco-editor .inline-breakpoint-widget.line-start {
left: -0.45em !important;
}
.debug-breakpoint-unverified,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unverified-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified {
background: url('breakpoint-unverified.svg') center center no-repeat;
}
@@ -35,21 +43,31 @@
}
.debug-breakpoint,
.monaco-editor .debug-breakpoint-column::before {
.monaco-editor .inline-breakpoint-widget {
background: url('breakpoint.svg') center center no-repeat;
}
.monaco-editor .debug-breakpoint-column::before,
.monaco-editor .debug-breakpoint-placeholder::before,
.monaco-editor .debug-top-stack-frame-column::before {
content: " ";
width: 1.3em;
height: 1.3em;
display: inline-block;
vertical-align: text-bottom;
margin-right: 2px;
margin-left: 2px;
}
.monaco-editor .debug-top-stack-frame-column::before {
height: 1.3em;
}
.monaco-editor .inline-breakpoint-widget {
width: 1.3em;
height: 1.3em;
margin-left: 0.61em;
cursor: pointer;
}
.debug-function-breakpoint {
background: url('breakpoint-function.svg') center center no-repeat;
}
@@ -75,34 +93,34 @@
}
.debug-breakpoint-conditional,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-conditional {
background: url('breakpoint-conditional.svg') center center no-repeat;
}
.debug-breakpoint-log,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-log-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log {
background: url('breakpoint-log.svg') center center no-repeat;
}
.debug-breakpoint-log-disabled,
.monaco-editor .debug-breakpoint-log-disabled-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-disabled {
background: url('breakpoint-log-disabled.svg') center center no-repeat;
}
.debug-breakpoint-log-unverified,
.monaco-editor .debug-breakpoint-log-unverified-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-unverified {
background: url('breakpoint-log-unverified.svg') center center no-repeat;
}
.debug-breakpoint-unsupported,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unsupported-column::before {
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unsupported {
background: url('breakpoint-unsupported.svg') center center no-repeat;
}
.monaco-editor .debug-top-stack-frame.debug-breakpoint,
.monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional,
.monaco-editor .debug-top-stack-frame.debug-breakpoint-log,
.monaco-editor .debug-breakpoint-column.debug-breakpoint-column.debug-top-stack-frame-column::before {
.monaco-editor .inline-breakpoint-widget.debug-top-stack-frame-column {
background: url('current-and-breakpoint.svg') center center no-repeat;
}

View File

@@ -88,19 +88,6 @@
font-size: 9px;
}
/* Actions */
.debug-action.clear-repl {
background: url('clear-light.svg') center center no-repeat;
}
.vs-dark .debug-action.clear-repl {
background: url('clear-dark.svg') center center no-repeat;
}
.hc-black .debug-action.clear-repl {
background: url('clear-hc.svg') center center no-repeat;
}
/* Output coloring and styling */
.repl .repl-tree .output.expression > .ignore {
font-style: italic;

View File

@@ -13,7 +13,7 @@ import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug';
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { URI } from 'vs/base/common/uri';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { env as processEnv } from 'vs/base/common/process';
@@ -79,7 +79,7 @@ export class RawDebugSession implements IDisposable {
dbgr: IDebugger,
private readonly telemetryService: ITelemetryService,
public readonly customTelemetryService: ITelemetryService | undefined,
private readonly windowsService: IWindowsService,
private readonly extensionHostDebugService: IExtensionHostDebugService,
private readonly openerService: IOpenerService
) {
@@ -381,6 +381,13 @@ export class RawDebugSession implements IDisposable {
return this.send<DebugProtocol.SetExceptionBreakpointsResponse>('setExceptionBreakpoints', args);
}
breakpointLocations(args: DebugProtocol.BreakpointLocationsArguments): Promise<DebugProtocol.BreakpointLocationsResponse> {
if (this.capabilities.supportsBreakpointLocationsRequest) {
return this.send('breakpointLocations', args);
}
return Promise.reject(new Error('breakpointLocations is not supported'));
}
configurationDone(): Promise<DebugProtocol.ConfigurationDoneResponse> {
if (this.capabilities.supportsConfigurationDoneRequest) {
return this.send('configurationDone', null);
@@ -594,7 +601,7 @@ export class RawDebugSession implements IDisposable {
} else {
args[key] = [value];
}
} else if (key === 'extensionDevelopmentPath') {
} else if (key === 'extensionDevelopmentPath' || key === 'enable-proposed-api') {
const v = args[key];
if (v) {
v.push(value);
@@ -625,7 +632,7 @@ export class RawDebugSession implements IDisposable {
Object.keys(env).filter(k => env[k] === null).forEach(key => delete env[key]);
}
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
return this.extensionHostDebugService.openExtensionDevelopmentHostWindow(args, env);
}
private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> {

View File

@@ -1008,7 +1008,7 @@ export class ClearReplAction extends Action {
constructor(id: string, label: string,
@IPanelService private readonly panelService: IPanelService
) {
super(id, label, 'debug-action clear-repl');
super(id, label, 'debug-action codicon-clear-all');
}
run(): Promise<any> {

View File

@@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel as EditorIModel } from 'vs/editor/common/model';
import { IEditor, ITextEditor } from 'vs/workbench/common/editor';
import { Position } from 'vs/editor/common/core/position';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { CompletionItem } from 'vs/editor/common/modes';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { Range, IRange } from 'vs/editor/common/core/range';
@@ -58,6 +58,7 @@ export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('resta
export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false);
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
export const BREAKPOINT_EDITOR_CONTRIBUTION_ID = 'editor.contrib.breakpoint';
export const DEBUG_SCHEME = 'debug';
export const INTERNAL_CONSOLE_OPTIONS_SCHEMA = {
enum: ['neverOpen', 'openOnSessionStart', 'openOnFirstSessionStart'],
@@ -207,6 +208,7 @@ export interface IDebugSession extends ITreeElement {
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }>;
sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void>;
sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void>;
breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]>;
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse>;
exceptionInfo(threadId: number): Promise<IExceptionInfo | undefined>;
@@ -850,9 +852,12 @@ export const enum BreakpointWidgetContext {
export interface IDebugEditorContribution extends IEditorContribution {
showHover(range: Range, focus: boolean): Promise<void>;
addLaunchConfiguration(): Promise<any>;
}
export interface IBreakpointEditorContribution extends IEditorContribution {
showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void;
closeBreakpointWidget(): void;
addLaunchConfiguration(): Promise<any>;
}
// temporary debug helper service

View File

@@ -7,13 +7,22 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
constructor(
@IMainProcessService readonly windowService: IMainProcessService,
@IMainProcessService readonly mainProcessService: IMainProcessService,
@IWindowsService private readonly windowsService: IWindowsService
) {
super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
super(mainProcessService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
}
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
// TODO@Isidor use debug IPC channel
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
}
}

View File

@@ -6,7 +6,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 } from 'vs/editor/common/core/position';
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 { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { CompletionItem } from 'vs/editor/common/modes';
@@ -132,6 +132,11 @@ export class MockDebugService implements IDebugService {
}
export class MockSession implements IDebugSession {
breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]> {
throw new Error('Method not implemented.');
}
dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> {
throw new Error('Method not implemented.');
}