export async function activate()

in src/goMain.ts [125:719]


export async function activate(ctx: vscode.ExtensionContext): Promise<ExtensionAPI> {
	if (process.env['VSCODE_GO_IN_TEST'] === '1') {
		// Make sure this does not run when running in test.
		return;
	}

	setGlobalState(ctx.globalState);
	setWorkspaceState(ctx.workspaceState);
	setEnvironmentVariableCollection(ctx.environmentVariableCollection);

	const cfg = getGoConfig();
	setLogConfig(cfg['logging']);

	if (vscode.window.registerWebviewPanelSerializer) {
		// Make sure we register a serializer in activation event
		vscode.window.registerWebviewPanelSerializer(WelcomePanel.viewType, {
			async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
				WelcomePanel.revive(webviewPanel, ctx.extensionUri);
			}
		});
	}

	if (isInPreviewMode()) {
		// For Nightly extension users, show a message directing them to forums
		// to give feedback.
		setTimeout(showGoNightlyWelcomeMessage, 10 * timeMinute);
	}

	// Show the Go welcome page on update.
	if (!IsInCloudIDE) {
		showGoWelcomePage(ctx);
	}

	const configGOROOT = getGoConfig()['goroot'];
	if (configGOROOT) {
		// We don't support unsetting go.goroot because we don't know whether
		// !configGOROOT case indicates the user wants to unset process.env['GOROOT']
		// or the user wants the extension to use the current process.env['GOROOT'] value.
		// TODO(hyangah): consider utilizing an empty value to indicate unset?
		await setGOROOTEnvVar(configGOROOT);
	}

	// Present a warning about the deprecation of the go.documentLink setting.
	const experimentalFeatures = getGoConfig()['languageServerExperimentalFeatures'];
	if (experimentalFeatures) {
		// TODO(golang/vscode-go#50): Eventually notify about deprecation of
		// all of the settings. See golang/vscode-go#1109 too.
		// The `diagnostics` setting is still used as a workaround for running custom vet.
		if (experimentalFeatures['documentLink'] === false) {
			vscode.window
				.showErrorMessage(`The 'go.languageServerExperimentalFeature.documentLink' setting is now deprecated.
Please use '"gopls": {"ui.navigation.importShortcut": "Definition" }' instead.
See [the settings doc](https://github.com/golang/vscode-go/blob/master/docs/settings.md#uinavigationimportshortcut) for more details.`);
		}
		const promptKey = 'promptedLanguageServerExperimentalFeatureDeprecation';
		const prompted = getFromGlobalState(promptKey, false);
		if (!prompted && experimentalFeatures['diagnostics'] === false) {
			const msg = `The 'go.languageServerExperimentalFeature.diagnostics' setting will be deprecated soon.
If you would like additional configuration for diagnostics from gopls, please see and response to [Issue 50](https://github.com/golang/vscode-go/issues/50).`;
			const selected = await vscode.window.showInformationMessage(msg, "Don't show again");
			switch (selected) {
				case "Don't show again":
					updateGlobalState(promptKey, true);
			}
		}
	}

	// Present a warning about the deprecation of a 'dlv-dap' binary setting.
	checkAlternateTools(cfg);

	updateGoVarsFromConfig().then(async () => {
		suggestUpdates(ctx);
		offerToInstallLatestGoVersion();
		offerToInstallTools();
		await configureLanguageServer(ctx);

		if (
			!languageServerIsRunning &&
			vscode.window.activeTextEditor &&
			vscode.window.activeTextEditor.document.languageId === 'go' &&
			isGoPathSet()
		) {
			// Check mod status so that cache is updated and then run build/lint/vet
			isModSupported(vscode.window.activeTextEditor.document.uri).then(() => {
				runBuilds(vscode.window.activeTextEditor.document, getGoConfig());
			});
		}
	});

	initCoverageDecorators(ctx);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.environment.status', async () => {
			expandGoStatusBar();
		})
	);
	const testCodeLensProvider = new GoRunTestCodeLensProvider();
	const referencesCodeLensProvider = new GoReferencesCodeLensProvider();

	ctx.subscriptions.push(vscode.languages.registerCodeLensProvider(GO_MODE, testCodeLensProvider));
	ctx.subscriptions.push(vscode.languages.registerCodeLensProvider(GO_MODE, referencesCodeLensProvider));

	// debug
	ctx.subscriptions.push(
		vscode.debug.registerDebugConfigurationProvider('go', new GoDebugConfigurationProvider('go'))
	);
	ctx.subscriptions.push(
		vscode.commands.registerCommand(
			'go.debug.pickProcess',
			async (): Promise<string> => {
				return await pickProcess();
			}
		)
	);
	ctx.subscriptions.push(
		vscode.commands.registerCommand(
			'go.debug.pickGoProcess',
			async (): Promise<string> => {
				return await pickGoProcess();
			}
		)
	);

	const debugOutputChannel = vscode.window.createOutputChannel('Go Debug');
	ctx.subscriptions.push(debugOutputChannel);

	const factory = new GoDebugAdapterDescriptorFactory(debugOutputChannel);
	ctx.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('go', factory));
	if ('dispose' in factory) {
		ctx.subscriptions.push(factory);
	}

	const tracker = new GoDebugAdapterTrackerFactory(debugOutputChannel);
	ctx.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory('go', tracker));
	if ('dispose' in tracker) {
		ctx.subscriptions.push(tracker);
	}

	buildDiagnosticCollection = vscode.languages.createDiagnosticCollection('go');
	ctx.subscriptions.push(buildDiagnosticCollection);
	lintDiagnosticCollection = vscode.languages.createDiagnosticCollection(
		lintDiagnosticCollectionName(getGoConfig()['lintTool'])
	);
	ctx.subscriptions.push(lintDiagnosticCollection);
	vetDiagnosticCollection = vscode.languages.createDiagnosticCollection('go-vet');
	ctx.subscriptions.push(vetDiagnosticCollection);

	addOnChangeTextDocumentListeners(ctx);
	addOnChangeActiveTextEditorListeners(ctx);
	addOnSaveTextDocumentListeners(ctx);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.gopath', () => {
			getCurrentGoPathCommand();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.locate.tools', async () => {
			getConfiguredGoToolsCommand();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.add.tags', (args) => {
			addTags(args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.remove.tags', (args) => {
			removeTags(args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.fill.struct', () => {
			runFillStruct(vscode.window.activeTextEditor);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.impl.cursor', () => {
			implCursor();
		})
	);
	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.godoctor.extract', () => {
			extractFunction();
		})
	);
	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.godoctor.var', () => {
			extractVariable();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.cursor', (args) => {
			const goConfig = getGoConfig();
			testAtCursor(goConfig, 'test', args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.cursorOrPrevious', (args) => {
			const goConfig = getGoConfig();
			testAtCursorOrPrevious(goConfig, 'test', args);
		})
	);

	if (isVscodeTestingAPIAvailable && cfg.get<boolean>('testExplorer.enable')) {
		GoTestExplorer.setup(ctx);
	}

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.subtest.cursor', (args) => {
			const goConfig = getGoConfig();
			subTestAtCursor(goConfig, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.debug.cursor', (args) => {
			const goConfig = getGoConfig();
			testAtCursor(goConfig, 'debug', args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.benchmark.cursor', (args) => {
			const goConfig = getGoConfig();
			testAtCursor(goConfig, 'benchmark', args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.package', (args) => {
			const goConfig = getGoConfig();
			const isBenchmark = false;
			testCurrentPackage(goConfig, isBenchmark, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.benchmark.package', (args) => {
			const goConfig = getGoConfig();
			const isBenchmark = true;
			testCurrentPackage(goConfig, isBenchmark, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.file', (args) => {
			const goConfig = getGoConfig();
			const isBenchmark = false;
			testCurrentFile(goConfig, isBenchmark, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.benchmark.file', (args) => {
			const goConfig = getGoConfig();
			const isBenchmark = true;
			testCurrentFile(goConfig, isBenchmark, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.workspace', (args) => {
			const goConfig = getGoConfig();
			testWorkspace(goConfig, args);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.previous', () => {
			testPrevious();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.debug.previous', () => {
			debugPrevious();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.coverage', () => {
			toggleCoverageCurrentPackage();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.showOutput', () => {
			showTestOutput();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.cancel', () => {
			cancelRunningTests();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.import.add', (arg) => {
			return addImport(arg);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.add.package.workspace', () => {
			addImportToWorkspace();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.tools.install', async (args) => {
			if (Array.isArray(args) && args.length) {
				const goVersion = await getGoVersion();
				await installTools(args, goVersion);
				return;
			}
			installAllTools();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.browse.packages', () => {
			browsePackages();
		})
	);

	ctx.subscriptions.push(
		vscode.workspace.onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => {
			if (!e.affectsConfiguration('go')) {
				return;
			}
			const updatedGoConfig = getGoConfig();

			if (e.affectsConfiguration('go.goroot')) {
				const configGOROOT = updatedGoConfig['goroot'];
				if (configGOROOT) {
					await setGOROOTEnvVar(configGOROOT);
				}
			}
			if (
				e.affectsConfiguration('go.goroot') ||
				e.affectsConfiguration('go.alternateTools') ||
				e.affectsConfiguration('go.gopath') ||
				e.affectsConfiguration('go.toolsEnvVars') ||
				e.affectsConfiguration('go.testEnvFile')
			) {
				updateGoVarsFromConfig();
			}
			if (e.affectsConfiguration('go.logging')) {
				setLogConfig(updatedGoConfig['logging']);
			}
			// If there was a change in "toolsGopath" setting, then clear cache for go tools
			if (getToolsGopath() !== getToolsGopath(false)) {
				clearCacheForTools();
			}

			if (updatedGoConfig['enableCodeLens']) {
				testCodeLensProvider.setEnabled(updatedGoConfig['enableCodeLens']['runtest']);
				referencesCodeLensProvider.setEnabled(updatedGoConfig['enableCodeLens']['references']);
			}

			if (e.affectsConfiguration('go.formatTool')) {
				checkToolExists(getFormatTool(updatedGoConfig));
			}
			if (e.affectsConfiguration('go.lintTool')) {
				checkToolExists(updatedGoConfig['lintTool']);
			}
			if (e.affectsConfiguration('go.docsTool')) {
				checkToolExists(updatedGoConfig['docsTool']);
			}
			if (e.affectsConfiguration('go.coverageDecorator')) {
				updateCodeCoverageDecorators(updatedGoConfig['coverageDecorator']);
			}
			if (e.affectsConfiguration('go.toolsEnvVars')) {
				const env = toolExecutionEnvironment();
				if (GO111MODULE !== env['GO111MODULE']) {
					const reloadMsg =
						'Reload VS Code window so that the Go tools can respect the change to GO111MODULE';
					vscode.window.showInformationMessage(reloadMsg, 'Reload').then((selected) => {
						if (selected === 'Reload') {
							vscode.commands.executeCommand('workbench.action.reloadWindow');
						}
					});
				}
			}
			if (e.affectsConfiguration('go.lintTool')) {
				const lintTool = lintDiagnosticCollectionName(updatedGoConfig['lintTool']);
				if (lintDiagnosticCollection && lintDiagnosticCollection.name !== lintTool) {
					lintDiagnosticCollection.dispose();
					lintDiagnosticCollection = vscode.languages.createDiagnosticCollection(lintTool);
					ctx.subscriptions.push(lintDiagnosticCollection);
					// TODO: actively maintain our own disposables instead of keeping pushing to ctx.subscription.
				}
			}
			if (e.affectsConfiguration('go.testExplorer.enable')) {
				const msg =
					'Go test explorer has been enabled or disabled. For this change to take effect, the window must be reloaded.';
				vscode.window.showInformationMessage(msg, 'Reload').then((selected) => {
					if (selected === 'Reload') {
						vscode.commands.executeCommand('workbench.action.reloadWindow');
					}
				});
			}
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.generate.package', () => {
			goGenerateTests.generateTestCurrentPackage();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.generate.file', () => {
			goGenerateTests.generateTestCurrentFile();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.test.generate.function', () => {
			goGenerateTests.generateTestCurrentFunction();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.toggle.test.file', () => {
			goGenerateTests.toggleTestFile();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.debug.startSession', (config) => {
			let workspaceFolder;
			if (vscode.window.activeTextEditor) {
				workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri);
			}

			return vscode.debug.startDebugging(workspaceFolder, config);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.show.commands', () => {
			const extCommands = getExtensionCommands();
			extCommands.push({
				command: 'editor.action.goToDeclaration',
				title: 'Go to Definition'
			});
			extCommands.push({
				command: 'editor.action.goToImplementation',
				title: 'Go to Implementation'
			});
			extCommands.push({
				command: 'workbench.action.gotoSymbol',
				title: 'Go to Symbol in File...'
			});
			extCommands.push({
				command: 'workbench.action.showAllSymbols',
				title: 'Go to Symbol in Workspace...'
			});
			vscode.window.showQuickPick(extCommands.map((x) => x.title)).then((cmd) => {
				const selectedCmd = extCommands.find((x) => x.title === cmd);
				if (selectedCmd) {
					vscode.commands.executeCommand(selectedCmd.command);
				}
			});
		})
	);

	ctx.subscriptions.push(vscode.commands.registerCommand('go.get.package', goGetPackage));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.playground', playgroundCommand));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.lint.package', () => lintCode('package')));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.lint.workspace', () => lintCode('workspace')));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.lint.file', () => lintCode('file')));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.vet.package', vetCode));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.vet.workspace', () => vetCode(true)));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.build.package', buildCode));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.build.workspace', () => buildCode(true)));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.install.package', installCurrentPackage));

	ctx.subscriptions.push(vscode.commands.registerCommand('go.run.modinit', goModInit));

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.extractServerChannel', () => {
			showServerOutputChannel();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.welcome', () => {
			WelcomePanel.createOrShow(ctx.extensionUri);
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.workspace.resetState', () => {
			resetWorkspaceState();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.global.resetState', () => {
			resetGlobalState();
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.toggle.gc_details', () => {
			if (!languageServerIsRunning) {
				vscode.window.showErrorMessage(
					'"Go: Toggle gc details" command is available only when the language server is running'
				);
				return;
			}
			const doc = vscode.window.activeTextEditor?.document.uri.toString();
			if (!doc || !doc.endsWith('.go')) {
				vscode.window.showErrorMessage('"Go: Toggle gc details" command cannot run when no Go file is open.');
				return;
			}
			vscode.commands.executeCommand('gc_details', doc).then(undefined, (reason0) => {
				vscode.commands.executeCommand('gopls.gc_details', doc).then(undefined, (reason1) => {
					vscode.window.showErrorMessage(
						`"Go: Toggle gc details" command failed: gc_details:${reason0} gopls_gc_details:${reason1}`
					);
				});
			});
		})
	);

	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.apply.coverprofile', () => {
			if (!vscode.window.activeTextEditor || !vscode.window.activeTextEditor.document.fileName.endsWith('.go')) {
				vscode.window.showErrorMessage('Cannot apply coverage profile when no Go file is open.');
				return;
			}
			const lastCoverProfilePathKey = 'lastCoverProfilePathKey';
			const lastCoverProfilePath = getFromWorkspaceState(lastCoverProfilePathKey, '');
			vscode.window
				.showInputBox({
					prompt: 'Enter the path to the coverage profile for current package',
					value: lastCoverProfilePath
				})
				.then((coverProfilePath) => {
					if (!coverProfilePath) {
						return;
					}
					if (!fileExists(coverProfilePath)) {
						vscode.window.showErrorMessage(`Cannot find the file ${coverProfilePath}`);
						return;
					}
					if (coverProfilePath !== lastCoverProfilePath) {
						updateWorkspaceState(lastCoverProfilePathKey, coverProfilePath);
					}
					applyCodeCoverageToAllEditors(
						coverProfilePath,
						getWorkspaceFolderPath(vscode.window.activeTextEditor.document.uri)
					);
				});
		})
	);

	// Go Enviornment switching commands
	ctx.subscriptions.push(
		vscode.commands.registerCommand('go.environment.choose', () => {
			chooseGoEnvironment();
		})
	);

	// Survey related commands
	ctx.subscriptions.push(vscode.commands.registerCommand('go.survey.showConfig', () => showSurveyConfig()));
	ctx.subscriptions.push(vscode.commands.registerCommand('go.survey.resetConfig', () => resetSurveyConfigs()));

	vscode.languages.setLanguageConfiguration(GO_MODE.language, {
		wordPattern: /(-?\d*\.\d\w*)|([^`~!@#%^&*()\-=+[{\]}\\|;:'",.<>/?\s]+)/g
	});

	return extensionAPI;
}