From 7d73a3124de99c2f18eff02090ff4d55148e9cd1 Mon Sep 17 00:00:00 2001 From: jogo- Date: Wed, 18 Jan 2023 20:16:41 +0100 Subject: [PATCH 01/17] Fix typo in CHANGELOG.md (#10384) --- Extension/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/CHANGELOG.md b/Extension/CHANGELOG.md index 6f81c305d4..843181340e 100644 --- a/Extension/CHANGELOG.md +++ b/Extension/CHANGELOG.md @@ -14,7 +14,7 @@ * Fix function inlay hints not working with `std::string_literal` arguments. [#10078](https://github.com/microsoft/vscode-cpptools/issues/10078) * Fix IntelliSense completion for `std::string` with `?:` and `string()`. [#10103](https://github.com/microsoft/vscode-cpptools/issues/10103) * Fix semantic colorization not working in a certain case. [#10105](https://github.com/microsoft/vscode-cpptools/issues/10105) -* Fix IntelliSense completion not working inside constuctor calls that are incomplete. [#10111](https://github.com/microsoft/vscode-cpptools/issues/10111) +* Fix IntelliSense completion not working inside constructor calls that are incomplete. [#10111](https://github.com/microsoft/vscode-cpptools/issues/10111) * Fix changes to the enclosing type not being taken into account after "Create Declaration / Definition" is used once. [#10162](https://github.com/microsoft/vscode-cpptools/issues/10162) * Fix "False positive expression must have a constant value with __builtin_choose_expr in _Static_assert". [#10168](https://github.com/microsoft/vscode-cpptools/issues/10168) * Fix file exclusions not being applied to the first directory found for each browse.path entry. [#10205](https://github.com/microsoft/vscode-cpptools/issues/10205) From 23f3b47e6fa07a054d98677bf195ccbc04bc2264 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Wed, 18 Jan 2023 12:52:54 -0800 Subject: [PATCH 02/17] Fix a crash in extractArgs (#10394) --- Extension/src/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/common.ts b/Extension/src/common.ts index 2a6e6f74eb..e57566d922 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -991,7 +991,7 @@ function extractArgs(argsString: string): string[] { } const still_escaping: boolean = (backslashCount % 2) !== 0; if (!reachedEnd && c === '\"') { - backslashCount /= 2; + backslashCount = Math.floor(backslashCount / 2); } while (backslashCount--) { currentArg += '\\'; From 8431b3720166233bfc6e4184fc9620c4e20837a4 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Thu, 19 Jan 2023 12:30:42 -0800 Subject: [PATCH 03/17] Await in protocol filter (#10306) --- Extension/package.json | 2 +- .../src/LanguageServer/protocolFilter.ts | 58 +++++++++---------- Extension/yarn.lock | 44 +++++++------- 3 files changed, 49 insertions(+), 55 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index f4e1c101a1..a7ef237ddb 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -5976,7 +5976,7 @@ "ssh-config": "^4.1.0", "tmp": "^0.2.1", "vscode-cpptools": "^6.1.0", - "vscode-languageclient": "^8.0.1", + "vscode-languageclient": "^8.1.0-next.4", "vscode-nls": "^5.0.0", "vscode-tas-client": "^0.1.27", "which": "^2.0.2", diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index f1329ea6de..a628a35229 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -13,16 +13,14 @@ import { shouldChangeFromCToCpp } from './utils'; export function createProtocolFilter(): Middleware { // Disabling lint for invoke handlers - const defaultHandler: (data: any, callback: (data: any) => Promise) => Promise = async (data, callback: (data: any) => void) => { clients.ActiveClient.notifyWhenLanguageClientReady(() => callback(data)); }; - // const invoke1 = async (a: any, next: (a: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a); }; + const invoke1 = async (a: any, next: (a: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a); }; const invoke2 = async (a: any, b: any, next: (a: any, b: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b); }; const invoke3 = async (a: any, b: any, c: any, next: (a: any, b: any, c: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c); }; - const invoke4 = async (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c, d); }; - // const invoke5 = async (a: any, b: any, c: any, d: any, e: any, next: (a: any, b: any, c: any, d: any, e: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c, d, e); }; - /* tslint:enable */ + const invoke4 = async (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c, d); }; /* tslint:enable */ return { didOpen: async (document, sendMessage) => { + await clients.ActiveClient.awaitUntilLanguageClientReady(); const editor: vscode.TextEditor | undefined = vscode.window.visibleTextEditors.find(e => e.document === document); if (editor) { // If the file was visible editor when we were activated, we will not get a call to @@ -34,28 +32,22 @@ export function createProtocolFilter(): Middleware { clients.timeTelemetryCollector.setDidOpenTime(document.uri); if (clients.checkOwnership(me, document)) { me.TrackedDocuments.add(document); - const finishDidOpen = (doc: vscode.TextDocument) => { - me.provideCustomConfiguration(doc.uri, undefined); - sendMessage(doc); + const finishDidOpen = async (doc: vscode.TextDocument) => { + await me.provideCustomConfiguration(doc.uri, undefined); + await sendMessage(doc); me.onDidOpenTextDocument(doc); if (editor && editor === vscode.window.activeTextEditor) { onDidChangeActiveTextEditor(editor); } }; - let languageChanged: boolean = false; if (document.languageId === "c" && shouldChangeFromCToCpp(document)) { const baesFileName: string = path.basename(document.fileName); const mappingString: string = baesFileName + "@" + document.fileName; me.addFileAssociations(mappingString, "cpp"); me.sendDidChangeSettings(); - vscode.languages.setTextDocumentLanguage(document, "cpp").then((newDoc: vscode.TextDocument) => { - finishDidOpen(newDoc); - }); - languageChanged = true; - } - if (!languageChanged) { - finishDidOpen(document); + document = await vscode.languages.setTextDocumentLanguage(document, "cpp"); } + await finishDidOpen(document); } } } else { @@ -69,36 +61,39 @@ export function createProtocolFilter(): Middleware { } }, didChange: async (textDocumentChangeEvent, sendMessage) => { + await clients.ActiveClient.awaitUntilLanguageClientReady(); const me: Client = clients.getClientFor(textDocumentChangeEvent.document.uri); me.onDidChangeTextDocument(textDocumentChangeEvent); - sendMessage(textDocumentChangeEvent); + await sendMessage(textDocumentChangeEvent); }, - willSave: defaultHandler, + willSave: invoke1, willSaveWaitUntil: async (event, sendMessage) => { + // await clients.ActiveClient.awaitUntilLanguageClientReady(); + // Don't use awaitUntilLanguageClientReady. + // Otherwise, the message can be delayed too long. const me: Client = clients.getClientFor(event.document.uri); if (me.TrackedDocuments.has(event.document)) { - // Don't use me.requestWhenReady or notifyWhenLanguageClientReady; - // otherwise, the message can be delayed too long. return sendMessage(event); } - return Promise.resolve([]); + return []; }, - didSave: defaultHandler, + didSave: invoke1, didClose: async (document, sendMessage) => { + await clients.ActiveClient.awaitUntilLanguageClientReady(); const me: Client = clients.getClientFor(document.uri); if (me.TrackedDocuments.has(document)) { me.onDidCloseTextDocument(document); me.TrackedDocuments.delete(document); - sendMessage(document); + await sendMessage(document); } }, - provideCompletionItem: invoke4, resolveCompletionItem: invoke2, - provideHover: (document, position, token, next: (document: any, position: any, token: any) => any) => { + provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => { + await clients.ActiveClient.awaitUntilLanguageClientReady(); const me: Client = clients.getClientFor(document.uri); - if (clients.checkOwnership(me, document)) { - return clients.ActiveClient.requestWhenReady(() => next(document, position, token)); + if (me.TrackedDocuments.has(document)) { + return next(document, position, token); } return null; }, @@ -106,10 +101,9 @@ export function createProtocolFilter(): Middleware { provideDefinition: invoke3, provideReferences: invoke4, provideDocumentHighlights: invoke3, - provideDeclaration: invoke3 - // I believe the default handler will do the same thing. - // workspace: { - // didChangeConfiguration: (sections, sendMessage) => sendMessage(sections) - // } + provideDeclaration: invoke3, + workspace: { + didChangeConfiguration: invoke1 + } }; } diff --git a/Extension/yarn.lock b/Extension/yarn.lock index 6ed78fcb46..0e5bb2239d 100644 --- a/Extension/yarn.lock +++ b/Extension/yarn.lock @@ -3846,7 +3846,7 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@3.0.4, minimatch@^3.0.4, minimatch@^3.0.5: +minimatch@3.0.4, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^5.1.0: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -5930,32 +5930,32 @@ vscode-dts@^0.3.2: prompts "^2.1.0" rimraf "^3.0.0" -vscode-jsonrpc@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" - integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== +vscode-jsonrpc@8.1.0-next.5: + version "8.1.0-next.5" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0-next.5.tgz#93fede04082a05268c735b77dae1edbb31708f33" + integrity sha512-9l9lB8gXW1kPECKLC5Goc41pFztSCfODY3dvGaNTJ0KfRgwKIUyIhEBSdlWT2IU4uL4Tcl/zcitpb+Lj6QP7aQ== -vscode-languageclient@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" - integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== +vscode-languageclient@^8.1.0-next.4: + version "8.1.0-next.4" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.1.0-next.4.tgz#f56aae6350cb7602d3ac60f9cdf0c7b1bf5feb79" + integrity sha512-dwo3Vf1aAb3o62mDhLHRGqYaLAYWN5RXAbHKL85Cs+yCJghxYzseuGGBvOUOH3BF5scnCU2BFrghekyP1xCUmQ== dependencies: - minimatch "^3.0.4" - semver "^7.3.5" - vscode-languageserver-protocol "3.17.1" + minimatch "^5.1.0" + semver "^7.3.7" + vscode-languageserver-protocol "3.17.3-next.4" -vscode-languageserver-protocol@3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" - integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== +vscode-languageserver-protocol@3.17.3-next.4: + version "3.17.3-next.4" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3-next.4.tgz#28b30c556910e6d35080c764543b263eea16aa43" + integrity sha512-G6XrjZGSe2LIo7uDa860JKX97sLKc1vQF4AU4SW8DI7NNVKxnCB+vEs8gYHmle7kD9v13PvFkDCBD5ApeONGNQ== dependencies: - vscode-jsonrpc "8.0.1" - vscode-languageserver-types "3.17.1" + vscode-jsonrpc "8.1.0-next.5" + vscode-languageserver-types "3.17.3-next.1" -vscode-languageserver-types@3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" - integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== +vscode-languageserver-types@3.17.3-next.1: + version "3.17.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3-next.1.tgz#0f9c65cf9d30b4236d4f20f2169b0ddbeb7646e7" + integrity sha512-i7HXZs5CdNibVHXZORZw9m5Bm0mfXiGhD/tZv6f7arBtz4iatgiiHu2qInxn0fKeahhMJoBbp6irhsL9+E3UAA== vscode-nls-dev@^4.0.0-next.1: version "4.0.0-next.1" From 0fcc415231297c62e6213ba5911f6217bc219d50 Mon Sep 17 00:00:00 2001 From: xisui-MSFT <44103947+xisui-MSFT@users.noreply.github.com> Date: Thu, 19 Jan 2023 13:24:15 -0800 Subject: [PATCH 04/17] Improve info os processes match (#10398) --- Extension/src/Debugger/attachToProcess.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/src/Debugger/attachToProcess.ts b/Extension/src/Debugger/attachToProcess.ts index 9eb582b91a..a278d4d3f8 100644 --- a/Extension/src/Debugger/attachToProcess.ts +++ b/Extension/src/Debugger/attachToProcess.ts @@ -200,7 +200,7 @@ export class RemoteAttachPicker { pid usr command cores 1 ? 2 ? - 3 /usr/bin/sample 0 + 3 /usr/bin/sample 0,2 4 root /usr/bin/gdbserver --multi :6000 0 Returns an AttachItem array, each item contains a label of "command", and a pid. @@ -217,7 +217,7 @@ export class RemoteAttachPicker { for (const line of lines) { const trimmedLine: string = line.trim(); if (!trimmedLine.endsWith('?')) { - const matches: RegExpMatchArray | null = trimmedLine.match(/^(\d+)\s+(.+?)\s+\d+$/); + const matches: RegExpMatchArray | null = trimmedLine.match(/^(\d+)\s+(.+?)\s+(?:\d+,)*\d+$/); if (matches?.length === 3) { const id: string = matches[1]; const userCommand: string = matches[2]; From 2d3cac0dea96a8b973cbea95cc0a1e302c28ad31 Mon Sep 17 00:00:00 2001 From: Bernardin-MS <114429917+Bernardin-MS@users.noreply.github.com> Date: Fri, 20 Jan 2023 16:25:50 -0500 Subject: [PATCH 05/17] Move status bar icons into the Language Status (#10126) --- Extension/src/LanguageServer/client.ts | 60 ++- Extension/src/LanguageServer/extension.ts | 84 +++- Extension/src/LanguageServer/ui.ts | 56 ++- Extension/src/LanguageServer/ui_new.ts | 547 ++++++++++++++++++++++ Extension/src/common.ts | 7 + 5 files changed, 712 insertions(+), 42 deletions(-) create mode 100644 Extension/src/LanguageServer/ui_new.ts diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 7facac8596..34c63346f0 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -21,7 +21,7 @@ import { CodeActionProvider } from './Providers/codeActionProvider'; import { InlayHintsProvider } from './Providers/inlayHintProvider'; // End provider imports -import { LanguageClientOptions, NotificationType, TextDocumentIdentifier, RequestType, ErrorAction, CloseAction, DidOpenTextDocumentParams, Range, Position, DocumentFilter } from 'vscode-languageclient'; +import { LanguageClientOptions, NotificationType, TextDocumentIdentifier, RequestType, ErrorAction, CloseAction, DidOpenTextDocumentParams, Range, Position } from 'vscode-languageclient'; import { LanguageClient, ServerOptions } from 'vscode-languageclient/node'; import { SourceFileConfigurationItem, WorkspaceBrowseConfiguration, SourceFileConfiguration, Version } from 'vscode-cpptools'; import { Status, IntelliSenseStatus } from 'vscode-cpptools/out/testApi'; @@ -731,7 +731,8 @@ export interface Client { handleConfigurationSelectCommand(): Promise; handleConfigurationProviderSelectCommand(): Promise; handleShowParsingCommands(): Promise; - handleShowCodeAnalysisCommands(): Promise; + handleShowActiveCodeAnalysisCommands(): Promise; + handleShowIdleCodeAnalysisCommands(): Promise; handleReferencesIcon(): void; handleConfigurationEditCommand(viewColumn?: vscode.ViewColumn): void; handleConfigurationEditJSONCommand(viewColumn?: vscode.ViewColumn): void; @@ -784,11 +785,6 @@ export class DefaultClient implements Client { private settingsTracker: SettingsTracker; private loggingLevel: string | undefined; private configurationProvider?: string; - private documentSelector: DocumentFilter[] = [ - { scheme: 'file', language: 'c' }, - { scheme: 'file', language: 'cpp' }, - { scheme: 'file', language: 'cuda-cpp' } - ]; public static referencesParams: RenameParams | FindAllReferencesParams | undefined; public static referencesRequestPending: boolean = false; @@ -928,11 +924,11 @@ export class DefaultClient implements Client { util.setProgress(util.getProgressExecutableStarted()); isFirstClient = true; } - ui = getUI(); - ui.bind(this); // requests/notifications are deferred until this.languageClient is set. this.queueBlockingTask(async () => { + ui = await getUI(); + ui.bind(this); await firstClientStarted; try { const workspaceFolder: vscode.WorkspaceFolder | undefined = this.rootFolder; @@ -961,26 +957,26 @@ export class DefaultClient implements Client { this.inlayHintsProvider = new InlayHintsProvider(this); - this.disposables.push(vscode.languages.registerInlayHintsProvider(this.documentSelector, this.inlayHintsProvider)); - this.disposables.push(vscode.languages.registerRenameProvider(this.documentSelector, new RenameProvider(this))); - this.disposables.push(vscode.languages.registerReferenceProvider(this.documentSelector, new FindAllReferencesProvider(this))); + this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider)); + this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, new RenameProvider(this))); + this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, new FindAllReferencesProvider(this))); this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this))); - this.disposables.push(vscode.languages.registerDocumentSymbolProvider(this.documentSelector, new DocumentSymbolProvider(), undefined)); - this.disposables.push(vscode.languages.registerCodeActionsProvider(this.documentSelector, new CodeActionProvider(this), undefined)); + this.disposables.push(vscode.languages.registerDocumentSymbolProvider(util.documentSelector, new DocumentSymbolProvider(), undefined)); + this.disposables.push(vscode.languages.registerCodeActionsProvider(util.documentSelector, new CodeActionProvider(this), undefined)); // Because formatting and codeFolding can vary per folder, we need to register these providers once // and leave them registered. The decision of whether to provide results needs to be made on a per folder basis, // within the providers themselves. - this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(this.documentSelector, new DocumentFormattingEditProvider(this)); - this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(this.documentSelector, new DocumentRangeFormattingEditProvider(this)); - this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(this.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n"); + this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(util.documentSelector, new DocumentFormattingEditProvider(this)); + this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(util.documentSelector, new DocumentRangeFormattingEditProvider(this)); + this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(util.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n"); this.codeFoldingProvider = new FoldingRangeProvider(this); - this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(this.documentSelector, this.codeFoldingProvider); + this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(util.documentSelector, this.codeFoldingProvider); const settings: CppSettings = new CppSettings(); if (settings.enhancedColorization && semanticTokensLegend) { this.semanticTokensProvider = new SemanticTokensProvider(this); - this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(this.documentSelector, this.semanticTokensProvider, semanticTokensLegend); + this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend); } // Listen for messages from the language server. this.registerNotifications(); @@ -1303,7 +1299,7 @@ export class DefaultClient implements Client { if (changedSettings["enhancedColorization"]) { if (settings.enhancedColorization && semanticTokensLegend) { this.semanticTokensProvider = new SemanticTokensProvider(this); - this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(this.documentSelector, this.semanticTokensProvider, semanticTokensLegend); + this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend); } else if (this.semanticTokensProviderDisposable) { this.semanticTokensProviderDisposable.dispose(); this.semanticTokensProviderDisposable = undefined; @@ -2174,14 +2170,14 @@ export class DefaultClient implements Client { private updateTagParseStatus(notificationBody: LocalizeStringParams): void { this.model.parsingWorkspaceStatus.Value = getLocalizedString(notificationBody); if (notificationBody.text.startsWith("Workspace parsing paused")) { - this.model.isParsingWorkspacePausable.Value = true; this.model.isParsingWorkspacePaused.Value = true; - } else if (notificationBody.text.startsWith("Parsing workspace")) { this.model.isParsingWorkspacePausable.Value = true; + } else if (notificationBody.text.startsWith("Parsing workspace")) { this.model.isParsingWorkspacePaused.Value = false; + this.model.isParsingWorkspacePausable.Value = true; } else { - this.model.isParsingWorkspacePausable.Value = false; this.model.isParsingWorkspacePaused.Value = false; + this.model.isParsingWorkspacePausable.Value = false; } } @@ -2748,13 +2744,24 @@ export class DefaultClient implements Client { } } - public async handleShowCodeAnalysisCommands(): Promise { + public async handleShowActiveCodeAnalysisCommands(): Promise { await this.awaitUntilLanguageClientReady(); - const index: number = await ui.showCodeAnalysisCommands(); + const index: number = await ui.showActiveCodeAnalysisCommands(); switch (index) { case 0: this.CancelCodeAnalysis(); break; case 1: this.PauseCodeAnalysis(); break; case 2: this.ResumeCodeAnalysis(); break; + case 3: this.handleShowIdleCodeAnalysisCommands(); break; + } + } + + public async handleShowIdleCodeAnalysisCommands(): Promise { + await this.awaitUntilLanguageClientReady(); + const index: number = await ui.showIdleCodeAnalysisCommands(); + switch (index) { + case 0: this.handleRunCodeAnalysisOnActiveFile(); break; + case 1: this.handleRunCodeAnalysisOnAllFiles(); break; + case 2: this.handleRunCodeAnalysisOnOpenFiles(); break; } } @@ -3269,7 +3276,8 @@ class NullClient implements Client { handleConfigurationSelectCommand(): Promise { return Promise.resolve(); } handleConfigurationProviderSelectCommand(): Promise { return Promise.resolve(); } handleShowParsingCommands(): Promise { return Promise.resolve(); } - handleShowCodeAnalysisCommands(): Promise { return Promise.resolve(); } + handleShowActiveCodeAnalysisCommands(): Promise { return Promise.resolve(); } + handleShowIdleCodeAnalysisCommands(): Promise { return Promise.resolve(); } handleReferencesIcon(): void { } handleConfigurationEditCommand(viewColumn?: vscode.ViewColumn): void { } handleConfigurationEditJSONCommand(viewColumn?: vscode.ViewColumn): void { } diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 5893d67f5c..560fe83800 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -174,7 +174,7 @@ export async function activate(): Promise { console.log("starting language server"); clients = new ClientCollection(); - ui = getUI(); + ui = await getUI(); // There may have already been registered CustomConfigurationProviders. // Request for configurations from those providers. @@ -403,7 +403,8 @@ export function registerCommands(enabled: boolean): void { commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResumeCodeAnalysis', enabled ? onResumeCodeAnalysis : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CancelCodeAnalysis', enabled ? onCancelCodeAnalysis : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowParsingCommands', enabled ? onShowParsingCommands : onDisabledCommand)); - commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowCodeAnalysisCommands', enabled ? onShowCodeAnalysisCommands : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowActiveCodeAnalysisCommands', enabled ? onShowActiveCodeAnalysisCommands : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowIdleCodeAnalysisCommands', enabled ? onShowIdleCodeAnalysisCommands : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowReferencesProgress', enabled ? onShowReferencesProgress : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.TakeSurvey', enabled ? onTakeSurvey : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.LogDiagnostics', enabled ? onLogDiagnostics : onDisabledCommand)); @@ -433,6 +434,73 @@ export function registerCommands(enabled: boolean): void { commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RestartIntelliSenseForFile', enabled ? onRestartIntelliSenseForFile : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.GenerateDoxygenComment', enabled ? onGenerateDoxygenComment : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CreateDeclarationOrDefinition', enabled ? onCreateDeclarationOrDefinition : onDisabledCommand)); + // ---------------- Wrappers ------------- + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationSelectUI_Telemetry', enabled ? + () => { + logForUIExperiment("ConfigurationSelect"); + onSelectConfiguration(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RescanWorkspaceUI_Telemetry', enabled ? + () => { + logForUIExperiment("RescanWorkspace"); + onRescanWorkspace(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowIdleCodeAnalysisCommandsUI_Telemetry', enabled ? + () => { + logForUIExperiment("ShowIdleCodeAnalysisCommands"); + onShowIdleCodeAnalysisCommands(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowActiveCodeAnalysisCommandsUI_Telemetry', enabled ? + () => { + logForUIExperiment("ShowActiveCodeAnalysisCommands"); + onShowActiveCodeAnalysisCommands(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.PauseParsingUI_Telemetry', enabled ? + () => { + logForUIExperiment("ParsingCommands"); + onPauseParsing(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResumeParsingUI_Telemetry', enabled ? + () => { + logForUIExperiment("ParsingCommands"); + onResumeParsing(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CheckForCompilerUI_Telemetry', enabled ? + () => { + logForUIExperiment("CheckForCompiler"); + onCheckForCompiler(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RestartIntelliSenseForFileUI_Telemetry', enabled ? + () => { + logForUIExperiment("RestartIntelliSenseForFile"); + onRestartIntelliSenseForFile(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowReferencesProgressUI_Telemetry', enabled ? + () => { + logForUIExperiment("ShowReferencesProgress"); + onShowReferencesProgress(); + } + : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowParsingCommandsUI_Telemetry', enabled ? + () => { + logForUIExperiment("ParsingCommands"); + onShowParsingCommands(); + } + : onDisabledCommand)); + // ---------------------------------------- +} + +async function logForUIExperiment(command: string): Promise { + const isNewUI: string = ui.isNewUI.toString(); + telemetry.logLanguageServerEvent(`experiment${command}`, { newUI: isNewUI }); } function onDisabledCommand(): void { @@ -510,8 +578,8 @@ async function selectClient(): Promise { if (clients.Count === 1) { return clients.ActiveClient; } else { - const key: string = await ui.showWorkspaces(clients.Names); - if (key !== "") { + const key: string | undefined = await ui.showWorkspaces(clients.Names); + if (key !== undefined && key !== "") { const client: Client | undefined = clients.get(key); if (client) { return client; @@ -730,8 +798,12 @@ function onShowParsingCommands(): void { clients.ActiveClient.handleShowParsingCommands(); } -function onShowCodeAnalysisCommands(): void { - clients.ActiveClient.handleShowCodeAnalysisCommands(); +function onShowActiveCodeAnalysisCommands(): void { + clients.ActiveClient.handleShowActiveCodeAnalysisCommands(); +} + +function onShowIdleCodeAnalysisCommands(): void { + clients.ActiveClient.handleShowIdleCodeAnalysisCommands(); } function onShowReferencesProgress(): void { diff --git a/Extension/src/LanguageServer/ui.ts b/Extension/src/LanguageServer/ui.ts index 31bfde783b..4e47556ee9 100644 --- a/Extension/src/LanguageServer/ui.ts +++ b/Extension/src/LanguageServer/ui.ts @@ -6,16 +6,37 @@ import * as vscode from 'vscode'; import { Client } from './client'; +import * as nls from 'vscode-nls'; +import { NewUI } from './ui_new'; import { ReferencesCommandMode, referencesCommandModeToString } from './references'; import { getCustomConfigProviders, CustomConfigurationProviderCollection, isSameProviderExtensionId } from './customProviders'; -import * as nls from 'vscode-nls'; -import { setTimeout } from 'timers'; +import * as telemetry from '../telemetry'; +import { IExperimentationService } from 'tas-client'; +import { CppSettings } from './settings'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); +let uiPromise: Promise; let ui: UI; +export interface UI { + isNewUI: boolean; + activeDocumentChanged(): void; + bind(client: Client): void; + showConfigurations(configurationNames: string[]): Promise; + showConfigurationProviders(currentProvider?: string): Promise; + showCompileCommands(paths: string[]): Promise; + showWorkspaces(workspaceNames: { name: string; key: string }[]): Promise; + showParsingCommands(): Promise; + showActiveCodeAnalysisCommands(): Promise; + showIdleCodeAnalysisCommands(): Promise; + showConfigureIncludePathMessage(prompt: () => Promise, onSkip: () => void): void; + showConfigureCompileCommandsMessage(prompt: () => Promise, onSkip: () => void): void; + showConfigureCustomProviderMessage(prompt: () => Promise, onSkip: () => void): void; + dispose(): void; +} + interface IndexableQuickPickItem extends vscode.QuickPickItem { index: number; } @@ -35,7 +56,7 @@ interface ConfigurationStatus { priority: ConfigurationPriority; } -export class UI { +export class OldUI implements UI { private configStatusBarItem: vscode.StatusBarItem; private browseEngineStatusBarItem: vscode.StatusBarItem; private intelliSenseStatusBarItem: vscode.StatusBarItem; @@ -57,19 +78,20 @@ export class UI { private readonly codeAnalysisTranslationHint: string = "{0} is a program name, such as clang-tidy"; private runningCodeAnalysisTooltip: string = ""; private codeAnalysisPausedTooltip: string = ""; + get isNewUI(): boolean { return false; }; constructor() { const configTooltip: string = localize("c.cpp.configuration.tooltip", "C/C++ Configuration"); this.configStatusBarItem = vscode.window.createStatusBarItem("c.cpp.configuration.tooltip", vscode.StatusBarAlignment.Right, 0); this.configStatusBarItem.name = configTooltip; - this.configStatusBarItem.command = "C_Cpp.ConfigurationSelect"; + this.configStatusBarItem.command = "C_Cpp.ConfigurationSelectUI_Telemetry"; this.configStatusBarItem.tooltip = configTooltip; this.ShowConfiguration = true; this.referencesStatusBarItem = vscode.window.createStatusBarItem("c.cpp.references.statusbar", vscode.StatusBarAlignment.Right, 901); this.referencesStatusBarItem.name = localize("c.cpp.references.statusbar", "C/C++ References Status"); this.referencesStatusBarItem.tooltip = ""; - this.referencesStatusBarItem.command = "C_Cpp.ShowReferencesProgress"; + this.referencesStatusBarItem.command = "C_Cpp.ShowReferencesProgressUI_Telemetry"; this.ShowReferencesIcon = false; this.intelliSenseStatusBarItem = vscode.window.createStatusBarItem("c.cpp.intellisense.statusbar", vscode.StatusBarAlignment.Right, 903); @@ -111,7 +133,7 @@ export class UI { private setIsParsingWorkspacePausable(val: boolean): void { if (val) { - this.browseEngineStatusBarItem.command = "C_Cpp.ShowParsingCommands"; + this.browseEngineStatusBarItem.command = "C_Cpp.ShowParsingCommandsUI_Telemetry"; } else { this.browseEngineStatusBarItem.command = undefined; } @@ -167,7 +189,7 @@ export class UI { this.intelliSenseStatusBarItem.tooltip = (this.isUpdatingIntelliSense ? this.updatingIntelliSenseTooltip : "") + (twoStatus ? " | " : "") + (val ? this.runningCodeAnalysisTooltip : ""); - this.intelliSenseStatusBarItem.command = val ? "C_Cpp.ShowCodeAnalysisCommands" : undefined; + this.intelliSenseStatusBarItem.command = val ? "C_Cpp.ShowActiveCodeAnalysisCommandsUI_Telemetry" : undefined; } private updateCodeAnalysisTooltip(): void { @@ -371,7 +393,7 @@ export class UI { return (selection) ? selection.index : -1; } - public async showCodeAnalysisCommands(): Promise { + public async showActiveCodeAnalysisCommands(): Promise { const options: vscode.QuickPickOptions = {}; options.placeHolder = this.selectACommandString; @@ -387,6 +409,8 @@ export class UI { return (selection) ? selection.index : -1; } + public async showIdleCodeAnalysisCommands(): Promise {return -1; } + public showConfigureIncludePathMessage(prompt: () => Promise, onSkip: () => void): void { setTimeout(() => { this.showConfigurationPrompt(ConfigurationPriority.IncludePath, prompt, onSkip); @@ -438,9 +462,21 @@ export class UI { } } -export function getUI(): UI { +export async function getUI(): Promise { + if (!uiPromise) { + uiPromise = _getUI(); + } + return uiPromise; +} + +async function _getUI(): Promise { if (!ui) { - ui = new UI(); + const experimentationService: IExperimentationService | undefined = await telemetry.getExperimentationService(); + if (experimentationService !== undefined) { + const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); + const useNewUI: boolean | undefined = experimentationService.getTreatmentVariable("vscode", "ShowLangStatBar"); + ui = useNewUI || settings.experimentalFeatures ? new NewUI() : new OldUI(); + } } return ui; } diff --git a/Extension/src/LanguageServer/ui_new.ts b/Extension/src/LanguageServer/ui_new.ts new file mode 100644 index 0000000000..ff8f026fd1 --- /dev/null +++ b/Extension/src/LanguageServer/ui_new.ts @@ -0,0 +1,547 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. + * See 'LICENSE' in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as vscode from 'vscode'; +import { documentSelector } from '../common'; +import { Client } from './client'; +import { ReferencesCommandMode, referencesCommandModeToString } from './references'; +import { getCustomConfigProviders, CustomConfigurationProviderCollection, isSameProviderExtensionId } from './customProviders'; +import * as nls from 'vscode-nls'; +import { setTimeout } from 'timers'; +import { CppSettings } from './settings'; +import { UI } from './ui'; + +nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); + +interface IndexableQuickPickItem extends vscode.QuickPickItem { + index: number; +} +interface KeyedQuickPickItem extends vscode.QuickPickItem { + key: string; +} + +// Higher numbers mean greater priority. +enum ConfigurationPriority { + IncludePath = 1, + CompileCommands = 2, + CustomProvider = 3, +} + +interface ConfigurationStatus { + configured: boolean; + priority: ConfigurationPriority; +} + +enum LanguageStatusPriority { + First = 0, + High = 1, + Mid = 2, + Low = 3 +} + +export class NewUI implements UI { + private configStatusBarItem: vscode.LanguageStatusItem; + private browseEngineStatusBarItem: vscode.LanguageStatusItem; + private intelliSenseStatusBarItem: vscode.LanguageStatusItem; + private referencesStatusBarItem: vscode.StatusBarItem; + private codeAnalysisStatusBarItem: vscode.LanguageStatusItem; + private configDocumentSelector: vscode.DocumentFilter[] = [ + { scheme: 'file', language: 'c' }, + { scheme: 'file', language: 'cpp' }, + { scheme: 'file', language: 'cuda-cpp' }, + { scheme: 'file', language: 'jsonc', pattern: '**/.vscode/*.json'}, + { scheme: 'file', language: 'jsonc', pattern: '**/*.code-workspace'}, + { scheme: 'output'} + ]; + /** **************************************************** */ + private curConfigurationStatus?: Promise; + private isParsingWorkspace: boolean = false; + private isParsingWorkspacePaused: boolean = false; + private isParsingFiles: boolean = false; + private isRunningCodeAnalysis: boolean = false; + private isCodeAnalysisPaused: boolean = false; + private codeAnalysisProcessed: number = 0; + private codeAnalysisTotal: number = 0; + private readonly workspaceParsingRunningText: string = localize("running.tagparser.text", "Parsing Workspace"); + private readonly workspaceParsingPausedText: string = localize("paused.tagparser.text", "Parsing Workspace: Paused"); + private readonly workspaceParseingDoneText: string = localize("complete.tagparser.text", "Parsing Complete"); + private workspaceParsingStatus: string = ""; + private workspaceParsingProgress: string = ""; + private readonly workspaceRescanText = localize("rescan.tagparse.text", "Rescan Workspace"); + private codeAnalysisProgram: string = ""; + private readonly parsingFilesTooltip: string = localize("c.cpp.parsing.open.files.tooltip", "Parsing Open Files"); + private readonly referencesPreviewTooltip: string = ` (${localize("click.to.preview", "click to preview results")})`; + private readonly updatingIntelliSenseText: string = localize("updating.intellisense.text", "IntelliSense: Updating"); + private readonly idleIntelliSenseText: string = localize("idle.intellisense.text", "IntelliSense: Ready"); + private readonly missingIntelliSenseText: string = localize("absent.intellisense.text", "IntelliSense: Not configured"); + private readonly codeAnalysisTranslationHint: string = "{0} is a program name, such as clang-tidy"; + private readonly codeAnalysisRunningText: string = localize("running.analysis.text", "Code Analysis: Running"); + private readonly codeAnalysisPausedText: string = localize("paused.analysis.text", "Code Analysis: Paused"); + private readonly codeAnalysisModePrefix: string = localize("mode.analysis.prefix", "Code Analysis Mode: "); + private codeAnalysProgress: string = ""; + // Prevent icons from appearing too often and for too short of a time. + private readonly iconDelayTime: number = 1000; + get isNewUI(): boolean { return true; }; + + constructor() { + this.configStatusBarItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.First}.configuration`, this.configDocumentSelector); + this.configStatusBarItem.name = localize("cpptools.status.configuration", "Select Configuration"); + this.configStatusBarItem.text = "Loading configuration..."; + this.configStatusBarItem.command = { + command: "C_Cpp.ConfigurationSelectUI_Telemetry", + title: this.configStatusBarItem.name as string, + tooltip: this.configStatusBarItem.name as string + }; + + this.referencesStatusBarItem = vscode.window.createStatusBarItem(`c.cpp.references.statusbar`, vscode.StatusBarAlignment.Right, 901); + this.referencesStatusBarItem.name = localize("c.cpp.references.statusbar", "C/C++ References Status"); + this.referencesStatusBarItem.tooltip = ""; + this.referencesStatusBarItem.command = "C_Cpp.ShowReferencesProgressUI_Telemetry"; + this.ShowReferencesIcon = false; + + this.intelliSenseStatusBarItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.intellisense`, documentSelector); + this.intelliSenseStatusBarItem.name = localize("cpptools.status.intellisense", "C/C++ IntelliSense Status"); + this.intelliSenseStatusBarItem.text = this.idleIntelliSenseText; + + this.browseEngineStatusBarItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.tagparser`, documentSelector); + this.browseEngineStatusBarItem.name = localize("cpptools.status.tagparser", "C/C++ Tag Parser Status"); + this.browseEngineStatusBarItem.detail = localize("indexing.files.tooltip", "Indexing Workspace"); + this.browseEngineStatusBarItem.text = "$(database)"; + this.browseEngineStatusBarItem.command = { + command: "C_Cpp.RescanWorkspaceUI_Telemetry", + title: this.workspaceRescanText + }; + this.workspaceParsingStatus = this.workspaceParsingRunningText; + + this.codeAnalysisStatusBarItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Low}.codeanalysis`, documentSelector); + this.codeAnalysisStatusBarItem.name = localize("cpptools.status.codeanalysis", "C/C++ Code Analysis Status"); + this.codeAnalysisStatusBarItem.text = `Code Analysis Mode: ${this.codeAnalysisCurrentMode()}`; + this.codeAnalysisStatusBarItem.command = { + command: "C_Cpp.ShowIdleCodeAnalysisCommandsUI_Telemetry", + title: localize("c.cpp.codeanalysis.statusbar.runNow", "Run Now") + }; + + } + + private set ActiveConfig(label: string) { + this.configStatusBarItem.text = label ?? localize("configuration.notselected.text", "Configuration: Not selected"); + if (this.configStatusBarItem.command) { + this.configStatusBarItem.command.title = localize("configuration.selected.text", "Select Configuration"); + } + } + + private set TagParseStatus(label: string) { + this.workspaceParsingProgress = label; + if (this.browseEngineStatusBarItem.command) { + // Currently needed in order to update hover tooltip + this.browseEngineStatusBarItem.command.tooltip = (this.isParsingFiles ? `${this.parsingFilesTooltip} | ` : "") + this.workspaceParsingProgress; + this.browseEngineStatusBarItem.text = this.browseEngineStatusBarItem.text; + } + } + + private dbTimeout?: NodeJS.Timeout; + private setIsParsingWorkspace(val: boolean): void { + this.isParsingWorkspace = val; + const showIcon: boolean = val || this.isParsingFiles; + const twoStatus: boolean = val && this.isParsingFiles; + + // Leave this outside for more realtime respone + this.browseEngineStatusBarItem.busy = showIcon; + + if (showIcon) { + this.browseEngineStatusBarItem.text = "$(database)"; + this.browseEngineStatusBarItem.detail = (this.isParsingFiles ? this.parsingFilesTooltip : "") + + (twoStatus ? " | " : "") + + (val ? this.workspaceParsingStatus : ""); + + if (this.dbTimeout) { + clearTimeout(this.dbTimeout); + } + } else { + this.dbTimeout = setTimeout(() => { + this.browseEngineStatusBarItem.text = this.workspaceParseingDoneText; + this.browseEngineStatusBarItem.detail = ""; + this.browseEngineStatusBarItem.command = { + command: "C_Cpp.RescanWorkspaceUI_Telemetry", + title: this.workspaceRescanText + }; + }, this.iconDelayTime); + } + } + + private setIsParsingWorkspacePausable(val: boolean): void { + if (val && this.isParsingWorkspace) { + this.browseEngineStatusBarItem.command = { + command: "C_Cpp.PauseParsingUI_Telemetry", + title: localize("tagparser.pause.text", "Pause") + }; + } + } + + private setIsParsingWorkspacePaused(val: boolean): void { + this.isParsingWorkspacePaused = val; + this.browseEngineStatusBarItem.busy = !val || this.isParsingFiles; + this.browseEngineStatusBarItem.text = "$(database)"; + this.workspaceParsingStatus = val ? this.workspaceParsingPausedText : this.workspaceParsingRunningText; + this.browseEngineStatusBarItem.detail = (this.isParsingFiles ? `${this.parsingFilesTooltip} | ` : "") + this.workspaceParsingStatus; + this.browseEngineStatusBarItem.command = val ? { + command: "C_Cpp.ResumeParsingUI_Telemetry", + title: localize("tagparser.resume.text", "Resume") + } : { + command: "C_Cpp.PauseParsingUI_Telemetry", + title: localize("tagparser.pause.text", "Pause") + }; + } + + private setIsCodeAnalysisPaused(val: boolean): void { + if (!this.isRunningCodeAnalysis) { + return; + } + + this.isCodeAnalysisPaused = val; + this.codeAnalysisStatusBarItem.busy = !val; + this.codeAnalysisStatusBarItem.text = val ? this.codeAnalysisPausedText : this.codeAnalysisRunningText; + } + + private setIsParsingFiles(val: boolean): void { + + this.isParsingFiles = val; + const showIcon: boolean = val || (!this.isParsingWorkspacePaused && this.isParsingWorkspace); + const twoStatus: boolean = val && this.isParsingWorkspace; + + // Leave this outside for more realtime respone + this.browseEngineStatusBarItem.busy = showIcon; + + if (showIcon) { + this.browseEngineStatusBarItem.text = "$(database)"; + this.browseEngineStatusBarItem.detail = (val ? this.parsingFilesTooltip : "") + + (twoStatus ? " | " : "") + + (this.isParsingWorkspace ? this.workspaceParsingStatus : ""); + + if (this.dbTimeout) { + clearTimeout(this.dbTimeout); + } + } else if (!this.isParsingWorkspace && !val) { + this.dbTimeout = setTimeout(() => { + this.browseEngineStatusBarItem.text = this.workspaceParseingDoneText; + this.browseEngineStatusBarItem.detail = ""; + this.browseEngineStatusBarItem.command = { + command: "C_Cpp.RescanWorkspaceUI_Telemetry", + title: this.workspaceRescanText + }; + }, this.iconDelayTime); + } + } + + private flameTimeout?: NodeJS.Timeout; + private setIsUpdatingIntelliSense(val: boolean): void { + + const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); + + // TODO: Integrate with Tarik's feature to determine if compiler/bare-intellisense is configured + if (settings.intelliSenseEngine === "disabled") { + this.intelliSenseStatusBarItem.text = this.missingIntelliSenseText; + this.intelliSenseStatusBarItem.command = { + command: "C_Cpp.CheckForCompilerUI_Telemetry", + title: localize("intellisense.select.text", "Select a Compiler") + }; + return; + } + + this.intelliSenseStatusBarItem.busy = val; + + if (this.flameTimeout) { + clearTimeout(this.flameTimeout); + } + + if (val) { + this.intelliSenseStatusBarItem.text = "$(flame)"; + this.intelliSenseStatusBarItem.detail = this.updatingIntelliSenseText; + } else { + this.flameTimeout = setTimeout(() => { + if (this.intelliSenseStatusBarItem) { + this.intelliSenseStatusBarItem.text = this.idleIntelliSenseText; + this.intelliSenseStatusBarItem.detail = ""; + } + }, this.iconDelayTime); + } + this.intelliSenseStatusBarItem.command = { + command: "C_Cpp.RestartIntelliSenseForFileUI_Telemetry", + title: localize("rescan.intellisense.text", "Rescan"), + tooltip: localize("rescan.intellisense.tooltip", "Rescan IntelliSense") + }; + } + + private codeAnalysisCurrentMode(): string { + const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); + const state: string = (settings.codeAnalysisRunAutomatically && settings.clangTidyEnabled) + ? localize("mode.codeanalysis.status", "Automatic") + : localize("mode.codeanalysis.status", "Manual"); + return state; + } + + private setIsRunningCodeAnalysis(val: boolean): void { + if (this.isRunningCodeAnalysis && !val) { + this.codeAnalysisTotal = 0; + this.codeAnalysisProcessed = 0; + } + this.isRunningCodeAnalysis = val; + this.codeAnalysisStatusBarItem.busy = val; + const activeText: string = this.isCodeAnalysisPaused ? this.codeAnalysisPausedText : this.codeAnalysisRunningText; + const idleText: string = this.codeAnalysisModePrefix + this.codeAnalysisCurrentMode(); + this.codeAnalysisStatusBarItem.text = val ? activeText : idleText; + this.codeAnalysisStatusBarItem.command = val ? { + command: "C_Cpp.ShowActiveCodeAnalysisCommandsUI_Telemetry", + title: localize("c.cpp.codeanalysis.statusbar.showCodeAnalysisOptions", "Options"), + // Make sure not to overwrite current progress + tooltip: this.codeAnalysisStatusBarItem.command?.tooltip ?? localize("startup.codeanalysis.status", "Starting...") + } : { + command: "C_Cpp.ShowIdleCodeAnalysisCommandsUI_Telemetry", + title: localize("c.cpp.codeanalysis.statusbar.showRunNowOptions", "Run Now") + }; + } + + private updateCodeAnalysisTooltip(): void { + this.codeAnalysProgress = localize({ key: "running.analysis.processed.tooltip", comment: [this.codeAnalysisTranslationHint] }, "Running {0}: {1} / {2} ({3}%)", this.codeAnalysisProgram, + this.codeAnalysisProcessed, Math.max(this.codeAnalysisTotal, 1), Math.floor(100 * this.codeAnalysisProcessed / Math.max(this.codeAnalysisTotal, 1))); + + if (this.codeAnalysisStatusBarItem.command) { + this.codeAnalysisStatusBarItem.command.tooltip = this.codeAnalysProgress; + this.codeAnalysisStatusBarItem.text = this.codeAnalysisStatusBarItem.text; + + } + this.setIsRunningCodeAnalysis(true); + } + + private setCodeAnalysisProcessed(processed: number): void { + if (!this.isRunningCodeAnalysis) { + return; // Occurs when a multi-root workspace is activated. + } + this.codeAnalysisProcessed = processed; + if (this.codeAnalysisProcessed > this.codeAnalysisTotal) { + this.codeAnalysisTotal = this.codeAnalysisProcessed + 1; + } + this.updateCodeAnalysisTooltip(); + } + + private setCodeAnalysisTotal(total: number): void { + if (!this.isRunningCodeAnalysis) { + return; // Occurs when a multi-root workspace is activated. + } + this.codeAnalysisTotal = total; + this.updateCodeAnalysisTooltip(); + } + + private get ReferencesCommand(): ReferencesCommandMode { + return this.referencesStatusBarItem.tooltip === "" ? ReferencesCommandMode.None : + (this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Find) ? ReferencesCommandMode.Find : + (this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Rename) ? ReferencesCommandMode.Rename : + ReferencesCommandMode.Peek)); + } + + private set ReferencesCommand(val: ReferencesCommandMode) { + if (val === ReferencesCommandMode.None) { + this.referencesStatusBarItem.text = ""; + this.ShowReferencesIcon = false; + } else { + this.referencesStatusBarItem.text = "$(search)"; + this.referencesStatusBarItem.tooltip = referencesCommandModeToString(val) + (val !== ReferencesCommandMode.Find ? "" : this.referencesPreviewTooltip); + this.ShowReferencesIcon = true; + } + } + + private set ShowReferencesIcon(show: boolean) { + if (show && this.ReferencesCommand !== ReferencesCommandMode.None) { + this.referencesStatusBarItem.show(); + } else { + this.referencesStatusBarItem.hide(); + } + } + + public activeDocumentChanged(): void { + const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; + if (activeEditor) { + let isCppPropertiesJson: boolean = false; + if (activeEditor.document.languageId === "json" || activeEditor.document.languageId === "jsonc") { + isCppPropertiesJson = activeEditor.document.fileName.endsWith("c_cpp_properties.json"); + if (isCppPropertiesJson) { + vscode.languages.setTextDocumentLanguage(activeEditor.document, "jsonc"); + } + } + } + } + + public bind(client: Client): void { + client.ParsingWorkspaceChanged(value => { this.setIsParsingWorkspace(value); }); + client.ParsingWorkspacePausableChanged(value => { this.setIsParsingWorkspacePausable(value); }); + client.ParsingWorkspacePausedChanged(value => { this.setIsParsingWorkspacePaused(value); }); + client.ParsingFilesChanged(value => { this.setIsParsingFiles(value); }); + client.IntelliSenseParsingChanged(value => { this.setIsUpdatingIntelliSense(value); }); + client.RunningCodeAnalysisChanged(value => { this.setIsRunningCodeAnalysis(value); }); + client.CodeAnalysisPausedChanged(value => { this.setIsCodeAnalysisPaused(value); }); + client.CodeAnalysisProcessedChanged(value => { this.setCodeAnalysisProcessed(value); }); + client.CodeAnalysisTotalChanged(value => { this.setCodeAnalysisTotal(value); }); + client.ReferencesCommandModeChanged(value => { this.ReferencesCommand = value; }); + client.TagParserStatusChanged(value => { this.TagParseStatus = value; }); + client.ActiveConfigChanged(value => { this.ActiveConfig = value; }); + } + + public async showConfigurations(configurationNames: string[]): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = localize("select.a.configuration", "Select a Configuration..."); + + const items: IndexableQuickPickItem[] = []; + for (let i: number = 0; i < configurationNames.length; i++) { + items.push({ label: configurationNames[i], description: "", index: i }); + } + items.push({ label: localize("edit.configuration.ui", "Edit Configurations (UI)"), description: "", index: configurationNames.length }); + items.push({ label: localize("edit.configuration.json", "Edit Configurations (JSON)"), description: "", index: configurationNames.length + 1 }); + + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public async showConfigurationProviders(currentProvider?: string): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = localize("select.configuration.provider", "Select a Configuration Provider..."); + const providers: CustomConfigurationProviderCollection = getCustomConfigProviders(); + + const items: KeyedQuickPickItem[] = []; + providers.forEach(provider => { + let label: string = provider.name; + if (isSameProviderExtensionId(currentProvider, provider.extensionId)) { + label += ` (${localize("active", "active")})`; + } + items.push({ label: label, description: "", key: provider.extensionId }); + }); + items.push({ label: `(${localize("none", "none")})`, description: localize("disable.configuration.provider", "Disable the active configuration provider, if applicable."), key: "" }); + + const selection: KeyedQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.key : undefined; + } + + public async showCompileCommands(paths: string[]): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = localize("select.compile.commands", "Select a compile_commands.json..."); + + const items: IndexableQuickPickItem[] = []; + for (let i: number = 0; i < paths.length; i++) { + items.push({label: paths[i], description: "", index: i}); + } + + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public async showWorkspaces(workspaceNames: { name: string; key: string }[]): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = localize("select.workspace", "Select a workspace folder..."); + + const items: KeyedQuickPickItem[] = []; + workspaceNames.forEach(name => items.push({ label: name.name, description: "", key: name.key })); + + const selection: KeyedQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.key : ""; + } + + private readonly selectACommandString: string = localize("select.command", "Select a command..."); + + public async showParsingCommands(): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = this.selectACommandString; + + const items: IndexableQuickPickItem[] = []; + if (this.isParsingWorkspacePaused) { + items.push({ label: localize("resume.parsing", "Resume Workspace Parsing"), description: "", index: 1 }); + } else { + items.push({ label: localize("pause.parsing", "Pause Workspace Parsing"), description: "", index: 0 }); + } + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public async showActiveCodeAnalysisCommands(): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = this.selectACommandString; + + const items: IndexableQuickPickItem[] = []; + items.push({ label: localize({ key: "cancel.analysis", comment: [this.codeAnalysisTranslationHint]}, "Cancel {0}", this.codeAnalysisProgram), description: "", index: 0 }); + + if (this.isCodeAnalysisPaused) { + items.push({ label: localize({ key: "resume.analysis", comment: [this.codeAnalysisTranslationHint]}, "Resume {0}", this.codeAnalysisProgram), description: "", index: 2 }); + } else { + items.push({ label: localize({ key: "pause.analysis", comment: [this.codeAnalysisTranslationHint]}, "Pause {0}", this.codeAnalysisProgram), description: "", index: 1 }); + } + items.push({ label: localize({ key: "another.analysis", comment: [this.codeAnalysisTranslationHint]}, "Start Another {0}...", this.codeAnalysisProgram), description: "", index: 3 }); + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public async showIdleCodeAnalysisCommands(): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = this.selectACommandString; + + const items: IndexableQuickPickItem[] = []; + items.push({ label: localize({ key: "active.analysis", comment: [this.codeAnalysisTranslationHint]}, "Run Code Analysis on Active File", this.codeAnalysisProgram), description: "", index: 0 }); + items.push({ label: localize({ key: "all.analysis", comment: [this.codeAnalysisTranslationHint]}, "Run Code Analysis on All Files", this.codeAnalysisProgram), description: "", index: 1 }); + items.push({ label: localize({ key: "open.analysis", comment: [this.codeAnalysisTranslationHint]}, "Run Code Analysis on Open Files", this.codeAnalysisProgram), description: "", index: 2 }); + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public showConfigureIncludePathMessage(prompt: () => Promise, onSkip: () => void): void { + setTimeout(() => { + this.showConfigurationPrompt(ConfigurationPriority.IncludePath, prompt, onSkip); + }, 10000); + } + + public showConfigureCompileCommandsMessage(prompt: () => Promise, onSkip: () => void): void { + setTimeout(() => { + this.showConfigurationPrompt(ConfigurationPriority.CompileCommands, prompt, onSkip); + }, 5000); + } + + public showConfigureCustomProviderMessage(prompt: () => Promise, onSkip: () => void): void { + this.showConfigurationPrompt(ConfigurationPriority.CustomProvider, prompt, onSkip); + } + + private showConfigurationPrompt(priority: ConfigurationPriority, prompt: () => Thenable, onSkip: () => void): void { + const showPrompt: () => Promise = async () => { + const configured: boolean = await prompt(); + return Promise.resolve({ + priority: priority, + configured: configured + }); + }; + + if (this.curConfigurationStatus) { + this.curConfigurationStatus = this.curConfigurationStatus.then(result => { + if (priority > result.priority) { + return showPrompt(); + } else if (!result.configured) { + return showPrompt(); + } + onSkip(); + return Promise.resolve({ + priority: result.priority, + configured: true + }); + }); + } else { + this.curConfigurationStatus = showPrompt(); + } + } + + public dispose(): void { + this.configStatusBarItem.dispose(); + this.browseEngineStatusBarItem.dispose(); + this.intelliSenseStatusBarItem.dispose(); + this.referencesStatusBarItem.dispose(); + this.codeAnalysisStatusBarItem.dispose(); + } +} + diff --git a/Extension/src/common.ts b/Extension/src/common.ts index e57566d922..6886bb5dc1 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -17,6 +17,7 @@ import * as tmp from 'tmp'; import * as nls from 'vscode-nls'; import * as jsonc from 'comment-json'; import { TargetPopulation } from 'vscode-tas-client'; +import { DocumentFilter } from 'vscode-languageclient'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -1452,3 +1453,9 @@ export function whichAsync(name: string): Promise { }); }); } + +export const documentSelector: DocumentFilter[] = [ + { scheme: 'file', language: 'c' }, + { scheme: 'file', language: 'cpp' }, + { scheme: 'file', language: 'cuda-cpp' } +]; From c4d68fd859280834549cb83dd1f5d7b7851757f1 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:44:44 -0800 Subject: [PATCH 06/17] Disable auto-kill of extension when debugging (#10415) --- Extension/src/LanguageServer/client.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 34c63346f0..aaf0c87d8e 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -1178,10 +1178,8 @@ export class DefaultClient implements Client { } const serverName: string = this.getName(this.rootFolder); const serverOptions: ServerOptions = { - // Running detached would be preferred; however, that causes cpptools-srv to create a console window - // on Windows and that can't seem to be suppressed without suppressing assertion dialog boxes. run: { command: serverModule, options: { detached: false } }, - debug: { command: serverModule, args: [serverName], options: { detached: false } } + debug: { command: serverModule, args: [serverName], options: { detached: true } } }; let intelliSenseCacheDisabled: boolean = false; From b96737a919536d7d8dca8ef763c65b2bdf183348 Mon Sep 17 00:00:00 2001 From: browntarik <111317156+browntarik@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:02:47 -0800 Subject: [PATCH 07/17] Add support for selecting a default compiler (#10165) --- Extension/package.json | 6 + Extension/package.nls.json | 1 + Extension/src/LanguageServer/client.ts | 191 ++++++++++++++++-- .../src/LanguageServer/configurations.ts | 35 ++-- Extension/src/LanguageServer/extension.ts | 9 +- Extension/src/LanguageServer/settings.ts | 3 + Extension/src/common.ts | 24 ++- Extension/src/nativeStrings.json | 3 + 8 files changed, 234 insertions(+), 38 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index a7ef237ddb..27efd006e1 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -56,6 +56,7 @@ "onCommand:C_Cpp.RestartIntelliSenseForFile", "onCommand:C_Cpp.ConfigurationEditJSON", "onCommand:C_Cpp.ConfigurationEditUI", + "onCommand:C_Cpp.selectDefaultCompiler", "onCommand:C_Cpp.ConfigurationSelect", "onCommand:C_Cpp.ConfigurationProviderSelect", "onCommand:C_Cpp.CreateDeclarationOrDefinition", @@ -2941,6 +2942,11 @@ "title": "%c_cpp.command.configurationEditUI.title%", "category": "C/C++" }, + { + "command": "C_Cpp.selectDefaultCompiler", + "title": "%c_cpp.command.selectDefaultCompiler.title%", + "category": "C/C++" + }, { "command": "C_Cpp.SwitchHeaderSource", "title": "%c_cpp.command.switchHeaderSource.title%", diff --git a/Extension/package.nls.json b/Extension/package.nls.json index dddb6a81c5..1a66800400 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -11,6 +11,7 @@ "c_cpp.command.configurationProviderSelect.title": "Change Configuration Provider...", "c_cpp.command.configurationEditJSON.title": "Edit Configurations (JSON)", "c_cpp.command.configurationEditUI.title": "Edit Configurations (UI)", + "c_cpp.command.selectDefaultCompiler.title": "Select Default Compiler", "c_cpp.command.switchHeaderSource.title": "Switch Header/Source", "c_cpp.command.enableErrorSquiggles.title": "Enable Error Squiggles", "c_cpp.command.disableErrorSquiggles.title": "Disable Error Squiggles", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index aaf0c87d8e..8886d44c34 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -58,7 +58,8 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle(); let ui: UI; let timeStamp: number = 0; const configProviderTimeout: number = 2000; - +let initializedClientCount: number = 0; +export let compilerPaths: string[] = []; // Data shared by all clients. let languageClient: LanguageClient; let firstClientStarted: Promise; @@ -68,6 +69,7 @@ let pendingTask: util.BlockingTask | undefined; let compilerDefaults: configs.CompilerDefaults; let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection; let diagnosticsCollectionRefactor: vscode.DiagnosticCollection; +let displayedSelectCompiler: boolean = false; let workspaceDisposables: vscode.Disposable[] = []; export let workspaceReferences: refs.ReferencesManager; @@ -184,7 +186,8 @@ interface ReportStatusNotificationBody extends WorkspaceFolderParams { status: string; } -interface QueryCompilerDefaultsParams { +interface QueryDefaultCompilerParams { + trustedCompilerPaths: string[]; } interface CppPropertiesParams extends WorkspaceFolderParams { @@ -466,6 +469,13 @@ export interface GenerateDoxygenCommentResult { isCursorAboveSignatureLine: boolean; } +export interface IndexableQuickPickItem extends vscode.QuickPickItem { + index: number; +} +export interface UpdateTrustedCompilerPathsResult { + compilerPath: string; +} + export interface DoxygenCodeActionCommandArguments { initialCursor: Position; adjustedCursor: Position; @@ -517,7 +527,7 @@ interface InitializationOptions { }; // Requests -const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryCompilerDefaults'); +const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryCompilerDefaults'); const QueryTranslationUnitSourceRequest: RequestType = new RequestType('cpptools/queryTranslationUnitSource'); const SwitchHeaderSourceRequest: RequestType = new RequestType('cpptools/didSwitchHeaderSource'); const GetDiagnosticsRequest: RequestType = new RequestType('cpptools/getDiagnostics'); @@ -568,6 +578,7 @@ const RemoveCodeAnalysisProblemsNotification: NotificationType = new NotificationType('cpptools/reloadWindow'); +const UpdateTrustedCompilersNotification: NotificationType = new NotificationType('cpptools/updateTrustedCompilersList'); const LogTelemetryNotification: NotificationType = new NotificationType('cpptools/logTelemetry'); const ReportTagParseStatusNotification: NotificationType = new NotificationType('cpptools/reportTagParseStatus'); const ReportStatusNotification: NotificationType = new NotificationType('cpptools/reportStatus'); @@ -723,6 +734,7 @@ export interface Client { selectionChanged(selection: Range): void; resetDatabase(): void; deactivate(): void; + promptSelectCompiler(command: boolean): Promise; pauseParsing(): void; resumeParsing(): void; PauseCodeAnalysis(): void; @@ -844,7 +856,7 @@ export class DefaultClient implements Client { return this.innerLanguageClient; } - private get configuration(): configs.CppProperties { + public get configuration(): configs.CppProperties { if (!this.innerConfiguration) { throw new Error("Attempting to use configuration before initialized"); } @@ -864,6 +876,125 @@ export class DefaultClient implements Client { return workspaceFolder ? workspaceFolder.name : "untitled"; } + public updateClientConfigurations(): void { + clients.forEach(client => { + if (client instanceof DefaultClient) { + const defaultClient: DefaultClient = client; + defaultClient.configuration.CompilerDefaults = compilerDefaults; + defaultClient.configuration.handleConfigurationChange(); + } + }); + } + + public async showSelectCompiler(paths: string[]): Promise { + const options: vscode.QuickPickOptions = {}; + options.placeHolder = localize("select.compile.commands", "Select a compiler to configure for IntelliSense"); + + const items: IndexableQuickPickItem[] = []; + for (let i: number = 0; i < paths.length; i++) { + let option: string | undefined; + let isCompiler: boolean = false; + const slash: string = (os.platform() === 'win32') ? "\\" : "/"; + + if (paths[i].includes(slash)) { + if (paths[i].split(slash).pop() !== undefined) { + option = paths[i].split(slash).pop(); + isCompiler = true; + } + } + + if (option !== undefined && isCompiler) { + const path: string | undefined = paths[i].replace(option, ""); + items.push({ label: option, description: localize("found.string", "Found at {0}", path), index: i }); + } else { + items.push({ label: paths[i], index: i }); + } + } + + const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options); + return (selection) ? selection.index : -1; + } + + public async handleCompilerQuickPick(): Promise { + const settings: OtherSettings = new OtherSettings(); + let paths: string[] = []; + if (compilerDefaults.knownCompilers !== undefined) { + paths = compilerDefaults.knownCompilers.map(function (a: configs.KnownCompiler): string { return a.path; }); + } + paths.push(localize("selectAnotherCompiler.string", "Select another compiler on my machine")); + paths.push(localize("installCompiler.string", "Help me install a compiler")); + paths.push(localize("noConfig.string", "Do not configure a compiler (not recommended)")); + const index: number = await this.showSelectCompiler(paths); + if (index === -1) { + return; + } + if (index === paths.length - 1) { + settings.defaultCompiler = ""; + } else if (index === paths.length - 2) { + switch (os.platform()) { + case 'win32': + vscode.commands.executeCommand('vscode.open', "https://go.microsoft.com/fwlink/?linkid=2217614"); + return; + case 'darwin': + vscode.commands.executeCommand('vscode.open', "https://go.microsoft.com/fwlink/?linkid=2217706"); + return; + default: // Linux + vscode.commands.executeCommand('vscode.open', "https://go.microsoft.com/fwlink/?linkid=2217615"); + return; + } + } else if (index === paths.length - 3) { + const result: vscode.Uri[] | undefined = await vscode.window.showOpenDialog(); + if (result !== undefined && result.length > 0) { + util.addTrustedCompiler(compilerPaths, result[0].fsPath); + settings.defaultCompiler = result[0].fsPath; + compilerDefaults = await this.requestCompiler(compilerPaths); + this.updateClientConfigurations(); + return; + } + } else { + util.addTrustedCompiler(compilerPaths, paths[index]); + } + // If a compiler is selected, update the default.compilerPath user setting. + if (index < paths.length - 3) { + settings.defaultCompiler = paths[index]; + } + compilerDefaults = await this.requestCompiler(compilerPaths); + this.updateClientConfigurations(); + } + + async promptSelectCompiler(command: boolean): Promise { + const selectCompiler: string = localize("selectCompiler.string", "Select Compiler"); + const confirmCompiler: string = localize("confirmCompiler.string", "Yes"); + const settings: OtherSettings = new OtherSettings(); + if (compilerDefaults.compilerPath !== "") { + if (!command) { + const value: string | undefined = await vscode.window.showInformationMessage(localize("selectCompiler.message", "The compiler {0} was found on this computer. Do you want to configure it for IntelliSense?", compilerDefaults.compilerPath), confirmCompiler, selectCompiler); + if (value === confirmCompiler) { + compilerPaths = await util.addTrustedCompiler(compilerPaths, compilerDefaults.compilerPath); + settings.defaultCompiler = compilerDefaults.compilerPath; + compilerDefaults = await this.requestCompiler(compilerPaths); + this.updateClientConfigurations(); + } else if (value === selectCompiler) { + this.handleCompilerQuickPick(); + } else { + const setCompiler: string = localize("setCompiler.string", "Set Compiler"); + const value: string | undefined = await vscode.window.showInformationMessage(localize("setCompiler.message", "You do not have a compiler configured. Unless you set your own configurations, IntelliSense may not be functional."), selectCompiler); + if (value === setCompiler) { + this.handleCompilerQuickPick(); + } + } + } else if (!command && (compilerDefaults.compilerPath === undefined)) { + const setCompiler: string = localize("setCompiler.string", "Set Compiler"); + const value: string | undefined = await vscode.window.showInformationMessage(localize("setCompiler.message", "You do not have a compiler configured. Unless you set your own configurations, IntelliSense may not be functional."), selectCompiler); + if (value === setCompiler) { + this.handleCompilerQuickPick(); + } + } else { + this.handleCompilerQuickPick(); + } + } + } + /** * All public methods on this class must be guarded by the "pendingTask" promise. Requests and notifications received before the task is * complete are executed after this promise is resolved. @@ -944,17 +1075,10 @@ export class DefaultClient implements Client { if (isFirstClient) { workspaceReferences = new refs.ReferencesManager(this); - - // The configurations will not be sent to the language server until the default include paths and frameworks have been set. - // The event handlers must be set before this happens. - const inputCompilerDefaults: configs.CompilerDefaults = await languageClient.sendRequest(QueryCompilerDefaultsRequest, {}); - compilerDefaults = inputCompilerDefaults; - this.configuration.CompilerDefaults = compilerDefaults; - // Only register file watchers and providers after the extension has finished initializing, // e.g. prevents empty c_cpp_properties.json from generation. this.registerFileWatcher(); - + initializedClientCount = 0; this.inlayHintsProvider = new InlayHintsProvider(this); this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider)); @@ -980,8 +1104,28 @@ export class DefaultClient implements Client { } // Listen for messages from the language server. this.registerNotifications(); - } else { - this.configuration.CompilerDefaults = compilerDefaults; + } + // update all client configurations + this.configuration.setupConfigurations(); + initializedClientCount++; + // count number of clients, once all clients are configured, check for trusted compiler to display notification to user and add a short delay to account for config provider logic to finish + if ((vscode.workspace.workspaceFolders === undefined) || (initializedClientCount >= vscode.workspace.workspaceFolders.length)) { + // The configurations will not be sent to the language server until the default include paths and frameworks have been set. + // The event handlers must be set before this happens. + const inputCompilerDefaults: configs.CompilerDefaults = await this.requestCompiler(compilerPaths); + compilerDefaults = inputCompilerDefaults; + clients.forEach(client => { + if (client instanceof DefaultClient) { + const defaultClient: DefaultClient = client; + defaultClient.configuration.CompilerDefaults = compilerDefaults; + defaultClient.configuration.handleConfigurationChange(); + } + }); + if (!compilerDefaults.trustedCompilerFound && !displayedSelectCompiler) { + // if there is no compilerPath in c_cpp_properties.json, prompt user to configure a compiler + this.promptSelectCompiler(false); + displayedSelectCompiler = true; + } } } catch (err) { this.isSupported = false; // Running on an OS we don't support yet. @@ -1255,7 +1399,7 @@ export class DefaultClient implements Client { // Create the language client this.loggingLevel = initializationOptions.settings.loggingLevel; - languageClient = new LanguageClient(`cpptools`, serverOptions, clientOptions); + languageClient = new LanguageClient(`cpptools`, serverOptions, clientOptions); setupOutputHandlers(); languageClient.registerProposedFeatures(); await languageClient.start(); @@ -1884,6 +2028,7 @@ export class DefaultClient implements Client { console.assert(this.languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\""); this.languageClient.onNotification(ReloadWindowNotification, () => util.promptForReloadWindowDueToSettingsChange()); + this.languageClient.onNotification(UpdateTrustedCompilersNotification, (e) => util.addTrustedCompiler(compilerPaths, e.compilerPath)); this.languageClient.onNotification(LogTelemetryNotification, logTelemetry); this.languageClient.onNotification(ReportStatusNotification, (e) => this.updateStatus(e)); this.languageClient.onNotification(ReportTagParseStatusNotification, (e) => this.updateTagParseStatus(e)); @@ -2032,8 +2177,8 @@ export class DefaultClient implements Client { const settings: OtherSettings = new OtherSettings(); const assocs: any = settings.filesAssociations; - const filesAndPaths: string[] = fileAssociations.split(";"); let foundNewAssociation: boolean = false; + const filesAndPaths: string[] = fileAssociations.split(";"); for (let i: number = 0; i < filesAndPaths.length; ++i) { const fileAndPath: string[] = filesAndPaths[i].split("@"); // Skip empty or malformed @@ -2299,6 +2444,13 @@ export class DefaultClient implements Client { return this.requestWhenReady(() => this.languageClient.sendRequest(SwitchHeaderSourceRequest, params)); } + public requestCompiler(compilerPath: string[]): Thenable { + const params: QueryDefaultCompilerParams = { + trustedCompilerPaths: compilerPath + }; + return this.languageClient.sendRequest(QueryCompilerDefaultsRequest, params); + } + private async updateActiveDocumentTextOptions(): Promise { const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; if (editor?.document?.uri.scheme === "file" @@ -2563,6 +2715,9 @@ export class DefaultClient implements Client { itemConfig.compilerPath, util.isArrayOfString(itemConfig.compilerArgs) ? itemConfig.compilerArgs : undefined); itemConfig.compilerPath = compilerPathAndArgs.compilerPath; + if (itemConfig.compilerPath !== undefined) { + util.addTrustedCompiler(compilerPaths, itemConfig.compilerPath); + } if (providerVersion < Version.v6) { itemConfig.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs; itemConfig.compilerArgs = undefined; @@ -2655,6 +2810,9 @@ export class DefaultClient implements Client { sanitized.compilerPath, util.isArrayOfString(sanitized.compilerArgs) ? sanitized.compilerArgs : undefined); sanitized.compilerPath = compilerPathAndArgs.compilerPath; + if (sanitized.compilerPath !== undefined) { + util.addTrustedCompiler(compilerPaths, sanitized.compilerPath); + } if (providerVersion < Version.v6) { sanitized.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs; sanitized.compilerArgs = undefined; @@ -3265,6 +3423,7 @@ class NullClient implements Client { activate(): void { } selectionChanged(selection: Range): void { } resetDatabase(): void { } + promptSelectCompiler(command: boolean): Promise { return Promise.resolve(); } deactivate(): void { } pauseParsing(): void { } resumeParsing(): void { } diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 1c30a9b09a..45ed7f782f 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -21,7 +21,7 @@ import { setTimeout } from 'timers'; import * as which from 'which'; import { Version, WorkspaceBrowseConfiguration } from 'vscode-cpptools'; import { getOutputChannelLogger } from '../logger'; - +import { compilerPaths } from './client'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -103,6 +103,8 @@ export interface Browse { export interface KnownCompiler { path: string; isC: boolean; + isTrusted: boolean; // May be used in the future for build tasks. + isCL: boolean; } export interface CompilerDefaults { @@ -115,6 +117,7 @@ export interface CompilerDefaults { frameworks: string[]; windowsSdkVersion: string; intelliSenseMode: string; + trustedCompilerFound: boolean; } export class CppProperties { @@ -157,6 +160,7 @@ export class CppProperties { // Any time the default settings are parsed and assigned to `this.configurationJson`, // we want to track when the default includes have been added to it. private configurationIncomplete: boolean = true; + trustedCompilerFound: boolean = false; constructor(rootUri?: vscode.Uri, workspaceFolder?: vscode.WorkspaceFolder) { this.rootUri = rootUri; @@ -206,18 +210,11 @@ export class CppProperties { return result; } - public set CompilerDefaults(compilerDefaults: CompilerDefaults) { - this.defaultCompilerPath = compilerDefaults.compilerPath; - this.knownCompilers = compilerDefaults.knownCompilers; - this.defaultCStandard = compilerDefaults.cStandard; - this.defaultCppStandard = compilerDefaults.cppStandard; - this.defaultIncludes = compilerDefaults.includes; - this.defaultFrameworks = compilerDefaults.frameworks; - this.defaultWindowsSdkVersion = compilerDefaults.windowsSdkVersion; - this.defaultIntelliSenseMode = compilerDefaults.intelliSenseMode; + public setupConfigurations(): void { // defaultPaths is only used when there isn't a c_cpp_properties.json, but we don't send the configuration changed event // to the language server until the default include paths and frameworks have been sent. + const configFilePath: string = path.join(this.configFolder, "c_cpp_properties.json"); if (this.rootUri !== null && fs.existsSync(configFilePath)) { this.propertiesFile = vscode.Uri.file(configFilePath); @@ -273,7 +270,7 @@ export class CppProperties { const savedDocWorkspaceFolder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(doc.uri); const notifyingWorkspaceFolder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(settingsPath)); if ((!savedDocWorkspaceFolder && vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0 && notifyingWorkspaceFolder === vscode.workspace.workspaceFolders[0]) - || savedDocWorkspaceFolder === notifyingWorkspaceFolder) { + || savedDocWorkspaceFolder === notifyingWorkspaceFolder) { let fileType: string | undefined; const documentPath: string = doc.uri.fsPath.toLowerCase(); if (documentPath.endsWith("cmakelists.txt")) { @@ -298,6 +295,17 @@ export class CppProperties { this.handleConfigurationChange(); } + public set CompilerDefaults(compilerDefaults: CompilerDefaults) { + this.defaultCompilerPath = compilerDefaults.compilerPath; + this.knownCompilers = compilerDefaults.knownCompilers; + this.defaultCStandard = compilerDefaults.cStandard; + this.defaultCppStandard = compilerDefaults.cppStandard; + this.defaultIncludes = compilerDefaults.includes; + this.defaultFrameworks = compilerDefaults.frameworks; + this.defaultWindowsSdkVersion = compilerDefaults.windowsSdkVersion; + this.defaultIntelliSenseMode = compilerDefaults.intelliSenseMode; + this.trustedCompilerFound = compilerDefaults.trustedCompilerFound; + } public get VcpkgInstalled(): boolean { return this.vcpkgIncludes.length > 0; @@ -857,7 +865,7 @@ export class CppProperties { configuration.compilerPath = this.updateConfigurationString(configuration.compilerPath, settings.defaultCompilerPath, env, true); configuration.compilerPathIsExplicit = configuration.compilerPathIsExplicit || settings.defaultCompilerPath !== undefined; if (configuration.compilerPath === undefined) { - if (!!this.defaultCompilerPath) { + if (!!this.defaultCompilerPath && this.trustedCompilerFound) { // If no config value yet set for these, pick up values from the defaults, but don't consider them explicit. configuration.compilerPath = this.defaultCompilerPath; if (!configuration.cStandard && !!this.defaultCStandard) { @@ -883,6 +891,9 @@ export class CppProperties { configuration.macFrameworkPath = this.defaultFrameworks; } } + } else { + // add compiler to list of trusted compilers + util.addTrustedCompiler(compilerPaths, configuration.compilerPath); } } else { // However, if compileCommands are used and compilerPath is explicitly set, it's still necessary to resolve variables in it. diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 560fe83800..95df484126 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -387,6 +387,7 @@ export function registerCommands(enabled: boolean): void { commandDisposables.length = 0; commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SwitchHeaderSource', enabled ? onSwitchHeaderSource : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResetDatabase', enabled ? onResetDatabase : onDisabledCommand)); + commandDisposables.push(vscode.commands.registerCommand('C_Cpp.selectDefaultCompiler', enabled ? selectDefaultCompiler : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationSelect', enabled ? onSelectConfiguration : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationProviderSelect', enabled ? onSelectConfigurationProvider : onDisabledCommand)); commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationEditJSON', enabled ? onEditConfigurationJSON : onDisabledCommand)); @@ -595,9 +596,13 @@ function onResetDatabase(): void { clients.ActiveClient.resetDatabase(); } +function selectDefaultCompiler(): void { + clients.ActiveClient.promptSelectCompiler(true); +} + function onSelectConfiguration(): void { if (!isFolderOpen()) { - vscode.window.showInformationMessage(localize("configuration.select.first", 'Open a folder first to select a configuration')); + vscode.window.showInformationMessage(localize("configuration.select.first", 'Open a folder first to select a configuration.')); } else { // This only applies to the active client. You cannot change the configuration for // a client that is not active since that client's UI will not be visible. @@ -607,7 +612,7 @@ function onSelectConfiguration(): void { function onSelectConfigurationProvider(): void { if (!isFolderOpen()) { - vscode.window.showInformationMessage(localize("configuration.provider.select.first", 'Open a folder first to select a configuration provider')); + vscode.window.showInformationMessage(localize("configuration.provider.select.first", 'Open a folder first to select a configuration provider.')); } else { selectClient().then(client => client.handleConfigurationProviderSelectCommand(), rejected => {}); } diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index d55fd186b6..4231df9f65 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -964,6 +964,9 @@ export class OtherSettings { public set filesAssociations(value: any) { vscode.workspace.getConfiguration("files").update("associations", value, vscode.ConfigurationTarget.Workspace); } + public set defaultCompiler(value: string) { + vscode.workspace.getConfiguration("C_Cpp.default").update("compilerPath", value, vscode.ConfigurationTarget.Global); + } public get filesExclude(): vscode.WorkspaceConfiguration | undefined { return vscode.workspace.getConfiguration("files", this.resource).get("exclude"); } public get filesAutoSaveAfterDelay(): boolean { return vscode.workspace.getConfiguration("files").get("autoSave") === "afterDelay"; } public get editorInlayHintsEnabled(): boolean { return vscode.workspace.getConfiguration("editor.inlayHints").get("enabled") !== "off"; } diff --git a/Extension/src/common.ts b/Extension/src/common.ts index 6886bb5dc1..24dcc997ed 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -874,17 +874,25 @@ export async function renameAsync(oldName: string, newName: string): Promise { + await promptReloadWindow(localize("reload.workspace.for.changes", "Reload the workspace for the settings change to take effect.")); } -export function promptReloadWindow(message: string): void { +export async function promptReloadWindow(message: string): Promise { const reload: string = localize("reload.string", "Reload"); - vscode.window.showInformationMessage(message, reload).then((value?: string) => { - if (value === reload) { - vscode.commands.executeCommand("workbench.action.reloadWindow"); - } - }); + const value: string | undefined = await vscode.window.showInformationMessage(message, reload); + if (value === reload) { + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } +} + +export async function addTrustedCompiler(compilers: string[], path: string): Promise { + // Detect duplicate paths or invalid paths. + if (compilers.includes(path) || path === null || path === undefined) { + return compilers; + } + compilers.push(path); + return compilers; } export function createTempFileWithPostfix(postfix: string): Promise { diff --git a/Extension/src/nativeStrings.json b/Extension/src/nativeStrings.json index b9d7abebfe..4d496b3e09 100644 --- a/Extension/src/nativeStrings.json +++ b/Extension/src/nativeStrings.json @@ -177,6 +177,9 @@ "text": "+%d specializations", "hint": "Refers to C++ template specializations. This is part of a description indicating there are N additional specializations of a function. %d is replaced with that number." }, + "compiler": { + "text": "Note: IntelliSense is not fully configured. Use the 'Select Default Compiler' command to finish configuration." + }, "expands_to": "Expands to:", "attention_label": "Attention:", "author_label": "Author:", From 3adcec81a495861e105a296d494aae76b0f2493f Mon Sep 17 00:00:00 2001 From: Michelle Matias <38734287+michelleangela@users.noreply.github.com> Date: Wed, 25 Jan 2023 12:53:44 -0800 Subject: [PATCH 08/17] edge strings (#10416) --- Extension/bin/messages/cs/messages.json | 9 +++++---- Extension/bin/messages/de/messages.json | 9 +++++---- Extension/bin/messages/fr/messages.json | 9 +++++---- Extension/bin/messages/it/messages.json | 9 +++++---- Extension/bin/messages/ko/messages.json | 9 +++++---- Extension/bin/messages/pl/messages.json | 7 ++++--- Extension/bin/messages/pt-br/messages.json | 9 +++++---- Extension/bin/messages/ru/messages.json | 9 +++++---- Extension/bin/messages/zh-cn/messages.json | 9 +++++---- Extension/bin/messages/zh-tw/messages.json | 9 +++++---- 10 files changed, 49 insertions(+), 39 deletions(-) diff --git a/Extension/bin/messages/cs/messages.json b/Extension/bin/messages/cs/messages.json index e0fed86433..441db346ec 100644 --- a/Extension/bin/messages/cs/messages.json +++ b/Extension/bin/messages/cs/messages.json @@ -2935,7 +2935,7 @@ "Neplatný typ %t pro this-pointer členské funkce %nfd s omezením AMP", "Neplatný návratový typ %t pro funkci %nfd s omezením AMP", "Neplatný typ parametru %t pro funkci %nfd s omezením AMP", - null, + "Neplatný konstruktor ve funkci %nfd s omezením AMP", "Neplatná třída úložiště %s ve funkci %nfd s omezením AMP", "%s není ve funkci %nfd s omezením AMP povolené.", "Neplatné přetypování ve funkci s omezením AMP", @@ -3465,7 +3465,7 @@ "kvůli atributu „není k dispozici“", "duplicitní kvalifikátor asm", "bitové pole s nekompletním typem výčtu nebo neprůhledný výčet s neplatným základním typem", - "došlo k pokusu o vytvoření elementu z oddílu IFC %sq pomocí indexu do oddílu IFC %sq.", + "došlo k pokusu o vytvoření elementu z oddílu IFC %sq pomocí indexu do oddílu IFC %sq2.", "oddíl %sq určil svou velikost položky jako %d1, když bylo očekáváno %d2.", "při zpracování modulu %sq1 byl zjištěn neočekávaný požadavek IFC.", "podmínka selhala na řádku %d v %s1: %sq2", @@ -3478,9 +3478,10 @@ "neplatná hodnota řazení modulu %sq", "šablona funkce načtená z modulu IFC byla nesprávně parsována jako %nd.", "nepovedlo se načíst odkaz na entitu IFC v modulu %sq.", - "Řazení indexu IFC = %d1, hodnota = %d2", + "Z oddílu %sq, elementu %d1 (pozice v souboru %d2, relativní pozice %d3)", "zřetězené specifikátory nejsou povolené pro typ třídy s netriviálním destruktorem.", "Explicitní deklarace specializace nemůže být deklarací typu friend.", "typ std::float128_t se nepodporuje. místo toho se použije std::float64_t", - "typ std::bfloat16_t se nepodporuje. místo toho se použije std::float32_t" + "typ std::bfloat16_t se nepodporuje. místo toho se použije std::float32_t", + "vodítko pro dedukce se nedá deklarovat pro šablonu aliasu %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/de/messages.json b/Extension/bin/messages/de/messages.json index da9454c2f6..975c6d60ae 100644 --- a/Extension/bin/messages/de/messages.json +++ b/Extension/bin/messages/de/messages.json @@ -2935,7 +2935,7 @@ "Unzulässiger Typ %t im this-Zeiger für die eingeschränkte amp-Memberfunktion %nfd", "Unzulässiger Rückgabetyp \"%t\" für die auf AMP begrenzte Funktion \"%nfd\".", "Unzulässiger Parametertyp \"%t\" für die auf AMP begrenzte Funktion \"%nfd\".", - null, + "Unzulässiges Konstrukt in auf AMP begrenzter Funktion %nfd", "Unzulässige Speicherklasse \"%s\" in der auf AMP begrenzten Funktion \"%nfd\".", "\"%s\" ist in der auf AMP begrenzten Funktion \"%nfd\" unzulässig.", "Unzulässige Umwandlung in auf AMP begrenzte Funktion.", @@ -3465,7 +3465,7 @@ "aufgrund eines „nicht verfügbaren“ Attributs", "Doppelter „ASM“-Qualifizierer", "entweder ein Bitfeld mit einem unvollständigen Enumerationstyp oder eine opake Enumeration mit einem ungültigen Basistyp", - "Es wurde versucht, ein Element aus der IFC-Partition %sq mithilfe eines Indexes in der IFC-Partition %sq zu erstellen", + "Es wurde versucht, ein Element aus der IFC-Partition %sq mithilfe eines Indexes in der IFC-Partition %sq2 zu erstellen", "Die Partition %sq hat ihre Eintragsgröße mit %d1 angegeben, obwohl %d2 erwartet wurde", "Unerwartete IFC-Anforderung beim Verarbeiten des Moduls %sq1", "Bedingungsfehler in Zeile %d in %s1: %sq2", @@ -3478,9 +3478,10 @@ "Modul %sq ungültiger Sortierwert", "Eine aus einem IFC-Modul geladene Funktionsvorlage wurde fälschlicherweise als %nd analysiert", "Fehler beim Laden eines IFC-Entitätsverweises im Modul \"%sq\"", - "IFC-Indexsortierung = %d1, Wert = %d2", + "von Partition %sq Element %d1 (Dateiposition %d2, relative Position %d3)", "verkettete Kennzeichner sind für einen Klassentyp mit einem nichttrivialen Destruktor nicht zulässig", "Eine explizite Spezialisierungsdeklaration darf keine Frienddeklaration sein", "der Typ „std::float128_t“ wird nicht unterstützt. Stattdessen wird „std::float64_t“ verwendet", - "der Typ „std::bfloat16_t“ wird nicht unterstützt. Stattdessen wird „std::float32_t“ verwendet" + "der Typ „std::bfloat16_t“ wird nicht unterstützt. Stattdessen wird „std::float32_t“ verwendet", + "Für die Aliasvorlage %no darf keine Deduktionsanleitung deklariert werden." ] \ No newline at end of file diff --git a/Extension/bin/messages/fr/messages.json b/Extension/bin/messages/fr/messages.json index 9485d0f09e..5c604df66e 100644 --- a/Extension/bin/messages/fr/messages.json +++ b/Extension/bin/messages/fr/messages.json @@ -2935,7 +2935,7 @@ "type interdit %t dans ce pointeur pour la fonction membre %nfd restreinte à amp", "type de retour interdit %t pour la fonction à restriction amp %nfd", "type de paramètre interdit %t pour la fonction à restriction amp %nfd", - null, + "construction non conforme dans la fonction à restriction amp %nfd", "classe de stockage interdite %s dans la fonction à restriction amp %nfd", "%s non autorisé dans la fonction à restriction amp %nfd", "cast non conforme dans la fonction à restriction amp", @@ -3465,7 +3465,7 @@ "en raison d’un attribut 'unavailable'", "qualificateur 'asm' dupliqué", "soit un champ de bits avec un type enum incomplet, soit une énumération opaque avec un type de base non valide", - "a tenté de construire un élément à partir d’une partition IFC %sq à l’aide d’un index dans la partition IFC %sq.", + "a tenté de construire un élément à partir d’une partition IFC %sq à l’aide d’un index dans la partition IFC %sq2.", "le %sq de partition a spécifié sa taille d’entrée %d1 alors que %d2 était attendu.", "une exigence IFC inattendue s’est produite lors du traitement du module %sq1.", "échec de la condition à la ligne %d dans %s1 : %sq2", @@ -3478,9 +3478,10 @@ "le module %sq valeur de tri non valide", "un modèle de fonction chargé à partir d’un module IFC a été analysé de manière incorrecte en tant que %nd", "échec du chargement d’une référence d’entité IFC dans le module %sq", - "Tri d’index IFC = %d1, valeur = %d2", + "à partir de la partition %sq, élément %d1 (position de fichier %d2, position relative %d3)", "les désignateurs chaînés ne sont pas autorisés pour un type classe avec un destructeur non trivial", "une déclaration de spécialisation explicite ne peut pas être une déclaration friend", "le type std::float128_t n’est pas pris en charge ; std::float64_t sera utilisé à la place", - "le type std::bfloat16_t n’est pas pris en charge ; std::float32_t sera utilisé à la place" + "le type std::bfloat16_t n’est pas pris en charge ; std::float32_t sera utilisé à la place", + "un guide de déduction ne peut pas être déclaré pour le modèle d’alias %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/it/messages.json b/Extension/bin/messages/it/messages.json index 3f8970295e..47e2a8e419 100644 --- a/Extension/bin/messages/it/messages.json +++ b/Extension/bin/messages/it/messages.json @@ -2935,7 +2935,7 @@ "il tipo %t nel puntatore this per la funzione membro con limitazioni amp %nfd non è valido", "il tipo restituito %t per la funzione con restrizioni AMP %nfd non è valido", "il tipo di parametro %t per la funzione con restrizioni AMP %nfd non è valido", - null, + "il costrutto nella funzione con restrizioni AMP %nfd non è valido", "la classe di archiviazione %s nella funzione con restrizioni AMP %nfd non è valida", "%s non è consentito nella funzione con restrizioni AMP %nfd", "il cast nella funzione con restrizioni AMP non è valido", @@ -3465,7 +3465,7 @@ "a causa di un attributo 'non disponibile'", "qualificatore 'asm' duplicato", "o un campo di bit con un tipo di enumerazione incompleto o un'enumerazione opaca con un tipo di base non valido", - "ha tentato di costruire un elemento dalla partizione IFC %sq utilizzando un indice nella partizione IFC %sq", + "ha tentato di costruire un elemento dalla partizione IFC %sq utilizzando un indice nella partizione IFC %sq2", "la partizione %sq ha specificato la dimensione della voce come %d1 mentre era previsto %d2", "Durante l'elaborazione del modulo %sq1 è stato riscontrato un requisito IFC imprevisto.", "condizione fallita alla riga %d in %s1: %sq2", @@ -3478,9 +3478,10 @@ "il modulo %sq valore di ordinamento non valido", "un modello di funzione caricato da un modulo IFC è stato analizzato erroneamente come %nd", "non è stato possibile caricare un riferimento all'entità IFC nel modulo %sq", - "Ordinamento indice IFC = %d1, valore = %d2", + "dalla partizione %sq elemento %d1 (posizione file %d2, posizione relativa %d3)", "gli indicatori concatenati non sono consentiti per un tipo di classe con un distruttore non banale", "una dichiarazione di specializzazione esplicita non può essere una dichiarazione Friend", "il tipo std::float128_t non è supportato; verrà invece usato std::float64_t", - "il tipo std::bfloat16_t non è supportato; verrà utilizzato std::float32_t" + "il tipo std::bfloat16_t non è supportato; verrà utilizzato std::float32_t", + "non è possibile dichiarare una guida alla deduzione per il modello di alias %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/ko/messages.json b/Extension/bin/messages/ko/messages.json index fe64f06e1a..eb2da69acb 100644 --- a/Extension/bin/messages/ko/messages.json +++ b/Extension/bin/messages/ko/messages.json @@ -2935,7 +2935,7 @@ "amp 제한 멤버 함수 %nfd에 대한 this 포인터의 %t 형식이 잘못되었습니다.", "amp 제한 함수 %nfd의 반환 형식 %t이(가) 잘못되었습니다.", "amp 제한 함수 %nfd의 매개 변수 형식 %t이(가) 잘못되었습니다.", - null, + "amp 제한 함수 %nfd의 구문이 잘못되었습니다.", "잘못된 스토리지 클래스 %s(amp 제한 함수 %nfd 내)", "%s은(는) amp 제한 함수 %nfd에서 사용할 수 없습니다.", "amp 제한 함수의 캐스트가 잘못되었습니다.", @@ -3465,7 +3465,7 @@ "'unavailable' 특성 때문에", "중복된 'asm' 한정자", "불완전한 열거형 형식이 있는 비트 필드 또는 잘못된 기본 형식이 있는 불투명 열거형", - "IFC 파티션 %sq에 대한 인덱스를 사용하여 IFC 파티션 %sq에서 요소를 구성하려고 했습니다.", + "IFC 파티션 %sq2에 대한 인덱스를 사용하여 IFC 파티션 %sq에서 요소를 구성하려고 했습니다.", "파티션 %sq는 %d2가 예상될 때 항목 크기를 %d1로 지정했습니다.", "모듈 %sq1을(를) 처리하는 동안 예기치 않은 IFC 요구 사항이 발생했습니다.", "%d행(%s1)에서 조건 실패: %sq2", @@ -3478,9 +3478,10 @@ "모듈 %sq 잘못된 정렬 값", "IFC 모듈에서 로드된 함수 템플릿이 %nd(으)로 잘못 구문 분석되었습니다.", "모듈 %sq에서 IFC 엔터티 참조를 로드하지 못했습니다.", - "IFC 인덱스 정렬 = %d1, 값 = %d2", + "파티션 %sq 요소 %d1(파일 위치 %d2, 상대 위치 %d3)에서", "비자명 소멸자가 있는 클래스 형식에는 연결된 지정자를 사용할 수 없습니다.", "명시적 전문화 선언은 friend 선언이 아닐 수 있습니다.", "std::float128_t 형식은 지원되지 않습니다. std::float64_t이(가) 대신 사용됩니다.", - "std::bfloat16_t 형식은 지원되지 않습니다. std::float32_t이(가) 대신 사용됩니다." + "std::bfloat16_t 형식은 지원되지 않습니다. std::float32_t이(가) 대신 사용됩니다.", + "별칭 템플릿 %no에 대해 추론 가이드를 선언할 수 없습니다." ] \ No newline at end of file diff --git a/Extension/bin/messages/pl/messages.json b/Extension/bin/messages/pl/messages.json index 5ac00ab62f..67d387b8c2 100644 --- a/Extension/bin/messages/pl/messages.json +++ b/Extension/bin/messages/pl/messages.json @@ -2935,7 +2935,7 @@ "niedozwolony typ %t we wskaźniku this dla funkcji składowej ograniczonej przez amp %nfd", "niedozwolony zwracany typ %t dla funkcji z ograniczeniem amp %nfd", "niedozwolony typ parametru %t dla funkcji z ograniczeniem amp %nfd", - null, + "niedozwolona konstrukcja w funkcji z ograniczeniami amp %nfd", "niedozwolona klasa magazynu %s w funkcji z ograniczeniem amp %nfd", "element %s nie jest dozwolony w funkcji z ograniczeniem amp %nfd", "niedozwolone rzutowanie w funkcji z ograniczeniem amp", @@ -3478,9 +3478,10 @@ "nieprawidłowa wartość sortowania modułu %sq", "szablon funkcji załadowany z modułu IFC został niepoprawnie przeanalizowany jako %nd", "nie można załadować odwołania do jednostki IFC w module %sq", - "Sortowanie indeksu IFC = %d1, wartość = %d2", + "z partycji %sq element %d1 (pozycja pliku %d2, względna pozycja %d3)", "desygnator łańcuchowy nie jest dozwolony dla typu klasy z destruktorem nietrywialnym", "jawna deklaracja specjalizacji nie może być deklaracją zaprzyjaźnioną", "typ std::float128_t nie jest obsługiwany; zamiast tego zostanie użyty std::float64_t", - "Typ std::bfloat16_t nie jest obsługiwany; zamiast tego zostanie użyty std::float32_t" + "Typ std::bfloat16_t nie jest obsługiwany; zamiast tego zostanie użyty std::float32_t", + "nie można zadeklarować przewodnika wnioskowania dla szablonu aliasu %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/pt-br/messages.json b/Extension/bin/messages/pt-br/messages.json index 77d5f02f6b..dca16848b4 100644 --- a/Extension/bin/messages/pt-br/messages.json +++ b/Extension/bin/messages/pt-br/messages.json @@ -2935,7 +2935,7 @@ "tipo ilegal %t neste ponteiro para a função membro restrita por amp %nfd", "tipo de retorno %t ilícito para a função restrita por amp %nfd", "tipo de parâmetro %t ilícito para a função restrita por amp %nfd", - null, + "constructo ilícito na função restrita por amp %nfd", "classe de armazenamento %s ilícito na função restrita por amp %nfd", "%s não é permitido na função restrita por amp %nfd", "conversão ilícita na função restrita por amp", @@ -3465,7 +3465,7 @@ "devido a um atributo 'indisponível'", "qualificador 'asm' duplicado", "um campo de bits com um tipo de enumeração incompleto ou uma enumeração opaca com um tipo base inválido", - "tentou construir um elemento da partição IFC %sq usando um índice na partição IFC %sq", + "tentou construir um elemento da partição IFC %sq usando um índice na partição IFC %sq2", "a partição %sq especificou seu tamanho de entrada como %d1 quando %d2 era esperado", "um requisito IFC inesperado foi encontrado durante o processamento do módulo %sq1", "condição falhou na linha %d em %s1: %sq2", @@ -3478,9 +3478,10 @@ "valor de classificação inválido do módulo %sq", "um modelo de função carregado de um módulo IFC foi analisado incorretamente como %nd", "falha ao carregar uma referência de entidade IFC no módulo %sq", - "Classificação do índice IFC = %d1, valor = %d2", + "da partição %sq elemento %d1 (posição do arquivo %d2, posição relativa %d3)", "designadores encadeados não são permitidos para um tipo de classe com um destruidor não trivial", "uma declaração de especialização explícita não pode ser uma declaração de friend", "o tipo std::float128_t não tem suporte; em vez disso, std::float64_t será usado", - "o tipo std::bfloat16_t não tem suporte; em vez disso, std::float32_t será usado" + "o tipo std::bfloat16_t não tem suporte; em vez disso, std::float32_t será usado", + "um guia de dedução não pode ser declarado para o modelo de alias %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/ru/messages.json b/Extension/bin/messages/ru/messages.json index 56163596f1..52934240f3 100644 --- a/Extension/bin/messages/ru/messages.json +++ b/Extension/bin/messages/ru/messages.json @@ -2935,7 +2935,7 @@ "недопустимый тип %t в указателе this для функции-члена %nfd с описателем ограничения amp", "Недопустимый тип возвращаемого значения %t для функции %nfd со спецификатором ограничения amp.", "Недопустимый тип параметра %t для функции %nfd со спецификатором ограничения amp.", - null, + "Недопустимая метка в функции %nfd со спецификатором ограничения amp.", "Недопустимый класс хранения %s в функции %nfd со спецификатором ограничения amp.", "Недопустимо использовать %s в функции %nfd со спецификатором ограничения amp.", "Недопустимое приведение в функции со спецификатором ограничения amp.", @@ -3465,7 +3465,7 @@ "из-за атрибута \"unavailable\"", "дубликат квалификатора \"asm\"", "битовые поля с неполным типом или непрозрачное перечисление с недопустимым базовым типом", - "попытка создать элемент из раздела IFC %sq с использованием индекса в разделе IFC %sq", + "попытка создать элемент из раздела IFC %sq с использованием индекса в разделе IFC %sq2", "раздел %sq указал размер своей записи как %d1, в то время как ожидалось %d2", "При обработке модуля %sq1 было обнаружено неожиданное требование IFC", "сбой условия в строке %d в %s1: %sq2", @@ -3478,9 +3478,10 @@ "недопустимое значение сортировки модуля %sq", "шаблон функции, загруженный из модуля IFC, был неправильно проанализирован как %nd", "не удалось загрузить ссылку на объект IFC в модуль %sq", - "Сортировка индекса IFC = %d1, значение = %d2", + "из раздела %sq, элемент %d1 (позиция файла %d2, относительная позиция %d3)", "цепные обозначения не разрешены для типа класса с нетривиальным деструктором", "явное объявление специализации не может быть объявлением дружественной функции", "тип std::float128_t не поддерживается; вместо этого будет использоваться std::float64_t", - "тип std::bfloat16_t не поддерживается; вместо этого будет использоваться std::float32_t" + "тип std::bfloat16_t не поддерживается; вместо этого будет использоваться std::float32_t", + "руководство по дедукции не может быть объявлено для шаблона псевдонима %no" ] \ No newline at end of file diff --git a/Extension/bin/messages/zh-cn/messages.json b/Extension/bin/messages/zh-cn/messages.json index 987c36c268..87de6fc271 100644 --- a/Extension/bin/messages/zh-cn/messages.json +++ b/Extension/bin/messages/zh-cn/messages.json @@ -2935,7 +2935,7 @@ "this-pointer 中的类型 %t 对于 amp 限制的成员函数 %nfd 是非法的", "返回类型 %t 对于受 AMP 限制的函数 %nfd 是非法的", "参数类型 %t 对于受 AMP 限制的函数 %nfd 是非法的", - null, + "受 AMP 限制的函数 %nfd 中的非法构造", "存储类 %s 在受 AMP 限制的函数 %nfd 中是非法的", "%s 不可在受 AMP 限制的函数 %nfd 中使用", "受 AMP 限制的函数中的强制转换非法", @@ -3465,7 +3465,7 @@ "因为“不可用”属性", "重复的 \"asm\" 限定符", "具有不完整枚举类型的位字段或具有无效基类型的不透明枚举", - "已尝试使用索引将一个元素从 IFC 分区 %sq 构造到 IFC 分区 %sq", + "已尝试使用索引将一个元素从 IFC 分区 %sq 构造到 IFC 分区 %sq2", "分区 %sq 将其条目大小指定为 %d1,正确的大小为 %d2", "处理模块 %sq1 时遇到意外的 IFC 要求", "条件失败,行 %d,%s1: %sq2", @@ -3478,9 +3478,10 @@ "模块 %sq 排序值无效", "从 IFC 模块加载的函数模板被错误地分析为 %nd", "未能在模块 %sq 中加载 IFC 实体引用", - "IFC 索引排序 = %d1,值 = %d2", + "从分区 %sq 元素 %d1 (文件位置 %d2,相对位置 %d3)", "对于具有非平凡析构函数的类的类型,不允许使用链式指示符", "显式专用化声明不能是友元声明", "不支持 std::float128_t 类型; 将改用 std::float64_t", - "不支持 std::bfloat16_t 类型; 将改用 std::float32_t" + "不支持 std::bfloat16_t 类型; 将改用 std::float32_t", + "不能为别名模板 %no 声明推导指南" ] \ No newline at end of file diff --git a/Extension/bin/messages/zh-tw/messages.json b/Extension/bin/messages/zh-tw/messages.json index 1688ba832e..50d356524e 100644 --- a/Extension/bin/messages/zh-tw/messages.json +++ b/Extension/bin/messages/zh-tw/messages.json @@ -2935,7 +2935,7 @@ "類型 %t 在 amp 限定成員函式 %nfd 的 this 指標中不合法", "傳回型別 %t 在 AMP 限制涵式 %nfd 中不合法", "參數類型 %t 在 AMP 限制涵式 %nfd 中不合法", - null, + "AMP 限制涵式 %nfd 中有不合法的建構", "儲存類別 %s 在 AMP 限制涵式 %nfd 中不合法", "%s 不得出現在 AMP 限制涵式 %nfd 中", "AMP 限制涵式中有不合法的轉換", @@ -3465,7 +3465,7 @@ "因為 'unavailable' 屬性", "重复的 'asm' 限定詞", "具有不完整列舉類型的位欄位,或具有無效基底類型的不透明列舉", - "已嘗試使用索引從 IFC 磁碟分割 %sq 將元素建構到 IFC 磁碟分割 %sq", + "已嘗試使用索引從 IFC 磁碟分割 %sq2 將元素建構到 IFC 磁碟分割 %sq", "磁碟分割 %sq 在需要 %d2 時將其項目大小指定為 %d1", "處理模組 %sq1 時發現未預期的 IFC 需求", "第 %d 行 (在 %s1 中) 條件失敗: %sq2", @@ -3478,9 +3478,10 @@ "模組 %sq 無效排序值", "從 IFC 模組載入的函數範本不正確地剖析為 %nd", "無法在模組 %sq 中載入 IFC 實體參考", - "IFC 索引排序 = %d1,值 = %d2", + "從分割區 %sq 元素 %d1 (檔案位置 %d2,相對位置 %d3)", "具有非屬性解構函數的類別類型不允許連結指定元", "明確的特殊化宣告不能是 friend 宣告", "不支援 std::float128_t 類型,將改用 std::float64_t", - "不支援 std::bfloat16_t 類型,將改用 std::float32_t" + "不支援 std::bfloat16_t 類型,將改用 std::float32_t", + "別名範本不可宣告扣除指南 %no" ] \ No newline at end of file From dc0a7af0aab4cf5a860709b245c061aff7fb3a9d Mon Sep 17 00:00:00 2001 From: browntarik <111317156+browntarik@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:30:41 -0800 Subject: [PATCH 09/17] resolve compiler undefined message (#10418) --- Extension/src/LanguageServer/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 8886d44c34..b517a8761e 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -967,7 +967,7 @@ export class DefaultClient implements Client { const confirmCompiler: string = localize("confirmCompiler.string", "Yes"); const settings: OtherSettings = new OtherSettings(); if (compilerDefaults.compilerPath !== "") { - if (!command) { + if (!command && (compilerDefaults.compilerPath !== undefined)) { const value: string | undefined = await vscode.window.showInformationMessage(localize("selectCompiler.message", "The compiler {0} was found on this computer. Do you want to configure it for IntelliSense?", compilerDefaults.compilerPath), confirmCompiler, selectCompiler); if (value === confirmCompiler) { compilerPaths = await util.addTrustedCompiler(compilerPaths, compilerDefaults.compilerPath); From 98a9b0cabeff66af6c60dc603895a937c7dd07db Mon Sep 17 00:00:00 2001 From: browntarik <111317156+browntarik@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:51:28 -0800 Subject: [PATCH 10/17] add ChangeCppPropertiesRequest and remove Notification. (#10420) --- Extension/src/LanguageServer/client.ts | 6 +++--- Extension/src/LanguageServer/configurations.ts | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index b517a8761e..b47f32b423 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -541,6 +541,7 @@ export const FormatOnTypeRequest: RequestType = const CreateDeclarationOrDefinitionRequest: RequestType = new RequestType('cpptools/createDeclDef'); const GoToDirectiveInGroupRequest: RequestType = new RequestType('cpptools/goToDirectiveInGroup'); const GenerateDoxygenCommentRequest: RequestType = new RequestType('cpptools/generateDoxygenComment'); +const ChangeCppPropertiesRequest: RequestType = new RequestType('cpptools/didChangeCppProperties'); // Notifications to the server const DidOpenNotification: NotificationType = new NotificationType('textDocument/didOpen'); @@ -553,7 +554,6 @@ const ResumeParsingNotification: NotificationType = new NotificationType = new NotificationType('cpptools/activeDocumentChange'); const RestartIntelliSenseForFileNotification: NotificationType = new NotificationType('cpptools/restartIntelliSenseForFile'); const TextEditorSelectionChangeNotification: NotificationType = new NotificationType('cpptools/textEditorSelectionChange'); -const ChangeCppPropertiesNotification: NotificationType = new NotificationType('cpptools/didChangeCppProperties'); const ChangeCompileCommandsNotification: NotificationType = new NotificationType('cpptools/didChangeCompileCommands'); const ChangeSelectedSettingNotification: NotificationType = new NotificationType('cpptools/didChangeSelectedSetting'); const IntervalTimerNotification: NotificationType = new NotificationType('cpptools/onIntervalTimer'); @@ -2584,7 +2584,7 @@ export class DefaultClient implements Client { private doneInitialCustomBrowseConfigurationCheck: boolean = false; - private onConfigurationsChanged(cppProperties: configs.CppProperties): void { + private async onConfigurationsChanged(cppProperties: configs.CppProperties): Promise { if (!cppProperties.Configurations) { return; } @@ -2614,7 +2614,7 @@ export class DefaultClient implements Client { params.configurations.push(modifiedConfig); }); - this.languageClient.sendNotification(ChangeCppPropertiesNotification, params); + await this.languageClient.sendRequest(ChangeCppPropertiesRequest, params); const lastCustomBrowseConfigurationProviderId: PersistentFolderState | undefined = cppProperties.LastCustomBrowseConfigurationProviderId; const lastCustomBrowseConfigurationProviderVersion: PersistentFolderState | undefined = cppProperties.LastCustomBrowseConfigurationProviderVersion; const lastCustomBrowseConfiguration: PersistentFolderState | undefined = cppProperties.LastCustomBrowseConfiguration; diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 45ed7f782f..e778cbd545 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -893,7 +893,9 @@ export class CppProperties { } } else { // add compiler to list of trusted compilers - util.addTrustedCompiler(compilerPaths, configuration.compilerPath); + if (i === this.CurrentConfigurationIndex) { + util.addTrustedCompiler(compilerPaths, configuration.compilerPath); + } } } else { // However, if compileCommands are used and compilerPath is explicitly set, it's still necessary to resolve variables in it. From 2605cac2a93e3fb54763e3a4f4ee5d0f84ca6035 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:01:12 -0800 Subject: [PATCH 11/17] Address issues with request cancelation (#10296) --- .../Providers/codeActionProvider.ts | 251 +++++++++--------- .../documentFormattingEditProvider.ts | 8 +- .../documentRangeFormattingEditProvider.ts | 8 +- .../Providers/documentSymbolProvider.ts | 20 +- .../Providers/foldingRangeProvider.ts | 8 +- .../Providers/inlayHintProvider.ts | 20 +- .../Providers/onTypeFormattingEditProvider.ts | 8 +- .../Providers/semanticTokensProvider.ts | 34 +-- .../Providers/workspaceSymbolProvider.ts | 3 + Extension/src/LanguageServer/client.ts | 21 +- 10 files changed, 201 insertions(+), 180 deletions(-) diff --git a/Extension/src/LanguageServer/Providers/codeActionProvider.ts b/Extension/src/LanguageServer/Providers/codeActionProvider.ts index dabfd81bc2..c6990403ff 100644 --- a/Extension/src/LanguageServer/Providers/codeActionProvider.ts +++ b/Extension/src/LanguageServer/Providers/codeActionProvider.ts @@ -24,8 +24,12 @@ interface CodeActionCommand { uri?: string; } -export const GetCodeActionsRequest: RequestType = - new RequestType('cpptools/getCodeActions'); +interface GetCodeActionsResult { + commands: CodeActionCommand[]; +} + +export const GetCodeActionsRequest: RequestType = + new RequestType('cpptools/getCodeActions'); export class CodeActionProvider implements vscode.CodeActionProvider { private client: DefaultClient; @@ -35,145 +39,148 @@ 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)[]> { - return this.client.requestWhenReady(async () => { - let r: Range; - if (range instanceof vscode.Selection) { - if (range.active.isBefore(range.anchor)) { - r = Range.create(Position.create(range.active.line, range.active.character), - Position.create(range.anchor.line, range.anchor.character)); - } else { - r = Range.create(Position.create(range.anchor.line, range.anchor.character), - Position.create(range.active.line, range.active.character)); - } + await this.client.awaitUntilLanguageClientReady(); + let r: Range; + if (range instanceof vscode.Selection) { + if (range.active.isBefore(range.anchor)) { + r = Range.create(Position.create(range.active.line, range.active.character), + Position.create(range.anchor.line, range.anchor.character)); } else { - r = Range.create(Position.create(range.start.line, range.start.character), - Position.create(range.end.line, range.end.character)); + r = Range.create(Position.create(range.anchor.line, range.anchor.character), + Position.create(range.active.line, range.active.character)); } + } else { + r = Range.create(Position.create(range.start.line, range.start.character), + Position.create(range.end.line, range.end.character)); + } - const params: GetCodeActionsRequestParams = { - range: r, - uri: document.uri.toString() - }; + const params: GetCodeActionsRequestParams = { + range: r, + uri: document.uri.toString() + }; - const commands: CodeActionCommand[] = await this.client.languageClient.sendRequest( - GetCodeActionsRequest, params, token); - const resultCodeActions: vscode.CodeAction[] = []; + const response: GetCodeActionsResult = await this.client.languageClient.sendRequest( + GetCodeActionsRequest, params, token); - // Convert to vscode.CodeAction array - commands.forEach((command) => { - const title: string = getLocalizedString(command.localizeStringParams); - let wsEdit: vscode.WorkspaceEdit | undefined; - let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix; - if (command.edit) { - // Inline macro feature. - codeActionKind = vscode.CodeActionKind.RefactorInline; - wsEdit = new vscode.WorkspaceEdit(); - wsEdit.replace(document.uri, makeVscodeRange(command.edit.range), command.edit.newText); - } else if (command.command === "C_Cpp.RemoveAllCodeAnalysisProblems" && command.uri !== undefined) { - // The "RemoveAll" message is sent for all code analysis squiggles. - const vsCodeRange: vscode.Range = makeVscodeRange(r); - const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(command.uri); - if (codeActionDiagnosticInfo === undefined) { - return; - } - const fixCodeActions: vscode.CodeAction[] = []; - const disableCodeActions: vscode.CodeAction[] = []; - const removeCodeActions: vscode.CodeAction[] = []; - const docCodeActions: vscode.CodeAction[] = []; - const showClear: string = new CppSettings().clangTidyCodeActionShowClear; + const resultCodeActions: vscode.CodeAction[] = []; + if (token.isCancellationRequested || response.commands === undefined) { + throw new vscode.CancellationError(); + } - // Check which code actions to show. This can get called a lot - // (after every cursor change) so all the checks should be relatively fast. - for (const codeAction of codeActionDiagnosticInfo) { - if (!codeAction.range.contains(vsCodeRange)) { - continue; - } - let codeActionCodeInfo: CodeActionCodeInfo | undefined; - if (codeAnalysisCodeToFixes.has(codeAction.code)) { - codeActionCodeInfo = codeAnalysisCodeToFixes.get(codeAction.code); - } - if (codeAction.fixCodeAction !== undefined) { - // Potentially we could make the "fix all" or "fix all type" preferred instead. - codeAction.fixCodeAction.isPreferred = true; - fixCodeActions.push(codeAction.fixCodeAction); - if (codeActionCodeInfo !== undefined) { - if (codeActionCodeInfo.fixAllTypeCodeAction !== undefined && - (codeActionCodeInfo.uriToInfo.size > 1 || - codeActionCodeInfo.uriToInfo.values().next().value.numValidWorkspaceEdits > 1)) { - // Only show the "fix all type" if there is more than one fix for the type. - fixCodeActions.push(codeActionCodeInfo.fixAllTypeCodeAction); - } - } - } - if (codeAction.removeCodeAction === undefined) { - continue; - } - let removeAllTypeAvailable: boolean = false; + // Convert to vscode.CodeAction array + response.commands.forEach((command) => { + const title: string = getLocalizedString(command.localizeStringParams); + let wsEdit: vscode.WorkspaceEdit | undefined; + let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix; + if (command.edit) { + // Inline macro feature. + codeActionKind = vscode.CodeActionKind.RefactorInline; + wsEdit = new vscode.WorkspaceEdit(); + wsEdit.replace(document.uri, makeVscodeRange(command.edit.range), command.edit.newText); + } else if (command.command === "C_Cpp.RemoveAllCodeAnalysisProblems" && command.uri !== undefined) { + // The "RemoveAll" message is sent for all code analysis squiggles. + const vsCodeRange: vscode.Range = makeVscodeRange(r); + const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(command.uri); + if (codeActionDiagnosticInfo === undefined) { + return; + } + const fixCodeActions: vscode.CodeAction[] = []; + const disableCodeActions: vscode.CodeAction[] = []; + const removeCodeActions: vscode.CodeAction[] = []; + const docCodeActions: vscode.CodeAction[] = []; + const showClear: string = new CppSettings().clangTidyCodeActionShowClear; + + // Check which code actions to show. This can get called a lot + // (after every cursor change) so all the checks should be relatively fast. + for (const codeAction of codeActionDiagnosticInfo) { + if (!codeAction.range.contains(vsCodeRange)) { + continue; + } + let codeActionCodeInfo: CodeActionCodeInfo | undefined; + if (codeAnalysisCodeToFixes.has(codeAction.code)) { + codeActionCodeInfo = codeAnalysisCodeToFixes.get(codeAction.code); + } + if (codeAction.fixCodeAction !== undefined) { + // Potentially we could make the "fix all" or "fix all type" preferred instead. + codeAction.fixCodeAction.isPreferred = true; + fixCodeActions.push(codeAction.fixCodeAction); if (codeActionCodeInfo !== undefined) { - if (codeActionCodeInfo.disableAllTypeCodeAction !== undefined) { - disableCodeActions.push(codeActionCodeInfo.disableAllTypeCodeAction); - } - if (codeActionCodeInfo.removeAllTypeCodeAction !== undefined && - codeActionCodeInfo.uriToInfo.size > 0 && + if (codeActionCodeInfo.fixAllTypeCodeAction !== undefined && (codeActionCodeInfo.uriToInfo.size > 1 || - codeActionCodeInfo.uriToInfo.values().next().value.identifiers.length > 1)) { - // Only show the "clear all type" if there is more than one fix for the type. - removeAllTypeAvailable = true; + codeActionCodeInfo.uriToInfo.values().next().value.numValidWorkspaceEdits > 1)) { + // Only show the "fix all type" if there is more than one fix for the type. + fixCodeActions.push(codeActionCodeInfo.fixAllTypeCodeAction); } } - if (showClear !== "None") { - if (!removeAllTypeAvailable || showClear === "AllAndAllTypeAndThis") { - // The "Clear this" command is useful when you need to manually fix - // some of the cases, and then run "fix all type" for the rest. - removeCodeActions.push(codeAction.removeCodeAction); - } - if (removeAllTypeAvailable && codeActionCodeInfo?.removeAllTypeCodeAction) { - removeCodeActions.push(codeActionCodeInfo.removeAllTypeCodeAction); - } - } - - if (codeActionCodeInfo === undefined || codeActionCodeInfo.docCodeAction === undefined) { - continue; - } - docCodeActions.push(codeActionCodeInfo.docCodeAction); } - if (fixCodeActions.length > 0) { - resultCodeActions.push(...fixCodeActions); - if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments?.[1] !== undefined) { - // Only show "fix all" if there are multiple types of fixes. - // The arguments[1] only gets set when there are multiple types. - resultCodeActions.push(codeAnalysisAllFixes.fixAllCodeAction); + if (codeAction.removeCodeAction === undefined) { + continue; + } + let removeAllTypeAvailable: boolean = false; + if (codeActionCodeInfo !== undefined) { + if (codeActionCodeInfo.disableAllTypeCodeAction !== undefined) { + disableCodeActions.push(codeActionCodeInfo.disableAllTypeCodeAction); + } + if (codeActionCodeInfo.removeAllTypeCodeAction !== undefined && + codeActionCodeInfo.uriToInfo.size > 0 && + (codeActionCodeInfo.uriToInfo.size > 1 || + codeActionCodeInfo.uriToInfo.values().next().value.identifiers.length > 1)) { + // Only show the "clear all type" if there is more than one fix for the type. + removeAllTypeAvailable = true; } } if (showClear !== "None") { - let showClearAllAvailable: boolean = false; - if ((codeActionDiagnosticInfo.length > 1 || codeAnalysisFileToCodeActions.size > 1)) { - showClearAllAvailable = true; + if (!removeAllTypeAvailable || showClear === "AllAndAllTypeAndThis") { + // The "Clear this" command is useful when you need to manually fix + // some of the cases, and then run "fix all type" for the rest. + removeCodeActions.push(codeAction.removeCodeAction); } - if (!showClearAllAvailable || showClear !== "AllOnly") { - resultCodeActions.push(...removeCodeActions); - } - if (showClearAllAvailable) { - resultCodeActions.push(codeAnalysisAllFixes.removeAllCodeAction); + if (removeAllTypeAvailable && codeActionCodeInfo?.removeAllTypeCodeAction) { + removeCodeActions.push(codeActionCodeInfo.removeAllTypeCodeAction); } } - resultCodeActions.push(...disableCodeActions); - resultCodeActions.push(...docCodeActions); - return; + + if (codeActionCodeInfo === undefined || codeActionCodeInfo.docCodeAction === undefined) { + continue; + } + docCodeActions.push(codeActionCodeInfo.docCodeAction); } - const vscodeCodeAction: vscode.CodeAction = { + if (fixCodeActions.length > 0) { + resultCodeActions.push(...fixCodeActions); + if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments?.[1] !== undefined) { + // Only show "fix all" if there are multiple types of fixes. + // The arguments[1] only gets set when there are multiple types. + resultCodeActions.push(codeAnalysisAllFixes.fixAllCodeAction); + } + } + if (showClear !== "None") { + let showClearAllAvailable: boolean = false; + if ((codeActionDiagnosticInfo.length > 1 || codeAnalysisFileToCodeActions.size > 1)) { + showClearAllAvailable = true; + } + if (!showClearAllAvailable || showClear !== "AllOnly") { + resultCodeActions.push(...removeCodeActions); + } + if (showClearAllAvailable) { + resultCodeActions.push(codeAnalysisAllFixes.removeAllCodeAction); + } + } + resultCodeActions.push(...disableCodeActions); + resultCodeActions.push(...docCodeActions); + return; + } + const vscodeCodeAction: vscode.CodeAction = { + title: title, + command: command.command === "edit" ? undefined : { title: title, - command: command.command === "edit" ? undefined : { - title: title, - command: command.command, - arguments: command.arguments - }, - edit: wsEdit, - kind: codeActionKind - }; - resultCodeActions.push(vscodeCodeAction); - }); - return resultCodeActions; + command: command.command, + arguments: command.arguments + }, + edit: wsEdit, + kind: codeActionKind + }; + resultCodeActions.push(vscodeCodeAction); }); + return resultCodeActions; } } diff --git a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts index f777063f74..eaa85fd721 100644 --- a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts @@ -3,7 +3,7 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { DefaultClient, FormatParams, FormatDocumentRequest } from '../client'; +import { DefaultClient, FormatParams, FormatDocumentRequest, FormatResult } from '../client'; import { CppSettings, getEditorConfigSettings, OtherSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -69,7 +69,11 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - const results: vscode.TextEdit[] = makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatDocumentRequest, params)); + const response: FormatResult = await this.client.languageClient.sendRequest(FormatDocumentRequest, params, token); + if (token.isCancellationRequested || response.edits === undefined) { + throw new vscode.CancellationError(); + } + const results: vscode.TextEdit[] = makeVscodeTextEdits(response.edits); // Apply insert_final_newline from .editorconfig if (document.lineCount > 0 && editorConfigSettings !== undefined && editorConfigSettings.insert_final_newline) { // Check if there is already a newline at the end. If so, formatting edits should not replace it. diff --git a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts index c787703acc..5c950717ce 100644 --- a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts @@ -3,7 +3,7 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { DefaultClient, FormatParams, FormatRangeRequest } from '../client'; +import { DefaultClient, FormatParams, FormatRangeRequest, FormatResult } from '../client'; import { CppSettings, getEditorConfigSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -45,7 +45,11 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - return makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatRangeRequest, params)); + const response: FormatResult = await this.client.languageClient.sendRequest(FormatRangeRequest, params, token); + if (token.isCancellationRequested || response.edits === undefined) { + throw new vscode.CancellationError(); + } + return makeVscodeTextEdits(response.edits); }; if (!useVcFormat) { return configCallBack(undefined); diff --git a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts index ab39a8138c..81b93aab2e 100644 --- a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts @@ -3,7 +3,7 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { DefaultClient, LocalizeDocumentSymbol, GetDocumentSymbolRequestParams, GetDocumentSymbolRequest, SymbolScope, Client } from '../client'; +import { DefaultClient, LocalizeDocumentSymbol, GetDocumentSymbolRequestParams, GetDocumentSymbolRequest, SymbolScope, Client, GetDocumentSymbolResult } from '../client'; import { clients, processDelayedDidOpen } from '../extension'; import { makeVscodeRange } from '../utils'; import { getLocalizedString, getLocalizedSymbolScope } from '../localization'; @@ -60,14 +60,16 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { if (!defaultClient.TrackedDocuments.has(document)) { processDelayedDidOpen(document); } - return defaultClient.requestWhenReady(async () => { - const params: GetDocumentSymbolRequestParams = { - uri: document.uri.toString() - }; - const symbols: LocalizeDocumentSymbol[] = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token); - const resultSymbols: vscode.DocumentSymbol[] = this.getChildrenSymbols(symbols); - return resultSymbols; - }); + await defaultClient.awaitUntilLanguageClientReady(); + const params: GetDocumentSymbolRequestParams = { + uri: document.uri.toString() + }; + const response: GetDocumentSymbolResult = await defaultClient.languageClient.sendRequest(GetDocumentSymbolRequest, params, token); + if (token.isCancellationRequested || response.symbols === undefined) { + throw new vscode.CancellationError(); + }; + const resultSymbols: vscode.DocumentSymbol[] = this.getChildrenSymbols(response.symbols); + return resultSymbols; } return []; } diff --git a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts index 58bed22d3c..1cb9dd5eae 100644 --- a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts +++ b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts @@ -23,12 +23,12 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider { uri: document.uri.toString() }; await this.client.awaitUntilLanguageClientReady(); - const ranges: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token); - if (ranges.canceled) { - return undefined; + const response: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token); + if (token.isCancellationRequested || response.ranges === undefined) { + throw new vscode.CancellationError(); } const result: vscode.FoldingRange[] = []; - ranges.ranges.forEach((r: CppFoldingRange) => { + response.ranges.forEach((r: CppFoldingRange) => { const foldingRange: vscode.FoldingRange = { start: r.range.startLine, end: r.range.endLine diff --git a/Extension/src/LanguageServer/Providers/inlayHintProvider.ts b/Extension/src/LanguageServer/Providers/inlayHintProvider.ts index 8d21deec01..be14935be8 100644 --- a/Extension/src/LanguageServer/Providers/inlayHintProvider.ts +++ b/Extension/src/LanguageServer/Providers/inlayHintProvider.ts @@ -29,7 +29,6 @@ interface CppInlayHint { interface GetInlayHintsResult { fileVersion: number; - canceled: boolean; inlayHints: CppInlayHint[]; } @@ -59,7 +58,7 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider { const uriString: string = document.uri.toString(); // Get results from cache if available. - const cacheEntry: InlayHintsCacheEntry | undefined = this.cache.get(uriString); + let cacheEntry: InlayHintsCacheEntry | undefined = this.cache.get(uriString); if (cacheEntry?.FileVersion === document.version) { return this.buildVSCodeHints(document.uri, cacheEntry); } @@ -67,17 +66,14 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider { // Get new results from the language server const params: GetInlayHintsParams = { uri: uriString }; const inlayHintsResult: GetInlayHintsResult = await this.client.languageClient.sendRequest(GetInlayHintsRequest, params, token); - if (!inlayHintsResult.canceled) { - if (inlayHintsResult.fileVersion === openFileVersions.get(uriString)) { - const cacheEntry: InlayHintsCacheEntry = this.createCacheEntry(inlayHintsResult); - this.cache.set(uriString, cacheEntry); - return this.buildVSCodeHints(document.uri, cacheEntry); - } else { - // Force another request because file versions do not match. - this.onDidChangeInlayHintsEvent.fire(); - } + if (token.isCancellationRequested || inlayHintsResult.inlayHints === undefined || inlayHintsResult.fileVersion !== openFileVersions.get(uriString)) { + throw new vscode.CancellationError(); } - return undefined; + + cacheEntry = this.createCacheEntry(inlayHintsResult); + this.cache.set(uriString, cacheEntry); + return this.buildVSCodeHints(document.uri, cacheEntry); + } public invalidateFile(uri: string): void { diff --git a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts index 9a1381a96b..44c13c5725 100644 --- a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts @@ -3,7 +3,7 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { DefaultClient, FormatParams, FormatOnTypeRequest } from '../client'; +import { DefaultClient, FormatParams, FormatOnTypeRequest, FormatResult } from '../client'; import { CppSettings, getEditorConfigSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; @@ -45,7 +45,11 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - return makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatOnTypeRequest, params)); + const response: FormatResult = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params, token); + if (token.isCancellationRequested || response.edits === undefined) { + throw new vscode.CancellationError(); + } + return makeVscodeTextEdits(response.edits); }; if (!useVcFormat) { // If not using vcFormat, only process on-type requests for ';' diff --git a/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts b/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts index 26f70a0de4..2a09ec45ef 100644 --- a/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts +++ b/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts @@ -23,27 +23,21 @@ export class SemanticTokensProvider implements vscode.DocumentSemanticTokensProv const cache: [number, vscode.SemanticTokens] | undefined = this.tokenCaches.get(uriString); if (cache && cache[0] === document.version) { return cache[1]; - } else { - const params: GetSemanticTokensParams = { - uri: uriString - }; - const tokensResult: GetSemanticTokensResult = await this.client.languageClient.sendRequest(GetSemanticTokensRequest, params, token); - if (tokensResult.canceled) { - throw new vscode.CancellationError(); - } else { - if (tokensResult.fileVersion !== openFileVersions.get(uriString)) { - throw new vscode.CancellationError(); - } else { - const builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(semanticTokensLegend); - tokensResult.tokens.forEach((semanticToken) => { - builder.push(semanticToken.line, semanticToken.character, semanticToken.length, semanticToken.type, semanticToken.modifiers); - }); - const tokens: vscode.SemanticTokens = builder.build(); - this.tokenCaches.set(uriString, [tokensResult.fileVersion, tokens]); - return tokens; - } - } } + const params: GetSemanticTokensParams = { + uri: uriString + }; + const tokensResult: GetSemanticTokensResult = await this.client.languageClient.sendRequest(GetSemanticTokensRequest, params, token); + if (token.isCancellationRequested || tokensResult.tokens === undefined || tokensResult.fileVersion !== openFileVersions.get(uriString)) { + throw new vscode.CancellationError(); + } + const builder: vscode.SemanticTokensBuilder = new vscode.SemanticTokensBuilder(semanticTokensLegend); + tokensResult.tokens.forEach((semanticToken) => { + builder.push(semanticToken.line, semanticToken.character, semanticToken.length, semanticToken.type, semanticToken.modifiers); + }); + const tokens: vscode.SemanticTokens = builder.build(); + this.tokenCaches.set(uriString, [tokensResult.fileVersion, tokens]); + return tokens; } public invalidateFile(uri: string): void { diff --git a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts index 688dfa3938..24d08a148e 100644 --- a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts @@ -20,6 +20,9 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { const symbols: LocalizeSymbolInformation[] = await this.client.languageClient.sendRequest(GetSymbolInfoRequest, params, token); const resultSymbols: vscode.SymbolInformation[] = []; + if (token.isCancellationRequested) { + throw new vscode.CancellationError(); + } // Convert to vscode.Command array symbols.forEach((symbol) => { diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index b47f32b423..a6c00b621b 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -337,6 +337,10 @@ export interface LocalizeDocumentSymbol { children: LocalizeDocumentSymbol[]; } +export interface GetDocumentSymbolResult { + symbols: LocalizeDocumentSymbol[]; +} + export interface LocalizeSymbolInformation { name: string; kind: vscode.SymbolKind; @@ -368,6 +372,10 @@ export interface FormatParams { onChanges: boolean; } +export interface FormatResult { + edits: TextEdit[]; +} + export interface GetFoldingRangesParams { uri: string; } @@ -385,7 +393,6 @@ export interface CppFoldingRange { } export interface GetFoldingRangesResult { - canceled: boolean; ranges: CppFoldingRange[]; } @@ -403,7 +410,6 @@ interface SemanticToken { export interface GetSemanticTokensResult { fileVersion: number; - canceled: boolean; tokens: SemanticToken[]; } @@ -531,13 +537,13 @@ const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryTranslationUnitSource'); const SwitchHeaderSourceRequest: RequestType = new RequestType('cpptools/didSwitchHeaderSource'); const GetDiagnosticsRequest: RequestType = new RequestType('cpptools/getDiagnostics'); -export const GetDocumentSymbolRequest: RequestType = new RequestType('cpptools/getDocumentSymbols'); +export const GetDocumentSymbolRequest: RequestType = new RequestType('cpptools/getDocumentSymbols'); export const GetSymbolInfoRequest: RequestType = new RequestType('cpptools/getWorkspaceSymbols'); export const GetFoldingRangesRequest: RequestType = new RequestType('cpptools/getFoldingRanges'); export const GetSemanticTokensRequest: RequestType = new RequestType('cpptools/getSemanticTokens'); -export const FormatDocumentRequest: RequestType = new RequestType('cpptools/formatDocument'); -export const FormatRangeRequest: RequestType = new RequestType('cpptools/formatRange'); -export const FormatOnTypeRequest: RequestType = new RequestType('cpptools/formatOnType'); +export const FormatDocumentRequest: RequestType = new RequestType('cpptools/formatDocument'); +export const FormatRangeRequest: RequestType = new RequestType('cpptools/formatRange'); +export const FormatOnTypeRequest: RequestType = new RequestType('cpptools/formatOnType'); const CreateDeclarationOrDefinitionRequest: RequestType = new RequestType('cpptools/createDeclDef'); const GoToDirectiveInGroupRequest: RequestType = new RequestType('cpptools/goToDirectiveInGroup'); const GenerateDoxygenCommentRequest: RequestType = new RequestType('cpptools/generateDoxygenComment'); @@ -1688,7 +1694,8 @@ export class DefaultClient implements Client { } public async logDiagnostics(): Promise { - const response: GetDiagnosticsResult = await this.requestWhenReady(() => this.languageClient.sendRequest(GetDiagnosticsRequest, null)); + await this.awaitUntilLanguageClientReady(); + const response: GetDiagnosticsResult = await this.languageClient.sendRequest(GetDiagnosticsRequest, null); const diagnosticsChannel: vscode.OutputChannel = getDiagnosticsChannel(); diagnosticsChannel.clear(); From fafca55335e1b8c3bddd931e85a60a9f73ac1616 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:00:48 -0800 Subject: [PATCH 12/17] Fix loc issue with handling of ReportTagParseStatus (#10438) --- Extension/src/LanguageServer/client.ts | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index a6c00b621b..33bb5ec332 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -532,6 +532,12 @@ interface InitializationOptions { settings: SettingsParams; }; +interface TagParseStatus { + localizeStringParams: LocalizeStringParams; + isPausable: boolean; + isPaused: boolean; +} + // Requests const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryCompilerDefaults'); const QueryTranslationUnitSourceRequest: RequestType = new RequestType('cpptools/queryTranslationUnitSource'); @@ -586,7 +592,7 @@ const RemoveCodeAnalysisProblemsNotification: NotificationType = new NotificationType('cpptools/reloadWindow'); const UpdateTrustedCompilersNotification: NotificationType = new NotificationType('cpptools/updateTrustedCompilersList'); const LogTelemetryNotification: NotificationType = new NotificationType('cpptools/logTelemetry'); -const ReportTagParseStatusNotification: NotificationType = new NotificationType('cpptools/reportTagParseStatus'); +const ReportTagParseStatusNotification: NotificationType = new NotificationType('cpptools/reportTagParseStatus'); const ReportStatusNotification: NotificationType = new NotificationType('cpptools/reportStatus'); const DebugProtocolNotification: NotificationType = new NotificationType('cpptools/debugProtocol'); const DebugLogNotification: NotificationType = new NotificationType('cpptools/debugLog'); @@ -2317,18 +2323,10 @@ export class DefaultClient implements Client { } } - private updateTagParseStatus(notificationBody: LocalizeStringParams): void { - this.model.parsingWorkspaceStatus.Value = getLocalizedString(notificationBody); - if (notificationBody.text.startsWith("Workspace parsing paused")) { - this.model.isParsingWorkspacePaused.Value = true; - this.model.isParsingWorkspacePausable.Value = true; - } else if (notificationBody.text.startsWith("Parsing workspace")) { - this.model.isParsingWorkspacePaused.Value = false; - this.model.isParsingWorkspacePausable.Value = true; - } else { - this.model.isParsingWorkspacePaused.Value = false; - this.model.isParsingWorkspacePausable.Value = false; - } + private updateTagParseStatus(tagParseStatus: TagParseStatus): void { + this.model.parsingWorkspaceStatus.Value = getLocalizedString(tagParseStatus.localizeStringParams); + this.model.isParsingWorkspacePausable.Value = tagParseStatus.isPausable; + this.model.isParsingWorkspacePaused.Value = tagParseStatus.isPaused; } private updateInactiveRegions(params: InactiveRegionParams): void { From 6f2714bfbbff2dfb696d8e7050fdd460219a0494 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 30 Jan 2023 15:48:13 -0800 Subject: [PATCH 13/17] Fix empty intelliSenseMode being generated. (#10441) --- Extension/src/LanguageServer/configurations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index e778cbd545..0b108de9d5 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -303,7 +303,7 @@ export class CppProperties { this.defaultIncludes = compilerDefaults.includes; this.defaultFrameworks = compilerDefaults.frameworks; this.defaultWindowsSdkVersion = compilerDefaults.windowsSdkVersion; - this.defaultIntelliSenseMode = compilerDefaults.intelliSenseMode; + this.defaultIntelliSenseMode = compilerDefaults.intelliSenseMode !== "" ? compilerDefaults.intelliSenseMode : undefined; this.trustedCompilerFound = compilerDefaults.trustedCompilerFound; } From 93dc3737fbe8732e274b386c4b359ab6a8bf972c Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 30 Jan 2023 15:55:57 -0800 Subject: [PATCH 14/17] Fix an unstrusted compilerPath being used without a c_cpp_properties.json. (#10440) --- Extension/src/LanguageServer/configurations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 0b108de9d5..62b4584dc6 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -296,7 +296,7 @@ export class CppProperties { this.handleConfigurationChange(); } public set CompilerDefaults(compilerDefaults: CompilerDefaults) { - this.defaultCompilerPath = compilerDefaults.compilerPath; + this.defaultCompilerPath = compilerDefaults.trustedCompilerFound ? compilerDefaults.compilerPath : null; this.knownCompilers = compilerDefaults.knownCompilers; this.defaultCStandard = compilerDefaults.cStandard; this.defaultCppStandard = compilerDefaults.cppStandard; From 5f68e6a868e5ce06837dd36c9c02dd7d1d259323 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Tue, 31 Jan 2023 13:18:29 -0800 Subject: [PATCH 15/17] Fix issues with didOpen synchronization (#10442) --- .../Providers/documentSymbolProvider.ts | 5 +- .../Providers/foldingRangeProvider.ts | 3 +- .../Providers/inlayHintProvider.ts | 3 +- .../Providers/semanticTokensProvider.ts | 3 +- Extension/src/LanguageServer/client.ts | 42 +++++----- .../src/LanguageServer/configurations.ts | 1 - Extension/src/LanguageServer/extension.ts | 30 +++---- .../src/LanguageServer/protocolFilter.ts | 79 +++++++------------ 8 files changed, 69 insertions(+), 97 deletions(-) diff --git a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts index 81b93aab2e..1c26244a74 100644 --- a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts @@ -57,10 +57,7 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { const client: Client = clients.getClientFor(document.uri); if (client instanceof DefaultClient) { const defaultClient: DefaultClient = client; - if (!defaultClient.TrackedDocuments.has(document)) { - processDelayedDidOpen(document); - } - await defaultClient.awaitUntilLanguageClientReady(); + await client.requestWhenReady(() => processDelayedDidOpen(document)); const params: GetDocumentSymbolRequestParams = { uri: document.uri.toString() }; diff --git a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts index 1cb9dd5eae..025c32e856 100644 --- a/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts +++ b/Extension/src/LanguageServer/Providers/foldingRangeProvider.ts @@ -4,6 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import { DefaultClient, GetFoldingRangesParams, GetFoldingRangesRequest, FoldingRangeKind, GetFoldingRangesResult, CppFoldingRange } from '../client'; +import { processDelayedDidOpen } from '../extension'; import { CppSettings } from '../settings'; export class FoldingRangeProvider implements vscode.FoldingRangeProvider { @@ -22,7 +23,7 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider { const params: GetFoldingRangesParams = { uri: document.uri.toString() }; - await this.client.awaitUntilLanguageClientReady(); + await this.client.requestWhenReady(() => processDelayedDidOpen(document)); const response: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token); if (token.isCancellationRequested || response.ranges === undefined) { throw new vscode.CancellationError(); diff --git a/Extension/src/LanguageServer/Providers/inlayHintProvider.ts b/Extension/src/LanguageServer/Providers/inlayHintProvider.ts index be14935be8..ee97d43700 100644 --- a/Extension/src/LanguageServer/Providers/inlayHintProvider.ts +++ b/Extension/src/LanguageServer/Providers/inlayHintProvider.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { DefaultClient, openFileVersions } from '../client'; import { Position, RequestType } from 'vscode-languageclient'; import { CppSettings } from '../settings'; +import { processDelayedDidOpen } from '../extension'; interface GetInlayHintsParams { uri: string; @@ -54,7 +55,7 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider { public async provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise { - await this.client.awaitUntilLanguageClientReady(); + await this.client.requestWhenReady(() => processDelayedDidOpen(document)); const uriString: string = document.uri.toString(); // Get results from cache if available. diff --git a/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts b/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts index 2a09ec45ef..76c2698194 100644 --- a/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts +++ b/Extension/src/LanguageServer/Providers/semanticTokensProvider.ts @@ -4,6 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import { DefaultClient, GetSemanticTokensParams, GetSemanticTokensRequest, openFileVersions, GetSemanticTokensResult, semanticTokensLegend } from '../client'; +import { processDelayedDidOpen } from '../extension'; export class SemanticTokensProvider implements vscode.DocumentSemanticTokensProvider { private client: DefaultClient; @@ -17,7 +18,7 @@ export class SemanticTokensProvider implements vscode.DocumentSemanticTokensProv } public async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { - await this.client.awaitUntilLanguageClientReady(); + await this.client.requestWhenReady(() => processDelayedDidOpen(document)); const uriString: string = document.uri.toString(); // First check the semantic token cache to see if we already have results for that file and version const cache: [number, vscode.SemanticTokens] | undefined = this.tokenCaches.get(uriString); diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 33bb5ec332..c98b01c4e9 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -734,11 +734,12 @@ export interface Client { getVcpkgEnabled(): Thenable; getCurrentCompilerPathAndArgs(): Thenable; getKnownCompilers(): Thenable; - takeOwnership(document: vscode.TextDocument): void; + takeOwnership(document: vscode.TextDocument): Promise; + sendDidOpen(document: vscode.TextDocument): Promise; queueTask(task: () => Thenable): Promise; - requestWhenReady(request: () => Thenable): Thenable; - notifyWhenLanguageClientReady(notify: () => void): void; - awaitUntilLanguageClientReady(): Thenable; + requestWhenReady(request: () => Thenable): Promise; + notifyWhenLanguageClientReady(notify: () => T): Promise; + awaitUntilLanguageClientReady(): Promise; requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string): Thenable; activeDocumentChanged(document: vscode.TextDocument): Promise; restartIntelliSenseForFile(document: vscode.TextDocument): Promise; @@ -1934,7 +1935,13 @@ export class DefaultClient implements Client { * that it knows about the file, as well as adding it to this client's set of * tracked documents. */ - public takeOwnership(document: vscode.TextDocument): void { + public async takeOwnership(document: vscode.TextDocument): Promise { + this.trackedDocuments.add(document); + this.updateActiveDocumentTextOptions(); + await this.requestWhenReady(() => this.sendDidOpen(document)); + } + + public async sendDidOpen(document: vscode.TextDocument): Promise { const params: DidOpenTextDocumentParams = { textDocument: { uri: document.uri.toString(), @@ -1943,9 +1950,7 @@ export class DefaultClient implements Client { text: document.getText() } }; - this.updateActiveDocumentTextOptions(); - this.notifyWhenLanguageClientReady(() => this.languageClient.sendNotification(DidOpenNotification, params)); - this.trackedDocuments.add(document); + await this.languageClient.sendNotification(DidOpenNotification, params); } /** @@ -2016,7 +2021,7 @@ export class DefaultClient implements Client { }); } - public requestWhenReady(request: () => Thenable): Thenable { + public requestWhenReady(request: () => Thenable): Promise { return this.queueTask(request); } @@ -2027,7 +2032,7 @@ export class DefaultClient implements Client { return this.queueTask(task); } - public awaitUntilLanguageClientReady(): Thenable { + public awaitUntilLanguageClientReady(): Promise { const task: () => Thenable = () => new Promise(resolve => { resolve(); }); @@ -2116,7 +2121,7 @@ export class DefaultClient implements Client { if (fileName === ".editorconfig") { cachedEditorConfigSettings.clear(); cachedEditorConfigLookups.clear(); - await this.updateActiveDocumentTextOptions(); + this.updateActiveDocumentTextOptions(); } if (fileName === ".clang-format" || fileName === "_clang-format") { cachedEditorConfigLookups.clear(); @@ -2144,7 +2149,7 @@ export class DefaultClient implements Client { if (fileName === ".editorconfig") { cachedEditorConfigSettings.clear(); cachedEditorConfigLookups.clear(); - await this.updateActiveDocumentTextOptions(); + this.updateActiveDocumentTextOptions(); } if (dotIndex !== -1) { const ext: string = uri.fsPath.substring(dotIndex + 1); @@ -2456,7 +2461,7 @@ export class DefaultClient implements Client { return this.languageClient.sendRequest(QueryCompilerDefaultsRequest, params); } - private async updateActiveDocumentTextOptions(): Promise { + private updateActiveDocumentTextOptions(): void { const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; if (editor?.document?.uri.scheme === "file" && (editor.document.languageId === "c" @@ -2493,7 +2498,7 @@ export class DefaultClient implements Client { * notifications to the language server */ public async activeDocumentChanged(document: vscode.TextDocument): Promise { - await this.updateActiveDocumentTextOptions(); + this.updateActiveDocumentTextOptions(); await this.awaitUntilLanguageClientReady(); this.languageClient.sendNotification(ActiveDocumentChangeNotification, this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document)); } @@ -3417,11 +3422,12 @@ class NullClient implements Client { getVcpkgEnabled(): Thenable { return Promise.resolve(false); } getCurrentCompilerPathAndArgs(): Thenable { return Promise.resolve(undefined); } getKnownCompilers(): Thenable { return Promise.resolve([]); } - takeOwnership(document: vscode.TextDocument): void { } + takeOwnership(document: vscode.TextDocument): Promise { return Promise.resolve(); } + sendDidOpen(document: vscode.TextDocument): Promise { return Promise.resolve(); } queueTask(task: () => Thenable): Promise { return Promise.resolve(task()); } - requestWhenReady(request: () => Thenable): Thenable { return request(); } - notifyWhenLanguageClientReady(notify: () => void): void { } - awaitUntilLanguageClientReady(): Thenable { return Promise.resolve(); } + requestWhenReady(request: () => Thenable): Promise { return Promise.resolve(request()); } + notifyWhenLanguageClientReady(notify: () => T): Promise { return Promise.resolve(notify()); } + awaitUntilLanguageClientReady(): Promise { return Promise.resolve(); } requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string): Thenable { return Promise.resolve(""); } activeDocumentChanged(document: vscode.TextDocument): Promise { return Promise.resolve(); } restartIntelliSenseForFile(document: vscode.TextDocument): Promise { return Promise.resolve(); } diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 62b4584dc6..56c84b8216 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -253,7 +253,6 @@ export class CppProperties { this.isCppPropertiesJsonVisible = true; if (!wasVisible) { this.handleSquiggles(); - } } }); diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 95df484126..b2e6b61cdf 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -324,7 +324,7 @@ function onDidChangeTextEditorSelection(event: vscode.TextEditorSelectionChangeE clients.ActiveClient.selectionChanged(makeCpptoolsRange(event.selections[0])); } -export function processDelayedDidOpen(document: vscode.TextDocument): boolean { +export async function processDelayedDidOpen(document: vscode.TextDocument): Promise { const client: Client = clients.getClientFor(document.uri); if (client) { // Log warm start. @@ -333,28 +333,17 @@ export function processDelayedDidOpen(document: vscode.TextDocument): boolean { // If not yet tracked, process as a newly opened file. (didOpen is sent to server in client.takeOwnership()). clients.timeTelemetryCollector.setDidOpenTime(document.uri); client.TrackedDocuments.add(document); - const finishDidOpen = (doc: vscode.TextDocument) => { - client.provideCustomConfiguration(doc.uri, undefined); - client.notifyWhenLanguageClientReady(() => { - client.takeOwnership(doc); - client.onDidOpenTextDocument(doc); - }); - }; - let languageChanged: boolean = false; // Work around vscode treating ".C" or ".H" as c, by adding this file name to file associations as cpp if (document.languageId === "c" && shouldChangeFromCToCpp(document)) { const baseFileName: string = path.basename(document.fileName); const mappingString: string = baseFileName + "@" + document.fileName; client.addFileAssociations(mappingString, "cpp"); client.sendDidChangeSettings(); - vscode.languages.setTextDocumentLanguage(document, "cpp").then((newDoc: vscode.TextDocument) => { - finishDidOpen(newDoc); - }); - languageChanged = true; - } - if (!languageChanged) { - finishDidOpen(document); + document = await vscode.languages.setTextDocumentLanguage(document, "cpp"); } + await client.provideCustomConfiguration(document.uri, undefined); + client.onDidOpenTextDocument(document); + await client.sendDidOpen(document); return true; } } @@ -364,12 +353,11 @@ export function processDelayedDidOpen(document: vscode.TextDocument): boolean { function onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]): void { // Process delayed didOpen for any visible editors we haven't seen before - editors.forEach(editor => { + editors.forEach(async (editor) => { if ((editor.document.uri.scheme === "file") && (editor.document.languageId === "c" || editor.document.languageId === "cpp" || editor.document.languageId === "cuda-cpp")) { - if (!processDelayedDidOpen(editor.document)) { - const client: Client = clients.getClientFor(editor.document.uri); - client.onDidChangeVisibleTextEditor(editor); - } + const client: Client = clients.getClientFor(editor.document.uri); + await client.requestWhenReady(() => processDelayedDidOpen(editor.document)); + client.onDidChangeVisibleTextEditor(editor); } }); } diff --git a/Extension/src/LanguageServer/protocolFilter.ts b/Extension/src/LanguageServer/protocolFilter.ts index a628a35229..d12a6b6015 100644 --- a/Extension/src/LanguageServer/protocolFilter.ts +++ b/Extension/src/LanguageServer/protocolFilter.ts @@ -4,51 +4,28 @@ * ------------------------------------------------------------------------------------------ */ 'use strict'; -import * as path from 'path'; import { Middleware } from 'vscode-languageclient'; import { Client } from './client'; import * as vscode from 'vscode'; -import { clients, onDidChangeActiveTextEditor } from './extension'; -import { shouldChangeFromCToCpp } from './utils'; +import { clients, onDidChangeActiveTextEditor, processDelayedDidOpen } from './extension'; export function createProtocolFilter(): Middleware { // Disabling lint for invoke handlers - const invoke1 = async (a: any, next: (a: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a); }; - const invoke2 = async (a: any, b: any, next: (a: any, b: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b); }; - const invoke3 = async (a: any, b: any, c: any, next: (a: any, b: any, c: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c); }; - const invoke4 = async (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any) => { await clients.ActiveClient.awaitUntilLanguageClientReady(); return next(a, b, c, d); }; /* tslint:enable */ + const invoke1 = (a: any, next: (a: any) => any): any => clients.ActiveClient.requestWhenReady(() => next(a)); + const invoke2 = (a: any, b: any, next: (a: any, b: any) => any): any => clients.ActiveClient.requestWhenReady(() => next(a, b)); + const invoke3 = (a: any, b: any, c: any, next: (a: any, b: any, c: any) => any): any => clients.ActiveClient.requestWhenReady(() => next(a, b, c)); + const invoke4 = (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any): any => clients.ActiveClient.requestWhenReady(() => next(a, b, c, d)); return { didOpen: async (document, sendMessage) => { - await clients.ActiveClient.awaitUntilLanguageClientReady(); const editor: vscode.TextEditor | undefined = vscode.window.visibleTextEditors.find(e => e.document === document); if (editor) { // If the file was visible editor when we were activated, we will not get a call to // onDidChangeVisibleTextEditors, so immediately open any file that is visible when we receive didOpen. // Otherwise, we defer opening the file until it's actually visible. - const me: Client = clients.getClientFor(document.uri); - if (!me.TrackedDocuments.has(document)) { - // Log warm start. - clients.timeTelemetryCollector.setDidOpenTime(document.uri); - if (clients.checkOwnership(me, document)) { - me.TrackedDocuments.add(document); - const finishDidOpen = async (doc: vscode.TextDocument) => { - await me.provideCustomConfiguration(doc.uri, undefined); - await sendMessage(doc); - me.onDidOpenTextDocument(doc); - if (editor && editor === vscode.window.activeTextEditor) { - onDidChangeActiveTextEditor(editor); - } - }; - if (document.languageId === "c" && shouldChangeFromCToCpp(document)) { - const baesFileName: string = path.basename(document.fileName); - const mappingString: string = baesFileName + "@" + document.fileName; - me.addFileAssociations(mappingString, "cpp"); - me.sendDidChangeSettings(); - document = await vscode.languages.setTextDocumentLanguage(document, "cpp"); - } - await finishDidOpen(document); - } + await clients.ActiveClient.requestWhenReady(() => processDelayedDidOpen(document)); + if (editor && editor === vscode.window.activeTextEditor) { + onDidChangeActiveTextEditor(editor); } } else { // NO-OP @@ -61,10 +38,11 @@ export function createProtocolFilter(): Middleware { } }, didChange: async (textDocumentChangeEvent, sendMessage) => { - await clients.ActiveClient.awaitUntilLanguageClientReady(); - const me: Client = clients.getClientFor(textDocumentChangeEvent.document.uri); - me.onDidChangeTextDocument(textDocumentChangeEvent); - await sendMessage(textDocumentChangeEvent); + await clients.ActiveClient.requestWhenReady(async () => { + const me: Client = clients.getClientFor(textDocumentChangeEvent.document.uri); + me.onDidChangeTextDocument(textDocumentChangeEvent); + await sendMessage(textDocumentChangeEvent); + }); }, willSave: invoke1, willSaveWaitUntil: async (event, sendMessage) => { @@ -79,24 +57,25 @@ export function createProtocolFilter(): Middleware { }, didSave: invoke1, didClose: async (document, sendMessage) => { - await clients.ActiveClient.awaitUntilLanguageClientReady(); - const me: Client = clients.getClientFor(document.uri); - if (me.TrackedDocuments.has(document)) { - me.onDidCloseTextDocument(document); - me.TrackedDocuments.delete(document); - await sendMessage(document); - } + await clients.ActiveClient.requestWhenReady(async () => { + const me: Client = clients.getClientFor(document.uri); + if (me.TrackedDocuments.has(document)) { + me.onDidCloseTextDocument(document); + me.TrackedDocuments.delete(document); + await sendMessage(document); + } + }); }, provideCompletionItem: invoke4, resolveCompletionItem: invoke2, - provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => { - await clients.ActiveClient.awaitUntilLanguageClientReady(); - const me: Client = clients.getClientFor(document.uri); - if (me.TrackedDocuments.has(document)) { - return next(document, position, token); - } - return null; - }, + provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => + clients.ActiveClient.requestWhenReady(async () => { + const me: Client = clients.getClientFor(document.uri); + if (me.TrackedDocuments.has(document)) { + return next(document, position, token); + } + return null; + }), provideSignatureHelp: invoke4, provideDefinition: invoke3, provideReferences: invoke4, From 8f55a2e8d296cb4dc04f7a92f9cb123cbcb0d99a Mon Sep 17 00:00:00 2001 From: browntarik <111317156+browntarik@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:11:59 -0800 Subject: [PATCH 16/17] add second prompt for when a compiler needs config (#10419) * add second prompt for when a compiler needs config * fix other bugs Co-authored-by: Sean McManus --- Extension/src/LanguageServer/client.ts | 116 +++++++++++++++---------- Extension/src/common.ts | 7 +- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index c98b01c4e9..e5ac873d41 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -70,6 +70,7 @@ let compilerDefaults: configs.CompilerDefaults; let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection; let diagnosticsCollectionRefactor: vscode.DiagnosticCollection; let displayedSelectCompiler: boolean = false; +let secondPromptCounter: number = 0; let workspaceDisposables: vscode.Disposable[] = []; export let workspaceReferences: refs.ReferencesManager; @@ -889,7 +890,7 @@ export class DefaultClient implements Client { return workspaceFolder ? workspaceFolder.name : "untitled"; } - public updateClientConfigurations(): void { + public static updateClientConfigurations(): void { clients.forEach(client => { if (client instanceof DefaultClient) { const defaultClient: DefaultClient = client; @@ -899,7 +900,7 @@ export class DefaultClient implements Client { }); } - public async showSelectCompiler(paths: string[]): Promise { + public async showSelectDefaultCompiler(paths: string[]): Promise { const options: vscode.QuickPickOptions = {}; options.placeHolder = localize("select.compile.commands", "Select a compiler to configure for IntelliSense"); @@ -907,9 +908,11 @@ export class DefaultClient implements Client { for (let i: number = 0; i < paths.length; i++) { let option: string | undefined; let isCompiler: boolean = false; + let isCl: boolean = false; const slash: string = (os.platform() === 'win32') ? "\\" : "/"; if (paths[i].includes(slash)) { + isCl = util.isCl(paths[i]); if (paths[i].split(slash).pop() !== undefined) { option = paths[i].split(slash).pop(); isCompiler = true; @@ -918,7 +921,8 @@ export class DefaultClient implements Client { if (option !== undefined && isCompiler) { const path: string | undefined = paths[i].replace(option, ""); - items.push({ label: option, description: localize("found.string", "Found at {0}", path), index: i }); + const description: string = isCl ? "" : localize("found.string", "Found at {0}", path); + items.push({ label: option, description: description, index: i }); } else { items.push({ label: paths[i], index: i }); } @@ -928,22 +932,55 @@ export class DefaultClient implements Client { return (selection) ? selection.index : -1; } - public async handleCompilerQuickPick(): Promise { + public async showPrompt(buttonMessage: string, showSecondPrompt: boolean): Promise { + if (secondPromptCounter < 1) { + const value: string | undefined = await vscode.window.showInformationMessage(localize("setCompiler.message", "You do not have IntelliSense configured. Unless you set your own configurations, IntelliSense may not be functional."), buttonMessage); + secondPromptCounter++; + if (value === buttonMessage) { + this.handleCompilerQuickPick(showSecondPrompt); + } + } + } + + public async handleCompilerQuickPick(showSecondPrompt: boolean): Promise { const settings: OtherSettings = new OtherSettings(); - let paths: string[] = []; + const selectCompiler: string = localize("selectCompiler.string", "Select Compiler"); + const paths: string[] = []; if (compilerDefaults.knownCompilers !== undefined) { - paths = compilerDefaults.knownCompilers.map(function (a: configs.KnownCompiler): string { return a.path; }); + const tempPaths: string[] = compilerDefaults.knownCompilers.map(function (a: configs.KnownCompiler): string { return a.path; }); + let clFound: boolean = false; + // Remove all but the first cl path. + for (const path of tempPaths) { + if (clFound) { + if (!util.isCl(path)) { + paths.push(path); + } + } else { + if (util.isCl(path)) { + clFound = true; + } + paths.push(path); + } + } } paths.push(localize("selectAnotherCompiler.string", "Select another compiler on my machine")); paths.push(localize("installCompiler.string", "Help me install a compiler")); paths.push(localize("noConfig.string", "Do not configure a compiler (not recommended)")); - const index: number = await this.showSelectCompiler(paths); + const index: number = await this.showSelectDefaultCompiler(paths); if (index === -1) { + if (showSecondPrompt) { + this.showPrompt(selectCompiler, true); + } return; } if (index === paths.length - 1) { settings.defaultCompiler = ""; - } else if (index === paths.length - 2) { + if (showSecondPrompt) { + this.showPrompt(selectCompiler, true); + } + return; + } + if (index === paths.length - 2) { switch (os.platform()) { case 'win32': vscode.commands.executeCommand('vscode.open', "https://go.microsoft.com/fwlink/?linkid=2217614"); @@ -955,55 +992,45 @@ export class DefaultClient implements Client { vscode.commands.executeCommand('vscode.open', "https://go.microsoft.com/fwlink/?linkid=2217615"); return; } - } else if (index === paths.length - 3) { + } + if (index === paths.length - 3) { const result: vscode.Uri[] | undefined = await vscode.window.showOpenDialog(); - if (result !== undefined && result.length > 0) { - util.addTrustedCompiler(compilerPaths, result[0].fsPath); - settings.defaultCompiler = result[0].fsPath; - compilerDefaults = await this.requestCompiler(compilerPaths); - this.updateClientConfigurations(); + if (result === undefined || result.length === 0) { return; } + settings.defaultCompiler = result[0].fsPath; } else { - util.addTrustedCompiler(compilerPaths, paths[index]); - } - // If a compiler is selected, update the default.compilerPath user setting. - if (index < paths.length - 3) { - settings.defaultCompiler = paths[index]; + settings.defaultCompiler = util.isCl(paths[index]) ? "cl.exe" : paths[index]; } + util.addTrustedCompiler(compilerPaths, settings.defaultCompiler); compilerDefaults = await this.requestCompiler(compilerPaths); - this.updateClientConfigurations(); + DefaultClient.updateClientConfigurations(); } - async promptSelectCompiler(command: boolean): Promise { + async promptSelectCompiler(isCommand: boolean): Promise { + if (compilerDefaults === undefined) { + return; + } const selectCompiler: string = localize("selectCompiler.string", "Select Compiler"); const confirmCompiler: string = localize("confirmCompiler.string", "Yes"); const settings: OtherSettings = new OtherSettings(); - if (compilerDefaults.compilerPath !== "") { - if (!command && (compilerDefaults.compilerPath !== undefined)) { - const value: string | undefined = await vscode.window.showInformationMessage(localize("selectCompiler.message", "The compiler {0} was found on this computer. Do you want to configure it for IntelliSense?", compilerDefaults.compilerPath), confirmCompiler, selectCompiler); + if (isCommand || compilerDefaults.compilerPath !== "") { + if (!isCommand && (compilerDefaults.compilerPath !== undefined)) { + const value: string | undefined = await vscode.window.showInformationMessage(localize("selectCompiler.message", "The compiler {0} was found. Do you want to configure IntelliSense with this compiler?", compilerDefaults.compilerPath), confirmCompiler, selectCompiler); if (value === confirmCompiler) { compilerPaths = await util.addTrustedCompiler(compilerPaths, compilerDefaults.compilerPath); settings.defaultCompiler = compilerDefaults.compilerPath; compilerDefaults = await this.requestCompiler(compilerPaths); - this.updateClientConfigurations(); + DefaultClient.updateClientConfigurations(); } else if (value === selectCompiler) { - this.handleCompilerQuickPick(); + this.handleCompilerQuickPick(true); } else { - const setCompiler: string = localize("setCompiler.string", "Set Compiler"); - const value: string | undefined = await vscode.window.showInformationMessage(localize("setCompiler.message", "You do not have a compiler configured. Unless you set your own configurations, IntelliSense may not be functional."), selectCompiler); - if (value === setCompiler) { - this.handleCompilerQuickPick(); - } - } - } else if (!command && (compilerDefaults.compilerPath === undefined)) { - const setCompiler: string = localize("setCompiler.string", "Set Compiler"); - const value: string | undefined = await vscode.window.showInformationMessage(localize("setCompiler.message", "You do not have a compiler configured. Unless you set your own configurations, IntelliSense may not be functional."), selectCompiler); - if (value === setCompiler) { - this.handleCompilerQuickPick(); + this.showPrompt(selectCompiler, true); } + } else if (!isCommand && (compilerDefaults.compilerPath === undefined)) { + this.showPrompt(selectCompiler, false); } else { - this.handleCompilerQuickPick(); + this.handleCompilerQuickPick(false); } } } @@ -1125,16 +1152,9 @@ export class DefaultClient implements Client { if ((vscode.workspace.workspaceFolders === undefined) || (initializedClientCount >= vscode.workspace.workspaceFolders.length)) { // The configurations will not be sent to the language server until the default include paths and frameworks have been set. // The event handlers must be set before this happens. - const inputCompilerDefaults: configs.CompilerDefaults = await this.requestCompiler(compilerPaths); - compilerDefaults = inputCompilerDefaults; - clients.forEach(client => { - if (client instanceof DefaultClient) { - const defaultClient: DefaultClient = client; - defaultClient.configuration.CompilerDefaults = compilerDefaults; - defaultClient.configuration.handleConfigurationChange(); - } - }); - if (!compilerDefaults.trustedCompilerFound && !displayedSelectCompiler) { + compilerDefaults = await this.requestCompiler(compilerPaths); + DefaultClient.updateClientConfigurations(); + if (!compilerDefaults.trustedCompilerFound && !displayedSelectCompiler && (compilerPaths.length !== 1 || compilerPaths[0] !== "")) { // if there is no compilerPath in c_cpp_properties.json, prompt user to configure a compiler this.promptSelectCompiler(false); displayedSelectCompiler = true; diff --git a/Extension/src/common.ts b/Extension/src/common.ts index 24dcc997ed..15fe67f7dc 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -1046,10 +1046,11 @@ function extractArgs(argsString: string): string[] { } } -function isCl(compilerPath: string): boolean { +export function isCl(compilerPath: string): boolean { const compilerPathLowercase: string = compilerPath.toLowerCase(); - return (compilerPathLowercase.endsWith("\\cl.exe") || compilerPathLowercase.endsWith("/cl.exe") || (compilerPathLowercase === "cl.exe") - || compilerPathLowercase.endsWith("\\cl") || compilerPathLowercase.endsWith("/cl") || (compilerPathLowercase === "cl")); + return compilerPathLowercase === "cl" || compilerPathLowercase === "cl.exe" + || compilerPathLowercase.endsWith("\\cl.exe") || compilerPathLowercase.endsWith("/cl.exe") + || compilerPathLowercase.endsWith("\\cl") || compilerPathLowercase.endsWith("/cl"); } /** CompilerPathAndArgs retains original casing of text input for compiler path and args */ From 6b6c16e378af722b3c995aadc8a8727edf1bbcb2 Mon Sep 17 00:00:00 2001 From: Michelle Matias <38734287+michelleangela@users.noreply.github.com> Date: Wed, 1 Feb 2023 14:06:01 -0800 Subject: [PATCH 17/17] changelog 1.14.1 (#10452) --- Extension/CHANGELOG.md | 17 +++++++++++++++++ Extension/package.json | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Extension/CHANGELOG.md b/Extension/CHANGELOG.md index 843181340e..8078e872ed 100644 --- a/Extension/CHANGELOG.md +++ b/Extension/CHANGELOG.md @@ -1,5 +1,22 @@ # C/C++ for Visual Studio Code Changelog +## Version 1.14.1: February 2, 2023 +### New Features +* Add recursive macro expansion on hover. [#3579](https://github.com/microsoft/vscode-cpptools/issues/3579) +* Move status bar items to the language status UI. [#8405](https://github.com/microsoft/vscode-cpptools/issues/8405) +* Add the Select Default Compiler command that lets you choose a default compiler to configure IntelliSense. [#10027](https://github.com/microsoft/vscode-cpptools/issues/10027) + +### Enhancements +* Exclude rename results external to the workspace. [#9235](https://github.com/microsoft/vscode-cpptools/issues/9235) +* Reorder commands in the code action context menu. [#10400](https://github.com/microsoft/vscode-cpptools/issues/10400) + +### Bug Fixes +* Fix Create Declaration / Definition with an anonymous namespace. [#10189](https://github.com/microsoft/vscode-cpptools/issues/10189) +* Potential fix for cpptools getting shutdown after waking up from sleep. [#10362](https://github.com/microsoft/vscode-cpptools/issues/10362) +* Fix the process id picker only showing part of the process on a remote machine. [#10379](https://github.com/microsoft/vscode-cpptools/issues/10379) +* Fix temp files generating at the incorrect path. [#10386](https://github.com/microsoft/vscode-cpptools/issues/10386) +* Fix a crash in extractArgs. [PR #10394](https://github.com/microsoft/vscode-cpptools/pull/10394) + ## Version 1.14.0: January 12, 2023 ### Enhancements * Add support for LLVM-based Intel C/C++ compilers. [#10218](https://github.com/microsoft/vscode-cpptools/issues/10218) diff --git a/Extension/package.json b/Extension/package.json index 27efd006e1..2affa584f9 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -2,7 +2,7 @@ "name": "cpptools", "displayName": "C/C++", "description": "C/C++ IntelliSense, debugging, and code browsing.", - "version": "1.14.0-main", + "version": "1.14.1-main", "publisher": "ms-vscode", "icon": "LanguageCCPP_color_128x.png", "readme": "README.md",