Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

When using go-languageserver, also use code completion feature #1607

Merged
merged 11 commits into from
May 27, 2018
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The Go extension is ready to use on the get go. If you want to customize the fea

The Go extension uses a host of Go tools to provide the various language features. An alternative is to use a single language server that provides the same feature.

Set `go.useLanguageServer` to `true` to use the Go language server from [Sourcegraph](https://github.com/sourcegraph/go-langserver) for features like Hover, Definition, Find All References, Signature Help, Go to Symbol in File and Workspace.
Set `go.useLanguageServer` to `true` to use the Go language server from [Sourcegraph](https://github.com/sourcegraph/go-langserver) for features like Code completion, Hover, Definition, Find All References, Signature Help, Go to Symbol in File and Workspace.
* This is an experimental feature and is not available in Windows yet.
* Since only a single language server is spun up for given VS Code instance, having multi-root setup where the folders have different GOPATH is not supported.
* If set to true, you will be prompted to install the Go language server. Once installed, you will have to reload VS Code window. The language server will then be run by the Go extension in the background to provide services needed for the above mentioned features.
Expand Down
36 changes: 23 additions & 13 deletions src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ 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) {
if (missing.indexOf('go-langserver') > -1) {
outputChannel.appendLine('Reload VS Code window to use the Go language server');
}
outputChannel.appendLine('All tools successfully installed. You\'re ready to Go :).');
Expand Down Expand Up @@ -370,27 +370,42 @@ function getMissingTools(goVersion: SemVersion): Promise<string[]> {
}

// 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 {
// If langserver needs to be used, and is installed, this will return the list of supported flags
// Returns null in all other cases
export function checkLanguageServer(): string[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep things simple, lets go with the assumption that the auto-completion feature from language server is available only if the user has the latest language server i.e if the user's version of the language server respects the initalizationOptions sent.

Towards that end, we can revert the changes made to checkLanguageServer here

let latestGoConfig = vscode.workspace.getConfiguration('go');
if (!latestGoConfig['useLanguageServer']) return false;
if (!latestGoConfig['useLanguageServer']) return null;

if (process.platform === 'win32') {
vscode.window.showInformationMessage('The Go language server is not supported on Windows yet.');
return false;
return null;
}
if (!allFoldersHaveSameGopath()) {
vscode.window.showInformationMessage('The Go language server is not supported in a multi root set up with different GOPATHs.');
return false;
return null;
}

let langServerAvailable = getBinPath('go-langserver') !== 'go-langserver';
if (!langServerAvailable) {
promptForMissingTool('go-langserver');
vscode.window.showInformationMessage('Reload VS Code window after installing the Go language server');
return null;
}
return langServerAvailable;

// we execute the languageserver using -help so that it will fail and
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty terrible, but it's the best I could come up with in case we want to make sure an up-to-date version of the language server is installed.

Alternatively we could call go-langserver -version, but I don't really know what do to with the output as it would currently just print sth like v2-dev: https://github.com/sourcegraph/go-langserver/blob/dd4c619b53ae9d18c94e372d23d8710e59f0766b/main.go#L41

// print all the available flags
let helpText = '';
try {
helpText = cp.execFileSync(getBinPath('go-langserver'), ['-help']).toString();
} catch (err) {
helpText = (<cp.SpawnSyncReturns<Buffer>>err).stderr.toString();
}

// return the list of supported flags so consumers know what features
// can be supported
return helpText.split('\n')
.filter(line => line.trim().startsWith('-'))
.map(flag => flag.split(' ')[0]);
}

function allFoldersHaveSameGopath(): boolean {
Expand All @@ -401,8 +416,3 @@ function allFoldersHaveSameGopath(): boolean {
let tempGopath = getCurrentGoPath(vscode.workspace.workspaceFolders[0].uri);
return vscode.workspace.workspaceFolders.find(x => tempGopath !== getCurrentGoPath(x.uri)) ? false : true;
}





26 changes: 21 additions & 5 deletions src/goMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,24 @@ export function activate(ctx: vscode.ExtensionContext): void {
ctx.globalState.update('goroot', currentGoroot);

offerToInstallTools();
let langServerAvailable = checkLanguageServer();
if (langServerAvailable) {
let langServerFlags: string[] = vscode.workspace.getConfiguration('go')['languageServerFlags'] || [];
let supportedLangServerFlags = checkLanguageServer();
if (supportedLangServerFlags) {
let configuredLangServerFlags: string[] = vscode.workspace.getConfiguration('go')['languageServerFlags'] || [];
configuredLangServerFlags = [
...configuredLangServerFlags,
'-gocodecompletion',
`-func-snippet-enabled=${vscode.workspace.getConfiguration('go')['useCodeSnippetsOnFunctionSuggest']}`
];

let applicableFlags = configuredLangServerFlags.filter(f => {
return supportedLangServerFlags.some(supported => f.startsWith(supported));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why startsWith and not === ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because for example the supported flags will contain -func-snippet-enabled but we also pass a value like -func-snippet-enabled=false.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Makes sense

});

const c = new LanguageClient(
'go-langserver',
{
command: getBinPath('go-langserver'),
args: ['-mode=stdio', ...langServerFlags],
args: ['-mode=stdio', ...applicableFlags],
options: {
env: getToolsEnvVars()
}
Expand All @@ -110,8 +120,15 @@ export function activate(ctx: vscode.ExtensionContext): void {
}
);

c.onReady().then(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a c.onReady() below, can you combine this with that?

if (c.initializeResult && c.initializeResult.capabilities && !c.initializeResult.capabilities.completionProvider) {
ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would get inside this if block when the user had enabled the languageServerExperimentalFeatures['autoComplete'] setting, but the language server is old as well. In this case, we should notify the user that their version of the language server is old and does not support the auto-complete feature.

Same for the format feature.

}
});

ctx.subscriptions.push(c.start());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since its possible for users to run the older versions of the language server where completions are not supported, add the below to register the completion provider from the extension

c.onReady().then(() => {
				if (c.initializeResult && c.initializeResult.capabilities && !c.initializeResult.capabilities.completionProvider) {
					ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
				}
			});

} else {
ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
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()));
Expand All @@ -133,7 +150,6 @@ export function activate(ctx: vscode.ExtensionContext): void {
let testCodeLensProvider = new GoRunTestCodeLensProvider();
let referencesCodeLensProvider = new GoReferencesCodeLensProvider();

ctx.subscriptions.push(vscode.languages.registerCompletionItemProvider(GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
ctx.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider(GO_MODE, new GoDocumentFormattingEditProvider()));
ctx.subscriptions.push(vscode.languages.registerRenameProvider(GO_MODE, new GoRenameProvider()));
ctx.subscriptions.push(vscode.languages.registerCodeActionsProvider(GO_MODE, new GoCodeActionProvider()));
Expand Down