diff --git a/Extension/CHANGELOG.md b/Extension/CHANGELOG.md index 502b51e56c..d33b5923c7 100644 --- a/Extension/CHANGELOG.md +++ b/Extension/CHANGELOG.md @@ -1,5 +1,13 @@ # C/C++ for Visual Studio Code Change Log +## Version 1.1.3: December 3, 2020 +### Bug Fixes +* Disable the "join Insiders" prompt for Linux CodeSpaces. [#6491](https://github.com/microsoft/vscode-cpptools/issues/6491) +* Fix "shell" tasks giving error "Cannot read property `includes` of undefined". [#6538](https://github.com/microsoft/vscode-cpptools/issues/6538) +* Fix various task variables not getting resolved with `cppbuild` tasks. [#6538](https://github.com/microsoft/vscode-cpptools/issues/6538) +* Fix warnings not appearing with `cppbuild` tasks. [#6556](https://github.com/microsoft/vscode-cpptools/issues/6556) +* Fix endless CPU/memory usage if the cpptools process crashes. [#6603](https://github.com/microsoft/vscode-cpptools/issues/6603) + ## Version 1.1.2: November 17, 2020 ### Bug Fix * Fix resolution of `${fileDirname}` with `cppbuild` tasks. [#6386](https://github.com/microsoft/vscode-cpptools/issues/6386) diff --git a/Extension/package.json b/Extension/package.json index 000f3f27e1..6c538fbbd6 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.1.2", + "version": "1.1.3", "publisher": "ms-vscode", "icon": "LanguageCCPP_color_128x.png", "readme": "README.md", @@ -2347,7 +2347,7 @@ "@types/plist": "^3.0.2", "@types/semver": "^7.1.0", "@types/tmp": "^0.1.0", - "@types/vscode": "1.44.0", + "@types/vscode": "1.49.0", "@types/webpack": "^4.39.0", "@types/which": "^1.3.2", "@types/yauzl": "^2.9.1", diff --git a/Extension/src/Debugger/configurationProvider.ts b/Extension/src/Debugger/configurationProvider.ts index 3142fe69da..a1e09cf090 100644 --- a/Extension/src/Debugger/configurationProvider.ts +++ b/Extension/src/Debugger/configurationProvider.ts @@ -150,12 +150,16 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider { } // Filter out build tasks that don't match the currently selected debug configuration type. buildTasks = buildTasks.filter((task: CppBuildTask) => { + const command: string = task.definition.command as string; + if (!command) { + return false; + } if (defaultConfig.name.startsWith("(Windows) ")) { - if ((task.definition.command as string).includes("cl.exe")) { + if (command.includes("cl.exe")) { return true; } } else { - if (!(task.definition.command as string).includes("cl.exe")) { + if (!command.includes("cl.exe")) { return true; } } diff --git a/Extension/src/Debugger/extension.ts b/Extension/src/Debugger/extension.ts index 2b525a722b..012c1d2563 100644 --- a/Extension/src/Debugger/extension.ts +++ b/Extension/src/Debugger/extension.ts @@ -50,7 +50,7 @@ export function initialize(context: vscode.ExtensionContext): void { // Not enabled because we do not react to single-file mode correctly yet. // We get an ENOENT when the user's c_cpp_properties.json is attempted to be parsed. // The DefaultClient will also have its configuration accessed, but since it doesn't exist it errors out. - vscode.window.showErrorMessage('This command is not yet available for single-file mode.'); + vscode.window.showErrorMessage(localize("single_file_mode_not_available", "This command is not available for single-file mode.")); return Promise.resolve(); } diff --git a/Extension/src/LanguageServer/clientCollection.ts b/Extension/src/LanguageServer/clientCollection.ts index f0b8ae2349..aa15f9edea 100644 --- a/Extension/src/LanguageServer/clientCollection.ts +++ b/Extension/src/LanguageServer/clientCollection.ts @@ -91,7 +91,11 @@ export class ClientCollection { } public forEach(callback: (client: cpptools.Client) => void): void { - this.languageClients.forEach(callback); + // Copy this.languageClients to languageClients to avoid an infinite foreach loop + // when callback modifies this.languageClients (e.g. when cpptools crashes). + const languageClients: cpptools.Client[] = []; + this.languageClients.forEach(client => languageClients.push(client)); + languageClients.forEach(callback); } public checkOwnership(client: cpptools.Client, document: vscode.TextDocument): boolean { diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 387790dd34..418489ec0e 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -246,7 +246,9 @@ export class CppProperties { } private onConfigurationsChanged(): void { - this.configurationsChanged.fire(this.Configurations); + if (this.Configurations) { + this.configurationsChanged.fire(this.Configurations); + } } private onSelectionChanged(): void { diff --git a/Extension/src/LanguageServer/cppBuildTaskProvider.ts b/Extension/src/LanguageServer/cppBuildTaskProvider.ts index 75d7d8a6cb..78b250a555 100644 --- a/Extension/src/LanguageServer/cppBuildTaskProvider.ts +++ b/Extension/src/LanguageServer/cppBuildTaskProvider.ts @@ -4,7 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import * as path from 'path'; import { - TaskDefinition, Task, TaskGroup, WorkspaceFolder, ShellExecution, Uri, workspace, + TaskDefinition, Task, TaskGroup, ShellExecution, Uri, workspace, TaskProvider, TaskScope, CustomExecution, ProcessExecution, TextEditor, Pseudoterminal, EventEmitter, Event, TerminalDimensions, window } from 'vscode'; import * as os from 'os'; @@ -15,6 +15,10 @@ import * as configs from './configurations'; import * as ext from './extension'; import * as cp from "child_process"; import { OtherSettings } from './settings'; +import * as nls from 'vscode-nls'; + +nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); +const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export interface CppBuildTaskDefinition extends TaskDefinition { type: string; @@ -156,7 +160,7 @@ export class CppBuildTaskProvider implements TaskProvider { if (!definition) { const taskLabel: string = ((appendSourceToName && !compilerPathBase.startsWith(CppBuildTaskProvider.CppBuildSourceStr)) ? - CppBuildTaskProvider.CppBuildSourceStr + ": " : "") + compilerPathBase + " build active file"; + CppBuildTaskProvider.CppBuildSourceStr + ": " : "") + compilerPathBase + " " + localize("build_active_file", "build active file"); const filePath: string = path.join('${fileDirname}', '${fileBasenameNoExtension}'); const isWindows: boolean = os.platform() === 'win32'; let args: string[] = isCl ? ['/Zi', '/EHsc', '/Fe:', filePath + '.exe', '${file}'] : ['-g', '${file}', '-o', filePath + (isWindows ? '.exe' : '')]; @@ -185,13 +189,13 @@ export class CppBuildTaskProvider implements TaskProvider { const scope: TaskScope = TaskScope.Workspace; const task: CppBuildTask = new Task(definition, scope, definition.label, CppBuildTaskProvider.CppBuildSourceStr, - new CustomExecution(async (): Promise => + new CustomExecution(async (resolvedDefinition: TaskDefinition): Promise => // When the task is executed, this callback will run. Here, we setup for running the task. - new CustomBuildTaskTerminal(resolvedcompilerPath, definition ? definition.args : [], definition ? definition.options : undefined) + new CustomBuildTaskTerminal(resolvedcompilerPath, resolvedDefinition.args, resolvedDefinition.options) ), isCl ? '$msCompile' : '$gcc'); task.group = TaskGroup.Build; - task.detail = detail ? detail : "compiler: " + resolvedcompilerPath; + task.detail = detail ? detail : localize("compiler_details", "compiler:") + " " + resolvedcompilerPath; return task; }; @@ -200,6 +204,9 @@ export class CppBuildTaskProvider implements TaskProvider { const rawJson: any = await this.getRawTasksJson(); const rawTasksJson: any = (!rawJson.tasks) ? new Array() : rawJson.tasks; const buildTasksJson: CppBuildTask[] = rawTasksJson.map((task: any) => { + if (!task.label) { + return null; + } const definition: CppBuildTaskDefinition = { type: task.type, label: task.label, @@ -211,7 +218,7 @@ export class CppBuildTaskProvider implements TaskProvider { cppBuildTask.detail = task.detail; return cppBuildTask; }); - return buildTasksJson; + return buildTasksJson.filter((task: CppBuildTask) => task !== null); } public async ensureBuildTaskExists(taskLabel: string): Promise { @@ -252,7 +259,7 @@ export class CppBuildTaskProvider implements TaskProvider { ...selectedTask.definition, problemMatcher: selectedTask.problemMatchers, group: { kind: "build", "isDefault": true }, - detail: "Generated task by Debugger" + detail: localize("task_generated_by_debugger", "Task generated by Debugger.") }; rawTasksJson.tasks.push(newTask); } @@ -333,7 +340,7 @@ class CustomBuildTaskTerminal implements Pseudoterminal { async open(_initialDimensions: TerminalDimensions | undefined): Promise { telemetry.logLanguageServerEvent("cppBuildTaskStarted"); // At this point we can start using the terminal. - this.writeEmitter.fire(`Starting build...${this.endOfLine}`); + this.writeEmitter.fire(localize("starting_build", "Starting build...") + this.endOfLine); await this.doBuild(); } @@ -343,16 +350,16 @@ class CustomBuildTaskTerminal implements Pseudoterminal { private async doBuild(): Promise { // Do build. - let activeCommand: string = util.resolveVariables(this.command, this.AdditionalEnvironment); + let activeCommand: string = util.resolveVariables(this.command); this.args.forEach(value => { - let temp: string = util.resolveVariables(value, this.AdditionalEnvironment); + let temp: string = util.resolveVariables(value); if (temp && temp.includes(" ")) { temp = "\"" + temp + "\""; } activeCommand = activeCommand + " " + temp; }); if (this.options?.cwd) { - this.options.cwd = util.resolveVariables(this.options.cwd, this.AdditionalEnvironment); + this.options.cwd = util.resolveVariables(this.options.cwd); } const splitWriteEmitter = (lines: string | Buffer) => { @@ -363,16 +370,34 @@ class CustomBuildTaskTerminal implements Pseudoterminal { try { const result: number = await new Promise((resolve, reject) => { cp.exec(activeCommand, this.options, (_error, stdout, _stderr) => { + const dot: string = (stdout || _stderr) ? ":" : "."; if (_error) { telemetry.logLanguageServerEvent("cppBuildTaskError"); - const dot: string = (stdout || _stderr) ? ":" : "."; - this.writeEmitter.fire(`Build finished with error${dot}${this.endOfLine}`); - splitWriteEmitter(stdout); - splitWriteEmitter(_stderr); + this.writeEmitter.fire(localize("build_finished_with_error", "Build finished with errors(s)") + dot + this.endOfLine); + if (stdout) { + splitWriteEmitter(stdout); // cl.exe + } else if (_stderr) { + splitWriteEmitter(_stderr); // gcc/clang + } else { + splitWriteEmitter(_error.message); // e.g. command executable not found + } resolve(-1); - } else { + return; + } else if (_stderr && !stdout) { // gcc/clang + telemetry.logLanguageServerEvent("cppBuildTaskWarnings"); + this.writeEmitter.fire(localize("build_finished_with_warnings", "Build finished with warning(s)") + dot + this.endOfLine); + splitWriteEmitter(_stderr); + resolve(0); + } else if (stdout && stdout.includes("warning C")) { // cl.exe + telemetry.logLanguageServerEvent("cppBuildTaskWarnings"); + this.writeEmitter.fire(localize("build_finished_with_warnings", "Build finished with warning(s)") + dot + this.endOfLine); splitWriteEmitter(stdout); - this.writeEmitter.fire(`Build finished successfully.${this.endOfLine}`); + resolve(0); + } else { + if (stdout) { + splitWriteEmitter(stdout); // cl.exe + } + this.writeEmitter.fire(localize("build finished successfully", "Build finished successfully.") + this.endOfLine); resolve(0); } }); @@ -382,23 +407,4 @@ class CustomBuildTaskTerminal implements Pseudoterminal { this.closeEmitter.fire(-1); } } - - private get AdditionalEnvironment(): { [key: string]: string | string[] } | undefined { - const editor: TextEditor | undefined = window.activeTextEditor; - if (!editor) { - return undefined; - } - const fileDir: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(editor.document.uri); - if (!fileDir) { - window.showErrorMessage('This command is not yet available for single-file mode.'); - return undefined; - } - const file: string = editor.document.fileName; - return { - "file": file, - "fileDirname": path.parse(file).dir, - "fileBasenameNoExtension": path.parse(file).name, - "workspaceFolder": fileDir.uri.fsPath - }; - } } diff --git a/Extension/src/LanguageServer/referencesTreeDataProvider.ts b/Extension/src/LanguageServer/referencesTreeDataProvider.ts index 4bcb6985f4..2dd5b90463 100644 --- a/Extension/src/LanguageServer/referencesTreeDataProvider.ts +++ b/Extension/src/LanguageServer/referencesTreeDataProvider.ts @@ -13,8 +13,8 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle(); export class ReferencesTreeDataProvider implements vscode.TreeDataProvider { private referencesModel: ReferencesModel | undefined; - private readonly _onDidChangeTreeData = new vscode.EventEmitter(); - readonly onDidChangeTreeData: vscode.Event; + private readonly _onDidChangeTreeData = new vscode.EventEmitter(); + readonly onDidChangeTreeData: vscode.Event; constructor() { this.onDidChangeTreeData = this._onDidChangeTreeData.event; diff --git a/Extension/yarn.lock b/Extension/yarn.lock index 6a9101a887..5eab2fac9e 100644 --- a/Extension/yarn.lock +++ b/Extension/yarn.lock @@ -204,10 +204,10 @@ dependencies: source-map "^0.6.1" -"@types/vscode@1.44.0": - version "1.44.0" - resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.44.0.tgz#62ecfe3d0e38942fce556574da54ee1013c775b7" - integrity sha512-WJZtZlinE3meRdH+I7wTsIhpz/GLhqEQwmPGeh4s1irWLwMzCeTV8WZ+pgPTwrDXoafVUWwo1LiZ9HJVHFlJSQ== +"@types/vscode@1.49.0": + version "1.49.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.49.0.tgz#f3731d97d7e8b2697510eb26f6e6d04ee8c17352" + integrity sha512-wfNQmLmm1VdMBr6iuNdprWmC1YdrgZ9dQzadv+l2eSjJlElOdJw8OTm4RU4oGTBcfvG6RZI2jOcppkdSS18mZw== "@types/webpack-sources@*": version "0.1.6"