Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdbac5714b | ||
|
|
4d01799159 | ||
|
|
dde8653da5 | ||
|
|
154f56e4c7 | ||
|
|
95717b4eb4 | ||
|
|
2587d00a47 | ||
|
|
77c1a14635 | ||
|
|
07a4927c41 | ||
|
|
5351c00667 |
@@ -16,7 +16,6 @@ nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFo
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
|
||||
export class CopilotHoverProvider implements vscode.HoverProvider {
|
||||
private client: DefaultClient;
|
||||
private currentDocument: vscode.TextDocument | undefined;
|
||||
private currentPosition: vscode.Position | undefined;
|
||||
private currentCancellationToken: vscode.CancellationToken | undefined;
|
||||
@@ -30,8 +29,8 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
|
||||
private chatModelId: string | undefined; // Save the selected model ID to avoid trying the same unavailable model repeatedly.
|
||||
// Flag to avoid querying the LanguageModelChat repeatedly if no model is found
|
||||
private checkedChatModel: boolean = false;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async getCachedChatModel(): Promise<vscode.LanguageModelChat | undefined> {
|
||||
@@ -171,7 +170,6 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
|
||||
position: Position.create(position.line, position.character)
|
||||
};
|
||||
|
||||
await this.client.ready;
|
||||
if (this.currentCancellationToken?.isCancellationRequested) {
|
||||
throw new vscode.CancellationError();
|
||||
}
|
||||
|
||||
@@ -10,11 +10,10 @@ import { RequestCancelled, ServerCancelled } from '../protocolFilter';
|
||||
import { CppSettings } from '../settings';
|
||||
|
||||
export class HoverProvider implements vscode.HoverProvider {
|
||||
private client: DefaultClient;
|
||||
private lastContent: vscode.MarkdownString[] | undefined;
|
||||
private readonly hasContent = new ManualSignal<boolean>(true);
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
|
||||
@@ -36,7 +35,6 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
textDocument: { uri: document.uri.toString() },
|
||||
position: Position.create(position.line, position.character)
|
||||
};
|
||||
await this.client.ready;
|
||||
let hoverResult: vscode.Hover;
|
||||
try {
|
||||
hoverResult = await this.client.languageClient.sendRequest(HoverRequest, params, token);
|
||||
|
||||
@@ -214,15 +214,11 @@ export async function sendCallHierarchyCallsFromRequest(client: DefaultClient, i
|
||||
export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
// Indicates whether a request is from an entry root node (e.g. top function in the call tree).
|
||||
private isEntryRootNodeTelemetry: boolean = false;
|
||||
private client: DefaultClient;
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.CallHierarchyItem | undefined> {
|
||||
await this.client.ready;
|
||||
|
||||
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
|
||||
workspaceReferences.clearViews();
|
||||
|
||||
@@ -261,7 +257,6 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
}
|
||||
|
||||
public async provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyIncomingCall[] | undefined> {
|
||||
await this.client.ready;
|
||||
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
|
||||
|
||||
const CallHierarchyCallsToEvent: string = "CallHierarchyCallsTo";
|
||||
@@ -316,8 +311,6 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await this.client.ready;
|
||||
|
||||
const result: vscode.CallHierarchyOutgoingCall[] | undefined =
|
||||
await sendCallHierarchyCallsFromRequest(this.client, item, token);
|
||||
if (token.isCancellationRequested || result === undefined) {
|
||||
|
||||
@@ -40,9 +40,7 @@ export const GetCodeActionsRequest: RequestType<GetCodeActionsRequestParams, Get
|
||||
new RequestType<GetCodeActionsRequestParams, GetCodeActionsResult, void>('cpptools/getCodeActions');
|
||||
|
||||
export class CodeActionProvider implements vscode.CodeActionProvider {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
private static inlineMacroKind: vscode.CodeActionKind = vscode.CodeActionKind.RefactorInline.append("macro");
|
||||
@@ -51,7 +49,6 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
|
||||
|
||||
public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection,
|
||||
context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<(vscode.Command | vscode.CodeAction)[]> {
|
||||
await this.client.ready;
|
||||
let r: Range;
|
||||
if (range instanceof vscode.Selection) {
|
||||
if (range.active.isBefore(range.anchor)) {
|
||||
|
||||
@@ -11,9 +11,7 @@ import { CppSettings, OtherSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideDocumentFormattingEdits(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
|
||||
@@ -21,7 +19,6 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting
|
||||
if (settings.formattingEngine === "disabled") {
|
||||
return [];
|
||||
}
|
||||
await this.client.ready;
|
||||
const filePath: string = document.uri.fsPath;
|
||||
if (options.onChanges) {
|
||||
let insertSpacesSet: boolean = false;
|
||||
|
||||
@@ -11,9 +11,7 @@ import { CppSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class DocumentRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range,
|
||||
@@ -22,7 +20,6 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange
|
||||
if (settings.formattingEngine === "disabled") {
|
||||
return [];
|
||||
}
|
||||
await this.client.ready;
|
||||
const filePath: string = document.uri.fsPath;
|
||||
const useVcFormat: boolean = settings.useVcFormat(document);
|
||||
const configCallBack = async (editorConfigSettings: any | undefined) => {
|
||||
|
||||
@@ -58,14 +58,12 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
||||
public async provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<vscode.SymbolInformation[] | vscode.DocumentSymbol[]> {
|
||||
const client: Client = clients.getClientFor(document.uri);
|
||||
if (client instanceof DefaultClient) {
|
||||
const defaultClient: DefaultClient = <DefaultClient>client;
|
||||
await client.ready;
|
||||
const params: GetDocumentSymbolRequestParams = {
|
||||
uri: document.uri.toString()
|
||||
};
|
||||
let response: GetDocumentSymbolResult;
|
||||
try {
|
||||
response = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
|
||||
response = await client.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
throw new vscode.CancellationError();
|
||||
|
||||
@@ -56,14 +56,10 @@ export async function sendFindAllReferencesRequest(client: DefaultClient, uri: v
|
||||
}
|
||||
|
||||
export class FindAllReferencesProvider implements vscode.ReferenceProvider {
|
||||
private client: DefaultClient;
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideReferences(document: vscode.TextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
await this.client.ready;
|
||||
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
|
||||
|
||||
// Listen to a cancellation for this request. When this request is cancelled,
|
||||
|
||||
@@ -14,7 +14,6 @@ interface FoldingRangeRequestInfo {
|
||||
}
|
||||
|
||||
export class FoldingRangeProvider implements vscode.FoldingRangeProvider {
|
||||
private client: DefaultClient;
|
||||
public onDidChangeFoldingRangesEvent = new vscode.EventEmitter<void>();
|
||||
public onDidChangeFoldingRanges?: vscode.Event<void>;
|
||||
|
||||
@@ -22,12 +21,11 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider {
|
||||
// for the same file without waiting for the prior request to complete or cancelling them.
|
||||
private pendingRequests: Map<string, FoldingRangeRequestInfo> = new Map<string, FoldingRangeRequestInfo>();
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
this.onDidChangeFoldingRanges = this.onDidChangeFoldingRangesEvent.event;
|
||||
}
|
||||
|
||||
async provideFoldingRanges(document: vscode.TextDocument, context: vscode.FoldingContext, token: vscode.CancellationToken): Promise<vscode.FoldingRange[] | undefined> {
|
||||
await this.client.ready;
|
||||
const settings: CppSettings = new CppSettings();
|
||||
if (!settings.codeFolding) {
|
||||
return [];
|
||||
|
||||
@@ -11,9 +11,7 @@ import { CppSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEditProvider {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideOnTypeFormattingEdits(document: vscode.TextDocument, position: vscode.Position, ch: string, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
|
||||
@@ -21,7 +19,6 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit
|
||||
if (settings.formattingEngine === "disabled") {
|
||||
return [];
|
||||
}
|
||||
await this.client.ready;
|
||||
const filePath: string = document.uri.fsPath;
|
||||
const useVcFormat: boolean = settings.useVcFormat(document);
|
||||
const configCallBack = async (editorConfigSettings: any | undefined) => {
|
||||
|
||||
@@ -18,14 +18,10 @@ const RenameRequest: RequestType<ReferencesParams, ReferencesResult, void> =
|
||||
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/rename');
|
||||
|
||||
export class RenameProvider implements vscode.RenameProvider {
|
||||
private client: DefaultClient;
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string, _token: vscode.CancellationToken): Promise<vscode.WorkspaceEdit | undefined> {
|
||||
await this.client.ready;
|
||||
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
|
||||
|
||||
const settings: CppSettings = new CppSettings();
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { ManualPromise } from '../../Utility/Async/manualPromise';
|
||||
|
||||
interface FileData
|
||||
{
|
||||
interface FileData {
|
||||
version: number;
|
||||
promise: ManualPromise<vscode.SemanticTokens>;
|
||||
tokenBuilder: vscode.SemanticTokensBuilder;
|
||||
|
||||
@@ -10,9 +10,7 @@ import { RequestCancelled, ServerCancelled } from '../protocolFilter';
|
||||
import { makeVscodeLocation } from '../utils';
|
||||
|
||||
export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
constructor(private client: DefaultClient) {
|
||||
}
|
||||
|
||||
public async provideWorkspaceSymbols(query: string, token: vscode.CancellationToken): Promise<vscode.SymbolInformation[]> {
|
||||
|
||||
@@ -23,19 +23,16 @@ import { WorkspaceSymbolProvider } from './Providers/workspaceSymbolProvider';
|
||||
// End provider imports
|
||||
|
||||
import { CodeSnippet, Trait } from '@github/copilot-language-server';
|
||||
import { ok } from 'assert';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import { SourceFileConfiguration, SourceFileConfigurationItem, Version, WorkspaceBrowseConfiguration } from 'vscode-cpptools';
|
||||
import { IntelliSenseStatus, Status } from 'vscode-cpptools/out/testApi';
|
||||
import { CloseAction, DidOpenTextDocumentParams, ErrorAction, LanguageClientOptions, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import { LanguageClient, ServerOptions } from 'vscode-languageclient/node';
|
||||
import { CloseAction, DidOpenTextDocumentParams, ErrorAction, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import * as rpc from 'vscode-languageclient/node';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { DebugConfigurationProvider } from '../Debugger/configurationProvider';
|
||||
import { ManualPromise } from '../Utility/Async/manualPromise';
|
||||
import { ManualSignal } from '../Utility/Async/manualSignal';
|
||||
import { logAndReturn } from '../Utility/Async/returns';
|
||||
import { is } from '../Utility/System/guards';
|
||||
import * as util from '../common';
|
||||
import { isWindows } from '../constants';
|
||||
import { instrument, isInstrumentationEnabled } from '../instrumentation';
|
||||
@@ -60,6 +57,7 @@ import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderE
|
||||
import { DataBinding } from './dataBinding';
|
||||
import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig';
|
||||
import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, isWritingCrashCallStack, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension';
|
||||
import { LanguageClient } from './languageClient';
|
||||
import { LocalizeStringParams, getLocaleId, getLocalizedString } from './localization';
|
||||
import { PersistentFolderState, PersistentState, PersistentWorkspaceState } from './persistentState';
|
||||
import { RequestCancelled, ServerCancelled, createProtocolFilter } from './protocolFilter';
|
||||
@@ -88,7 +86,7 @@ export function hasTrustedCompilerPaths(): boolean {
|
||||
}
|
||||
|
||||
// Data shared by all clients.
|
||||
let languageClient: LanguageClient;
|
||||
const languageClient: LanguageClient = new LanguageClient();
|
||||
let firstClientStarted: Promise<{ wasShutdown: boolean }>;
|
||||
let languageClientHasCrashed: boolean = false;
|
||||
let languageClientCrashedNeedsRestart: boolean = false;
|
||||
@@ -788,7 +786,6 @@ class ClientModel {
|
||||
|
||||
export interface Client {
|
||||
readonly ready: Promise<void>;
|
||||
enqueue<T>(task: () => Promise<T>): Promise<T>;
|
||||
InitializingWorkspaceChanged: vscode.Event<boolean>;
|
||||
IndexingWorkspaceChanged: vscode.Event<boolean>;
|
||||
ParsingWorkspaceChanged: vscode.Event<boolean>;
|
||||
@@ -900,7 +897,6 @@ export function createNullClient(): Client {
|
||||
}
|
||||
|
||||
export class DefaultClient implements Client {
|
||||
private innerLanguageClient?: LanguageClient; // The "client" that launches and communicates with our language "server" process.
|
||||
private disposables: vscode.Disposable[] = [];
|
||||
private documentFormattingProviderDisposable: vscode.Disposable | undefined;
|
||||
private formattingRangeProviderDisposable: vscode.Disposable | undefined;
|
||||
@@ -916,7 +912,6 @@ export class DefaultClient implements Client {
|
||||
private rootRealPath: string;
|
||||
private workspaceStoragePath: string;
|
||||
private trackedDocuments = new Map<string, vscode.TextDocument>();
|
||||
private isSupported: boolean = true;
|
||||
private inactiveRegionsDecorations = new Map<string, DecorationRangesPair>();
|
||||
private settingsTracker: SettingsTracker;
|
||||
private loggingLevel: number = 1;
|
||||
@@ -941,20 +936,6 @@ export class DefaultClient implements Client {
|
||||
private showConfigureIntelliSenseButton: boolean = false;
|
||||
private pendingTagParsingCalls: PendingTagParsingCall[] = [];
|
||||
|
||||
/** A queue of asynchronous tasks that need to be processed befofe ready is considered active. */
|
||||
private static queue = new Array<[ManualPromise<unknown>, () => Promise<unknown>] | [ManualPromise<unknown>]>();
|
||||
|
||||
/** returns a promise that waits initialization and/or a change to configuration to complete (i.e. language client is ready-to-use) */
|
||||
private static readonly isStarted = new ManualSignal<void>(true);
|
||||
|
||||
/**
|
||||
* Indicates if the blocking task dispatcher is currently running
|
||||
*
|
||||
* This will be in the Set state when the dispatcher is not running (i.e. if you await this it will be resolved immediately)
|
||||
* If the dispatcher is running, this will be in the Reset state (i.e. if you await this it will be resolved when the dispatcher is done)
|
||||
*/
|
||||
private static readonly dispatching = new ManualSignal<void>();
|
||||
|
||||
// The "model" that is displayed via the UI (status bar).
|
||||
private model: ClientModel = new ClientModel();
|
||||
|
||||
@@ -971,7 +952,7 @@ export class DefaultClient implements Client {
|
||||
public get ReferencesCommandModeChanged(): vscode.Event<refs.ReferencesCommandMode> { return this.model.referencesCommandMode.ValueChanged; }
|
||||
public get TagParserStatusChanged(): vscode.Event<string> { return this.model.parsingWorkspaceStatus.ValueChanged; }
|
||||
public get ActiveConfigChanged(): vscode.Event<string> { return this.model.activeConfigName.ValueChanged; }
|
||||
public isInitialized(): boolean { return this.innerLanguageClient !== undefined; }
|
||||
public isInitialized(): boolean { return this.languageClient.isInitialized; }
|
||||
public getShowConfigureIntelliSenseButton(): boolean { return this.showConfigureIntelliSenseButton; }
|
||||
public setShowConfigureIntelliSenseButton(show: boolean): void { this.showConfigureIntelliSenseButton = show; }
|
||||
|
||||
@@ -1006,10 +987,7 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public get languageClient(): LanguageClient {
|
||||
if (!this.innerLanguageClient) {
|
||||
throw new Error("Attempting to use languageClient before initialized");
|
||||
}
|
||||
return this.innerLanguageClient;
|
||||
return languageClient;
|
||||
}
|
||||
|
||||
public get configuration(): configs.CppProperties {
|
||||
@@ -1383,19 +1361,18 @@ export class DefaultClient implements Client {
|
||||
if (firstClientStarted === undefined || languageClientCrashedNeedsRestart) {
|
||||
if (languageClientCrashedNeedsRestart) {
|
||||
languageClientCrashedNeedsRestart = false;
|
||||
// if we're recovering, the isStarted needs to be reset.
|
||||
// if we're recovering, the isStarted needs to be reset
|
||||
// because we're starting the first client again.
|
||||
DefaultClient.isStarted.reset();
|
||||
this.languageClient.isStarted = false;
|
||||
this.languageClient.setLanguageClient(undefined);
|
||||
}
|
||||
firstClientStarted = this.createLanguageClient();
|
||||
util.setProgress(util.getProgressExecutableStarted());
|
||||
isFirstClient = true;
|
||||
}
|
||||
void this.init(rootUri, isFirstClient).catch(logAndReturn.undefined);
|
||||
|
||||
} 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;
|
||||
@@ -1415,8 +1392,7 @@ export class DefaultClient implements Client {
|
||||
ui = getUI();
|
||||
ui.bind(this);
|
||||
if ((await firstClientStarted).wasShutdown) {
|
||||
this.isSupported = false;
|
||||
DefaultClient.isStarted.resolve();
|
||||
this.languageClient.isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1428,7 +1404,10 @@ export class DefaultClient implements Client {
|
||||
this.innerConfiguration.CompileCommandsChanged((e) => this.onCompileCommandsChanged(e));
|
||||
this.disposables.push(this.innerConfiguration);
|
||||
|
||||
this.innerLanguageClient = languageClient;
|
||||
// Ideally this would be set earlier, but the task provider expects it to also mean that `this.innerConfiguration` is set.
|
||||
this.languageClient.isStarted = true;
|
||||
compilerDefaults = await this.requestCompiler();
|
||||
|
||||
telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings());
|
||||
failureMessageShown = false;
|
||||
|
||||
@@ -1495,7 +1474,6 @@ export class DefaultClient implements Client {
|
||||
});
|
||||
// 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.
|
||||
compilerDefaults = await this.requestCompiler();
|
||||
DefaultClient.updateClientConfigurations();
|
||||
clients.forEach(client => {
|
||||
if (client instanceof DefaultClient) {
|
||||
@@ -1505,14 +1483,11 @@ export class DefaultClient implements Client {
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
this.isSupported = false; // Running on an OS we don't support yet.
|
||||
if (!failureMessageShown) {
|
||||
failureMessageShown = true;
|
||||
void vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", String(err)));
|
||||
}
|
||||
}
|
||||
|
||||
DefaultClient.isStarted.resolve();
|
||||
}
|
||||
|
||||
private getWorkspaceFolderSettings(workspaceFolderUri: vscode.Uri | undefined, workspaceFolder: vscode.WorkspaceFolder | undefined, settings: CppSettings, otherSettings: OtherSettings): WorkspaceFolderSettingsParams {
|
||||
@@ -1700,7 +1675,7 @@ export class DefaultClient implements Client {
|
||||
// from a sanitizer build to files in that directory (see getSanitizerServerEnv). This is
|
||||
// undefined -- i.e. the environment is inherited unchanged -- for normal builds.
|
||||
const sanitizerServerEnv: NodeJS.ProcessEnv | undefined = getSanitizerServerEnv();
|
||||
const serverOptions: ServerOptions = {
|
||||
const serverOptions: rpc.ServerOptions = {
|
||||
run: { command: serverModule, options: { detached: false, cwd: util.getExtensionFilePath("bin"), env: sanitizerServerEnv } },
|
||||
debug: { command: serverModule, args: [serverName], options: { detached: true, cwd: util.getExtensionFilePath("bin"), env: sanitizerServerEnv } }
|
||||
};
|
||||
@@ -1763,7 +1738,7 @@ export class DefaultClient implements Client {
|
||||
loggingLevel: this.loggingLevel
|
||||
};
|
||||
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
const clientOptions: rpc.LanguageClientOptions = {
|
||||
documentSelector: [
|
||||
{ scheme: 'file', language: 'c' },
|
||||
{ scheme: 'file', language: 'cpp' },
|
||||
@@ -1843,34 +1818,40 @@ export class DefaultClient implements Client {
|
||||
// Refresh initializing state in UI.
|
||||
this.model.isInitializingWorkspace.Value = true;
|
||||
|
||||
// Create the language client
|
||||
languageClient = new LanguageClient(`cpptools`, serverOptions, clientOptions);
|
||||
languageClient.onNotification(DebugProtocolNotification, logDebugProtocol);
|
||||
languageClient.onNotification(DebugLogNotification, logLocalized);
|
||||
languageClient.onNotification(LogTelemetryNotification, (e) => void this.logTelemetry(e));
|
||||
languageClient.onNotification(ShowMessageWindowNotification, showMessageWindow);
|
||||
languageClient.registerProposedFeatures();
|
||||
await languageClient.start();
|
||||
// Create the language client that spawns cpptools and configures RPC over stdin/stdout.
|
||||
// This is the ONLY place outside of the LanguageClient wrapper where the VS Code LanguageClient class should be used directly.
|
||||
// All other code should use the LanguageClient wrapper class.
|
||||
const client = new rpc.LanguageClient(`cpptools`, serverOptions, clientOptions);
|
||||
client.onNotification(DebugProtocolNotification, logDebugProtocol);
|
||||
client.onNotification(DebugLogNotification, logLocalized);
|
||||
client.onNotification(LogTelemetryNotification, (e) => void this.logTelemetry(e));
|
||||
client.onNotification(ShowMessageWindowNotification, showMessageWindow);
|
||||
client.registerProposedFeatures();
|
||||
await client.start();
|
||||
|
||||
if (usesCrashHandler()) {
|
||||
watchForCrashes(await languageClient.sendRequest(PreInitializationRequest, null));
|
||||
watchForCrashes(await client.sendRequest(PreInitializationRequest, null));
|
||||
} else if (os.platform() === "win32") {
|
||||
const settings: CppSettings = new CppSettings();
|
||||
if ((settings.windowsErrorReportingMode === "default" && !languageClientHasCrashed) ||
|
||||
settings.windowsErrorReportingMode === "enabled") {
|
||||
await languageClient.sendRequest(PreInitializationRequest, null);
|
||||
await client.sendRequest(PreInitializationRequest, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Move initialization to a separate message, so we can see log output from it.
|
||||
// A request is used in order to wait for completion and ensure that no subsequent
|
||||
// higher priority message may be processed before the Initialization request.
|
||||
const initializeResult = await languageClient.sendRequest(InitializationRequest, cppInitializationParams);
|
||||
const initializeResult = await client.sendRequest(InitializationRequest, cppInitializationParams);
|
||||
|
||||
// If the server requested shutdown, then reload with the failsafe (null) client.
|
||||
if (initializeResult.shouldShutdown) {
|
||||
await languageClient.stop();
|
||||
await client.stop();
|
||||
await clients.recreateClients(true);
|
||||
} else {
|
||||
// Don't set the inner language client on the wrapper until after initialization is complete.
|
||||
// This ensures the order of the initialization messages.
|
||||
languageClient.setLanguageClient(client);
|
||||
}
|
||||
|
||||
return { wasShutdown: initializeResult.shouldShutdown };
|
||||
@@ -1878,7 +1859,6 @@ export class DefaultClient implements Client {
|
||||
|
||||
public async sendDidChangeSettings(): Promise<void> {
|
||||
// Send settings json to native side.
|
||||
await this.ready;
|
||||
await this.languageClient.sendNotification(DidChangeSettingsNotification, this.getAllSettings());
|
||||
}
|
||||
|
||||
@@ -2218,7 +2198,6 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async logDiagnostics(): Promise<void> {
|
||||
await this.ready;
|
||||
const response: GetDiagnosticsResult = await this.languageClient.sendRequest(GetDiagnosticsRequest, null);
|
||||
const diagnosticsChannel: vscode.OutputChannel = getDiagnosticsChannel();
|
||||
diagnosticsChannel.clear();
|
||||
@@ -2286,16 +2265,12 @@ export class DefaultClient implements Client {
|
||||
diagnosticsChannel.show(false);
|
||||
}
|
||||
|
||||
public async rescanFolder(): Promise<void> {
|
||||
await this.ready;
|
||||
public rescanFolder(): Promise<void> {
|
||||
return this.languageClient.sendNotification(RescanFolderNotification);
|
||||
}
|
||||
|
||||
public async provideCustomConfigurations(docUris: vscode.Uri[], batchId: number): Promise<void> {
|
||||
let isProviderRegistered: boolean = false;
|
||||
const onFinished: () => void = () => {
|
||||
void this.languageClient.sendNotification(FinishedRequestCustomConfig, { batchId, isProviderRegistered });
|
||||
};
|
||||
try {
|
||||
const providerId: string | undefined = this.configurationProvider;
|
||||
if (!providerId) {
|
||||
@@ -2309,7 +2284,7 @@ export class DefaultClient implements Client {
|
||||
const resultCode = await this.provideCustomConfigurationAsync(docUris, provider);
|
||||
telemetry.logLanguageServerEvent('provideCustomConfigurations', { providerId, resultCode });
|
||||
} finally {
|
||||
onFinished();
|
||||
void this.languageClient.sendNotification(FinishedRequestCustomConfig, { batchId, isProviderRegistered });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2529,9 +2504,8 @@ export class DefaultClient implements Client {
|
||||
* the UI results and always re-requests (no caching).
|
||||
*/
|
||||
|
||||
public async getIncludes(uri: vscode.Uri, maxDepth: number): Promise<GetIncludesResult> {
|
||||
public getIncludes(uri: vscode.Uri, maxDepth: number): Promise<GetIncludesResult> {
|
||||
const params: GetIncludesParams = { fileUri: uri.toString(), maxDepth };
|
||||
await this.ready;
|
||||
return this.languageClient.sendRequest(IncludesRequest, params);
|
||||
}
|
||||
|
||||
@@ -2552,82 +2526,11 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
/**
|
||||
* a Promise that can be awaited to know when it's ok to proceed.
|
||||
*
|
||||
* This is a lighter-weight complement to `enqueue()`
|
||||
*
|
||||
* Use `await <client>.ready` when you need to ensure that the client is initialized, and to run in order
|
||||
* Use `enqueue()` when you want to ensure that subsequent calls are blocked until a critical bit of code is run.
|
||||
*
|
||||
* This is lightweight, because if the queue is empty, then the only thing to wait for is the client itself to be initialized
|
||||
* A Promise that can be awaited to know when the language client (cpptools) is up and running.
|
||||
* It also implies that `this.innerConfiguration` is set.
|
||||
*/
|
||||
get ready(): Promise<void> {
|
||||
if (!DefaultClient.dispatching.isCompleted || DefaultClient.queue.length) {
|
||||
// if the dispatcher has stuff going on, then we need to stick in a promise into the queue so we can
|
||||
// be notified when it's our turn
|
||||
const p = new ManualPromise<void>();
|
||||
DefaultClient.queue.push([p as ManualPromise<unknown>]);
|
||||
return p;
|
||||
}
|
||||
|
||||
// otherwise, we're only waiting for the client to be in an initialized state, in which case just wait for that.
|
||||
return DefaultClient.isStarted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue a task to ensure that the order is maintained. The tasks are executed sequentially after the client is ready.
|
||||
*
|
||||
* this is a bit more expensive than `.ready` - this ensures the task is absolutely finished executing before allowing
|
||||
* the dispatcher to move forward.
|
||||
*
|
||||
* Use `enqueue()` when you want to ensure that subsequent calls are blocked until a critical bit of code is run.
|
||||
* Use `await <client>.ready` when you need to ensure that the client is initialized, and still run in order.
|
||||
*/
|
||||
enqueue<T>(task: () => Promise<T>) {
|
||||
ok(this.isSupported, localize("unsupported.client", "Unsupported client"));
|
||||
|
||||
// create a placeholder promise that is resolved when the task is complete.
|
||||
const result = new ManualPromise<unknown>();
|
||||
|
||||
// add the task to the queue
|
||||
DefaultClient.queue.push([result, task]);
|
||||
|
||||
// if we're not already dispatching, start
|
||||
if (DefaultClient.dispatching.isSet) {
|
||||
// start dispatching
|
||||
void DefaultClient.dispatch();
|
||||
}
|
||||
|
||||
// return the placeholder promise to the caller.
|
||||
return result as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dispatch loop asynchronously processes items in the async queue in order, and ensures that tasks are dispatched in the
|
||||
* order they were inserted.
|
||||
*/
|
||||
private static async dispatch() {
|
||||
// reset the promise for the dispatcher
|
||||
DefaultClient.dispatching.reset();
|
||||
|
||||
do {
|
||||
// ensure that this is OK to start working
|
||||
await this.isStarted;
|
||||
|
||||
// pick items up off the queue and run then one at a time until the queue is empty
|
||||
const [promise, task] = DefaultClient.queue.shift() ?? [];
|
||||
if (is.promise(promise)) {
|
||||
try {
|
||||
promise.resolve(task ? await task() : undefined);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
} while (DefaultClient.queue.length);
|
||||
|
||||
// unblock anything that is waiting for the dispatcher to empty
|
||||
this.dispatching.resolve();
|
||||
return this.languageClient.ready;
|
||||
}
|
||||
|
||||
private static async withLspCancellationHandling<T>(task: () => Promise<T>, token: vscode.CancellationToken): Promise<T> {
|
||||
@@ -2679,7 +2582,7 @@ export class DefaultClient implements Client {
|
||||
* listen for notifications from the language server.
|
||||
*/
|
||||
private registerNotifications(): void {
|
||||
console.assert(this.languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
|
||||
console.assert(this.languageClient.isInitialized, "This method must not be called until the language client is initialized.");
|
||||
|
||||
this.languageClient.onNotification(ReloadWindowNotification, () => void util.promptForReloadWindowDueToSettingsChange());
|
||||
this.languageClient.onNotification(UpdateTrustedCompilersNotification, (e) => void this.addTrustedCompiler(e.compilerPath));
|
||||
@@ -2788,7 +2691,7 @@ export class DefaultClient implements Client {
|
||||
* listen for file created/deleted events under the ${workspaceFolder} folder
|
||||
*/
|
||||
private registerFileWatcher(): void {
|
||||
console.assert(this.languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
|
||||
console.assert(this.languageClient.isInitialized, "This method must not be called until the language client is initialized.");
|
||||
|
||||
if (this.rootFolder) {
|
||||
// WARNING: The default limit on Linux is 8k, so for big directories, this can cause file watching to fail.
|
||||
@@ -3150,18 +3053,16 @@ export class DefaultClient implements Client {
|
||||
switchHeaderSourceFileName: fileName,
|
||||
workspaceFolderUri: rootUri.toString()
|
||||
};
|
||||
return this.enqueue(async () => {
|
||||
// Don't use withLspCancellationHandling() or withCancellation() here. If the switch target is already known,
|
||||
// the caller should still be able to use it even if the progress notification was just cancelled.
|
||||
try {
|
||||
return await this.languageClient.sendRequest(SwitchHeaderSourceRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
throw new vscode.CancellationError();
|
||||
}
|
||||
throw e;
|
||||
// Don't use withLspCancellationHandling() or withCancellation() here. If the switch target is already known,
|
||||
// the caller should still be able to use it even if the progress notification was just cancelled.
|
||||
try {
|
||||
return await this.languageClient.sendRequest(SwitchHeaderSourceRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
throw new vscode.CancellationError();
|
||||
}
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public async requestCompiler(newCompilerPath?: string): Promise<configs.CompilerDefaults> {
|
||||
@@ -3241,7 +3142,6 @@ export class DefaultClient implements Client {
|
||||
* send notifications to the language server to restart IntelliSense for the selected file.
|
||||
*/
|
||||
public async restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(RestartIntelliSenseForFileNotification, this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document)).catch(logAndReturn.undefined);
|
||||
}
|
||||
|
||||
@@ -3258,7 +3158,6 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async resetDatabase(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ResetDatabaseNotification);
|
||||
}
|
||||
|
||||
@@ -3270,29 +3169,24 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async pauseParsing(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(PauseParsingNotification);
|
||||
}
|
||||
|
||||
public async resumeParsing(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ResumeParsingNotification);
|
||||
}
|
||||
|
||||
public async PauseCodeAnalysis(): Promise<void> {
|
||||
await this.ready;
|
||||
this.model.isCodeAnalysisPaused.Value = true;
|
||||
return this.languageClient.sendNotification(PauseCodeAnalysisNotification);
|
||||
}
|
||||
|
||||
public async ResumeCodeAnalysis(): Promise<void> {
|
||||
await this.ready;
|
||||
this.model.isCodeAnalysisPaused.Value = false;
|
||||
return this.languageClient.sendNotification(ResumeCodeAnalysisNotification);
|
||||
}
|
||||
|
||||
public async CancelCodeAnalysis(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(CancelCodeAnalysisNotification);
|
||||
}
|
||||
|
||||
@@ -3427,7 +3321,6 @@ export class DefaultClient implements Client {
|
||||
currentConfiguration: index,
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
await this.languageClient.sendNotification(ChangeSelectedSettingNotification, params);
|
||||
|
||||
let configName: string = "";
|
||||
@@ -3443,7 +3336,6 @@ export class DefaultClient implements Client {
|
||||
uri: vscode.Uri.file(path).toString(),
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ChangeCompileCommandsNotification, params);
|
||||
}
|
||||
|
||||
@@ -3629,7 +3521,6 @@ export class DefaultClient implements Client {
|
||||
const params: WorkspaceFolderParams = {
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ClearCustomConfigurationsNotification, params);
|
||||
}
|
||||
|
||||
@@ -3638,7 +3529,6 @@ export class DefaultClient implements Client {
|
||||
const params: WorkspaceFolderParams = {
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ClearCustomBrowseConfigurationNotification, params);
|
||||
}
|
||||
|
||||
@@ -3725,7 +3615,6 @@ export class DefaultClient implements Client {
|
||||
position: editor.selection.active,
|
||||
next: next
|
||||
};
|
||||
await this.ready;
|
||||
const response: Position | undefined = await this.languageClient.sendRequest(GoToDirectiveInGroupRequest, params);
|
||||
if (response) {
|
||||
const p: vscode.Position = new vscode.Position(response.line, response.character);
|
||||
@@ -3758,7 +3647,6 @@ export class DefaultClient implements Client {
|
||||
isCodeAction: codeActionArguments !== undefined,
|
||||
isCursorAboveSignatureLine: codeActionArguments?.isCursorAboveSignatureLine
|
||||
};
|
||||
await this.ready;
|
||||
const currentFileVersion: number | undefined = openFileVersions.get(params.uri);
|
||||
if (currentFileVersion === undefined) {
|
||||
return;
|
||||
@@ -3804,23 +3692,19 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
}
|
||||
|
||||
public async handleRunCodeAnalysisOnActiveFile(): Promise<void> {
|
||||
await this.ready;
|
||||
public handleRunCodeAnalysisOnActiveFile(): Promise<void> {
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.ActiveFile });
|
||||
}
|
||||
|
||||
public async handleRunCodeAnalysisOnOpenFiles(): Promise<void> {
|
||||
await this.ready;
|
||||
public handleRunCodeAnalysisOnOpenFiles(): Promise<void> {
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.OpenFiles });
|
||||
}
|
||||
|
||||
public async handleRunCodeAnalysisOnAllFiles(): Promise<void> {
|
||||
await this.ready;
|
||||
public handleRunCodeAnalysisOnAllFiles(): Promise<void> {
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.AllFiles });
|
||||
}
|
||||
|
||||
public async handleRemoveAllCodeAnalysisProblems(): Promise<void> {
|
||||
await this.ready;
|
||||
if (removeAllCodeAnalysisProblems()) {
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.ClearSquiggles });
|
||||
}
|
||||
@@ -3851,8 +3735,6 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise<void> {
|
||||
await this.ready;
|
||||
|
||||
// A deep copy is needed because the call to identifiers.splice below can
|
||||
// remove elements in identifiersAndUris[...].identifiers.
|
||||
const identifiersAndUrisCopy: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
|
||||
@@ -4332,9 +4214,8 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public onInterval(): void {
|
||||
// These events can be discarded until the language client is ready.
|
||||
// Don't queue them up with this.notifyWhenLanguageClientReady calls.
|
||||
if (this.innerLanguageClient !== undefined && this.configuration !== undefined) {
|
||||
// These events can be discarded until the language client is ready. Don't queue them up.
|
||||
if (this.languageClient.isInitialized && this.configuration !== undefined) {
|
||||
void this.languageClient.sendNotification(IntervalTimerNotification).catch(logAndReturn.undefined);
|
||||
this.configuration.checkCppProperties();
|
||||
this.configuration.checkCompileCommands();
|
||||
@@ -4380,8 +4261,6 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async handleReferencesIcon(): Promise<void> {
|
||||
await this.ready;
|
||||
|
||||
workspaceReferences.UpdateProgressUICounter(this.model.referencesCommandMode.Value);
|
||||
|
||||
// If the search is find all references, preview partial results.
|
||||
@@ -4515,9 +4394,6 @@ class NullClient implements Client {
|
||||
|
||||
readonly ready: Promise<void> = Promise.resolve();
|
||||
|
||||
async enqueue<T>(task: () => Promise<T>) {
|
||||
return task();
|
||||
}
|
||||
public get InitializingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
|
||||
public get IndexingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
|
||||
public get ParsingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
|
||||
|
||||
@@ -121,7 +121,6 @@ export class ClientCollection {
|
||||
const client: cpptools.Client = pair[1];
|
||||
|
||||
const newClient: cpptools.Client = this.createClient(client.RootFolder, true);
|
||||
await newClient.ready;
|
||||
for (const document of client.TrackedDocuments.values()) {
|
||||
this.transferOwnership(document, client);
|
||||
await newClient.sendDidOpen(document);
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
import * as vscode from 'vscode';
|
||||
import { LanguageClient, NotificationType, Range } from 'vscode-languageclient/node';
|
||||
import { NotificationType, Range } from 'vscode-languageclient';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Location, WorkspaceEdit } from './commonTypes';
|
||||
import { CppSourceStr } from './extension';
|
||||
import { LanguageClient } from './languageClient';
|
||||
import { LocalizeStringParams, getLocalizedString } from './localization';
|
||||
import { CppSettings } from './settings';
|
||||
import { makeVscodeLocation, makeVscodeRange, makeVscodeTextEdits, rangeEquals } from './utils';
|
||||
|
||||
@@ -136,7 +136,7 @@ export interface CompilerDefaults {
|
||||
trustedCompilerFound: boolean;
|
||||
}
|
||||
|
||||
export class CppProperties {
|
||||
export class CppProperties implements vscode.Disposable {
|
||||
private client: DefaultClient;
|
||||
private rootUri: vscode.Uri | undefined;
|
||||
private propertiesFile: vscode.Uri | undefined | null = undefined; // undefined and null values are handled differently
|
||||
|
||||
@@ -185,11 +185,11 @@ export async function activate(): Promise<void> {
|
||||
disposables.push(vscode.workspace.onDidOpenTextDocument(onDidOpenTextDocument));
|
||||
|
||||
disposables.push(vscode.workspace.onDidChangeConfiguration(onDidChangeSettings));
|
||||
disposables.push(vscode.window.onDidChangeTextEditorVisibleRanges((e) => clients.ActiveClient.enqueue(async () => onDidChangeTextEditorVisibleRanges(e))));
|
||||
disposables.push(vscode.window.onDidChangeActiveTextEditor((e) => clients.ActiveClient.enqueue(async () => onDidChangeActiveTextEditor(e))));
|
||||
disposables.push(vscode.window.onDidChangeTextEditorVisibleRanges(e => onDidChangeTextEditorVisibleRanges(e)));
|
||||
disposables.push(vscode.window.onDidChangeActiveTextEditor(e => onDidChangeActiveTextEditor(e)));
|
||||
ui.didChangeActiveEditor(); // Handle already active documents (for non-cpp files that we don't register didOpen).
|
||||
disposables.push(vscode.window.onDidChangeTextEditorSelection((e) => clients.ActiveClient.enqueue(async () => onDidChangeTextEditorSelection(e))));
|
||||
disposables.push(vscode.window.onDidChangeVisibleTextEditors((e) => clients.ActiveClient.enqueue(async () => onDidChangeVisibleTextEditors(e))));
|
||||
disposables.push(vscode.window.onDidChangeTextEditorSelection(e => onDidChangeTextEditorSelection(e)));
|
||||
disposables.push(vscode.window.onDidChangeVisibleTextEditors(e => onDidChangeVisibleTextEditors(e)));
|
||||
updateLanguageConfigurations();
|
||||
|
||||
reportMacCrashes();
|
||||
@@ -565,12 +565,10 @@ async function selectClient(): Promise<Client> {
|
||||
}
|
||||
|
||||
async function onResetDatabase(): Promise<void> {
|
||||
await clients.ActiveClient.ready;
|
||||
return clients.ActiveClient.resetDatabase();
|
||||
}
|
||||
|
||||
async function onRescanCompilers(sender?: any): Promise<void> {
|
||||
await clients.ActiveClient.ready;
|
||||
return clients.ActiveClient.rescanCompilers(sender);
|
||||
}
|
||||
|
||||
@@ -579,7 +577,6 @@ async function onAddMissingInclude(): Promise<void> {
|
||||
}
|
||||
|
||||
async function selectIntelliSenseConfiguration(sender?: any): Promise<void> {
|
||||
await clients.ActiveClient.ready;
|
||||
return clients.ActiveClient.promptSelectIntelliSenseConfiguration(sender);
|
||||
}
|
||||
|
||||
@@ -877,7 +874,6 @@ async function onFindAllReferences(uri: vscode.Uri, position: vscode.Position, t
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
const result = await sendFindAllReferencesRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
return result?.locations;
|
||||
}
|
||||
@@ -892,7 +888,6 @@ async function onGoToDefinition(uri: vscode.Uri, position: vscode.Position, toke
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendGoToDefinitionRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -906,7 +901,6 @@ async function onPrepareCallHierarchy(uri: vscode.Uri, position: vscode.Position
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendPrepareCallHierarchyRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -920,7 +914,6 @@ async function onCallHierarchyCallsTo(item: vscode.CallHierarchyItem, token?: vs
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsToRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -934,7 +927,6 @@ async function onCallHierarchyCallsFrom(item: vscode.CallHierarchyItem, token?:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsFromRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
|
||||
import { Disposable } from 'vscode';
|
||||
import { CancellationToken, NotificationHandler, NotificationType, RequestType } from 'vscode-languageclient';
|
||||
import * as rpc from 'vscode-languageclient/node';
|
||||
import { ManualSignal } from '../Utility/Async/manualSignal';
|
||||
|
||||
export class LanguageClient {
|
||||
private _rpcClient?: rpc.LanguageClient;
|
||||
private readonly _started = new ManualSignal<void>(true);
|
||||
|
||||
/**
|
||||
* Returns a promise that waits for the RPC connection to be ready.
|
||||
*/
|
||||
public get ready(): Promise<void> {
|
||||
return this._started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initialization state of the underlying RPC client.
|
||||
* This is used to indicate that the underlying RPC client has been initialized and is ready to send requests.
|
||||
* If resetting the RPC client, set this to false.
|
||||
*/
|
||||
public set isStarted(value: boolean) {
|
||||
if (value) {
|
||||
this._started.resolve();
|
||||
} else {
|
||||
this._started.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying RPC client has been initialized.
|
||||
* Used in cases where a quick check of the initialization state is desired instead of waiting on the `ready` promise.
|
||||
*/
|
||||
public get isInitialized(): boolean {
|
||||
return !!this._rpcClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the underlying RPC client.
|
||||
* This should only be called once during initialization.
|
||||
*/
|
||||
public setLanguageClient(languageClient?: rpc.LanguageClient): void {
|
||||
this._rpcClient = languageClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and return the underlying RPC client.
|
||||
* Strips away the `undefined` type from `this._rpcClient`.
|
||||
*/
|
||||
private get rpcClient(): rpc.LanguageClient {
|
||||
if (!this._rpcClient) {
|
||||
throw new Error("Attempting to use languageClient before initialized");
|
||||
}
|
||||
|
||||
return this._rpcClient;
|
||||
}
|
||||
|
||||
public get protocol2CodeConverter(): rpc.LanguageClient["protocol2CodeConverter"] {
|
||||
return this.rpcClient.protocol2CodeConverter;
|
||||
}
|
||||
|
||||
public get code2ProtocolConverter(): rpc.LanguageClient["code2ProtocolConverter"] {
|
||||
return this.rpcClient.code2ProtocolConverter;
|
||||
}
|
||||
|
||||
public async sendRequest<P, R, E>(type: RequestType<P, R, E>, params: P, token?: CancellationToken): Promise<R> {
|
||||
await this.ready;
|
||||
return this.rpcClient.sendRequest(type, params, token);
|
||||
}
|
||||
|
||||
public async sendNotification<P>(type: NotificationType<P>, params?: P): Promise<void> {
|
||||
await this.ready;
|
||||
return this.rpcClient.sendNotification(type, params);
|
||||
}
|
||||
|
||||
public onNotification<P>(type: NotificationType<P>, handler: NotificationHandler<P>): Disposable {
|
||||
// These messages are received from cpptools, and therefore it is not needed to await the ready signal.
|
||||
return this.rpcClient.onNotification(type, handler);
|
||||
}
|
||||
|
||||
public stop(): Promise<void> {
|
||||
return this._rpcClient?.stop() ?? Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,8 @@ export function createProtocolFilter(): Middleware {
|
||||
// client.takeOwnership() will call client.TrackedDocuments.add() again, but that's ok. It's a Set.
|
||||
client.takeOwnership(document);
|
||||
void sendMessage(document);
|
||||
client.ready.then(() => {
|
||||
const cppEditors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => util.isCpp(e.document));
|
||||
client.onDidChangeVisibleTextEditors(cppEditors).catch(logAndReturn.undefined);
|
||||
}).catch(logAndReturn.undefined);
|
||||
const cppEditors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => util.isCpp(e.document));
|
||||
void client.onDidChangeVisibleTextEditors(cppEditors).catch(logAndReturn.undefined);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user