goLanguageServer: turn on all experiments in the Nightly
For users of the Go Nightly extension and gopls/v0.5.2 and greater,
enable "allExperiments" by default. Users can still provide their own
overrides, and they can still set the "allExperiments" flag to false
manually.
Fixes golang/vscode-go#818
Change-Id: Ife0db71e6a1cb7472cfe2f18ca5a3d4aa2987697
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/264317
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Trust: Rebecca Stambler <rstambler@golang.org>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index 3699e0a..f2c2481 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -15,8 +15,11 @@
import util = require('util');
import vscode = require('vscode');
import {
+ CancellationToken,
CloseAction,
CompletionItemKind,
+ ConfigurationParams,
+ ConfigurationRequest,
ErrorAction,
HandleDiagnosticsSignature,
InitializeError,
@@ -24,6 +27,7 @@
ProvideCodeLensesSignature,
ProvideCompletionItemsSignature,
ProvideDocumentLinksSignature,
+ ResponseError,
RevealOutputChannelOn
} from 'vscode-languageclient';
import {
@@ -57,6 +61,7 @@
interface LanguageServerConfig {
serverName: string;
path: string;
+ version: string;
modtime: Date;
enabled: boolean;
flags: string[];
@@ -171,7 +176,7 @@
// Track the latest config used to start the language server,
// and rebuild the language client.
latestConfig = config;
- languageClient = buildLanguageClient(config);
+ languageClient = await buildLanguageClient(config);
crashCount = 0;
}
@@ -201,27 +206,28 @@
return true;
}
-function buildLanguageClient(config: LanguageServerConfig): LanguageClient {
+async function buildLanguageClient(cfg: LanguageServerConfig): Promise<LanguageClient> {
// Reuse the same output channel for each instance of the server.
- if (config.enabled) {
+ if (cfg.enabled) {
if (!serverOutputChannel) {
- serverOutputChannel = vscode.window.createOutputChannel(config.serverName + ' (server)');
+ serverOutputChannel = vscode.window.createOutputChannel(cfg.serverName + ' (server)');
}
if (!serverTraceChannel) {
- serverTraceChannel = vscode.window.createOutputChannel(config.serverName);
+ serverTraceChannel = vscode.window.createOutputChannel(cfg.serverName);
}
}
- const goplsConfig = getGoplsConfig();
+ let goplsWorkspaceConfig = getGoplsConfig();
+ goplsWorkspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, goplsWorkspaceConfig);
const c = new LanguageClient(
'go', // id
- config.serverName, // name
+ cfg.serverName, // name
{
- command: config.path,
- args: ['-mode=stdio', ...config.flags],
- options: { env: config.env },
+ command: cfg.path,
+ args: ['-mode=stdio', ...cfg.flags],
+ options: { env: cfg.env },
},
{
- initializationOptions: goplsConfig,
+ initializationOptions: goplsWorkspaceConfig,
documentSelector: ['go', 'go.mod', 'go.sum'],
uriConverters: {
// Apply file:/// scheme to all file paths.
@@ -298,7 +304,7 @@
diagnostics: vscode.Diagnostic[],
next: HandleDiagnosticsSignature
) => {
- if (!config.features.diagnostics) {
+ if (!cfg.features.diagnostics) {
return null;
}
return next(uri, diagnostics);
@@ -308,7 +314,7 @@
token: vscode.CancellationToken,
next: ProvideDocumentLinksSignature
) => {
- if (!config.features.documentLink) {
+ if (!cfg.features.documentLink) {
return null;
}
return next(document, token);
@@ -399,12 +405,50 @@
lastUserAction = new Date();
next(e);
},
+ workspace: {
+ configuration: async (params: ConfigurationParams, token: CancellationToken, next: ConfigurationRequest.HandlerSignature): Promise<any[] | ResponseError<void>> => {
+ const configs = await next(params, token);
+ if (!Array.isArray(configs)) {
+ return configs;
+ }
+ for (let workspaceConfig of configs) {
+ workspaceConfig = await adjustGoplsWorkspaceConfiguration(cfg, workspaceConfig);
+ }
+ return configs;
+ },
+ },
}
}
);
return c;
}
+// adjustGoplsWorkspaceConfiguration adds any extra options to the gopls
+// config. Right now, the only extra option is enabling experiments for the
+// Nightly extension.
+async function adjustGoplsWorkspaceConfiguration(cfg: LanguageServerConfig, config: any): Promise<any> {
+ if (!config) {
+ return config;
+ }
+ // Only modify the user's configurations for the Nightly.
+ if (extensionId !== 'golang.go-nightly') {
+ return config;
+ }
+ // allExperiments is only available with gopls/v0.5.2 and above.
+ const version = await getLocalGoplsVersion(cfg);
+ if (!version) {
+ return config;
+ }
+ const sv = semver.parse(version, true);
+ if (!sv || semver.lt(sv, 'v0.5.2')) {
+ return config;
+ }
+ if (!config['allExperiments']) {
+ config['allExperiments'] = true;
+ }
+ return config;
+}
+
// createTestCodeLens adds the go.test.cursor and go.debug.cursor code lens
function createTestCodeLens(lens: vscode.CodeLens): vscode.CodeLens[] {
// CodeLens argument signature in gopls is [fileName: string, testFunctions: string[], benchFunctions: string[]],
@@ -510,6 +554,7 @@
const cfg: LanguageServerConfig = {
serverName: '',
path: '',
+ version: '', // compute version lazily
modtime: null,
enabled: goConfig['useLanguageServer'] === true,
flags: goConfig['languageServerFlags'] || [],
@@ -748,7 +793,12 @@
// getLocalGoplsVersion returns the version of gopls that is currently
// installed on the user's machine. This is determined by running the
// `gopls version` command.
+//
+// If this command has already been executed, it returns the saved result.
export const getLocalGoplsVersion = async (cfg: LanguageServerConfig) => {
+ if (cfg.version !== '') {
+ return cfg.version;
+ }
const execFile = util.promisify(cp.execFile);
let output: any;
try {
@@ -802,7 +852,8 @@
//
// v0.1.3
//
- return split[1];
+ cfg.version = split[1];
+ return cfg.version;
};
async function goProxyRequest(tool: Tool, endpoint: string): Promise<any> {
diff --git a/test/gopls/update.test.ts b/test/gopls/update.test.ts
index 031bea5..2c838ff 100644
--- a/test/gopls/update.test.ts
+++ b/test/gopls/update.test.ts
@@ -104,6 +104,7 @@
const got = await lsp.shouldUpdateLanguageServer(tool, {
enabled: true,
path: 'bad/path/to/gopls',
+ version: '',
checkForUpdates: true,
env: {},
features: {