diff --git a/package.json b/package.json index 297e0d08a..0994a1fca 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "json-rpc2": "^1.0.2", "vscode-debugadapter": "^1.11.0", "vscode-debugprotocol": "^1.11.0", - "vscode-extension-telemetry": "0.0.5" + "vscode-extension-telemetry": "0.0.5", + "vscode-languageclient": "^2.5.0" }, "devDependencies": { "@types/fs-extra": "0.0.35", @@ -388,6 +389,11 @@ "type": "string", "default": "", "description": "Location to install the Go tools that the extension depends on if you don't want them in your GOPATH." + }, + "go.useLanguageServer": { + "type": "boolean", + "default": false, + "description": "Use Go language server from Sourcegraph for Hover, Definition, Find All References, Signature Help, File Outline and Workspace Symbol features" } } } diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index cd59aa3ed..2b18693eb 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -52,6 +52,10 @@ function getTools(goVersion: SemVersion): { [key: string]: string } { tools['gometalinter'] = 'github.com/alecthomas/gometalinter'; } + if (goConfig['useLanguageServer']) { + tools['langserver-go'] = 'github.com/sourcegraph/go-langserver/langserver/cmd/langserver-go'; + } + return tools; } @@ -179,6 +183,9 @@ function installTools(goVersion: SemVersion, missing?: string[]) { outputChannel.appendLine(''); // Blank line for spacing let failures = res.filter(x => x != null); if (failures.length === 0) { + if (missing.indexOf('langserver-go') > -1) { + outputChannel.appendLine('Reload VS Code window to use the Go language server'); + } outputChannel.appendLine('All tools successfully installed. You\'re ready to Go :).'); return; } @@ -249,7 +256,20 @@ function getMissingTools(goVersion: SemVersion): Promise { }); } - +// If langserver needs to be used, but is not installed, this will prompt user to install and Reload +// If langserver needs to be used, and is installed, this will return true +// Returns false in all other cases +export function checkLanguageServer(): boolean { + let latestGoConfig = vscode.workspace.getConfiguration('go'); + if (!latestGoConfig['useLanguageServer']) return false; + + let langServerAvailable = getBinPath('langserver-go') !== 'langserver-go'; + if (!langServerAvailable) { + promptForMissingTool('langserver-go'); + vscode.window.showInformationMessage('Reload VS Code window after installing the Go language server'); + } + return langServerAvailable; +} diff --git a/src/goMain.ts b/src/goMain.ts index 1ee5f8f71..fd8dd7125 100644 --- a/src/goMain.ts +++ b/src/goMain.ts @@ -27,22 +27,47 @@ import { coverageCurrentPackage, getCodeCoverage, removeCodeCoverage } from './g import { testAtCursor, testCurrentPackage, testCurrentFile, testPrevious } from './goTest'; import * as goGenerateTests from './goGenerateTests'; import { addImport } from './goImport'; -import { installAllTools } from './goInstallTools'; -import { isGoPathSet } from './util'; +import { installAllTools, checkLanguageServer } from './goInstallTools'; +import { isGoPathSet, getBinPath } from './util'; +import { LanguageClient } from 'vscode-languageclient'; let diagnosticCollection: vscode.DiagnosticCollection; +let useLangServer: boolean; export function activate(ctx: vscode.ExtensionContext): void { + let useLangServer = vscode.workspace.getConfiguration('go')['useLanguageServer']; + if (checkLanguageServer()) { + const c = new LanguageClient( + 'langserver-go', + { + command: getBinPath('langserver-go'), + args: [ + '-mode=stdio' + ], + }, + { + documentSelector: ['go'], + uriConverters: { + // Apply file:/// scheme to all file paths. + code2Protocol: (uri: vscode.Uri): string => (uri.scheme ? uri : uri.with({ scheme: 'file' })).toString(), + protocol2Code: (uri: string) => vscode.Uri.parse(uri), + }, + } + ); + + ctx.subscriptions.push(c.start()); + } else { + ctx.subscriptions.push(vscode.languages.registerHoverProvider(GO_MODE, new GoHoverProvider())); + ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(GO_MODE, new GoDefinitionProvider())); + ctx.subscriptions.push(vscode.languages.registerReferenceProvider(GO_MODE, new GoReferenceProvider())); + ctx.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(GO_MODE, new GoDocumentSymbolProvider())); + ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(new GoWorkspaceSymbolProvider())); + ctx.subscriptions.push(vscode.languages.registerSignatureHelpProvider(GO_MODE, new GoSignatureHelpProvider(), '(', ',')); + } - ctx.subscriptions.push(vscode.languages.registerHoverProvider(GO_MODE, new GoHoverProvider())); ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(GO_MODE, new GoCompletionItemProvider(), '.', '\"')); - ctx.subscriptions.push(vscode.languages.registerDefinitionProvider(GO_MODE, new GoDefinitionProvider())); - ctx.subscriptions.push(vscode.languages.registerReferenceProvider(GO_MODE, new GoReferenceProvider())); ctx.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider(GO_MODE, new GoDocumentFormattingEditProvider())); - ctx.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(GO_MODE, new GoDocumentSymbolProvider())); - ctx.subscriptions.push(vscode.languages.registerWorkspaceSymbolProvider(new GoWorkspaceSymbolProvider())); ctx.subscriptions.push(vscode.languages.registerRenameProvider(GO_MODE, new GoRenameProvider())); - ctx.subscriptions.push(vscode.languages.registerSignatureHelpProvider(GO_MODE, new GoSignatureHelpProvider(), '(', ',')); ctx.subscriptions.push(vscode.languages.registerCodeActionsProvider(GO_MODE, new GoCodeActionProvider())); diagnosticCollection = vscode.languages.createDiagnosticCollection('go'); @@ -92,6 +117,12 @@ export function activate(ctx: vscode.ExtensionContext): void { ctx.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => { updateGoPathGoRootFromConfig(); + let updatedGoConfig = vscode.workspace.getConfiguration('go'); + // If there was a change in "useLanguageServer" setting, then ask the user to reload VS Code. + if (useLangServer !== updatedGoConfig['useLanguageServer'] && (!updatedGoConfig['useLanguageServer'] || checkLanguageServer())) { + vscode.window.showInformationMessage('Reload VS Code window for the change in usage of language server to take effect'); + } + useLangServer = updatedGoConfig['useLanguageServer']; })); ctx.subscriptions.push(vscode.commands.registerCommand('go.test.generate.package', () => { @@ -213,3 +244,4 @@ function startBuildOnSaveWatcher(subscriptions: vscode.Disposable[]) { }, null, subscriptions); } +