src/goEnvironmentStatus.ts: create status bar item for Go environment

This CL is the first in a series which should follow this general
outline:

1. Create status bar item for switching Go binary (not implemented)
2. Create command palette menu for choosing the Go binary
3. Track the currently selected Go binary using workspace context
4. Show versions of Go that are not installed and allow them to be
selected and installed
5. Ensure new integrated terminals use the selected environment
6. Detect if Go is not installed and prompt to install it
7. Detect if user has the latest version of Go installed and prompt them
to install it
8. Cache Go paths upon extension initialization for faster menu loading

This CL only creates a status bar item that displays the current Go
path when pressed.

Change-Id: I6d15811250fc9eaa257db071358261c906bbfe0a
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/238624
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/package.json b/package.json
index 2cf105b..409d2bc 100644
--- a/package.json
+++ b/package.json
@@ -345,6 +345,11 @@
         "command": "go.languageserver.restart",
         "title": "Go: Restart Language Server",
         "description": "Restart the running instance of the language server"
+      },
+      {
+        "command": "go.environment.choose",
+        "title": "Go: Choose Go Environment",
+        "description": "Choose a different Go version or binary for this project. (WIP)"
       }
     ],
     "breakpoints": [
diff --git a/src/goEnvironmentStatus.ts b/src/goEnvironmentStatus.ts
new file mode 100644
index 0000000..ee6f9d7
--- /dev/null
+++ b/src/goEnvironmentStatus.ts
@@ -0,0 +1,102 @@
+/*---------------------------------------------------------
+ * Copyright 2020 The Go Authors. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *--------------------------------------------------------*/
+
+'use strict';
+
+import vscode = require('vscode');
+
+import { updateGoVarsFromConfig } from './goInstallTools';
+import { getCurrentGoRoot } from './goPath';
+import { getGoVersion } from './util';
+
+// statusbar item for switching the Go environment
+let goEnvStatusbarItem: vscode.StatusBarItem;
+
+/**
+ * Initialize the status bar item with current Go binary
+ */
+export async function initGoStatusBar() {
+	goEnvStatusbarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 50);
+
+	// make goroot default to go.goroot and fallback on $PATH
+	const goroot = await getActiveGoRoot();
+	if (!goroot) {
+		// TODO: prompt user to install Go
+		vscode.window.showErrorMessage('No Go command could be found.');
+	}
+
+	// set Go version and command
+	const version = await getGoVersion();
+	goEnvStatusbarItem.text = formatGoVersion(version.format());
+	goEnvStatusbarItem.command = 'go.environment.choose';
+
+	showGoStatusBar();
+}
+
+/**
+ * disable the Go environment status bar item
+ */
+export function disposeGoStatusBar() {
+	if (!!goEnvStatusbarItem) {
+		goEnvStatusbarItem.dispose();
+	}
+}
+
+/**
+ * Show the Go Environment statusbar item on the statusbar
+ */
+export function showGoStatusBar() {
+	if (!!goEnvStatusbarItem) {
+		goEnvStatusbarItem.show();
+	}
+}
+
+/**
+ * Hide the Go Environment statusbar item from the statusbar
+ */
+export function hideGoStatusBar() {
+	if (!!goEnvStatusbarItem) {
+		goEnvStatusbarItem.hide();
+	}
+}
+
+/**
+ * Present a command palette menu to the user to select their go binary
+ * TODO: remove temporary alert and implement correct functionality
+ */
+export function chooseGoEnvironment() {
+	vscode.window.showInformationMessage(`Current GOROOT: ${getCurrentGoRoot()}`);
+}
+
+/**
+ * return reference to the statusbar item
+ */
+export function getGoEnvironmentStatusbarItem(): vscode.StatusBarItem {
+	return goEnvStatusbarItem;
+}
+
+export async function getActiveGoRoot(): Promise<string | undefined> {
+	// look for current current go binary
+	let goroot = getCurrentGoRoot();
+	if (!goroot) {
+		await updateGoVarsFromConfig();
+		goroot = getCurrentGoRoot();
+	}
+	return goroot || undefined;
+}
+
+export function formatGoVersion(version: string): string {
+	const versionWords = version.split(' ');
+	if (versionWords[0] === 'devel') {
+		// Go devel +hash
+		return `Go ${versionWords[0]} ${versionWords[4]}`;
+	} else if (versionWords.length > 0) {
+		// some other version format
+		return `Go ${version.substr(0, 8)}`;
+	} else {
+		// default semantic version format
+		return `Go ${versionWords[0]}`;
+	}
+}
diff --git a/src/goMain.ts b/src/goMain.ts
index 0f7b50c..ac4fc8e 100644
--- a/src/goMain.ts
+++ b/src/goMain.ts
@@ -19,6 +19,7 @@
 import { GoDebugConfigurationProvider } from './goDebugConfiguration';
 import { extractFunction, extractVariable } from './goDoctor';
 import { toolExecutionEnvironment } from './goEnv';
+import { chooseGoEnvironment, initGoStatusBar } from './goEnvironmentStatus';
 import { runFillStruct } from './goFillStruct';
 import * as goGenerateTests from './goGenerateTests';
 import { goGetPackage } from './goGetPackage';
@@ -169,6 +170,9 @@
 	);
 	showHideStatus(vscode.window.activeTextEditor);
 
+	// show the go environment status bar item
+	initGoStatusBar();
+
 	const testCodeLensProvider = new GoRunTestCodeLensProvider();
 	const referencesCodeLensProvider = new GoReferencesCodeLensProvider();
 
@@ -559,6 +563,13 @@
 		})
 	);
 
+	// Go Enviornment switching commands
+	ctx.subscriptions.push(
+		vscode.commands.registerCommand('go.environment.choose', () => {
+			chooseGoEnvironment();
+		})
+	);
+
 	vscode.languages.setLanguageConfiguration(GO_MODE.language, {
 		wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g
 	});
diff --git a/test/integration/statusbar.test.ts b/test/integration/statusbar.test.ts
new file mode 100644
index 0000000..f55d34e
--- /dev/null
+++ b/test/integration/statusbar.test.ts
@@ -0,0 +1,35 @@
+/*---------------------------------------------------------
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ * Modification copyright 2020 The Go Authors. All rights reserved.
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
+ *--------------------------------------------------------*/
+
+import * as assert from 'assert';
+import { describe, it } from 'mocha';
+
+import { disposeGoStatusBar, formatGoVersion, getGoEnvironmentStatusbarItem, initGoStatusBar } from '../../src/goEnvironmentStatus';
+import { getGoVersion } from '../../src/util';
+
+describe('#initGoStatusBar()', function () {
+	this.beforeAll(() => {
+		initGoStatusBar();
+	});
+
+	this.afterAll(() => {
+		disposeGoStatusBar();
+	});
+
+	it('should create a status bar item', () => {
+		assert.notEqual(getGoEnvironmentStatusbarItem(), undefined);
+	});
+
+	it('should create a status bar item with a label matching go.goroot version', async () =>  {
+		const version = await getGoVersion();
+		const versionLabel = formatGoVersion(version.format());
+		assert.equal(
+			getGoEnvironmentStatusbarItem().text,
+			versionLabel,
+			'goroot version does not match status bar item text'
+		);
+	});
+});