mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 17:23:29 -05:00
Merge from vscode fc10e26ea50f82cdd84e9141491357922e6f5fba (#4639)
This commit is contained in:
@@ -97,7 +97,7 @@ export class CallStackView extends ViewletPanel {
|
||||
dom.addClass(container, 'debug-call-stack');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
this.dataSource = new CallStackDataSource();
|
||||
this.dataSource = new CallStackDataSource(this.debugService);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, new CallStackDelegate(), [
|
||||
new SessionsRenderer(),
|
||||
new ThreadsRenderer(),
|
||||
@@ -562,6 +562,8 @@ function isDeemphasized(frame: IStackFrame): boolean {
|
||||
class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem> {
|
||||
deemphasizedStackFramesToShow: IStackFrame[];
|
||||
|
||||
constructor(private debugService: IDebugService) { }
|
||||
|
||||
hasChildren(element: IDebugModel | CallStackItem): boolean {
|
||||
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
|
||||
}
|
||||
@@ -573,13 +575,18 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (sessions.length > 1) {
|
||||
return Promise.resolve(sessions);
|
||||
return Promise.resolve(sessions.filter(s => !s.parentSession));
|
||||
}
|
||||
|
||||
const threads = sessions[0].getAllThreads();
|
||||
// Only show the threads in the call stack if there is more than 1 thread.
|
||||
return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
|
||||
} else if (isDebugSession(element)) {
|
||||
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
|
||||
if (childSessions.length) {
|
||||
return Promise.resolve(childSessions);
|
||||
}
|
||||
|
||||
return Promise.resolve(element.getAllThreads());
|
||||
} else {
|
||||
return this.getThreadChildren(<Thread>element);
|
||||
|
||||
@@ -217,7 +217,15 @@ export class FocusSessionActionItem extends SelectActionItem {
|
||||
private update() {
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
const sessions = this.getSessions();
|
||||
const names = sessions.map(s => s.getLabel());
|
||||
const names = sessions.map(s => {
|
||||
const label = s.getLabel();
|
||||
if (s.parentSession) {
|
||||
// Indent child sessions so they look like children
|
||||
return `\u00A0\u00A0${label}`;
|
||||
}
|
||||
|
||||
return label;
|
||||
});
|
||||
this.setOptions(names.map(data => <ISelectOptionItem>{ text: data }), session ? sessions.indexOf(session) : undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -516,6 +516,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
|
||||
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo);
|
||||
this.exceptionWidget.show({ lineNumber, column }, 0);
|
||||
this.editor.revealLine(lineNumber);
|
||||
}
|
||||
|
||||
private closeExceptionWidget(): void {
|
||||
|
||||
@@ -37,7 +37,6 @@ export class ExceptionWidget extends ZoneWidget {
|
||||
this._applyTheme(themeService.getTheme());
|
||||
this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this)));
|
||||
|
||||
|
||||
this.create();
|
||||
const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50);
|
||||
this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));
|
||||
|
||||
@@ -39,11 +39,6 @@
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.start,
|
||||
.hc-black .monaco-workbench .debug-action.start {
|
||||
background: url('continue-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.configure,
|
||||
.hc-black .monaco-workbench .debug-action.configure {
|
||||
background: url('configure-inverse.svg') center center no-repeat;
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace {
|
||||
margin-top: 0.5em;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget a {
|
||||
|
||||
@@ -149,6 +149,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
readonly unresolvedConfiguration: IConfig | undefined;
|
||||
readonly state: State;
|
||||
readonly root: IWorkspaceFolder;
|
||||
readonly parentSession: IDebugSession | undefined;
|
||||
|
||||
getLabel(): string;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ 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 { distinct } from 'vs/base/common/arrays';
|
||||
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,
|
||||
@@ -797,7 +797,17 @@ export class DebugModel implements IDebugModel {
|
||||
|
||||
return true;
|
||||
});
|
||||
this.sessions.push(session);
|
||||
|
||||
let index = -1;
|
||||
if (session.parentSession) {
|
||||
// Make sure that child sessions are placed after the parent session
|
||||
index = lastIndex(this.sessions, s => s.parentSession === session.parentSession || s === session.parentSession);
|
||||
}
|
||||
if (index >= 0) {
|
||||
this.sessions.splice(index + 1, 0, session);
|
||||
} else {
|
||||
this.sessions.push(session);
|
||||
}
|
||||
this._onDidChangeCallStack.fire(undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export class ReplModel {
|
||||
|
||||
addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
const expression = new Expression(name);
|
||||
this.addReplElements([expression]);
|
||||
this.addReplElement(expression);
|
||||
return expression.evaluate(this.session, stackFrame, 'repl');
|
||||
}
|
||||
|
||||
@@ -39,26 +39,18 @@ export class ReplModel {
|
||||
}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
const previousElement = this.replElements.length && (this.replElements[this.replElements.length - 1] as SimpleReplElement);
|
||||
|
||||
const toAdd = data.split('\n').map((line, index) => new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, line, sev, index === 0 ? source : undefined));
|
||||
if (previousElement && previousElement.value === '') {
|
||||
// remove potential empty lines between different repl types
|
||||
this.replElements.pop();
|
||||
} else if (previousElement instanceof SimpleReplElement && sev === previousElement.severity && toAdd.length && toAdd[0].sourceData === previousElement.sourceData) {
|
||||
previousElement.value += toAdd.shift()!.value;
|
||||
}
|
||||
this.addReplElements(toAdd);
|
||||
const element = new SimpleReplElement(`topReplElement:${topReplElementCounter++}`, data.trimRight(), sev, source);
|
||||
this.addReplElement(element);
|
||||
} else {
|
||||
// TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression
|
||||
(<any>data).severity = sev;
|
||||
(<any>data).sourceData = source;
|
||||
this.addReplElements([data]);
|
||||
this.addReplElement(data);
|
||||
}
|
||||
}
|
||||
|
||||
private addReplElements(newElements: IReplElement[]): void {
|
||||
this.replElements.push(...newElements);
|
||||
private addReplElement(newElement: IReplElement): void {
|
||||
this.replElements.push(newElement);
|
||||
if (this.replElements.length > MAX_REPL_LENGTH) {
|
||||
this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL, EXTENSION_RELOAD_BROADCAST_CHANNEL, EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
|
||||
import { IRemoteConsoleLog, parse, getFirstFrame } from 'vs/base/node/console';
|
||||
import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast';
|
||||
import { IRemoteConsoleLog, 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';
|
||||
@@ -315,7 +315,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug);
|
||||
return this.createSession(launchForName, launchForName!.getConfiguration(name), noDebug, parentSession);
|
||||
})).then(values => values.every(success => !!success)); // Compound launch is a success only if each configuration launched successfully
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ export class DebugService implements IDebugService {
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
|
||||
return this.createSession(launch, config, noDebug);
|
||||
return this.createSession(launch, config, noDebug, parentSession);
|
||||
});
|
||||
}));
|
||||
}).then(success => {
|
||||
@@ -341,7 +341,7 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* gets the debugger for the type, resolves configurations by providers, substitutes variables and runs prelaunch tasks
|
||||
*/
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean): Promise<boolean> {
|
||||
private createSession(launch: ILaunch | undefined, config: IConfig | undefined, noDebug: boolean, parentSession?: IDebugSession): Promise<boolean> {
|
||||
// We keep the debug type in a separate variable 'type' so that a no-folder config has no attributes.
|
||||
// Storing the type in the config would break extensions that assume that the no-folder case is indicated by an empty config.
|
||||
let type: string | undefined;
|
||||
@@ -386,7 +386,7 @@ export class DebugService implements IDebugService {
|
||||
const workspace = launch ? launch.workspace : undefined;
|
||||
return this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask).then(result => {
|
||||
if (result === TaskRunResult.Success) {
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig });
|
||||
return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, parentSession);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -415,9 +415,9 @@ export class DebugService implements IDebugService {
|
||||
/**
|
||||
* instantiates the new session, initializes the session, registers session listeners and reports telemetry
|
||||
*/
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }): Promise<boolean> {
|
||||
private doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, parentSession?: IDebugSession): Promise<boolean> {
|
||||
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model);
|
||||
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, parentSession);
|
||||
this.model.addSession(session);
|
||||
// register listeners as the very first thing!
|
||||
this.registerSessionListeners(session);
|
||||
|
||||
@@ -57,6 +57,7 @@ export class DebugSession implements IDebugSession {
|
||||
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
|
||||
public root: IWorkspaceFolder,
|
||||
private model: DebugModel,
|
||||
private _parentSession: IDebugSession | undefined,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IOutputService private readonly outputService: IOutputService,
|
||||
@@ -83,6 +84,10 @@ export class DebugSession implements IDebugSession {
|
||||
return this._configuration.unresolved;
|
||||
}
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return this._parentSession;
|
||||
}
|
||||
|
||||
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig | undefined }) {
|
||||
this._configuration = configuration;
|
||||
}
|
||||
@@ -178,6 +183,10 @@ export class DebugSession implements IDebugSession {
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(undefined, err => {
|
||||
this.initialized = true;
|
||||
this._onDidChangeState.fire();
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,11 @@ export class MockDebugService implements IDebugService {
|
||||
}
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
|
||||
get parentSession(): IDebugSession | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getReplElements(): IReplElement[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession';
|
||||
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
|
||||
function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession {
|
||||
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
}
|
||||
|
||||
suite('Debug - Model', () => {
|
||||
let model: DebugModel;
|
||||
let rawSession: MockRawSession;
|
||||
@@ -109,7 +113,7 @@ suite('Debug - Model', () => {
|
||||
test('threads simple', () => {
|
||||
const threadId = 1;
|
||||
const threadName = 'firstThread';
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
assert.equal(model.getSessions(true).length, 1);
|
||||
@@ -136,7 +140,7 @@ suite('Debug - Model', () => {
|
||||
const stoppedReason = 'breakpoint';
|
||||
|
||||
// Add the threads
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
session['raw'] = <any>rawSession;
|
||||
@@ -224,7 +228,7 @@ suite('Debug - Model', () => {
|
||||
const runningThreadId = 2;
|
||||
const runningThreadName = 'runningThread';
|
||||
const stoppedReason = 'breakpoint';
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
session['raw'] = <any>rawSession;
|
||||
@@ -338,7 +342,7 @@ suite('Debug - Model', () => {
|
||||
});
|
||||
|
||||
test('repl expressions', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
assert.equal(session.getReplElements().length, 0);
|
||||
model.addSession(session);
|
||||
|
||||
@@ -362,7 +366,7 @@ suite('Debug - Model', () => {
|
||||
});
|
||||
|
||||
test('stack frame get specific source name', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
|
||||
let firstStackFrame: StackFrame;
|
||||
@@ -390,10 +394,33 @@ suite('Debug - Model', () => {
|
||||
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
|
||||
});
|
||||
|
||||
test('debug child sessions are added in correct order', () => {
|
||||
const session = createMockSession(model);
|
||||
model.addSession(session);
|
||||
const secondSession = createMockSession(model, 'mockSession2');
|
||||
model.addSession(secondSession);
|
||||
const firstChild = createMockSession(model, 'firstChild', session);
|
||||
model.addSession(firstChild);
|
||||
const secondChild = createMockSession(model, 'secondChild', session);
|
||||
model.addSession(secondChild);
|
||||
const thirdSession = createMockSession(model, 'mockSession3');
|
||||
model.addSession(thirdSession);
|
||||
const anotherChild = createMockSession(model, 'secondChild', secondSession);
|
||||
model.addSession(anotherChild);
|
||||
|
||||
const sessions = model.getSessions();
|
||||
assert.equal(sessions[0].getId(), session.getId());
|
||||
assert.equal(sessions[1].getId(), firstChild.getId());
|
||||
assert.equal(sessions[2].getId(), secondChild.getId());
|
||||
assert.equal(sessions[3].getId(), secondSession.getId());
|
||||
assert.equal(sessions[4].getId(), anotherChild.getId());
|
||||
assert.equal(sessions[5].getId(), thirdSession.getId());
|
||||
});
|
||||
|
||||
// Repl output
|
||||
|
||||
test('repl output', () => {
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
|
||||
const repl = new ReplModel(session);
|
||||
repl.appendToRepl('first line\n', severity.Error);
|
||||
repl.appendToRepl('second line', severity.Error);
|
||||
|
||||
Reference in New Issue
Block a user