diff --git a/.gitignore b/.gitignore
index 5bf6ff89b..10415c3b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
bin
node_modules
out
+
+*.vsix
diff --git a/.vscodeignore b/.vscodeignore
new file mode 100644
index 000000000..d8cdc7b5b
--- /dev/null
+++ b/.vscodeignore
@@ -0,0 +1,13 @@
+**/*.gitignore
+tsconfig.json
+
+src/**
+**/*.map
+
+.vscode/**
+
+coreclr-debug/debugAdapters/**
+coreclr-debug/bin/**
+coreclr-debug/obj/**
+coreclr-debug/project.lock.json
+coreclr-debug/install.log
\ No newline at end of file
diff --git a/coreclr-debug/.gitignore b/coreclr-debug/.gitignore
new file mode 100644
index 000000000..0541f8ebe
--- /dev/null
+++ b/coreclr-debug/.gitignore
@@ -0,0 +1,5 @@
+bin
+obj
+project.lock.json
+debugAdapters
+install.log
\ No newline at end of file
diff --git a/coreclr-debug/NuGet.config b/coreclr-debug/NuGet.config
new file mode 100644
index 000000000..9567dad4b
--- /dev/null
+++ b/coreclr-debug/NuGet.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/coreclr-debug/dummy.cs b/coreclr-debug/dummy.cs
new file mode 100644
index 000000000..15513fc2c
--- /dev/null
+++ b/coreclr-debug/dummy.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Dummy
+{
+ class Dummy
+ {
+ static void Main(string[] args) {
+ // empty boilerplate required by dotnet build/publish to emit an entry point
+ // The entrypoint created is dummy[.exe], which we rename to OpenDebugAD7[.exe]
+ // The generated entry point will then run OpenDebugAD7.dll for us
+ }
+ }
+}
\ No newline at end of file
diff --git a/coreclr-debug/project.json b/coreclr-debug/project.json
new file mode 100644
index 000000000..5524d23c4
--- /dev/null
+++ b/coreclr-debug/project.json
@@ -0,0 +1,33 @@
+{
+ "name": "dummy",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "Microsoft.VisualStudio.clrdbg": "14.0.25025-preview-2839567",
+ "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30225-preview-2",
+ "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20225-preview-2",
+ "NETStandard.Library": "1.0.0-rc3-23819",
+ "Newtonsoft.Json": "7.0.1",
+ "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1",
+ "System.Collections.Specialized": "4.0.1-rc3-23819",
+ "System.Collections.Immutable": "1.2.0-rc3-23819",
+ "System.Diagnostics.Process" : "4.1.0-rc3-23819",
+ "System.Diagnostics.StackTrace": "4.0.1-rc3-23819",
+ "System.Dynamic.Runtime": "4.0.11-rc3-23819",
+ "Microsoft.CSharp": "4.0.1-rc3-23819",
+ "System.Threading.Tasks.Dataflow": "4.6.0-rc3-23819",
+ "System.Threading.Thread": "4.0.0-rc3-23819",
+ "System.Xml.XDocument": "4.0.11-rc3-23819",
+ "System.Xml.XmlDocument": "4.0.1-rc3-23819",
+ "System.Xml.XmlSerializer": "4.0.11-rc3-23819",
+ "System.ComponentModel": "4.0.1-rc3-23819",
+ "System.ComponentModel.Annotations": "4.1.0-rc3-23819",
+ "System.ComponentModel.EventBasedAsync": "4.0.11-rc3-23819",
+ "System.Runtime.Serialization.Primitives": "4.1.0-rc3-23819",
+ "System.Net.Http": "4.0.1-rc3-23819"
+ },
+ "frameworks": {
+ "dnxcore50": { }
+ }
+}
diff --git a/package.json b/package.json
index 698e39dcc..b0c6a0254 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
"tslint-microsoft-contrib": "^2.0.0"
},
"engines": {
- "vscode": "^0.10.1"
+ "vscode": "^0.10.10"
},
"activationEvents": [
"onLanguage:csharp",
@@ -128,6 +128,228 @@
"language": "csharp",
"path": "./snippets/csharp.json"
}
+ ],
+ "debuggers": [
+ {
+ "type": "coreclr",
+ "label": ".NET Core",
+ "enableBreakpointsFor": { "languageIds": [ "csharp" ] },
+
+ "program": "./coreclr-debug/debugAdapters/OpenDebugAD7",
+ "windows": {
+ "program": "./coreclr-debug/debugAdapters/OpenDebugAD7.exe"
+ },
+
+ "configurationAttributes": {
+ "launch": {
+ "required": [ "program", "cwd" ],
+ "properties": {
+ "program": {
+ "type": "string",
+ "description": "Path to the program (executable file) to launch. On Windows, a '.exe' suffix is appended if not specified already.",
+ "default": "${workspaceRoot}/bin/Debug/dnxcore50/"
+ },
+ "cwd": {
+ "type": "string",
+ "description": "Path to the working directory of the program being debugged. Default is the current workspace.",
+ "default": "${workspaceRoot}"
+ },
+ "args": {
+ "type": "array",
+ "description": "Command line arguments passed to the program.",
+ "items": { "type": "string" },
+ "default": [ ]
+ },
+ "stopAtEntry": {
+ "type": "boolean",
+ "description": "If true, the debugger should stop at the entry point of the target.",
+ "default": false
+ },
+ "launchBrowser": {
+ "type": "object",
+ "description": "Describes options to launch a web browser as part of launch",
+ "default": {
+ "enabled": true,
+ "args": "${auto-detect-url}",
+ "windows": {
+ "command": "cmd.exe",
+ "args": "/C start ${auto-detect-url}"
+ },
+ "osx": {
+ "command": "open"
+ },
+ "linux": {
+ "command": "xdg-open"
+ }
+ },
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "description": "Whether web browser launch is enabled",
+ "default": true
+ },
+ "args": {
+ "type": "string",
+ "description": "The arguments to pass to the command to open the browser. Use ${auto-detect-url} to automatically use the address the server is listening to",
+ "default": "${auto-detect-url}"
+ },
+ "osx": {
+ "type": "object",
+ "description": "OSX-specific web launch configuration options",
+ "default": {
+ "command": "open"
+ },
+ "properties": {
+ "command": {
+ "type": "string",
+ "description": "The command to execute for launching the web browser",
+ "default": "open"
+ },
+ "args": {
+ "type": "string",
+ "description": "The arguments to pass to the command to open the browser. Use ${auto-detect-url} to automatically use the address the server is listening to",
+ "default": "${auto-detect-url}"
+ }
+ }
+ },
+ "linux": {
+ "type": "object",
+ "description": "Linux-specific web launch configuration options",
+ "default": {
+ "command": "xdg-open"
+ },
+ "properties": {
+ "command": {
+ "type": "string",
+ "description": "The command to execute for launching the web browser",
+ "default": "xdg-open"
+ },
+ "args": {
+ "type": "string",
+ "description": "The arguments to pass to the command to open the browser. Use ${auto-detect-url} to automatically use the address the server is listening to",
+ "default": "${auto-detect-url}"
+ }
+ }
+ },
+ "windows": {
+ "type": "object",
+ "description": "Windows-specific web launch configuration options",
+ "default": {
+ "command": "cmd.exe",
+ "args": "/C start ${auto-detect-url}"
+ },
+ "properties": {
+ "command": {
+ "type": "string",
+ "description": "The command to execute for launching the web browser",
+ "default": "cmd.exe"
+ },
+ "args": {
+ "type": "string",
+ "description": "The arguments to pass to the command to open the browser. Use ${auto-detect-url} to automatically use the address the server is listening to",
+ "default": "/C start ${auto-detect-url}"
+ }
+ }
+ }
+ }
+ },
+ "sourceFileMap": {
+ "type": "object",
+ "description": "Optional source file mappings passed to the debug engine.",
+ "default": { }
+ },
+ "justMyCode": {
+ "type": "boolean",
+ "description": "Optional flag to only show user code.",
+ "default": true
+ },
+ "symbolPath": {
+ "type": "array",
+ "description": "Array of directories to use to search for .pdb files. These directories will be searched in addition to the default locations -- next to the module and the path where the pdb was originally dropped to. Example: '[ \"/Volumes/symbols\" ]",
+ "items": { "type": "string" },
+ "default": [ ]
+ }
+ }
+ },
+ "attach": {
+ "required": [ ],
+ "properties": {
+ "processName": {
+ "type": "string",
+ "description": "",
+ "default": "The process name to attach to. If this is used, 'processId' should not be used."
+ },
+ "processId": {
+ "type": "integer",
+ "description": "The process id to attach to. If this is used, 'processName' should not be used.",
+ "default": ""
+ },
+ "sourceFileMap": {
+ "type": "object",
+ "description": "Optional source file mappings passed to the debug engine.",
+ "default": { }
+ },
+ "justMyCode": {
+ "type": "boolean",
+ "description": "Optional flag to only show user code.",
+ "default": true
+ },
+ "symbolPath": {
+ "type": "array",
+ "description": "Array of directories to use to search for .pdb files. These directories will be searched in addition to the default locations -- next to the module and the path where the pdb was originally dropped to. Example: '[ \"~/symbols\" ]",
+ "items": { "type": "string" },
+ "default": [ ]
+ }
+ }
+ }
+ },
+
+ "initialConfigurations": [
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceRoot}/bin/Debug/dnxcore50/",
+ "args": [ ],
+ "cwd": "${workspaceRoot}",
+ "stopAtEntry": false,
+ "sourceFileMap": { }
+ },
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceRoot}/bin/Debug/dnxcore50/",
+ "args": [ ],
+ "cwd": "${workspaceRoot}",
+ "stopAtEntry": false,
+ "sourceFileMap": { },
+ "launchBrowser": {
+ "enabled": true,
+ "args": "${auto-detect-url}",
+ "windows": {
+ "command": "cmd.exe",
+ "args": "/C start ${auto-detect-url}"
+ },
+ "osx": {
+ "command": "open"
+ },
+ "linux": {
+ "command": "xdg-open"
+ }
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processName": "",
+ "sourceFileMap": { }
+ }
+ ]
+ }
]
}
}
\ No newline at end of file
diff --git a/src/coreclr-debug.ts b/src/coreclr-debug.ts
new file mode 100644
index 000000000..afa8e2a56
--- /dev/null
+++ b/src/coreclr-debug.ts
@@ -0,0 +1,174 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+'use strict';
+
+import * as vscode from 'vscode';
+import * as child_process from 'child_process';
+import * as fs from 'fs';
+import * as path from 'path';
+
+let _coreClrDebugDir: string;
+let _debugAdapterDir: string;
+let _channel: vscode.OutputChannel;
+let _installLog: NodeJS.WritableStream;
+const _completionFileName: string = 'install.complete';
+
+export function installCoreClrDebug(context: vscode.ExtensionContext) {
+ _coreClrDebugDir = path.join(context.extensionPath, 'coreclr-debug');
+ _debugAdapterDir = path.join(_coreClrDebugDir, 'debugAdapters');
+
+ if (existsSync(path.join(_debugAdapterDir, _completionFileName))) {
+ console.log('.NET Core Debugger tools already installed');
+ return;
+ }
+
+ _channel = vscode.window.createOutputChannel('coreclr-debug');
+
+ // Create our log file and override _channel.append to also outpu to the log
+ _installLog = fs.createWriteStream(path.join(_coreClrDebugDir, 'install.log'));
+ (function() {
+ var proxied = _channel.append;
+ _channel.append = function(val: string) {
+ _installLog.write(val);
+ proxied.apply(this, arguments);
+ };
+ })();
+
+ _channel.appendLine("Downloading and configuring the .NET Core Debugger...");
+ _channel.show(vscode.ViewColumn.Three);
+
+ spawnChildProcess('dotnet', ['--verbose', 'restore'], _channel, _coreClrDebugDir)
+ .then(function() {
+ return spawnChildProcess('dotnet', ['--verbose', 'publish', '-o', _debugAdapterDir], _channel, _coreClrDebugDir);
+ }).then(function() {
+ var promises: Promise[] = [];
+
+ promises.push(renameDummyEntrypoint());
+ promises.push(removeLibCoreClrTraceProvider());
+
+ return Promise.all(promises);
+ }).then(function() {
+ return writeCompletionFile();
+ }).then(function() {
+ _channel.appendLine('Succesfully installed .NET Core Debugger.');
+ })
+ .catch(function(error) {
+ _channel.appendLine('Error while installing .NET Core Debugger.');
+ console.log(error);
+ });
+}
+
+function writeCompletionFile() : Promise {
+ return new Promise(function(resolve, reject) {
+ fs.writeFile(path.join(_debugAdapterDir, _completionFileName), '', function(err) {
+ if (err) {
+ reject(err);
+ }
+ else {
+ resolve();
+ }
+ });
+ });
+}
+
+function renameDummyEntrypoint() : Promise {
+ var src = path.join(_debugAdapterDir, 'dummy');
+ var dest = path.join(_debugAdapterDir, 'OpenDebugAD7');
+
+ src += getPlatformExeExtension();
+ dest += getPlatformExeExtension();
+
+ var promise = new Promise(function(resolve, reject) {
+ fs.rename(src, dest, function(err) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+
+ return promise;
+}
+
+function removeLibCoreClrTraceProvider() : Promise
+{
+ var filePath = path.join(_debugAdapterDir, 'libcoreclrtraceptprovider' + getPlatformLibExtension());
+
+ if (!existsSync(filePath)) {
+ return Promise.resolve();
+ } else {
+ return new Promise(function(resolve, reject) {
+ fs.unlink(filePath, function(err) {
+ if (err) {
+ reject(err);
+ } else {
+ _channel.appendLine('Succesfully deleted ' + filePath);
+ resolve();
+ }
+ });
+ });
+ }
+}
+
+function existsSync(path: string) : boolean {
+ try {
+ fs.accessSync(path, fs.F_OK);
+ return true;
+ } catch (err) {
+ if (err.code === 'ENOENT') {
+ return false;
+ } else {
+ throw err;
+ }
+ }
+}
+
+function getPlatformExeExtension() : string {
+ if (process.platform === 'win32') {
+ return '.exe';
+ }
+
+ return '';
+}
+
+function getPlatformLibExtension() : string {
+ switch (process.platform) {
+ case 'win32':
+ return '.dll';
+ case 'darwin':
+ return '.dylib';
+ case 'linux':
+ return '.so';
+ default:
+ throw Error('Unsupported platform ' + process.platform);
+ }
+}
+
+function spawnChildProcess(process: string, args: string[], channel: vscode.OutputChannel, workingDirectory: string) : Promise {
+ var promise = new Promise( function (resolve, reject) {
+ const child = child_process.spawn(process, args, {cwd: workingDirectory});
+
+ child.stdout.on('data', (data) => {
+ channel.append(`${data}`);
+ });
+
+ child.stderr.on('data', (data) => {
+ channel.appendLine(`Error: ${data}`);
+ });
+
+ child.on('close', (code: number) => {
+ if (code != 0) {
+ channel.appendLine(`${process} exited with error code ${code}`);
+ reject(new Error(code.toString()));
+ }
+ else {
+ resolve();
+ }
+ });
+ });
+
+ return promise;
+}
\ No newline at end of file
diff --git a/src/omnisharpMain.ts b/src/omnisharpMain.ts
index 5c31ee507..6ce667295 100644
--- a/src/omnisharpMain.ts
+++ b/src/omnisharpMain.ts
@@ -24,6 +24,7 @@ import forwardChanges from './features/changeForwarding';
import reportStatus from './features/omnisharpStatus';
import findLaunchTargets from './launchTargetFinder';
import {Disposable, ExtensionContext, DocumentSelector, languages, extensions} from 'vscode';
+import {installCoreClrDebug} from './coreclr-debug';
export function activate(context: ExtensionContext): any {
@@ -75,6 +76,9 @@ export function activate(context: ExtensionContext): any {
advisor.dispose();
server.stop();
}));
+
+ // install coreclr-debug
+ installCoreClrDebug(context);
context.subscriptions.push(...disposables);
}
diff --git a/tsconfig.json b/tsconfig.json
index 73d8ec0fc..a6e763bd2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"noLib": true,
- "target": "ES5",
+ "target": "es5",
"module": "commonjs",
"outDir": "out",
"sourceMap": true