Compare commits

..
Author SHA1 Message Date
Sean McManus bae4e46a2a Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-13 19:15:52 +00:00
Sean McManus 5fce68cd74 Merge commit '1a8cdb843801d8ff0daf6837de0ba7202b8fd27a' into seanmcm/integration 2026-08-12 23:47:28 +00:00
Sean McManus 1a8cdb8438 Fix configuration path regex escaping 2026-08-12 22:59:06 +00:00
Sean McManus f2b4ae2103 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-12 22:15:04 +00:00
Sean McManus 544cd026c8 Merge commit '4370d14a2bde025e0d2802135dc5eda51654c72c' into seanmcm/integration 2026-08-12 21:09:47 +00:00
Sean McManus 4370d14a2b Update changelog and version for 1.33.8 2026-08-12 20:35:33 +00:00
Sean McManus b1b47db524 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-12 20:24:28 +00:00
Sean McManus c40ff01d00 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-12 20:14:15 +00:00
Sean McManus db29f1bb68 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-11 19:29:09 +00:00
Sean McManus 53e9bdb245 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-11 17:06:07 +00:00
Sean McManus 74af7ade30 Merge commit '79e58c61515b92ea5288e85500cc48bdfbb50df8' into seanmcm/integration 2026-08-11 02:08:34 +00:00
Sean McManus 79e58c6151 Lock localization literals 2026-08-11 01:34:01 +00:00
Sean McManus 52be722a32 Merge commit '639a0c7b08b1b2dfc521327072fb1ab492fe5ed7' into seanmcm/integration 2026-08-11 01:33:46 +00:00
Sean McManus 639a0c7b08 Validate Yarn lockfile selectors 2026-08-11 01:21:19 +00:00
Sean McManus eae53ddf84 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-11 01:11:46 +00:00
Sean McManus a8d2b261ba Merge commit '12d2528b29f63b4674d90d6fb02771b0561bb0e1' into seanmcm/integration 2026-08-11 01:03:16 +00:00
Sean McManus 12d2528b29 Preserve Portuguese include literals 2026-08-11 01:01:54 +00:00
Sean McManus 61f51d1690 Merge commit 'a78136f85b76b8239a2ad846ebd04c64fb4cce1a' into seanmcm/integration 2026-08-11 00:49:13 +00:00
Sean McManus a78136f85b Merge remote-tracking branch 'origin/seanmcm/devbox2-wsl/agent4/fix-localization-translation-errors' into seanmcm/devbox2-wsl/agent4/fix-localization-translation-errors 2026-08-11 00:35:50 +00:00
Sean McManus b2ddb96611 Preserve Turkish check option literal 2026-08-11 00:35:02 +00:00
Sean McManus b7fcd42e88 Merge branch 'main' into seanmcm/devbox2-wsl/agent4/fix-localization-translation-errors 2026-08-10 17:30:53 -07:00
Sean McManus 1385e1e19f Fix localization translation errors 2026-08-11 00:20:31 +00:00
Sean McManus 282c176eb3 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-10 23:53:36 +00:00
Sean McManus ac37abac12 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-10 23:05:58 +00:00
Sean McManus 314495ef37 Merge commit '6112068ac68245da8bc0b015b9eb6ba4a55ed6d1' into seanmcm/integration 2026-08-10 23:01:17 +00:00
Sean McManus 6112068ac6 Use frozen lockfile for webpack install 2026-08-10 22:27:56 +00:00
Sean McManus 9564835dd8 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-10 21:47:56 +00:00
Sean McManus b4afbe2672 Merge commit 'd6c9fd5559bba437babd466ed3dc5686a1d6b46f' into seanmcm/integration 2026-08-10 21:42:47 +00:00
Sean McManus d6c9fd5559 Update nanoid to 3.3.17 2026-08-10 19:59:13 +00:00
Sean McManus 75d458accb Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-10 18:24:12 +00:00
Sean McManus 8e81300a7c Merge commit '24831bc81adff860e046d8cc83d270307a8f3dc8' into seanmcm/integration 2026-08-10 17:46:38 +00:00
Sean McManus 24831bc81a Update js-yaml in remaining lockfiles 2026-08-10 15:28:58 +00:00
Sean McManus 6cb184c483 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-10 14:37:43 +00:00
Sean McManus 53a3811743 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-09 16:43:54 +00:00
Sean McManus f630fc4da9 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-08 00:08:32 +00:00
Sean McManus a1a4bb0f5d Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-07 03:28:32 +00:00
Sean McManus 660abd601c Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-05 01:10:26 +00:00
Sean McManus c0ad99a76f Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-04 20:13:21 +00:00
Sean McManus bb288f7e1a Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-04 18:30:53 +00:00
Sean McManus 5ce4eaaf6a Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-04 17:01:25 +00:00
csigs c1a9d604ac Localization - Translated Strings 2026-08-04 07:16:05 +00:00
Sean McManus 038c742125 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-03 17:08:43 -07:00
Sean McManus f9f1e55832 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-03 14:19:31 -07:00
Sean McManus 32cb58fe87 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-03 11:30:08 -07:00
Sean McManus b3e83d8b48 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-08-03 09:26:38 -07:00
Sean McManus 9a1b479ced Merge branch 'seanmcm/updateIntelliSenseLocStringsPR757614' into seanmcm/integration 2026-08-03 08:25:29 -07:00
Sean McManus 8878f05a18 Merge branch 'main' into seanmcm/updateIntelliSenseLocStringsPR757614 2026-08-03 08:24:38 -07:00
Sean McManus 0b10e39fef Merge branch 'seanmcm/devbox2-wsl/agent9/fix-copy-binaries-tracked-files' into seanmcm/integration 2026-08-01 21:29:18 +00:00
Sean McManus 9b2644d614 Restore repo-tracked files after copying test binaries
The install/copy-binaries script rm -rf's and re-copies the installed extension's bin, debugAdapters, and LLVM folders. A few files under bin are checked into the repo (bin/cpp.hint and bin/messages/**/messages.json); the copy overwrote them with the installed extension's versions (differing line endings and/or content), leaving spurious local modifications that had to be reverted by hand. Restore any tracked files the copy changed so only the untracked binaries remain, and gitignore the generated bin/binaryVersion.json marker.
2026-08-01 21:03:34 +00:00
Sean McManus cdd5240e39 Merge remote-tracking branch 'origin/main' into seanmcm/integration 2026-07-31 03:33:53 +00:00
Sean McManus dd5f8f997c Merge branch 'main' into seanmcm/integration 2026-07-30 23:17:41 +00:00
Sean McManus dac32bc0c3 Merge branch 'main' into seanmcm/integration 2026-07-30 00:45:22 +00:00
Sean McManus 778ddbd6a3 Merge branch 'seanmcm/devbox2-wsl/agent6/bump-test-electron' into seanmcm/integration 2026-07-29 19:40:40 +00:00
Sean McManus 0bbd36695f Move test VS Code pin to 1.131.0
With @vscode/test-electron 3.1.0 the macOS 1.131.0 bundle launches correctly, so advance the pinned test VS Code from 1.130.0 to the current stable 1.131.0.
2026-07-29 17:15:16 +00:00
Sean McManus e962adaccc Bump @vscode/test-electron to 3.1.0 so tests launch VS Code >=1.110 on macOS
VS Code 1.110 renamed the macOS main binary from Contents/MacOS/Electron to the product name and later removed the compatibility symlink (microsoft/vscode#326502, 2026-07-20), so @vscode/test-electron <=3.0.0 — which hardcodes the Electron name — fails to launch downloaded stable builds on macOS with 'spawn .../Contents/MacOS/Electron ENOENT'. 3.1.0 resolves the executable from the bundle's Info.plist CFBundleExecutable (microsoft/vscode-test#348, #349), letting the tests track latest stable VS Code again without pinning.
2026-07-29 17:15:16 +00:00
Sean McManus f01ab4da97 Merge branch 'main' into seanmcm/integration 2026-07-28 21:55:42 +00:00
Sean McManus 9053d9fb0d Merge branch 'main' into seanmcm/integration 2026-07-28 11:13:29 +00:00
Sean McManus 56be5729fb Merge branch 'main' into seanmcm/integration 2026-07-27 23:12:25 +00:00
Sean McManus d8f8783035 Merge branch 'seanmcm/updateThirdPartyNotices' into seanmcm/integration 2026-07-27 22:26:57 +00:00
Sean McManus 6ab8203ce0 Update from review. 2026-07-27 22:25:12 +00:00
Sean McManus 6d33605e84 Merge branch 'seanmcm/updateThirdPartyNotices' into seanmcm/integration 2026-07-27 22:00:26 +00:00
Sean McManus 51b25d1e9e Merge branch 'main' into seanmcm/integration 2026-07-27 22:00:18 +00:00
Sean McManus 3ee7d16c6d Update ThirdPartyNotices.txt 2026-07-27 21:36:51 +00:00
Sean McManus 9bb8ee4409 Merge branch 'seanmcm/updateBraceExpansion' into seanmcm/integration 2026-07-27 18:40:43 +00:00
Sean McManus d57678108d Update brace-expansion. 2026-07-27 18:36:38 +00:00
Sean McManus 0a82449d66 Merge branch 'seanmcm/skipTerminateHandlerFrames' into seanmcm/integration 2026-07-26 21:46:31 +00:00
Sean McManus c412f7da71 Skip terminate_handler( frames. 2026-07-26 21:29:34 +00:00
Sean McManus 4113e00318 Merge branch 'seanmcm/fixEmptyUndefinedSignalInfo' into seanmcm/integration 2026-07-26 20:43:38 +00:00
Sean McManus 248c44bdbc Code review feedback. 2026-07-26 20:33:30 +00:00
Sean McManus 9db0aff845 Fix si_code=, si_addr=undefined. 2026-07-26 20:15:47 +00:00
Sean McManus 627a4622b0 Merge branch 'seanmcm/updateGitIgnore' into seanmcm/integration 2026-07-26 17:48:15 +00:00
Sean McManus c2b605399a Merge branch 'seanmcm/updateIntelliSenseStringAddJsonNewlines' into seanmcm/integration 2026-07-26 17:47:45 +00:00
Sean McManus 714b35123d Update IntelliSense loc strings for PR 757614. 2026-07-26 17:41:35 +00:00
Sean McManus ab6e93fa31 Undo the IntelliSense string change. 2026-07-26 17:34:34 +00:00
Sean McManus 8ccffc9e5b Merge branch 'main' into seanmcm/updateIntelliSenseStringAddJsonNewlines 2026-07-26 17:31:00 +00:00
Sean McManus 9a12ee6149 Update .gitignore for installed bin files. 2026-07-26 17:25:17 +00:00
Sean McManus bdd6a39e9d Merge branch 'main' into seanmcm/updateIntelliSenseStringAddJsonNewlines 2026-07-14 14:52:55 -07:00
Sean McManus b477243fef Add a new IntelliSense translation string and unify json newlines. 2026-07-13 04:40:53 -07:00
21 changed files with 257 additions and 183 deletions
+2 -2
View File
@@ -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[]> {
+182 -66
View File
@@ -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);
+1 -2
View File
@@ -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
+12 -4
View File
@@ -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);
}
}
},