diff --git a/src/features/signatureHelpProvider.ts b/src/features/signatureHelpProvider.ts index f7c4bed0f..96ad28c50 100644 --- a/src/features/signatureHelpProvider.ts +++ b/src/features/signatureHelpProvider.ts @@ -7,9 +7,10 @@ import AbstractSupport from './abstractProvider'; import * as serverUtils from '../omnisharp/utils'; -import {extractSummaryText} from './documentation'; -import {createRequest} from '../omnisharp/typeConvertion'; -import {SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterInformation, CancellationToken, TextDocument, Position} from 'vscode'; +import { createRequest } from '../omnisharp/typeConvertion'; +import { SignatureHelpProvider, SignatureHelp, SignatureInformation, ParameterInformation, CancellationToken, TextDocument, Position } from 'vscode'; +import { MarkdownString } from 'vscode'; +import { SignatureHelpParameter } from '../omnisharp/protocol'; export default class OmniSharpSignatureHelpProvider extends AbstractSupport implements SignatureHelpProvider { @@ -18,7 +19,7 @@ export default class OmniSharpSignatureHelpProvider extends AbstractSupport impl let req = createRequest(document, position); return serverUtils.signatureHelp(this._server, req, token).then(res => { - + if (!res) { return undefined; } @@ -29,13 +30,13 @@ export default class OmniSharpSignatureHelpProvider extends AbstractSupport impl for (let signature of res.Signatures) { - let signatureInfo = new SignatureInformation(signature.Label, extractSummaryText(signature.Documentation)); + let signatureInfo = new SignatureInformation(signature.Label, signature.StructuredDocumentation.SummaryText); ret.signatures.push(signatureInfo); for (let parameter of signature.Parameters) { let parameterInfo = new ParameterInformation( parameter.Label, - extractSummaryText(parameter.Documentation)); + this.GetParameterDocumentation(parameter)); signatureInfo.parameters.push(parameterInfo); } @@ -44,4 +45,14 @@ export default class OmniSharpSignatureHelpProvider extends AbstractSupport impl return ret; }); } + + private GetParameterDocumentation(parameter: SignatureHelpParameter) { + let summary = parameter.Documentation; + if (summary.length > 0) { + let paramText = `**${parameter.Name}**: ${summary}`; + return new MarkdownString(paramText); + } + + return ""; + } } diff --git a/src/omnisharp/protocol.ts b/src/omnisharp/protocol.ts index 0e9480f5d..46f902b62 100644 --- a/src/omnisharp/protocol.ts +++ b/src/omnisharp/protocol.ts @@ -398,6 +398,7 @@ export interface SignatureHelpItem { Label: string; Documentation: string; Parameters: SignatureHelpParameter[]; + StructuredDocumentation: DocumentationComment; } export interface SignatureHelpParameter { diff --git a/test/integrationTests/signatureHelp.integration.test.ts b/test/integrationTests/signatureHelp.integration.test.ts new file mode 100644 index 000000000..8c4c75dc0 --- /dev/null +++ b/test/integrationTests/signatureHelp.integration.test.ts @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the MIT License. See License.txt in the project root for license information. +*--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import * as path from 'path'; + +import poll from './poll'; +import { should, expect } from 'chai'; +import testAssetWorkspace from './testAssets/testAssetWorkspace'; +import { omnisharp } from '../../src/omnisharp/extension'; + +const chai = require('chai'); +chai.use(require('chai-arrays')); +chai.use(require('chai-fs')); + +suite(`SignatureHelp: ${testAssetWorkspace.description}`, function () { + let fileUri: vscode.Uri; + suiteSetup(async function () { + should(); + + let csharpExtension = vscode.extensions.getExtension("ms-vscode.csharp"); + if (!csharpExtension.isActive) { + await csharpExtension.activate(); + } + + await csharpExtension.exports.initializationFinished; + + let fileName = 'sigHelp.cs'; + let dir = path.dirname(testAssetWorkspace.projects[0].projectDirectoryPath); + let loc = path.join(dir, fileName); + fileUri = vscode.Uri.file(loc); + await omnisharp.waitForEmptyEventQueue(); + await vscode.commands.executeCommand("vscode.open", fileUri); + }); + + + test("Returns response with documentation as undefined when method does not have documentation", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(19, 23)); + expect(c.signatures[0].documentation).to.be.undefined; + }); + + test("Returns label when method does not have documentation", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(19, 23)); + let answer = `void sigHelp.noDocMethod()`; + expect(c.signatures[0].label).to.equal(answer); + }); + + test("Returns summary as documentation for the method", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 18)); + let answer = `DoWork is some method.`; + expect(c.signatures[0].documentation).to.equal(answer); + }); + + test("Returns label for the method", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 18)); + let answer = `void sigHelp.DoWork(int Int1, float Float1)`; + expect(c.signatures[0].label).to.equal(answer); + }); + + test("Returns label for the parameters", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 18)); + let param1 = `int Int1`; + let param2 = `float Float1`; + expect(c.signatures[0].parameters[0].label).to.equal(param1); + expect(c.signatures[0].parameters[1].label).to.equal(param2); + }); + + test("Returns documentation for the parameters", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 18)); + let param1 = `**Int1**: Used to indicate status.`; + let param2 = `**Float1**: Used to specify context.`; + expect(( c.signatures[0].parameters[0].documentation).value).to.equal(param1); + expect(( c.signatures[0].parameters[1].documentation).value).to.equal(param2); + }); + + test("Signature Help identifies active parameter if there is no comma", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 18)); + let answer = `int Int1`; + expect(c.signatures[0].parameters[c.activeParameter].label).to.equal(answer); + }); + + test("Signature Help identifies active parameter based on comma", async function () { + let c = await vscode.commands.executeCommand("vscode.executeSignatureHelpProvider", fileUri, new vscode.Position(18, 20)); + let answer = `float Float1`; + expect(c.signatures[0].parameters[c.activeParameter].label).to.equal(answer); + }); + + suiteTeardown(async () => { + await testAssetWorkspace.cleanupWorkspace(); + }); +}); \ No newline at end of file diff --git a/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache b/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache index ccde3e0e4..2c37f2978 100644 --- a/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache +++ b/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -fe2f654e9c48e6a308b6a264aa38a2b3defe5730 +a42255fc669f86623d73c2e9ad48ccb8310c65c0 diff --git a/test/integrationTests/testAssets/singleCsproj/sigHelp.cs b/test/integrationTests/testAssets/singleCsproj/sigHelp.cs new file mode 100644 index 000000000..9e3bf5f85 --- /dev/null +++ b/test/integrationTests/testAssets/singleCsproj/sigHelp.cs @@ -0,0 +1,23 @@ +using System; +namespace Test +{ + class sigHelp + { + ///DoWork is some method. + /// Used to indicate status. + /// Used to specify context. + public static void DoWork(int Int1, float Float1) + { + } + + public static void noDocMethod() + { + } + + public static void main() + { + DoWork(4, 4.0f); + noDocMethod(); + } + } +} \ No newline at end of file diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/sigHelp.cs b/test/integrationTests/testAssets/slnWithCsproj/src/app/sigHelp.cs new file mode 100644 index 000000000..9e3bf5f85 --- /dev/null +++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/sigHelp.cs @@ -0,0 +1,23 @@ +using System; +namespace Test +{ + class sigHelp + { + ///DoWork is some method. + /// Used to indicate status. + /// Used to specify context. + public static void DoWork(int Int1, float Float1) + { + } + + public static void noDocMethod() + { + } + + public static void main() + { + DoWork(4, 4.0f); + noDocMethod(); + } + } +} \ No newline at end of file