blob: 466cbdfbdf6a5adb01bddb1c22d88564539237e3 [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 { getTool } from '../goTools';
import {
buildLanguageClient,
buildLanguageClientOption,
buildLanguageServerConfig,
errorKind,
languageServerUsingDefault,
RestartReason,
scheduleGoplsSuggestions,
stopLanguageClient,
suggestGoplsIssueReport,
suggestUpdateGopls,
toServerInfo,
updateRestartHistory
} from '../language/goLanguageServer';
import { LegacyLanguageService } from '../language/registerDefaultProviders';
import { Mutex } from '../utils/mutex';
const languageServerStartMutex = new Mutex();
export const startLanguageServer: CommandFactory = (ctx, goCtx) => {
return async (reason: RestartReason = RestartReason.MANUAL) => {
const goConfig = getGoConfig();
const cfg = buildLanguageServerConfig(goConfig);
if (typeof reason === 'string') {
updateRestartHistory(goCtx, reason, cfg.enabled);
}
const unlock = await languageServerStartMutex.lock();
try {
if (reason === RestartReason.MANUAL) {
await suggestGoplsIssueReport(
goCtx,
"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);
}
// 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 the language server is gopls, we enable a few additional features.
if (cfg.serverName === 'gopls') {
const tool = getTool(cfg.serverName);
if (tool) {
// If the language server is turned on because it is enabled by default,
// make sure that the user is using a new enough version.
if (cfg.enabled && languageServerUsingDefault(goConfig)) {
suggestUpdateGopls(tool, cfg);
}
}
}
if (!cfg.enabled) {
const legacyService = new LegacyLanguageService(ctx, goCtx);
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);
updateStatus(goCtx, goConfig, true);
console.log(`Server: ${JSON.stringify(goCtx.serverInfo, null, 2)}`);
} finally {
goCtx.latestConfig = cfg;
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.appendLine(
'Language service on the guest side is disabled. ' +
'The server-side language service will provide the language features.'
);
return;
case 'ssh':
outputChannel.appendLine('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.appendLine(
`None of the folders in this workspace ${schemes.join(
','
)} are the types the language server recognizes. Disabling the language features.`
);
return;
}
return true;
}