goLanguageServer: restart the language server 5x when it crashes

A little cleanup, and a fix for the "Never" button.
I also added handling for alternateTools for gopls, since I noticed
that it wouldn't pick up the change in setting.

I really wanted to add tests for this behavior, but constructing a
version of gopls that worked enough to initialize but then crashed
seemed to be more effort than this test is worth. Also, the timing of
waiting for the crash was just too complicated.

Change-Id: Idfb7192e875dcddc3efe55011cd1b59be57b337b
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/238657
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index ec374fd..e2afaca 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -64,6 +64,7 @@
 let latestConfig: LanguageServerConfig;
 let serverOutputChannel: vscode.OutputChannel;
 let serverTraceChannel: vscode.OutputChannel;
+let crashCount = 0;
 
 // defaultLanguageProviders is the list of providers currently registered.
 let defaultLanguageProviders: vscode.Disposable[] = [];
@@ -131,6 +132,7 @@
 		// and rebuild the language client.
 		latestConfig = config;
 		languageClient = await buildLanguageClient(config);
+		crashCount = 0;
 	}
 
 	// If the user has not enabled the language server, return early.
@@ -203,13 +205,18 @@
 					vscode.window.showErrorMessage(
 						`Error communicating with the language server: ${error}: ${message}.`
 					);
-					// Stick with the default number of 5 crashes before shutdown.
-					if (count >= 5) {
-						return ErrorAction.Shutdown;
+					// Allow 5 crashes before shutdown.
+					if (count < 5) {
+						return ErrorAction.Continue;
 					}
-					return ErrorAction.Continue;
+					return ErrorAction.Shutdown;
 				},
 				closed: (): CloseAction => {
+					// Allow 5 crashes before shutdown.
+					crashCount++;
+					if (crashCount < 5) {
+						return CloseAction.Restart;
+					}
 					serverOutputChannel.show();
 					suggestGoplsIssueReport(`The connection to gopls has been closed. The gopls server may have crashed.`);
 					return CloseAction.DoNotRestart;
@@ -348,7 +355,8 @@
 	if (
 		e.affectsConfiguration('go.useLanguageServer') ||
 		e.affectsConfiguration('go.languageServerFlags') ||
-		e.affectsConfiguration('go.languageServerExperimentalFeatures')
+		e.affectsConfiguration('go.languageServerExperimentalFeatures') ||
+		e.affectsConfiguration('go.alternateTools')
 	) {
 		restartLanguageServer();
 	}
@@ -812,14 +820,14 @@
 	const promptForIssueOnGoplsRestartKey = `promptForIssueOnGoplsRestart`;
 	let saved: any;
 	try {
-		saved = JSON.parse(getFromGlobalState(promptForIssueOnGoplsRestartKey, true));
+		saved = JSON.parse(getFromGlobalState(promptForIssueOnGoplsRestartKey, false));
 	} catch (err) {
 		console.log(`Failed to parse as JSON ${getFromGlobalState(promptForIssueOnGoplsRestartKey, true)}: ${err}`);
 		return;
 	}
 	// If the user has already seen this prompt, they may have opted-out for
 	// the future. Only prompt again if it's been more than a year since.
-	if (saved['date'] && saved['prompt']) {
+	if (saved) {
 		const dateSaved = new Date(saved['date']);
 		const prompt = <boolean>saved['prompt'];
 		if (!prompt && daysBetween(new Date(), dateSaved) <= 365) {
diff --git a/src/goPath.ts b/src/goPath.ts
index c069171..6f4d742 100644
--- a/src/goPath.ts
+++ b/src/goPath.ts
@@ -36,15 +36,15 @@
 	preferredGopaths: string[],
 	alternateTool?: string
 ) {
-	if (binPathCache[toolName]) {
-		return binPathCache[toolName];
-	}
-
 	if (alternateTool && path.isAbsolute(alternateTool) && executableFileExists(alternateTool)) {
 		binPathCache[toolName] = alternateTool;
 		return alternateTool;
 	}
 
+	if (binPathCache[toolName]) {
+		return binPathCache[toolName];
+	}
+
 	const binname = alternateTool && !path.isAbsolute(alternateTool) ? alternateTool : toolName;
 	const pathFromGoBin = getBinPathFromEnvVar(binname, process.env['GOBIN'], false);
 	if (pathFromGoBin) {