support exception configuration

This commit is contained in:
Andre Weinand 2017-03-22 22:33:38 +01:00
Родитель 0b4141442b
Коммит 6d637b7689
4 изменённых файлов: 223 добавлений и 54 удалений

Просмотреть файл

@ -4,6 +4,7 @@
!bin/Release/*
!out/extension.js
!node_modules/vscode-nls/**/*
!node_modules/vscode-debugprotocol/**/*
!package.json
!package.nls.json
!README.md

Просмотреть файл

@ -26,6 +26,7 @@
"node": "^6.3.0"
},
"dependencies": {
"vscode-debugprotocol": "^1.17.0",
"vscode-nls": "^2.0.2"
},
"repository": {
@ -50,9 +51,40 @@
},
"main": "./out/extension",
"activationEvents": [
"onCommand:extension.mono-debug.configureExceptions"
"onCommand:extension.mono-debug.configureExceptions",
"onCommand:extension.mono-debug.startSession"
],
"contributes": {
"configuration": {
"type": "object",
"title": "Mono Debug Exception Configuration",
"properties": {
"mono-debug.exceptionOptions": {
"type": "object",
"additionalProperties": {
"type": "string",
"enum": [ "never", "always", "unhandled", "userUnhandled" ],
"enumDescriptions": [
"never breaks",
"breaks when exception handled or unhandled",
"breaks when exception unhandled"
],
"description": "Possible conditions when a thrown exception should result in a break.",
"default": "never"
},
"description": "Configuration options for exceptions",
"default": {
"System.Exception": "never",
"System.SystemException": "never",
"System.NullReferenceException": "always",
"System.IndexOutOfRangeException": "unhandled",
"System.ArithmeticException": "unhandled"
}
}
}
},
"commands": [
{
"command": "extension.mono-debug.configureExceptions",
@ -60,6 +92,12 @@
"category": "Debug"
}
],
"keybindings": [
{
"command": "extension.mono-debug.configureExceptions",
"key": "f3"
}
],
"breakpoints": [
{
"language": "csharp"
@ -79,6 +117,9 @@
"runtime": "mono"
},
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"startSessionCommand": "extension.mono-debug.startSession",
"initialConfigurations": [
{
"name": "%mono.launch.config.name%",

Просмотреть файл

@ -15,15 +15,6 @@ namespace VSCodeDebug
{
public class MonoDebugSession : DebugSession
{
private readonly string[] EXCEPTIONS = new String[] {
"System.Exception",
"System.SystemException",
"System.NullReferenceException",
"System.IndexOutOfRangeException",
"System.ArithmeticException"
};
private const string MONO = "mono";
private readonly string[] MONO_EXTENSIONS = new String[] {
".cs", ".csx",
@ -182,31 +173,19 @@ namespace VSCodeDebug
supportsEvaluateForHovers = false,
// This debug adapter does not support exception breakpoint filters
exceptionBreakpointFilters = exceptionFilters()
exceptionBreakpointFilters = new dynamic[0]
});
// Mono Debug is ready to accept breakpoints immediately
SendEvent(new InitializedEvent());
}
private object[] exceptionFilters()
{
var exceptions = new List<object>();
foreach (var e in EXCEPTIONS) {
exceptions.Add(new {
label = e,
filter = e
});
}
return exceptions.ToArray();
}
public override void Launch(Response response, dynamic args)
{
_attachMode = false;
SetExceptionBreakpoints(args.__exceptionOptions);
// validate argument 'program'
string programPath = getString(args, "program");
if (programPath == null) {
@ -408,6 +387,8 @@ namespace VSCodeDebug
{
_attachMode = true;
SetExceptionBreakpoints(args.__exceptionOptions);
// validate argument 'address'
var host = getString(args, "address");
if (host == null) {
@ -521,30 +502,7 @@ namespace VSCodeDebug
public override void SetExceptionBreakpoints(Response response, dynamic args)
{
// validate argument 'filters'
string[] filters = null;
if (args.filters != null) {
filters = args.filters.ToObject<string[]>();
if (filters != null && filters.Length == 0) {
filters = null;
}
}
foreach (var cp in _catchpoints) {
_session.Breakpoints.Remove(cp);
}
_catchpoints.Clear();
if (filters != null) {
foreach (var filter in filters) {
_catchpoints.Add(_session.Breakpoints.AddCatchpoint(filter));
}
}
/** Configuration options for selected exceptions. */
//exceptionOptions ?: ExceptionOptions[];
SetExceptionBreakpoints(args.exceptionOptions);
SendResponse(response);
}
@ -785,6 +743,42 @@ namespace VSCodeDebug
//---- private ------------------------------------------
private void SetExceptionBreakpoints(dynamic exceptionOptions)
{
if (exceptionOptions != null) {
// clear all existig catchpoints
foreach (var cp in _catchpoints) {
_session.Breakpoints.Remove(cp);
}
_catchpoints.Clear();
var exceptions = exceptionOptions.ToObject<dynamic[]>();
for (int i = 0; i < exceptions.Length; i++) {
var exception = exceptions[i];
string exName = null;
string exBreakMode = exception.breakMode;
if (exception.path != null) {
var paths = exception.path.ToObject<dynamic[]>();
var path = paths[0];
if (path.names != null) {
var names = path.names.ToObject<dynamic[]>();
if (names.Length > 0) {
exName = names[0];
}
}
}
if (exName != null && exBreakMode == "always") {
_catchpoints.Add(_session.Breakpoints.AddCatchpoint(exName));
}
}
}
}
private void SendOutput(string category, string data) {
if (!String.IsNullOrEmpty(data)) {
if (data[data.Length-1] != '\n') {

Просмотреть файл

@ -6,28 +6,161 @@
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { DebugProtocol } from 'vscode-debugprotocol';
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)();
const configuration = vscode.workspace.getConfiguration('mono-debug');
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('extension.mono-debug.configureExceptions', () => configureExceptions()));
context.subscriptions.push(vscode.commands.registerCommand('extension.mono-debug.startSession', config => startSession(config)));
}
export function deactivate() {
}
//----- configureExceptions ---------------------------------------------------------------------------------------------------
// we store the exception configuration in the workspace or user settings as
type ExceptionConfigurations = { [exception: string]: DebugProtocol.ExceptionBreakMode; };
// if the user has not configured anything, we populate the exception configurationwith these defaults
const DEFAULT_EXCEPTIONS : ExceptionConfigurations = {
"System.Exception": "never",
"System.SystemException": "never",
"System.NullReferenceException": "always",
"System.IndexOutOfRangeException": "unhandled",
"System.ArithmeticException": "unhandled"
};
class BreakOptionItem implements vscode.QuickPickItem {
label: string;
description: string;
breakMode: DebugProtocol.ExceptionBreakMode
}
// the possible exception options converted into QuickPickItem
const OPTIONS = ['never', 'always', 'unhandled', 'userUnhandled'].map<BreakOptionItem>((bm: DebugProtocol.ExceptionBreakMode) => {
return {
label: translate(bm),
description: '',
breakMode: bm
}
});
class ExceptionItem implements vscode.QuickPickItem {
label: string;
description: string;
model: DebugProtocol.ExceptionOptions
}
function translate(mode: DebugProtocol.ExceptionBreakMode) {
switch (mode) {
case 'never':
return localize('breakmode.never', "Never break");
case 'always':
return localize('breakmode.always', "Always break");
case 'unhandled':
return localize('breakmode.unhandled', "Break when exception unhandled");
case 'userUnhandled':
return localize('breakmode.userUnhandled', "Break if exception is not handled by user code");
}
}
function getModel() {
let model = DEFAULT_EXCEPTIONS;
if (configuration) {
const exceptionOptions = configuration.get('exceptionOptions');
if (exceptionOptions) {
model = <ExceptionConfigurations> exceptionOptions;
}
}
return model;
}
function configureExceptions() {
let options : vscode.QuickPickOptions = {
placeHolder: localize('select.exception.category', "Select Exception Category"),
const options: vscode.QuickPickOptions = {
placeHolder: localize('select.exception', "First Select Exception"),
matchOnDescription: true,
matchOnDetail: true
};
vscode.window.showQuickPick([ "Category 1", "Category 2", "Category 3" ], options).then(item => {
if (item) {
vscode.window.showInformationMessage(`Selected: ${item}`);
const exceptionItems: vscode.QuickPickItem[] = [];
const model = getModel();
for (var exception in model) {
exceptionItems.push({
label: exception,
description: translate(model[exception])
});
}
vscode.window.showQuickPick(exceptionItems, options).then(exceptionItem => {
if (exceptionItem) {
const options: vscode.QuickPickOptions = {
placeHolder: localize('select.break.option', "Then Select Break Option"),
matchOnDescription: true,
matchOnDetail: true
};
vscode.window.showQuickPick(OPTIONS, options).then(item => {
if (item) {
model[exceptionItem.label] = item.breakMode;
if (configuration) {
configuration.update('exceptionOptions', model);
}
setExceptionBreakpoints(model);
}
});
}
});
}
function setExceptionBreakpoints(model: ExceptionConfigurations) : Thenable<DebugProtocol.SetExceptionBreakpointsResponse> {
const args: DebugProtocol.SetExceptionBreakpointsArguments = {
filters: [],
exceptionOptions: convertToExceptionOptions(model)
}
return vscode.commands.executeCommand<DebugProtocol.SetExceptionBreakpointsResponse>('workbench.customDebugRequest', 'setExceptionBreakpoints', args);
}
function convertToExceptionOptions(model: ExceptionConfigurations): DebugProtocol.ExceptionOptions[] {
const exceptionItems: DebugProtocol.ExceptionOptions[] = [];
for (var exception in model) {
exceptionItems.push({
path: [ { names: [ exception ] } ],
breakMode: model[exception]
});
}
return exceptionItems;
}
//----- configureExceptions ---------------------------------------------------------------------------------------------------
/**
* The result type of the startSession command.
*/
class StartSessionResult {
status: 'ok' | 'initialConfiguration' | 'saveConfiguration';
content?: string; // launch.json content for 'save'
};
function startSession(config: any): StartSessionResult {
if (config && !config.__exceptionOptions) {
config.__exceptionOptions = convertToExceptionOptions(getModel());
}
vscode.commands.executeCommand('vscode.startDebug', config);
return {
status: 'ok'
};
}