mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode cbeff45f80213db0ddda2183170281ed97ed3b12 (#8670)
* Merge from vscode cbeff45f80213db0ddda2183170281ed97ed3b12 * fix null strict checks
This commit is contained in:
@@ -641,7 +641,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
.monaco-workbench .codicon-debug-breakpoint-function,
|
||||
.monaco-workbench .codicon-debug-breakpoint-data,
|
||||
.monaco-workbench .codicon-debug-breakpoint-unsupported,
|
||||
.monaco-workbench .codicon-debug-hint:not([class*='codicon-debug-breakpoint']),
|
||||
.monaco-workbench .codicon-debug-hint:not([class*='codicon-debug-breakpoint']):not([class*='codicon-debug-stackframe']),
|
||||
.monaco-workbench .codicon-debug-breakpoint.codicon-debug-stackframe-focused::after,
|
||||
.monaco-workbench .codicon-debug-breakpoint.codicon-debug-stackframe::after {
|
||||
color: ${debugIconBreakpointColor} !important;
|
||||
@@ -662,7 +662,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
if (debugIconBreakpointUnverifiedColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon[class*='-unverified'] {
|
||||
color: ${debugIconBreakpointUnverifiedColor} !important;
|
||||
color: ${debugIconBreakpointUnverifiedColor};
|
||||
}
|
||||
`);
|
||||
}
|
||||
@@ -670,7 +670,8 @@ registerThemingParticipant((theme, collector) => {
|
||||
const debugIconBreakpointCurrentStackframeForegroundColor = theme.getColor(debugIconBreakpointCurrentStackframeForeground);
|
||||
if (debugIconBreakpointCurrentStackframeForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-debug-stackframe {
|
||||
.monaco-workbench .codicon-debug-stackframe,
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
color: ${debugIconBreakpointCurrentStackframeForegroundColor} !important;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -119,7 +119,6 @@ class CallStackEditorContribution implements IEditorContribution {
|
||||
|
||||
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-top-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
@@ -130,7 +129,6 @@ class CallStackEditorContribution implements IEditorContribution {
|
||||
|
||||
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-focused-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
|
||||
@@ -84,7 +84,7 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(Viewlet
|
||||
DebugViewlet,
|
||||
VIEWLET_ID,
|
||||
nls.localize('debugAndRun', "Debug and Run"),
|
||||
'codicon-debug',
|
||||
'codicon-debug-alt',
|
||||
13 // {{SQL CARBON EDIT}}
|
||||
));
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import * as errors from 'vs/base/common/errors';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -22,18 +21,15 @@ import { DebugModel, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expres
|
||||
import { ViewModel } from 'vs/workbench/contrib/debug/common/debugViewModel';
|
||||
import * as debugactions from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { ConfigurationManager } from 'vs/workbench/contrib/debug/browser/debugConfigurationManager';
|
||||
import Constants from 'vs/workbench/contrib/markers/browser/constants';
|
||||
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
|
||||
import { VIEWLET_ID as EXPLORER_VIEWLET_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
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 } from 'vs/base/common/actions';
|
||||
@@ -42,12 +38,13 @@ import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions, CONTEXT_DEBUG_UX } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { getExtensionHostDebugSession } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { isErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { TaskRunResult, DebugTaskRunner } from 'vs/workbench/contrib/debug/browser/debugTaskRunner';
|
||||
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
|
||||
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
|
||||
const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
|
||||
@@ -55,23 +52,6 @@ const DEBUG_DATA_BREAKPOINTS_KEY = 'debug.databreakpoint';
|
||||
const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint';
|
||||
const DEBUG_WATCH_EXPRESSIONS_KEY = 'debug.watchexpressions';
|
||||
|
||||
function once(match: (e: TaskEvent) => boolean, event: Event<TaskEvent>): Event<TaskEvent> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
const result = event(e => {
|
||||
if (match(e)) {
|
||||
result.dispose();
|
||||
return listener.call(thisArgs, e);
|
||||
}
|
||||
}, null, disposables);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
const enum TaskRunResult {
|
||||
Failure,
|
||||
Success
|
||||
}
|
||||
|
||||
export class DebugService implements IDebugService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
@@ -81,6 +61,7 @@ export class DebugService implements IDebugService {
|
||||
private readonly _onDidEndSession: Emitter<IDebugSession>;
|
||||
private model: DebugModel;
|
||||
private viewModel: ViewModel;
|
||||
private taskRunner: DebugTaskRunner;
|
||||
private configurationManager: ConfigurationManager;
|
||||
private toDispose: IDisposable[];
|
||||
private debugType: IContextKey<string>;
|
||||
@@ -91,6 +72,7 @@ export class DebugService implements IDebugService {
|
||||
private initializing = false;
|
||||
private previousState: State | undefined;
|
||||
private initCancellationToken: CancellationTokenSource | undefined;
|
||||
private activity: IDisposable | undefined;
|
||||
|
||||
constructor(
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@@ -107,11 +89,10 @@ export class DebugService implements IDebugService {
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IMarkerService private readonly markerService: IMarkerService,
|
||||
@ITaskService private readonly taskService: ITaskService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService
|
||||
@IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService,
|
||||
@IActivityService private readonly activityService: IActivityService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
|
||||
@@ -136,6 +117,7 @@ export class DebugService implements IDebugService {
|
||||
this.toDispose.push(this.model);
|
||||
|
||||
this.viewModel = new ViewModel(contextKeyService);
|
||||
this.taskRunner = this.instantiationService.createInstance(DebugTaskRunner);
|
||||
|
||||
this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
|
||||
this.lifecycleService.onShutdown(this.dispose, this);
|
||||
@@ -176,6 +158,16 @@ export class DebugService implements IDebugService {
|
||||
this.toDispose.push(this.configurationManager.onDidSelectConfiguration(() => {
|
||||
this.debugUx.set(!!(this.state !== State.Inactive || this.configurationManager.selectedConfiguration.name) ? 'default' : 'simple');
|
||||
}));
|
||||
this.toDispose.push(Event.any(this.onDidNewSession, this.onDidEndSession)(() => {
|
||||
const numberOfSessions = this.model.getSessions().length;
|
||||
if (numberOfSessions === 0) {
|
||||
if (this.activity) {
|
||||
this.activity.dispose();
|
||||
}
|
||||
} else {
|
||||
this.activity = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(numberOfSessions, n => n === 1 ? nls.localize('1activeSession', "1 active session") : nls.localize('nActiveSessions', "{0} active sessions", n)));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
getModel(): IDebugModel {
|
||||
@@ -299,7 +291,7 @@ export class DebugService implements IDebugService {
|
||||
"Compound must have \"configurations\" attribute set in order to start multiple configurations."));
|
||||
}
|
||||
if (compound.preLaunchTask) {
|
||||
const taskResult = await this.runTaskAndCheckErrors(launch?.workspace || this.contextService.getWorkspace(), compound.preLaunchTask);
|
||||
const taskResult = await this.taskRunner.runTaskAndCheckErrors(launch?.workspace || this.contextService.getWorkspace(), compound.preLaunchTask, this.showError);
|
||||
if (taskResult === TaskRunResult.Failure) {
|
||||
this.endInitializingState();
|
||||
return false;
|
||||
@@ -411,7 +403,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
|
||||
const workspace = launch ? launch.workspace : this.contextService.getWorkspace();
|
||||
const taskResult = await this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask);
|
||||
const taskResult = await this.taskRunner.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask, this.showError);
|
||||
if (taskResult === TaskRunResult.Success) {
|
||||
return this.doCreateSession(launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
|
||||
}
|
||||
@@ -548,7 +540,7 @@ export class DebugService implements IDebugService {
|
||||
|
||||
if (session.configuration.postDebugTask) {
|
||||
try {
|
||||
await this.runTask(session.root, session.configuration.postDebugTask);
|
||||
await this.taskRunner.runTask(session.root, session.configuration.postDebugTask);
|
||||
} catch (err) {
|
||||
this.notificationService.error(err);
|
||||
}
|
||||
@@ -587,8 +579,8 @@ export class DebugService implements IDebugService {
|
||||
return Promise.resolve(TaskRunResult.Success);
|
||||
}
|
||||
|
||||
await this.runTask(session.root, session.configuration.postDebugTask);
|
||||
return this.runTaskAndCheckErrors(session.root, session.configuration.preLaunchTask);
|
||||
await this.taskRunner.runTask(session.root, session.configuration.postDebugTask);
|
||||
return this.taskRunner.runTaskAndCheckErrors(session.root, session.configuration.preLaunchTask, this.showError);
|
||||
};
|
||||
|
||||
const extensionDebugSession = getExtensionHostDebugSession(session);
|
||||
@@ -715,129 +707,6 @@ export class DebugService implements IDebugService {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//---- task management
|
||||
|
||||
private async runTaskAndCheckErrors(root: IWorkspaceFolder | IWorkspace | undefined, taskId: string | TaskIdentifier | undefined): Promise<TaskRunResult> {
|
||||
try {
|
||||
const taskSummary = await this.runTask(root, taskId);
|
||||
|
||||
const errorCount = taskId ? this.markerService.getStatistics().errors : 0;
|
||||
const successExitCode = taskSummary && taskSummary.exitCode === 0;
|
||||
const failureExitCode = taskSummary && taskSummary.exitCode !== 0;
|
||||
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 : '';
|
||||
const message = errorCount > 1
|
||||
? nls.localize('preLaunchTaskErrors', "Errors exist after running preLaunchTask '{0}'.", taskLabel)
|
||||
: errorCount === 1
|
||||
? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel)
|
||||
: nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary ? taskSummary.exitCode : 0);
|
||||
|
||||
const result = await 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
|
||||
});
|
||||
|
||||
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);
|
||||
} catch (err) {
|
||||
await this.showError(err.message, [this.taskService.configureAction()]);
|
||||
return TaskRunResult.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
private async runTask(root: IWorkspace | IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise<ITaskSummary | null> {
|
||||
if (!taskId) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (!root) {
|
||||
return Promise.reject(new Error(nls.localize('invalidTaskReference', "Task '{0}' can not be referenced from a launch configuration that is in a different workspace folder.", typeof taskId === 'string' ? taskId : taskId.type)));
|
||||
}
|
||||
// run a task before starting a debug session
|
||||
const task = await this.taskService.getTask(root, taskId);
|
||||
if (!task) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('DebugTaskNotFoundWithTaskId', "Could not find the task '{0}'.", taskId)
|
||||
: nls.localize('DebugTaskNotFound', "Could not find the specified task.");
|
||||
return Promise.reject(createErrorWithActions(errorMessage));
|
||||
}
|
||||
|
||||
// If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340
|
||||
let taskStarted = false;
|
||||
const inactivePromise: Promise<ITaskSummary | null> = new Promise((c, e) => once(e => {
|
||||
// When a task isBackground it will go inactive when it is safe to launch.
|
||||
// But when a background task is terminated by the user, it will also fire an inactive event.
|
||||
// This means that we will not get to see the real exit code from running the task (undefined when terminated by the user).
|
||||
// Catch the ProcessEnded event here, which occurs before inactive, and capture the exit code to prevent this.
|
||||
return (e.kind === TaskEventKind.Inactive
|
||||
|| (e.kind === TaskEventKind.ProcessEnded && e.exitCode === undefined))
|
||||
&& e.taskId === task._id;
|
||||
}, this.taskService.onDidStateChange)(e => {
|
||||
taskStarted = true;
|
||||
c(e.kind === TaskEventKind.ProcessEnded ? { exitCode: e.exitCode } : null);
|
||||
}));
|
||||
|
||||
const promise: Promise<ITaskSummary | null> = this.taskService.getActiveTasks().then(async (tasks): Promise<ITaskSummary | null> => {
|
||||
if (tasks.filter(t => t._id === task._id).length) {
|
||||
// Check that the task isn't busy and if it is, wait for it
|
||||
const busyTasks = await this.taskService.getBusyTasks();
|
||||
if (busyTasks.filter(t => t._id === task._id).length) {
|
||||
taskStarted = true;
|
||||
return inactivePromise;
|
||||
}
|
||||
// task is already running and isn't busy - nothing to do.
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.taskId === task._id, this.taskService.onDidStateChange)(() => {
|
||||
// Task is active, so everything seems to be fine, no need to prompt after 10 seconds
|
||||
// Use case being a slow running task should not be prompted even though it takes more than 10 seconds
|
||||
taskStarted = true;
|
||||
});
|
||||
const taskPromise = this.taskService.run(task);
|
||||
if (task.configurationProperties.isBackground) {
|
||||
return inactivePromise;
|
||||
}
|
||||
|
||||
return taskPromise.then(withUndefinedAsNull);
|
||||
});
|
||||
|
||||
return new Promise((c, e) => {
|
||||
promise.then(result => {
|
||||
taskStarted = true;
|
||||
c(result);
|
||||
}, error => e(error));
|
||||
|
||||
setTimeout(() => {
|
||||
if (!taskStarted) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('taskNotTrackedWithTaskId', "The specified task cannot be tracked.")
|
||||
: nls.localize('taskNotTracked', "The task '{0}' cannot be tracked.", JSON.stringify(taskId));
|
||||
e({ severity: severity.Error, message: errorMessage });
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
//---- focus management
|
||||
|
||||
async focusStackFrame(stackFrame: IStackFrame | undefined, thread?: IThread, session?: IDebugSession, explicit?: boolean): Promise<void> {
|
||||
|
||||
@@ -691,6 +691,11 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
initializeForTest(raw: RawDebugSession): void {
|
||||
this.raw = raw;
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
//---- private
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
169
src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts
Normal file
169
src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import Constants from 'vs/workbench/contrib/markers/browser/constants';
|
||||
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
|
||||
function once(match: (e: TaskEvent) => boolean, event: Event<TaskEvent>): Event<TaskEvent> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
const result = event(e => {
|
||||
if (match(e)) {
|
||||
result.dispose();
|
||||
return listener.call(thisArgs, e);
|
||||
}
|
||||
}, null, disposables);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export const enum TaskRunResult {
|
||||
Failure,
|
||||
Success
|
||||
}
|
||||
|
||||
export class DebugTaskRunner {
|
||||
|
||||
constructor(
|
||||
@ITaskService private readonly taskService: ITaskService,
|
||||
@IMarkerService private readonly markerService: IMarkerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IPanelService private readonly panelService: IPanelService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
) { }
|
||||
|
||||
async runTaskAndCheckErrors(root: IWorkspaceFolder | IWorkspace | undefined, taskId: string | TaskIdentifier | undefined, onError: (msg: string, actions: IAction[]) => Promise<void>): Promise<TaskRunResult> {
|
||||
try {
|
||||
const taskSummary = await this.runTask(root, taskId);
|
||||
|
||||
const errorCount = taskId ? this.markerService.getStatistics().errors : 0;
|
||||
const successExitCode = taskSummary && taskSummary.exitCode === 0;
|
||||
const failureExitCode = taskSummary && taskSummary.exitCode !== 0;
|
||||
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 : '';
|
||||
const message = errorCount > 1
|
||||
? nls.localize('preLaunchTaskErrors', "Errors exist after running preLaunchTask '{0}'.", taskLabel)
|
||||
: errorCount === 1
|
||||
? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel)
|
||||
: nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary ? taskSummary.exitCode : 0);
|
||||
|
||||
const result = await 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
|
||||
});
|
||||
|
||||
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);
|
||||
} catch (err) {
|
||||
await onError(err.message, [this.taskService.configureAction()]);
|
||||
return TaskRunResult.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
async runTask(root: IWorkspace | IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise<ITaskSummary | null> {
|
||||
if (!taskId) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (!root) {
|
||||
return Promise.reject(new Error(nls.localize('invalidTaskReference', "Task '{0}' can not be referenced from a launch configuration that is in a different workspace folder.", typeof taskId === 'string' ? taskId : taskId.type)));
|
||||
}
|
||||
// run a task before starting a debug session
|
||||
const task = await this.taskService.getTask(root, taskId);
|
||||
if (!task) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('DebugTaskNotFoundWithTaskId', "Could not find the task '{0}'.", taskId)
|
||||
: nls.localize('DebugTaskNotFound', "Could not find the specified task.");
|
||||
return Promise.reject(createErrorWithActions(errorMessage));
|
||||
}
|
||||
|
||||
// If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340
|
||||
let taskStarted = false;
|
||||
const inactivePromise: Promise<ITaskSummary | null> = new Promise((c, e) => once(e => {
|
||||
// When a task isBackground it will go inactive when it is safe to launch.
|
||||
// But when a background task is terminated by the user, it will also fire an inactive event.
|
||||
// This means that we will not get to see the real exit code from running the task (undefined when terminated by the user).
|
||||
// Catch the ProcessEnded event here, which occurs before inactive, and capture the exit code to prevent this.
|
||||
return (e.kind === TaskEventKind.Inactive
|
||||
|| (e.kind === TaskEventKind.ProcessEnded && e.exitCode === undefined))
|
||||
&& e.taskId === task._id;
|
||||
}, this.taskService.onDidStateChange)(e => {
|
||||
taskStarted = true;
|
||||
c(e.kind === TaskEventKind.ProcessEnded ? { exitCode: e.exitCode } : null);
|
||||
}));
|
||||
|
||||
const promise: Promise<ITaskSummary | null> = this.taskService.getActiveTasks().then(async (tasks): Promise<ITaskSummary | null> => {
|
||||
if (tasks.filter(t => t._id === task._id).length) {
|
||||
// Check that the task isn't busy and if it is, wait for it
|
||||
const busyTasks = await this.taskService.getBusyTasks();
|
||||
if (busyTasks.filter(t => t._id === task._id).length) {
|
||||
taskStarted = true;
|
||||
return inactivePromise;
|
||||
}
|
||||
// task is already running and isn't busy - nothing to do.
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.taskId === task._id, this.taskService.onDidStateChange)(() => {
|
||||
// Task is active, so everything seems to be fine, no need to prompt after 10 seconds
|
||||
// Use case being a slow running task should not be prompted even though it takes more than 10 seconds
|
||||
taskStarted = true;
|
||||
});
|
||||
const taskPromise = this.taskService.run(task);
|
||||
if (task.configurationProperties.isBackground) {
|
||||
return inactivePromise;
|
||||
}
|
||||
|
||||
return taskPromise.then(withUndefinedAsNull);
|
||||
});
|
||||
|
||||
return new Promise((c, e) => {
|
||||
promise.then(result => {
|
||||
taskStarted = true;
|
||||
c(result);
|
||||
}, error => e(error));
|
||||
|
||||
setTimeout(() => {
|
||||
if (!taskStarted) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('taskNotTrackedWithTaskId', "The specified task cannot be tracked.")
|
||||
: nls.localize('taskNotTracked', "The task '{0}' cannot be tracked.", JSON.stringify(taskId));
|
||||
e({ severity: severity.Error, message: errorMessage });
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.codicon-debug-hint:not([class*='codicon-debug-breakpoint']) {
|
||||
opacity: .4 !important;
|
||||
.codicon-debug-hint:not([class*='codicon-debug-breakpoint']):not([class*='codicon-debug-stackframe']) {
|
||||
opacity: 0.4 !important;
|
||||
}
|
||||
|
||||
.inline-breakpoint-widget.codicon {
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
.codicon-debug-breakpoint.codicon-debug-stackframe-focused::after,
|
||||
.codicon-debug-breakpoint.codicon-debug-stackframe::after {
|
||||
content: "\eb8a";
|
||||
content: '\eb8a';
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@@ -28,26 +28,38 @@
|
||||
|
||||
.monaco-editor .debug-breakpoint-placeholder::before,
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
content: " ";
|
||||
content: ' ';
|
||||
width: 0.9em;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
margin-left: 2px;
|
||||
margin-top: -1px; /* TODO @misolori: figure out a way to not use negative margin for alignment */
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
content: '\eb8b';
|
||||
font: normal normal normal 16px/1 codicon;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
margin-left: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
/* Do not show call stack decoration when we plan to show breakpoint and top stack frame in one decoration */
|
||||
.monaco-editor .debug-breakpoint-placeholder ~ .debug-top-stack-frame-column::before {
|
||||
width: 0em;
|
||||
content: "";
|
||||
content: '';
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -104,7 +116,7 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .name {
|
||||
color: #9B46B0;
|
||||
color: #9b46b0;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .name.virtual {
|
||||
@@ -120,61 +132,61 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .error {
|
||||
color: #E51400;
|
||||
color: #e51400;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .value.number {
|
||||
color: #09885A;
|
||||
color: #09885a;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .value.boolean {
|
||||
color: #0000FF;
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-list-row .expression .value.string {
|
||||
color: #A31515;
|
||||
color: #a31515;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench > .monaco-list-row .expression .value {
|
||||
.vs-dark .monaco-workbench > .monaco-list-row .expression .value {
|
||||
color: rgba(204, 204, 204, 0.6);
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .error {
|
||||
color: #F48771;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.number {
|
||||
color: #B5CEA8;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.number {
|
||||
color: #89d185;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.boolean {
|
||||
color: #75bdfe;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.string {
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .error {
|
||||
color: #f48771;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.boolean {
|
||||
color: #4E94CE;
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.number {
|
||||
color: #b5cea8;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.string {
|
||||
color: #CE9178;
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.number {
|
||||
color: #89d185;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.boolean {
|
||||
color: #75bdfe;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .value.string {
|
||||
color: #f48771;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.boolean {
|
||||
color: #4e94ce;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .value.string {
|
||||
color: #ce9178;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .error {
|
||||
color: #F48771;
|
||||
color: #f48771;
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-list-row .expression .name {
|
||||
color: #C586C0;
|
||||
color: #c586c0;
|
||||
}
|
||||
|
||||
/* High Contrast Theming */
|
||||
@@ -182,7 +194,3 @@
|
||||
.hc-black .monaco-workbench .monaco-list-row .expression .name {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.hc-black .monaco-editor .debug-remove-token-colors {
|
||||
color:black;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ export class RawDebugSession implements IDisposable {
|
||||
public readonly customTelemetryService: ITelemetryService | undefined,
|
||||
private readonly extensionHostDebugService: IExtensionHostDebugService,
|
||||
private readonly openerService: IOpenerService
|
||||
|
||||
) {
|
||||
this.debugAdapter = debugAdapter;
|
||||
this._capabilities = Object.create(null);
|
||||
@@ -598,13 +597,13 @@ export class RawDebugSession implements IDisposable {
|
||||
}
|
||||
|
||||
private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> {
|
||||
return new Promise<R>((completeDispatch, errorDispatch) => {
|
||||
return new Promise<DebugProtocol.Response>((completeDispatch, errorDispatch) => {
|
||||
if (!this.debugAdapter) {
|
||||
errorDispatch(new Error('no debug adapter found'));
|
||||
return;
|
||||
}
|
||||
let cancelationListener: IDisposable;
|
||||
const requestId = this.debugAdapter.sendRequest(command, args, (response: R) => {
|
||||
const requestId = this.debugAdapter.sendRequest(command, args, (response: DebugProtocol.Response) => {
|
||||
if (cancelationListener) {
|
||||
cancelationListener.dispose();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
const $ = dom.$;
|
||||
|
||||
|
||||
export class StartView extends ViewPane {
|
||||
|
||||
static ID = 'workbench.debug.startView';
|
||||
|
||||
@@ -5,7 +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';
|
||||
import { timeout, Queue } from 'vs/base/common/async';
|
||||
|
||||
/**
|
||||
* Abstract implementation of the low level API for a debug adapter.
|
||||
@@ -18,6 +18,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
private requestCallback: ((request: DebugProtocol.Request) => void) | undefined;
|
||||
private eventCallback: ((request: DebugProtocol.Event) => void) | undefined;
|
||||
private messageCallback: ((message: DebugProtocol.ProtocolMessage) => void) | undefined;
|
||||
private readonly queue = new Queue();
|
||||
protected readonly _onError = new Emitter<Error>();
|
||||
protected readonly _onExit = new Emitter<number | null>();
|
||||
|
||||
@@ -108,26 +109,33 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
this.messageCallback(message);
|
||||
}
|
||||
else {
|
||||
switch (message.type) {
|
||||
case 'event':
|
||||
if (this.eventCallback) {
|
||||
this.eventCallback(<DebugProtocol.Event>message);
|
||||
}
|
||||
break;
|
||||
case 'request':
|
||||
if (this.requestCallback) {
|
||||
this.requestCallback(<DebugProtocol.Request>message);
|
||||
}
|
||||
break;
|
||||
case 'response':
|
||||
const response = <DebugProtocol.Response>message;
|
||||
const clb = this.pendingRequests.get(response.request_seq);
|
||||
if (clb) {
|
||||
this.pendingRequests.delete(response.request_seq);
|
||||
clb(response);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.queue.queue(() => {
|
||||
switch (message.type) {
|
||||
case 'event':
|
||||
if (this.eventCallback) {
|
||||
this.eventCallback(<DebugProtocol.Event>message);
|
||||
}
|
||||
break;
|
||||
case 'request':
|
||||
if (this.requestCallback) {
|
||||
this.requestCallback(<DebugProtocol.Request>message);
|
||||
}
|
||||
break;
|
||||
case 'response':
|
||||
const response = <DebugProtocol.Response>message;
|
||||
const clb = this.pendingRequests.get(response.request_seq);
|
||||
if (clb) {
|
||||
this.pendingRequests.delete(response.request_seq);
|
||||
clb(response);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Artificially queueing protocol messages guarantees that any microtasks for
|
||||
// previous message finish before next message is processed. This is essential
|
||||
// to guarantee ordering when using promises anywhere along the call path.
|
||||
return timeout(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +172,6 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// noop
|
||||
this.queue.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ export interface IDebugAdapterServer {
|
||||
}
|
||||
|
||||
export interface IDebugAdapterInlineImpl extends IDisposable {
|
||||
readonly onSendMessage: Event<DebugProtocol.Message>;
|
||||
readonly onDidSendMessage: Event<DebugProtocol.Message>;
|
||||
handleMessage(message: DebugProtocol.Message): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@ import { URI as uri } from 'vs/base/common/uri';
|
||||
import severity from 'vs/base/common/severity';
|
||||
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 { MockRawSession, MockDebugAdapter } from 'vs/workbench/contrib/debug/test/common/mockDebug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { IBreakpointUpdateData, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession {
|
||||
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService);
|
||||
@@ -548,4 +550,26 @@ suite('Debug - Model', () => {
|
||||
assert.equal(grandChild.getReplElements().length, 2);
|
||||
assert.equal(child3.getReplElements().length, 1);
|
||||
});
|
||||
|
||||
test('repl ordering', async () => {
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
const adapter = new MockDebugAdapter();
|
||||
const raw = new RawDebugSession(adapter, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
session.initializeForTest(raw);
|
||||
|
||||
await session.addReplExpression(undefined, 'before.1');
|
||||
assert.equal(session.getReplElements().length, 3);
|
||||
assert.equal((<ReplEvaluationInput>session.getReplElements()[0]).value, 'before.1');
|
||||
assert.equal((<SimpleReplElement>session.getReplElements()[1]).value, 'before.1');
|
||||
assert.equal((<ReplEvaluationResult>session.getReplElements()[2]).value, '=before.1');
|
||||
|
||||
await session.addReplExpression(undefined, 'after.2');
|
||||
await timeout(0);
|
||||
assert.equal(session.getReplElements().length, 6);
|
||||
assert.equal((<ReplEvaluationInput>session.getReplElements()[3]).value, 'after.2');
|
||||
assert.equal((<ReplEvaluationResult>session.getReplElements()[4]).value, '=after.2');
|
||||
assert.equal((<SimpleReplElement>session.getReplElements()[5]).value, 'after.2');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IS
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { CompletionItem } from 'vs/editor/common/modes';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstractDebugAdapter';
|
||||
|
||||
export class MockDebugService implements IDebugService {
|
||||
|
||||
@@ -464,3 +465,67 @@ export class MockRawSession {
|
||||
|
||||
public readonly onDidStop: Event<DebugProtocol.StoppedEvent> = null!;
|
||||
}
|
||||
|
||||
export class MockDebugAdapter extends AbstractDebugAdapter {
|
||||
private seq = 0;
|
||||
|
||||
startSession(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
stopSession(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
sendMessage(message: DebugProtocol.ProtocolMessage): void {
|
||||
setTimeout(() => {
|
||||
if (message.type === 'request') {
|
||||
const request = message as DebugProtocol.Request;
|
||||
switch (request.command) {
|
||||
case 'evaluate':
|
||||
this.evaluate(request, request.arguments);
|
||||
return;
|
||||
}
|
||||
this.sendResponseBody(request, {});
|
||||
return;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
sendResponseBody(request: DebugProtocol.Request, body: any) {
|
||||
const response: DebugProtocol.Response = {
|
||||
seq: ++this.seq,
|
||||
type: 'response',
|
||||
request_seq: request.seq,
|
||||
command: request.command,
|
||||
success: true,
|
||||
body
|
||||
};
|
||||
this.acceptMessage(response);
|
||||
}
|
||||
|
||||
sendEventBody(event: string, body: any) {
|
||||
const response: DebugProtocol.Event = {
|
||||
seq: ++this.seq,
|
||||
type: 'event',
|
||||
event,
|
||||
body
|
||||
};
|
||||
this.acceptMessage(response);
|
||||
}
|
||||
|
||||
evaluate(request: DebugProtocol.Request, args: DebugProtocol.EvaluateArguments) {
|
||||
if (args.expression.indexOf('before.') === 0) {
|
||||
this.sendEventBody('output', { output: args.expression });
|
||||
}
|
||||
|
||||
this.sendResponseBody(request, {
|
||||
result: '=' + args.expression,
|
||||
variablesReference: 0
|
||||
});
|
||||
|
||||
if (args.expression.indexOf('after.') === 0) {
|
||||
this.sendEventBody('output', { output: args.expression });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user