Compare commits
209
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca5da8db30 | ||
|
|
70a4a89f0b | ||
|
|
3fa4cf2ddb | ||
|
|
995752b9e5 | ||
|
|
3d0c45ff96 | ||
|
|
734df7ec71 | ||
|
|
fc37c7091f | ||
|
|
f6cc1fbd03 | ||
|
|
e0bd199546 | ||
|
|
bc914dc69c | ||
|
|
b2f5c605c4 | ||
|
|
d41e14fd86 | ||
|
|
35c0fd37e2 | ||
|
|
99259bf194 | ||
|
|
10c1e1b606 | ||
|
|
fcdb6efbab | ||
|
|
bd5f6c0462 | ||
|
|
9c45e4d2bc | ||
|
|
31f6b66e6b | ||
|
|
4404bf76a7 | ||
|
|
133896eb4c | ||
|
|
376562ee75 | ||
|
|
668b33c1e5 | ||
|
|
6317e27e45 | ||
|
|
223a3e2cbe | ||
|
|
5b000d939b | ||
|
|
b6b11027da | ||
|
|
e22017f6df | ||
|
|
a2f6a72aed | ||
|
|
593ed07c56 | ||
|
|
40f7455acd | ||
|
|
adf4681ef8 | ||
|
|
a53dac8bef | ||
|
|
04c60c288a | ||
|
|
fa71378712 | ||
|
|
36a78e89e1 | ||
|
|
364ba2789c | ||
|
|
8d5fc737b1 | ||
|
|
1172405856 | ||
|
|
b013b10b64 | ||
|
|
c6ff700da2 | ||
|
|
936e7e3b15 | ||
|
|
e7e2e3983f | ||
|
|
80a6d16f83 | ||
|
|
e5a976f229 | ||
|
|
70fbfd71e1 | ||
|
|
5b3b56c694 | ||
|
|
777ff002f1 | ||
|
|
8de8679b3e | ||
|
|
e02269ba89 | ||
|
|
7852d4587c | ||
|
|
a1cb1d8bec | ||
|
|
e10273d4a5 | ||
|
|
0ae864f1d7 | ||
|
|
58e66e8aac | ||
|
|
cf11bb5666 | ||
|
|
777af10222 | ||
|
|
ca3dcdbc8f | ||
|
|
ff2fb7eb65 | ||
|
|
a1fa61e73f | ||
|
|
42f7302d6b | ||
|
|
af326bd298 | ||
|
|
b50bf604fd | ||
|
|
f4f3d8ca8b | ||
|
|
303b838a41 | ||
|
|
36cea36784 | ||
|
|
e4f859dd56 | ||
|
|
97c5f14bd5 | ||
|
|
c4003c07e8 | ||
|
|
c27806e763 | ||
|
|
7cfb2d3316 | ||
|
|
9a03b747c6 | ||
|
|
989cee4414 | ||
|
|
c357224407 | ||
|
|
a636c87f3e | ||
|
|
471cdfecf8 | ||
|
|
97128122b0 | ||
|
|
006ebff619 | ||
|
|
1458694ed6 | ||
|
|
896024ba9c | ||
|
|
779bb080c1 | ||
|
|
97df273fc1 | ||
|
|
7037b070ce | ||
|
|
205e63772c | ||
|
|
e7dff799fd | ||
|
|
ec41c3e481 | ||
|
|
71cf89ce70 | ||
|
|
f7863066f3 | ||
|
|
0c2862c379 | ||
|
|
6026c84c6f | ||
|
|
e3ee2ee76a | ||
|
|
ff1cd88466 | ||
|
|
98696368f4 | ||
|
|
99d98afcec | ||
|
|
784f1450c0 | ||
|
|
7d26dd1c4f | ||
|
|
37950ffb2d | ||
|
|
23b0672837 | ||
|
|
7bafd64cfe | ||
|
|
381d69646b | ||
|
|
bfa36bc662 | ||
|
|
5cbe83ec44 | ||
|
|
dead10ac8a | ||
|
|
ce20613f24 | ||
|
|
86c6c10f18 | ||
|
|
db6e0cb5cf | ||
|
|
f9e067f5d1 | ||
|
|
b137df0bcd | ||
|
|
827db55084 | ||
|
|
8a2324daaa | ||
|
|
d41ccfd497 | ||
|
|
bdd3541f28 | ||
|
|
c8b7f13c1a | ||
|
|
8d0d3601a7 | ||
|
|
e9613ae7ad | ||
|
|
3570705b5c | ||
|
|
096b1463a6 | ||
|
|
812318163d | ||
|
|
225b776d99 | ||
|
|
12d95f4708 | ||
|
|
317df57496 | ||
|
|
f63c3652f8 | ||
|
|
5d62607760 | ||
|
|
26d0932972 | ||
|
|
3cc2650dfa | ||
|
|
fdf9b5bfe0 | ||
|
|
fdd71bc963 | ||
|
|
1d266a9c0e | ||
|
|
f818529a08 | ||
|
|
41a05a90c8 | ||
|
|
e59c6ca759 | ||
|
|
287ee3961b | ||
|
|
8a8fd883ac | ||
|
|
4fe56500a9 | ||
|
|
03911153f9 | ||
|
|
acea31e572 | ||
|
|
bf21e01764 | ||
|
|
30f1361d23 | ||
|
|
825033f768 | ||
|
|
d8426caacc | ||
|
|
8942530744 | ||
|
|
e663939e56 | ||
|
|
1fb5b63ab7 | ||
|
|
03933b0a74 | ||
|
|
fc8eb8632f | ||
|
|
f6722bc8ff | ||
|
|
894db52405 | ||
|
|
abf384619d | ||
|
|
fd482d2169 | ||
|
|
2fafd831e5 | ||
|
|
1ceae9d4ed | ||
|
|
d4d5d4551f | ||
|
|
0ef77b5616 | ||
|
|
efdc8e90f6 | ||
|
|
9f020e9258 | ||
|
|
c058568767 | ||
|
|
8809e69e91 | ||
|
|
7af5c40dd0 | ||
|
|
1d2bd10691 | ||
|
|
dac96fe852 | ||
|
|
a1487e5e79 | ||
|
|
6f19496172 | ||
|
|
ad5d6de4ea | ||
|
|
153e232f2d | ||
|
|
bcd4a7f025 | ||
|
|
3c3d463a81 | ||
|
|
92691929ed | ||
|
|
86a41c9021 | ||
|
|
a71c90c140 | ||
|
|
1d28851ef7 | ||
|
|
1aced54699 | ||
|
|
a8cf39c8b4 | ||
|
|
e037b95926 | ||
|
|
af7f6ce52e | ||
|
|
9a18982440 | ||
|
|
35bf4c8b0f | ||
|
|
23446558cf | ||
|
|
76ccb791ff | ||
|
|
a5a5735089 | ||
|
|
5077edf585 | ||
|
|
f38926f8b1 | ||
|
|
30de9bcc27 | ||
|
|
100e2e0828 | ||
|
|
e3b41771c6 | ||
|
|
3f7f3090f6 | ||
|
|
4149493f2c | ||
|
|
43aad3f65c | ||
|
|
bedcacb0a1 | ||
|
|
a5f8f84b43 | ||
|
|
e53b190380 | ||
|
|
1846fd4001 | ||
|
|
62e09945e3 | ||
|
|
c9b0db02fd | ||
|
|
51da619eec | ||
|
|
3eb50568e9 | ||
|
|
866b145645 | ||
|
|
9762fe5397 | ||
|
|
377896c30a | ||
|
|
98f13a6f11 | ||
|
|
0d85aea687 | ||
|
|
25d2b76514 | ||
|
|
42dfef3f6b | ||
|
|
1ce1e9cd71 | ||
|
|
65163966d5 | ||
|
|
edf8e0a155 | ||
|
|
4083075476 | ||
|
|
b745ebc218 | ||
|
|
b69d17a0f5 | ||
|
|
be8b6fb693 |
@@ -63,7 +63,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
|
||||
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
|
||||
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ 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;
|
||||
@@ -29,8 +30,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(private client: DefaultClient) {
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async getCachedChatModel(): Promise<vscode.LanguageModelChat | undefined> {
|
||||
@@ -170,6 +171,7 @@ 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,10 +10,11 @@ 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(private client: DefaultClient) {
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
|
||||
@@ -35,6 +36,7 @@ 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,11 +214,15 @@ 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(private client: DefaultClient) {
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -257,6 +261,7 @@ 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";
|
||||
@@ -311,6 +316,8 @@ 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,7 +40,9 @@ export const GetCodeActionsRequest: RequestType<GetCodeActionsRequestParams, Get
|
||||
new RequestType<GetCodeActionsRequestParams, GetCodeActionsResult, void>('cpptools/getCodeActions');
|
||||
|
||||
export class CodeActionProvider implements vscode.CodeActionProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
private static inlineMacroKind: vscode.CodeActionKind = vscode.CodeActionKind.RefactorInline.append("macro");
|
||||
@@ -49,6 +51,7 @@ 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,7 +11,9 @@ import { CppSettings, OtherSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async provideDocumentFormattingEdits(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
|
||||
@@ -19,6 +21,7 @@ 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,7 +11,9 @@ import { CppSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class DocumentRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range,
|
||||
@@ -20,6 +22,7 @@ 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,12 +58,14 @@ 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 client.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
|
||||
response = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
throw new vscode.CancellationError();
|
||||
|
||||
@@ -56,10 +56,14 @@ export async function sendFindAllReferencesRequest(client: DefaultClient, uri: v
|
||||
}
|
||||
|
||||
export class FindAllReferencesProvider implements vscode.ReferenceProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
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,6 +14,7 @@ interface FoldingRangeRequestInfo {
|
||||
}
|
||||
|
||||
export class FoldingRangeProvider implements vscode.FoldingRangeProvider {
|
||||
private client: DefaultClient;
|
||||
public onDidChangeFoldingRangesEvent = new vscode.EventEmitter<void>();
|
||||
public onDidChangeFoldingRanges?: vscode.Event<void>;
|
||||
|
||||
@@ -21,11 +22,12 @@ 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(private client: DefaultClient) {
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
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,7 +11,9 @@ import { CppSettings } from '../settings';
|
||||
import { makeVscodeTextEdits } from '../utils';
|
||||
|
||||
export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEditProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async provideOnTypeFormattingEdits(document: vscode.TextDocument, position: vscode.Position, ch: string, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
|
||||
@@ -19,6 +21,7 @@ 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,10 +18,14 @@ const RenameRequest: RequestType<ReferencesParams, ReferencesResult, void> =
|
||||
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/rename');
|
||||
|
||||
export class RenameProvider implements vscode.RenameProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
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,7 +5,8 @@
|
||||
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,7 +10,9 @@ import { RequestCancelled, ServerCancelled } from '../protocolFilter';
|
||||
import { makeVscodeLocation } from '../utils';
|
||||
|
||||
export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
|
||||
constructor(private client: DefaultClient) {
|
||||
private client: DefaultClient;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async provideWorkspaceSymbols(query: string, token: vscode.CancellationToken): Promise<vscode.SymbolInformation[]> {
|
||||
|
||||
@@ -23,16 +23,19 @@ 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, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import * as rpc from 'vscode-languageclient/node';
|
||||
import { CloseAction, DidOpenTextDocumentParams, ErrorAction, LanguageClientOptions, NotificationType, Position, Range, RequestType, ResponseError, TextDocumentIdentifier, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import { LanguageClient, ServerOptions } 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';
|
||||
@@ -57,7 +60,6 @@ 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';
|
||||
@@ -86,7 +88,7 @@ export function hasTrustedCompilerPaths(): boolean {
|
||||
}
|
||||
|
||||
// Data shared by all clients.
|
||||
const languageClient: LanguageClient = new LanguageClient();
|
||||
let languageClient: LanguageClient;
|
||||
let firstClientStarted: Promise<{ wasShutdown: boolean }>;
|
||||
let languageClientHasCrashed: boolean = false;
|
||||
let languageClientCrashedNeedsRestart: boolean = false;
|
||||
@@ -219,16 +221,9 @@ interface FileChangedParams extends WorkspaceFolderParams {
|
||||
uri: string;
|
||||
}
|
||||
|
||||
interface InputLineRange {
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
}
|
||||
|
||||
interface InputRegion {
|
||||
startLine: number;
|
||||
startColumn: number;
|
||||
endLine: number;
|
||||
endColumn: number;
|
||||
}
|
||||
|
||||
interface DecorationRangesPair {
|
||||
@@ -379,7 +374,7 @@ export enum FoldingRangeKind {
|
||||
|
||||
export interface CppFoldingRange {
|
||||
kind: FoldingRangeKind;
|
||||
range: InputLineRange;
|
||||
range: InputRegion;
|
||||
}
|
||||
|
||||
export interface GetFoldingRangesResult {
|
||||
@@ -786,6 +781,7 @@ 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>;
|
||||
@@ -897,6 +893,7 @@ 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;
|
||||
@@ -912,6 +909,7 @@ 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;
|
||||
@@ -936,6 +934,20 @@ 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();
|
||||
|
||||
@@ -952,7 +964,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.languageClient.isInitialized; }
|
||||
public isInitialized(): boolean { return this.innerLanguageClient !== undefined; }
|
||||
public getShowConfigureIntelliSenseButton(): boolean { return this.showConfigureIntelliSenseButton; }
|
||||
public setShowConfigureIntelliSenseButton(show: boolean): void { this.showConfigureIntelliSenseButton = show; }
|
||||
|
||||
@@ -987,7 +999,10 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public get languageClient(): LanguageClient {
|
||||
return languageClient;
|
||||
if (!this.innerLanguageClient) {
|
||||
throw new Error("Attempting to use languageClient before initialized");
|
||||
}
|
||||
return this.innerLanguageClient;
|
||||
}
|
||||
|
||||
public get configuration(): configs.CppProperties {
|
||||
@@ -1361,18 +1376,19 @@ 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.
|
||||
this.languageClient.isStarted = false;
|
||||
this.languageClient.setLanguageClient(undefined);
|
||||
DefaultClient.isStarted.reset();
|
||||
}
|
||||
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;
|
||||
@@ -1392,7 +1408,8 @@ export class DefaultClient implements Client {
|
||||
ui = getUI();
|
||||
ui.bind(this);
|
||||
if ((await firstClientStarted).wasShutdown) {
|
||||
this.languageClient.isStarted = true;
|
||||
this.isSupported = false;
|
||||
DefaultClient.isStarted.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1404,10 +1421,7 @@ export class DefaultClient implements Client {
|
||||
this.innerConfiguration.CompileCommandsChanged((e) => this.onCompileCommandsChanged(e));
|
||||
this.disposables.push(this.innerConfiguration);
|
||||
|
||||
// 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();
|
||||
|
||||
this.innerLanguageClient = languageClient;
|
||||
telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings());
|
||||
failureMessageShown = false;
|
||||
|
||||
@@ -1474,6 +1488,7 @@ 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) {
|
||||
@@ -1483,11 +1498,14 @@ 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 {
|
||||
@@ -1675,7 +1693,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: rpc.ServerOptions = {
|
||||
const serverOptions: 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 } }
|
||||
};
|
||||
@@ -1738,7 +1756,7 @@ export class DefaultClient implements Client {
|
||||
loggingLevel: this.loggingLevel
|
||||
};
|
||||
|
||||
const clientOptions: rpc.LanguageClientOptions = {
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [
|
||||
{ scheme: 'file', language: 'c' },
|
||||
{ scheme: 'file', language: 'cpp' },
|
||||
@@ -1818,40 +1836,34 @@ export class DefaultClient implements Client {
|
||||
// Refresh initializing state in UI.
|
||||
this.model.isInitializingWorkspace.Value = true;
|
||||
|
||||
// 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();
|
||||
// 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();
|
||||
|
||||
if (usesCrashHandler()) {
|
||||
watchForCrashes(await client.sendRequest(PreInitializationRequest, null));
|
||||
watchForCrashes(await languageClient.sendRequest(PreInitializationRequest, null));
|
||||
} else if (os.platform() === "win32") {
|
||||
const settings: CppSettings = new CppSettings();
|
||||
if ((settings.windowsErrorReportingMode === "default" && !languageClientHasCrashed) ||
|
||||
settings.windowsErrorReportingMode === "enabled") {
|
||||
await client.sendRequest(PreInitializationRequest, null);
|
||||
await languageClient.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 client.sendRequest(InitializationRequest, cppInitializationParams);
|
||||
const initializeResult = await languageClient.sendRequest(InitializationRequest, cppInitializationParams);
|
||||
|
||||
// If the server requested shutdown, then reload with the failsafe (null) client.
|
||||
if (initializeResult.shouldShutdown) {
|
||||
await client.stop();
|
||||
await languageClient.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 };
|
||||
@@ -1859,6 +1871,7 @@ 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());
|
||||
}
|
||||
|
||||
@@ -2198,6 +2211,7 @@ 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();
|
||||
@@ -2265,12 +2279,16 @@ export class DefaultClient implements Client {
|
||||
diagnosticsChannel.show(false);
|
||||
}
|
||||
|
||||
public rescanFolder(): Promise<void> {
|
||||
public async rescanFolder(): Promise<void> {
|
||||
await this.ready;
|
||||
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) {
|
||||
@@ -2284,7 +2302,7 @@ export class DefaultClient implements Client {
|
||||
const resultCode = await this.provideCustomConfigurationAsync(docUris, provider);
|
||||
telemetry.logLanguageServerEvent('provideCustomConfigurations', { providerId, resultCode });
|
||||
} finally {
|
||||
void this.languageClient.sendNotification(FinishedRequestCustomConfig, { batchId, isProviderRegistered });
|
||||
onFinished();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2504,8 +2522,9 @@ export class DefaultClient implements Client {
|
||||
* the UI results and always re-requests (no caching).
|
||||
*/
|
||||
|
||||
public getIncludes(uri: vscode.Uri, maxDepth: number): Promise<GetIncludesResult> {
|
||||
public async getIncludes(uri: vscode.Uri, maxDepth: number): Promise<GetIncludesResult> {
|
||||
const params: GetIncludesParams = { fileUri: uri.toString(), maxDepth };
|
||||
await this.ready;
|
||||
return this.languageClient.sendRequest(IncludesRequest, params);
|
||||
}
|
||||
|
||||
@@ -2526,11 +2545,82 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
get ready(): Promise<void> {
|
||||
return this.languageClient.ready;
|
||||
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();
|
||||
}
|
||||
|
||||
private static async withLspCancellationHandling<T>(task: () => Promise<T>, token: vscode.CancellationToken): Promise<T> {
|
||||
@@ -2582,7 +2672,7 @@ export class DefaultClient implements Client {
|
||||
* listen for notifications from the language server.
|
||||
*/
|
||||
private registerNotifications(): void {
|
||||
console.assert(this.languageClient.isInitialized, "This method must not be called until the language client is initialized.");
|
||||
console.assert(this.languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
|
||||
|
||||
this.languageClient.onNotification(ReloadWindowNotification, () => void util.promptForReloadWindowDueToSettingsChange());
|
||||
this.languageClient.onNotification(UpdateTrustedCompilersNotification, (e) => void this.addTrustedCompiler(e.compilerPath));
|
||||
@@ -2691,7 +2781,7 @@ export class DefaultClient implements Client {
|
||||
* listen for file created/deleted events under the ${workspaceFolder} folder
|
||||
*/
|
||||
private registerFileWatcher(): void {
|
||||
console.assert(this.languageClient.isInitialized, "This method must not be called until the language client is initialized.");
|
||||
console.assert(this.languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
|
||||
|
||||
if (this.rootFolder) {
|
||||
// WARNING: The default limit on Linux is 8k, so for big directories, this can cause file watching to fail.
|
||||
@@ -2964,8 +3054,7 @@ export class DefaultClient implements Client {
|
||||
this.inactiveRegionsDecorations.set(uriString, currentSet);
|
||||
}
|
||||
|
||||
Array.prototype.push.apply(currentSet.ranges, inactiveRegions.map(element =>
|
||||
new vscode.Range(element.startLine, element.startColumn, element.endLine, element.endColumn)));
|
||||
Array.prototype.push.apply(currentSet.ranges, inactiveRegions.map(element => new vscode.Range(element.startLine, 0, element.endLine, 0)));
|
||||
|
||||
// Apply the decorations to all *visible* text editors
|
||||
const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === uriString);
|
||||
@@ -3053,16 +3142,18 @@ export class DefaultClient implements Client {
|
||||
switchHeaderSourceFileName: fileName,
|
||||
workspaceFolderUri: rootUri.toString()
|
||||
};
|
||||
// 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();
|
||||
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;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async requestCompiler(newCompilerPath?: string): Promise<configs.CompilerDefaults> {
|
||||
@@ -3142,6 +3233,7 @@ 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);
|
||||
}
|
||||
|
||||
@@ -3158,6 +3250,7 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public async resetDatabase(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ResetDatabaseNotification);
|
||||
}
|
||||
|
||||
@@ -3169,24 +3262,29 @@ 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);
|
||||
}
|
||||
|
||||
@@ -3321,6 +3419,7 @@ export class DefaultClient implements Client {
|
||||
currentConfiguration: index,
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
await this.languageClient.sendNotification(ChangeSelectedSettingNotification, params);
|
||||
|
||||
let configName: string = "";
|
||||
@@ -3336,6 +3435,7 @@ export class DefaultClient implements Client {
|
||||
uri: vscode.Uri.file(path).toString(),
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ChangeCompileCommandsNotification, params);
|
||||
}
|
||||
|
||||
@@ -3521,6 +3621,7 @@ export class DefaultClient implements Client {
|
||||
const params: WorkspaceFolderParams = {
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ClearCustomConfigurationsNotification, params);
|
||||
}
|
||||
|
||||
@@ -3529,6 +3630,7 @@ export class DefaultClient implements Client {
|
||||
const params: WorkspaceFolderParams = {
|
||||
workspaceFolderUri: this.RootUri?.toString()
|
||||
};
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(ClearCustomBrowseConfigurationNotification, params);
|
||||
}
|
||||
|
||||
@@ -3615,6 +3717,7 @@ 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);
|
||||
@@ -3647,6 +3750,7 @@ 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;
|
||||
@@ -3692,19 +3796,23 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
}
|
||||
|
||||
public handleRunCodeAnalysisOnActiveFile(): Promise<void> {
|
||||
public async handleRunCodeAnalysisOnActiveFile(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.ActiveFile });
|
||||
}
|
||||
|
||||
public handleRunCodeAnalysisOnOpenFiles(): Promise<void> {
|
||||
public async handleRunCodeAnalysisOnOpenFiles(): Promise<void> {
|
||||
await this.ready;
|
||||
return this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.OpenFiles });
|
||||
}
|
||||
|
||||
public handleRunCodeAnalysisOnAllFiles(): Promise<void> {
|
||||
public async handleRunCodeAnalysisOnAllFiles(): Promise<void> {
|
||||
await this.ready;
|
||||
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 });
|
||||
}
|
||||
@@ -3735,6 +3843,8 @@ 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[] = [];
|
||||
@@ -4214,8 +4324,9 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public onInterval(): void {
|
||||
// These events can be discarded until the language client is ready. Don't queue them up.
|
||||
if (this.languageClient.isInitialized && this.configuration !== undefined) {
|
||||
// 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) {
|
||||
void this.languageClient.sendNotification(IntervalTimerNotification).catch(logAndReturn.undefined);
|
||||
this.configuration.checkCppProperties();
|
||||
this.configuration.checkCompileCommands();
|
||||
@@ -4261,6 +4372,8 @@ 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.
|
||||
@@ -4394,6 +4507,9 @@ 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,6 +121,7 @@ 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,11 +4,10 @@
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
import * as vscode from 'vscode';
|
||||
import { NotificationType, Range } from 'vscode-languageclient';
|
||||
import { LanguageClient, NotificationType, Range } from 'vscode-languageclient/node';
|
||||
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 implements vscode.Disposable {
|
||||
export class CppProperties {
|
||||
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 => onDidChangeTextEditorVisibleRanges(e)));
|
||||
disposables.push(vscode.window.onDidChangeActiveTextEditor(e => onDidChangeActiveTextEditor(e)));
|
||||
disposables.push(vscode.window.onDidChangeTextEditorVisibleRanges((e) => clients.ActiveClient.enqueue(async () => onDidChangeTextEditorVisibleRanges(e))));
|
||||
disposables.push(vscode.window.onDidChangeActiveTextEditor((e) => clients.ActiveClient.enqueue(async () => onDidChangeActiveTextEditor(e))));
|
||||
ui.didChangeActiveEditor(); // Handle already active documents (for non-cpp files that we don't register didOpen).
|
||||
disposables.push(vscode.window.onDidChangeTextEditorSelection(e => onDidChangeTextEditorSelection(e)));
|
||||
disposables.push(vscode.window.onDidChangeVisibleTextEditors(e => onDidChangeVisibleTextEditors(e)));
|
||||
disposables.push(vscode.window.onDidChangeTextEditorSelection((e) => clients.ActiveClient.enqueue(async () => onDidChangeTextEditorSelection(e))));
|
||||
disposables.push(vscode.window.onDidChangeVisibleTextEditors((e) => clients.ActiveClient.enqueue(async () => onDidChangeVisibleTextEditors(e))));
|
||||
updateLanguageConfigurations();
|
||||
|
||||
reportMacCrashes();
|
||||
@@ -565,10 +565,12 @@ 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);
|
||||
}
|
||||
|
||||
@@ -577,6 +579,7 @@ async function onAddMissingInclude(): Promise<void> {
|
||||
}
|
||||
|
||||
async function selectIntelliSenseConfiguration(sender?: any): Promise<void> {
|
||||
await clients.ActiveClient.ready;
|
||||
return clients.ActiveClient.promptSelectIntelliSenseConfiguration(sender);
|
||||
}
|
||||
|
||||
@@ -874,6 +877,7 @@ 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;
|
||||
}
|
||||
@@ -888,6 +892,7 @@ async function onGoToDefinition(uri: vscode.Uri, position: vscode.Position, toke
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendGoToDefinitionRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -901,6 +906,7 @@ async function onPrepareCallHierarchy(uri: vscode.Uri, position: vscode.Position
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendPrepareCallHierarchyRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -914,6 +920,7 @@ async function onCallHierarchyCallsTo(item: vscode.CallHierarchyItem, token?: vs
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsToRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
@@ -927,6 +934,7 @@ async function onCallHierarchyCallsFrom(item: vscode.CallHierarchyItem, token?:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsFromRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* 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,8 +45,10 @@ 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);
|
||||
const cppEditors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => util.isCpp(e.document));
|
||||
void client.onDidChangeVisibleTextEditors(cppEditors).catch(logAndReturn.undefined);
|
||||
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);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user