src/goStatus: present error icon if gopls couldn't be found

We wanted the missing gopls error notification to be more
visible, but for some reason, sometimes it's auto-collapsed
and only visible only if user clicks the bell in the right
bottom corner. Even though there should be the "Analysis
tools missing" error, it may be difficult for users to miss
that. Add another icon next to the go version string in the
Go status bar item.

When the user clicks the Go status bar item, the quickpick
menu includes an option to install gopls.

We also promoted the missing tool notification to 'error'
level - missing tool is an error.

Change-Id: Ice121a186f7b23ec94663579087aa737e93df792
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/286672
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts
index d63334a..43e7334 100644
--- a/src/goInstallTools.ts
+++ b/src/goInstallTools.ts
@@ -302,7 +302,7 @@
 	}
 	const msg = `The "${tool.name}" command is not available.
 Run "go get -v ${getImportPath(tool, goVersion)}" to install.`;
-	const selected = await vscode.window.showInformationMessage(msg, ...installOptions);
+	const selected = await vscode.window.showErrorMessage(msg, ...installOptions);
 	switch (selected) {
 		case 'Install':
 			await installTools([tool], goVersion);
@@ -527,8 +527,8 @@
 
 async function suggestDownloadGo() {
 	const msg = `Failed to find the "go" binary in either GOROOT(${getCurrentGoRoot()}) or PATH(${envPath}).` +
-			`Check PATH, or Install Go and reload the window. ` +
-			`If PATH isn't what you expected, see https://github.com/golang/vscode-go/issues/971`;
+		`Check PATH, or Install Go and reload the window. ` +
+		`If PATH isn't what you expected, see https://github.com/golang/vscode-go/issues/971`;
 	if (suggestedDownloadGo) {
 		vscode.window.showErrorMessage(msg);
 		return;
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index c2a70a3..914d158 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -168,7 +168,8 @@
 			// We already created various notification - e.g. missing gopls, ...
 			// So, just leave a log message here instead of issuing one more notification.
 			outputChannel.appendLine(
-				`Failed to start the language server (${cfg.serverName}). Falling back to default language providers...`);
+				`Failed to start the language server (gopls). Falling back to default language providers...`);
+			outputChannel.show();
 		}
 		// If the server has been disabled, or failed to start,
 		// fall back to the default providers, while making sure not to
@@ -179,7 +180,7 @@
 
 		if (disposable) { disposable.dispose(); }
 		languageServerIsRunning = started;
-		updateLanguageServerIconGoStatusBar(started, cfg.serverName);
+		updateLanguageServerIconGoStatusBar(started, goConfig['useLanguageServer']);
 		languageServerStartInProgress = false;
 	});
 }
diff --git a/src/goStatus.ts b/src/goStatus.ts
index 3f31d04..d3306ef 100644
--- a/src/goStatus.ts
+++ b/src/goStatus.ts
@@ -13,6 +13,7 @@
 import { buildLanguageServerConfig, getLocalGoplsVersion, languageServerIsRunning, serverOutputChannel } from './goLanguageServer';
 import { isGoFile } from './goMode';
 import { getModFolderPath, isModSupported } from './goModules';
+import { allToolsInformation } from './goTools';
 import { getGoVersion } from './util';
 
 export let outputChannel = vscode.window.createOutputChannel('Go');
@@ -24,6 +25,7 @@
 
 let modulePath: string;
 export const languageServerIcon = '$(zap)';
+export const languageServerErrorIcon = '$(warning)';
 
 export function updateGoStatusBar(editor: vscode.TextEditor) {
 	// Only update the module path if we are in a Go file.
@@ -47,11 +49,17 @@
 	];
 
 	// Get the gopls configuration
-	const cfg = buildLanguageServerConfig(getGoConfig());
+	const goConfig = getGoConfig();
+	const cfg = buildLanguageServerConfig(goConfig);
 	if (languageServerIsRunning && cfg.serverName === 'gopls') {
 		const goplsVersion = await getLocalGoplsVersion(cfg);
 		options.push({label: `${languageServerIcon}Open 'gopls' trace`, description: `${goplsVersion}`});
 	}
+	if (!languageServerIsRunning && !cfg.serverName && goConfig['useLanguageServer']) {
+		options.push({
+			label: `Install Go Language Server`,
+			description: `${languageServerErrorIcon}'gopls' is required but missing`});
+	}
 
 	// If modules is enabled, add link to mod file
 	if (!!modulePath) {
@@ -72,6 +80,9 @@
 						serverOutputChannel.show();
 					}
 					break;
+				case `Install Go Language Server`:
+					vscode.commands.executeCommand('go.tools.install', [allToolsInformation['gopls']]);
+					break;
 				case `Open 'go.mod'`:
 					const openPath = vscode.Uri.file(item.description);
 					vscode.workspace.openTextDocument(openPath).then((doc) => {
@@ -101,27 +112,37 @@
 	// Add an icon to indicate that the 'gopls' server is running.
 	// Assume if it is configured it is already running, since the
 	// icon will be updated on an attempt to start.
-	const cfg = buildLanguageServerConfig(getGoConfig());
-	updateLanguageServerIconGoStatusBar(languageServerIsRunning, cfg.serverName);
+	const goConfig = getGoConfig();
+	const cfg = buildLanguageServerConfig(goConfig);
+	updateLanguageServerIconGoStatusBar(languageServerIsRunning, goConfig['useLanguageServer']);
 
 	showGoStatusBar();
 }
 
-export async function updateLanguageServerIconGoStatusBar(started: boolean, server: string) {
+export function updateLanguageServerIconGoStatusBar(started: boolean, enabled: boolean) {
 	if (!goEnvStatusbarItem) {
 		return;
 	}
 
-	const text = goEnvStatusbarItem.text;
-	if (started && server === 'gopls') {
-		if (!text.endsWith(languageServerIcon)) {
-			goEnvStatusbarItem.text = text + languageServerIcon;
-		}
-	} else {
-		if (text.endsWith(languageServerIcon)) {
-			goEnvStatusbarItem.text = text.substring(0, text.length - languageServerIcon.length);
-		}
+	// Split the existing goEnvStatusbarItem.text into the version string part and
+	// the gopls icon part.
+	let text = goEnvStatusbarItem.text;
+	let icon = '';
+	if (text.endsWith(languageServerIcon)) {
+		icon = languageServerIcon;
+		text = text.substring(0, text.length - languageServerIcon.length);
+	} else if (text.endsWith(languageServerErrorIcon)) {
+		icon = languageServerErrorIcon;
+		text = text.substring(0, text.length - languageServerErrorIcon.length);
 	}
+
+	if (started && enabled) {
+		icon = languageServerIcon;
+	} else if (!started && enabled) {
+		icon = languageServerErrorIcon;
+	}
+
+	goEnvStatusbarItem.text = text + icon;
 }
 
 /**