in Extension/src/LanguageServer/client.ts [882:1068]
constructor(allClients: ClientCollection, workspaceFolder?: vscode.WorkspaceFolder) {
this.rootFolder = workspaceFolder;
this.rootRealPath = this.RootPath ? (fs.existsSync(this.RootPath) ? fs.realpathSync(this.RootPath) : this.RootPath) : "";
let storagePath: string | undefined;
if (util.extensionContext) {
const path: string | undefined = util.extensionContext.storageUri?.fsPath;
if (path) {
storagePath = path;
}
}
if (!storagePath) {
storagePath = this.RootPath ? path.join(this.RootPath, "/.vscode") : "";
}
if (workspaceFolder && vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 1) {
storagePath = path.join(storagePath, util.getUniqueWorkspaceStorageName(workspaceFolder));
}
this.storagePath = storagePath;
const rootUri: vscode.Uri | undefined = this.RootUri;
this.settingsTracker = getTracker(rootUri);
try {
let firstClient: boolean = false;
if (!languageClient || languageClientCrashedNeedsRestart) {
if (languageClientCrashedNeedsRestart) {
languageClientCrashedNeedsRestart = false;
}
languageClient = this.createLanguageClient(allClients);
clientCollection = allClients;
languageClient.registerProposedFeatures();
languageClient.start(); // This returns Disposable, but doesn't need to be tracked because we call .stop() explicitly in our dispose()
util.setProgress(util.getProgressExecutableStarted());
firstClient = true;
}
ui = getUI();
ui.bind(this);
// requests/notifications are deferred until this.languageClient is set.
this.queueBlockingTask(async () => {
await languageClient.onReady();
try {
const workspaceFolder: vscode.WorkspaceFolder | undefined = this.rootFolder;
this.innerConfiguration = new configs.CppProperties(rootUri, workspaceFolder);
this.innerConfiguration.ConfigurationsChanged((e) => this.onConfigurationsChanged(e));
this.innerConfiguration.SelectionChanged((e) => this.onSelectedConfigurationChanged(e));
this.innerConfiguration.CompileCommandsChanged((e) => this.onCompileCommandsChanged(e));
this.disposables.push(this.innerConfiguration);
this.innerLanguageClient = languageClient;
telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings());
failureMessageShown = false;
class CodeActionProvider implements vscode.CodeActionProvider {
private client: DefaultClient;
constructor(client: DefaultClient) {
this.client = client;
}
public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<(vscode.Command | vscode.CodeAction)[]> {
return this.client.requestWhenReady(async () => {
let r: Range;
if (range instanceof vscode.Selection) {
if (range.active.isBefore(range.anchor)) {
r = Range.create(Position.create(range.active.line, range.active.character), Position.create(range.anchor.line, range.anchor.character));
} else {
r = Range.create(Position.create(range.anchor.line, range.anchor.character), Position.create(range.active.line, range.active.character));
}
} else {
r = Range.create(Position.create(range.start.line, range.start.character), Position.create(range.end.line, range.end.character));
}
const params: GetCodeActionsRequestParams = {
range: r,
uri: document.uri.toString()
};
const commands: CodeActionCommand[] = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params);
const resultCodeActions: vscode.CodeAction[] = [];
// Convert to vscode.CodeAction array
commands.forEach((command) => {
const title: string = util.getLocalizedString(command.localizeStringParams);
let edit: vscode.WorkspaceEdit | undefined;
if (command.edit) {
edit = new vscode.WorkspaceEdit();
edit.replace(document.uri, new vscode.Range(
new vscode.Position(command.edit.range.start.line, command.edit.range.start.character),
new vscode.Position(command.edit.range.end.line, command.edit.range.end.character)),
command.edit.newText);
}
const vscodeCodeAction: vscode.CodeAction = {
title: title,
command: command.command === "edit" ? undefined : {
title: title,
command: command.command,
arguments: command.arguments
},
edit: edit,
kind: edit === undefined ? vscode.CodeActionKind.QuickFix : vscode.CodeActionKind.RefactorInline
};
resultCodeActions.push(vscodeCodeAction);
});
return resultCodeActions;
});
}
}
// Semantic token types are identified by indexes in this list of types, in the legend.
const tokenTypesLegend: string[] = [];
for (const e in SemanticTokenTypes) {
// An enum is actually a set of mappings from key <=> value. Enumerate over only the names.
// This allow us to represent the constants using an enum, which we can match in native code.
if (isNaN(Number(e))) {
tokenTypesLegend.push(e);
}
}
// Semantic token modifiers are bit indexes corresponding to the indexes in this list of modifiers in the legend.
const tokenModifiersLegend: string[] = [];
for (const e in SemanticTokenModifiers) {
if (isNaN(Number(e))) {
tokenModifiersLegend.push(e);
}
}
this.semanticTokensLegend = new vscode.SemanticTokensLegend(tokenTypesLegend, tokenModifiersLegend);
if (firstClient) {
workspaceReferences = new refs.ReferencesManager(this);
// The configurations will not be sent to the language server until the default include paths and frameworks have been set.
// The event handlers must be set before this happens.
const inputCompilerDefaults: configs.CompilerDefaults = await languageClient.sendRequest(QueryCompilerDefaultsRequest, {});
compilerDefaults = inputCompilerDefaults;
this.configuration.CompilerDefaults = compilerDefaults;
// Only register file watchers, providers, and the real commands after the extension has finished initializing,
// e.g. prevents empty c_cpp_properties.json from generation.
registerCommands();
this.registerFileWatcher();
this.disposables.push(vscode.languages.registerRenameProvider(this.documentSelector, new RenameProvider(this)));
this.disposables.push(vscode.languages.registerReferenceProvider(this.documentSelector, new FindAllReferencesProvider(this)));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this)));
this.disposables.push(vscode.languages.registerDocumentSymbolProvider(this.documentSelector, new DocumentSymbolProvider(this), undefined));
this.disposables.push(vscode.languages.registerCodeActionsProvider(this.documentSelector, new CodeActionProvider(this), undefined));
const settings: CppSettings = new CppSettings();
if (settings.formattingEngine !== "Disabled") {
this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(this.documentSelector, new DocumentFormattingEditProvider(this));
this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(this.documentSelector, new DocumentRangeFormattingEditProvider(this));
this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(this.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n");
}
if (settings.codeFolding) {
this.codeFoldingProvider = new FoldingRangeProvider(this);
this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(this.documentSelector, this.codeFoldingProvider);
}
if (settings.enhancedColorization && this.semanticTokensLegend) {
this.semanticTokensProvider = new SemanticTokensProvider(this);
this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(this.documentSelector, this.semanticTokensProvider, this.semanticTokensLegend);
}
// Listen for messages from the language server.
this.registerNotifications();
} else {
this.configuration.CompilerDefaults = compilerDefaults;
}
} catch (err) {
this.isSupported = false; // Running on an OS we don't support yet.
if (!failureMessageShown) {
failureMessageShown = true;
vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", String(err)));
}
}
});
} catch (errJS) {
const err: NodeJS.ErrnoException = errJS as NodeJS.ErrnoException;
this.isSupported = false; // Running on an OS we don't support yet.
if (!failureMessageShown) {
failureMessageShown = true;
let additionalInfo: string;
if (err.code === "EPERM") {
additionalInfo = localize('check.permissions', "EPERM: Check permissions for '{0}'", getLanguageServerFileName());
} else {
additionalInfo = String(err);
}
vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", additionalInfo));
}
}
}