blob: 3c13e3142bbc89f16aef3f2aa5c11be26ff896d1 [file] [log] [blame]
/*---------------------------------------------------------
* Copyright 2022 The Go Authors. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
import * as vscode from 'vscode';
import { CommandFactory } from '.';
import { getGoConfig } from '../config';
import { GoExtensionContext } from '../context';
import { outputChannel, updateLanguageServerIconGoStatusBar } from '../goStatus';
import {
buildLanguageClient,
buildLanguageClientOption,
buildLanguageServerConfig,
errorKind,
RestartReason,
scheduleGoplsSuggestions,
stopLanguageClient,
suggestGoplsIssueReport,
toServerInfo,
updateRestartHistory
} from '../language/goLanguageServer';
import { LegacyLanguageService } from '../language/registerDefaultProviders';
import { Mutex } from '../utils/mutex';
import { TelemetryService } from '../goTelemetry';
const languageServerStartMutex = new Mutex();
export const startLanguageServer: CommandFactory = (ctx, goCtx) => {
return async (reason: RestartReason = RestartReason.MANUAL) => {
const goConfig = getGoConfig();
const cfg = await buildLanguageServerConfig(goConfig);
if (typeof reason === 'string') {
updateRestartHistory(goCtx, reason, cfg.enabled);
}
const unlock = await languageServerStartMutex.lock();
goCtx.latestConfig = cfg;
try {
if (reason === RestartReason.MANUAL) {
await suggestGoplsIssueReport(
goCtx,
cfg,
"Looks like you're about to manually restart the language server.",
errorKind.manualRestart
);
}
// If the client has already been started, make sure to clear existing
// diagnostics and stop it.
if (goCtx.languageClient) {
await stopLanguageClient(goCtx);
}
updateStatus(goCtx, goConfig, false);
// Before starting the language server, make sure to deregister any
// currently registered language providers.
if (goCtx.legacyLanguageService) {
goCtx.legacyLanguageService.dispose();
goCtx.legacyLanguageService = undefined;
}
if (!shouldActivateLanguageFeatures()) {
return;
}
// We have some extra prompts for gopls users and for people who have opted
// out of gopls.
if (reason === RestartReason.ACTIVATION) {
scheduleGoplsSuggestions(goCtx);
}
if (!cfg.enabled) {
const legacyService = new LegacyLanguageService();
goCtx.legacyLanguageService = legacyService;
ctx.subscriptions.push(legacyService);
updateStatus(goCtx, goConfig, false);
return;
}
goCtx.languageClient = await buildLanguageClient(goCtx, buildLanguageClientOption(goCtx, cfg));
await goCtx.languageClient.start();
goCtx.serverInfo = toServerInfo(goCtx.languageClient.initializeResult);
goCtx.telemetryService = new TelemetryService(
goCtx.languageClient,
ctx.globalState,
goCtx.serverInfo?.Commands
);
updateStatus(goCtx, goConfig, true);
console.log(`Server: ${JSON.stringify(goCtx.serverInfo, null, 2)}`);
} catch (e) {
const msg = `Error starting language server: ${e}`;
console.log(msg);
goCtx.serverOutputChannel?.append(msg);
} finally {
unlock();
}
};
};
function updateStatus(goCtx: GoExtensionContext, goConfig: vscode.WorkspaceConfiguration, didStart: boolean) {
goCtx.languageServerIsRunning = didStart;
vscode.commands.executeCommand('setContext', 'go.goplsIsRunning', didStart);
updateLanguageServerIconGoStatusBar(didStart, goConfig['useLanguageServer'] === true);
}
function shouldActivateLanguageFeatures() {
for (const folder of vscode.workspace.workspaceFolders || []) {
switch (folder.uri.scheme) {
case 'vsls':
outputChannel.error(
'Language service on the guest side is disabled. ' +
'The server-side language service will provide the language features.'
);
return;
case 'ssh':
outputChannel.error('The language server is not supported for SSH. Disabling it.');
return;
}
}
const schemes = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.scheme);
if (schemes && schemes.length > 0 && !schemes.includes('file') && !schemes.includes('untitled')) {
outputChannel.error(
`None of the folders in this workspace ${schemes.join(
','
)} are the types the language server recognizes. Disabling the language features.`
);
return;
}
return true;
}
export const startGoplsMaintainerInterface: CommandFactory = (ctx, goCtx) => {
return () => {
if (!goCtx.languageServerIsRunning) {
vscode.window.showErrorMessage(
'"Go: Start language server\'s maintainer interface" command is available only when the language server is running'
);
return;
}
vscode.commands.executeCommand('gopls.start_debugging', {}).then(undefined, (reason) => {
vscode.window.showErrorMessage(
`"Go: Start language server's maintainer interface" command failed: ${reason}`
);
});
};
};