From 101758914cc369bf3f15366a2d558b21e448554e Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Mon, 2 May 2016 17:08:43 -0700 Subject: [PATCH 01/24] Add 'ASPNETCORE_ENVIRONMENT' to default ASP.NET launch options This checkin adds 'env' to the launch.json schema, and it adds a "ASPNETCORE_ENVIRONMENT=Development" environment variable by default. This completes the fix for https://github.com/OmniSharp/omnisharp-vscode/issues/172 --- package.json | 9 +++++++++ src/assets.ts | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e46ab38525..8e47d85fef 100644 --- a/package.json +++ b/package.json @@ -258,6 +258,12 @@ } } }, + "env": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment variables passed to the program.", + "default": { } + }, "sourceFileMap": { "type": "object", "description": "Optional source file mappings passed to the debug engine. Example: '{ \"C:\\foo\":\"/home/user/foo\" }'", @@ -349,6 +355,9 @@ "linux": { "command": "xdg-open" } + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" } }, { diff --git a/src/assets.ts b/src/assets.ts index b921a533ce..ca8085ebdd 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -24,7 +24,8 @@ interface ConsoleLaunchConfiguration extends DebugConfiguration { program: string, args: string[], cwd: string, - stopAtEntry: boolean + stopAtEntry: boolean, + env?: any } interface CommandLine { @@ -164,6 +165,9 @@ function createWebLaunchConfiguration(targetFramework: string, executableName: s linux: { command: 'xdg-open' } + }, + env: { + ASPNETCORE_ENVIRONMENT: "Development" } } } From 4c07ddbf362447ba6db10ec09adede25b00ff113 Mon Sep 17 00:00:00 2001 From: Chuck Ries Date: Fri, 20 May 2016 12:48:23 -0700 Subject: [PATCH 02/24] Update coreclr-debug packages for post rc2 work --- coreclr-debug/NuGet.config | 2 ++ package.json | 2 +- src/coreclr-debug/main.ts | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/coreclr-debug/NuGet.config b/coreclr-debug/NuGet.config index 5db080cb7d..53671d96c9 100644 --- a/coreclr-debug/NuGet.config +++ b/coreclr-debug/NuGet.config @@ -4,5 +4,7 @@ + + diff --git a/package.json b/package.json index 3bf121fce1..c08877bd35 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.0.11", + "version": "1.1.0", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index 6a44192d1e..36bf095b85 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -332,9 +332,9 @@ function createProjectJson(targetRuntime: string): any emitEntryPoint: true }, dependencies: { - "Microsoft.VisualStudio.clrdbg": "14.0.25229-preview-2963841", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30401-preview-1", - "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20405-preview-1", + "Microsoft.VisualStudio.clrdbg": "14.0.25320-preview-3008693", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30520-preview-9", + "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20520-preview-3", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1", "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1", From ce34735fa77dcd05e824e3fa95f74b3fdfe08a39 Mon Sep 17 00:00:00 2001 From: Rajkumar Janakiraman Date: Fri, 20 May 2016 15:09:08 -0700 Subject: [PATCH 03/24] Creating launch for web or console. It is a web application if it has any dependencies on microsoft.aspnetcore.server.* --- src/assets.ts | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/assets.ts b/src/assets.ts index b921a533ce..0b2785186e 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -177,14 +177,25 @@ function createAttachConfiguration(): AttachConfiguration { } } -function createLaunchJson(targetFramework: string, executableName: string): any { - return { - version: '0.2.0', - configurations: [ - createLaunchConfiguration(targetFramework, executableName), - createWebLaunchConfiguration(targetFramework, executableName), - createAttachConfiguration() - ] +function createLaunchJson(targetFramework: string, executableName: string, isWebProject: boolean): any { + let version = '0.2.0'; + if (!isWebProject) { + return { + version: version, + configurations: [ + createLaunchConfiguration(targetFramework, executableName), + createAttachConfiguration() + ] + } + } + else { + return { + version: version, + configurations: [ + createWebLaunchConfiguration(targetFramework, executableName), + createAttachConfiguration() + ] + } } } @@ -220,7 +231,24 @@ function addTasksJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, path }); } -function addLaunchJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, paths: Paths, operations: Operations) { +function hasWebServerDependency(projectJsonPath: string) { + let projectJson = fs.readFileSync(projectJsonPath, 'utf8'); + let projectJsonObject = JSON.parse(projectJson); + + if (projectJsonObject == null) { + return false; + } + + for (var key in projectJsonObject.dependencies) { + if (key.toLowerCase().startsWith("microsoft.aspnetcore.server")) { + return true; + } + } + + return false; +} + +function addLaunchJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, paths: Paths, operations: Operations, projectJsonPath: string) { return new Promise((resolve, reject) => { if (!operations.addLaunchJson) { return resolve(); @@ -248,7 +276,7 @@ function addLaunchJsonIfNecessary(info: protocol.DotNetWorkspaceInformation, pat } } - const launchJson = createLaunchJson(targetFramework, executableName); + const launchJson = createLaunchJson(targetFramework, executableName, hasWebServerDependency(projectJsonPath)); const launchJsonText = JSON.stringify(launchJson, null, ' '); return fs.writeFileAsync(paths.launchJsonPath, launchJsonText); @@ -284,7 +312,7 @@ export function addAssetsIfNecessary(server: OmnisharpServer) { return fs.ensureDirAsync(paths.vscodeFolder).then(() => { return Promise.all([ addTasksJsonIfNecessary(info.DotNet, paths, operations), - addLaunchJsonIfNecessary(info.DotNet, paths, operations) + addLaunchJsonIfNecessary(info.DotNet, paths, operations, projectJsonPath) ]); }); }); From b92e0b6ae22dc105b74456cd6456f9dd39fd8a34 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Wed, 25 May 2016 16:37:36 -0700 Subject: [PATCH 04/24] Add dotnet-test discovery and execution --- src/features/codeLensProvider.ts | 133 +++++---- src/features/commands.ts | 231 +++++++------- src/omnisharpUtils.ts | 7 + src/protocol.ts | 498 ++++++++++++++++--------------- 4 files changed, 469 insertions(+), 400 deletions(-) diff --git a/src/features/codeLensProvider.ts b/src/features/codeLensProvider.ts index 496b660d72..24661251e8 100644 --- a/src/features/codeLensProvider.ts +++ b/src/features/codeLensProvider.ts @@ -13,71 +13,80 @@ import * as serverUtils from '../omnisharpUtils'; class OmniSharpCodeLens extends CodeLens { - fileName: string; + fileName: string; - constructor(fileName: string, range: Range) { - super(range); - this.fileName = fileName; - } + constructor(fileName: string, range: Range) { + super(range); + this.fileName = fileName; + } } export default class OmniSharpCodeLensProvider extends AbstractSupport implements CodeLensProvider { - private static filteredSymbolNames: { [name: string]: boolean } = { - 'Equals': true, - 'Finalize': true, - 'GetHashCode': true, - 'ToString': true - }; - - provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable { - - return serverUtils.currentFileMembersAsTree(this._server, { Filename: document.fileName }, token).then(tree => { - let ret: CodeLens[] = []; - tree.TopLevelTypeDefinitions.forEach(node => OmniSharpCodeLensProvider._convertQuickFix(ret, document.fileName, node)); - return ret; - }); - } - - private static _convertQuickFix(bucket: CodeLens[], fileName:string, node: protocol.Node): void { - - if (node.Kind === 'MethodDeclaration' && OmniSharpCodeLensProvider.filteredSymbolNames[node.Location.Text]) { - return; - } - - let lens = new OmniSharpCodeLens(fileName, toRange(node.Location)); - bucket.push(lens); - - for (let child of node.ChildNodes) { - OmniSharpCodeLensProvider._convertQuickFix(bucket, fileName, child); - } - } - - resolveCodeLens(codeLens: CodeLens, token: CancellationToken): Thenable { - if (codeLens instanceof OmniSharpCodeLens) { - - let req = { - Filename: codeLens.fileName, - Line: codeLens.range.start.line + 1, - Column: codeLens.range.start.character + 1, - OnlyThisFile: false, - ExcludeDefinition: true - }; - - return serverUtils.findUsages(this._server, req, token).then(res => { - if (!res || !Array.isArray(res.QuickFixes)) { - return; - } - - let len = res.QuickFixes.length; - codeLens.command = { - title: len === 1 ? '1 reference' : `${len} references`, - command: 'editor.action.showReferences', - arguments: [Uri.file(req.Filename), codeLens.range.start, res.QuickFixes.map(toLocation)] - }; - - return codeLens; - }); - } - } + private static filteredSymbolNames: { [name: string]: boolean } = { + 'Equals': true, + 'Finalize': true, + 'GetHashCode': true, + 'ToString': true + }; + + provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable { + + return serverUtils.currentFileMembersAsTree(this._server, { Filename: document.fileName }, token).then(tree => { + let ret: CodeLens[] = []; + tree.TopLevelTypeDefinitions.forEach(node => OmniSharpCodeLensProvider._convertQuickFix(ret, document.fileName, node)); + return ret; + }); + } + + private static _convertQuickFix(bucket: CodeLens[], fileName: string, node: protocol.Node): void { + + if (node.Kind === 'MethodDeclaration' && OmniSharpCodeLensProvider.filteredSymbolNames[node.Location.Text]) { + return; + } + + let lens = new OmniSharpCodeLens(fileName, toRange(node.Location)); + bucket.push(lens); + + for (let child of node.ChildNodes) { + OmniSharpCodeLensProvider._convertQuickFix(bucket, fileName, child); + } + + let testFeature = node.Features.find(value => value.startsWith('XunitTestMethod')); + if (testFeature) { + // this test method has a test feature + let testMethod = testFeature.split(':')[1]; + + bucket.push(new CodeLens(toRange(node.Location), { title: "run test", command: 'dotnet.test.run', arguments: [testMethod, fileName] })); + bucket.push(new CodeLens(toRange(node.Location), { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); + } + } + + resolveCodeLens(codeLens: CodeLens, token: CancellationToken): Thenable { + if (codeLens instanceof OmniSharpCodeLens) { + + let req = { + Filename: codeLens.fileName, + Line: codeLens.range.start.line + 1, + Column: codeLens.range.start.character + 1, + OnlyThisFile: false, + ExcludeDefinition: true + }; + + return serverUtils.findUsages(this._server, req, token).then(res => { + if (!res || !Array.isArray(res.QuickFixes)) { + return; + } + + let len = res.QuickFixes.length; + codeLens.command = { + title: len === 1 ? '1 reference' : `${len} references`, + command: 'editor.action.showReferences', + arguments: [Uri.file(req.Filename), codeLens.range.start, res.QuickFixes.map(toLocation)] + }; + + return codeLens; + }); + } + } } diff --git a/src/features/commands.ts b/src/features/commands.ts index e3e71241b6..d9da712a41 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -17,130 +17,157 @@ import * as vscode from 'vscode'; let channel = vscode.window.createOutputChannel('.NET'); export default function registerCommands(server: OmnisharpServer, extensionPath: string) { - let d1 = vscode.commands.registerCommand('o.restart', () => server.restart()); - let d2 = vscode.commands.registerCommand('o.pickProjectAndStart', () => pickProjectAndStart(server)); - let d3 = vscode.commands.registerCommand('o.showOutput', () => server.getChannel().show(vscode.ViewColumn.Three)); - let d4 = vscode.commands.registerCommand('dotnet.restore', () => dotnetRestoreAllProjects(server)); - + let d1 = vscode.commands.registerCommand('o.restart', () => server.restart()); + let d2 = vscode.commands.registerCommand('o.pickProjectAndStart', () => pickProjectAndStart(server)); + let d3 = vscode.commands.registerCommand('o.showOutput', () => server.getChannel().show(vscode.ViewColumn.Three)); + let d4 = vscode.commands.registerCommand('dotnet.restore', () => dotnetRestoreAllProjects(server)); + // register empty handler for csharp.installDebugger // running the command activates the extension, which is all we need for installation to kickoff let d5 = vscode.commands.registerCommand('csharp.downloadDebugger', () => { }); - - return vscode.Disposable.from(d1, d2, d3, d4, d5); + + return vscode.Disposable.from(d1, d2, d3, d4, d5, + vscode.commands.registerCommand('dotnet.test.run', (testMethod, fileName) => runDotnetTest(testMethod, fileName, server)), + vscode.commands.registerCommand('dotnet.test.debug', (testMethod, fileName) => debugDotnetTest(testMethod, fileName, server))); +} + +// Run test through dotnet-test command. This function can be moved to a separate structure +function runDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { + vscode.window.showInformationMessage('run test! ' + testMethod + ' at ' + fileName); + serverUtils.runDotNetTest(server, { FileName: fileName, MethodName: testMethod }).then(response => { + vscode.window.showInformationMessage('Test ' + testMethod + response.Pass ? 'Passed' : 'Failed'); + }); +} + +// Run test through dotnet-test command with debugger attached +function debugDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { + serverUtils.getTestStartInfo(server, { FileName: fileName, MethodName: testMethod }).then(response => { + vscode.commands.executeCommand( + 'vscode.startDebug', { + "name": ".NET test launch", + "type": "coreclr", + "request": "launch", + "program": response.Executable, + "args": [response.Argument], + "cwd": "${workspaceRoot}", + "stopAtEntry": false + } + ); + }); } function pickProjectAndStart(server: OmnisharpServer) { - return findLaunchTargets().then(targets => { - - let currentPath = server.getSolutionPathOrFolder(); - if (currentPath) { - for (let target of targets) { - if (target.target.fsPath === currentPath) { - target.label = `\u2713 ${target.label}`; - } - } - } - - return vscode.window.showQuickPick(targets, { - matchOnDescription: true, - placeHolder: `Select 1 of ${targets.length} projects` - }).then(target => { - if (target) { - return server.restart(target.target.fsPath); - } - }); - }); + return findLaunchTargets().then(targets => { + + let currentPath = server.getSolutionPathOrFolder(); + if (currentPath) { + for (let target of targets) { + if (target.target.fsPath === currentPath) { + target.label = `\u2713 ${target.label}`; + } + } + } + + return vscode.window.showQuickPick(targets, { + matchOnDescription: true, + placeHolder: `Select 1 of ${targets.length} projects` + }).then(target => { + if (target) { + return server.restart(target.target.fsPath); + } + }); + }); } interface Command { - label: string; - description: string; - execute(): Thenable; + label: string; + description: string; + execute(): Thenable; } function projectsToCommands(projects: protocol.DotNetProject[]): Promise[] { - return projects.map(project => { - let projectDirectory = project.Path; - - return fs.lstatAsync(projectDirectory).then(stats => { - if (stats.isFile()) { - projectDirectory = path.dirname(projectDirectory); - } - - return { - label: `dotnet restore - (${project.Name || path.basename(project.Path)})`, - description: projectDirectory, - execute() { - return runDotnetRestore(projectDirectory); - } - }; - }); - }); + return projects.map(project => { + let projectDirectory = project.Path; + + return fs.lstatAsync(projectDirectory).then(stats => { + if (stats.isFile()) { + projectDirectory = path.dirname(projectDirectory); + } + + return { + label: `dotnet restore - (${project.Name || path.basename(project.Path)})`, + description: projectDirectory, + execute() { + return runDotnetRestore(projectDirectory); + } + }; + }); + }); } export function dotnetRestoreAllProjects(server: OmnisharpServer) { - if (!server.isRunning()) { - return Promise.reject('OmniSharp server is not running.'); - } - - return serverUtils.requestWorkspaceInformation(server).then(info => { - - if (!('DotNet in info') || info.DotNet.Projects.length < 1) { - return Promise.reject("No .NET Core projects found"); - } - - let commandPromises = projectsToCommands(info.DotNet.Projects); - - return Promise.all(commandPromises).then(commands => { - return vscode.window.showQuickPick(commands); - }).then(command => { - if (command) { - return command.execute(); - } - }); - }); + if (!server.isRunning()) { + return Promise.reject('OmniSharp server is not running.'); + } + + return serverUtils.requestWorkspaceInformation(server).then(info => { + + if (!('DotNet in info') || info.DotNet.Projects.length < 1) { + return Promise.reject("No .NET Core projects found"); + } + + let commandPromises = projectsToCommands(info.DotNet.Projects); + + return Promise.all(commandPromises).then(commands => { + return vscode.window.showQuickPick(commands); + }).then(command => { + if (command) { + return command.execute(); + } + }); + }); } export function dotnetRestoreForProject(server: OmnisharpServer, fileName: string) { - if (!server.isRunning()) { - return Promise.reject('OmniSharp server is not running.'); - } - - return serverUtils.requestWorkspaceInformation(server).then(info => { - - if (!('DotNet in info') || info.DotNet.Projects.length < 1) { - return Promise.reject("No .NET Core projects found"); - } - - let directory = path.dirname(fileName); - - for (let project of info.DotNet.Projects) { - if (project.Path === directory) { - return runDotnetRestore(directory, fileName); - } - } - }); + if (!server.isRunning()) { + return Promise.reject('OmniSharp server is not running.'); + } + + return serverUtils.requestWorkspaceInformation(server).then(info => { + + if (!('DotNet in info') || info.DotNet.Projects.length < 1) { + return Promise.reject("No .NET Core projects found"); + } + + let directory = path.dirname(fileName); + + for (let project of info.DotNet.Projects) { + if (project.Path === directory) { + return runDotnetRestore(directory, fileName); + } + } + }); } function runDotnetRestore(cwd: string, fileName?: string) { - return new Promise((resolve, reject) => { - channel.clear(); - channel.show(); - - let cmd = 'dotnet restore'; - if (fileName) { - cmd = `${cmd} "${fileName}"` - } - - return cp.exec(cmd, {cwd: cwd, env: process.env}, (err, stdout, stderr) => { - channel.append(stdout.toString()); - channel.append(stderr.toString()); - if (err) { - channel.append('ERROR: ' + err); - } - }); - }); + return new Promise((resolve, reject) => { + channel.clear(); + channel.show(); + + let cmd = 'dotnet restore'; + if (fileName) { + cmd = `${cmd} "${fileName}"` + } + + return cp.exec(cmd, { cwd: cwd, env: process.env }, (err, stdout, stderr) => { + channel.append(stdout.toString()); + channel.append(stderr.toString()); + if (err) { + channel.append('ERROR: ' + err); + } + }); + }); } \ No newline at end of file diff --git a/src/omnisharpUtils.ts b/src/omnisharpUtils.ts index 409a51e239..d8733cb688 100644 --- a/src/omnisharpUtils.ts +++ b/src/omnisharpUtils.ts @@ -73,3 +73,10 @@ export function updateBuffer(server: OmnisharpServer, request: protocol.UpdateBu return server.makeRequest(protocol.Requests.UpdateBuffer, request); } +export function getTestStartInfo(server: OmnisharpServer, request: protocol.GetTestStartInfoRequest) { + return server.makeRequest(protocol.Requests.GetTestStartInfo, request); +} + +export function runDotNetTest(server: OmnisharpServer, request: protocol.RunDotNetTestRequest) { + return server.makeRequest(protocol.Requests.RunDotNetTest, request); +} \ No newline at end of file diff --git a/src/protocol.ts b/src/protocol.ts index 959d05a17d..61ab87117b 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -23,16 +23,19 @@ export module Requests { export const RemoveFromProject = '/removefromproject'; export const Rename = '/rename'; export const RunCodeAction = '/runcodeaction'; - export const SignatureHelp = '/signatureHelp'; + export const SignatureHelp = '/signatureHelp'; export const TypeLookup = '/typelookup'; export const UpdateBuffer = '/updatebuffer'; + + export const GetTestStartInfo = '/getteststartinfo'; + export const RunDotNetTest = '/rundotnettest'; } export interface Request { - Filename: string; - Line?: number; - Column?: number; - Buffer?: string; + Filename: string; + Line?: number; + Column?: number; + Buffer?: string; Changes?: LinePositionSpanTextChange[]; } @@ -49,394 +52,417 @@ export interface UpdateBufferRequest extends Request { } export interface ChangeBufferRequest { - FileName: string; - StartLine: number; - StartColumn: number; - EndLine: number; - EndColumn: number; - NewText: string; + FileName: string; + StartLine: number; + StartColumn: number; + EndLine: number; + EndColumn: number; + NewText: string; } export interface AddToProjectRequest extends Request { - //? + //? } export interface RemoveFromProjectRequest extends Request { - //? + //? } export interface FindUsagesRequest extends Request { - // MaxWidth: number; ? - OnlyThisFile: boolean; - ExcludeDefinition: boolean; + // MaxWidth: number; ? + OnlyThisFile: boolean; + ExcludeDefinition: boolean; } export interface FindSymbolsRequest extends Request { - Filter: string; + Filter: string; } export interface FormatRequest extends Request { - ExpandTab: boolean; + ExpandTab: boolean; } export interface CodeActionRequest extends Request { - CodeAction: number; - WantsTextChanges?: boolean; - SelectionStartColumn?: number; - SelectionStartLine?: number; - SelectionEndColumn?: number; - SelectionEndLine?: number; + CodeAction: number; + WantsTextChanges?: boolean; + SelectionStartColumn?: number; + SelectionStartLine?: number; + SelectionEndColumn?: number; + SelectionEndLine?: number; } export interface FormatResponse { - Buffer: string; + Buffer: string; } export interface TextChange { - NewText: string; - StartLine: number; - StartColumn: number; - EndLine: number; - EndColumn: number; + NewText: string; + StartLine: number; + StartColumn: number; + EndLine: number; + EndColumn: number; } export interface FormatAfterKeystrokeRequest extends Request { - Character: string; + Character: string; } export interface FormatRangeRequest extends Request { - EndLine: number; - EndColumn: number; + EndLine: number; + EndColumn: number; } export interface FormatRangeResponse { - Changes: TextChange[]; + Changes: TextChange[]; } export interface ResourceLocation { - FileName: string; - Line: number; - Column: number; + FileName: string; + Line: number; + Column: number; } export interface Error { - Message: string; - Line: number; - Column: number; - EndLine: number; - EndColumn: number; - FileName: string; + Message: string; + Line: number; + Column: number; + EndLine: number; + EndColumn: number; + FileName: string; } export interface ErrorResponse { - Errors: Error[]; + Errors: Error[]; } export interface QuickFix { - LogLevel: string; - FileName: string; - Line: number; - Column: number; - EndLine: number; - EndColumn: number; - Text: string; - Projects: string[]; + LogLevel: string; + FileName: string; + Line: number; + Column: number; + EndLine: number; + EndColumn: number; + Text: string; + Projects: string[]; } export interface SymbolLocation extends QuickFix { - Kind: string; + Kind: string; } export interface QuickFixResponse { - QuickFixes: QuickFix[]; + QuickFixes: QuickFix[]; } export interface FindSymbolsResponse { - QuickFixes: SymbolLocation[]; + QuickFixes: SymbolLocation[]; } export interface TypeLookupRequest extends Request { - IncludeDocumentation: boolean; + IncludeDocumentation: boolean; } export interface TypeLookupResponse { - Type: string; - Documentation: string; + Type: string; + Documentation: string; } export interface RunCodeActionResponse { - Text: string; - Changes: TextChange[]; + Text: string; + Changes: TextChange[]; } export interface GetCodeActionsResponse { - CodeActions: string[]; + CodeActions: string[]; } export interface Node { - ChildNodes: Node[]; - Location: QuickFix; - Kind: string; + ChildNodes: Node[]; + Location: QuickFix; + Kind: string; + Features: string[]; } export interface CurrentFileMembersAsTreeResponse { - TopLevelTypeDefinitions: Node[]; + TopLevelTypeDefinitions: Node[]; } export interface AutoCompleteRequest extends Request { - WordToComplete: string; - WantDocumentationForEveryCompletionResult?: boolean; - WantImportableTypes?: boolean; - WantMethodHeader?: boolean; - WantSnippet?: boolean; - WantReturnType?: boolean; - WantKind?: boolean; + WordToComplete: string; + WantDocumentationForEveryCompletionResult?: boolean; + WantImportableTypes?: boolean; + WantMethodHeader?: boolean; + WantSnippet?: boolean; + WantReturnType?: boolean; + WantKind?: boolean; } export interface AutoCompleteResponse { - CompletionText: string; - Description: string; - DisplayText: string; - RequiredNamespaceImport: string; - MethodHeader: string; - ReturnType: string; - Snippet: string; - Kind: string; + CompletionText: string; + Description: string; + DisplayText: string; + RequiredNamespaceImport: string; + MethodHeader: string; + ReturnType: string; + Snippet: string; + Kind: string; } export interface ProjectInformationResponse { - MsBuildProject: MSBuildProject; - DnxProject: DnxProject; + MsBuildProject: MSBuildProject; + DnxProject: DnxProject; } export interface WorkspaceInformationResponse { - MsBuild: MsBuildWorkspaceInformation; - Dnx: DnxWorkspaceInformation; + MsBuild: MsBuildWorkspaceInformation; + Dnx: DnxWorkspaceInformation; DotNet: DotNetWorkspaceInformation; - ScriptCs: ScriptCsContext; + ScriptCs: ScriptCsContext; } export interface MsBuildWorkspaceInformation { - SolutionPath: string; - Projects: MSBuildProject[]; + SolutionPath: string; + Projects: MSBuildProject[]; } export interface ScriptCsContext { - CsxFiles: { [n: string]: string }; - References: { [n: string]: string }; - Usings: { [n: string]: string }; - ScriptPacks: { [n: string]: string }; - Path: string; + CsxFiles: { [n: string]: string }; + References: { [n: string]: string }; + Usings: { [n: string]: string }; + ScriptPacks: { [n: string]: string }; + Path: string; } export interface MSBuildProject { - ProjectGuid: string; - Path: string; - AssemblyName: string; - TargetPath: string; - TargetFramework: string; - SourceFiles: string[]; + ProjectGuid: string; + Path: string; + AssemblyName: string; + TargetPath: string; + TargetFramework: string; + SourceFiles: string[]; } export interface DnxWorkspaceInformation { - RuntimePath: string; - DesignTimeHostPort: number; - Projects: DnxProject[]; + RuntimePath: string; + DesignTimeHostPort: number; + Projects: DnxProject[]; } export interface DnxProject { - Path: string; - Name: string; - Commands: { [name: string]: string; }; - Configurations: string[]; - ProjectSearchPaths: string[]; - Frameworks: DnxFramework[]; - GlobalJsonPath: string; - SourceFiles: string[]; + Path: string; + Name: string; + Commands: { [name: string]: string; }; + Configurations: string[]; + ProjectSearchPaths: string[]; + Frameworks: DnxFramework[]; + GlobalJsonPath: string; + SourceFiles: string[]; } export interface DnxFramework { - Name: string; - FriendlyName: string; - ShortName: string; + Name: string; + FriendlyName: string; + ShortName: string; } export interface DotNetWorkspaceInformation { - Projects: DotNetProject[]; - RuntimePath: string; + Projects: DotNetProject[]; + RuntimePath: string; } export interface DotNetProject { - Path: string; - Name: string; - ProjectSearchPaths: string[]; - Configurations: DotNetConfiguration[]; - Frameworks: DotNetFramework[]; - SourceFiles: string[]; + Path: string; + Name: string; + ProjectSearchPaths: string[]; + Configurations: DotNetConfiguration[]; + Frameworks: DotNetFramework[]; + SourceFiles: string[]; } export interface DotNetConfiguration { - Name: string; - CompilationOutputPath: string; - CompilationOutputAssemblyFile: string; - CompilationOutputPdbFile: string; - EmitEntryPoint?: boolean; + Name: string; + CompilationOutputPath: string; + CompilationOutputAssemblyFile: string; + CompilationOutputPdbFile: string; + EmitEntryPoint?: boolean; } export interface DotNetFramework { - Name: string; - FriendlyName: string; - ShortName: string; + Name: string; + FriendlyName: string; + ShortName: string; } export interface RenameRequest extends Request { - RenameTo: string; - WantsTextChanges?: boolean; + RenameTo: string; + WantsTextChanges?: boolean; } export interface ModifiedFileResponse { - FileName: string; - Buffer: string; - Changes: TextChange[]; + FileName: string; + Buffer: string; + Changes: TextChange[]; } export interface RenameResponse { - Changes: ModifiedFileResponse[]; + Changes: ModifiedFileResponse[]; } export interface SignatureHelp { - Signatures: SignatureHelpItem[]; - ActiveSignature: number; - ActiveParameter: number; + Signatures: SignatureHelpItem[]; + ActiveSignature: number; + ActiveParameter: number; } export interface SignatureHelpItem { - Name: string; - Label: string; - Documentation: string; - Parameters: SignatureHelpParameter[]; + Name: string; + Label: string; + Documentation: string; + Parameters: SignatureHelpParameter[]; } export interface SignatureHelpParameter { - Name: string; - Label: string; - Documentation: string; + Name: string; + Label: string; + Documentation: string; } export interface MSBuildProjectDiagnostics { - FileName: string; - Warnings: MSBuildDiagnosticsMessage[]; - Errors: MSBuildDiagnosticsMessage[]; + FileName: string; + Warnings: MSBuildDiagnosticsMessage[]; + Errors: MSBuildDiagnosticsMessage[]; } export interface MSBuildDiagnosticsMessage { - LogLevel: string; - FileName: string; - Text: string; - StartLine: number; - StartColumn: number; - EndLine: number; - EndColumn: number; + LogLevel: string; + FileName: string; + Text: string; + StartLine: number; + StartColumn: number; + EndLine: number; + EndColumn: number; } export interface ErrorMessage { - Text: string; - FileName: string; - Line: number; - Column: number; + Text: string; + FileName: string; + Line: number; + Column: number; } export interface PackageRestoreMessage { - FileName: string; - Succeeded: boolean; + FileName: string; + Succeeded: boolean; } export interface UnresolvedDependenciesMessage { - FileName: string; - UnresolvedDependencies: PackageDependency[]; + FileName: string; + UnresolvedDependencies: PackageDependency[]; } export interface PackageDependency { - Name: string; - Version: string; + Name: string; + Version: string; } export namespace V2 { - + export module Requests { export const GetCodeActions = '/v2/getcodeactions'; export const RunCodeAction = '/v2/runcodeaction'; } - export interface Point { - Line: number; - Column: number; - } - - export interface Range { - Start: Point; - End: Point; - } - - export interface GetCodeActionsRequest extends Request { - Selection: Range; - } - - export interface OmniSharpCodeAction { - Identifier: string; - Name: string; - } - - export interface GetCodeActionsResponse { - CodeActions: OmniSharpCodeAction[]; - } - - export interface RunCodeActionRequest extends Request { - Identifier: string; - Selection: Range; - WantsTextChanges: boolean; - } - - export interface RunCodeActionResponse { - Changes: ModifiedFileResponse[]; - } - - - export interface MSBuildProjectDiagnostics { - FileName: string; - Warnings: MSBuildDiagnosticsMessage[]; - Errors: MSBuildDiagnosticsMessage[]; - } - - export interface MSBuildDiagnosticsMessage { - LogLevel: string; - FileName: string; - Text: string; - StartLine: number; - StartColumn: number; - EndLine: number; - EndColumn: number; - } - - export interface ErrorMessage { - Text: string; - FileName: string; - Line: number; - Column: number; - } - - export interface PackageRestoreMessage { - FileName: string; - Succeeded: boolean; - } - - export interface UnresolvedDependenciesMessage { - FileName: string; - UnresolvedDependencies: PackageDependency[]; - } - - export interface PackageDependency { - Name: string; - Version: string; - } + export interface Point { + Line: number; + Column: number; + } + + export interface Range { + Start: Point; + End: Point; + } + + export interface GetCodeActionsRequest extends Request { + Selection: Range; + } + + export interface OmniSharpCodeAction { + Identifier: string; + Name: string; + } + + export interface GetCodeActionsResponse { + CodeActions: OmniSharpCodeAction[]; + } + + export interface RunCodeActionRequest extends Request { + Identifier: string; + Selection: Range; + WantsTextChanges: boolean; + } + + export interface RunCodeActionResponse { + Changes: ModifiedFileResponse[]; + } + + + export interface MSBuildProjectDiagnostics { + FileName: string; + Warnings: MSBuildDiagnosticsMessage[]; + Errors: MSBuildDiagnosticsMessage[]; + } + + export interface MSBuildDiagnosticsMessage { + LogLevel: string; + FileName: string; + Text: string; + StartLine: number; + StartColumn: number; + EndLine: number; + EndColumn: number; + } + + export interface ErrorMessage { + Text: string; + FileName: string; + Line: number; + Column: number; + } + + export interface PackageRestoreMessage { + FileName: string; + Succeeded: boolean; + } + + export interface UnresolvedDependenciesMessage { + FileName: string; + UnresolvedDependencies: PackageDependency[]; + } + + export interface PackageDependency { + Name: string; + Version: string; + } +} + +// dotnet-test endpoints + +export interface GetTestStartInfoRequest { + FileName: string; + MethodName: string; +} + +export interface GetTestStartInfoResponse { + Executable: string; + Argument: string; +} + +export interface RunDotNetTestRequest { + FileName: string; + MethodName: string; +} + +export interface RunDotNetTestResponse { + Failure: string; + Pass: boolean; } \ No newline at end of file From 7193f187aae2be9dfdc5ca5d2950fdde6e709a01 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Wed, 25 May 2016 22:13:10 -0700 Subject: [PATCH 05/24] split arguments to prevent long argument issue --- src/features/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/commands.ts b/src/features/commands.ts index d9da712a41..34c20ecd75 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -48,7 +48,7 @@ function debugDotnetTest(testMethod: string, fileName: string, server: Omnisharp "type": "coreclr", "request": "launch", "program": response.Executable, - "args": [response.Argument], + "args": response.Argument.split(' '), "cwd": "${workspaceRoot}", "stopAtEntry": false } From fe2e7a48c8790e1494e1356f030ab247795bccd6 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 26 May 2016 00:19:51 -0700 Subject: [PATCH 06/24] test result feedback --- src/features/commands.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/features/commands.ts b/src/features/commands.ts index 34c20ecd75..224e5ae023 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -33,9 +33,13 @@ export default function registerCommands(server: OmnisharpServer, extensionPath: // Run test through dotnet-test command. This function can be moved to a separate structure function runDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { - vscode.window.showInformationMessage('run test! ' + testMethod + ' at ' + fileName); serverUtils.runDotNetTest(server, { FileName: fileName, MethodName: testMethod }).then(response => { - vscode.window.showInformationMessage('Test ' + testMethod + response.Pass ? 'Passed' : 'Failed'); + if (response.Pass) { + vscode.window.showInformationMessage('Test passed'); + } + else { + vscode.window.showErrorMessage('Test failed'); + } }); } From 0302243db195c2120965f4dc548faa62c9490845 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 26 May 2016 11:21:24 -0700 Subject: [PATCH 07/24] move dotnet test logic to its own file --- src/features/commands.ts | 34 ++--------------------- src/features/dotnetTest.ts | 57 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 src/features/dotnetTest.ts diff --git a/src/features/commands.ts b/src/features/commands.ts index 224e5ae023..881aac806c 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -13,6 +13,7 @@ import * as fs from 'fs-extra-promise'; import * as path from 'path'; import * as protocol from '../protocol'; import * as vscode from 'vscode'; +import * as dotnetTest from './dotnetTest' let channel = vscode.window.createOutputChannel('.NET'); @@ -27,37 +28,8 @@ export default function registerCommands(server: OmnisharpServer, extensionPath: let d5 = vscode.commands.registerCommand('csharp.downloadDebugger', () => { }); return vscode.Disposable.from(d1, d2, d3, d4, d5, - vscode.commands.registerCommand('dotnet.test.run', (testMethod, fileName) => runDotnetTest(testMethod, fileName, server)), - vscode.commands.registerCommand('dotnet.test.debug', (testMethod, fileName) => debugDotnetTest(testMethod, fileName, server))); -} - -// Run test through dotnet-test command. This function can be moved to a separate structure -function runDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { - serverUtils.runDotNetTest(server, { FileName: fileName, MethodName: testMethod }).then(response => { - if (response.Pass) { - vscode.window.showInformationMessage('Test passed'); - } - else { - vscode.window.showErrorMessage('Test failed'); - } - }); -} - -// Run test through dotnet-test command with debugger attached -function debugDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { - serverUtils.getTestStartInfo(server, { FileName: fileName, MethodName: testMethod }).then(response => { - vscode.commands.executeCommand( - 'vscode.startDebug', { - "name": ".NET test launch", - "type": "coreclr", - "request": "launch", - "program": response.Executable, - "args": response.Argument.split(' '), - "cwd": "${workspaceRoot}", - "stopAtEntry": false - } - ); - }); + dotnetTest.registerDotNetTestRunCommand(server), + dotnetTest.registerDotNetTestDebugCommand(server)); } function pickProjectAndStart(server: OmnisharpServer) { diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts new file mode 100644 index 0000000000..26b0e86c7e --- /dev/null +++ b/src/features/dotnetTest.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * 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 {OmnisharpServer} from '../omnisharpServer'; +import * as vscode from 'vscode'; +import * as serverUtils from "../omnisharpUtils"; + +export function registerDotNetTestRunCommand(server: OmnisharpServer): vscode.Disposable { + return vscode.commands.registerCommand( + 'dotnet.test.run', + (testMethod, fileName) => runDotnetTest(testMethod, fileName, server)); +} + +export function registerDotNetTestDebugCommand(server: OmnisharpServer): vscode.Disposable { + return vscode.commands.registerCommand( + 'dotnet.test.debug', + (testMethod, fileName) => debugDotnetTest(testMethod, fileName, server)); +} + +// Run test through dotnet-test command. This function can be moved to a separate structure +export function runDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { + serverUtils + .runDotNetTest(server, { FileName: fileName, MethodName: testMethod }) + .then( + response => { + if (response.Pass) { + vscode.window.showInformationMessage('Test passed'); + } + else { + vscode.window.showErrorMessage('Test failed'); + } + }, + reason => { + vscode.window.showErrorMessage('Fail to run test because ' + reason + '.'); + }); +} + +// Run test through dotnet-test command with debugger attached +export function debugDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { + serverUtils.getTestStartInfo(server, { FileName: fileName, MethodName: testMethod }).then(response => { + vscode.commands.executeCommand( + 'vscode.startDebug', { + "name": ".NET test launch", + "type": "coreclr", + "request": "launch", + "program": response.Executable, + "args": response.Argument.split(' '), + "cwd": "${workspaceRoot}", + "stopAtEntry": false + } + ).then(undefined, reason => { vscode.window.showErrorMessage('Failed to debug test because ' + reason + '.') }); + }); +} \ No newline at end of file From 1efd3b41edf69b16c232e954b77630e13d2a74cd Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 26 May 2016 11:42:00 -0700 Subject: [PATCH 08/24] move code from codelens provider to dotnetTest --- src/features/codeLensProvider.ts | 10 ++-------- src/features/dotnetTest.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/features/codeLensProvider.ts b/src/features/codeLensProvider.ts index 24661251e8..fe421daedb 100644 --- a/src/features/codeLensProvider.ts +++ b/src/features/codeLensProvider.ts @@ -8,6 +8,7 @@ import {CancellationToken, CodeLens, Range, Uri, TextDocument, CodeLensProvider} from 'vscode'; import {toRange, toLocation} from '../typeConvertion'; import AbstractSupport from './abstractProvider'; +import {updateCodeLensForTest} from './dotnetTest'; import * as protocol from '../protocol'; import * as serverUtils from '../omnisharpUtils'; @@ -52,14 +53,7 @@ export default class OmniSharpCodeLensProvider extends AbstractSupport implement OmniSharpCodeLensProvider._convertQuickFix(bucket, fileName, child); } - let testFeature = node.Features.find(value => value.startsWith('XunitTestMethod')); - if (testFeature) { - // this test method has a test feature - let testMethod = testFeature.split(':')[1]; - - bucket.push(new CodeLens(toRange(node.Location), { title: "run test", command: 'dotnet.test.run', arguments: [testMethod, fileName] })); - bucket.push(new CodeLens(toRange(node.Location), { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); - } + updateCodeLensForTest(bucket, fileName, node); } resolveCodeLens(codeLens: CodeLens, token: CancellationToken): Thenable { diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts index 26b0e86c7e..3883add22f 100644 --- a/src/features/dotnetTest.ts +++ b/src/features/dotnetTest.ts @@ -6,8 +6,10 @@ 'use strict'; import {OmnisharpServer} from '../omnisharpServer'; +import {toRange} from '../typeConvertion'; import * as vscode from 'vscode'; import * as serverUtils from "../omnisharpUtils"; +import * as protocol from '../protocol'; export function registerDotNetTestRunCommand(server: OmnisharpServer): vscode.Disposable { return vscode.commands.registerCommand( @@ -54,4 +56,20 @@ export function debugDotnetTest(testMethod: string, fileName: string, server: Om } ).then(undefined, reason => { vscode.window.showErrorMessage('Failed to debug test because ' + reason + '.') }); }); +} + +export function updateCodeLensForTest(bucket: vscode.CodeLens[], fileName: string, node: protocol.Node) { + let testFeature = node.Features.find(value => value.startsWith('XunitTestMethod')); + if (testFeature) { + // this test method has a test feature + let testMethod = testFeature.split(':')[1]; + + bucket.push(new vscode.CodeLens( + toRange(node.Location), + { title: "run test", command: 'dotnet.test.run', arguments: [testMethod, fileName] })); + + bucket.push(new vscode.CodeLens( + toRange(node.Location), + { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); + } } \ No newline at end of file From 60e9de7c9dd6ce4b78567ac806b5cd4d44de19b0 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Thu, 26 May 2016 12:03:12 -0700 Subject: [PATCH 09/24] disable debug trigger if startDebug command doesn't exist --- src/features/dotnetTest.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts index 3883add22f..4ccfd64ef8 100644 --- a/src/features/dotnetTest.ts +++ b/src/features/dotnetTest.ts @@ -11,6 +11,15 @@ import * as vscode from 'vscode'; import * as serverUtils from "../omnisharpUtils"; import * as protocol from '../protocol'; +let enableDebug = false; + +// check if debugger start is enable +vscode.commands.getCommands().then(commands => { + if (commands.find(c => c == "vscode.startDebug")) { + enableDebug = true; + } +}); + export function registerDotNetTestRunCommand(server: OmnisharpServer): vscode.Disposable { return vscode.commands.registerCommand( 'dotnet.test.run', @@ -54,7 +63,11 @@ export function debugDotnetTest(testMethod: string, fileName: string, server: Om "cwd": "${workspaceRoot}", "stopAtEntry": false } - ).then(undefined, reason => { vscode.window.showErrorMessage('Failed to debug test because ' + reason + '.') }); + ).then( + response => { + vscode.window.showInformationMessage('call back from debugger start command') + }, + reason => { vscode.window.showErrorMessage('Failed to debug test because ' + reason + '.') }); }); } @@ -68,8 +81,10 @@ export function updateCodeLensForTest(bucket: vscode.CodeLens[], fileName: strin toRange(node.Location), { title: "run test", command: 'dotnet.test.run', arguments: [testMethod, fileName] })); - bucket.push(new vscode.CodeLens( - toRange(node.Location), - { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); + if (enableDebug) { + bucket.push(new vscode.CodeLens( + toRange(node.Location), + { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); + } } } \ No newline at end of file From ca485c8ca080d6cf85356b267a11b1c656ecb8ee Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Fri, 27 May 2016 11:43:37 -0700 Subject: [PATCH 10/24] Update endpoint names for test scenarios --- src/protocol.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocol.ts b/src/protocol.ts index 61ab87117b..72eb608582 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -27,8 +27,8 @@ export module Requests { export const TypeLookup = '/typelookup'; export const UpdateBuffer = '/updatebuffer'; - export const GetTestStartInfo = '/getteststartinfo'; - export const RunDotNetTest = '/rundotnettest'; + export const GetTestStartInfo = '/v2/getteststartinfo'; + export const RunDotNetTest = '/v2/runtest'; } export interface Request { From 7de84082636f75021977b95a79f67565d4cb1ec1 Mon Sep 17 00:00:00 2001 From: Rajkumar Janakiraman Date: Fri, 27 May 2016 13:25:26 -0700 Subject: [PATCH 11/24] Schema for pipe transport options. (#376) * Schema for pipe transport options. * Incorporating code review comments. * Updating package dependency for OpenDebugAD7. * Updating the version of MIEngine. --- coreclr-debug/NuGet.config | 2 +- package.json | 92 ++++++++++++++++++++++++++++++++++++++ src/coreclr-debug/main.ts | 4 +- 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/coreclr-debug/NuGet.config b/coreclr-debug/NuGet.config index 53671d96c9..045c4497c2 100644 --- a/coreclr-debug/NuGet.config +++ b/coreclr-debug/NuGet.config @@ -5,6 +5,6 @@ - + diff --git a/package.json b/package.json index 48d3a70bef..df5474976a 100644 --- a/package.json +++ b/package.json @@ -288,6 +288,98 @@ "type": "string" }, "default": [] + }, + "pipeTransport": { + "type": "object", + "description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the .NET Core debugger backend executable (clrdbg).", + "default": { + "pipeProgram": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'", + "pipeArgs": [] + }, + "properties" : { + "pipeProgram": { + "type": "string", + "description": "The fully qualified pipe command to execute.", + "default": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'" + }, + "pipeArgs": { + "type": "array", + "description": "Command line arguments passed to the pipe program.", + "items": { + "type": "string" + }, + "default": [] + }, + "windows": { + "type": "object", + "description": "Windows-specific pipe launch configuration options", + "default": { + "pipeProgram": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'", + "pipeArgs": [] + }, + "properties": { + "pipeProgram": { + "type": "string", + "description": "The fully qualified pipe command to execute.", + "default": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'" + }, + "pipeArgs": { + "type": "array", + "description": "Command line arguments passed to the pipe program.", + "items": { + "type": "string" + }, + "default": [] + } + } + }, + "osx": { + "type": "object", + "description": "OSX-specific pipe launch configuration options", + "default": { + "pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'", + "pipeArgs": [] + }, + "properties": { + "pipeProgram": { + "type": "string", + "description": "The fully qualified pipe command to execute.", + "default": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'" + }, + "pipeArgs": { + "type": "array", + "description": "Command line arguments passed to the pipe program.", + "items": { + "type": "string" + }, + "default": [] + } + } + }, + "linux": { + "type": "object", + "description": "Linux-specific pipe launch configuration options", + "default": { + "pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'", + "pipeArgs": [] + }, + "properties": { + "pipeProgram": { + "type": "string", + "description": "The fully qualified pipe command to execute.", + "default": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'" + }, + "pipeArgs": { + "type": "array", + "description": "Command line arguments passed to the pipe program.", + "items": { + "type": "string" + }, + "default": [] + } + } + } + } } } }, diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index 36bf095b85..e0c45ff228 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -333,8 +333,8 @@ function createProjectJson(targetRuntime: string): any }, dependencies: { "Microsoft.VisualStudio.clrdbg": "14.0.25320-preview-3008693", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30520-preview-9", - "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20520-preview-3", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30527-preview-1", + "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20527-preview-1", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1", "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1", From bc3222cbbe9ff640060d29f1f9bbab24f56c0511 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Fri, 27 May 2016 17:11:12 -0700 Subject: [PATCH 12/24] Move isDebugEnable switch into OmniSharpServer --- src/features/codeLensProvider.ts | 10 ++-- src/features/dotnetTest.ts | 31 +++++------- src/omnisharpServer.ts | 86 ++++++++++++++++++-------------- src/protocol.ts | 7 ++- 4 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/features/codeLensProvider.ts b/src/features/codeLensProvider.ts index fe421daedb..1c24c1e1bd 100644 --- a/src/features/codeLensProvider.ts +++ b/src/features/codeLensProvider.ts @@ -32,15 +32,15 @@ export default class OmniSharpCodeLensProvider extends AbstractSupport implement }; provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable { - + let request = { Filename: document.fileName }; return serverUtils.currentFileMembersAsTree(this._server, { Filename: document.fileName }, token).then(tree => { let ret: CodeLens[] = []; - tree.TopLevelTypeDefinitions.forEach(node => OmniSharpCodeLensProvider._convertQuickFix(ret, document.fileName, node)); + tree.TopLevelTypeDefinitions.forEach(node => this._convertQuickFix(ret, document.fileName, node)); return ret; }); } - private static _convertQuickFix(bucket: CodeLens[], fileName: string, node: protocol.Node): void { + private _convertQuickFix(bucket: CodeLens[], fileName: string, node: protocol.Node): void { if (node.Kind === 'MethodDeclaration' && OmniSharpCodeLensProvider.filteredSymbolNames[node.Location.Text]) { return; @@ -50,10 +50,10 @@ export default class OmniSharpCodeLensProvider extends AbstractSupport implement bucket.push(lens); for (let child of node.ChildNodes) { - OmniSharpCodeLensProvider._convertQuickFix(bucket, fileName, child); + this._convertQuickFix(bucket, fileName, child); } - updateCodeLensForTest(bucket, fileName, node); + updateCodeLensForTest(bucket, fileName, node, this._server.isDebugEnable()); } resolveCodeLens(codeLens: CodeLens, token: CancellationToken): Thenable { diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts index 4ccfd64ef8..3060c00803 100644 --- a/src/features/dotnetTest.ts +++ b/src/features/dotnetTest.ts @@ -11,15 +11,6 @@ import * as vscode from 'vscode'; import * as serverUtils from "../omnisharpUtils"; import * as protocol from '../protocol'; -let enableDebug = false; - -// check if debugger start is enable -vscode.commands.getCommands().then(commands => { - if (commands.find(c => c == "vscode.startDebug")) { - enableDebug = true; - } -}); - export function registerDotNetTestRunCommand(server: OmnisharpServer): vscode.Disposable { return vscode.commands.registerCommand( 'dotnet.test.run', @@ -64,27 +55,29 @@ export function debugDotnetTest(testMethod: string, fileName: string, server: Om "stopAtEntry": false } ).then( - response => { - vscode.window.showInformationMessage('call back from debugger start command') - }, - reason => { vscode.window.showErrorMessage('Failed to debug test because ' + reason + '.') }); + response => { }, + reason => { vscode.window.showErrorMessage('Failed to start debugger on test because ' + reason + '.') }); }); } -export function updateCodeLensForTest(bucket: vscode.CodeLens[], fileName: string, node: protocol.Node) { - let testFeature = node.Features.find(value => value.startsWith('XunitTestMethod')); +export function updateCodeLensForTest(bucket: vscode.CodeLens[], fileName: string, node: protocol.Node, isDebugEnable: boolean) { + // backward compatible check: Features property doesn't present on older version OmniSharp + if (node.Features == undefined) { + return; + } + + let testFeature = node.Features.find(value => value.Name == 'XunitTestMethod'); if (testFeature) { // this test method has a test feature - let testMethod = testFeature.split(':')[1]; bucket.push(new vscode.CodeLens( toRange(node.Location), - { title: "run test", command: 'dotnet.test.run', arguments: [testMethod, fileName] })); + { title: "run test", command: 'dotnet.test.run', arguments: [testFeature.Data, fileName] })); - if (enableDebug) { + if (isDebugEnable) { bucket.push(new vscode.CodeLens( toRange(node.Location), - { title: "debug test", command: 'dotnet.test.debug', arguments: [testMethod, fileName] })); + { title: "debug test", command: 'dotnet.test.debug', arguments: [testFeature.Data, fileName] })); } } } \ No newline at end of file diff --git a/src/omnisharpServer.ts b/src/omnisharpServer.ts index 96d6c946e1..33bf072240 100644 --- a/src/omnisharpServer.ts +++ b/src/omnisharpServer.ts @@ -14,6 +14,7 @@ import {Disposable, CancellationToken, OutputChannel, workspace, window} from 'v import {ErrorMessage, UnresolvedDependenciesMessage, MSBuildProjectDiagnostics, ProjectInformationResponse} from './protocol'; import getLaunchTargets, {LaunchTarget} from './launchTargetFinder'; import TelemetryReporter from 'vscode-extension-telemetry'; +import * as vscode from 'vscode' enum ServerState { Starting, @@ -31,29 +32,29 @@ interface Request { module Events { export const StateChanged = 'stateChanged'; - + export const StdOut = 'stdout'; export const StdErr = 'stderr'; - + export const Error = 'Error'; export const ServerError = 'ServerError'; - + export const UnresolvedDependencies = 'UnresolvedDependencies'; export const PackageRestoreStarted = 'PackageRestoreStarted'; export const PackageRestoreFinished = 'PackageRestoreFinished'; - + export const ProjectChanged = 'ProjectChanged'; export const ProjectAdded = 'ProjectAdded'; export const ProjectRemoved = 'ProjectRemoved'; - + export const MsBuildProjectDiagnostics = 'MsBuildProjectDiagnostics'; - + export const BeforeServerStart = 'BeforeServerStart'; export const ServerStart = 'ServerStart'; export const ServerStop = 'ServerStop'; - + export const MultipleLaunchTargets = 'server:MultipleLaunchTargets'; - + export const Started = 'started'; } @@ -65,7 +66,7 @@ class Delays { idleDelays: number = 0; // 501-1500 milliseconds nonFocusDelays: number = 0; // 1501-3000 milliseconds bigDelays: number = 0; // 3000+ milliseconds - + public report(elapsedTime: number) { if (elapsedTime <= 25) { this.immediateDelays += 1; @@ -89,8 +90,8 @@ class Delays { this.bigDelays += 1; } } - - public toMeasures(): {[key: string]: number} { + + public toMeasures(): { [key: string]: number } { return { immedateDelays: this.immediateDelays, nearImmediateDelays: this.nearImmediateDelays, @@ -115,6 +116,8 @@ export abstract class OmnisharpServer { private _isProcessingQueue = false; private _channel: OutputChannel; + private _isDebugEnable: boolean = false; + protected _serverProcess: ChildProcess; protected _extraArgv: string[]; @@ -132,28 +135,28 @@ export abstract class OmnisharpServer { return this._state; } - private _setState(value: ServerState) : void { + private _setState(value: ServerState): void { if (typeof value !== 'undefined' && value !== this._state) { this._state = value; this._fireEvent(Events.StateChanged, this._state); } } - + private _recordRequestDelay(requestName: string, elapsedTime: number) { let delays = this._requestDelays[requestName]; if (!delays) { delays = new Delays(); this._requestDelays[requestName] = delays; } - + delays.report(elapsedTime); } - + public reportAndClearTelemetry() { for (var path in this._requestDelays) { const eventName = 'omnisharp' + path; const measures = this._requestDelays[path].toMeasures(); - + this._reporter.sendTelemetryEvent(eventName, null, measures); } @@ -168,6 +171,10 @@ export abstract class OmnisharpServer { return this._channel; } + public isDebugEnable(): boolean { + return this._isDebugEnable; + } + // --- eventing public onStdout(listener: (e: string) => any, thisArg?: any) { @@ -186,7 +193,7 @@ export abstract class OmnisharpServer { return this._addListener(Events.ServerError, listener, thisArg); } - public onUnresolvedDependencies(listener: (e: UnresolvedDependenciesMessage) => any, thisArg?:any) { + public onUnresolvedDependencies(listener: (e: UnresolvedDependenciesMessage) => any, thisArg?: any) { return this._addListener(Events.UnresolvedDependencies, listener, thisArg); } @@ -214,7 +221,7 @@ export abstract class OmnisharpServer { return this._addListener(Events.MsBuildProjectDiagnostics, listener, thisArg); } - public onBeforeServerStart(listener: (e:string) => any) { + public onBeforeServerStart(listener: (e: string) => any) { return this._addListener(Events.BeforeServerStart, listener); } @@ -271,6 +278,13 @@ export abstract class OmnisharpServer { this._setState(ServerState.Started); this._fireEvent(Events.ServerStart, solutionPath); return this._doConnect(); + }).then(_ => { + return vscode.commands.getCommands() + .then(commands => { + if (commands.find(c => c == "vscode.startDebug")) { + this._isDebugEnable = true; + } + }); }).then(_ => { this._processQueue(); }, err => { @@ -300,7 +314,7 @@ export abstract class OmnisharpServer { return reject(err); } }); - + killer.on('exit', resolve); killer.on('error', reject); }); @@ -309,7 +323,7 @@ export abstract class OmnisharpServer { this._serverProcess.kill('SIGTERM'); ret = Promise.resolve(undefined); } - + return ret.then(_ => { this._start = null; this._serverProcess = null; @@ -327,7 +341,7 @@ export abstract class OmnisharpServer { } } - public autoStart(preferredPath:string): Thenable { + public autoStart(preferredPath: string): Thenable { return getLaunchTargets().then(targets => { if (targets.length === 0) { return new Promise((resolve, reject) => { @@ -368,13 +382,13 @@ export abstract class OmnisharpServer { if (this._getState() !== ServerState.Started) { return Promise.reject('server has been stopped or not started'); } - + let startTime: number; let request: Request; - + let promise = new Promise((resolve, reject) => { startTime = Date.now(); - + request = { path, data, @@ -382,9 +396,9 @@ export abstract class OmnisharpServer { onError: err => reject(err), _enqueued: Date.now() }; - + this._queue.push(request); - + if (this._getState() === ServerState.Started && !this._isProcessingQueue) { this._processQueue(); } @@ -406,7 +420,7 @@ export abstract class OmnisharpServer { let endTime = Date.now(); let elapsedTime = endTime - startTime; this._recordRequestDelay(path, elapsedTime); - + return response; }); } @@ -504,19 +518,17 @@ export class StdioOmnisharpServer extends OmnisharpServer { // timeout logic const handle = setTimeout(() => { - if (listener) - { + if (listener) { listener.dispose(); } - + reject(new Error('Failed to start OmniSharp')); }, StdioOmnisharpServer.StartupTimeout); // handle started-event listener = this.onOmnisharpStart(() => { - if (listener) - { - listener.dispose(); + if (listener) { + listener.dispose(); } clearTimeout(handle); resolve(this); @@ -552,17 +564,17 @@ export class StdioOmnisharpServer extends OmnisharpServer { switch (packet.Type) { case 'response': - this._handleResponsePacket( packet); + this._handleResponsePacket(packet); break; case 'event': - this._handleEventPacket( packet); + this._handleEventPacket(packet); break; default: console.warn('unknown packet: ', packet); break; } }; - + this._rl.addListener('line', onLineReceived); this._callOnStop.push(() => this._rl.removeListener('line', onLineReceived)); } @@ -590,7 +602,7 @@ export class StdioOmnisharpServer extends OmnisharpServer { if (packet.Event === 'log') { // handle log events - const entry = <{ LogLevel: string; Name: string; Message: string; }> packet.Body; + const entry = <{ LogLevel: string; Name: string; Message: string; }>packet.Body; this._fireEvent(Events.StdOut, `[${entry.LogLevel}:${entry.Name}] ${entry.Message}\n`); return; } else { diff --git a/src/protocol.ts b/src/protocol.ts index 72eb608582..beb54ceb5a 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -176,11 +176,16 @@ export interface GetCodeActionsResponse { CodeActions: string[]; } +export interface SyntaxFeature { + Name: string; + Data: string; +} + export interface Node { ChildNodes: Node[]; Location: QuickFix; Kind: string; - Features: string[]; + Features: SyntaxFeature[]; } export interface CurrentFileMembersAsTreeResponse { From 5c9ee8ee460e730ac8eebd156a9fb5a164fc9239 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Fri, 27 May 2016 18:49:06 -0700 Subject: [PATCH 13/24] Add test output channel --- src/features/dotnetTest.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts index 3060c00803..abfd37c2de 100644 --- a/src/features/dotnetTest.ts +++ b/src/features/dotnetTest.ts @@ -11,6 +11,16 @@ import * as vscode from 'vscode'; import * as serverUtils from "../omnisharpUtils"; import * as protocol from '../protocol'; +let _testOutputChannel: vscode.OutputChannel = undefined; + +function getTestOutputChannel(): vscode.OutputChannel { + if (_testOutputChannel == undefined) { + _testOutputChannel = vscode.window.createOutputChannel(".NET Test Log"); + } + + return _testOutputChannel; +} + export function registerDotNetTestRunCommand(server: OmnisharpServer): vscode.Disposable { return vscode.commands.registerCommand( 'dotnet.test.run', @@ -25,15 +35,17 @@ export function registerDotNetTestDebugCommand(server: OmnisharpServer): vscode. // Run test through dotnet-test command. This function can be moved to a separate structure export function runDotnetTest(testMethod: string, fileName: string, server: OmnisharpServer) { + getTestOutputChannel().show(); + getTestOutputChannel().appendLine('Running test ' + testMethod + '...'); serverUtils .runDotNetTest(server, { FileName: fileName, MethodName: testMethod }) .then( response => { if (response.Pass) { - vscode.window.showInformationMessage('Test passed'); + getTestOutputChannel().appendLine('Test passed \n'); } else { - vscode.window.showErrorMessage('Test failed'); + getTestOutputChannel().appendLine('Test failed \n'); } }, reason => { From 62b9fe2ba4c5c8c516d67899581b11df28d08b00 Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 31 May 2016 09:58:32 -0700 Subject: [PATCH 14/24] Address review comments --- src/features/commands.ts | 8 +++++--- src/features/dotnetTest.ts | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/features/commands.ts b/src/features/commands.ts index 881aac806c..7036e9e494 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -27,9 +27,11 @@ export default function registerCommands(server: OmnisharpServer, extensionPath: // running the command activates the extension, which is all we need for installation to kickoff let d5 = vscode.commands.registerCommand('csharp.downloadDebugger', () => { }); - return vscode.Disposable.from(d1, d2, d3, d4, d5, - dotnetTest.registerDotNetTestRunCommand(server), - dotnetTest.registerDotNetTestDebugCommand(server)); + // register two commands for running and debugging xunit tests + let d6 = dotnetTest.registerDotNetTestRunCommand(server); + let d7 = dotnetTest.registerDotNetTestDebugCommand(server); + + return vscode.Disposable.from(d1, d2, d3, d4, d5, d6, d7); } function pickProjectAndStart(server: OmnisharpServer) { diff --git a/src/features/dotnetTest.ts b/src/features/dotnetTest.ts index abfd37c2de..65e2c7407e 100644 --- a/src/features/dotnetTest.ts +++ b/src/features/dotnetTest.ts @@ -49,7 +49,7 @@ export function runDotnetTest(testMethod: string, fileName: string, server: Omni } }, reason => { - vscode.window.showErrorMessage('Fail to run test because ' + reason + '.'); + vscode.window.showErrorMessage(`Failed to run test because ${reason}.`); }); } @@ -68,7 +68,7 @@ export function debugDotnetTest(testMethod: string, fileName: string, server: Om } ).then( response => { }, - reason => { vscode.window.showErrorMessage('Failed to start debugger on test because ' + reason + '.') }); + reason => { vscode.window.showErrorMessage(`Failed to start debugger on test because ${reason}.`) }); }); } From c44f3c3378265eeeaa0a91c2fd5a2b5344720e09 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 31 May 2016 10:07:02 -0700 Subject: [PATCH 15/24] Update decompress module to 4.0.0 This should address the race condition in the decompress module reported at https://github.com/kevva/decompress/issues/28. This should fix https://github.com/OmniSharp/omnisharp-vscode/issues/202. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df5474976a..f44b530ed8 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "postinstall": "tsc" }, "dependencies": { - "decompress": "^3.0.0", + "decompress": "^4.0.0", "del": "^2.0.2", "fs-extra-promise": "^0.3.1", "http-proxy-agent": "^1.0.0", From 10eccb9dcbb018730bb00fb495af8ff855248433 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 31 May 2016 10:16:18 -0700 Subject: [PATCH 16/24] Update OmniSharp to 1.9-beta4 --- src/omnisharpDownload.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/omnisharpDownload.ts b/src/omnisharpDownload.ts index 4b42cf4a58..01b49f1090 100644 --- a/src/omnisharpDownload.ts +++ b/src/omnisharpDownload.ts @@ -18,24 +18,24 @@ const Decompress = require('decompress'); const BaseDownloadUrl = 'https://vscodeoscon.blob.core.windows.net/ext'; const DefaultInstallLocation = path.join(__dirname, '../.omnisharp'); -const ApiToken = '18a6f5ecea711220d4f433d4fd41062d479fda1d'; +const OmniSharpVersion = '1.9-beta4'; tmp.setGracefulCleanup(); function getOmnisharpAssetName(): string { switch (getSupportedPlatform()) { case SupportedPlatform.Windows: - return 'omnisharp-win-x64-net451.zip'; + return `omnisharp-${OmniSharpVersion}-win-x64-net451.zip`; case SupportedPlatform.OSX: - return 'omnisharp-osx-x64-netcoreapp1.0.tar.gz'; + return `omnisharp-${OmniSharpVersion}-osx-x64-netcoreapp1.0.tar.gz`; case SupportedPlatform.CentOS: - return 'omnisharp-centos-x64-netcoreapp1.0.tar.gz'; + return `omnisharp-${OmniSharpVersion}-centos-x64-netcoreapp1.0.tar.gz`; case SupportedPlatform.Debian: - return 'omnisharp-debian-x64-netcoreapp1.0.tar.gz'; + return `omnisharp-${OmniSharpVersion}-debian-x64-netcoreapp1.0.tar.gz`; case SupportedPlatform.RHEL: - return 'omnisharp-rhel-x64-netcoreapp1.0.tar.gz'; + return `omnisharp-${OmniSharpVersion}-rhel-x64-netcoreapp1.0.tar.gz`; case SupportedPlatform.Ubuntu: - return 'omnisharp-ubuntu-x64-netcoreapp1.0.tar.gz'; + return `omnisharp-${OmniSharpVersion}-ubuntu-x64-netcoreapp1.0.tar.gz`; default: if (process.platform === 'linux') { From 42cc77d9d198415cd6a7fd3c007c0fec39647e58 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 31 May 2016 10:51:38 -0700 Subject: [PATCH 17/24] Update version to 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f44b530ed8..86c3fb6604 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.1.0", + "version": "1.1.1", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", From 4c5911a1380988ee2388d1a65b933443cc8b24a9 Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Tue, 31 May 2016 12:44:17 -0700 Subject: [PATCH 18/24] Add 'externalConsole' launch option (#390) With this checkin, we now support an 'externalConsole' launch option. This option is specified by default for console projects. This completes the fix for: https://github.com/OmniSharp/omnisharp-vscode/issues/175 --- package.json | 8 +++++++- src/assets.ts | 4 +++- src/coreclr-debug/main.ts | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 86c3fb6604..be0c4cd520 100644 --- a/package.json +++ b/package.json @@ -269,6 +269,11 @@ "description": "Environment variables passed to the program.", "default": { } }, + "externalConsole": { + "type": "boolean", + "description": "If 'true' the debugger should launch the target application into a new external console.", + "default": true + }, "sourceFileMap": { "type": "object", "description": "Optional source file mappings passed to the debug engine. Example: '{ \"C:\\foo\":\"/home/user/foo\" }'", @@ -428,7 +433,8 @@ "program": "${workspaceRoot}/bin/Debug//", "args": [], "cwd": "${workspaceRoot}", - "stopAtEntry": false + "stopAtEntry": false, + "externalConsole": true }, { "name": ".NET Core Launch (web)", diff --git a/src/assets.ts b/src/assets.ts index f82a6a7489..4878602549 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -25,7 +25,8 @@ interface ConsoleLaunchConfiguration extends DebugConfiguration { args: string[], cwd: string, stopAtEntry: boolean, - env?: any + env?: any, + externalConsole?: boolean } interface CommandLine { @@ -138,6 +139,7 @@ function createLaunchConfiguration(targetFramework: string, executableName: stri program: '${workspaceRoot}/bin/Debug/' + targetFramework + '/'+ executableName, args: [], cwd: '${workspaceRoot}', + externalConsole: true, stopAtEntry: false } } diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index 38ac227a41..ae40981e8e 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -333,7 +333,7 @@ function createProjectJson(targetRuntime: string): any }, dependencies: { "Microsoft.VisualStudio.clrdbg": "14.0.25320-preview-3008693", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30527-preview-1", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30531-preview-1", "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20527-preview-1", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1", From bbb2b3b1001647c877f41ad8d4bb44741c1be41a Mon Sep 17 00:00:00 2001 From: Troy Dai Date: Tue, 31 May 2016 13:51:15 -0700 Subject: [PATCH 19/24] Update namespace of test endpoints to V2 --- src/omnisharpUtils.ts | 8 ++++---- src/protocol.ts | 40 +++++++++++++++++++--------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/omnisharpUtils.ts b/src/omnisharpUtils.ts index d8733cb688..d1b1e88227 100644 --- a/src/omnisharpUtils.ts +++ b/src/omnisharpUtils.ts @@ -73,10 +73,10 @@ export function updateBuffer(server: OmnisharpServer, request: protocol.UpdateBu return server.makeRequest(protocol.Requests.UpdateBuffer, request); } -export function getTestStartInfo(server: OmnisharpServer, request: protocol.GetTestStartInfoRequest) { - return server.makeRequest(protocol.Requests.GetTestStartInfo, request); +export function getTestStartInfo(server: OmnisharpServer, request: protocol.V2.GetTestStartInfoRequest) { + return server.makeRequest(protocol.V2.Requests.GetTestStartInfo, request); } -export function runDotNetTest(server: OmnisharpServer, request: protocol.RunDotNetTestRequest) { - return server.makeRequest(protocol.Requests.RunDotNetTest, request); +export function runDotNetTest(server: OmnisharpServer, request: protocol.V2.RunDotNetTestRequest) { + return server.makeRequest(protocol.V2.Requests.RunDotNetTest, request); } \ No newline at end of file diff --git a/src/protocol.ts b/src/protocol.ts index beb54ceb5a..76bb72bd18 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -26,9 +26,6 @@ export module Requests { export const SignatureHelp = '/signatureHelp'; export const TypeLookup = '/typelookup'; export const UpdateBuffer = '/updatebuffer'; - - export const GetTestStartInfo = '/v2/getteststartinfo'; - export const RunDotNetTest = '/v2/runtest'; } export interface Request { @@ -375,6 +372,8 @@ export namespace V2 { export module Requests { export const GetCodeActions = '/v2/getcodeactions'; export const RunCodeAction = '/v2/runcodeaction'; + export const GetTestStartInfo = '/v2/getteststartinfo'; + export const RunDotNetTest = '/v2/runtest'; } export interface Point { @@ -448,26 +447,25 @@ export namespace V2 { Name: string; Version: string; } -} -// dotnet-test endpoints - -export interface GetTestStartInfoRequest { - FileName: string; - MethodName: string; -} + // dotnet-test endpoints + export interface GetTestStartInfoRequest { + FileName: string; + MethodName: string; + } -export interface GetTestStartInfoResponse { - Executable: string; - Argument: string; -} + export interface GetTestStartInfoResponse { + Executable: string; + Argument: string; + } -export interface RunDotNetTestRequest { - FileName: string; - MethodName: string; -} + export interface RunDotNetTestRequest { + FileName: string; + MethodName: string; + } -export interface RunDotNetTestResponse { - Failure: string; - Pass: boolean; + export interface RunDotNetTestResponse { + Failure: string; + Pass: boolean; + } } \ No newline at end of file From 5ffff216427efd4cefcfc29ea1a6ff24223f86d9 Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Tue, 31 May 2016 13:59:32 -0700 Subject: [PATCH 20/24] Fix OmniSharp download and improve logging This change fixes the use of the decompress (which changed its API shape in 4.0.0), and passes a VS Code OutputChannel into the downloading logic to surface logging. --- src/omnisharpDownload.ts | 43 +++++++++++++--------------------- src/omnisharpServerLauncher.ts | 2 +- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/omnisharpDownload.ts b/src/omnisharpDownload.ts index 01b49f1090..dbb407c08e 100644 --- a/src/omnisharpDownload.ts +++ b/src/omnisharpDownload.ts @@ -13,8 +13,9 @@ import * as tmp from 'tmp'; import {parse} from 'url'; import {SupportedPlatform, getSupportedPlatform} from './utils'; import {getProxyAgent} from './proxy'; +import {OutputChannel} from 'vscode'; -const Decompress = require('decompress'); +const decompress = require('decompress'); const BaseDownloadUrl = 'https://vscodeoscon.blob.core.windows.net/ext'; const DefaultInstallLocation = path.join(__dirname, '../.omnisharp'); @@ -73,14 +74,14 @@ function download(urlString: string): Promise { }); } -export function downloadOmnisharp(): Promise { +export function downloadOmnisharp(output: OutputChannel): Promise { return new Promise((resolve, reject) => { - console.log(`[OmniSharp]: Installing to ${DefaultInstallLocation}`); + output.appendLine(`[INFO] Installing to ${DefaultInstallLocation}`); const assetName = getOmnisharpAssetName(); const urlString = `${BaseDownloadUrl}/${assetName}`; - console.log(`[OmniSharp] Attempting to download ${assetName}...`); + output.appendLine(`[INFO] Attempting to download ${assetName}...`); return download(urlString) .then(inStream => { @@ -89,7 +90,7 @@ export function downloadOmnisharp(): Promise { return reject(err); } - console.log(`[OmniSharp] Downloading to ${tmpPath}...`); + output.appendLine(`[INFO] Downloading to ${tmpPath}...`); const outStream = fs.createWriteStream(null, { fd: fd }); @@ -99,30 +100,18 @@ export function downloadOmnisharp(): Promise { outStream.once('finish', () => { // At this point, the asset has finished downloading. - console.log(`[OmniSharp] Download complete!`); + output.appendLine(`[INFO] Download complete!`); + output.appendLine(`[INFO] Decompressing...`); - let decompress = new Decompress() - .src(tmpPath) - .dest(DefaultInstallLocation); - - if (path.extname(assetName).toLowerCase() === '.zip') { - decompress = decompress.use(Decompress.zip()); - console.log(`[OmniSharp] Unzipping...`); - } - else { - decompress = decompress.use(Decompress.targz()); - console.log(`[OmniSharp] Untaring...`); - } - - decompress.run((err, files) => { - if (err) { + return decompress(tmpPath, DefaultInstallLocation) + .then(files => { + output.appendLine(`[INFO] Done! ${files.length} files unpacked.`) + return resolve(true); + }) + .error(err => { + output.appendLine(`[ERROR] ${err}`); return reject(err); - } - - console.log(`[OmniSharp] Done! ${files.length} files unpacked.`) - - return resolve(true); - }); + }); }); inStream.pipe(outStream); diff --git a/src/omnisharpServerLauncher.ts b/src/omnisharpServerLauncher.ts index 561c7d805f..b4d0bb87d2 100644 --- a/src/omnisharpServerLauncher.ts +++ b/src/omnisharpServerLauncher.ts @@ -37,7 +37,7 @@ export function installOmnisharpIfNeeded(output: OutputChannel): Promise throw err; } - return downloadOmnisharp().then(_ => { + return downloadOmnisharp(output).then(_ => { return getOmnisharpLaunchFilePath(); }) }); From 2f99338c64b351a9c06e7311b94233b51f4c7b2f Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Wed, 1 Jun 2016 13:04:45 -0700 Subject: [PATCH 21/24] Update version to 1.1.2 (#395) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index be0c4cd520..287ffbb761 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.1.1", + "version": "1.1.2", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", From 019520c5152c2d1d4efecf726ed68c1c3e176aac Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Wed, 1 Jun 2016 17:33:27 -0700 Subject: [PATCH 22/24] Add "What's new" section and update debugger docs with new features (#396) --- README.md | 11 +++++++++++ debugger.md | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b5708cd6e1..e9610671fc 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,17 @@ Please file any issues at https://github.com/OmniSharp/omnisharp-vscode/issues. ### Debugging The C# extension now supports basic debugging capabilities! See http://aka.ms/vscclrdebugger for details. +### What's new in C# extension version 1.1 + +* Preliminary support for `dotnet test` +* Fix for OmniSharp installation problems on networks with an http proxy +* Debugger support for an external console +* Debugger support for environment variables +* Support for debugging .NET Core 1.0.0 post RC2 builds +* Automatic web vs. console debugger configuration detection +* Detach support +* Fix expression evaluation errors when referencing assemblies which aren't currently loaded + ### Development First install: diff --git a/debugger.md b/debugger.md index d548941c09..323edcc531 100644 --- a/debugger.md +++ b/debugger.md @@ -116,9 +116,23 @@ You can optionally configure a file by file mapping by providing map following t "sourceFileMap": { "C:\foo":"/home/me/foo" - } + } #####Symbol Path You can optionally provide paths to symbols following this schema: "symbolPath":"[ \"/Volumes/symbols\"]" + +#####Environment variables +Environment variables may be passed to your program using this schema: + + "env": { + "myVariableName":"theValueGoesHere" + } + +#####External console (terminal) window +The target process can optionally launch into a seperate console window. This is enabled by default for non-ASP.NET applications. But it can be explicitly set with: + + "externalConsole": true + +If your console app doesn't take console input (ex: all input comes from the command line), you may want to turn this off. From b59505612c5d375113ae4df429ccb833a7b8d791 Mon Sep 17 00:00:00 2001 From: Chuck Ries Date: Thu, 2 Jun 2016 12:43:04 -0700 Subject: [PATCH 23/24] Improve error handling for 'isOnPath' isOnPath calls existsSync, which was not handling ENOTDIR. This can arise if a portion of a path is not a directory, such as /dir1/dir2//foo/bar. existsSync should return false in these cases. Additionally, this adds a try/catch to isOnPath that should catch all other errors from existsSync and treat them as basic failures for that particular path segment. --- package.json | 2 +- src/coreclr-debug/main.ts | 20 ++++++++++++-------- src/coreclr-debug/util.ts | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 287ffbb761..085f590980 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.1.2", + "version": "1.1.3", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index ae40981e8e..81b709438d 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -200,25 +200,29 @@ function isOnPath(command : string) : boolean { return false; } let fileName = command; - let seperatorChar = ':'; if (process.platform == 'win32') { // on Windows, add a '.exe', and the path is semi-colon seperatode fileName = fileName + ".exe"; - seperatorChar = ';'; } - - let pathSegments: string[] = pathValue.split(seperatorChar); + + let pathSegments: string[] = pathValue.split(path.delimiter); for (let segment of pathSegments) { if (segment.length === 0 || !path.isAbsolute(segment)) { continue; } - + const segmentPath = path.join(segment, fileName); - if (CoreClrDebugUtil.existsSync(segmentPath)) { - return true; + + try { + if (CoreClrDebugUtil.existsSync(segmentPath)) { + return true; + } + } catch (err) { + // any error from existsSync can be treated as the command not being on the path + continue; } } - + return false; } diff --git a/src/coreclr-debug/util.ts b/src/coreclr-debug/util.ts index baca1c201c..e17f35af98 100644 --- a/src/coreclr-debug/util.ts +++ b/src/coreclr-debug/util.ts @@ -83,7 +83,7 @@ export default class CoreClrDebugUtil fs.accessSync(path, fs.F_OK); return true; } catch (err) { - if (err.code === 'ENOENT') { + if (err.code === 'ENOENT' || err.code === 'ENOTDIR') { return false; } else { throw Error(err.code); From 49c3e37de96cdca421f152a8c2dfbedec72d2778 Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Mon, 6 Jun 2016 13:44:03 -0700 Subject: [PATCH 24/24] Debugger changes for 1.1.4 (#407) This updates the clrdbg package to the 25406 build. This includes fixes for Win7 expression evulation and the System.Task breaking change. This addresses: https://github.com/OmniSharp/omnisharp-vscode/issues/258 This also the MIEngine to pull in https://github.com/Microsoft/MIEngine/pull/353 Lastly this disables the external console by default. We decided to have it off by default as we have seen some issues with it on OSX (ex: not always closing when the target exits), and we are hoping it will be possible soon to use the new VS Code console window instead. So we decided to turn it off by default, at least for now. --- README.md | 1 + debugger.md | 4 +--- package.json | 6 +++--- src/assets.ts | 2 +- src/coreclr-debug/main.ts | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e9610671fc..5d325f42c5 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ The C# extension now supports basic debugging capabilities! See http://aka.ms/vs * Automatic web vs. console debugger configuration detection * Detach support * Fix expression evaluation errors when referencing assemblies which aren't currently loaded +* Fix expression evaluation on Windows 7 ### Development diff --git a/debugger.md b/debugger.md index 323edcc531..691c1f5ab9 100644 --- a/debugger.md +++ b/debugger.md @@ -131,8 +131,6 @@ Environment variables may be passed to your program using this schema: } #####External console (terminal) window -The target process can optionally launch into a seperate console window. This is enabled by default for non-ASP.NET applications. But it can be explicitly set with: +The target process can optionally launch into a seperate console window. You will want this if your console app takes console input (ex: Console.ReadLine). This can be enabled with: "externalConsole": true - -If your console app doesn't take console input (ex: all input comes from the command line), you may want to turn this off. diff --git a/package.json b/package.json index 085f590980..3171c4aa97 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.1.3", + "version": "1.1.4", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", @@ -272,7 +272,7 @@ "externalConsole": { "type": "boolean", "description": "If 'true' the debugger should launch the target application into a new external console.", - "default": true + "default": false }, "sourceFileMap": { "type": "object", @@ -434,7 +434,7 @@ "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, - "externalConsole": true + "externalConsole": false }, { "name": ".NET Core Launch (web)", diff --git a/src/assets.ts b/src/assets.ts index 4878602549..29172eaf18 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -139,7 +139,7 @@ function createLaunchConfiguration(targetFramework: string, executableName: stri program: '${workspaceRoot}/bin/Debug/' + targetFramework + '/'+ executableName, args: [], cwd: '${workspaceRoot}', - externalConsole: true, + externalConsole: false, stopAtEntry: false } } diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index 81b709438d..f8c77524c0 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -336,8 +336,8 @@ function createProjectJson(targetRuntime: string): any emitEntryPoint: true }, dependencies: { - "Microsoft.VisualStudio.clrdbg": "14.0.25320-preview-3008693", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30531-preview-1", + "Microsoft.VisualStudio.clrdbg": "14.0.25406-preview-3044032", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30606-preview-1", "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20527-preview-1", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1",