提交 27ca195e 编写于 作者: I Isidor Nikolic 提交者: GitHub

Merge pull request #22948 from michelkaporin/exception-widget

Surfacing new Exception DAP in UI
......@@ -9,13 +9,13 @@ import * as dom from 'vs/base/browser/dom';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IDebugService } from 'vs/workbench/parts/debug/common/debug';
import { IDebugService, IExceptionInfo } from 'vs/workbench/parts/debug/common/debug';
import { RunOnceScheduler } from 'vs/base/common/async';
const $ = dom.$;
export class ExceptionWidget extends ZoneWidget {
constructor(editor: ICodeEditor, private lineNumber: number,
constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, private lineNumber: number,
@IContextViewService private contextViewService: IContextViewService,
@IDebugService private debugService: IDebugService
) {
......@@ -35,15 +35,38 @@ export class ExceptionWidget extends ZoneWidget {
this.container.style.lineHeight = `${fontInfo.lineHeight}px`;
let title = $('.title');
title.textContent = nls.localize('exceptionThrown', 'Exception occurred');
dom.append(container, title);
let msg = $('.message');
const defaultConditionMessage = nls.localize('exceptionThrown', 'Exception has occurred.');
if (this.exceptionInfo.breakMode) {
let conditionMessage;
switch (this.exceptionInfo.breakMode) {
case 'never':
conditionMessage = nls.localize('neverException', 'User-handled exception has occurred.');
break;
case 'always':
conditionMessage = nls.localize('alwaysException', 'Always-breaking exception has occurred.');
break;
case 'unhandled':
conditionMessage = nls.localize('unhandledException', 'Unhandled exception has occurred.');
break;
case 'userUnhandled':
conditionMessage = nls.localize('userUnhandledException', 'User-unhandled exception has occurred.');
break;
default:
conditionMessage = defaultConditionMessage;
break;
}
const thread = this.debugService.getViewModel().focusedThread;
if (thread && thread.stoppedDetails) {
let msg = $('.message');
msg.textContent = thread.stoppedDetails.text;
dom.append(container, msg);
title.textContent = `${conditionMessage} ${this.exceptionInfo.description}`;
msg.textContent = this.exceptionInfo.details.stackTrace;
} else {
title.textContent = defaultConditionMessage;
msg.textContent = this.exceptionInfo.description;
}
dom.append(container, title);
dom.append(container, msg);
}
protected _doLayout(heightInPixel: number, widthInPixel: number): void {
......
......@@ -77,6 +77,7 @@ export interface IExpression extends ITreeElement, IExpressionContainer {
export interface ISession {
stackTrace(args: DebugProtocol.StackTraceArguments): TPromise<DebugProtocol.StackTraceResponse>;
exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise<DebugProtocol.ExceptionInfoResponse>;
scopes(args: DebugProtocol.ScopesArguments): TPromise<DebugProtocol.ScopesResponse>;
variables(args: DebugProtocol.VariablesArguments): TPromise<DebugProtocol.VariablesResponse>;
evaluate(args: DebugProtocol.EvaluateArguments): TPromise<DebugProtocol.EvaluateResponse>;
......@@ -133,6 +134,11 @@ export interface IThread extends ITreeElement {
*/
stoppedDetails: IRawStoppedDetails;
/**
* Information about the exception if an 'exception' stopped event raised and DA supports the 'exceptionInfo' request, otherwise null.
*/
exceptionInfo: TPromise<IExceptionInfo>;
/**
* Gets the callstack if it has already been received from the debug
* adapter, otherwise it returns null.
......@@ -214,6 +220,13 @@ export interface IExceptionBreakpoint extends IEnablement {
label: string;
}
export interface IExceptionInfo {
id?: string;
description?: string;
breakMode: string;
details?: DebugProtocol.ExceptionDetails;
}
// model interfaces
export interface IViewModel extends ITreeElement {
......
......@@ -19,7 +19,7 @@ import { ISuggestion } from 'vs/editor/common/modes';
import { Position } from 'vs/editor/common/core/position';
import {
ITreeElement, IExpression, IExpressionContainer, IProcess, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IModel,
IConfig, ISession, IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IRawBreakpoint
IConfig, ISession, IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IRawBreakpoint, IExceptionInfo
} from 'vs/workbench/parts/debug/common/debug';
import { Source } from 'vs/workbench/parts/debug/common/debugSource';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -490,6 +490,30 @@ export class Thread implements IThread {
});
}
/**
* Returns exception info promise if the exception was thrown, otherwise null
*/
public get exceptionInfo(): TPromise<IExceptionInfo> {
const session = this.process.session;
if (this.stoppedDetails && this.stoppedDetails.reason === 'exception') {
if (!session.capabilities.supportsExceptionInfoRequest) {
return TPromise.as({
description: this.stoppedDetails.text,
breakMode: null
});
}
return session.exceptionInfo({ threadId: this.threadId }).then(exception => ({
id: exception.body.exceptionId,
description: exception.body.description,
breakMode: exception.body.breakMode,
details: exception.body.details
}));
}
return TPromise.as(null);
}
public next(): TPromise<any> {
return this.process.session.next({ threadId: this.threadId });
}
......
......@@ -30,7 +30,7 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c
import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView';
import { DebugHoverWidget } from 'vs/workbench/parts/debug/electron-browser/debugHover';
import { RemoveBreakpointAction, EditConditionalBreakpointAction, EnableBreakpointAction, DisableBreakpointAction, AddConditionalBreakpointAction } from 'vs/workbench/parts/debug/browser/debugActions';
import { IDebugEditorContribution, IDebugService, State, IBreakpoint, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, IStackFrame, IDebugConfiguration, IExpression } from 'vs/workbench/parts/debug/common/debug';
import { IDebugEditorContribution, IDebugService, State, IBreakpoint, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo } from 'vs/workbench/parts/debug/common/debug';
import { BreakpointWidget } from 'vs/workbench/parts/debug/browser/breakpointWidget';
import { ExceptionWidget } from 'vs/workbench/parts/debug/browser/exceptionWidget';
import { FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
......@@ -360,17 +360,21 @@ export class DebugEditorContribution implements IDebugEditorContribution {
const sameUri = exceptionSf.source.uri.toString() === model.uri.toString();
if (this.exceptionWidget && !sameUri) {
this.closeExceptionWidget();
} else if (sameUri && focusedSf.thread.stoppedDetails && focusedSf.thread.stoppedDetails.reason === 'exception') {
this.showExceptionWidget(exceptionSf.lineNumber, exceptionSf.column);
} else if (sameUri) {
focusedSf.thread.exceptionInfo.then(exceptionInfo => {
if (exceptionInfo) {
this.showExceptionWidget(exceptionInfo, exceptionSf.lineNumber, exceptionSf.column);
}
});
}
}
private showExceptionWidget(lineNumber: number, column: number): void {
private showExceptionWidget(exceptionInfo: IExceptionInfo, lineNumber: number, column: number): void {
if (this.exceptionWidget) {
this.exceptionWidget.dispose();
}
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, lineNumber);
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo, lineNumber);
this.exceptionWidget.show({ lineNumber, column }, 0);
}
......
......@@ -323,6 +323,10 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession {
return this.send('stackTrace', args);
}
public exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise<DebugProtocol.ExceptionInfoResponse> {
return this.send('exceptionInfo', args);
}
public scopes(args: DebugProtocol.ScopesArguments): TPromise<DebugProtocol.ScopesResponse> {
return this.send('scopes', args);
}
......
......@@ -120,6 +120,15 @@ export class MockSession implements debug.ISession {
});
}
public exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise<DebugProtocol.ExceptionInfoResponse> {
return TPromise.as({
body: {
exceptionId: 'mockExceptionId',
breakMode: 'unhandled'
}
});
}
public attach(args: DebugProtocol.AttachRequestArguments): TPromise<DebugProtocol.AttachResponse> {
return TPromise.as(null);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册