goLanguageServer: use a webview for the survey
This change restructures a bit of the survey logic so that we check if
we should prompt for the survey once a day, regardless of activation.
The same goes for update prompts.
Also, we use a webview for the survey instead of opening a new browser
window.
Change-Id: I812bb11b78cdfed7a2086606f96dbe745c6f24b0
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/241197
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index 969ebff..6b2c53b 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -82,24 +82,12 @@
export async function startLanguageServerWithFallback(ctx: vscode.ExtensionContext, activation: boolean) {
const cfg = buildLanguageServerConfig();
- // If the language server is gopls, we can check if the user needs to
- // update their gopls version. We do this only once per VS Code
- // activation to avoid inundating the user.
- if (activation && cfg.enabled && cfg.serverName === 'gopls') {
+ // If the language server is gopls, we enable a few additional features.
+ // These include prompting for updates and surveys.
+ if (activation && cfg.serverName === 'gopls') {
const tool = getTool(cfg.serverName);
if (tool) {
- const versionToUpdate = await shouldUpdateLanguageServer(tool, cfg.path, cfg.checkForUpdates);
- if (versionToUpdate) {
- promptForUpdatingTool(tool.name, versionToUpdate);
- } else if (goplsSurveyOn) {
- // Only prompt users to fill out the gopls survey if we are not
- // also prompting them to update (both would be too much).
- const timeout = 1000 * 60 * 60; // 1 hour
- setTimeout(async () => {
- const surveyCfg = await maybePromptForGoplsSurvey();
- flushSurveyConfig(surveyCfg);
- }, timeout);
- }
+ scheduleGoplsSuggestions(tool);
}
}
@@ -113,6 +101,44 @@
}
}
+// scheduleGoplsSuggestions sets timeouts for the various gopls-specific
+// suggestions. We check user's gopls versions once per day to prompt users to
+// update to the latest version. We also check if we should prompt users to
+// fill out the survey.
+function scheduleGoplsSuggestions(tool: Tool) {
+ const minute = 1000 * 60;
+ const hour = minute * 60;
+ const day = hour * 24;
+
+ const update = async () => {
+ setTimeout(update, day);
+
+ const cfg = buildLanguageServerConfig();
+ if (!cfg.enabled) {
+ return;
+ }
+ const versionToUpdate = await shouldUpdateLanguageServer(tool, cfg);
+ if (versionToUpdate) {
+ promptForUpdatingTool(tool.name, versionToUpdate);
+ }
+ };
+ const survey = async () => {
+ setTimeout(survey, day);
+
+ const cfg = buildLanguageServerConfig();
+ if (!goplsSurveyOn || !cfg.enabled) {
+ return;
+ }
+ const surveyCfg = await maybePromptForGoplsSurvey();
+ if (surveyCfg) {
+ flushSurveyConfig(surveyCfg);
+ }
+ };
+
+ setTimeout(update, 10 * minute);
+ setTimeout(survey, hour);
+}
+
async function startLanguageServer(ctx: vscode.ExtensionContext, config: LanguageServerConfig): Promise<boolean> {
// If the client has already been started, make sure to clear existing
// diagnostics and stop it.
@@ -465,8 +491,7 @@
export async function shouldUpdateLanguageServer(
tool: Tool,
- languageServerToolPath: string,
- makeProxyCall: boolean
+ cfg: LanguageServerConfig,
): Promise<semver.SemVer> {
// Only support updating gopls for now.
if (tool.name !== 'gopls') {
@@ -474,7 +499,9 @@
}
// First, run the "gopls version" command and parse its results.
- const usersVersion = await getLocalGoplsVersion(languageServerToolPath);
+ // TODO(rstambler): Confirm that the gopls binary's modtime matches the
+ // modtime in the config. Update it if needed.
+ const usersVersion = await getLocalGoplsVersion(cfg);
// We might have a developer version. Don't make the user update.
if (usersVersion === '(devel)') {
@@ -482,7 +509,7 @@
}
// Get the latest gopls version. If it is for nightly, using the prereleased version is ok.
- let latestVersion = makeProxyCall ? await getLatestGoplsVersion(tool) : tool.latestVersion;
+ let latestVersion = cfg.checkForUpdates ? await getLatestGoplsVersion(tool) : tool.latestVersion;
// If we failed to get the gopls version, pick the one we know to be latest at the time of this extension's last update
if (!latestVersion) {
@@ -501,7 +528,8 @@
const usersTime = parseTimestampFromPseudoversion(usersVersion);
// If the user has a pseudoversion, get the timestamp for the latest gopls version and compare.
if (usersTime) {
- let latestTime = makeProxyCall ? await getTimestampForVersion(tool, latestVersion) : tool.latestVersionTimestamp;
+ let latestTime = cfg.checkForUpdates ?
+ await getTimestampForVersion(tool, latestVersion) : tool.latestVersionTimestamp;
if (!latestTime) {
latestTime = tool.latestVersionTimestamp;
}
@@ -604,11 +632,11 @@
// getLocalGoplsVersion returns the version of gopls that is currently
// installed on the user's machine. This is determined by running the
// `gopls version` command.
-export const getLocalGoplsVersion = async (goplsPath: string) => {
+export const getLocalGoplsVersion = async (cfg: LanguageServerConfig) => {
const execFile = util.promisify(cp.execFile);
let output: any;
try {
- const { stdout } = await execFile(goplsPath, ['version'], { env: toolExecutionEnvironment() });
+ const { stdout } = await execFile(cfg.path, ['version'], { env: toolExecutionEnvironment() });
output = stdout;
} catch (e) {
// The "gopls version" command is not supported, or something else went wrong.
@@ -730,8 +758,19 @@
cfg.lastDateAccepted = now;
cfg.prompt = true;
- // Open the link to the survey.
- vscode.env.openExternal(vscode.Uri.parse('https://www.whattimeisitrightnow.com/'));
+ // Open the link to the survey in a webview.
+ const panel = vscode.window.createWebviewPanel('goplsSurvey', 'gopls survey', {
+ viewColumn: null,
+ preserveFocus: false,
+ }, {});
+
+ // TODO(rstambler): Not sure how to set the correct height here.
+ panel.webview.html = `<!DOCTYPE html>
+<html>
+<body>
+<iframe width="100%" height="500px" src="https://golang.org"></iframe>
+</body>
+</html>`;
break;
case 'Not now':
cfg.prompt = true;
diff --git a/test/gopls/update.test.ts b/test/gopls/update.test.ts
index bac3aaf..031bea5 100644
--- a/test/gopls/update.test.ts
+++ b/test/gopls/update.test.ts
@@ -101,7 +101,19 @@
return latestPrereleaseVersionTimestamp;
}
});
- const got = await lsp.shouldUpdateLanguageServer(tool, 'bad/path/to/gopls', true);
+ const got = await lsp.shouldUpdateLanguageServer(tool, {
+ enabled: true,
+ path: 'bad/path/to/gopls',
+ checkForUpdates: true,
+ env: {},
+ features: {
+ diagnostics: true,
+ documentLink: true,
+ },
+ flags: [],
+ modtime: new Date(),
+ serverName: 'gopls',
+ });
assert.deepEqual(got, want, `${name}: failed (got: '${got}' ${typeof got} want: '${want}' ${typeof want})`);
sinon.restore();
}