Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 (#7206)
* Merge from vscode 64980ea1f3f532c82bb6c28d27bba9ef2c5b4463 * fix config changes * fix strictnull checks
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IExpression, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IExpression, IDebugService, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Expression, Variable, ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInputValidationOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
@@ -16,6 +16,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
|
||||
export const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
export const twistiePixels = 20;
|
||||
@@ -29,6 +30,7 @@ export interface IRenderValueOptions {
|
||||
maxValueLength?: number;
|
||||
showHover?: boolean;
|
||||
colorize?: boolean;
|
||||
linkDetector?: LinkDetector;
|
||||
}
|
||||
|
||||
export interface IVariableTemplateData {
|
||||
@@ -50,7 +52,7 @@ export function replaceWhitespace(value: string): string {
|
||||
return value.replace(/[\n\r\t]/g, char => map[char]);
|
||||
}
|
||||
|
||||
export function renderExpressionValue(expressionOrValue: IExpression | string, container: HTMLElement, options: IRenderValueOptions): void {
|
||||
export function renderExpressionValue(expressionOrValue: IExpressionContainer | string, container: HTMLElement, options: IRenderValueOptions): void {
|
||||
let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value;
|
||||
|
||||
// remove stale classes
|
||||
@@ -83,16 +85,22 @@ export function renderExpressionValue(expressionOrValue: IExpression | string, c
|
||||
value = value.substr(0, options.maxValueLength) + '...';
|
||||
}
|
||||
if (value && !options.preserveWhitespace) {
|
||||
container.textContent = replaceWhitespace(value);
|
||||
value = replaceWhitespace(value);
|
||||
} else {
|
||||
container.textContent = value || '';
|
||||
value = value || '';
|
||||
}
|
||||
if (options.linkDetector) {
|
||||
container.textContent = '';
|
||||
container.appendChild(options.linkDetector.handleLinks(value));
|
||||
} else {
|
||||
container.textContent = value;
|
||||
}
|
||||
if (options.showHover) {
|
||||
container.title = value || '';
|
||||
}
|
||||
}
|
||||
|
||||
export function renderVariable(variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[]): void {
|
||||
export function renderVariable(variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[], linkDetector?: LinkDetector): void {
|
||||
if (variable.available) {
|
||||
let text = replaceWhitespace(variable.name);
|
||||
if (variable.value && typeof variable.name === 'string') {
|
||||
@@ -109,7 +117,8 @@ export function renderVariable(variable: Variable, data: IVariableTemplateData,
|
||||
maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET,
|
||||
preserveWhitespace: false,
|
||||
showHover: true,
|
||||
colorize: true
|
||||
colorize: true,
|
||||
linkDetector
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,16 +218,19 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
||||
renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
|
||||
const { element } = node;
|
||||
if (element === this.debugService.getViewModel().getSelectedExpression()) {
|
||||
data.enableInputBox(element, this.getInputBoxOptions(element));
|
||||
} else {
|
||||
this.renderExpression(element, data, createMatches(node.filterData));
|
||||
const options = this.getInputBoxOptions(element);
|
||||
if (options) {
|
||||
data.enableInputBox(element, options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.renderExpression(element, data, createMatches(node.filterData));
|
||||
}
|
||||
|
||||
protected abstract renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void;
|
||||
protected abstract getInputBoxOptions(expression: IExpression): IInputBoxOptions;
|
||||
protected abstract getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined;
|
||||
|
||||
disposeTemplate(templateData: IExpressionTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,13 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
const $ = dom.$;
|
||||
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
|
||||
export interface IPrivateBreakpointWidgetService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
close(success: boolean): void;
|
||||
}
|
||||
const DECORATION_KEY = 'breakpointwidgetdecoration';
|
||||
|
||||
export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWidgetService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private selectContainer!: HTMLElement;
|
||||
private input!: IActiveCodeEditor;
|
||||
|
||||
@@ -70,23 +70,23 @@ export class BreakpointsView extends ViewletPanel {
|
||||
dom.addClass(container, 'debug-breakpoints');
|
||||
const delegate = new BreakpointsDelegate(this.debugService);
|
||||
|
||||
this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [
|
||||
this.list = this.instantiationService.createInstance(WorkbenchList, 'Breakpoints', container, delegate, [
|
||||
this.instantiationService.createInstance(BreakpointsRenderer),
|
||||
new ExceptionBreakpointsRenderer(this.debugService),
|
||||
this.instantiationService.createInstance(FunctionBreakpointsRenderer),
|
||||
this.instantiationService.createInstance(DataBreakpointsRenderer),
|
||||
new FunctionBreakpointInputRenderer(this.debugService, this.contextViewService, this.themeService)
|
||||
], {
|
||||
identityProvider: { getId: (element: IEnablement) => element.getId() },
|
||||
multipleSelectionSupport: false,
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e },
|
||||
ariaProvider: {
|
||||
getSetSize: (_: IEnablement, index: number, listLength: number) => listLength,
|
||||
getPosInSet: (_: IEnablement, index: number) => index,
|
||||
getRole: (breakpoint: IEnablement) => 'checkbox',
|
||||
isChecked: (breakpoint: IEnablement) => breakpoint.enabled
|
||||
}
|
||||
});
|
||||
identityProvider: { getId: (element: IEnablement) => element.getId() },
|
||||
multipleSelectionSupport: false,
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e },
|
||||
ariaProvider: {
|
||||
getSetSize: (_: IEnablement, index: number, listLength: number) => listLength,
|
||||
getPosInSet: (_: IEnablement, index: number) => index,
|
||||
getRole: (breakpoint: IEnablement) => 'checkbox',
|
||||
isChecked: (breakpoint: IEnablement) => breakpoint.enabled
|
||||
}
|
||||
});
|
||||
|
||||
CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService);
|
||||
|
||||
@@ -445,7 +445,7 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = functionBreakpoint.enabled;
|
||||
data.breakpoint.title = functionBreakpoint.name;
|
||||
data.breakpoint.title = message ? message : '';
|
||||
|
||||
// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
@@ -500,7 +500,7 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IBaseBrea
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = dataBreakpoint.enabled;
|
||||
data.breakpoint.title = dataBreakpoint.label;
|
||||
data.breakpoint.title = message ? message : '';
|
||||
|
||||
// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
@@ -639,8 +639,8 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
if (!breakpoint.enabled || !debugService.getModel().areBreakpointsActivated()) {
|
||||
return {
|
||||
className: breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-disabled' : breakpoint.logMessage ? 'debug-breakpoint-log-disabled' : 'debug-breakpoint-disabled',
|
||||
message: breakpoint.logMessage ? nls.localize('disabledLogpoint', "Disabled logpoint") : nls.localize('disabledBreakpoint', "Disabled breakpoint"),
|
||||
className: breakpoint instanceof DataBreakpoint ? 'debug-data-breakpoint-disabled' : breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-disabled' : breakpoint.logMessage ? 'debug-breakpoint-log-disabled' : 'debug-breakpoint-disabled',
|
||||
message: breakpoint.logMessage ? nls.localize('disabledLogpoint', "Disabled Logpoint") : nls.localize('disabledBreakpoint', "Disabled Breakpoint"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -649,8 +649,8 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
};
|
||||
if (debugActive && !breakpoint.verified) {
|
||||
return {
|
||||
className: breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-unverified' : breakpoint.logMessage ? 'debug-breakpoint-log-unverified' : 'debug-breakpoint-unverified',
|
||||
message: breakpoint.logMessage ? nls.localize('unverifiedLogpoint', "Unverified logpoint") : nls.localize('unverifiedBreakopint', "Unverified breakpoint"),
|
||||
className: breakpoint instanceof DataBreakpoint ? 'debug-data-breakpoint-unverified' : breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-unverified' : breakpoint.logMessage ? 'debug-breakpoint-log-unverified' : 'debug-breakpoint-unverified',
|
||||
message: breakpoint.message || (breakpoint.logMessage ? nls.localize('unverifiedLogpoint', "Unverified Logpoint") : nls.localize('unverifiedBreakopint', "Unverified Breakpoint")),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -665,6 +665,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
return {
|
||||
className: 'debug-function-breakpoint',
|
||||
message: breakpoint.message || nls.localize('functionBreakpoint', "Function Breakpoint")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -678,6 +679,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
return {
|
||||
className: 'debug-data-breakpoint',
|
||||
message: breakpoint.message || nls.localize('dataBreakpoint', "Data Breakpoint")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -722,6 +724,6 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
return {
|
||||
className: 'debug-breakpoint',
|
||||
message: breakpoint.message
|
||||
message: breakpoint.message || nls.localize('breakpoint', "Breakpoint")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -30,6 +30,10 @@ import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlighte
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { STOP_ID, STOP_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, RESTART_SESSION_ID, RESTART_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STEP_INTO_LABEL, STEP_INTO_ID, STEP_OUT_LABEL, STEP_OUT_ID, PAUSE_ID, PAUSE_LABEL, CONTINUE_ID, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -48,6 +52,7 @@ export class CallStackView extends ViewletPanel {
|
||||
private tree!: WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>;
|
||||
private contributedContextMenu: IMenu;
|
||||
private parentSessionToExpand = new Set<IDebugSession>();
|
||||
private selectionNeedsUpdate = false;
|
||||
|
||||
constructor(
|
||||
private options: IViewletViewOptions,
|
||||
@@ -86,7 +91,10 @@ export class CallStackView extends ViewletPanel {
|
||||
this.tree.updateChildren().then(() => {
|
||||
this.parentSessionToExpand.forEach(s => this.tree.expand(s));
|
||||
this.parentSessionToExpand.clear();
|
||||
this.updateTreeSelection();
|
||||
if (this.selectionNeedsUpdate) {
|
||||
this.selectionNeedsUpdate = false;
|
||||
this.updateTreeSelection();
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
@@ -105,48 +113,48 @@ export class CallStackView extends ViewletPanel {
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
this.dataSource = new CallStackDataSource(this.debugService);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new CallStackDelegate(), [
|
||||
new SessionsRenderer(),
|
||||
new ThreadsRenderer(),
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [
|
||||
new SessionsRenderer(this.instantiationService),
|
||||
new ThreadsRenderer(this.instantiationService),
|
||||
this.instantiationService.createInstance(StackFramesRenderer),
|
||||
new ErrorsRenderer(),
|
||||
new LoadMoreRenderer(),
|
||||
new ShowMoreRenderer()
|
||||
], this.dataSource, {
|
||||
accessibilityProvider: new CallStackAccessibilityProvider(),
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack"),
|
||||
identityProvider: {
|
||||
getId: (element: CallStackItem) => {
|
||||
if (typeof element === 'string') {
|
||||
return element;
|
||||
}
|
||||
if (element instanceof Array) {
|
||||
return `showMore ${element[0].getId()}`;
|
||||
}
|
||||
|
||||
return element.getId();
|
||||
accessibilityProvider: new CallStackAccessibilityProvider(),
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack"),
|
||||
identityProvider: {
|
||||
getId: (element: CallStackItem) => {
|
||||
if (typeof element === 'string') {
|
||||
return element;
|
||||
}
|
||||
},
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (e: CallStackItem) => {
|
||||
if (isDebugSession(e)) {
|
||||
return e.getLabel();
|
||||
}
|
||||
if (e instanceof Thread) {
|
||||
return `${e.name} ${e.stateLabel}`;
|
||||
}
|
||||
if (e instanceof StackFrame || typeof e === 'string') {
|
||||
return e;
|
||||
}
|
||||
if (e instanceof ThreadAndSessionIds) {
|
||||
return LoadMoreRenderer.LABEL;
|
||||
}
|
||||
|
||||
return nls.localize('showMoreStackFrames2', "Show More Stack Frames");
|
||||
if (element instanceof Array) {
|
||||
return `showMore ${element[0].getId()}`;
|
||||
}
|
||||
},
|
||||
expandOnlyOnTwistieClick: true
|
||||
});
|
||||
|
||||
return element.getId();
|
||||
}
|
||||
},
|
||||
keyboardNavigationLabelProvider: {
|
||||
getKeyboardNavigationLabel: (e: CallStackItem) => {
|
||||
if (isDebugSession(e)) {
|
||||
return e.getLabel();
|
||||
}
|
||||
if (e instanceof Thread) {
|
||||
return `${e.name} ${e.stateLabel}`;
|
||||
}
|
||||
if (e instanceof StackFrame || typeof e === 'string') {
|
||||
return e;
|
||||
}
|
||||
if (e instanceof ThreadAndSessionIds) {
|
||||
return LoadMoreRenderer.LABEL;
|
||||
}
|
||||
|
||||
return nls.localize('showMoreStackFrames2', "Show More Stack Frames");
|
||||
}
|
||||
},
|
||||
expandOnlyOnTwistieClick: true
|
||||
});
|
||||
|
||||
this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError);
|
||||
|
||||
@@ -201,8 +209,8 @@ export class CallStackView extends ViewletPanel {
|
||||
this.onCallStackChangeScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
const onCallStackChange = Event.any<any>(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession);
|
||||
this._register(onCallStackChange(() => {
|
||||
const onFocusChange = Event.any<any>(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession);
|
||||
this._register(onFocusChange(() => {
|
||||
if (this.ignoreFocusStackFrameEvent) {
|
||||
return;
|
||||
}
|
||||
@@ -210,6 +218,10 @@ export class CallStackView extends ViewletPanel {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
if (this.onCallStackChangeScheduler.isScheduled()) {
|
||||
this.selectionNeedsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateTreeSelection();
|
||||
}));
|
||||
@@ -227,6 +239,7 @@ export class CallStackView extends ViewletPanel {
|
||||
}));
|
||||
|
||||
this._register(this.debugService.onDidNewSession(s => {
|
||||
this._register(s.onDidChangeName(() => this.tree.rerender(s)));
|
||||
if (s.parentSession) {
|
||||
// Auto expand sessions that have sub sessions
|
||||
this.parentSessionToExpand.add(s.parentSession);
|
||||
@@ -334,6 +347,7 @@ interface IThreadTemplateData {
|
||||
state: HTMLElement;
|
||||
stateLabel: HTMLSpanElement;
|
||||
label: HighlightedLabel;
|
||||
actionBar: ActionBar;
|
||||
}
|
||||
|
||||
interface ISessionTemplateData {
|
||||
@@ -342,6 +356,7 @@ interface ISessionTemplateData {
|
||||
state: HTMLElement;
|
||||
stateLabel: HTMLSpanElement;
|
||||
label: HighlightedLabel;
|
||||
actionBar: ActionBar;
|
||||
}
|
||||
|
||||
interface IErrorTemplateData {
|
||||
@@ -363,6 +378,10 @@ interface IStackFrameTemplateData {
|
||||
class SessionsRenderer implements ITreeRenderer<IDebugSession, FuzzyScore, ISessionTemplateData> {
|
||||
static readonly ID = 'session';
|
||||
|
||||
constructor(
|
||||
private readonly instantiationService: IInstantiationService
|
||||
) { }
|
||||
|
||||
get templateId(): string {
|
||||
return SessionsRenderer.ID;
|
||||
}
|
||||
@@ -373,28 +392,35 @@ class SessionsRenderer implements ITreeRenderer<IDebugSession, FuzzyScore, ISess
|
||||
const state = dom.append(session, $('.state'));
|
||||
const stateLabel = dom.append(state, $('span.label'));
|
||||
const label = new HighlightedLabel(name, false);
|
||||
const actionBar = new ActionBar(session);
|
||||
|
||||
return { session, name, state, stateLabel, label };
|
||||
return { session, name, state, stateLabel, label, actionBar };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<IDebugSession, FuzzyScore>, index: number, data: ISessionTemplateData): void {
|
||||
renderElement(element: ITreeNode<IDebugSession, FuzzyScore>, _: number, data: ISessionTemplateData): void {
|
||||
const session = element.element;
|
||||
data.session.title = nls.localize({ key: 'session', comment: ['Session is a noun'] }, "Session");
|
||||
data.label.set(session.getLabel(), createMatches(element.filterData));
|
||||
const stoppedThread = session.getAllThreads().filter(t => t.stopped).pop();
|
||||
|
||||
data.actionBar.clear();
|
||||
const actions = getActions(this.instantiationService, element.element);
|
||||
data.actionBar.push(actions, { icon: true, label: false });
|
||||
|
||||
data.stateLabel.textContent = stoppedThread ? nls.localize('paused', "Paused")
|
||||
: nls.localize({ key: 'running', comment: ['indicates state'] }, "Running");
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISessionTemplateData): void {
|
||||
// noop
|
||||
templateData.actionBar.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadsRenderer implements ITreeRenderer<IThread, FuzzyScore, IThreadTemplateData> {
|
||||
static readonly ID = 'thread';
|
||||
|
||||
constructor(private readonly instantiationService: IInstantiationService) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ThreadsRenderer.ID;
|
||||
}
|
||||
@@ -405,8 +431,9 @@ class ThreadsRenderer implements ITreeRenderer<IThread, FuzzyScore, IThreadTempl
|
||||
const state = dom.append(thread, $('.state'));
|
||||
const stateLabel = dom.append(state, $('span.label'));
|
||||
const label = new HighlightedLabel(name, false);
|
||||
const actionBar = new ActionBar(thread);
|
||||
|
||||
return { thread, name, state, stateLabel, label };
|
||||
return { thread, name, state, stateLabel, label, actionBar };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<IThread, FuzzyScore>, index: number, data: IThreadTemplateData): void {
|
||||
@@ -414,10 +441,14 @@ class ThreadsRenderer implements ITreeRenderer<IThread, FuzzyScore, IThreadTempl
|
||||
data.thread.title = nls.localize('thread', "Thread");
|
||||
data.label.set(thread.name, createMatches(element.filterData));
|
||||
data.stateLabel.textContent = thread.stateLabel;
|
||||
|
||||
data.actionBar.clear();
|
||||
const actions = getActions(this.instantiationService, thread);
|
||||
data.actionBar.push(actions, { icon: true, label: false });
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IThreadTemplateData): void {
|
||||
// noop
|
||||
templateData.actionBar.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,3 +738,147 @@ class CallStackAccessibilityProvider implements IAccessibilityProvider<CallStack
|
||||
return nls.localize('loadMoreStackFrames', "Load More Stack Frames");
|
||||
}
|
||||
}
|
||||
|
||||
function getActions(instantiationService: IInstantiationService, element: IDebugSession | IThread): IAction[] {
|
||||
const getThreadActions = (thread: IThread): IAction[] => {
|
||||
return [
|
||||
thread.stopped ? instantiationService.createInstance(ContinueAction, thread) : instantiationService.createInstance(PauseAction, thread),
|
||||
instantiationService.createInstance(StepOverAction, thread),
|
||||
instantiationService.createInstance(StepIntoAction, thread),
|
||||
instantiationService.createInstance(StepOutAction, thread)
|
||||
];
|
||||
};
|
||||
|
||||
if (element instanceof Thread) {
|
||||
return getThreadActions(element);
|
||||
}
|
||||
|
||||
const session = <IDebugSession>element;
|
||||
const stopOrDisconectAction = isSessionAttach(session) ? instantiationService.createInstance(DisconnectAction, session) : instantiationService.createInstance(StopAction, session);
|
||||
const restartAction = instantiationService.createInstance(RestartAction, session);
|
||||
const threads = session.getAllThreads();
|
||||
if (threads.length === 1) {
|
||||
return getThreadActions(threads[0]).concat([
|
||||
restartAction,
|
||||
stopOrDisconectAction
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
restartAction,
|
||||
stopOrDisconectAction
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
class StopAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action stop');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STOP_ID, this.session.getId(), this.session);
|
||||
}
|
||||
}
|
||||
|
||||
class DisconnectAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(DISCONNECT_ID, this.session.getId(), this.session);
|
||||
}
|
||||
}
|
||||
|
||||
class RestartAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action restart');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(RESTART_SESSION_ID, this.session.getId(), this.session);
|
||||
}
|
||||
}
|
||||
|
||||
class StepOverAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action step-over', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_OVER_ID, this.thread.threadId, this.thread);
|
||||
}
|
||||
}
|
||||
|
||||
class StepIntoAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action step-into', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_INTO_ID, this.thread.threadId, this.thread);
|
||||
}
|
||||
}
|
||||
|
||||
class StepOutAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action step-out', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_OUT_ID, this.thread.threadId, this.thread);
|
||||
}
|
||||
}
|
||||
|
||||
class PauseAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action pause', !thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(PAUSE_ID, this.thread.threadId, this.thread);
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action continue', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(CONTINUE_ID, this.thread.threadId, this.thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBr
|
||||
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
|
||||
import * as service from 'vs/workbench/contrib/debug/browser/debugService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
|
||||
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
|
||||
import { IViewsRegistry, Extensions as ViewExtensions } from 'vs/workbench/common/views';
|
||||
@@ -48,6 +48,7 @@ import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchEx
|
||||
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';
|
||||
|
||||
class OpenDebugViewletAction extends ShowViewletAction {
|
||||
public static readonly ID = VIEWLET_ID;
|
||||
@@ -148,23 +149,16 @@ const registerDebugCommandPaletteItem = (id: string, title: string, when?: Conte
|
||||
}
|
||||
});
|
||||
};
|
||||
const restartLabel = nls.localize('restartDebug', "Restart");
|
||||
const stepOverLabel = nls.localize('stepOverDebug', "Step Over");
|
||||
const stepIntoLabel = nls.localize('stepIntoDebug', "Step Into");
|
||||
const stepOutLabel = nls.localize('stepOutDebug', "Step Out");
|
||||
const pauseLabel = nls.localize('pauseDebug', "Pause");
|
||||
const disconnectLabel = nls.localize('disconnect', "Disconnect");
|
||||
const stopLabel = nls.localize('stop', "Stop");
|
||||
const continueLabel = nls.localize('continueDebug', "Continue");
|
||||
registerDebugCommandPaletteItem(RESTART_SESSION_ID, restartLabel);
|
||||
|
||||
registerDebugCommandPaletteItem(RESTART_SESSION_ID, RESTART_LABEL);
|
||||
registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE);
|
||||
registerDebugCommandPaletteItem(STEP_OVER_ID, stepOverLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(STEP_INTO_ID, stepIntoLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(STEP_OUT_ID, stepOutLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(PAUSE_ID, pauseLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running'));
|
||||
registerDebugCommandPaletteItem(DISCONNECT_ID, disconnectLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugCommandPaletteItem(STOP_ID, stopLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugCommandPaletteItem(CONTINUE_ID, continueLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(STEP_OVER_ID, STEP_OVER_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(STEP_INTO_ID, STEP_INTO_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(STEP_OUT_ID, STEP_OUT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(PAUSE_ID, PAUSE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('running'));
|
||||
registerDebugCommandPaletteItem(DISCONNECT_ID, DISCONNECT_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugCommandPaletteItem(STOP_ID, STOP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugCommandPaletteItem(CONTINUE_ID, CONTINUE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCommandPaletteItem(FOCUS_REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View'));
|
||||
registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('jumpToCursor', "Jump to Cursor"), ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED));
|
||||
registerDebugCommandPaletteItem(RunToCursorAction.ID, RunToCursorAction.LABEL, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')));
|
||||
@@ -265,6 +259,11 @@ configurationRegistry.registerConfiguration({
|
||||
type: 'boolean',
|
||||
description: nls.localize('debug.focusWindowOnBreak', "Controls whether the workbench window should be focused when the debugger breaks."),
|
||||
default: true
|
||||
},
|
||||
'debug.onTaskErrors': {
|
||||
enum: ['debugAnyway', 'showErrors', 'prompt'],
|
||||
description: nls.localize('debug.onTaskErrors', "Controls what to do when errors are encountered after running a preLaunchTask."),
|
||||
default: 'prompt'
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -274,7 +273,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
|
||||
// Debug toolbar
|
||||
|
||||
const registerDebugToolBarItem = (id: string, title: string, icon: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => {
|
||||
const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, iconDarkUri: URI, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => {
|
||||
MenuRegistry.appendMenuItem(MenuId.DebugToolBar, {
|
||||
group: 'navigation',
|
||||
when,
|
||||
@@ -283,24 +282,24 @@ const registerDebugToolBarItem = (id: string, title: string, icon: string, order
|
||||
id,
|
||||
title,
|
||||
iconLocation: {
|
||||
light: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-light.svg`)),
|
||||
dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-dark.svg`))
|
||||
light: iconLightUri,
|
||||
dark: iconDarkUri
|
||||
},
|
||||
precondition
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
registerDebugToolBarItem(CONTINUE_ID, continueLabel, 'continue', 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(PAUSE_ID, pauseLabel, 'pause', 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped'));
|
||||
registerDebugToolBarItem(STOP_ID, stopLabel, 'stop', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugToolBarItem(DISCONNECT_ID, disconnectLabel, 'disconnect', 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugToolBarItem(STEP_OVER_ID, stepOverLabel, 'step-over', 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_INTO_ID, stepIntoLabel, 'step-into', 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_OUT_ID, stepOutLabel, 'step-out', 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(RESTART_SESSION_ID, restartLabel, 'restart', 60);
|
||||
registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), 'step-back', 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 'reverse-continue', 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-dark.svg')), 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-dark.svg')), 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped'));
|
||||
registerDebugToolBarItem(STOP_ID, STOP_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-dark.svg')), 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-dark.svg')), 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-dark.svg')), 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-dark.svg')), 60);
|
||||
registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-dark.svg')), 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg')), 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
|
||||
// Debug callstack context menu
|
||||
const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => {
|
||||
@@ -315,13 +314,13 @@ const registerDebugCallstackItem = (id: string, title: string, order: number, wh
|
||||
}
|
||||
});
|
||||
};
|
||||
registerDebugCallstackItem(RESTART_SESSION_ID, restartLabel, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session'));
|
||||
registerDebugCallstackItem(STOP_ID, stopLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session'));
|
||||
registerDebugCallstackItem(PAUSE_ID, pauseLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running')));
|
||||
registerDebugCallstackItem(CONTINUE_ID, continueLabel, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')));
|
||||
registerDebugCallstackItem(STEP_OVER_ID, stepOverLabel, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(STEP_INTO_ID, stepIntoLabel, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(STEP_OUT_ID, stepOutLabel, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(RESTART_SESSION_ID, RESTART_LABEL, 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session'));
|
||||
registerDebugCallstackItem(STOP_ID, STOP_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('session'));
|
||||
registerDebugCallstackItem(PAUSE_ID, PAUSE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('running')));
|
||||
registerDebugCallstackItem(CONTINUE_ID, CONTINUE_LABEL, 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped')));
|
||||
registerDebugCallstackItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugCallstackItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), 10, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('thread'), undefined, 'termination');
|
||||
registerDebugCallstackItem(RESTART_FRAME_ID, nls.localize('restartFrame', "Restart Frame"), 10, ContextKeyExpr.and(CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'), CONTEXT_RESTART_FRAME_SUPPORTED));
|
||||
registerDebugCallstackItem(COPY_STACK_TRACE_ID, nls.localize('copyStackTrace', "Copy Call Stack"), 20, CONTEXT_CALLSTACK_ITEM_TYPE.isEqualTo('stackFrame'));
|
||||
@@ -544,12 +543,12 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, {
|
||||
// Touch Bar
|
||||
if (isMacintosh) {
|
||||
|
||||
const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => {
|
||||
const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, iconUri: URI) => {
|
||||
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
|
||||
command: {
|
||||
id,
|
||||
title,
|
||||
iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}`)) }
|
||||
iconLocation: { dark: iconUri }
|
||||
},
|
||||
when,
|
||||
group: '9_debug',
|
||||
@@ -557,13 +556,13 @@ if (isMacintosh) {
|
||||
});
|
||||
};
|
||||
|
||||
registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-tb.png');
|
||||
registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png');
|
||||
registerTouchBarEntry(CONTINUE_ID, continueLabel, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png');
|
||||
registerTouchBarEntry(PAUSE_ID, pauseLabel, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png');
|
||||
registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png');
|
||||
registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png');
|
||||
registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png');
|
||||
registerTouchBarEntry(RESTART_SESSION_ID, restartLabel, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png');
|
||||
registerTouchBarEntry(STOP_ID, stopLabel, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png');
|
||||
registerTouchBarEntry(StartAction.ID, StartAction.LABEL, 0, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png')));
|
||||
registerTouchBarEntry(CONTINUE_ID, CONTINUE_LABEL, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-tb.png')));
|
||||
registerTouchBarEntry(PAUSE_ID, PAUSE_LABEL, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-tb.png')));
|
||||
registerTouchBarEntry(STEP_OVER_ID, STEP_OVER_LABEL, 2, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepover-tb.png')));
|
||||
registerTouchBarEntry(STEP_INTO_ID, STEP_INTO_LABEL, 3, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepinto-tb.png')));
|
||||
registerTouchBarEntry(STEP_OUT_ID, STEP_OUT_LABEL, 4, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stepout-tb.png')));
|
||||
registerTouchBarEntry(RESTART_SESSION_ID, RESTART_LABEL, 5, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-tb.png')));
|
||||
registerTouchBarEntry(STOP_ID, STOP_LABEL, 6, CONTEXT_IN_DEBUG_MODE, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-tb.png')));
|
||||
}
|
||||
|
||||
@@ -209,7 +209,13 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.debugService.onDidNewSession(() => this.update()));
|
||||
this._register(this.debugService.onDidNewSession(session => {
|
||||
this._register(session.onDidChangeName(() => this.update()));
|
||||
this.update();
|
||||
}));
|
||||
this.getSessions().forEach(session => {
|
||||
this._register(session.onDidChangeName(() => this.update()));
|
||||
});
|
||||
this._register(this.debugService.onDidEndSession(() => this.update()));
|
||||
|
||||
this.update();
|
||||
|
||||
@@ -210,7 +210,7 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction {
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0);
|
||||
return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0 || model.getDataBreakpoints().length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ export class ToggleBreakpointsActivatedAction extends AbstractDebugAction {
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return (this.debugService.getModel().getFunctionBreakpoints().length + this.debugService.getModel().getBreakpoints().length) > 0;
|
||||
return !!(this.debugService.getModel().getFunctionBreakpoints().length || this.debugService.getModel().getBreakpoints().length || this.debugService.getModel().getDataBreakpoints().length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction {
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (state === State.Running || state === State.Stopped) &&
|
||||
(model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length > 0);
|
||||
((model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getDataBreakpoints().length) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,15 @@ export const CONTINUE_ID = 'workbench.action.debug.continue';
|
||||
export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl';
|
||||
export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor';
|
||||
|
||||
export const RESTART_LABEL = nls.localize('restartDebug', "Restart");
|
||||
export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over");
|
||||
export const STEP_INTO_LABEL = nls.localize('stepIntoDebug', "Step Into");
|
||||
export const STEP_OUT_LABEL = nls.localize('stepOutDebug', "Step Out");
|
||||
export const PAUSE_LABEL = nls.localize('pauseDebug', "Pause");
|
||||
export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect");
|
||||
export const STOP_LABEL = nls.localize('stop', "Stop");
|
||||
export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue");
|
||||
|
||||
function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise<void>, ): void {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
if (!(thread instanceof Thread)) {
|
||||
@@ -224,9 +233,9 @@ export function registerCommands(): void {
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: DISCONNECT_ID,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const session = debugService.getViewModel().focusedSession;
|
||||
session = session || debugService.getViewModel().focusedSession;
|
||||
debugService.stopSession(session).then(undefined, onUnexpectedError);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ 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 } from 'vs/editor/common/config/editorOptions';
|
||||
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';
|
||||
@@ -168,7 +168,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => {
|
||||
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)) {
|
||||
@@ -213,18 +213,18 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
|
||||
);
|
||||
|
||||
this.dialogService.show(severity.Info, disable ? disabling : enabling, [
|
||||
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 }).then(choice => {
|
||||
if (choice === 0) {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
}
|
||||
if (choice === 1) {
|
||||
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
|
||||
}
|
||||
});
|
||||
], { 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()));
|
||||
}
|
||||
@@ -540,7 +540,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
if (this.configurationWidget) {
|
||||
this.configurationWidget.dispose();
|
||||
}
|
||||
if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getConfiguration().readOnly) {
|
||||
if (model && LAUNCH_JSON_REGEX.test(model.uri.toString()) && !this.editor.getOption(EditorOption.readOnly)) {
|
||||
this.configurationWidget = this.instantiationService.createInstance(FloatingClickWidget, this.editor, nls.localize('addConfiguration', "Add Configuration..."), null);
|
||||
this.configurationWidget.render();
|
||||
this.toDispose.push(this.configurationWidget.onClick(() => this.addLaunchConfiguration()));
|
||||
|
||||
@@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -73,13 +73,13 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
this.treeContainer.setAttribute('role', 'tree');
|
||||
const dataSource = new DebugHoverDataSource();
|
||||
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)],
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)],
|
||||
dataSource, {
|
||||
ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"),
|
||||
accessibilityProvider: new DebugHoverAccessibilityProvider(),
|
||||
mouseSupport: false,
|
||||
horizontalScrolling: true
|
||||
});
|
||||
ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"),
|
||||
accessibilityProvider: new DebugHoverAccessibilityProvider(),
|
||||
mouseSupport: false,
|
||||
horizontalScrolling: true
|
||||
});
|
||||
|
||||
this.valueContainer = $('.value');
|
||||
this.valueContainer.tabIndex = 0;
|
||||
@@ -114,8 +114,8 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
this.hide();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
|
||||
if (e.fontInfo) {
|
||||
this.toDispose.push(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {
|
||||
if (e.hasChanged(EditorOption.fontInfo)) {
|
||||
this.editor.applyFontInfo(this.domNode);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -37,7 +37,7 @@ import { parse, getFirstFrame } from 'vs/base/common/console';
|
||||
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { deepClone, equals } from 'vs/base/common/objects';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
@@ -50,7 +50,6 @@ import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
|
||||
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
|
||||
const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
|
||||
const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
|
||||
const DEBUG_DATA_BREAKPOINTS_KEY = 'debug.databreakpoint';
|
||||
const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint';
|
||||
@@ -74,7 +73,7 @@ const enum TaskRunResult {
|
||||
}
|
||||
|
||||
export class DebugService implements IDebugService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeState: Emitter<State>;
|
||||
private readonly _onDidNewSession: Emitter<IDebugSession>;
|
||||
@@ -129,7 +128,7 @@ export class DebugService implements IDebugService {
|
||||
this.debugState = CONTEXT_DEBUG_STATE.bindTo(contextKeyService);
|
||||
this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService);
|
||||
|
||||
this.model = new DebugModel(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true), this.loadFunctionBreakpoints(),
|
||||
this.model = new DebugModel(this.loadBreakpoints(), this.loadFunctionBreakpoints(),
|
||||
this.loadExceptionBreakpoints(), this.loadDataBreakpoints(), this.loadWatchExpressions(), this.textFileService);
|
||||
this.toDispose.push(this.model);
|
||||
|
||||
@@ -671,29 +670,33 @@ export class DebugService implements IDebugService {
|
||||
return Promise.resolve(config);
|
||||
}
|
||||
|
||||
private showError(message: string, errorActions: ReadonlyArray<IAction> = []): Promise<void> {
|
||||
private async showError(message: string, errorActions: ReadonlyArray<IAction> = []): Promise<void> {
|
||||
const configureAction = this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL);
|
||||
const actions = [...errorActions, configureAction];
|
||||
return this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length }).then(choice => {
|
||||
if (choice < actions.length) {
|
||||
return actions[choice].run();
|
||||
}
|
||||
const { choice } = await this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length });
|
||||
if (choice < actions.length) {
|
||||
return actions[choice].run();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//---- task management
|
||||
|
||||
private runTaskAndCheckErrors(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise<TaskRunResult> {
|
||||
|
||||
const debugAnywayAction = new Action('debug.debugAnyway', nls.localize('debugAnyway', "Debug Anyway"), undefined, true, () => Promise.resolve(TaskRunResult.Success));
|
||||
return this.runTask(root, taskId).then((taskSummary: ITaskSummary) => {
|
||||
|
||||
const errorCount = taskId ? this.markerService.getStatistics().errors : 0;
|
||||
const successExitCode = taskSummary && taskSummary.exitCode === 0;
|
||||
const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0;
|
||||
if (successExitCode || (errorCount === 0 && !failureExitCode)) {
|
||||
return <any>TaskRunResult.Success;
|
||||
const onTaskErrors = this.configurationService.getValue<IDebugConfiguration>('debug').onTaskErrors;
|
||||
if (successExitCode || onTaskErrors === 'debugAnyway' || (errorCount === 0 && !failureExitCode)) {
|
||||
return TaskRunResult.Success;
|
||||
}
|
||||
if (onTaskErrors === 'showErrors') {
|
||||
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
}
|
||||
|
||||
const taskLabel = typeof taskId === 'string' ? taskId : taskId ? taskId.name : '';
|
||||
@@ -703,14 +706,28 @@ export class DebugService implements IDebugService {
|
||||
? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel)
|
||||
: nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary.exitCode);
|
||||
|
||||
const showErrorsAction = new Action('debug.showErrors', nls.localize('showErrors', "Show Errors"), undefined, true, () => {
|
||||
return this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], {
|
||||
checkbox: {
|
||||
label: nls.localize('remember', "Remember my choice in user settings"),
|
||||
},
|
||||
cancelId: 2
|
||||
}).then(result => {
|
||||
if (result.choice === 2) {
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
}
|
||||
const debugAnyway = result.choice === 0;
|
||||
if (result.checkboxChecked) {
|
||||
this.configurationService.updateValue('debug.onTaskErrors', debugAnyway ? 'debugAnyway' : 'showErrors');
|
||||
}
|
||||
if (debugAnyway) {
|
||||
return TaskRunResult.Success;
|
||||
}
|
||||
|
||||
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
});
|
||||
|
||||
return this.showError(message, [debugAnywayAction, showErrorsAction]);
|
||||
}, (err: TaskError) => {
|
||||
return this.showError(err.message, [debugAnywayAction, this.taskService.configureAction()]);
|
||||
return this.showError(err.message, [this.taskService.configureAction()]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -901,12 +918,6 @@ export class DebugService implements IDebugService {
|
||||
|
||||
setBreakpointsActivated(activated: boolean): Promise<void> {
|
||||
this.model.setBreakpointsActivated(activated);
|
||||
if (activated) {
|
||||
this.storageService.store(DEBUG_BREAKPOINTS_ACTIVATED_KEY, 'false', StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
return this.sendAllBreakpoints();
|
||||
}
|
||||
|
||||
@@ -944,7 +955,8 @@ export class DebugService implements IDebugService {
|
||||
return Promise.all(distinct(this.model.getBreakpoints(), bp => bp.uri.toString()).map(bp => this.sendBreakpoints(bp.uri, false, session)))
|
||||
.then(() => this.sendFunctionBreakpoints(session))
|
||||
// send exception breakpoints at the end since some debug adapters rely on the order
|
||||
.then(() => this.sendExceptionBreakpoints(session));
|
||||
.then(() => this.sendExceptionBreakpoints(session))
|
||||
.then(() => this.sendDataBreakpoints(session));
|
||||
}
|
||||
|
||||
private sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise<void> {
|
||||
|
||||
@@ -33,6 +33,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
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';
|
||||
|
||||
export class DebugSession implements IDebugSession {
|
||||
|
||||
@@ -43,6 +44,7 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
private sources = new Map<string, Source>();
|
||||
private threads = new Map<number, Thread>();
|
||||
private cancellationMap = new Map<number, CancellationTokenSource[]>();
|
||||
private rawListeners: IDisposable[] = [];
|
||||
private fetchThreadsScheduler: RunOnceScheduler | undefined;
|
||||
private repl: ReplModel;
|
||||
@@ -55,6 +57,9 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
private readonly _onDidChangeREPLElements = new Emitter<void>();
|
||||
|
||||
private name: string | undefined;
|
||||
private readonly _onDidChangeName = new Emitter<string>();
|
||||
|
||||
constructor(
|
||||
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
|
||||
public root: IWorkspaceFolder,
|
||||
@@ -105,7 +110,13 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
getLabel(): string {
|
||||
const includeRoot = this.workspaceContextService.getWorkspace().folders.length > 1;
|
||||
return includeRoot && this.root ? `${this.configuration.name} (${resources.basenameOrAuthority(this.root.uri)})` : this.configuration.name;
|
||||
const name = this.name || this.configuration.name;
|
||||
return includeRoot && this.root ? `${name} (${resources.basenameOrAuthority(this.root.uri)})` : name;
|
||||
}
|
||||
|
||||
setName(name: string): void {
|
||||
this.name = name;
|
||||
this._onDidChangeName.fire(name);
|
||||
}
|
||||
|
||||
get state(): State {
|
||||
@@ -144,6 +155,10 @@ export class DebugSession implements IDebugSession {
|
||||
return this._onDidChangeREPLElements.event;
|
||||
}
|
||||
|
||||
get onDidChangeName(): Event<string> {
|
||||
return this._onDidChangeName.event;
|
||||
}
|
||||
|
||||
//---- DAP events
|
||||
|
||||
get onDidCustomEvent(): Event<DebugProtocol.Event> {
|
||||
@@ -222,6 +237,7 @@ export class DebugSession implements IDebugSession {
|
||||
*/
|
||||
terminate(restart = false): Promise<void> {
|
||||
if (this.raw) {
|
||||
this.cancelAllRequests();
|
||||
if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') {
|
||||
return this.raw.terminate(restart).then(response => {
|
||||
return undefined;
|
||||
@@ -239,6 +255,7 @@ export class DebugSession implements IDebugSession {
|
||||
*/
|
||||
disconnect(restart = false): Promise<void> {
|
||||
if (this.raw) {
|
||||
this.cancelAllRequests();
|
||||
return this.raw.disconnect(restart).then(response => {
|
||||
return undefined;
|
||||
});
|
||||
@@ -251,6 +268,7 @@ export class DebugSession implements IDebugSession {
|
||||
*/
|
||||
restart(): Promise<void> {
|
||||
if (this.raw) {
|
||||
this.cancelAllRequests();
|
||||
return this.raw.restart().then(() => undefined);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
@@ -367,7 +385,8 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse> {
|
||||
if (this.raw) {
|
||||
return this.raw.stackTrace({ threadId, startFrame, levels });
|
||||
const token = this.getNewCancellationToken(threadId);
|
||||
return this.raw.stackTrace({ threadId, startFrame, levels }, token);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
@@ -389,16 +408,18 @@ export class DebugSession implements IDebugSession {
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
scopes(frameId: number): Promise<DebugProtocol.ScopesResponse> {
|
||||
scopes(frameId: number, threadId: number): Promise<DebugProtocol.ScopesResponse> {
|
||||
if (this.raw) {
|
||||
return this.raw.scopes({ frameId });
|
||||
const token = this.getNewCancellationToken(threadId);
|
||||
return this.raw.scopes({ frameId }, token);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
variables(variablesReference: number, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse> {
|
||||
variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse> {
|
||||
if (this.raw) {
|
||||
return this.raw.variables({ variablesReference, filter, start, count });
|
||||
const token = threadId ? this.getNewCancellationToken(threadId) : undefined;
|
||||
return this.raw.variables({ variablesReference, filter, start, count }, token);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
@@ -506,17 +527,8 @@ export class DebugSession implements IDebugSession {
|
||||
rawSource = source.raw;
|
||||
} else {
|
||||
// create a Source
|
||||
|
||||
let sourceRef: number | undefined;
|
||||
if (resource.query) {
|
||||
const data = Source.getEncodedDebugData(resource);
|
||||
sourceRef = data.sourceReference;
|
||||
}
|
||||
|
||||
rawSource = {
|
||||
path: resource.with({ scheme: '', query: '' }).toString(true), // Remove debug: scheme
|
||||
sourceReference: sourceRef
|
||||
};
|
||||
const data = Source.getEncodedDebugData(resource);
|
||||
rawSource = { path: data.path, sourceReference: data.sourceReference };
|
||||
}
|
||||
|
||||
return this.raw.source({ sourceReference: rawSource.sourceReference || 0, source: rawSource });
|
||||
@@ -537,14 +549,14 @@ export class DebugSession implements IDebugSession {
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number): Promise<CompletionItem[]> {
|
||||
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<CompletionItem[]> {
|
||||
if (this.raw) {
|
||||
return this.raw.completions({
|
||||
frameId,
|
||||
text,
|
||||
column: position.column,
|
||||
line: position.lineNumber
|
||||
}).then(response => {
|
||||
line: position.lineNumber,
|
||||
}, token).then(response => {
|
||||
|
||||
const result: CompletionItem[] = [];
|
||||
if (response && response.body && response.body.targets) {
|
||||
@@ -753,6 +765,16 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
this.rawListeners.push(this.raw.onDidContinued(event => {
|
||||
const threadId = event.body.allThreadsContinued !== false ? undefined : event.body.threadId;
|
||||
if (threadId) {
|
||||
const tokens = this.cancellationMap.get(threadId);
|
||||
this.cancellationMap.delete(threadId);
|
||||
if (tokens) {
|
||||
tokens.forEach(t => t.cancel());
|
||||
}
|
||||
} else {
|
||||
this.cancelAllRequests();
|
||||
}
|
||||
|
||||
this.model.clearThreads(this.getId(), false, threadId);
|
||||
this._onDidChangeState.fire();
|
||||
}));
|
||||
@@ -783,7 +805,7 @@ export class DebugSession implements IDebugSession {
|
||||
source: this.getSource(event.body.source)
|
||||
} : undefined;
|
||||
if (event.body.variablesReference) {
|
||||
const container = new ExpressionContainer(this, event.body.variablesReference, generateUuid());
|
||||
const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid());
|
||||
outpuPromises.push(container.getChildren().then(children => {
|
||||
return Promise.all(waitFor).then(() => children.forEach(child => {
|
||||
// Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names)
|
||||
@@ -799,8 +821,8 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
this.rawListeners.push(this.raw.onDidBreakpoint(event => {
|
||||
const id = event.body && event.body.breakpoint ? event.body.breakpoint.id : undefined;
|
||||
const breakpoint = this.model.getBreakpoints().filter(bp => bp.idFromAdapter === id).pop();
|
||||
const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.idFromAdapter === id).pop();
|
||||
const breakpoint = this.model.getBreakpoints().filter(bp => bp.getIdFromAdapter(this.getId()) === id).pop();
|
||||
const functionBreakpoint = this.model.getFunctionBreakpoints().filter(bp => bp.getIdFromAdapter(this.getId()) === id).pop();
|
||||
|
||||
if (event.body.reason === 'new' && event.body.breakpoint.source && event.body.breakpoint.line) {
|
||||
const source = this.getSource(event.body.breakpoint.source);
|
||||
@@ -860,6 +882,7 @@ export class DebugSession implements IDebugSession {
|
||||
dispose(this.rawListeners);
|
||||
if (this.raw) {
|
||||
this.raw.disconnect();
|
||||
this.raw.dispose();
|
||||
}
|
||||
this.raw = undefined;
|
||||
this.model.clearThreads(this.getId(), true);
|
||||
@@ -891,6 +914,20 @@ export class DebugSession implements IDebugSession {
|
||||
return source;
|
||||
}
|
||||
|
||||
private getNewCancellationToken(threadId: number): CancellationToken {
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const tokens = this.cancellationMap.get(threadId) || [];
|
||||
tokens.push(tokenSource);
|
||||
this.cancellationMap.set(threadId, tokens);
|
||||
|
||||
return tokenSource.token;
|
||||
}
|
||||
|
||||
private cancelAllRequests(): void {
|
||||
this.cancellationMap.forEach(tokens => tokens.forEach(t => t.cancel()));
|
||||
this.cancellationMap.clear();
|
||||
}
|
||||
|
||||
private getUriKey(uri: URI): string {
|
||||
// TODO: the following code does not make sense if uri originates from a different platform
|
||||
return platform.isLinux ? uri.toString() : uri.toString().toLowerCase();
|
||||
@@ -908,11 +945,11 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
|
||||
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
const viewModel = this.debugService.getViewModel();
|
||||
await this.repl.addReplExpression(stackFrame, name);
|
||||
const expressionEvaluated = this.repl.addReplExpression(stackFrame, name);
|
||||
this._onDidChangeREPLElements.fire();
|
||||
await expressionEvaluated;
|
||||
this._onDidChangeREPLElements.fire();
|
||||
// Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some.
|
||||
this.debugService.focusStackFrame(viewModel.focusedStackFrame, viewModel.focusedThread, viewModel.focusedSession);
|
||||
variableSetEmitter.fire();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
const $ = dom.$;
|
||||
|
||||
// theming
|
||||
@@ -62,7 +63,7 @@ export class ExceptionWidget extends ZoneWidget {
|
||||
protected _fillContainer(container: HTMLElement): void {
|
||||
this.setCssClass('exception-widget');
|
||||
// Set the font size and line height to the one from the editor configuration.
|
||||
const fontInfo = this.editor.getConfiguration().fontInfo;
|
||||
const fontInfo = this.editor.getOption(EditorOption.fontInfo);
|
||||
container.style.fontSize = `${fontInfo.fontSize}px`;
|
||||
container.style.lineHeight = `${fontInfo.lineHeight}px`;
|
||||
|
||||
@@ -89,7 +90,7 @@ export class ExceptionWidget extends ZoneWidget {
|
||||
// Reload the height with respect to the exception text content and relayout it to match the line count.
|
||||
this.container!.style.height = 'initial';
|
||||
|
||||
const lineHeight = this.editor.getConfiguration().lineHeight;
|
||||
const lineHeight = this.editor.getOption(EditorOption.lineHeight);
|
||||
const arrowHeight = Math.round(lineHeight / 3);
|
||||
const computedLinesNumber = Math.ceil((this.container!.offsetHeight + arrowHeight) / lineHeight);
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ import { IEnvironmentService } 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';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
|
||||
@@ -22,11 +23,16 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
) {
|
||||
const connection = remoteAgentService.getConnection();
|
||||
|
||||
if (!connection) {
|
||||
throw new Error('Missing agent connection');
|
||||
let channel: IChannel;
|
||||
if (connection) {
|
||||
channel = connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName);
|
||||
} else {
|
||||
channel = { call: async () => undefined, listen: () => Event.None } as any;
|
||||
// TODO@weinand TODO@isidorn fallback?
|
||||
console.warn('Extension Host Debugging not available due to missing connection.');
|
||||
}
|
||||
|
||||
super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
|
||||
super(channel);
|
||||
|
||||
this._register(this.onReload(event => {
|
||||
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||
@@ -45,7 +51,7 @@ registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService);
|
||||
|
||||
class BrowserDebugHelperService implements IDebugHelperService {
|
||||
|
||||
_serviceBrand!: ServiceIdentifier<IDebugHelperService>;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
|
||||
return undefined;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { URI as uri } from 'vs/base/common/uri';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export class LinkDetector {
|
||||
private static readonly MAX_LENGTH = 500;
|
||||
@@ -87,11 +87,13 @@ export class LinkDetector {
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.textContent = line.substr(match.index, match[0].length);
|
||||
link.title = isMacintosh ? nls.localize('fileLinkMac', "Click to follow (Cmd + click opens to the side)") : nls.localize('fileLink', "Click to follow (Ctrl + click opens to the side)");
|
||||
link.title = isMacintosh ? nls.localize('fileLinkMac', "Cmd + click to follow link") : nls.localize('fileLink', "Ctrl + click to follow link");
|
||||
lineContainer.appendChild(link);
|
||||
const lineNumber = Number(match[3]);
|
||||
const columnNumber = match[4] ? Number(match[4]) : undefined;
|
||||
link.onclick = (e) => this.onLinkClick(new StandardMouseEvent(e), resource!, lineNumber, columnNumber);
|
||||
link.onmousemove = (event) => link.classList.toggle('pointer', isMacintosh ? event.metaKey : event.ctrlKey);
|
||||
link.onmouseleave = () => link.classList.remove('pointer');
|
||||
|
||||
lastMatchIndex = pattern.lastIndex;
|
||||
const currentMatch = match;
|
||||
@@ -141,9 +143,11 @@ export class LinkDetector {
|
||||
if (!selection || selection.type === 'Range') {
|
||||
return; // do not navigate when user is selecting
|
||||
}
|
||||
if (!(isMacintosh ? event.metaKey : event.ctrlKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
const group = event.ctrlKey || event.metaKey ? SIDE_GROUP : ACTIVE_GROUP;
|
||||
|
||||
this.editorService.openEditor({
|
||||
resource,
|
||||
@@ -153,6 +157,6 @@ export class LinkDetector {
|
||||
startColumn: column
|
||||
}
|
||||
}
|
||||
}, group);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
|
||||
this._register(this.treeLabels);
|
||||
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new LoadedScriptsDelegate(),
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(),
|
||||
[new LoadedScriptsRenderer(this.treeLabels)],
|
||||
new LoadedScriptsDataSource(),
|
||||
{
|
||||
@@ -466,7 +466,21 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
}
|
||||
}));
|
||||
|
||||
const registerLoadedSourceListener = (session: IDebugSession) => {
|
||||
const scheduleRefreshOnVisible = () => {
|
||||
if (this.isBodyVisible()) {
|
||||
this.changeScheduler.schedule();
|
||||
} else {
|
||||
this.treeNeedsRefreshOnVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
const registerSessionListeners = (session: IDebugSession) => {
|
||||
this._register(session.onDidChangeName(() => {
|
||||
// Re-add session, this will trigger proper sorting and id recalculation.
|
||||
root.remove(session.getId());
|
||||
root.add(session);
|
||||
scheduleRefreshOnVisible();
|
||||
}));
|
||||
this._register(session.onDidLoadedSource(event => {
|
||||
let sessionRoot: SessionTreeItem;
|
||||
switch (event.reason) {
|
||||
@@ -474,11 +488,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
case 'changed':
|
||||
sessionRoot = root.add(session);
|
||||
sessionRoot.addPath(event.source);
|
||||
if (this.isBodyVisible()) {
|
||||
this.changeScheduler.schedule();
|
||||
} else {
|
||||
this.treeNeedsRefreshOnVisible = true;
|
||||
}
|
||||
scheduleRefreshOnVisible();
|
||||
if (event.reason === 'changed') {
|
||||
DebugContentProvider.refreshDebugContent(event.source.uri);
|
||||
}
|
||||
@@ -486,11 +496,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
case 'removed':
|
||||
sessionRoot = root.find(session);
|
||||
if (sessionRoot && sessionRoot.removePath(event.source)) {
|
||||
if (this.isBodyVisible()) {
|
||||
this.changeScheduler.schedule();
|
||||
} else {
|
||||
this.treeNeedsRefreshOnVisible = true;
|
||||
}
|
||||
scheduleRefreshOnVisible();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -501,8 +507,8 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
}));
|
||||
};
|
||||
|
||||
this._register(this.debugService.onDidNewSession(registerLoadedSourceListener));
|
||||
this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener);
|
||||
this._register(this.debugService.onDidNewSession(registerSessionListeners));
|
||||
this.debugService.getModel().getSessions().forEach(registerSessionListeners);
|
||||
|
||||
this._register(this.debugService.onDidEndSession(session => {
|
||||
root.remove(session.getId());
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C4 5.79086 5.79086 4 8 4C10.2091 4 12 5.79086 12 8C12 10.2091 10.2091 12 8 12C5.79086 12 4 10.2091 4 8ZM6 10L6 9L10 9L10 10L6 10ZM6 6L6 7L10 7L10 6L6 6Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 327 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 10.75C9.51878 10.75 10.75 9.51878 10.75 8C10.75 6.48122 9.51878 5.25 8 5.25C6.48122 5.25 5.25 6.48122 5.25 8C5.25 9.51878 6.48122 10.75 8 10.75ZM8 12C10.2091 12 12 10.2091 12 8C12 5.79086 10.2091 4 8 4C5.79086 4 4 5.79086 4 8C4 10.2091 5.79086 12 8 12ZM9.5 6.5V7.5H6.5V6.5H9.5ZM9.5 9.5V8.5H6.5V9.5H9.5Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 476 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2376 8L9.9282 12H5.3094L3 8L5.3094 4H9.9282L12.2376 8Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 189 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.487 8L9.55293 11.35H5.68468L3.75056 8L5.68468 4.65H9.55293L11.487 8Z" stroke="#848484" stroke-width="1.3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 224 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2376 8L9.9282 12H5.3094L3 8L5.3094 4H9.9282L12.2376 8Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 189 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 2H4V2.24001L4 14L2.5 14L2.5 2ZM6 2.18094V14L15 8.06218L6 2.18094ZM12.3148 8.06218L7.50024 5L7.50024 11.1809L12.3148 8.06218Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 300 B |
@@ -62,6 +62,18 @@
|
||||
background: url('breakpoint-function-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint {
|
||||
background: url('breakpoint-data.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint-unverified {
|
||||
background: url('breakpoint-data-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint-disabled {
|
||||
background: url('breakpoint-data-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-conditional,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before {
|
||||
background: url('breakpoint-conditional.svg') center center no-repeat;
|
||||
@@ -135,6 +147,16 @@
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .value a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .value a.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* White color when element is selected and list is focused. White looks better on blue selection background. */
|
||||
.monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .name,
|
||||
.monaco-workbench .monaco-list:focus .monaco-list-row.selected .expression .value {
|
||||
|
||||
@@ -179,6 +179,27 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .thread:hover > .state,
|
||||
.debug-viewlet .debug-call-stack .session:hover > .state,
|
||||
.debug-viewlet .debug-call-stack .monaco-list-row.focused .state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list-row .monaco-action-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list-row.focused .monaco-action-bar,
|
||||
.debug-viewlet .debug-call-stack .monaco-list-row:hover .monaco-action-bar {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-viewlet .debug-call-stack .monaco-action-bar .action-item > .action-label {
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .thread > .state > .label,
|
||||
.debug-viewlet .debug-call-stack .session > .state > .label {
|
||||
background: rgba(136, 136, 136, 0.3);
|
||||
@@ -257,6 +278,102 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.stop {
|
||||
background: url('stop-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.stop {
|
||||
background: url('stop-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.stop {
|
||||
background: url('stop-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.disconnect {
|
||||
background: url('disconnect-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.disconnect {
|
||||
background: url('disconnect-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.disconnect {
|
||||
background: url('disconnect-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.restart {
|
||||
background: url('restart-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.restart {
|
||||
background: url('restart-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.restart {
|
||||
background: url('restart-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.step-over {
|
||||
background: url('step-over-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-over {
|
||||
background: url('step-over-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-over {
|
||||
background: url('step-over-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.step-into {
|
||||
background: url('step-into-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-into {
|
||||
background: url('step-into-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-into {
|
||||
background: url('step-into-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.step-out {
|
||||
background: url('step-out-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.step-out {
|
||||
background: url('step-out-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.step-out {
|
||||
background: url('step-out-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.pause {
|
||||
background: url('pause-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.pause {
|
||||
background: url('pause-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.pause {
|
||||
background: url('pause-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .debug-action.continue {
|
||||
background: url('continue-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack .debug-action.continue {
|
||||
background: url('continue-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .debug-action.continue {
|
||||
background: url('continue-white.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* Variables & Expression view */
|
||||
|
||||
.debug-viewlet .scope {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.6172 3.84375C13.5169 3.5293 13.3665 3.23991 13.166 2.97559L14.5195 1.61523L13.9043 1L12.5439 2.35352C12.2796 2.15299 11.9902 2.0026 11.6758 1.90234C11.3659 1.79753 11.0446 1.74512 10.7119 1.74512C10.3063 1.74512 9.91439 1.82259 9.53613 1.97754C9.16243 2.13249 8.83203 2.35352 8.54492 2.64062L7 4.19238L11.3271 8.51953L12.8789 6.97461C13.166 6.6875 13.387 6.3571 13.542 5.9834C13.6969 5.60514 13.7744 5.21322 13.7744 4.80762C13.7744 4.47493 13.722 4.15365 13.6172 3.84375ZM12.7285 5.64844C12.6191 5.91276 12.4619 6.14746 12.2568 6.35254L11.3271 7.28223L8.2373 4.19238L9.16699 3.2627C9.37207 3.05762 9.60677 2.90039 9.87109 2.79102C10.14 2.67708 10.4202 2.62012 10.7119 2.62012C11.0127 2.62012 11.2952 2.67936 11.5596 2.79785C11.8239 2.91178 12.054 3.06901 12.25 3.26953C12.4505 3.46549 12.6077 3.69564 12.7217 3.95996C12.8402 4.22428 12.8994 4.50684 12.8994 4.80762C12.8994 5.09928 12.8424 5.37956 12.7285 5.64844ZM7.9043 10.6416L9.3877 9.09668L8.77246 8.47461L7.28223 10.0264L5.42285 8.16699L6.91309 6.61523L6.29102 6L4.80762 7.54492L4.19238 6.92969L2.64062 8.47461C2.35352 8.76172 2.13249 9.0944 1.97754 9.47266C1.82259 9.84635 1.74512 10.236 1.74512 10.6416C1.74512 10.9743 1.79525 11.2979 1.89551 11.6123C2.00033 11.9222 2.15299 12.2093 2.35352 12.4736L1 13.834L1.61523 14.4492L2.97559 13.0957C3.23991 13.2962 3.52702 13.4489 3.83691 13.5537C4.15137 13.654 4.47493 13.7041 4.80762 13.7041C5.21322 13.7041 5.60286 13.6266 5.97656 13.4717C6.35482 13.3167 6.6875 13.0957 6.97461 12.8086L8.51953 11.2568L7.9043 10.6416ZM5.6416 12.665C5.37728 12.7744 5.09928 12.8291 4.80762 12.8291C4.50684 12.8291 4.22201 12.7721 3.95312 12.6582C3.6888 12.5443 3.45638 12.3893 3.25586 12.1934C3.0599 11.9928 2.90495 11.7604 2.79102 11.4961C2.67708 11.2272 2.62012 10.9424 2.62012 10.6416C2.62012 10.3499 2.6748 10.0719 2.78418 9.80762C2.89811 9.53874 3.05762 9.30176 3.2627 9.09668L4.19238 8.16699L7.28223 11.2568L6.35254 12.1865C6.14746 12.3916 5.91048 12.5511 5.6416 12.665Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.5 3L6 3V13H4.5V3ZM11.5 3V13H10V3L11.5 3Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 174 B |
@@ -48,11 +48,13 @@
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression > .value {
|
||||
.repl .repl-tree .output.expression > .value,
|
||||
.repl .repl-tree .evaluation-result.expression > .value {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression > .annotation {
|
||||
.repl .repl-tree .output.expression > .annotation,
|
||||
.repl .repl-tree .evaluation-result.expression > .annotation {
|
||||
font-size: inherit;
|
||||
padding-left: 6px;
|
||||
}
|
||||
@@ -67,7 +69,7 @@
|
||||
}
|
||||
|
||||
/* Only show 'stale expansion' info when the element gets expanded. */
|
||||
.repl .repl-tree .input-output-pair > .output > .annotation::before {
|
||||
.repl .repl-tree .evaluation-result > .annotation::before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
@@ -132,9 +134,3 @@
|
||||
.monaco-workbench .repl .repl-tree .output.expression .code-bold { font-weight: bold; }
|
||||
.monaco-workbench .repl .repl-tree .output.expression .code-italic { font-style: italic; }
|
||||
.monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; }
|
||||
|
||||
/* Links */
|
||||
.monaco-workbench .repl .repl-tree .output.expression a {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.75 8C12.75 10.4853 10.7353 12.5 8.24999 12.5C6.41795 12.5 4.84162 11.4052 4.13953 9.83416L2.74882 10.399C3.67446 12.5186 5.78923 14 8.24999 14C11.5637 14 14.25 11.3137 14.25 8C14.25 4.68629 11.5637 2 8.24999 2C6.3169 2 4.59732 2.91418 3.5 4.3338V2.5H2V6.5L2.75 7.25H6.25V5.75H4.35201C5.13008 4.40495 6.58436 3.5 8.24999 3.5C10.7353 3.5 12.75 5.51472 12.75 8Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 533 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 9.532H8.54201L12.447 5.627L11.386 4.567L8.74901 7.177L8.74901 1H8.00001H7.25101L7.25101 7.177L4.61401 4.567L3.55301 5.627L7.45801 9.532H8.00001ZM9.95601 13.013C9.95601 14.1176 9.06058 15.013 7.95601 15.013C6.85144 15.013 5.95601 14.1176 5.95601 13.013C5.95601 11.9084 6.85144 11.013 7.95601 11.013C9.06058 11.013 9.95601 11.9084 9.95601 13.013Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 524 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 1H7.45801L3.55301 4.905L4.61401 5.965L7.25101 3.355V9.532H8.00001H8.74901V3.355L11.386 5.965L12.447 4.905L8.54201 1H8.00001ZM9.95601 13.013C9.95601 14.1176 9.06058 15.013 7.95601 15.013C6.85144 15.013 5.95601 14.1176 5.95601 13.013C5.95601 11.9084 6.85144 11.013 7.95601 11.013C9.06058 11.013 9.95601 11.9084 9.95601 13.013Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.25 5.75V1.75H12.75V4.2916C11.605 2.93303 9.83901 2.08334 7.90917 2.08334C4.73318 2.08334 1.98943 4.39036 1.75074 7.48075L1.72994 7.75H3.23102L3.2529 7.5241C3.46544 5.32932 5.45511 3.58334 7.90917 3.58334C9.64522 3.58334 11.1528 4.45925 11.9587 5.75H9.12988V7.25H13.292L14.2535 6.27493V5.75H14.25ZM8 14C9.10457 14 10 13.1046 10 12C10 10.8954 9.10457 10 8 10C6.89543 10 6 10.8954 6 12C6 13.1046 6.89543 14 8 14Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 584 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2.625" y="2.625" width="10.75" height="10.75" stroke="#FFFFFF" stroke-width="1.25"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 197 B |
@@ -18,6 +18,8 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { env as processEnv } from 'vs/base/common/process';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
/**
|
||||
* This interface represents a single command line argument split into a "prefix" and a "path" half.
|
||||
@@ -37,7 +39,7 @@ interface ILaunchVSCodeArguments {
|
||||
/**
|
||||
* Encapsulates the DebugAdapter lifecycle and some idiosyncrasies of the Debug Adapter Protocol.
|
||||
*/
|
||||
export class RawDebugSession {
|
||||
export class RawDebugSession implements IDisposable {
|
||||
|
||||
private allThreadsContinued = true;
|
||||
private _readyForBreakpoints = false;
|
||||
@@ -70,6 +72,8 @@ export class RawDebugSession {
|
||||
private readonly _onDidExitAdapter: Emitter<AdapterEndEvent>;
|
||||
private debugAdapter: IDebugAdapter | null;
|
||||
|
||||
private toDispose: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
debugAdapter: IDebugAdapter,
|
||||
dbgr: IDebugger,
|
||||
@@ -96,18 +100,18 @@ export class RawDebugSession {
|
||||
|
||||
this._onDidExitAdapter = new Emitter<AdapterEndEvent>();
|
||||
|
||||
this.debugAdapter.onError(err => {
|
||||
this.toDispose.push(this.debugAdapter.onError(err => {
|
||||
this.shutdown(err);
|
||||
});
|
||||
}));
|
||||
|
||||
this.debugAdapter.onExit(code => {
|
||||
this.toDispose.push(this.debugAdapter.onExit(code => {
|
||||
if (code !== 0) {
|
||||
this.shutdown(new Error(`exit code: ${code}`));
|
||||
} else {
|
||||
// normal exit
|
||||
this.shutdown();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this.debugAdapter.onEvent(event => {
|
||||
switch (event.event) {
|
||||
@@ -341,9 +345,9 @@ export class RawDebugSession {
|
||||
return Promise.reject(new Error('restartFrame not supported'));
|
||||
}
|
||||
|
||||
completions(args: DebugProtocol.CompletionsArguments): Promise<DebugProtocol.CompletionsResponse> {
|
||||
completions(args: DebugProtocol.CompletionsArguments, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse> {
|
||||
if (this.capabilities.supportsCompletionsRequest) {
|
||||
return this.send<DebugProtocol.CompletionsResponse>('completions', args);
|
||||
return this.send<DebugProtocol.CompletionsResponse>('completions', args, token);
|
||||
}
|
||||
return Promise.reject(new Error('completions not supported'));
|
||||
}
|
||||
@@ -384,8 +388,8 @@ export class RawDebugSession {
|
||||
return Promise.reject(new Error('configurationDone not supported'));
|
||||
}
|
||||
|
||||
stackTrace(args: DebugProtocol.StackTraceArguments): Promise<DebugProtocol.StackTraceResponse> {
|
||||
return this.send<DebugProtocol.StackTraceResponse>('stackTrace', args);
|
||||
stackTrace(args: DebugProtocol.StackTraceArguments, token: CancellationToken): Promise<DebugProtocol.StackTraceResponse> {
|
||||
return this.send<DebugProtocol.StackTraceResponse>('stackTrace', args, token);
|
||||
}
|
||||
|
||||
exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise<DebugProtocol.ExceptionInfoResponse> {
|
||||
@@ -395,12 +399,12 @@ export class RawDebugSession {
|
||||
return Promise.reject(new Error('exceptionInfo not supported'));
|
||||
}
|
||||
|
||||
scopes(args: DebugProtocol.ScopesArguments): Promise<DebugProtocol.ScopesResponse> {
|
||||
return this.send<DebugProtocol.ScopesResponse>('scopes', args);
|
||||
scopes(args: DebugProtocol.ScopesArguments, token: CancellationToken): Promise<DebugProtocol.ScopesResponse> {
|
||||
return this.send<DebugProtocol.ScopesResponse>('scopes', args, token);
|
||||
}
|
||||
|
||||
variables(args: DebugProtocol.VariablesArguments): Promise<DebugProtocol.VariablesResponse> {
|
||||
return this.send<DebugProtocol.VariablesResponse>('variables', args);
|
||||
variables(args: DebugProtocol.VariablesArguments, token?: CancellationToken): Promise<DebugProtocol.VariablesResponse> {
|
||||
return this.send<DebugProtocol.VariablesResponse>('variables', args, token);
|
||||
}
|
||||
|
||||
source(args: DebugProtocol.SourceArguments): Promise<DebugProtocol.SourceResponse> {
|
||||
@@ -463,18 +467,21 @@ export class RawDebugSession {
|
||||
return Promise.reject(new Error('goto is not supported'));
|
||||
}
|
||||
|
||||
cancel(args: DebugProtocol.CancelArguments): Promise<DebugProtocol.CancelResponse> {
|
||||
return this.send('cancel', args);
|
||||
}
|
||||
|
||||
custom(request: string, args: any): Promise<DebugProtocol.Response> {
|
||||
return this.send(request, args);
|
||||
}
|
||||
|
||||
//---- private
|
||||
|
||||
|
||||
private shutdown(error?: Error, restart = false): Promise<any> {
|
||||
if (!this.inShutdown) {
|
||||
this.inShutdown = true;
|
||||
if (this.debugAdapter) {
|
||||
return this.send('disconnect', { restart }, 500).then(() => {
|
||||
return this.send('disconnect', { restart }, undefined, 500).then(() => {
|
||||
this.stopAdapter(error);
|
||||
}, () => {
|
||||
// ignore error
|
||||
@@ -583,15 +590,17 @@ export class RawDebugSession {
|
||||
|
||||
const v = args[key];
|
||||
if (v) {
|
||||
if (Array.isArray(v)) {
|
||||
v.push(value);
|
||||
} else {
|
||||
args[key] = [v, value];
|
||||
}
|
||||
v.push(value);
|
||||
} else {
|
||||
args[key] = value;
|
||||
args[key] = [value];
|
||||
}
|
||||
} else if (key === 'extensionDevelopmentPath') {
|
||||
const v = args[key];
|
||||
if (v) {
|
||||
v.push(value);
|
||||
} else {
|
||||
args[key] = [value];
|
||||
}
|
||||
|
||||
} else {
|
||||
(<any>args)[key] = value;
|
||||
}
|
||||
@@ -619,20 +628,34 @@ export class RawDebugSession {
|
||||
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
|
||||
}
|
||||
|
||||
private send<R extends DebugProtocol.Response>(command: string, args: any, timeout?: number): Promise<R> {
|
||||
private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> {
|
||||
return new Promise<R>((completeDispatch, errorDispatch) => {
|
||||
if (!this.debugAdapter) {
|
||||
errorDispatch(new Error('no debug adapter found'));
|
||||
return;
|
||||
}
|
||||
this.debugAdapter.sendRequest(command, args, (response: R) => {
|
||||
let cancelationListener: IDisposable;
|
||||
const requestId = this.debugAdapter.sendRequest(command, args, (response: R) => {
|
||||
if (cancelationListener) {
|
||||
cancelationListener.dispose();
|
||||
}
|
||||
|
||||
if (response.success) {
|
||||
completeDispatch(response);
|
||||
} else {
|
||||
errorDispatch(response);
|
||||
}
|
||||
}, timeout);
|
||||
}).then(response => response, err => Promise.reject(this.handleErrorResponse(err)));
|
||||
|
||||
if (token) {
|
||||
cancelationListener = token.onCancellationRequested(() => {
|
||||
cancelationListener.dispose();
|
||||
if (this.capabilities.supportsCancelRequest) {
|
||||
this.cancel({ requestId });
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(undefined, err => Promise.reject(this.handleErrorResponse(err)));
|
||||
}
|
||||
|
||||
private handleErrorResponse(errorResponse: DebugProtocol.Response): Error {
|
||||
@@ -696,4 +719,8 @@ export class RawDebugSession {
|
||||
this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage });
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,25 +44,25 @@ import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'v
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Variable, Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { renderExpressionValue, AbstractExpressionsRenderer, IExpressionTemplateData, renderVariable, IInputBoxOptions } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { removeAnsiEscapeCodes } from 'vs/base/common/strings';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -71,7 +71,7 @@ const IPrivateReplService = createDecorator<IPrivateReplService>('privateReplSer
|
||||
const DECORATION_KEY = 'replinputdecoration';
|
||||
|
||||
interface IPrivateReplService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
acceptReplInput(): void;
|
||||
getVisibleContent(): string;
|
||||
selectSession(session?: IDebugSession): void;
|
||||
@@ -85,7 +85,7 @@ function revealLastElement(tree: WorkbenchAsyncDataTree<any, any, any>) {
|
||||
|
||||
const sessionsToIgnore = new Set<IDebugSession>();
|
||||
export class Repl extends Panel implements IPrivateReplService, IHistoryNavigationWidget {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private static readonly REFRESH_DELAY = 100; // delay in ms to refresh the repl for new elements to show
|
||||
private static readonly REPL_INPUT_INITIAL_HEIGHT = 19;
|
||||
@@ -149,7 +149,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
const text = model.getLineContent(position.lineNumber);
|
||||
const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
const frameId = focusedStackFrame ? focusedStackFrame.frameId : undefined;
|
||||
const suggestions = await session.completions(frameId, text, position, overwriteBefore);
|
||||
const suggestions = await session.completions(frameId, text, position, overwriteBefore, token);
|
||||
return { suggestions };
|
||||
}
|
||||
|
||||
@@ -404,15 +404,18 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
this.replDelegate = new ReplDelegate(this.configurationService);
|
||||
const wordWrap = this.configurationService.getValue<IDebugConfiguration>('debug').console.wordWrap;
|
||||
dom.toggleClass(treeContainer, 'word-wrap', wordWrap);
|
||||
const linkDetector = this.instantiationService.createInstance(LinkDetector);
|
||||
this.tree = this.instantiationService.createInstance(
|
||||
WorkbenchAsyncDataTree,
|
||||
'DebugRepl',
|
||||
treeContainer,
|
||||
this.replDelegate,
|
||||
[
|
||||
this.instantiationService.createInstance(VariablesRenderer),
|
||||
this.instantiationService.createInstance(ReplSimpleElementsRenderer),
|
||||
new ReplExpressionsRenderer(),
|
||||
new ReplRawObjectsRenderer()
|
||||
this.instantiationService.createInstance(ReplVariablesRenderer, linkDetector),
|
||||
this.instantiationService.createInstance(ReplSimpleElementsRenderer, linkDetector),
|
||||
new ReplEvaluationInputsRenderer(),
|
||||
new ReplEvaluationResultsRenderer(linkDetector),
|
||||
new ReplRawObjectsRenderer(linkDetector),
|
||||
],
|
||||
// https://github.com/microsoft/TypeScript/issues/32526
|
||||
new ReplDataSource() as IAsyncDataSource<IDebugSession, IReplElement>,
|
||||
@@ -444,7 +447,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
|
||||
private createReplInput(container: HTMLElement): void {
|
||||
this.replInputContainer = dom.append(container, $('.repl-input-wrapper'));
|
||||
this.replInputContainer.title = nls.localize('debugConsole', "Debug Console");
|
||||
|
||||
const { scopedContextKeyService, historyNavigationEnablement } = createAndBindHistoryNavigationWidgetScopedContextKeyService(this.contextKeyService, { target: this.replInputContainer, historyNavigator: this });
|
||||
this.historyNavigationEnablement = historyNavigationEnablement;
|
||||
@@ -455,6 +457,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
[IContextKeyService, scopedContextKeyService], [IPrivateReplService, this]));
|
||||
const options = getSimpleEditorOptions();
|
||||
options.readOnly = true;
|
||||
options.ariaLabel = nls.localize('debugConsole', "Debug Console");
|
||||
|
||||
this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions());
|
||||
|
||||
this._register(this.replInput.onDidScrollChange(e => {
|
||||
@@ -566,12 +570,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
|
||||
// Repl tree
|
||||
|
||||
interface IExpressionTemplateData {
|
||||
input: HTMLElement;
|
||||
output: HTMLElement;
|
||||
interface IReplEvaluationInputTemplateData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
interface IReplEvaluationResultTemplateData {
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
interface ISimpleReplElementTemplateData {
|
||||
@@ -591,31 +596,53 @@ interface IRawObjectReplTemplateData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
class ReplExpressionsRenderer implements ITreeRenderer<Expression, FuzzyScore, IExpressionTemplateData> {
|
||||
static readonly ID = 'expressionRepl';
|
||||
class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluationInput, FuzzyScore, IReplEvaluationInputTemplateData> {
|
||||
static readonly ID = 'replEvaluationInput';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplExpressionsRenderer.ID;
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IExpressionTemplateData {
|
||||
dom.addClass(container, 'input-output-pair');
|
||||
const input = dom.append(container, $('.input.expression'));
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
|
||||
const input = dom.append(container, $('.expression'));
|
||||
const label = new HighlightedLabel(input, false);
|
||||
const output = dom.append(container, $('.output.expression'));
|
||||
return { label };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationInput, FuzzyScore>, index: number, templateData: IReplEvaluationInputTemplateData): void {
|
||||
const evaluation = element.element;
|
||||
templateData.label.set(evaluation.value, createMatches(element.filterData));
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationInputTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluationResult, FuzzyScore, IReplEvaluationResultTemplateData> {
|
||||
static readonly ID = 'replEvaluationResult';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData {
|
||||
const output = dom.append(container, $('.evaluation-result.expression'));
|
||||
const value = dom.append(output, $('span.value'));
|
||||
const annotation = dom.append(output, $('span'));
|
||||
|
||||
return { input, label, output, value, annotation };
|
||||
return { value, annotation };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<Expression, FuzzyScore>, index: number, templateData: IExpressionTemplateData): void {
|
||||
renderElement(element: ITreeNode<ReplEvaluationResult, FuzzyScore>, index: number, templateData: IReplEvaluationResultTemplateData): void {
|
||||
const expression = element.element;
|
||||
templateData.label.set(expression.name, createMatches(element.filterData));
|
||||
renderExpressionValue(expression, templateData.value, {
|
||||
preserveWhitespace: !expression.hasChildren,
|
||||
showHover: false,
|
||||
colorize: true
|
||||
colorize: true,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
if (expression.hasChildren) {
|
||||
templateData.annotation.className = 'annotation octicon octicon-info';
|
||||
@@ -623,7 +650,7 @@ class ReplExpressionsRenderer implements ITreeRenderer<Expression, FuzzyScore, I
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IExpressionTemplateData): void {
|
||||
disposeTemplate(templateData: IReplEvaluationResultTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@@ -632,9 +659,9 @@ class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, Fuz
|
||||
static readonly ID = 'simpleReplElement';
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
) { }
|
||||
|
||||
@@ -642,11 +669,6 @@ class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, Fuz
|
||||
return ReplSimpleElementsRenderer.ID;
|
||||
}
|
||||
|
||||
@memoize
|
||||
get linkDetector(): LinkDetector {
|
||||
return this.instantiationService.createInstance(LinkDetector);
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): ISimpleReplElementTemplateData {
|
||||
const data: ISimpleReplElementTemplateData = Object.create(null);
|
||||
dom.addClass(container, 'output');
|
||||
@@ -692,9 +714,37 @@ class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, Fuz
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
|
||||
|
||||
static readonly ID = 'replVariable';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
) {
|
||||
super(debugService, contextViewService, themeService);
|
||||
}
|
||||
|
||||
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
|
||||
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
|
||||
}
|
||||
|
||||
protected getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElement, FuzzyScore, IRawObjectReplTemplateData> {
|
||||
static readonly ID = 'rawObject';
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ReplRawObjectsRenderer.ID;
|
||||
}
|
||||
@@ -724,7 +774,8 @@ class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElement, Fuzz
|
||||
// value
|
||||
renderExpressionValue(element.value, templateData.value, {
|
||||
preserveWhitespace: true,
|
||||
showHover: false
|
||||
showHover: false,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
|
||||
// annotation if any
|
||||
@@ -755,24 +806,23 @@ class ReplDelegate implements IListVirtualDelegate<IReplElement> {
|
||||
const rowHeight = Math.ceil(1.4 * fontSize);
|
||||
const wordWrap = config.console.wordWrap;
|
||||
if (!wordWrap) {
|
||||
return element instanceof Expression ? 2 * rowHeight : rowHeight;
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
// In order to keep scroll position we need to give a good approximation to the tree
|
||||
// For every 150 characters increase the number of lines needed
|
||||
if (element instanceof Expression) {
|
||||
let { name, value } = element;
|
||||
let nameRows = countNumberOfLines(name) + Math.floor(name.length / 150);
|
||||
if (element instanceof ReplEvaluationResult) {
|
||||
let value = element.value;
|
||||
|
||||
if (element.hasChildren) {
|
||||
return (nameRows + 1) * rowHeight;
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
let valueRows = value ? (countNumberOfLines(value) + Math.floor(value.length / 150)) : 0;
|
||||
return rowHeight * (nameRows + valueRows);
|
||||
return rowHeight * valueRows;
|
||||
}
|
||||
|
||||
if (element instanceof SimpleReplElement) {
|
||||
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput) {
|
||||
let value = element.value;
|
||||
let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150);
|
||||
|
||||
@@ -784,10 +834,13 @@ class ReplDelegate implements IListVirtualDelegate<IReplElement> {
|
||||
|
||||
getTemplateId(element: IReplElement): string {
|
||||
if (element instanceof Variable && element.name) {
|
||||
return VariablesRenderer.ID;
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
if (element instanceof Expression) {
|
||||
return ReplExpressionsRenderer.ID;
|
||||
if (element instanceof ReplEvaluationResult) {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
if (element instanceof ReplEvaluationInput) {
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) {
|
||||
// Variable with no name is a top level variable which should be rendered like a repl element #17404
|
||||
@@ -834,10 +887,7 @@ class ReplAccessibilityProvider implements IAccessibilityProvider<IReplElement>
|
||||
if (element instanceof Variable) {
|
||||
return nls.localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
if (element instanceof Expression) {
|
||||
return nls.localize('replExpressionAriaLabel', "Expression {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
if (element instanceof SimpleReplElement) {
|
||||
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
|
||||
return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value);
|
||||
}
|
||||
if (element instanceof RawObjectReplElement) {
|
||||
|
||||
@@ -70,9 +70,13 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri
|
||||
|
||||
// Border Color
|
||||
const borderColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_DEBUGGING_BORDER, STATUS_BAR_BORDER)) || this.getColor(contrastBorder);
|
||||
container.style.borderTopWidth = borderColor ? '1px' : null;
|
||||
container.style.borderTopStyle = borderColor ? 'solid' : null;
|
||||
container.style.borderTopColor = borderColor;
|
||||
if (borderColor) {
|
||||
addClass(container, 'status-border-top');
|
||||
container.style.setProperty('--status-border-top-color', borderColor.toString());
|
||||
} else {
|
||||
removeClass(container, 'status-border-top');
|
||||
container.style.removeProperty('--status-border-top-color');
|
||||
}
|
||||
|
||||
// Notification Beak
|
||||
if (!this.styleElement) {
|
||||
|
||||
@@ -86,14 +86,14 @@ export class VariablesView extends ViewletPanel {
|
||||
dom.addClass(container, 'debug-variables');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new VariablesDelegate(),
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'VariablesView', treeContainer, new VariablesDelegate(),
|
||||
[this.instantiationService.createInstance(VariablesRenderer), new ScopesRenderer()],
|
||||
new VariablesDataSource(), {
|
||||
ariaLabel: nls.localize('variablesAriaTreeLabel', "Debug Variables"),
|
||||
accessibilityProvider: new VariablesAccessibilityProvider(),
|
||||
identityProvider: { getId: (element: IExpression | IScope) => element.getId() },
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e }
|
||||
});
|
||||
ariaLabel: nls.localize('variablesAriaTreeLabel', "Debug Variables"),
|
||||
accessibilityProvider: new VariablesAccessibilityProvider(),
|
||||
identityProvider: { getId: (element: IExpression | IScope) => element.getId() },
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e }
|
||||
});
|
||||
|
||||
this.tree.setInput(this.debugService.getViewModel()).then(null, onUnexpectedError);
|
||||
|
||||
@@ -179,7 +179,7 @@ export class VariablesView extends ViewletPanel {
|
||||
const dataid = response.dataId;
|
||||
if (dataid) {
|
||||
actions.push(new Separator());
|
||||
actions.push(new Action('debug.addDataBreakpoint', nls.localize('setDataBreakpoint', "Set Data Breakpoint"), undefined, true, () => {
|
||||
actions.push(new Action('debug.breakWhenValueChanges', nls.localize('breakWhenValueChanges', "Break When Value Changes"), undefined, true, () => {
|
||||
return this.debugService.addDataBreakpoint(response.description, dataid, !!response.canPersist);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -61,14 +61,14 @@ export class WatchExpressionsView extends ViewletPanel {
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
const expressionsRenderer = this.instantiationService.createInstance(WatchExpressionsRenderer);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)],
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'WatchExpressions', treeContainer, new WatchExpressionsDelegate(), [expressionsRenderer, this.instantiationService.createInstance(VariablesRenderer)],
|
||||
new WatchExpressionsDataSource(), {
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"),
|
||||
accessibilityProvider: new WatchExpressionsAccessibilityProvider(),
|
||||
identityProvider: { getId: (element: IExpression) => element.getId() },
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e },
|
||||
dnd: new WatchExpressionsDragAndDrop(this.debugService),
|
||||
});
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'watchAriaTreeLabel' }, "Debug Watch Expressions"),
|
||||
accessibilityProvider: new WatchExpressionsAccessibilityProvider(),
|
||||
identityProvider: { getId: (element: IExpression) => element.getId() },
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e },
|
||||
dnd: new WatchExpressionsDragAndDrop(this.debugService),
|
||||
});
|
||||
|
||||
this.tree.setInput(this.debugService).then(undefined, onUnexpectedError);
|
||||
CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(this.tree.contextKeyService);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDebugAdapter } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
/**
|
||||
* Abstract implementation of the low level API for a debug adapter.
|
||||
@@ -70,7 +71,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): void {
|
||||
sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): number {
|
||||
const request: any = {
|
||||
command: command
|
||||
};
|
||||
@@ -100,6 +101,8 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
// store callback for this request
|
||||
this.pendingRequests.set(request.seq, clb);
|
||||
}
|
||||
|
||||
return request.seq;
|
||||
}
|
||||
|
||||
acceptMessage(message: DebugProtocol.ProtocolMessage): void {
|
||||
@@ -136,25 +139,33 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
this.sendMessage(message);
|
||||
}
|
||||
|
||||
protected cancelPending() {
|
||||
const pending = this.pendingRequests;
|
||||
this.pendingRequests.clear();
|
||||
setTimeout(_ => {
|
||||
pending.forEach((callback, request_seq) => {
|
||||
const err: DebugProtocol.Response = {
|
||||
type: 'response',
|
||||
seq: 0,
|
||||
request_seq,
|
||||
success: false,
|
||||
command: 'canceled',
|
||||
message: 'canceled'
|
||||
};
|
||||
callback(err);
|
||||
});
|
||||
}, 1000);
|
||||
protected async cancelPendingRequests(): Promise<void> {
|
||||
if (this.pendingRequests.size === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const pending = new Map<number, (e: DebugProtocol.Response) => void>();
|
||||
this.pendingRequests.forEach((value, key) => pending.set(key, value));
|
||||
await timeout(500);
|
||||
pending.forEach((callback, request_seq) => {
|
||||
const err: DebugProtocol.Response = {
|
||||
type: 'response',
|
||||
seq: 0,
|
||||
request_seq,
|
||||
success: false,
|
||||
command: 'canceled',
|
||||
message: 'canceled'
|
||||
};
|
||||
callback(err);
|
||||
this.pendingRequests.delete(request_seq);
|
||||
});
|
||||
}
|
||||
|
||||
getPendingRequestIds(): number[] {
|
||||
return Array.from(this.pendingRequests.keys());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.cancelPending();
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,13 +104,13 @@ export interface IExpressionContainer extends ITreeElement {
|
||||
readonly hasChildren: boolean;
|
||||
getChildren(): Promise<IExpression[]>;
|
||||
readonly reference?: number;
|
||||
readonly value: string;
|
||||
readonly type?: string;
|
||||
valueChanged?: boolean;
|
||||
}
|
||||
|
||||
export interface IExpression extends IReplElement, IExpressionContainer {
|
||||
export interface IExpression extends IExpressionContainer {
|
||||
name: string;
|
||||
readonly value: string;
|
||||
valueChanged?: boolean;
|
||||
readonly type?: string;
|
||||
}
|
||||
|
||||
export interface IDebugger {
|
||||
@@ -157,6 +157,8 @@ export interface IDebugSession extends ITreeElement {
|
||||
|
||||
setSubId(subId: string | undefined): void;
|
||||
|
||||
setName(name: string): void;
|
||||
readonly onDidChangeName: Event<string>;
|
||||
getLabel(): string;
|
||||
|
||||
getSourceForUri(modelUri: uri): Source | undefined;
|
||||
@@ -208,8 +210,8 @@ export interface IDebugSession extends ITreeElement {
|
||||
|
||||
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse>;
|
||||
exceptionInfo(threadId: number): Promise<IExceptionInfo | undefined>;
|
||||
scopes(frameId: number): Promise<DebugProtocol.ScopesResponse>;
|
||||
variables(variablesReference: number, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse>;
|
||||
scopes(frameId: number, threadId: number): Promise<DebugProtocol.ScopesResponse>;
|
||||
variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse>;
|
||||
evaluate(expression: string, frameId?: number, context?: string): Promise<DebugProtocol.EvaluateResponse>;
|
||||
customRequest(request: string, args: any): Promise<DebugProtocol.Response>;
|
||||
|
||||
@@ -223,7 +225,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
pause(threadId: number): Promise<void>;
|
||||
terminateThreads(threadIds: number[]): Promise<void>;
|
||||
|
||||
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number): Promise<CompletionItem[]>;
|
||||
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<CompletionItem[]>;
|
||||
setVariable(variablesReference: number | undefined, name: string, value: string): Promise<DebugProtocol.SetVariableResponse>;
|
||||
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse>;
|
||||
getLoadedSources(): Promise<Source[]>;
|
||||
@@ -308,6 +310,7 @@ export interface IStackFrame extends ITreeElement {
|
||||
restart(): Promise<any>;
|
||||
toString(): string;
|
||||
openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise<ITextEditor | null>;
|
||||
equals(other: IStackFrame): boolean;
|
||||
}
|
||||
|
||||
export interface IEnablement extends ITreeElement {
|
||||
@@ -337,7 +340,7 @@ export interface IBaseBreakpoint extends IEnablement {
|
||||
readonly hitCondition?: string;
|
||||
readonly logMessage?: string;
|
||||
readonly verified: boolean;
|
||||
readonly idFromAdapter: number | undefined;
|
||||
getIdFromAdapter(sessionId: string): number | undefined;
|
||||
}
|
||||
|
||||
export interface IBreakpoint extends IBaseBreakpoint {
|
||||
@@ -452,6 +455,7 @@ export interface IDebugConfiguration {
|
||||
wordWrap: boolean;
|
||||
};
|
||||
focusWindowOnBreak: boolean;
|
||||
onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt';
|
||||
}
|
||||
|
||||
export interface IGlobalConfig {
|
||||
@@ -500,7 +504,7 @@ export interface IDebugAdapter extends IDisposable {
|
||||
startSession(): Promise<void>;
|
||||
sendMessage(message: DebugProtocol.ProtocolMessage): void;
|
||||
sendResponse(response: DebugProtocol.Response): void;
|
||||
sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): void;
|
||||
sendRequest(command: string, args: any, clb: (result: DebugProtocol.Response) => void, timeout?: number): number;
|
||||
stopSession(): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -682,7 +686,7 @@ export interface ILaunch {
|
||||
export const IDebugService = createDecorator<IDebugService>(DEBUG_SERVICE_ID);
|
||||
|
||||
export interface IDebugService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Gets the current debug state.
|
||||
@@ -857,7 +861,7 @@ export const DEBUG_HELPER_SERVICE_ID = 'debugHelperService';
|
||||
export const IDebugHelperService = createDecorator<IDebugHelperService>(DEBUG_HELPER_SERVICE_ID);
|
||||
|
||||
export interface IDebugHelperService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined;
|
||||
}
|
||||
|
||||
@@ -10,13 +10,12 @@ import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { isObject, isString, isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { isString, isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { distinct, lastIndex } from 'vs/base/common/arrays';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import {
|
||||
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel, IReplElementSource,
|
||||
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IReplElement, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint
|
||||
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel,
|
||||
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint
|
||||
} from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { commonSuffixLength } from 'vs/base/common/strings';
|
||||
@@ -25,81 +24,20 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextEditor } from 'vs/workbench/common/editor';
|
||||
|
||||
export class SimpleReplElement implements IReplElement {
|
||||
constructor(
|
||||
private id: string,
|
||||
public value: string,
|
||||
public severity: severity,
|
||||
public sourceData?: IReplElementSource,
|
||||
) { }
|
||||
|
||||
toString(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
export class RawObjectReplElement implements IExpression {
|
||||
|
||||
private static readonly MAX_CHILDREN = 1000; // upper bound of children per value
|
||||
|
||||
constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { }
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
if (this.valueObj === null) {
|
||||
return 'null';
|
||||
} else if (Array.isArray(this.valueObj)) {
|
||||
return `Array[${this.valueObj.length}]`;
|
||||
} else if (isObject(this.valueObj)) {
|
||||
return 'Object';
|
||||
} else if (isString(this.valueObj)) {
|
||||
return `"${this.valueObj}"`;
|
||||
}
|
||||
|
||||
return String(this.valueObj) || '';
|
||||
}
|
||||
|
||||
get hasChildren(): boolean {
|
||||
return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0);
|
||||
}
|
||||
|
||||
getChildren(): Promise<IExpression[]> {
|
||||
let result: IExpression[] = [];
|
||||
if (Array.isArray(this.valueObj)) {
|
||||
result = (<any[]>this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN)
|
||||
.map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v));
|
||||
} else if (isObject(this.valueObj)) {
|
||||
result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN)
|
||||
.map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key]));
|
||||
}
|
||||
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.name}\n${this.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExpressionContainer implements IExpressionContainer {
|
||||
|
||||
public static allValues = new Map<string, string>();
|
||||
// Use chunks to support variable paging #9537
|
||||
private static readonly BASE_CHUNK_SIZE = 100;
|
||||
|
||||
public type: string | undefined;
|
||||
public valueChanged = false;
|
||||
private _value: string = '';
|
||||
protected children?: Promise<IExpression[]>;
|
||||
|
||||
constructor(
|
||||
protected session: IDebugSession | undefined,
|
||||
protected threadId: number | undefined,
|
||||
private _reference: number | undefined,
|
||||
private id: string,
|
||||
public namedVariables: number | undefined = 0,
|
||||
@@ -148,7 +86,7 @@ export class ExpressionContainer implements IExpressionContainer {
|
||||
for (let i = 0; i < numberOfChunks; i++) {
|
||||
const start = (this.startOfVariables || 0) + i * chunkSize;
|
||||
const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize);
|
||||
children.push(new Variable(this.session, this, this.reference, `[${start}..${start + count - 1}]`, '', '', undefined, count, { kind: 'virtual' }, undefined, true, start));
|
||||
children.push(new Variable(this.session, this.threadId, this, this.reference, `[${start}..${start + count - 1}]`, '', '', undefined, count, { kind: 'virtual' }, undefined, true, start));
|
||||
}
|
||||
|
||||
return children;
|
||||
@@ -172,12 +110,12 @@ export class ExpressionContainer implements IExpressionContainer {
|
||||
}
|
||||
|
||||
private fetchVariables(start: number | undefined, count: number | undefined, filter: 'indexed' | 'named' | undefined): Promise<Variable[]> {
|
||||
return this.session!.variables(this.reference || 0, filter, start, count).then(response => {
|
||||
return this.session!.variables(this.reference || 0, this.threadId, filter, start, count).then(response => {
|
||||
return response && response.body && response.body.variables
|
||||
? distinct(response.body.variables.filter(v => !!v && isString(v.name)), (v: DebugProtocol.Variable) => v.name).map((v: DebugProtocol.Variable) =>
|
||||
new Variable(this.session, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.presentationHint, v.type))
|
||||
new Variable(this.session, this.threadId, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.presentationHint, v.type))
|
||||
: [];
|
||||
}, (e: Error) => [new Variable(this.session, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]);
|
||||
}, (e: Error) => [new Variable(this.session, this.threadId, this, 0, e.message, e.message, '', 0, 0, { kind: 'virtual' }, undefined, false)]);
|
||||
}
|
||||
|
||||
// The adapter explicitly sents the children count of an expression only if there are lots of children which should be chunked.
|
||||
@@ -195,16 +133,46 @@ export class ExpressionContainer implements IExpressionContainer {
|
||||
toString(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
async evaluateExpression(
|
||||
expression: string,
|
||||
session: IDebugSession | undefined,
|
||||
stackFrame: IStackFrame | undefined,
|
||||
context: string): Promise<boolean> {
|
||||
|
||||
if (!session || (!stackFrame && context !== 'repl')) {
|
||||
this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE;
|
||||
this.reference = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.session = session;
|
||||
try {
|
||||
const response = await session.evaluate(expression, stackFrame ? stackFrame.frameId : undefined, context);
|
||||
if (response && response.body) {
|
||||
this.value = response.body.result || '';
|
||||
this.reference = response.body.variablesReference;
|
||||
this.namedVariables = response.body.namedVariables;
|
||||
this.indexedVariables = response.body.indexedVariables;
|
||||
this.type = response.body.type || this.type;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
this.value = e.message || '';
|
||||
this.reference = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Expression extends ExpressionContainer implements IExpression {
|
||||
static DEFAULT_VALUE = nls.localize('notAvailable', "not available");
|
||||
|
||||
public available: boolean;
|
||||
public type: string | undefined;
|
||||
|
||||
constructor(public name: string, id = generateUuid()) {
|
||||
super(undefined, 0, id);
|
||||
super(undefined, undefined, 0, id);
|
||||
this.available = false;
|
||||
// name is not set if the expression is just being added
|
||||
// in that case do not set default value to prevent flashing #14499
|
||||
@@ -214,30 +182,7 @@ export class Expression extends ExpressionContainer implements IExpression {
|
||||
}
|
||||
|
||||
async evaluate(session: IDebugSession | undefined, stackFrame: IStackFrame | undefined, context: string): Promise<void> {
|
||||
if (!session || (!stackFrame && context !== 'repl')) {
|
||||
this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions") : Expression.DEFAULT_VALUE;
|
||||
this.available = false;
|
||||
this.reference = 0;
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
this.session = session;
|
||||
try {
|
||||
const response = await session.evaluate(this.name, stackFrame ? stackFrame.frameId : undefined, context);
|
||||
this.available = !!(response && response.body);
|
||||
if (response && response.body) {
|
||||
this.value = response.body.result || '';
|
||||
this.reference = response.body.variablesReference;
|
||||
this.namedVariables = response.body.namedVariables;
|
||||
this.indexedVariables = response.body.indexedVariables;
|
||||
this.type = response.body.type || this.type;
|
||||
}
|
||||
} catch (e) {
|
||||
this.value = e.message || '';
|
||||
this.available = false;
|
||||
this.reference = 0;
|
||||
}
|
||||
this.available = await this.evaluateExpression(this.name, session, stackFrame, context);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
@@ -252,6 +197,7 @@ export class Variable extends ExpressionContainer implements IExpression {
|
||||
|
||||
constructor(
|
||||
session: IDebugSession | undefined,
|
||||
threadId: number | undefined,
|
||||
public parent: IExpressionContainer,
|
||||
reference: number | undefined,
|
||||
public name: string,
|
||||
@@ -264,7 +210,7 @@ export class Variable extends ExpressionContainer implements IExpression {
|
||||
public available = true,
|
||||
startOfVariables = 0
|
||||
) {
|
||||
super(session, reference, `variable:${parent.getId()}:${name}`, namedVariables, indexedVariables, startOfVariables);
|
||||
super(session, threadId, reference, `variable:${parent.getId()}:${name}`, namedVariables, indexedVariables, startOfVariables);
|
||||
this.value = value || '';
|
||||
}
|
||||
|
||||
@@ -304,7 +250,7 @@ export class Scope extends ExpressionContainer implements IScope {
|
||||
indexedVariables?: number,
|
||||
public range?: IRange
|
||||
) {
|
||||
super(stackFrame.thread.session, reference, `scope:${name}:${index}`, namedVariables, indexedVariables);
|
||||
super(stackFrame.thread.session, stackFrame.thread.threadId, reference, `scope:${name}:${index}`, namedVariables, indexedVariables);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
@@ -332,7 +278,7 @@ export class StackFrame implements IStackFrame {
|
||||
|
||||
getScopes(): Promise<IScope[]> {
|
||||
if (!this.scopes) {
|
||||
this.scopes = this.thread.session.scopes(this.frameId).then(response => {
|
||||
this.scopes = this.thread.session.scopes(this.frameId, this.thread.threadId).then(response => {
|
||||
return response && response.body && response.body.scopes ?
|
||||
response.body.scopes.map((rs, index) => new Scope(this, index, rs.name, rs.variablesReference, rs.expensive, rs.namedVariables, rs.indexedVariables,
|
||||
rs.line && rs.column && rs.endLine && rs.endColumn ? new Range(rs.line, rs.column, rs.endLine, rs.endColumn) : undefined)) : [];
|
||||
@@ -395,6 +341,10 @@ export class StackFrame implements IStackFrame {
|
||||
return !this.source.available ? Promise.resolve(null) :
|
||||
this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned);
|
||||
}
|
||||
|
||||
equals(other: IStackFrame): boolean {
|
||||
return (this.name === other.name) && (other.thread === this.thread) && (other.source === this.source) && (Range.equalsRange(this.range, other.range));
|
||||
}
|
||||
}
|
||||
|
||||
export class Thread implements IThread {
|
||||
@@ -578,13 +528,22 @@ export class BaseBreakpoint extends Enablement implements IBaseBreakpoint {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
get message(): string | undefined {
|
||||
const data = this.getSessionData();
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return data.message;
|
||||
}
|
||||
|
||||
get verified(): boolean {
|
||||
const data = this.getSessionData();
|
||||
return data ? data.verified : true;
|
||||
}
|
||||
|
||||
get idFromAdapter(): number | undefined {
|
||||
const data = this.getSessionData();
|
||||
getIdFromAdapter(sessionId: string): number | undefined {
|
||||
const data = this.sessionData.get(sessionId);
|
||||
return data ? data.id : undefined;
|
||||
}
|
||||
|
||||
@@ -637,15 +596,11 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
|
||||
}
|
||||
|
||||
get message(): string | undefined {
|
||||
const data = this.getSessionData();
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
if (this.textFileService.isDirty(this.uri)) {
|
||||
return nls.localize('breakpointDirtydHover', "Unverified breakpoint. File is modified, please restart debug session.");
|
||||
}
|
||||
|
||||
return data.message;
|
||||
return super.message;
|
||||
}
|
||||
|
||||
get adapterData(): any {
|
||||
@@ -797,13 +752,13 @@ export class DebugModel implements IDebugModel {
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private schedulers = new Map<string, RunOnceScheduler>();
|
||||
private breakpointsSessionId: string | undefined;
|
||||
private breakpointsActivated = true;
|
||||
private readonly _onDidChangeBreakpoints: Emitter<IBreakpointsChangeEvent | undefined>;
|
||||
private readonly _onDidChangeCallStack: Emitter<void>;
|
||||
private readonly _onDidChangeWatchExpressions: Emitter<IExpression | undefined>;
|
||||
|
||||
constructor(
|
||||
private breakpoints: Breakpoint[],
|
||||
private breakpointsActivated: boolean,
|
||||
private functionBreakpoints: FunctionBreakpoint[],
|
||||
private exceptionBreakpoints: ExceptionBreakpoint[],
|
||||
private dataBreakopints: DataBreakpoint[],
|
||||
@@ -901,7 +856,16 @@ export class DebugModel implements IDebugModel {
|
||||
if (!this.schedulers.has(thread.getId())) {
|
||||
this.schedulers.set(thread.getId(), new RunOnceScheduler(() => {
|
||||
thread.fetchCallStack(19).then(() => {
|
||||
this._onDidChangeCallStack.fire();
|
||||
const stale = thread.getStaleCallStack();
|
||||
const current = thread.getCallStack();
|
||||
let bottomOfCallStackChanged = stale.length !== current.length;
|
||||
for (let i = 1; i < stale.length && !bottomOfCallStackChanged; i++) {
|
||||
bottomOfCallStackChanged = !stale[i].equals(current[i]);
|
||||
}
|
||||
|
||||
if (bottomOfCallStackChanged) {
|
||||
this._onDidChangeCallStack.fire();
|
||||
}
|
||||
c();
|
||||
});
|
||||
}, 420));
|
||||
@@ -1065,9 +1029,9 @@ export class DebugModel implements IDebugModel {
|
||||
}
|
||||
|
||||
setEnablement(element: IEnablement, enable: boolean): void {
|
||||
if (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof ExceptionBreakpoint) {
|
||||
const changed: Array<IBreakpoint | IFunctionBreakpoint> = [];
|
||||
if (element.enabled !== enable && (element instanceof Breakpoint || element instanceof FunctionBreakpoint)) {
|
||||
if (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof ExceptionBreakpoint || element instanceof DataBreakpoint) {
|
||||
const changed: Array<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint> = [];
|
||||
if (element.enabled !== enable && (element instanceof Breakpoint || element instanceof FunctionBreakpoint || element instanceof DataBreakpoint)) {
|
||||
changed.push(element);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ declare module DebugProtocol {
|
||||
|
||||
/** Base class of requests, responses, and events. */
|
||||
export interface ProtocolMessage {
|
||||
/** Sequence number. */
|
||||
/** Sequence number (also known as message ID). For protocol messages of type 'request' this ID can be used to cancel the request. */
|
||||
seq: number;
|
||||
/** Message type.
|
||||
Values: 'request', 'response', 'event', etc.
|
||||
@@ -41,11 +41,20 @@ declare module DebugProtocol {
|
||||
// type: 'response';
|
||||
/** Sequence number of the corresponding request. */
|
||||
request_seq: number;
|
||||
/** Outcome of the request. */
|
||||
/** Outcome of the request.
|
||||
If true, the request was successful and the 'body' attribute may contain the result of the request.
|
||||
If the value is false, the attribute 'message' contains the error in short form and the 'body' may contain additional information (see 'ErrorResponse.body.error').
|
||||
*/
|
||||
success: boolean;
|
||||
/** The command requested. */
|
||||
command: string;
|
||||
/** Contains error message if success == false. */
|
||||
/** Contains the raw error in short form if 'success' is false.
|
||||
This raw error might be interpreted by the frontend and is not shown in the UI.
|
||||
Some predefined values exist.
|
||||
Values:
|
||||
'cancelled': request was cancelled.
|
||||
etc.
|
||||
*/
|
||||
message?: string;
|
||||
/** Contains request result if success is true and optional error details if success is false. */
|
||||
body?: any;
|
||||
@@ -59,6 +68,30 @@ declare module DebugProtocol {
|
||||
};
|
||||
}
|
||||
|
||||
/** Cancel request; value of command field is 'cancel'.
|
||||
The 'cancel' request is used by the frontend to indicate that it is no longer interested in the result produced by a specific request issued earlier.
|
||||
This request has a hint characteristic: a debug adapter can only be expected to make a 'best effort' in honouring this request but there are no guarantees.
|
||||
The 'cancel' request may return an error if it could not cancel an operation but a frontend should refrain from presenting this error to end users.
|
||||
A frontend client should only call this request if the capability 'supportsCancelRequest' is true.
|
||||
The request that got canceled still needs to send a response back.
|
||||
This can either be a normal result ('success' attribute true) or an error response ('success' attribute false and the 'message' set to 'cancelled').
|
||||
Returning partial results from a cancelled request is possible but please note that a frontend client has no generic way for detecting that a response is partial or not.
|
||||
*/
|
||||
export interface CancelRequest extends Request {
|
||||
// command: 'cancel';
|
||||
arguments?: CancelArguments;
|
||||
}
|
||||
|
||||
/** Arguments for 'cancel' request. */
|
||||
export interface CancelArguments {
|
||||
/** The ID (attribute 'seq') of the request to cancel. */
|
||||
requestId?: number;
|
||||
}
|
||||
|
||||
/** Response to 'cancel' request. This is just an acknowledgement, so no body field is required. */
|
||||
export interface CancelResponse extends Response {
|
||||
}
|
||||
|
||||
/** Event message for 'initialized' event type.
|
||||
This event indicates that the debug adapter is ready to accept configuration requests (e.g. SetBreakpointsRequest, SetExceptionBreakpointsRequest).
|
||||
A debug adapter is expected to send this event when it is ready to accept configuration requests (but not before the 'initialize' request has finished).
|
||||
@@ -455,6 +488,38 @@ declare module DebugProtocol {
|
||||
export interface TerminateResponse extends Response {
|
||||
}
|
||||
|
||||
/** BreakpointLocations request; value of command field is 'breakpointLocations'.
|
||||
The 'breakpointLocations' request returns all possible locations for source breakpoints in a given range.
|
||||
*/
|
||||
export interface BreakpointLocationsRequest extends Request {
|
||||
// command: 'breakpointLocations';
|
||||
arguments?: BreakpointLocationsArguments;
|
||||
}
|
||||
|
||||
/** Arguments for 'breakpointLocations' request. */
|
||||
export interface BreakpointLocationsArguments {
|
||||
/** The source location of the breakpoints; either 'source.path' or 'source.reference' must be specified. */
|
||||
source: Source;
|
||||
/** Start line of range to search possible breakpoint locations in. If only the line is specified, the request returns all possible locations in that line. */
|
||||
line: number;
|
||||
/** Optional start column of range to search possible breakpoint locations in. If no start column is given, the first column in the start line is assumed. */
|
||||
column?: number;
|
||||
/** Optional end line of range to search possible breakpoint locations in. If no end line is given, then the end line is assumed to be the start line. */
|
||||
endLine?: number;
|
||||
/** Optional end column of range to search possible breakpoint locations in. If no end column is given, then it is assumed to be in the last column of the end line. */
|
||||
endColumn?: number;
|
||||
}
|
||||
|
||||
/** Response to 'breakpointLocations' request.
|
||||
Contains possible locations for source breakpoints.
|
||||
*/
|
||||
export interface BreakpointLocationsResponse extends Response {
|
||||
body: {
|
||||
/** Sorted set of possible breakpoint locations. */
|
||||
breakpoints: BreakpointLocation[];
|
||||
};
|
||||
}
|
||||
|
||||
/** SetBreakpoints request; value of command field is 'setBreakpoints'.
|
||||
Sets multiple breakpoints for a single source and clears all previous breakpoints in that source.
|
||||
To clear all breakpoint for a source, specify an empty array.
|
||||
@@ -1330,6 +1395,10 @@ declare module DebugProtocol {
|
||||
supportsReadMemoryRequest?: boolean;
|
||||
/** The debug adapter supports the 'disassemble' request. */
|
||||
supportsDisassembleRequest?: boolean;
|
||||
/** The debug adapter supports the 'cancel' request. */
|
||||
supportsCancelRequest?: boolean;
|
||||
/** The debug adapter supports the 'breakpointLocations' request. */
|
||||
supportsBreakpointLocationsRequest?: boolean;
|
||||
}
|
||||
|
||||
/** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */
|
||||
@@ -1577,6 +1646,18 @@ declare module DebugProtocol {
|
||||
visibility?: string;
|
||||
}
|
||||
|
||||
/** Properties of a breakpoint location returned from the 'breakpointLocations' request. */
|
||||
export interface BreakpointLocation {
|
||||
/** Start line of breakpoint location. */
|
||||
line: number;
|
||||
/** Optional start column of breakpoint location. */
|
||||
column?: number;
|
||||
/** Optional end line of breakpoint location if the location covers a range. */
|
||||
endLine?: number;
|
||||
/** Optional end column of breakpoint location if the location covers a range. */
|
||||
endColumn?: number;
|
||||
}
|
||||
|
||||
/** Properties of a breakpoint or logpoint passed to the setBreakpoints request. */
|
||||
export interface SourceBreakpoint {
|
||||
/** The source line of the breakpoint or logpoint. */
|
||||
|
||||
@@ -137,6 +137,8 @@ export const launchSchema: IJSONSchema = {
|
||||
id: launchSchemaId,
|
||||
type: 'object',
|
||||
title: nls.localize('app.launch.json.title', "Launch"),
|
||||
allowsTrailingCommas: true,
|
||||
allowComments: true,
|
||||
required: [],
|
||||
default: { version: '0.2.0', configurations: [], compounds: [] },
|
||||
properties: {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
||||
import { IConfig, IDebuggerContribution, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IConfig, IDebuggerContribution, IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { isAbsolute } from 'vs/base/common/path';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
@@ -42,6 +42,10 @@ export function formatPII(value: string, excludePII: boolean, args: { [key: stri
|
||||
});
|
||||
}
|
||||
|
||||
export function isSessionAttach(session: IDebugSession): boolean {
|
||||
return !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration);
|
||||
}
|
||||
|
||||
export function isExtensionHostDebugging(config: IConfig) {
|
||||
return config.type && equalsIgnoreCase(config.type === 'vslsShare' ? (<any>config).adapterProxy.configuration.type : config.type, 'extensionhost');
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
|
||||
export class ViewModel implements IViewModel {
|
||||
|
||||
@@ -71,7 +71,7 @@ export class ViewModel implements IViewModel {
|
||||
this.stepBackSupportedContextKey.set(session ? !!session.capabilities.supportsStepBack : false);
|
||||
this.restartFrameSupportedContextKey.set(session ? !!session.capabilities.supportsRestartFrame : false);
|
||||
this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false);
|
||||
const attach = !!session && !session.parentSession && session.configuration.request === 'attach' && !isExtensionHostDebugging(session.configuration);
|
||||
const attach = !!session && isSessionAttach(session);
|
||||
this.focusedSessionIsAttach.set(attach);
|
||||
|
||||
if (shouldEmitForSession) {
|
||||
|
||||
@@ -6,15 +6,105 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { IReplElement, IStackFrame, IExpression, IReplElementSource, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { isUndefinedOrNull, isObject } from 'vs/base/common/types';
|
||||
import { ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { isString, isUndefinedOrNull, isObject } from 'vs/base/common/types';
|
||||
import { basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
const MAX_REPL_LENGTH = 10000;
|
||||
let topReplElementCounter = 0;
|
||||
|
||||
export class SimpleReplElement implements IReplElement {
|
||||
constructor(
|
||||
private id: string,
|
||||
public value: string,
|
||||
public severity: severity,
|
||||
public sourceData?: IReplElementSource,
|
||||
) { }
|
||||
|
||||
toString(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
export class RawObjectReplElement implements IExpression {
|
||||
|
||||
private static readonly MAX_CHILDREN = 1000; // upper bound of children per value
|
||||
|
||||
constructor(private id: string, public name: string, public valueObj: any, public sourceData?: IReplElementSource, public annotation?: string) { }
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
if (this.valueObj === null) {
|
||||
return 'null';
|
||||
} else if (Array.isArray(this.valueObj)) {
|
||||
return `Array[${this.valueObj.length}]`;
|
||||
} else if (isObject(this.valueObj)) {
|
||||
return 'Object';
|
||||
} else if (isString(this.valueObj)) {
|
||||
return `"${this.valueObj}"`;
|
||||
}
|
||||
|
||||
return String(this.valueObj) || '';
|
||||
}
|
||||
|
||||
get hasChildren(): boolean {
|
||||
return (Array.isArray(this.valueObj) && this.valueObj.length > 0) || (isObject(this.valueObj) && Object.getOwnPropertyNames(this.valueObj).length > 0);
|
||||
}
|
||||
|
||||
getChildren(): Promise<IExpression[]> {
|
||||
let result: IExpression[] = [];
|
||||
if (Array.isArray(this.valueObj)) {
|
||||
result = (<any[]>this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN)
|
||||
.map((v, index) => new RawObjectReplElement(`${this.id}:${index}`, String(index), v));
|
||||
} else if (isObject(this.valueObj)) {
|
||||
result = Object.getOwnPropertyNames(this.valueObj).slice(0, RawObjectReplElement.MAX_CHILDREN)
|
||||
.map((key, index) => new RawObjectReplElement(`${this.id}:${index}`, key, this.valueObj[key]));
|
||||
}
|
||||
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.name}\n${this.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplEvaluationInput implements IReplElement {
|
||||
private id: string;
|
||||
|
||||
constructor(public value: string) {
|
||||
this.id = generateUuid();
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplEvaluationResult extends ExpressionContainer implements IReplElement {
|
||||
constructor() {
|
||||
super(undefined, undefined, 0, generateUuid());
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.value}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplModel {
|
||||
private replElements: IReplElement[] = [];
|
||||
|
||||
@@ -24,10 +114,11 @@ export class ReplModel {
|
||||
return this.replElements;
|
||||
}
|
||||
|
||||
addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
const expression = new Expression(name);
|
||||
this.addReplElement(expression);
|
||||
return expression.evaluate(this.session, stackFrame, 'repl');
|
||||
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
this.addReplElement(new ReplEvaluationInput(name));
|
||||
const result = new ReplEvaluationResult();
|
||||
await result.evaluateExpression(name, this.session, stackFrame, 'repl');
|
||||
this.addReplElement(result);
|
||||
}
|
||||
|
||||
appendToRepl(data: string | IExpression, sev: severity, source?: IReplElementSource): void {
|
||||
|
||||
@@ -127,11 +127,8 @@ export class SocketDebugAdapter extends StreamDebugAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
stopSession(): Promise<void> {
|
||||
|
||||
// Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666.
|
||||
this.cancelPending();
|
||||
|
||||
async stopSession(): Promise<void> {
|
||||
await this.cancelPendingRequests();
|
||||
if (this.socket) {
|
||||
this.socket.end();
|
||||
this.socket = undefined;
|
||||
@@ -252,10 +249,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
stopSession(): Promise<void> {
|
||||
|
||||
// Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666.
|
||||
this.cancelPending();
|
||||
async stopSession(): Promise<void> {
|
||||
|
||||
if (!this.serverProcess) {
|
||||
return Promise.resolve(undefined);
|
||||
@@ -264,6 +258,7 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter {
|
||||
// when killing a process in windows its child
|
||||
// processes are *not* killed but become root
|
||||
// processes. Therefore we use TASKKILL.EXE
|
||||
await this.cancelPendingRequests();
|
||||
if (platform.isWindows) {
|
||||
return new Promise<void>((c, e) => {
|
||||
const killer = cp.exec(`taskkill /F /T /PID ${this.serverProcess!.pid}`, function (err, stdout, stderr) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export class NodeDebugHelperService implements IDebugHelperService {
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
|
||||
@@ -9,9 +9,21 @@ import * as dom from 'vs/base/browser/dom';
|
||||
import { Expression, Variable, Scope, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
|
||||
const $ = dom.$;
|
||||
|
||||
suite('Debug - Base Debug View', () => {
|
||||
let linkDetector: LinkDetector;
|
||||
|
||||
/**
|
||||
* Instantiate services for use by the functions being tested.
|
||||
*/
|
||||
setup(() => {
|
||||
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService();
|
||||
linkDetector = instantiationService.createInstance(LinkDetector);
|
||||
});
|
||||
|
||||
test('replace whitespace', () => {
|
||||
assert.equal(replaceWhitespace('hey there'), 'hey there');
|
||||
@@ -36,7 +48,7 @@ suite('Debug - Base Debug View', () => {
|
||||
expression.available = true;
|
||||
expression.value = '"string value"';
|
||||
container = $('.container');
|
||||
renderExpressionValue(expression, container, { colorize: true });
|
||||
renderExpressionValue(expression, container, { colorize: true, linkDetector });
|
||||
assert.equal(container.className, 'value string');
|
||||
assert.equal(container.textContent, '"string value"');
|
||||
|
||||
@@ -48,8 +60,14 @@ suite('Debug - Base Debug View', () => {
|
||||
|
||||
expression.value = 'this is a long string';
|
||||
container = $('.container');
|
||||
renderExpressionValue(expression, container, { colorize: true, maxValueLength: 4 });
|
||||
renderExpressionValue(expression, container, { colorize: true, maxValueLength: 4, linkDetector });
|
||||
assert.equal(container.textContent, 'this...');
|
||||
|
||||
expression.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5';
|
||||
container = $('.container');
|
||||
renderExpressionValue(expression, container, { colorize: true, linkDetector });
|
||||
assert.ok(container.querySelector('a'));
|
||||
assert.equal(container.querySelector('a')!.textContent, expression.value);
|
||||
});
|
||||
|
||||
test.skip('render variable', () => { // {{SQL CARBON EDIT}} skip test
|
||||
@@ -58,7 +76,7 @@ suite('Debug - Base Debug View', () => {
|
||||
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: undefined!, endColumn: undefined! }, 0);
|
||||
const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10);
|
||||
|
||||
let variable = new Variable(session, scope, 2, 'foo', 'bar.foo', undefined!, 0, 0, {}, 'string');
|
||||
let variable = new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined!, 0, 0, {}, 'string');
|
||||
let expression = $('.');
|
||||
let name = $('.');
|
||||
let value = $('.');
|
||||
@@ -73,16 +91,24 @@ suite('Debug - Base Debug View', () => {
|
||||
expression = $('.');
|
||||
name = $('.');
|
||||
value = $('.');
|
||||
renderVariable(variable, { expression, name, value, label }, false, []);
|
||||
renderVariable(variable, { expression, name, value, label }, false, [], linkDetector);
|
||||
assert.equal(value.textContent, 'hey');
|
||||
assert.equal(label.element.textContent, 'foo:');
|
||||
assert.equal(label.element.title, 'string');
|
||||
|
||||
variable = new Variable(session, scope, 2, 'console', 'console', '5', 0, 0, { kind: 'virtual' });
|
||||
variable.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5';
|
||||
expression = $('.');
|
||||
name = $('.');
|
||||
value = $('.');
|
||||
renderVariable(variable, { expression, name, value, label }, false, []);
|
||||
renderVariable(variable, { expression, name, value, label }, false, [], linkDetector);
|
||||
assert.ok(value.querySelector('a'));
|
||||
assert.equal(value.querySelector('a')!.textContent, variable.value);
|
||||
|
||||
variable = new Variable(session, 1, scope, 2, 'console', 'console', '5', 0, 0, { kind: 'virtual' });
|
||||
expression = $('.');
|
||||
name = $('.');
|
||||
value = $('.');
|
||||
renderVariable(variable, { expression, name, value, label }, false, [], linkDetector);
|
||||
assert.equal(name.className, 'virtual');
|
||||
assert.equal(label.element.textContent, 'console:');
|
||||
assert.equal(label.element.title, 'console');
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
import * as assert from 'assert';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { SimpleReplElement, DebugModel, Expression, RawObjectReplElement, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { DebugModel, Expression, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import * as sinon from 'sinon';
|
||||
import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
@@ -24,7 +24,7 @@ suite('Debug - Model', () => {
|
||||
let rawSession: MockRawSession;
|
||||
|
||||
setup(() => {
|
||||
model = new DebugModel([], true, [], [], [], [], <any>{ isDirty: (e: any) => false });
|
||||
model = new DebugModel([], [], [], [], [], <any>{ isDirty: (e: any) => false });
|
||||
rawSession = new MockRawSession();
|
||||
});
|
||||
|
||||
@@ -348,9 +348,7 @@ suite('Debug - Model', () => {
|
||||
|
||||
assert.equal(replModel.getReplElements().length, 3);
|
||||
replModel.getReplElements().forEach(re => {
|
||||
assert.equal((<Expression>re).available, false);
|
||||
assert.equal((<Expression>re).name, 'myVariable');
|
||||
assert.equal((<Expression>re).reference, 0);
|
||||
assert.equal((<ReplEvaluationInput>re).value, 'myVariable');
|
||||
});
|
||||
|
||||
replModel.removeReplExpressions();
|
||||
|
||||
@@ -14,7 +14,7 @@ import Severity from 'vs/base/common/severity';
|
||||
|
||||
export class MockDebugService implements IDebugService {
|
||||
|
||||
public _serviceBrand: any;
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
public get state(): State {
|
||||
throw new Error('not implemented');
|
||||
@@ -180,6 +180,10 @@ export class MockSession implements IDebugSession {
|
||||
return 'mockname';
|
||||
}
|
||||
|
||||
setName(name: string): void {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
getSourceForUri(modelUri: uri): Source {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
@@ -204,6 +208,10 @@ export class MockSession implements IDebugSession {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
get onDidChangeName(): Event<string> {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig }) { }
|
||||
|
||||
getAllThreads(): IThread[] {
|
||||
@@ -256,7 +264,7 @@ export class MockSession implements IDebugSession {
|
||||
scopes(frameId: number): Promise<DebugProtocol.ScopesResponse> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
variables(variablesReference: number, filter: 'indexed' | 'named', start: number, count: number): Promise<DebugProtocol.VariablesResponse> {
|
||||
variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named', start: number, count: number): Promise<DebugProtocol.VariablesResponse> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
evaluate(expression: string, frameId: number, context?: string): Promise<DebugProtocol.EvaluateResponse> {
|
||||
|
||||