diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index d94423266f..83ac2578a1 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -246,6 +246,40 @@ export class CppProperties { } }); + vscode.workspace.onDidSaveTextDocument((doc: vscode.TextDocument) => { + // For multi-root, the "onDidSaveTextDocument" will be received once for each project folder. + // To avoid misleading telemetry (for CMake retention) skip if the notifying folder + // is not the same workspace folder of the modified document. + // Exception: if the document does not belong to any of the folders in this workspace, + // getWorkspaceFolder will return undefined and we report this as "outside". + // Even in this case make sure we send the telemetry information only once, + // not for each notifying folder. + 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 && notifyingWorkspaceFolder === vscode.workspace.workspaceFolders[0]) + || savedDocWorkspaceFolder === notifyingWorkspaceFolder) { + let fileType: string | undefined; + const documentPath: string = doc.uri.fsPath.toLowerCase(); + if (documentPath.endsWith("cmakelists.txt")) { + fileType = "CMakeLists"; + } else if (documentPath.endsWith("cmakecache.txt")) { + fileType = "CMakeCache"; + } else if (documentPath.endsWith(".cmake")) { + fileType = ".cmake"; + } + + if (fileType) { + // We consider the changed cmake file as outside if it is not found in any + // of the projects folders. + telemetry.logLanguageServerEvent("cmakeFileWrite", + { + filetype: fileType, + outside: (savedDocWorkspaceFolder === undefined).toString() + }); + } + } + }); + this.handleConfigurationChange(); } diff --git a/Extension/src/common.ts b/Extension/src/common.ts index f32502b913..f906154dcc 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -417,21 +417,18 @@ export function getHttpsProxyAgent(): HttpsProxyAgent | undefined { return new HttpsProxyAgent(proxyOptions); } -/** Creates a file if it doesn't exist */ -function touchFile(file: string): Promise { - return new Promise((resolve, reject) => { - fs.writeFile(file, "", (err) => { - if (err) { - reject(err); - } - - resolve(); - }); - }); -} +export interface InstallLockContents { + platform: string; + architecture: string; +}; -export function touchInstallLockFile(): Promise { - return touchFile(getInstallLockPath()); +export function touchInstallLockFile(info: PlatformInformation): Promise { + const installLockObject: InstallLockContents = { + platform: info.platform, + architecture: info.architecture + }; + const content: string = JSON.stringify(installLockObject); + return writeFileText(getInstallLockPath(), content); } export function touchExtensionFolder(): Promise { @@ -503,20 +500,6 @@ export function checkInstallLockFile(): Promise { return checkFileExists(getInstallLockPath()); } -/** Get the platform that the installed binaries belong to.*/ -export function getInstalledBinaryPlatform(): string | undefined { - // the LLVM/bin folder is utilized to identify the platform - let installedPlatform: string | undefined; - if (checkFileExistsSync(path.join(extensionPath, "LLVM/bin/clang-format.exe"))) { - installedPlatform = "win32"; - } else if (checkFileExistsSync(path.join(extensionPath, "LLVM/bin/clang-format.darwin"))) { - installedPlatform = "darwin"; - } else if (checkFileExistsSync(path.join(extensionPath, "LLVM/bin/clang-format"))) { - installedPlatform = "linux"; - } - return installedPlatform; -} - /** Check if the core binaries exists in extension's installation folder */ export async function checkInstallBinariesExist(): Promise { if (!checkInstallLockFile()) { diff --git a/Extension/src/main.ts b/Extension/src/main.ts index 9512f0f2ce..611f98eb5f 100644 --- a/Extension/src/main.ts +++ b/Extension/src/main.ts @@ -75,38 +75,71 @@ export async function activate(context: vscode.ExtensionContext): Promise = new PersistentState("CPP.promptForMacArchictureMismatch", true); + + // Read archictures of binaries from install.lock + const fileContents: string = await util.readFileText(util.getInstallLockPath()); + let installedPlatformAndArchitecture: util.InstallLockContents; + // Just in case we're debugging with an existing install.lock that is empty, assume current platform if empty. + if (fileContents.length === 0) { + installedPlatformAndArchitecture = { + platform: process.platform, + architecture: arch + }; + } else { + installedPlatformAndArchitecture = JSON.parse(fileContents); + } // Check the main binaries files to declare if the extension has been installed successfully. - if (installedPlatform && process.platform !== installedPlatform) { + if (process.platform !== installedPlatformAndArchitecture.platform + || (arch !== installedPlatformAndArchitecture.architecture && (arch !== "x64" || installedPlatformAndArchitecture.architecture !== 'x86' || process.platform !== "win32"))) { // Check if the correct offline/insiders vsix is installed on the correct platform. const platformInfo: PlatformInformation = await PlatformInformation.GetPlatformInformation(); const vsixName: string = vsixNameForPlatform(platformInfo); - errMsg = localize("native.binaries.not.supported", "This {0} version of the extension is incompatible with your OS. Please download and install the \"{1}\" version of the extension.", GetOSName(installedPlatform), vsixName); - const downloadLink: string = localize("download.button", "Go to Download Page"); - vscode.window.showErrorMessage(errMsg, downloadLink).then(async (selection) => { - if (selection === downloadLink) { - vscode.env.openExternal(vscode.Uri.parse(releaseDownloadUrl)); - } - }); - } else if (!(await util.checkInstallBinariesExist())) { - errMsg = localize("extension.installation.failed", "The C/C++ extension failed to install successfully. You will need to repair or reinstall the extension for C/C++ language features to function properly."); - const reload: string = localize("remove.extension", "Attempt to Repair"); - vscode.window.showErrorMessage(errMsg, reload).then(async (value?: string) => { - if (value === reload) { - await util.removeInstallLockFile(); - vscode.commands.executeCommand("workbench.action.reloadWindow"); - } - }); - } else if (!(await util.checkInstallJsonsExist())) { - // Check the Json files to declare if the extension has been installed successfully. - errMsg = localize("jason.files.missing", "The C/C++ extension failed to install successfully. You will need to reinstall the extension for C/C++ language features to function properly."); const downloadLink: string = localize("download.button", "Go to Download Page"); - vscode.window.showErrorMessage(errMsg, downloadLink).then(async (selection) => { - if (selection === downloadLink) { - vscode.env.openExternal(vscode.Uri.parse(releaseDownloadUrl)); + if (installedPlatformAndArchitecture.platform === 'darwin' && installedPlatformAndArchitecture.architecture === "x64" && arch === "arm64") { + if (promptForMacArchictureMismatch.Value) { + // Display a message specifically referring the user to the ARM64 Mac build on ARM64 Mac. + errMsg = localize("native.binaries.mismatch.osx", "This Intel version of the extension has been installed. Since you are on an Apple Silicon Mac, we recommend installing the Apple Silicon version of the extension."); + promptForMacArchictureMismatch.Value = false; + vscode.window.showErrorMessage(errMsg, downloadLink).then(async (selection) => { + if (selection === downloadLink) { + vscode.env.openExternal(vscode.Uri.parse(releaseDownloadUrl)); + } + }); } - }); + } else { + // Reset the persistent boolean tracking whether to warn the user of architecture mismatch on OSX. + promptForMacArchictureMismatch.Value = true; + errMsg = localize("native.binaries.not.supported", "This {0} version of the extension is incompatible with your OS. Please download and install the \"{1}\" version of the extension.", GetOSName(installedPlatformAndArchitecture.platform), vsixName); + vscode.window.showErrorMessage(errMsg, downloadLink).then(async (selection) => { + if (selection === downloadLink) { + vscode.env.openExternal(vscode.Uri.parse(releaseDownloadUrl)); + } + }); + } + } else { + // Reset the persistent boolean tracking whether to warn the user of architecture mismatch on OSX. + promptForMacArchictureMismatch.Value = true; + if (!(await util.checkInstallBinariesExist())) { + errMsg = localize("extension.installation.failed", "The C/C++ extension failed to install successfully. You will need to repair or reinstall the extension for C/C++ language features to function properly."); + const reload: string = localize("remove.extension", "Attempt to Repair"); + vscode.window.showErrorMessage(errMsg, reload).then(async (value?: string) => { + if (value === reload) { + await util.removeInstallLockFile(); + vscode.commands.executeCommand("workbench.action.reloadWindow"); + } + }); + } else if (!(await util.checkInstallJsonsExist())) { + // Check the Json files to declare if the extension has been installed successfully. + errMsg = localize("jason.files.missing", "The C/C++ extension failed to install successfully. You will need to reinstall the extension for C/C++ language features to function properly."); + const downloadLink: string = localize("download.button", "Go to Download Page"); + vscode.window.showErrorMessage(errMsg, downloadLink).then(async (selection) => { + if (selection === downloadLink) { + vscode.env.openExternal(vscode.Uri.parse(releaseDownloadUrl)); + } + }); + } } return cppTools; @@ -219,7 +252,7 @@ async function onlineInstallation(info: PlatformInformation): Promise { await rewriteManifest(); setInstallationStage('touchInstallLockFile'); - await touchInstallLockFile(); + await touchInstallLockFile(info); setInstallationStage('postInstall'); await postInstall(info); @@ -311,8 +344,8 @@ function removeUnnecessaryFile(): Promise { return Promise.resolve(); } -function touchInstallLockFile(): Promise { - return util.touchInstallLockFile(); +function touchInstallLockFile(info: PlatformInformation): Promise { + return util.touchInstallLockFile(info); } function handleError(error: any): void {