From c417da6ed438327a39b7fa0d18bfd4d05e3279cc Mon Sep 17 00:00:00 2001 From: browntarik <111317156+browntarik@users.noreply.github.com> Date: Thu, 23 Mar 2023 17:22:36 -0700 Subject: [PATCH] Add "Configure Intellisense" Status Bar Item (#10690) * change description for natvisDiagnostics * Add "Configure Intellisense" Status Bar Item * resolve PR --- .../Providers/codeActionProvider.ts | 1 + Extension/src/LanguageServer/client.ts | 35 +++++++++++-------- Extension/src/LanguageServer/extension.ts | 17 +++------ Extension/src/LanguageServer/ui.ts | 33 +++++++++++++++++ Extension/src/LanguageServer/ui_new.ts | 33 +++++++++++++++++ Extension/src/common.ts | 9 +++++ Extension/src/telemetry.ts | 9 +++++ 7 files changed, 109 insertions(+), 28 deletions(-) diff --git a/Extension/src/LanguageServer/Providers/codeActionProvider.ts b/Extension/src/LanguageServer/Providers/codeActionProvider.ts index 41202d2447..046a9d5a11 100644 --- a/Extension/src/LanguageServer/Providers/codeActionProvider.ts +++ b/Extension/src/LanguageServer/Providers/codeActionProvider.ts @@ -174,6 +174,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider { } else if (command.command === 'C_Cpp.CreateDeclarationOrDefinition' && (command.arguments ?? []).length === 0) { command.arguments = ['codeAction']; // We report the sender of the command } else if (command.command === "C_Cpp.SelectDefaultCompiler") { + command.arguments = ['codeAction']; hasSelectDefaultCompiler = true; if (this.client.configuration.CurrentConfiguration?.rawCompilerPath !== undefined) { hasConfigurationCompilerPath = true; diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 3438ea0bde..128607a103 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -760,7 +760,7 @@ export interface Client { selectionChanged(selection: Range): void; resetDatabase(): void; deactivate(): void; - promptSelectCompiler(command: boolean): Promise; + promptSelectCompiler(command: boolean, sender?: any): Promise; pauseParsing(): void; resumeParsing(): void; PauseCodeAnalysis(): void; @@ -947,17 +947,17 @@ export class DefaultClient implements Client { return (selection) ? selection.index : -1; } - public async showPrompt(buttonMessage: string, showSecondPrompt: boolean): Promise { + public async showPrompt(buttonMessage: string, showSecondPrompt: boolean, sender?: any): 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); + this.handleCompilerQuickPick(showSecondPrompt, sender); } } } - public async handleCompilerQuickPick(showSecondPrompt: boolean): Promise { + public async handleCompilerQuickPick(showSecondPrompt: boolean, sender?: any): Promise { const settings: CppSettings = new CppSettings(); const selectCompiler: string = localize("selectCompiler.string", "Select Compiler"); const paths: string[] = []; @@ -987,7 +987,7 @@ export class DefaultClient implements Client { if (index === -1) { action = "escaped"; if (showSecondPrompt && !compilerDefaults.trustedCompilerFound) { - this.showPrompt(selectCompiler, true); + this.showPrompt(selectCompiler, true, sender); } return; } @@ -995,8 +995,9 @@ export class DefaultClient implements Client { action = "disable"; settings.defaultCompilerPath = ""; if (showSecondPrompt) { - this.showPrompt(selectCompiler, true); + this.showPrompt(selectCompiler, true, sender); } + ui.showCompilerStatusIcon(false); return; } if (index === paths.length - 2) { @@ -1017,27 +1018,29 @@ export class DefaultClient implements Client { const result: vscode.Uri[] | undefined = await vscode.window.showOpenDialog(); if (result === undefined || result.length === 0) { if (showSecondPrompt && !compilerDefaults.trustedCompilerFound) { - this.showPrompt(selectCompiler, true); + this.showPrompt(selectCompiler, true, sender); } action = "browse dismissed"; return; } action = "compiler browsed"; settings.defaultCompilerPath = result[0].fsPath; + ui.showCompilerStatusIcon(false); } else { action = "select compiler"; settings.defaultCompilerPath = util.isCl(paths[index]) ? "cl.exe" : paths[index]; + ui.showCompilerStatusIcon(false); } util.addTrustedCompiler(compilerPaths, settings.defaultCompilerPath); compilerDefaults = await this.requestCompiler(compilerPaths); DefaultClient.updateClientConfigurations(); } finally { - telemetry.logLanguageServerEvent('compilerSelection', { action }, { compilerCount: paths.length }); + telemetry.logLanguageServerEvent('compilerSelection', { action, sender: util.getSenderType(sender)}, { compilerCount: paths.length }); } } - async promptSelectCompiler(isCommand: boolean): Promise { + async promptSelectCompiler(isCommand: boolean, sender?: any): Promise { secondPromptCounter = 0; if (compilerDefaults === undefined) { return; @@ -1054,19 +1057,20 @@ export class DefaultClient implements Client { settings.defaultCompilerPath = compilerDefaults.compilerPath; compilerDefaults = await this.requestCompiler(compilerPaths); DefaultClient.updateClientConfigurations(); + ui.showCompilerStatusIcon(false); action = "confirm compiler"; } else if (value === selectCompiler) { - this.handleCompilerQuickPick(true); + this.handleCompilerQuickPick(true, sender); action = "show quickpick"; } else { - this.showPrompt(selectCompiler, true); + this.showPrompt(selectCompiler, true, sender); action = "dismissed"; } telemetry.logLanguageServerEvent('compilerNotification', { action }); } else if (!isCommand && (compilerDefaults.compilerPath === undefined)) { - this.showPrompt(selectCompiler, false); + this.showPrompt(selectCompiler, false, sender); } else { - this.handleCompilerQuickPick(isCommand); + this.handleCompilerQuickPick(isCommand, sender); } } } @@ -1205,8 +1209,9 @@ export class DefaultClient implements Client { compilerDefaults = await this.requestCompiler(compilerPaths); DefaultClient.updateClientConfigurations(); if (!compilerDefaults.trustedCompilerFound && !displayedSelectCompiler && (compilerPaths.length !== 1 || compilerPaths[0] !== "")) { + await ui.showCompilerStatusIcon(true); // if there is no compilerPath in c_cpp_properties.json, prompt user to configure a compiler - this.promptSelectCompiler(false); + this.promptSelectCompiler(false, 'initialization'); displayedSelectCompiler = true; } } @@ -3547,7 +3552,7 @@ class NullClient implements Client { activate(): void { } selectionChanged(selection: Range): void { } resetDatabase(): void { } - promptSelectCompiler(command: boolean): Promise { return Promise.resolve(); } + promptSelectCompiler(command: boolean, sender?: any): Promise { return Promise.resolve(); } deactivate(): void { } pauseParsing(): void { } resumeParsing(): void { } diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 99aaa85211..243565af3e 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -434,20 +434,11 @@ function logForUIExperiment(command: string, sender?: any): void { const properties: {[key: string]: string} = { newUI: ui.isNewUI.toString(), uiOverride: (settings.experimentalFeatures ?? false).toString(), - sender: getSenderType(sender) + sender: util.getSenderType(sender) }; telemetry.logLanguageServerEvent(`experiment${command}`, properties); } -function getSenderType(sender?: any): string { - if (util.isString(sender)) { - return sender; - } else if (util.isUri(sender)) { - return 'contextMenu'; - } - return 'commandPalette'; -} - function onDisabledCommand(): void { const message: string = localize( { @@ -541,8 +532,8 @@ function onResetDatabase(): void { clients.ActiveClient.resetDatabase(); } -function selectDefaultCompiler(): void { - clients.ActiveClient.promptSelectCompiler(true); +function selectDefaultCompiler(sender?: any): void { + clients.ActiveClient.promptSelectCompiler(true, sender); } function onSelectConfiguration(sender?: any): void { @@ -690,7 +681,7 @@ async function onDisableAllTypeCodeAnalysisProblems(code: string, identifiersAnd async function onCreateDeclarationOrDefinition(sender?: any): Promise { const properties: { [key: string]: string } = { - sender: getSenderType(sender) + sender: util.getSenderType(sender) }; telemetry.logLanguageServerEvent('CreateDeclDefn', properties); getActiveClient().handleCreateDeclarationOrDefinition(); diff --git a/Extension/src/LanguageServer/ui.ts b/Extension/src/LanguageServer/ui.ts index 4706a04eca..c1ed1c56c1 100644 --- a/Extension/src/LanguageServer/ui.ts +++ b/Extension/src/LanguageServer/ui.ts @@ -23,6 +23,7 @@ export interface UI { activeDocumentChanged(): void; bind(client: Client): void; showConfigurations(configurationNames: string[]): Promise; + showCompilerStatusIcon(show: boolean): Promise; showConfigurationProviders(currentProvider?: string): Promise; showCompileCommands(paths: string[]): Promise; showWorkspaces(workspaceNames: { name: string; key: string }[]): Promise; @@ -60,6 +61,7 @@ export class OldUI implements UI { private configStatusBarItem: vscode.StatusBarItem; private browseEngineStatusBarItem: vscode.StatusBarItem; private intelliSenseStatusBarItem: vscode.StatusBarItem; + private compilerStatusItem: vscode.StatusBarItem; private referencesStatusBarItem: vscode.StatusBarItem; private curConfigurationStatus?: Promise; private isParsingWorkspace: boolean = false; @@ -102,6 +104,17 @@ export class OldUI implements UI { }; this.ShowReferencesIcon = false; + this.compilerStatusItem = vscode.window.createStatusBarItem(`c.cpp.compilerStatus.statusbar`, vscode.StatusBarAlignment.Right, 901); + this.compilerStatusItem.name = localize("c.cpp.compilerStatus.statusbar", "Configure IntelliSense"); + this.compilerStatusItem.text = `$(warning) ${this.compilerStatusItem.name}`; + this.compilerStatusItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.compilerStatusItem.command = { + command: "C_Cpp.SelectDefaultCompiler", + title: this.compilerStatusItem.name, + arguments: ['statusBar'] + }; + this.showCompilerStatusIcon(false); + this.intelliSenseStatusBarItem = vscode.window.createStatusBarItem("c.cpp.intellisense.statusbar", vscode.StatusBarAlignment.Right, 903); this.intelliSenseStatusBarItem.name = localize("c.cpp.intellisense.statusbar", "C/C++ IntelliSense Status"); this.intelliSenseStatusBarItem.tooltip = this.updatingIntelliSenseTooltip; @@ -294,6 +307,26 @@ export class OldUI implements UI { } } + private compilerTimout?: NodeJS.Timeout; + public async showCompilerStatusIcon(show: boolean): Promise { + if (!telemetry.showStatusBarIntelliSenseIndicator()) { + return; + } + if (this.compilerTimout) { + clearTimeout(this.compilerTimout); + this.compilerTimout = undefined; + } + if (show) { + this.compilerTimout = setTimeout(() => { + this.compilerStatusItem.show(); + telemetry.logLanguageServerEvent('compilerStatusBar'); + this.compilerTimout = undefined; + }, 15000); + } else { + this.compilerStatusItem.hide(); + } + } + public activeDocumentChanged(): void { const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; if (!activeEditor) { diff --git a/Extension/src/LanguageServer/ui_new.ts b/Extension/src/LanguageServer/ui_new.ts index 720e35bc45..67d72b9a2e 100644 --- a/Extension/src/LanguageServer/ui_new.ts +++ b/Extension/src/LanguageServer/ui_new.ts @@ -13,6 +13,7 @@ import * as nls from 'vscode-nls'; import { setTimeout } from 'timers'; import { CppSettings } from './settings'; import { UI } from './ui'; +import * as telemetry from '../telemetry'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -49,6 +50,7 @@ export class NewUI implements UI { private configStatusItem: vscode.LanguageStatusItem; private browseEngineStatusItem: vscode.LanguageStatusItem; private intelliSenseStatusItem: vscode.LanguageStatusItem; + private compilerStatusItem: vscode.StatusBarItem; private referencesStatusBarItem: vscode.StatusBarItem; private codeAnalysisStatusItem: vscode.LanguageStatusItem; private configDocumentSelector: vscode.DocumentFilter[] = [ @@ -112,6 +114,17 @@ export class NewUI implements UI { }; this.ShowReferencesIcon = false; + this.compilerStatusItem = vscode.window.createStatusBarItem(`c.cpp.compilerStatus.statusbar`, vscode.StatusBarAlignment.Right, 901); + this.compilerStatusItem.name = localize("c.cpp.compilerStatus.statusbar", "Configure IntelliSense"); + this.compilerStatusItem.text = `$(warning) ${this.compilerStatusItem.name}`; + this.compilerStatusItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.compilerStatusItem.command = { + command: "C_Cpp.SelectDefaultCompiler", + title: this.compilerStatusItem.name, + arguments: ['statusBar'] + }; + this.showCompilerStatusIcon(false); + this.intelliSenseStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.intellisense`, documentSelector); this.intelliSenseStatusItem.name = localize("cpptools.status.intellisense", "C/C++ IntelliSense Status"); this.intelliSenseStatusItem.text = this.idleIntelliSenseText; @@ -403,6 +416,26 @@ export class NewUI implements UI { } } + private compilerTimout?: NodeJS.Timeout; + public async showCompilerStatusIcon(show: boolean): Promise { + if (!telemetry.showStatusBarIntelliSenseIndicator()) { + return; + } + if (this.compilerTimout) { + clearTimeout(this.compilerTimout); + this.compilerTimout = undefined; + } + if (show) { + this.compilerTimout = setTimeout(() => { + this.compilerStatusItem.show(); + telemetry.logLanguageServerEvent('compilerStatusBar'); + this.compilerTimout = undefined; + }, 15000); + } else { + this.compilerStatusItem.hide(); + } + } + public activeDocumentChanged(): void { const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; if (activeEditor) { diff --git a/Extension/src/common.ts b/Extension/src/common.ts index 15fe67f7dc..564f596c1d 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -1188,6 +1188,15 @@ export class BlockingTask { } } +export function getSenderType(sender?: any): string { + if (isString(sender)) { + return sender; + } else if (isUri(sender)) { + return 'contextMenu'; + } + return 'commandPalette'; +} + function decodeUCS16(input: string): number[] { const output: number[] = []; let counter: number = 0; diff --git a/Extension/src/telemetry.ts b/Extension/src/telemetry.ts index 08863bea1e..a50d708666 100644 --- a/Extension/src/telemetry.ts +++ b/Extension/src/telemetry.ts @@ -139,6 +139,15 @@ export function logLanguageServerEvent(eventName: string, properties?: { [key: s sendTelemetry(); } +export async function showStatusBarIntelliSenseIndicator(): Promise { + if (new CppSettings().experimentalFeatures) { + return true; + } + const experimentationService: IExperimentationService | undefined = await getExperimentationService(); + const useNewUI: boolean | undefined = experimentationService?.getTreatmentVariable("vscode", "showStatusBarIntelliSenseIndicator"); + return useNewUI ?? false; +} + function getPackageInfo(): IPackageInfo { return { name: util.packageJson.publisher + "." + util.packageJson.name,