Compare commits
124
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
294a751210 | ||
|
|
f6cc1fbd03 | ||
|
|
e0bd199546 | ||
|
|
bc914dc69c | ||
|
|
b2f5c605c4 | ||
|
|
d41e14fd86 | ||
|
|
35c0fd37e2 | ||
|
|
99259bf194 | ||
|
|
10c1e1b606 | ||
|
|
fcdb6efbab | ||
|
|
bd5f6c0462 | ||
|
|
9c45e4d2bc | ||
|
|
31f6b66e6b | ||
|
|
4404bf76a7 | ||
|
|
133896eb4c | ||
|
|
376562ee75 | ||
|
|
668b33c1e5 | ||
|
|
6317e27e45 | ||
|
|
223a3e2cbe | ||
|
|
5b000d939b | ||
|
|
b6b11027da | ||
|
|
e22017f6df | ||
|
|
a2f6a72aed | ||
|
|
593ed07c56 | ||
|
|
40f7455acd | ||
|
|
adf4681ef8 | ||
|
|
a53dac8bef | ||
|
|
04c60c288a | ||
|
|
fa71378712 | ||
|
|
36a78e89e1 | ||
|
|
364ba2789c | ||
|
|
8d5fc737b1 | ||
|
|
1172405856 | ||
|
|
b013b10b64 | ||
|
|
c6ff700da2 | ||
|
|
936e7e3b15 | ||
|
|
e7e2e3983f | ||
|
|
80a6d16f83 | ||
|
|
e5a976f229 | ||
|
|
70fbfd71e1 | ||
|
|
5b3b56c694 | ||
|
|
777ff002f1 | ||
|
|
8de8679b3e | ||
|
|
e02269ba89 | ||
|
|
7852d4587c | ||
|
|
a1cb1d8bec | ||
|
|
e10273d4a5 | ||
|
|
0ae864f1d7 | ||
|
|
58e66e8aac | ||
|
|
cf11bb5666 | ||
|
|
777af10222 | ||
|
|
ca3dcdbc8f | ||
|
|
ff2fb7eb65 | ||
|
|
a1fa61e73f | ||
|
|
42f7302d6b | ||
|
|
af326bd298 | ||
|
|
b50bf604fd | ||
|
|
f4f3d8ca8b | ||
|
|
303b838a41 | ||
|
|
36cea36784 | ||
|
|
e4f859dd56 | ||
|
|
97c5f14bd5 | ||
|
|
c4003c07e8 | ||
|
|
c27806e763 | ||
|
|
7cfb2d3316 | ||
|
|
9a03b747c6 | ||
|
|
989cee4414 | ||
|
|
c357224407 | ||
|
|
a636c87f3e | ||
|
|
471cdfecf8 | ||
|
|
97128122b0 | ||
|
|
006ebff619 | ||
|
|
1458694ed6 | ||
|
|
896024ba9c | ||
|
|
779bb080c1 | ||
|
|
97df273fc1 | ||
|
|
7037b070ce | ||
|
|
205e63772c | ||
|
|
37950ffb2d | ||
|
|
23b0672837 | ||
|
|
7bafd64cfe | ||
|
|
dead10ac8a | ||
|
|
ce20613f24 | ||
|
|
86c6c10f18 | ||
|
|
db6e0cb5cf | ||
|
|
f9e067f5d1 | ||
|
|
b137df0bcd | ||
|
|
827db55084 | ||
|
|
8a2324daaa | ||
|
|
bdd3541f28 | ||
|
|
3cc2650dfa | ||
|
|
fdf9b5bfe0 | ||
|
|
fdd71bc963 | ||
|
|
1d266a9c0e | ||
|
|
f818529a08 | ||
|
|
41a05a90c8 | ||
|
|
e59c6ca759 | ||
|
|
287ee3961b | ||
|
|
8a8fd883ac | ||
|
|
4fe56500a9 | ||
|
|
03911153f9 | ||
|
|
acea31e572 | ||
|
|
bf21e01764 | ||
|
|
30f1361d23 | ||
|
|
03933b0a74 | ||
|
|
fc8eb8632f | ||
|
|
f6722bc8ff | ||
|
|
894db52405 | ||
|
|
abf384619d | ||
|
|
ad5d6de4ea | ||
|
|
153e232f2d | ||
|
|
bcd4a7f025 | ||
|
|
3c3d463a81 | ||
|
|
92691929ed | ||
|
|
86a41c9021 | ||
|
|
a71c90c140 | ||
|
|
1d28851ef7 | ||
|
|
1aced54699 | ||
|
|
a8cf39c8b4 | ||
|
|
e037b95926 | ||
|
|
af7f6ce52e | ||
|
|
9a18982440 | ||
|
|
35bf4c8b0f | ||
|
|
23446558cf |
@@ -1,4 +1,2 @@
|
||||
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
|
||||
always-auth=true
|
||||
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
|
||||
ignore-scripts=true
|
||||
always-auth=true
|
||||
Generated
+3
-3
@@ -4125,9 +4125,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha1-d31z1yqS+OxNLkEOtHNSpWuOg0A=",
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
"integrity": "sha1-KEdKFZ07nRHvYgUKFO1g5N9tYbw=",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
||||
@@ -66,11 +66,6 @@ jobs:
|
||||
# run: yarn test --scenario=MultirootDeadlockTest
|
||||
# working-directory: Extension
|
||||
|
||||
# - name: Run E2E IntelliSense features tests
|
||||
# if: ${{ inputs.platform == 'windows' }}
|
||||
# run: yarn test --scenario=RunWithoutDebugging
|
||||
# working-directory: Extension
|
||||
|
||||
# NOTE: For mac/linux run the tests with xvfb-action for UI support.
|
||||
# Another way to start xvfb https://github.com/microsoft/vscode-test/blob/master/sample/azure-pipelines.yml
|
||||
|
||||
@@ -88,10 +83,3 @@ jobs:
|
||||
# run: yarn test --scenario=MultirootDeadlockTest
|
||||
# working-directory: Extension
|
||||
|
||||
# - name: Run E2E IntelliSense features tests (xvfb)
|
||||
# if: ${{ inputs.platform == 'mac' || inputs.platform == 'linux' }}
|
||||
# uses: coactions/setup-xvfb@v1
|
||||
# with:
|
||||
# run: yarn test --scenario=RunWithoutDebugging
|
||||
# working-directory: Extension
|
||||
|
||||
|
||||
+4
-10
@@ -107,14 +107,8 @@ extends:
|
||||
fi
|
||||
retryCountOnTaskFailure: 3
|
||||
|
||||
- script: yarn install --frozen-lockfile
|
||||
displayName: Install dependencies with yarn
|
||||
workingDirectory: $(Build.SourcesDirectory)\Extension
|
||||
|
||||
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
|
||||
displayName: Verify vsce-sign binary exists
|
||||
workingDirectory: $(Build.SourcesDirectory)\Extension
|
||||
|
||||
- script: npx vsce package --yarn -o $(Build.ArtifactStagingDirectory)\Extension\cpptools.vsix
|
||||
- script: |
|
||||
cd $(Build.SourcesDirectory)\Extension
|
||||
npx @vscode/[email protected] package --yarn -o $(Build.ArtifactStagingDirectory)\Extension\cpptools.vsix
|
||||
name: ProcessRunner_12
|
||||
displayName: Run VSCE to package vsix
|
||||
workingDirectory: $(Build.SourcesDirectory)\Extension
|
||||
|
||||
@@ -59,24 +59,13 @@ jobs:
|
||||
- script: mkdir $(Build.ArtifactStagingDirectory)\vsix
|
||||
displayName: Create Staging Directory
|
||||
|
||||
- script: npm install --no-save --ignore-scripts=false --include=optional --force @vscode/[email protected]
|
||||
displayName: Install vsce
|
||||
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
|
||||
- script: npm rebuild @vscode/vsce-sign --ignore-scripts=false
|
||||
displayName: Rebuild vsce-sign binary
|
||||
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
|
||||
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
|
||||
displayName: Verify vsce-sign binary exists
|
||||
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
|
||||
- script: npx vsce package -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix
|
||||
- script: |
|
||||
cd $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
npx @vscode/[email protected] package -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix
|
||||
displayName: Run VSCE to package vsix
|
||||
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
|
||||
# sign the vsix
|
||||
- script: npx vsce generate-manifest -i $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.manifest
|
||||
- script: npx @vscode/[email protected] generate-manifest -i $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.vsix -o $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.manifest
|
||||
displayName: generate manifest
|
||||
workingDirectory: $(Build.SourcesDirectory)\${{ parameters.srcDir }}
|
||||
- script: copy $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.manifest $(Build.ArtifactStagingDirectory)\vsix\${{ parameters.vsixName }}.signature.p7s
|
||||
|
||||
@@ -31,16 +31,8 @@ jobs:
|
||||
$aadToken = az account get-access-token --query accessToken --resource $(AzureGuid) -o tsv
|
||||
Write-Host "##vso[task.setvariable variable=AAD_TOKEN;issecret=true]$aadToken"
|
||||
|
||||
- script: npm install --no-save --ignore-scripts=false --include=optional --force @vscode/[email protected]
|
||||
displayName: Install vsce
|
||||
|
||||
- script: npm rebuild @vscode/vsce-sign --ignore-scripts=false
|
||||
displayName: Rebuild vsce-sign binary
|
||||
|
||||
- script: if not exist node_modules\@vscode\vsce-sign\bin\vsce-sign.exe (echo Missing vsce-sign.exe && exit 1)
|
||||
displayName: Verify vsce-sign binary exists
|
||||
|
||||
- script: npx vsce publish --skip-duplicate -i $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.vsix --manifestPath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.manifest --signaturePath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.signature.p7s
|
||||
- script: |
|
||||
npx @vscode/[email protected] publish --skip-duplicate -i $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.vsix --manifestPath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.manifest --signaturePath $(Build.StagingDirectory)\vsix\${{ parameters.vsixName }}.signature.p7s
|
||||
displayName: Publish to Marketplace
|
||||
env:
|
||||
VSCE_PAT: $(AAD_TOKEN)
|
||||
|
||||
+1
-3
@@ -1,4 +1,2 @@
|
||||
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
|
||||
always-auth=true
|
||||
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
|
||||
ignore-scripts=true
|
||||
always-auth=true
|
||||
@@ -1,113 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import { cp, readdir, rm, stat } from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { $args, $root, green, heading, note } from './common';
|
||||
|
||||
const extensionPrefix = 'ms-vscode.cpptools-';
|
||||
const foldersToCopy = ['bin', 'debugAdapters', 'LLVM'] as const;
|
||||
|
||||
type InstalledExtension = {
|
||||
path: string;
|
||||
version: number[];
|
||||
modified: number;
|
||||
};
|
||||
|
||||
function compareVersions(left: number[], right: number[]): number {
|
||||
const maxLength: number = Math.max(left.length, right.length);
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
const diff: number = (left[i] ?? 0) - (right[i] ?? 0);
|
||||
if (diff !== 0) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function tryParseVersion(folderName: string): number[] | undefined {
|
||||
if (!folderName.startsWith(extensionPrefix)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const versionText: string | undefined = folderName.substring(extensionPrefix.length).match(/^\d+\.\d+\.\d+/)?.[0];
|
||||
return versionText?.split('.').map(each => Number(each));
|
||||
}
|
||||
|
||||
async function getInstalledExtensions(root: string): Promise<InstalledExtension[]> {
|
||||
try {
|
||||
const entries = await readdir(root, { withFileTypes: true });
|
||||
const candidates: Promise<InstalledExtension | undefined>[] = entries.map(async (entry) => {
|
||||
if (!entry.isDirectory()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const version: number[] | undefined = tryParseVersion(entry.name);
|
||||
if (!version) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const extensionPath: string = join(root, entry.name);
|
||||
for (const folder of foldersToCopy) {
|
||||
const info = await stat(join(extensionPath, folder)).catch(() => undefined);
|
||||
if (!info?.isDirectory()) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const info = await stat(extensionPath);
|
||||
return {
|
||||
path: extensionPath,
|
||||
version,
|
||||
modified: info.mtimeMs
|
||||
};
|
||||
});
|
||||
|
||||
const found = await Promise.all(candidates);
|
||||
return found.filter((entry): entry is InstalledExtension => entry !== undefined);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function findLatestInstalledExtension(providedPath?: string): Promise<string> {
|
||||
if (providedPath) {
|
||||
return providedPath;
|
||||
}
|
||||
|
||||
const searchRoots: string[] = [
|
||||
join(homedir(), '.vscode', 'extensions'),
|
||||
join(homedir(), '.vscode-insiders', 'extensions'),
|
||||
join(homedir(), '.vscode-server', 'extensions'),
|
||||
join(homedir(), '.vscode-server-insiders', 'extensions')
|
||||
];
|
||||
|
||||
const installed: InstalledExtension[] = (await Promise.all(searchRoots.map(each => getInstalledExtensions(each)))).flat();
|
||||
if (!installed.length) {
|
||||
throw new Error(`Unable to find an installed C/C++ extension under ${searchRoots.join(' or ')}.`);
|
||||
}
|
||||
|
||||
installed.sort((left, right) => compareVersions(right.version, left.version) || right.modified - left.modified);
|
||||
return installed[0].path;
|
||||
}
|
||||
|
||||
export async function main(sourcePath = $args[0]) {
|
||||
console.log(heading('Copy installed extension binaries'));
|
||||
|
||||
const installedExtensionPath: string = await findLatestInstalledExtension(sourcePath);
|
||||
note(`Using installed extension at ${installedExtensionPath}`);
|
||||
|
||||
for (const folder of foldersToCopy) {
|
||||
const source: string = join(installedExtensionPath, folder);
|
||||
const destination: string = join($root, folder);
|
||||
|
||||
console.log(`Copying ${green(folder)} from ${source}`);
|
||||
await rm(destination, { recursive: true, force: true });
|
||||
await cp(source, destination, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
note(`Copied installed binaries into ${$root}`);
|
||||
}
|
||||
Vendored
-4
@@ -97,10 +97,6 @@
|
||||
"label": "MultirootDeadlockTest ",
|
||||
"value": "${workspaceFolder}/test/scenarios/MultirootDeadlockTest/assets/test.code-workspace"
|
||||
},
|
||||
{
|
||||
"label": "RunWithoutDebugging ",
|
||||
"value": "${workspaceFolder}/test/scenarios/RunWithoutDebugging/assets/"
|
||||
},
|
||||
{
|
||||
"label": "SimpleCppProject ",
|
||||
"value": "${workspaceFolder}/test/scenarios/SimpleCppProject/assets/simpleCppProject.code-workspace"
|
||||
|
||||
@@ -35,7 +35,6 @@ eslint.config.js
|
||||
gulpfile.js
|
||||
localized_string_ids.h
|
||||
readme.developer.md
|
||||
Reinstalling the Extension.md
|
||||
test.tsconfig.json
|
||||
translations_auto_pr.js
|
||||
tsconfig.json
|
||||
|
||||
+3
-16
@@ -1,22 +1,9 @@
|
||||
# C/C++ for Visual Studio Code Changelog
|
||||
|
||||
## Version 1.32.0: April 14, 2026
|
||||
### New Feature
|
||||
* Add support for run without debugging. [#1201](https://github.com/microsoft/vscode-cpptools/issues/1201)
|
||||
|
||||
### Enhancements
|
||||
* Add a `C_Cpp.doxygen.generateOnCodeAction` setting to allow disabling of Doxygen generation code actions. [#14341](https://github.com/microsoft/vscode-cpptools/issues/14341)
|
||||
* Improve wildcard matching with the debugger natvis. [MIEngine#1162](https://github.com/microsoft/MIEngine/issues/1162)
|
||||
* Add support for `HideRawView` with the debugger natvis. [MIEngine#1458](https://github.com/microsoft/MIEngine/issues/1458)
|
||||
|
||||
## Version 1.31.5: April 20, 2026
|
||||
### Bug Fixes
|
||||
* Fix high CPU usage caused by repeated calls to `selectChatModels`. [#14168](https://github.com/microsoft/vscode-cpptools/issues/14168), [#14211](https://github.com/microsoft/vscode-cpptools/issues/14211), [#14241](https://github.com/microsoft/vscode-cpptools/issues/14241)
|
||||
* Fix the MSVC developer environment not working if `UCRTVersion` isn't found, and update the walkthrough instructions for installing MSVC. [#14352](https://github.com/microsoft/vscode-cpptools/issues/14352)
|
||||
* Fix Copilot hover taking too many premium requests. [#14372](https://github.com/microsoft/vscode-cpptools/issues/14372)
|
||||
* Fix null pointers being expandable for variables in the debugger. [MIEngine#698](https://github.com/microsoft/MIEngine/issues/698)
|
||||
* Fix recursive `{this}` evaluation with the debugger natvis. [MIEngine#1391](https://github.com/microsoft/MIEngine/issues/1391)
|
||||
* Update clang-tidy and clang-format from 22.1.1 to 22.1.3 (bug fixes).
|
||||
* Fix a bug with semantic colorization of operators.
|
||||
* Fix `Reinstalling the Extension.md` not being found. [#14389](https://github.com/microsoft/vscode-cpptools/issues/14389)
|
||||
* Fix the `C/C++ DevTools` extension language service tools not working after the `C/C++` extension updates via `Restart Extensions`. [#14392](https://github.com/microsoft/vscode-cpptools/issues/14392)
|
||||
|
||||
## Version 1.31.4: March 31, 2026
|
||||
### Bug Fix
|
||||
|
||||
@@ -1250,7 +1250,7 @@ SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
@xmldom/xmldom 0.8.12 - MIT
|
||||
@xmldom/xmldom 0.8.11 - MIT
|
||||
https://github.com/xmldom/xmldom
|
||||
|
||||
Copyright 2019 - present Christopher J. Brody and other contributors
|
||||
@@ -1510,7 +1510,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
brace-expansion 1.1.13 - MIT
|
||||
brace-expansion 1.1.12 - MIT
|
||||
https://github.com/juliangruber/brace-expansion
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <[email protected]>
|
||||
@@ -1542,7 +1542,7 @@ SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
brace-expansion 2.0.3 - MIT
|
||||
brace-expansion 2.0.2 - MIT
|
||||
https://github.com/juliangruber/brace-expansion
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <[email protected]>
|
||||
@@ -1642,7 +1642,7 @@ SOFTWARE.
|
||||
chokidar 3.6.0 - MIT
|
||||
https://github.com/paulmillr/chokidar
|
||||
|
||||
(c) Paul Miller
|
||||
(c) Paul Miller <https://paulmillr.com>
|
||||
Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker
|
||||
|
||||
The MIT License (MIT)
|
||||
@@ -3018,7 +3018,7 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
picomatch 2.3.2 - MIT
|
||||
picomatch 2.3.1 - MIT
|
||||
https://github.com/micromatch/picomatch
|
||||
|
||||
Copyright (c) 2017-present, Jon Schlinkert
|
||||
@@ -3183,7 +3183,7 @@ readdirp 3.6.0 - MIT
|
||||
https://github.com/paulmillr/readdirp
|
||||
|
||||
Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com)
|
||||
Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller ( https://paulmillr.com )
|
||||
Copyright (c) 2012-2019 Thorsten Lorenz, Paul Miller <https://paulmillr.com>
|
||||
|
||||
MIT License
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "cpptools",
|
||||
"displayName": "C/C++",
|
||||
"description": "C/C++ IntelliSense, debugging, and code browsing.",
|
||||
"version": "1.32.0-main",
|
||||
"version": "1.31.5-main",
|
||||
"publisher": "ms-vscode",
|
||||
"icon": "LanguageCCPP_color_128x.png",
|
||||
"readme": "README.md",
|
||||
@@ -1703,12 +1703,6 @@
|
||||
"description": "%c_cpp.configuration.doxygen.generateOnType.description%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"C_Cpp.doxygen.generateOnCodeAction": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%c_cpp.configuration.doxygen.generateOnCodeAction.description%",
|
||||
"scope": "resource"
|
||||
},
|
||||
"C_Cpp.doxygen.generatedStyle": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -6805,7 +6799,6 @@
|
||||
"generate-native-strings": "ts-node -T ./.scripts/generateNativeStrings.ts",
|
||||
"generate-options-schema": "ts-node -T ./.scripts/generateOptionsSchema.ts",
|
||||
"copy-walkthrough-media": "ts-node -T ./.scripts/copyWalkthruMedia.ts",
|
||||
"copy-extension-binaries": "ts-node -T ./.scripts/copyExtensionBinaries.ts",
|
||||
"translations-export": "yarn install && yarn prep && yarn generate-native-strings && gulp translations-export",
|
||||
"translations-generate": "gulp translations-generate",
|
||||
"translations-import": "gulp translations-import",
|
||||
|
||||
@@ -580,7 +580,6 @@
|
||||
]
|
||||
},
|
||||
"c_cpp.configuration.doxygen.generateOnType.description": "Controls whether to automatically insert the Doxygen comment after typing the chosen comment style.",
|
||||
"c_cpp.configuration.doxygen.generateOnCodeAction.description": "Controls whether the code action to generate a Doxygen comment is enabled.",
|
||||
"c_cpp.configuration.doxygen.generatedStyle.description": "The string of characters used as the starting line of the Doxygen comment.",
|
||||
"c_cpp.configuration.doxygen.sectionTags.description": "Select the Doxygen section tags that you would like to appear on hover in the tooltip area when the 'Simplify Structured Comments' setting is enabled. ",
|
||||
"c_cpp.configuration.commentContinuationPatterns.items.anyof.string.markdownDescription": {
|
||||
|
||||
@@ -147,14 +147,12 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile, "configMode": ConfigMode.noLaunchConfig, "cancelled": "true", "succeeded": "true" });
|
||||
return undefined; // aborts debugging silently
|
||||
} else {
|
||||
const noDebug = config.noDebug ?? false; // Preserve the noDebug value from the config if it exists.
|
||||
// Currently, we expect only one debug config to be selected.
|
||||
console.assert(configs.length === 1, "More than one debug config is selected.");
|
||||
config = configs[0];
|
||||
// Keep track of the entry point where the debug config has been selected, for telemetry purposes.
|
||||
config.debuggerEvent = DebuggerEvent.debugPanel;
|
||||
config.configSource = folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile;
|
||||
config.noDebug = noDebug;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ function createLaunchString(name: string, type: string, executable: string): str
|
||||
"stopAtEntry": false,
|
||||
"cwd": "$\{fileDirname\}",
|
||||
"environment": [],
|
||||
${type === "cppdbg" ? `"externalConsole": false` : `"console": "internalConsole"`}
|
||||
${ type === "cppdbg" ? `"externalConsole": false` : `"console": "externalTerminal"` }
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class MIConfigurations extends Configuration {
|
||||
\t${indentJsonString(createLaunchString(name, this.miDebugger, this.executable))},
|
||||
\t"MIMode": "${this.MIMode}"{0}{1}
|
||||
}`, [this.miDebugger === "cppdbg" && os.platform() === "win32" ? `,${os.EOL}\t"miDebuggerPath": "/path/to/gdb"` : "",
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
@@ -182,7 +182,7 @@ export class MIConfigurations extends Configuration {
|
||||
\t${indentJsonString(createAttachString(name, this.miDebugger, this.executable))}
|
||||
\t"MIMode": "${this.MIMode}"{0}{1}
|
||||
}`, [this.miDebugger === "cppdbg" && os.platform() === "win32" ? `,${os.EOL}\t"miDebuggerPath": "/path/to/gdb"` : "",
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
|
||||
@@ -7,13 +7,11 @@ import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from "vscode";
|
||||
import * as nls from 'vscode-nls';
|
||||
import { getOutputChannel } from '../logger';
|
||||
import { RunWithoutDebuggingAdapter } from './runWithoutDebuggingAdapter';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
|
||||
// Registers DebugAdapterDescriptorFactory for `cppdbg` and `cppvsdbg`.
|
||||
// Registers DebugAdapterDescriptorFactory for `cppdbg` and `cppvsdbg`. If it is not ready, it will prompt a wait for the download dialog.
|
||||
// NOTE: This file is not automatically tested.
|
||||
|
||||
abstract class AbstractDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
|
||||
@@ -28,15 +26,8 @@ abstract class AbstractDebugAdapterDescriptorFactory implements vscode.DebugAdap
|
||||
}
|
||||
|
||||
export class CppdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDescriptorFactory {
|
||||
async createDebugAdapterDescriptor(session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor> {
|
||||
if (session.configuration.noDebug) {
|
||||
if (noDebugSupported(session.configuration)) {
|
||||
return new vscode.DebugAdapterInlineImplementation(new RunWithoutDebuggingAdapter());
|
||||
}
|
||||
// If the configuration is not supported, gracefully fall back to a regular debug session and log a message to the user.
|
||||
logReasonForNoDebugNotSupported(session.configuration);
|
||||
}
|
||||
|
||||
async createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor> {
|
||||
const adapter: string = "./debugAdapters/bin/OpenDebugAD7" + (os.platform() === 'win32' ? ".exe" : "");
|
||||
|
||||
const command: string = path.join(this.context.extensionPath, adapter);
|
||||
@@ -46,15 +37,8 @@ export class CppdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDes
|
||||
}
|
||||
|
||||
export class CppvsdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDescriptorFactory {
|
||||
async createDebugAdapterDescriptor(session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor | null> {
|
||||
if (session.configuration.noDebug) {
|
||||
if (noDebugSupported(session.configuration)) {
|
||||
return new vscode.DebugAdapterInlineImplementation(new RunWithoutDebuggingAdapter());
|
||||
}
|
||||
// If the configuration is not supported, gracefully fall back to a regular debug session and log a message to the user.
|
||||
logReasonForNoDebugNotSupported(session.configuration);
|
||||
}
|
||||
|
||||
async createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor | null> {
|
||||
if (os.platform() !== 'win32') {
|
||||
void vscode.window.showErrorMessage(localize("debugger.not.available", "Debugger type '{0}' is not available for non-Windows machines.", "cppvsdbg"));
|
||||
return null;
|
||||
@@ -66,28 +50,3 @@ export class CppvsdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function noDebugSupported(configuration: vscode.DebugConfiguration): boolean {
|
||||
// Don't attempt to start a noDebug session if the configuration has any of these properties, which require a debug adapter to function.
|
||||
return configuration.request === 'launch' && !configuration.pipeTransport && !configuration.debugServerPath && !configuration.miDebuggerServerAddress && !configuration.coreDumpPath;
|
||||
}
|
||||
|
||||
function logReasonForNoDebugNotSupported(configuration: vscode.DebugConfiguration): void {
|
||||
const outputChannel = getOutputChannel();
|
||||
if (configuration.request !== 'launch') {
|
||||
outputChannel.appendLine(localize("debugger.noDebug.requestType.not.supported", "Run Without Debugging is only supported for launch configurations."));
|
||||
}
|
||||
if (configuration.pipeTransport) {
|
||||
outputChannel.appendLine(localize("debugger.noDebug.pipeTransport.not.supported", "Run Without Debugging is not supported for configurations with 'pipeTransport' set."));
|
||||
}
|
||||
if (configuration.debugServerPath) {
|
||||
outputChannel.appendLine(localize("debugger.noDebug.debugServerPath.not.supported", "Run Without Debugging is not supported for configurations with 'debugServerPath' set."));
|
||||
}
|
||||
if (configuration.miDebuggerServerAddress) {
|
||||
outputChannel.appendLine(localize("debugger.noDebug.miDebuggerServerAddress.not.supported", "Run Without Debugging is not supported for configurations with 'miDebuggerServerAddress' set."));
|
||||
}
|
||||
if (configuration.coreDumpPath) {
|
||||
outputChannel.appendLine(localize("debugger.noDebug.coreDumpPath.not.supported", "Run Without Debugging is not supported for configurations with 'coreDumpPath' set."));
|
||||
}
|
||||
outputChannel.show(true);
|
||||
}
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { buildShellCommandLine, sessionIsWsl } from '../common';
|
||||
import { isWindows } from '../constants';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/**
|
||||
* A minimal inline Debug Adapter that runs the target program directly without a debug adapter
|
||||
* when the user invokes "Run Without Debugging".
|
||||
*/
|
||||
export class RunWithoutDebuggingAdapter implements vscode.DebugAdapter {
|
||||
private readonly sendMessageEmitter = new vscode.EventEmitter<vscode.DebugProtocolMessage>();
|
||||
public readonly onDidSendMessage: vscode.Event<vscode.DebugProtocolMessage> = this.sendMessageEmitter.event;
|
||||
private readonly terminalListeners: vscode.Disposable[] = [];
|
||||
|
||||
private seq: number = 1;
|
||||
private childProcess?: cp.ChildProcess;
|
||||
private terminal?: vscode.Terminal;
|
||||
private terminalExecution?: vscode.TerminalShellExecution;
|
||||
private hasTerminated: boolean = false;
|
||||
|
||||
public handleMessage(message: vscode.DebugProtocolMessage): void {
|
||||
const msg = message as { type: string; command: string; seq: number; arguments?: any; };
|
||||
if (msg.type === 'request') {
|
||||
void this.handleRequest(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleRequest(request: { command: string; seq: number; arguments?: any; }): Promise<void> {
|
||||
switch (request.command) {
|
||||
case 'initialize':
|
||||
this.sendResponse(request, {});
|
||||
this.sendEvent('initialized');
|
||||
break;
|
||||
case 'launch':
|
||||
await this.launch(request);
|
||||
break;
|
||||
case 'configurationDone':
|
||||
this.sendResponse(request, {});
|
||||
break;
|
||||
case 'disconnect':
|
||||
case 'terminate':
|
||||
this.sendResponse(request, {});
|
||||
break;
|
||||
default:
|
||||
this.sendResponse(request, {});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async launch(request: { command: string; seq: number; arguments?: any; }): Promise<void> {
|
||||
const config = request.arguments as {
|
||||
program?: string;
|
||||
args?: string[];
|
||||
cwd?: string;
|
||||
environment?: { name: string; value: string; }[];
|
||||
console?: string;
|
||||
externalConsole?: boolean;
|
||||
};
|
||||
|
||||
const program: string = config.program ?? '';
|
||||
const args: string[] = config.args ?? [];
|
||||
const cwd: string | undefined = config.cwd;
|
||||
const environment: { name: string; value: string; }[] = config.environment ?? [];
|
||||
const consoleMode: string = config.console ?? (config.externalConsole ? 'externalTerminal' : 'integratedTerminal');
|
||||
|
||||
// Merge the launch config's environment variables on top of the inherited process environment.
|
||||
const env: NodeJS.ProcessEnv = { ...process.env };
|
||||
for (const e of environment) {
|
||||
env[e.name] = e.value;
|
||||
}
|
||||
|
||||
this.sendResponse(request, {});
|
||||
|
||||
if (consoleMode === 'integratedTerminal' || consoleMode === 'internalConsole') {
|
||||
await this.launchIntegratedTerminal(program, args, cwd, env);
|
||||
} else if (consoleMode === 'externalTerminal') {
|
||||
this.launchExternalTerminal(program, args, cwd, env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the program in a VS Code integrated terminal.
|
||||
* The terminal will remain open after the program exits and be reused for the next session, if applicable.
|
||||
*/
|
||||
private async launchIntegratedTerminal(program: string, args: string[], cwd: string | undefined, env: NodeJS.ProcessEnv): Promise<void> {
|
||||
const terminalName = path.normalize(program);
|
||||
const existingTerminal = vscode.window.terminals.find(t => t.name === terminalName);
|
||||
this.terminal = existingTerminal ?? vscode.window.createTerminal({
|
||||
name: terminalName,
|
||||
cwd,
|
||||
env: env as Record<string, string>
|
||||
});
|
||||
this.terminal.show(true);
|
||||
|
||||
const shellIntegration: vscode.TerminalShellIntegration | undefined =
|
||||
this.terminal.shellIntegration ?? await this.waitForShellIntegration(this.terminal, 3000);
|
||||
|
||||
// Not all terminals support shell integration. If it's not available, we'll just send the command as text though we won't be able to monitor its execution.
|
||||
if (shellIntegration) {
|
||||
this.monitorIntegratedTerminal(this.terminal);
|
||||
let executable: string = program;
|
||||
let executableArgs: string[] = args;
|
||||
if (!program.match(/["']/) && program.match(/\s/)) {
|
||||
// VS Code does not automatically quote the program path if it has spaces.
|
||||
const shellPath: string | undefined = 'shellPath' in this.terminal.creationOptions
|
||||
? this.terminal.creationOptions.shellPath?.toLowerCase()
|
||||
: undefined;
|
||||
const terminalShell: string | undefined = this.terminal.state.shell?.toLowerCase();
|
||||
const defaultTerminalProfile: string | undefined = isWindows
|
||||
? vscode.workspace.getConfiguration('terminal.integrated').get<string>('defaultProfile.windows')?.toLowerCase()
|
||||
: undefined;
|
||||
const isPowerShell: boolean | undefined =
|
||||
shellPath?.endsWith('pwsh.exe') || shellPath?.endsWith('powershell.exe') || shellPath?.endsWith('pwsh') ||
|
||||
terminalShell?.includes('powershell') || terminalShell?.includes('pwsh') ||
|
||||
defaultTerminalProfile?.includes('powershell') || defaultTerminalProfile?.includes('pwsh');
|
||||
|
||||
if (isPowerShell || (isWindows && isPowerShell === undefined)) { // PowerShell is the default on Windows if we can't determine the shell.
|
||||
executable = '&';
|
||||
executableArgs = [program, ...args];
|
||||
} else {
|
||||
executable = `"${program}"`;
|
||||
}
|
||||
}
|
||||
this.terminalExecution = shellIntegration.executeCommand(executable, executableArgs);
|
||||
} else {
|
||||
const cmdLine: string = buildShellCommandLine('', program, args, true);
|
||||
this.terminal.sendText(cmdLine);
|
||||
|
||||
// The terminal manages its own lifecycle; notify VS Code the "debug" session is done.
|
||||
this.sendEvent('terminated');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the program in an external terminal. We do not keep track of this terminal or the spawned process.
|
||||
*/
|
||||
private launchExternalTerminal(program: string, args: string[], cwd: string | undefined, env: NodeJS.ProcessEnv): void {
|
||||
const cmdLine: string = buildShellCommandLine('', program, args, true);
|
||||
const platform: string = os.platform();
|
||||
if (platform === 'win32') {
|
||||
cp.spawn('cmd.exe', ['/c', 'start', 'cmd.exe', '/K', `"${cmdLine}"`], { cwd, env, windowsVerbatimArguments: true, detached: true, stdio: 'ignore' }).unref();
|
||||
} else if (platform === 'darwin') {
|
||||
cp.spawn('osascript', ['-e', `tell application "Terminal" to do script "${this.escapeQuotes(cmdLine)}"`], { cwd, env, detached: true, stdio: 'ignore' }).unref();
|
||||
} else if (platform === 'linux' && sessionIsWsl()) {
|
||||
cp.spawn('/mnt/c/Windows/System32/cmd.exe', ['/c', 'start', 'bash', '-c', `${cmdLine};read -p 'Press enter to continue...'`], { env, detached: true, stdio: 'ignore' }).unref();
|
||||
} else { // platform === 'linux'
|
||||
this.launchLinuxExternalTerminal(cmdLine, cwd, env);
|
||||
}
|
||||
this.sendEvent('terminated');
|
||||
}
|
||||
|
||||
/**
|
||||
* On Linux, find and launch an available terminal emulator to run the command.
|
||||
*/
|
||||
private launchLinuxExternalTerminal(cmdLine: string, cwd: string | undefined, env: NodeJS.ProcessEnv): void {
|
||||
const bashCmd = `${cmdLine}; echo; read -p 'Press enter to continue...'`;
|
||||
const bashArgs = ['bash', '-c', bashCmd];
|
||||
|
||||
// Terminal emulators in order of preference, with the correct flag style for each.
|
||||
const candidates: { cmd: string; buildArgs(): string[] }[] = [
|
||||
{ cmd: 'x-terminal-emulator', buildArgs: () => ['-e', ...bashArgs] },
|
||||
{ cmd: 'gnome-terminal', buildArgs: () => ['-e', ...bashArgs] },
|
||||
{ cmd: 'konsole', buildArgs: () => ['-e', ...bashArgs] },
|
||||
{ cmd: 'xterm', buildArgs: () => ['-e', ...bashArgs] }
|
||||
];
|
||||
|
||||
// Honor the $TERMINAL environment variable if set.
|
||||
const terminalEnv = process.env['TERMINAL'];
|
||||
if (terminalEnv) {
|
||||
candidates.unshift({ cmd: terminalEnv, buildArgs: () => ['-e', ...bashArgs] });
|
||||
}
|
||||
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
const result = cp.spawnSync('which', [candidate.cmd], { stdio: 'pipe' });
|
||||
if (result.status === 0) {
|
||||
cp.spawn(candidate.cmd, candidate.buildArgs(), { cwd, env, detached: true, stdio: 'ignore' }).unref();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const message = localize('no.terminal.emulator', 'No terminal emulator found. Please set the $TERMINAL environment variable to your terminal emulator of choice, or install one of the following: x-terminal-emulator, gnome-terminal, konsole, xterm.');
|
||||
vscode.window.showErrorMessage(message);
|
||||
}
|
||||
|
||||
private escapeQuotes(arg: string): string {
|
||||
return arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
private waitForShellIntegration(terminal: vscode.Terminal, timeoutMs: number): Promise<vscode.TerminalShellIntegration | undefined> {
|
||||
return new Promise(resolve => {
|
||||
let resolved: boolean = false;
|
||||
const done = (shellIntegration: vscode.TerminalShellIntegration | undefined): void => {
|
||||
if (resolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
resolved = true;
|
||||
clearTimeout(timeout);
|
||||
shellIntegrationChanged.dispose();
|
||||
terminalClosed.dispose();
|
||||
resolve(shellIntegration);
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => done(undefined), timeoutMs);
|
||||
const shellIntegrationChanged = vscode.window.onDidChangeTerminalShellIntegration(event => {
|
||||
if (event.terminal === terminal) {
|
||||
done(event.shellIntegration);
|
||||
}
|
||||
});
|
||||
const terminalClosed = vscode.window.onDidCloseTerminal(closedTerminal => {
|
||||
if (closedTerminal === terminal) {
|
||||
done(undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private monitorIntegratedTerminal(terminal: vscode.Terminal): void {
|
||||
this.disposeTerminalListeners();
|
||||
this.terminalListeners.push(
|
||||
vscode.window.onDidEndTerminalShellExecution(event => {
|
||||
if (event.terminal !== terminal || event.execution !== this.terminalExecution || this.hasTerminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.exitCode !== undefined) {
|
||||
this.sendEvent('exited', { exitCode: event.exitCode });
|
||||
}
|
||||
|
||||
this.sendEvent('terminated');
|
||||
}),
|
||||
vscode.window.onDidCloseTerminal(closedTerminal => {
|
||||
if (closedTerminal !== terminal || this.hasTerminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendEvent('terminated');
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private disposeTerminalListeners(): void {
|
||||
while (this.terminalListeners.length > 0) {
|
||||
this.terminalListeners.pop()?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private sendResponse(request: { command: string; seq: number; }, body: object): void {
|
||||
this.sendMessageEmitter.fire({
|
||||
type: 'response',
|
||||
seq: this.seq++,
|
||||
request_seq: request.seq,
|
||||
success: true,
|
||||
command: request.command,
|
||||
body
|
||||
} as vscode.DebugProtocolMessage);
|
||||
}
|
||||
|
||||
private sendEvent(event: string, body?: object): void {
|
||||
if (event === 'terminated') {
|
||||
if (this.hasTerminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hasTerminated = true;
|
||||
this.disposeTerminalListeners();
|
||||
}
|
||||
|
||||
this.sendMessageEmitter.fire({
|
||||
type: 'event',
|
||||
seq: this.seq++,
|
||||
event,
|
||||
body
|
||||
} as vscode.DebugProtocolMessage);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.terminateProcess();
|
||||
this.disposeTerminalListeners();
|
||||
this.sendMessageEmitter.dispose();
|
||||
}
|
||||
|
||||
private terminateProcess(): void {
|
||||
this.childProcess?.kill();
|
||||
this.childProcess = undefined;
|
||||
}
|
||||
}
|
||||
@@ -26,69 +26,10 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
|
||||
private cancelledDocument: vscode.TextDocument | undefined;
|
||||
private cancelledPosition: vscode.Position | undefined;
|
||||
private content: string | undefined;
|
||||
private chatModel: vscode.LanguageModelChat | undefined;
|
||||
private chatModelId: string | undefined; // Save the selected model ID to avoid trying the same unavailable model repeatedly.
|
||||
// Flag to avoid querying the LanguageModelChat repeatedly if no model is found
|
||||
private checkedChatModel: boolean = false;
|
||||
constructor(client: DefaultClient) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public async getCachedChatModel(): Promise<vscode.LanguageModelChat | undefined> {
|
||||
if (this.checkedChatModel) {
|
||||
return this.chatModel;
|
||||
}
|
||||
|
||||
const vscodelm = getVSCodeLanguageModel();
|
||||
if (vscodelm) {
|
||||
try {
|
||||
let model: vscode.LanguageModelChat | undefined;
|
||||
if (this.chatModelId === undefined) {
|
||||
// First look for GPT-4o which should be available to all
|
||||
// users and have a 0x multiplier on paid plans.
|
||||
// GPT-4o is faster than the x0 GPT-5-mini (which seems too slow for hover, e.g. 10+ seconds).
|
||||
this.chatModelId = 'gpt-4o';
|
||||
[model] = await vscodelm.selectChatModels({ ...modelSelector, id: this.chatModelId });
|
||||
if (!model) {
|
||||
// If GPT-4o is not available, fallback to GPT-5.4-mini (x0.33 and fast).
|
||||
this.chatModelId = 'gpt-5.4-mini';
|
||||
[model] = await vscodelm.selectChatModels({ ...modelSelector, id: this.chatModelId });
|
||||
}
|
||||
if (!model) {
|
||||
// If GPT-5.4-mini is not available, fallback to the first available model.
|
||||
this.chatModelId = 'default';
|
||||
[model] = await vscodelm.selectChatModels(modelSelector);
|
||||
}
|
||||
} else {
|
||||
if (this.chatModelId === 'default') {
|
||||
[model] = await vscodelm.selectChatModels(modelSelector);
|
||||
} else {
|
||||
[model] = await vscodelm.selectChatModels({ ...modelSelector, id: this.chatModelId });
|
||||
}
|
||||
}
|
||||
if (!model) {
|
||||
telemetry.logLanguageServerEvent('CopilotHoverNoModelSelected', { remoteName: vscode.env.remoteName || 'local' });
|
||||
} else {
|
||||
this.chatModel = model;
|
||||
}
|
||||
} catch (e: any) {
|
||||
const exceptionType = e?.name || e?.constructor?.name || typeof e;
|
||||
telemetry.logLanguageServerEvent('CopilotHoverSelectModelFailed', {
|
||||
remoteName: vscode.env.remoteName || 'local',
|
||||
exceptionType: String(exceptionType)
|
||||
});
|
||||
}
|
||||
}
|
||||
this.checkedChatModel = true;
|
||||
return this.chatModel;
|
||||
}
|
||||
|
||||
public async refreshCachedChatModel(): Promise<vscode.LanguageModelChat | undefined> {
|
||||
this.chatModel = undefined;
|
||||
this.checkedChatModel = false;
|
||||
return this.getCachedChatModel();
|
||||
}
|
||||
|
||||
public async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Hover | undefined> {
|
||||
await this.client.ready;
|
||||
|
||||
@@ -102,9 +43,12 @@ export class CopilotHoverProvider implements vscode.HoverProvider {
|
||||
}
|
||||
|
||||
// Ensure the user has access to Copilot.
|
||||
const model = await this.getCachedChatModel();
|
||||
if (!model) {
|
||||
return undefined;
|
||||
const vscodelm = getVSCodeLanguageModel();
|
||||
if (vscodelm) {
|
||||
const [model] = await vscodelm.selectChatModels(modelSelector);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const newHover = this.isNewHover(document, position);
|
||||
|
||||
@@ -88,129 +88,6 @@ const CallHierarchyCallsToRequest: RequestType<CallHierarchyParams, CallHierarch
|
||||
const CallHierarchyCallsFromRequest: RequestType<CallHierarchyParams, CallHierarchyCallsItemResult, void> =
|
||||
new RequestType<CallHierarchyParams, CallHierarchyCallsItemResult, void>('cpptools/callHierarchyCallsFrom');
|
||||
|
||||
function makeVscodeCallHierarchyItem(client: DefaultClient, item: CallHierarchyItem): vscode.CallHierarchyItem {
|
||||
const containerDetail: string = (item.detail !== "") ? `${item.detail} - ` : "";
|
||||
const itemUri: vscode.Uri = vscode.Uri.file(item.file);
|
||||
|
||||
// Get file detail
|
||||
const isInWorkspace: boolean = client.RootUri !== undefined &&
|
||||
itemUri.fsPath.startsWith(client.RootUri.fsPath);
|
||||
const dirPath: string = isInWorkspace ?
|
||||
path.relative(client.RootPath, path.dirname(item.file)) : path.dirname(item.file);
|
||||
const fileDetail: string = dirPath.length === 0 ?
|
||||
`${path.basename(item.file)}` : `${path.basename(item.file)} (${dirPath})`;
|
||||
|
||||
return new vscode.CallHierarchyItem(
|
||||
item.kind,
|
||||
item.name,
|
||||
containerDetail + fileDetail,
|
||||
itemUri,
|
||||
makeVscodeRange(item.range),
|
||||
makeVscodeRange(item.selectionRange));
|
||||
}
|
||||
|
||||
function createIncomingCalls(client: DefaultClient, calls: CallHierarchyCallsItem[]): vscode.CallHierarchyIncomingCall[] {
|
||||
const result: vscode.CallHierarchyIncomingCall[] = [];
|
||||
|
||||
for (const call of calls) {
|
||||
const item: vscode.CallHierarchyItem = makeVscodeCallHierarchyItem(client, call.item);
|
||||
const ranges: vscode.Range[] = [];
|
||||
call.fromRanges.forEach(r => {
|
||||
ranges.push(makeVscodeRange(r));
|
||||
});
|
||||
|
||||
const incomingCall: vscode.CallHierarchyIncomingCall =
|
||||
new vscode.CallHierarchyIncomingCall(item, ranges);
|
||||
result.push(incomingCall);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createOutgoingCalls(client: DefaultClient, calls: CallHierarchyCallsItem[]): vscode.CallHierarchyOutgoingCall[] {
|
||||
const result: vscode.CallHierarchyOutgoingCall[] = [];
|
||||
|
||||
for (const call of calls) {
|
||||
const item: vscode.CallHierarchyItem = makeVscodeCallHierarchyItem(client, call.item);
|
||||
const ranges: vscode.Range[] = [];
|
||||
call.fromRanges.forEach(r => {
|
||||
ranges.push(makeVscodeRange(r));
|
||||
});
|
||||
|
||||
const outgoingCall: vscode.CallHierarchyOutgoingCall =
|
||||
new vscode.CallHierarchyOutgoingCall(item, ranges);
|
||||
result.push(outgoingCall);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function sendPrepareCallHierarchyRequest(client: DefaultClient, uri: vscode.Uri, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.CallHierarchyItem[] | undefined> {
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: uri.toString() },
|
||||
position: Position.create(position.line, position.character)
|
||||
};
|
||||
let response: CallHierarchyItemResult;
|
||||
try {
|
||||
response = await client.languageClient.sendRequest(CallHierarchyItemRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return response.item === undefined ? [] : [makeVscodeCallHierarchyItem(client, response.item)];
|
||||
}
|
||||
|
||||
export async function sendCallHierarchyCallsToRequest(client: DefaultClient, item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyIncomingCall[] | undefined> {
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: item.uri.toString() },
|
||||
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
|
||||
};
|
||||
let response: CallHierarchyCallsItemResult;
|
||||
try {
|
||||
response = await client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return response.calls.length !== 0 ? createIncomingCalls(client, response.calls) : [];
|
||||
}
|
||||
|
||||
export async function sendCallHierarchyCallsFromRequest(client: DefaultClient, item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyOutgoingCall[] | undefined> {
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: item.uri.toString() },
|
||||
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
|
||||
};
|
||||
let response: CallHierarchyCallsItemResult;
|
||||
try {
|
||||
response = await client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return response.calls.length !== 0 ? createOutgoingCalls(client, response.calls) : [];
|
||||
}
|
||||
|
||||
export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
// Indicates whether a request is from an entry root node (e.g. top function in the call tree).
|
||||
private isEntryRootNodeTelemetry: boolean = false;
|
||||
@@ -241,10 +118,20 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
cancelSource.cancel();
|
||||
});
|
||||
|
||||
let result: vscode.CallHierarchyItem[] | undefined;
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: document.uri.toString() },
|
||||
position: Position.create(position.line, position.character)
|
||||
};
|
||||
let response: CallHierarchyItemResult;
|
||||
try {
|
||||
result = await sendPrepareCallHierarchyRequest(this.client, document.uri, position, cancelSource.token);
|
||||
} finally {
|
||||
response = await this.client.languageClient.sendRequest(CallHierarchyItemRequest, params, cancelSource.token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
cancellationTokenListener.dispose();
|
||||
requestCanceledListener.dispose();
|
||||
}
|
||||
@@ -252,12 +139,12 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
if (cancelSource.token.isCancellationRequested) {
|
||||
throw new vscode.CancellationError();
|
||||
}
|
||||
if (!result || result.length === 0) {
|
||||
if (response.item === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.isEntryRootNodeTelemetry = true;
|
||||
return result[0];
|
||||
return this.makeVscodeCallHierarchyItem(response.item);
|
||||
}
|
||||
|
||||
public async provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyIncomingCall[] | undefined> {
|
||||
@@ -285,28 +172,39 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
|
||||
// Send the request to the language server.
|
||||
let result: vscode.CallHierarchyIncomingCall[] | undefined;
|
||||
let progressBarDuration: number | undefined;
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: item.uri.toString() },
|
||||
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
|
||||
};
|
||||
let response: CallHierarchyCallsItemResult | undefined;
|
||||
let cancelled: boolean = false;
|
||||
try {
|
||||
result = await sendCallHierarchyCallsToRequest(this.client, item, cancelSource.token);
|
||||
} finally {
|
||||
// Reset anything that can be cleared before processing the result.
|
||||
progressBarDuration = workspaceReferences.getCallHierarchyProgressBarDuration();
|
||||
workspaceReferences.resetProgressBar();
|
||||
workspaceReferences.resetReferences();
|
||||
cancellationTokenListener.dispose();
|
||||
requestCanceledListener.dispose();
|
||||
response = await this.client.languageClient.sendRequest(CallHierarchyCallsToRequest, params, cancelSource.token);
|
||||
} catch (e: any) {
|
||||
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
|
||||
if (!cancelled) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// Reset anything that can be cleared before processing the result.
|
||||
const progressBarDuration: number | undefined = workspaceReferences.getCallHierarchyProgressBarDuration();
|
||||
workspaceReferences.resetProgressBar();
|
||||
workspaceReferences.resetReferences();
|
||||
cancellationTokenListener.dispose();
|
||||
requestCanceledListener.dispose();
|
||||
|
||||
// Process the result.
|
||||
if (cancelSource.token.isCancellationRequested || result === undefined || requestCanceled !== undefined) {
|
||||
if (cancelSource.token.isCancellationRequested || cancelled || requestCanceled !== undefined) {
|
||||
const requestStatus: CallHierarchyRequestStatus = requestCanceled === CancellationSender.User ?
|
||||
CallHierarchyRequestStatus.CanceledByUser : CallHierarchyRequestStatus.Canceled;
|
||||
this.logTelemetry(CallHierarchyCallsToEvent, requestStatus, progressBarDuration);
|
||||
throw new vscode.CancellationError();
|
||||
} else if (response && response.calls.length !== 0) {
|
||||
result = this.createIncomingCalls(response.calls);
|
||||
}
|
||||
|
||||
this.logTelemetry(CallHierarchyCallsToEvent, CallHierarchyRequestStatus.Succeeded, progressBarDuration);
|
||||
return result.length !== 0 ? result : undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
public async provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyOutgoingCall[] | undefined> {
|
||||
@@ -318,15 +216,87 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
|
||||
|
||||
await this.client.ready;
|
||||
|
||||
const result: vscode.CallHierarchyOutgoingCall[] | undefined =
|
||||
await sendCallHierarchyCallsFromRequest(this.client, item, token);
|
||||
if (token.isCancellationRequested || result === undefined) {
|
||||
let result: vscode.CallHierarchyOutgoingCall[] | undefined;
|
||||
const params: CallHierarchyParams = {
|
||||
textDocument: { uri: item.uri.toString() },
|
||||
position: Position.create(item.selectionRange.start.line, item.selectionRange.start.character)
|
||||
};
|
||||
let response: CallHierarchyCallsItemResult | undefined;
|
||||
let cancelled: boolean = false;
|
||||
try {
|
||||
response = await this.client.languageClient.sendRequest(CallHierarchyCallsFromRequest, params, token);
|
||||
} catch (e: any) {
|
||||
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
|
||||
if (!cancelled) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (token.isCancellationRequested || cancelled) {
|
||||
this.logTelemetry(CallHierarchyCallsFromEvent, CallHierarchyRequestStatus.Canceled);
|
||||
throw new vscode.CancellationError();
|
||||
} else if (response && response.calls.length !== 0) {
|
||||
result = this.createOutgoingCalls(response.calls);
|
||||
}
|
||||
|
||||
this.logTelemetry(CallHierarchyCallsFromEvent, CallHierarchyRequestStatus.Succeeded);
|
||||
return result.length !== 0 ? result : undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
private makeVscodeCallHierarchyItem(item: CallHierarchyItem): vscode.CallHierarchyItem {
|
||||
const containerDetail: string = (item.detail !== "") ? `${item.detail} - ` : "";
|
||||
const itemUri: vscode.Uri = vscode.Uri.file(item.file);
|
||||
|
||||
// Get file detail
|
||||
const isInWorkspace: boolean = this.client.RootUri !== undefined &&
|
||||
itemUri.fsPath.startsWith(this.client.RootUri?.fsPath);
|
||||
const dirPath: string = isInWorkspace ?
|
||||
path.relative(this.client.RootPath, path.dirname(item.file)) : path.dirname(item.file);
|
||||
const fileDetail: string = dirPath.length === 0 ?
|
||||
`${path.basename(item.file)}` : `${path.basename(item.file)} (${dirPath})`;
|
||||
|
||||
return new vscode.CallHierarchyItem(
|
||||
item.kind,
|
||||
item.name,
|
||||
containerDetail + fileDetail,
|
||||
itemUri,
|
||||
makeVscodeRange(item.range),
|
||||
makeVscodeRange(item.selectionRange));
|
||||
}
|
||||
|
||||
private createIncomingCalls(calls: CallHierarchyCallsItem[]): vscode.CallHierarchyIncomingCall[] {
|
||||
const result: vscode.CallHierarchyIncomingCall[] = [];
|
||||
|
||||
for (const call of calls) {
|
||||
const item: vscode.CallHierarchyItem = this.makeVscodeCallHierarchyItem(call.item);
|
||||
const ranges: vscode.Range[] = [];
|
||||
call.fromRanges.forEach(r => {
|
||||
ranges.push(makeVscodeRange(r));
|
||||
});
|
||||
|
||||
const incomingCall: vscode.CallHierarchyIncomingCall =
|
||||
new vscode.CallHierarchyIncomingCall(item, ranges);
|
||||
result.push(incomingCall);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private createOutgoingCalls(calls: CallHierarchyCallsItem[]): vscode.CallHierarchyOutgoingCall[] {
|
||||
const result: vscode.CallHierarchyOutgoingCall[] = [];
|
||||
|
||||
for (const call of calls) {
|
||||
const item: vscode.CallHierarchyItem = this.makeVscodeCallHierarchyItem(call.item);
|
||||
const ranges: vscode.Range[] = [];
|
||||
call.fromRanges.forEach(r => {
|
||||
ranges.push(makeVscodeRange(r));
|
||||
});
|
||||
|
||||
const outgoingCall: vscode.CallHierarchyOutgoingCall =
|
||||
new vscode.CallHierarchyOutgoingCall(item, ranges);
|
||||
result.push(outgoingCall);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private logTelemetry(eventName: string, requestStatus: CallHierarchyRequestStatus, progressBarDuration?: number): void {
|
||||
|
||||
@@ -11,50 +11,6 @@ import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, Ref
|
||||
const FindAllReferencesRequest: RequestType<ReferencesParams, ReferencesResult, void> =
|
||||
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/findAllReferences');
|
||||
|
||||
export interface FindAllReferencesResult {
|
||||
referencesResult: ReferencesResult;
|
||||
locations: vscode.Location[];
|
||||
}
|
||||
|
||||
function convertConfirmedReferencesToLocations(referencesResult: ReferencesResult): vscode.Location[] {
|
||||
const locationsResult: vscode.Location[] = [];
|
||||
referencesResult.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
|
||||
if (referenceInfo.type === ReferenceType.Confirmed) {
|
||||
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
|
||||
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
|
||||
referenceInfo.position.line, referenceInfo.position.character + referencesResult.text.length);
|
||||
locationsResult.push(new vscode.Location(uri, range));
|
||||
}
|
||||
});
|
||||
return locationsResult;
|
||||
}
|
||||
|
||||
export async function sendFindAllReferencesRequest(client: DefaultClient, uri: vscode.Uri, position: vscode.Position, token: vscode.CancellationToken): Promise<FindAllReferencesResult | undefined> {
|
||||
const params: ReferencesParams = {
|
||||
newName: "",
|
||||
position: Position.create(position.line, position.character),
|
||||
textDocument: { uri: uri.toString() }
|
||||
};
|
||||
let response: ReferencesResult;
|
||||
try {
|
||||
response = await client.languageClient.sendRequest(FindAllReferencesRequest, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested || response.isCanceled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
referencesResult: response,
|
||||
locations: convertConfirmedReferencesToLocations(response)
|
||||
};
|
||||
}
|
||||
|
||||
export class FindAllReferencesProvider implements vscode.ReferenceProvider {
|
||||
private client: DefaultClient;
|
||||
|
||||
@@ -73,10 +29,23 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
|
||||
const requestCanceledListener: vscode.Disposable = workspaceReferences.onCancellationRequested(_sender => { cancelSource.cancel(); });
|
||||
|
||||
// Send the request to the language server.
|
||||
let result: FindAllReferencesResult | undefined;
|
||||
const locationsResult: vscode.Location[] = [];
|
||||
const params: ReferencesParams = {
|
||||
newName: "",
|
||||
position: Position.create(position.line, position.character),
|
||||
textDocument: { uri: document.uri.toString() }
|
||||
};
|
||||
let response: ReferencesResult | undefined;
|
||||
let cancelled: boolean = false;
|
||||
try {
|
||||
result = await sendFindAllReferencesRequest(this.client, document.uri, position, cancelSource.token);
|
||||
} finally {
|
||||
response = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token);
|
||||
} catch (e: any) {
|
||||
cancelled = e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled);
|
||||
if (!cancelled) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Reset anything that can be cleared before processing the result.
|
||||
workspaceReferences.resetProgressBar();
|
||||
cancellationTokenListener.dispose();
|
||||
@@ -84,21 +53,30 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
|
||||
}
|
||||
|
||||
// Process the result.
|
||||
if (cancelSource.token.isCancellationRequested || !result) {
|
||||
if (cancelSource.token.isCancellationRequested || cancelled || (response && response.isCanceled)) {
|
||||
// Return undefined instead of vscode.CancellationError to avoid the following error message from VS Code:
|
||||
// "Cannot destructure property 'range' of 'e.location' as it is undefined."
|
||||
// TODO: per issue https://github.com/microsoft/vscode/issues/169698
|
||||
// vscode.CancellationError is expected, so when VS Code fixes the error use vscode.CancellationError again.
|
||||
workspaceReferences.resetReferences();
|
||||
return undefined;
|
||||
} else if (result.referencesResult.referenceInfos.length > 0) {
|
||||
} else if (response && response.referenceInfos.length > 0) {
|
||||
response.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
|
||||
if (referenceInfo.type === ReferenceType.Confirmed) {
|
||||
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
|
||||
const range: vscode.Range = new vscode.Range(referenceInfo.position.line, referenceInfo.position.character,
|
||||
referenceInfo.position.line, referenceInfo.position.character + response.text.length);
|
||||
locationsResult.push(new vscode.Location(uri, range));
|
||||
}
|
||||
});
|
||||
|
||||
// Display other reference types in panel or channel view.
|
||||
// Note: ReferencesManager.resetReferences is called in ReferencesManager.showResultsInPanelView
|
||||
workspaceReferences.showResultsInPanelView(result.referencesResult);
|
||||
workspaceReferences.showResultsInPanelView(response);
|
||||
} else {
|
||||
workspaceReferences.resetReferences();
|
||||
}
|
||||
|
||||
return result.locations;
|
||||
return locationsResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import * as vscode from 'vscode';
|
||||
import { Definition, DefinitionLink, DefinitionRequest, Position, ResponseError, TextDocumentPositionParams } from 'vscode-languageclient';
|
||||
import { DefaultClient } from '../client';
|
||||
import { RequestCancelled, ServerCancelled } from '../protocolFilter';
|
||||
|
||||
function convertDefinitionsToLocations(definitionsResult: vscode.Definition | vscode.DefinitionLink[] | undefined): vscode.Location[] {
|
||||
if (!definitionsResult) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!Array.isArray(definitionsResult)) {
|
||||
return [definitionsResult];
|
||||
}
|
||||
|
||||
const result: vscode.Location[] = [];
|
||||
for (const definition of definitionsResult) {
|
||||
if (definition instanceof vscode.Location) {
|
||||
result.push(definition);
|
||||
} else {
|
||||
result.push(new vscode.Location(definition.targetUri, definition.targetSelectionRange ?? definition.targetRange));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function sendGoToDefinitionRequest(client: DefaultClient, uri: vscode.Uri, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
const params: TextDocumentPositionParams = {
|
||||
position: Position.create(position.line, position.character),
|
||||
textDocument: { uri: uri.toString() }
|
||||
};
|
||||
let response: Definition | DefinitionLink[] | null;
|
||||
try {
|
||||
response = await client.languageClient.sendRequest(DefinitionRequest.type, params, token);
|
||||
} catch (e: any) {
|
||||
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
|
||||
return undefined;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result: vscode.Definition | vscode.DefinitionLink[] | undefined =
|
||||
await client.languageClient.protocol2CodeConverter.asDefinitionResult(response, token);
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return convertDefinitionsToLocations(result);
|
||||
}
|
||||
@@ -805,6 +805,7 @@ export interface Client {
|
||||
setCurrentConfigName(configurationName: string): Thenable<void>;
|
||||
getCurrentConfigName(): Thenable<string | undefined>;
|
||||
getCurrentConfigCustomVariable(variableName: string): Thenable<string>;
|
||||
waitForIdle(timeout?: number): Promise<boolean>;
|
||||
getVcpkgInstalled(): Thenable<boolean>;
|
||||
getVcpkgEnabled(): Thenable<boolean>;
|
||||
getCurrentCompilerPathAndArgs(): Thenable<util.CompilerPathAndArgs | undefined>;
|
||||
@@ -919,6 +920,7 @@ export class DefaultClient implements Client {
|
||||
|
||||
private configStateReceived: ConfigStateReceived = { compilers: false, compileCommands: false, configProviders: undefined, timeout: false };
|
||||
private showConfigureIntelliSenseButton: boolean = false;
|
||||
private pendingIdleCalls: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout }[] = [];
|
||||
|
||||
/** A queue of asynchronous tasks that need to be processed befofe ready is considered active. */
|
||||
private static queue = new Array<[ManualPromise<unknown>, () => Promise<unknown>] | [ManualPromise<unknown>]>();
|
||||
@@ -1008,6 +1010,56 @@ export class DefaultClient implements Client {
|
||||
};
|
||||
}
|
||||
|
||||
private isIdle(): boolean {
|
||||
return !this.model.isInitializingWorkspace.Value
|
||||
&& !this.model.isIndexingWorkspace.Value
|
||||
&& !this.model.isParsingWorkspace.Value
|
||||
&& !this.model.isParsingFiles.Value
|
||||
&& !this.model.isUpdatingIntelliSense.Value;
|
||||
}
|
||||
|
||||
private resolvePendingIdleCallsIfReady(): void {
|
||||
if (!this.pendingIdleCalls.length || !this.isIdle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pendingCalls: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout }[] = this.pendingIdleCalls;
|
||||
this.pendingIdleCalls = [];
|
||||
pendingCalls.forEach(pendingCall => {
|
||||
if (pendingCall.timer) {
|
||||
clearTimeout(pendingCall.timer);
|
||||
}
|
||||
pendingCall.promise.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
public async waitForIdle(timeout?: number): Promise<boolean> {
|
||||
if (this.isIdle()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (timeout !== undefined && timeout <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pendingCall: { promise: ManualPromise<boolean>; timer?: NodeJS.Timeout } = {
|
||||
promise: new ManualPromise<boolean>()
|
||||
};
|
||||
|
||||
if (timeout !== undefined) {
|
||||
pendingCall.timer = global.setTimeout(() => {
|
||||
const index: number = this.pendingIdleCalls.indexOf(pendingCall);
|
||||
if (index !== -1) {
|
||||
this.pendingIdleCalls.splice(index, 1);
|
||||
}
|
||||
pendingCall.promise.resolve(false);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
this.pendingIdleCalls.push(pendingCall);
|
||||
return pendingCall.promise;
|
||||
}
|
||||
|
||||
private getName(workspaceFolder?: vscode.WorkspaceFolder): string {
|
||||
return workspaceFolder ? workspaceFolder.name : "untitled";
|
||||
}
|
||||
@@ -1537,7 +1589,6 @@ export class DefaultClient implements Client {
|
||||
vcFormatSpaceAroundTernaryOperator: settings.vcFormatSpaceAroundTernaryOperator,
|
||||
vcFormatWrapPreserveBlocks: settings.vcFormatWrapPreserveBlocks,
|
||||
doxygenGenerateOnType: settings.doxygenGenerateOnType,
|
||||
doxygenGenerateOnCodeAction: settings.doxygenGenerateOnCodeAction,
|
||||
doxygenGeneratedStyle: settings.doxygenGeneratedCommentStyle,
|
||||
doxygenSectionTags: settings.doxygenSectionTags,
|
||||
filesExclude: otherSettings.filesExclude,
|
||||
@@ -2893,6 +2944,8 @@ export class DefaultClient implements Client {
|
||||
} else if (message.includes("/")) {
|
||||
this.lastInvokedLspMessage = message;
|
||||
}
|
||||
|
||||
this.resolvePendingIdleCallsIfReady();
|
||||
}
|
||||
|
||||
private updateTagParseStatus(tagParseStatus: TagParseStatus): void {
|
||||
@@ -4208,6 +4261,13 @@ export class DefaultClient implements Client {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.pendingIdleCalls.forEach(pendingCall => {
|
||||
if (pendingCall.timer) {
|
||||
clearTimeout(pendingCall.timer);
|
||||
}
|
||||
pendingCall.promise.resolve(false);
|
||||
});
|
||||
this.pendingIdleCalls = [];
|
||||
this.disposables.forEach((d) => d.dispose());
|
||||
this.disposables = [];
|
||||
if (this.documentFormattingProviderDisposable) {
|
||||
@@ -4360,6 +4420,7 @@ class NullClient implements Client {
|
||||
setCurrentConfigName(configurationName: string): Thenable<void> { return Promise.resolve(); }
|
||||
getCurrentConfigName(): Thenable<string> { return Promise.resolve(""); }
|
||||
getCurrentConfigCustomVariable(variableName: string): Thenable<string> { return Promise.resolve(""); }
|
||||
waitForIdle(timeout?: number): Promise<boolean> { return Promise.resolve(true); }
|
||||
getVcpkgInstalled(): Thenable<boolean> { return Promise.resolve(false); }
|
||||
getVcpkgEnabled(): Thenable<boolean> { return Promise.resolve(false); }
|
||||
getCurrentCompilerPathAndArgs(): Thenable<util.CompilerPathAndArgs | undefined> { return Promise.resolve(undefined); }
|
||||
|
||||
@@ -17,15 +17,12 @@ import { TargetPopulation } from 'vscode-tas-client';
|
||||
import * as which from 'which';
|
||||
import { logAndReturn } from '../Utility/Async/returns';
|
||||
import * as util from '../common';
|
||||
import { isWindows } from '../constants';
|
||||
import { isWindows, modelSelector } from '../constants';
|
||||
import { instrument } from '../instrumentation';
|
||||
import { getCrashCallStacksChannel } from '../logger';
|
||||
import { PlatformInformation } from '../platform';
|
||||
import * as telemetry from '../telemetry';
|
||||
import { CopilotHoverProvider } from './Providers/CopilotHoverProvider';
|
||||
import { sendCallHierarchyCallsFromRequest, sendCallHierarchyCallsToRequest, sendPrepareCallHierarchyRequest } from './Providers/callHierarchyProvider';
|
||||
import { sendFindAllReferencesRequest } from './Providers/findAllReferencesProvider';
|
||||
import { sendGoToDefinitionRequest } from './Providers/goToDefinitionProvider';
|
||||
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, openFileVersions } from './client';
|
||||
import { ClientCollection } from './clientCollection';
|
||||
import { CodeActionDiagnosticInfo, CodeAnalysisDiagnosticIdentifiersAndUri, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions } from './codeAnalysis';
|
||||
@@ -275,6 +272,7 @@ export async function activate(): Promise<void> {
|
||||
}
|
||||
|
||||
await registerRelatedFilesProvider();
|
||||
await vscode.commands.executeCommand('setContext', 'cpptools.languageServerActivated', true);
|
||||
}
|
||||
|
||||
export function updateLanguageConfigurations(): void {
|
||||
@@ -400,11 +398,6 @@ export async function registerCommands(enabled: boolean): Promise<void> {
|
||||
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.FindAllReferences', enabled ? onFindAllReferences : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.GoToDefinition', enabled ? onGoToDefinition : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.PrepareCallHierarchy', enabled ? onPrepareCallHierarchy : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CallHierarchyCallsTo', enabled ? onCallHierarchyCallsTo : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CallHierarchyCallsFrom', enabled ? onCallHierarchyCallsFrom : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.TakeSurvey', enabled ? onTakeSurvey : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.LogDiagnostics', enabled ? onLogDiagnostics : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RescanWorkspace', enabled ? onRescanWorkspace : onDisabledCommand));
|
||||
@@ -429,6 +422,7 @@ export async function registerCommands(enabled: boolean): Promise<void> {
|
||||
commandDisposables.push(vscode.commands.registerCommand('cpptools.activeConfigName', enabled ? onGetActiveConfigName : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('cpptools.activeConfigCustomVariable', enabled ? onGetActiveConfigCustomVariable : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('cpptools.setActiveConfigName', enabled ? onSetActiveConfigName : onDisabledCommand));
|
||||
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.waitForIdle', enabled ? onWaitForIdle : onDisabledCommand));
|
||||
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));
|
||||
@@ -816,77 +810,6 @@ function onShowReferencesProgress(): void {
|
||||
void clients.ActiveClient.handleReferencesIcon().catch(logAndReturn.undefined);
|
||||
}
|
||||
|
||||
async function onFindAllReferences(uri: vscode.Uri, position: vscode.Position, token?: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
if (!uri || !position) {
|
||||
throw new Error("C_Cpp.FindAllReferences requires both a uri and position.");
|
||||
}
|
||||
|
||||
const client: Client = clients.getClientFor(uri);
|
||||
if (!(client instanceof DefaultClient)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
const result = await sendFindAllReferencesRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
return result?.locations;
|
||||
}
|
||||
|
||||
async function onGoToDefinition(uri: vscode.Uri, position: vscode.Position, token?: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
if (!uri || !position) {
|
||||
throw new Error("C_Cpp.GoToDefinition requires both a uri and position.");
|
||||
}
|
||||
|
||||
const client: Client = clients.getClientFor(uri);
|
||||
if (!(client instanceof DefaultClient)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendGoToDefinitionRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
async function onPrepareCallHierarchy(uri: vscode.Uri, position: vscode.Position, token?: vscode.CancellationToken): Promise<vscode.CallHierarchyItem[] | undefined> {
|
||||
if (!uri || !position) {
|
||||
throw new Error("C_Cpp.PrepareCallHierarchy requires both a uri and position.");
|
||||
}
|
||||
|
||||
const client: Client = clients.getClientFor(uri);
|
||||
if (!(client instanceof DefaultClient)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendPrepareCallHierarchyRequest(client, uri, position, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
async function onCallHierarchyCallsTo(item: vscode.CallHierarchyItem, token?: vscode.CancellationToken): Promise<vscode.CallHierarchyIncomingCall[] | undefined> {
|
||||
if (!item) {
|
||||
throw new Error("C_Cpp.CallHierarchyCallsTo requires an item.");
|
||||
}
|
||||
|
||||
const client: Client = clients.getClientFor(item.uri);
|
||||
if (!(client instanceof DefaultClient)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsToRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
async function onCallHierarchyCallsFrom(item: vscode.CallHierarchyItem, token?: vscode.CancellationToken): Promise<vscode.CallHierarchyOutgoingCall[] | undefined> {
|
||||
if (!item) {
|
||||
throw new Error("C_Cpp.CallHierarchyCallsFrom requires an item.");
|
||||
}
|
||||
|
||||
const client: Client = clients.getClientFor(item.uri);
|
||||
if (!(client instanceof DefaultClient)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await client.ready;
|
||||
return sendCallHierarchyCallsFromRequest(client, item, token ?? CancellationToken.None);
|
||||
}
|
||||
|
||||
function onToggleRefGroupView(): void {
|
||||
// Set context to switch icons
|
||||
const client: Client = getActiveClient();
|
||||
@@ -984,6 +907,13 @@ function onRescanWorkspace(): Promise<void> {
|
||||
return clients.ActiveClient.rescanFolder();
|
||||
}
|
||||
|
||||
async function onWaitForIdle(timeout?: number): Promise<boolean> {
|
||||
const pending: Promise<boolean>[] = [];
|
||||
clients.forEach(client => pending.push(client.waitForIdle(timeout)));
|
||||
const results: boolean[] = await Promise.all(pending);
|
||||
return results.every(result => result);
|
||||
}
|
||||
|
||||
function onShowRefCommand(arg?: TreeNode): void {
|
||||
if (!arg) {
|
||||
return;
|
||||
@@ -1550,12 +1480,8 @@ async function onCopilotHover(): Promise<void> {
|
||||
|
||||
let chatResponse: vscode.LanguageModelChatResponse | undefined;
|
||||
try {
|
||||
// Select the chat model (refresh from cache).
|
||||
const model = await copilotHoverProvider.refreshCachedChatModel();
|
||||
if (!model) {
|
||||
await reportCopilotFailure(copilotHoverProvider, hoverDocument, hoverPosition, "Copilot model not available.");
|
||||
return;
|
||||
}
|
||||
// Select the chat model.
|
||||
const [model] = await vscodelm.selectChatModels(modelSelector);
|
||||
|
||||
chatResponse = await model.sendRequest(
|
||||
messages,
|
||||
|
||||
@@ -126,7 +126,6 @@ export interface WorkspaceFolderSettingsParams {
|
||||
vcFormatSpaceAroundTernaryOperator: string;
|
||||
vcFormatWrapPreserveBlocks: string;
|
||||
doxygenGenerateOnType: boolean;
|
||||
doxygenGenerateOnCodeAction: boolean;
|
||||
doxygenGeneratedStyle: string;
|
||||
doxygenSectionTags: string[];
|
||||
filesExclude: Excludes;
|
||||
@@ -384,7 +383,6 @@ export class CppSettings extends Settings {
|
||||
public get simplifyStructuredComments(): boolean { return this.getAsBoolean("simplifyStructuredComments"); }
|
||||
public get doxygenGeneratedCommentStyle(): string { return this.getAsString("doxygen.generatedStyle"); }
|
||||
public get doxygenGenerateOnType(): boolean { return this.getAsBoolean("doxygen.generateOnType"); }
|
||||
public get doxygenGenerateOnCodeAction(): boolean { return this.getAsBoolean("doxygen.generateOnCodeAction"); }
|
||||
public get commentContinuationPatterns(): (string | CommentPattern)[] {
|
||||
const value: any = super.Section.get<any>("commentContinuationPatterns");
|
||||
if (this.isArrayOfCommentContinuationPatterns(value)) {
|
||||
|
||||
+3
-41
@@ -1549,6 +1549,7 @@ export function hasMsvcEnvironment(): boolean {
|
||||
'INCLUDE',
|
||||
'LIB',
|
||||
'LIBPATH',
|
||||
'UCRTVersion',
|
||||
'UniversalCRTSdkDir',
|
||||
'VCIDEInstallDir',
|
||||
'VCINSTALLDIR',
|
||||
@@ -1567,34 +1568,6 @@ export function hasMsvcEnvironment(): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export function getMissingMsvcEnvironmentVariables(): string[] {
|
||||
const msvcEnvVars: string[] = [
|
||||
'DevEnvDir',
|
||||
'Framework40Version',
|
||||
'FrameworkDir',
|
||||
'FrameworkVersion',
|
||||
'INCLUDE',
|
||||
'LIB',
|
||||
'LIBPATH',
|
||||
'UCRTVersion',
|
||||
'UniversalCRTSdkDir',
|
||||
'VCIDEInstallDir',
|
||||
'VCINSTALLDIR',
|
||||
'VCToolsRedistDir',
|
||||
'VisualStudioVersion',
|
||||
'VSINSTALLDIR',
|
||||
'WindowsLibPath',
|
||||
'WindowsSdkBinPath',
|
||||
'WindowsSdkDir',
|
||||
'WindowsSDKLibVersion',
|
||||
'WindowsSDKVersion'
|
||||
];
|
||||
return msvcEnvVars.filter(envVarName =>
|
||||
(process.env[envVarName] === undefined || process.env[envVarName] === '') &&
|
||||
extensionContext?.environmentVariableCollection?.get(envVarName) === undefined
|
||||
);
|
||||
}
|
||||
|
||||
function isIntegral(str: string): boolean {
|
||||
const regex = /^-?\d+$/;
|
||||
return regex.test(str);
|
||||
@@ -1695,7 +1668,7 @@ export interface IQuotedString {
|
||||
|
||||
export type CommandString = string | IQuotedString;
|
||||
|
||||
export function buildShellCommandLine(originalCommand: CommandString, command: CommandString, args: CommandString[], singleCommandOnly: boolean = false): string {
|
||||
export function buildShellCommandLine(originalCommand: CommandString, command: CommandString, args: CommandString[]): string {
|
||||
|
||||
let shellQuoteOptions: IShellQuotingOptions;
|
||||
const isWindows: boolean = os.platform() === 'win32';
|
||||
@@ -1809,7 +1782,7 @@ export function buildShellCommandLine(originalCommand: CommandString, command: C
|
||||
|
||||
let commandLine = result.join(' ');
|
||||
// There are special rules quoted command line in cmd.exe
|
||||
if (isWindows && !singleCommandOnly) {
|
||||
if (isWindows) {
|
||||
commandLine = `chcp 65001>nul && ${commandLine}`;
|
||||
if (commandQuoted && argQuoted) {
|
||||
commandLine = '"' + commandLine + '"';
|
||||
@@ -1877,14 +1850,3 @@ export function getVSCodeLanguageModel(): any | undefined {
|
||||
}
|
||||
return vscodelm;
|
||||
}
|
||||
|
||||
export function sessionIsWsl(): boolean {
|
||||
if (process.env.WSL_DISTRO_NAME) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <fstream>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ofstream resultFile(argv[1]);
|
||||
if (!resultFile) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
resultFile << argv[i];
|
||||
if (i + 1 < argc) {
|
||||
resultFile << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <fstream>
|
||||
|
||||
int main() {
|
||||
std::ofstream resultFile("runWithoutDebuggingResult.txt");
|
||||
if (!resultFile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
resultFile << 37;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
/// <reference path="../../../../vscode.d.ts" />
|
||||
import * as assert from 'assert';
|
||||
import * as cp from 'child_process';
|
||||
import * as vscode from 'vscode';
|
||||
import * as util from '../../../../src/common';
|
||||
import { isLinux, isMacOS, isWindows } from '../../../../src/constants';
|
||||
import { getEffectiveEnvironment } from '../../../../src/LanguageServer/devcmd';
|
||||
|
||||
interface ProcessResult {
|
||||
code: number | null;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
function runProcess(command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<ProcessResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = cp.spawn(command, args, { cwd, env });
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
child.stdout.on('data', (data: Buffer) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
|
||||
child.stderr.on('data', (data: Buffer) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
|
||||
child.on('error', reject);
|
||||
child.on('close', (code) => resolve({ code, stdout, stderr }));
|
||||
});
|
||||
}
|
||||
|
||||
async function setWindowsBuildEnvironment(): Promise<void> {
|
||||
const promise = vscode.commands.executeCommand('C_Cpp.SetVsDeveloperEnvironment', 'test');
|
||||
const timer = setInterval(() => {
|
||||
void vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
|
||||
}, 1000);
|
||||
await promise;
|
||||
clearInterval(timer);
|
||||
const missingVars = util.getMissingMsvcEnvironmentVariables();
|
||||
assert.strictEqual(missingVars.length, 0, `MSVC environment missing: ${missingVars.join(', ')}`);
|
||||
}
|
||||
|
||||
export async function compileProgram(workspacePath: string, sourcePath: string, outputPath: string): Promise<void> {
|
||||
if (isWindows) {
|
||||
await setWindowsBuildEnvironment();
|
||||
const env = getEffectiveEnvironment();
|
||||
const result = await runProcess('cl.exe', ['/nologo', '/EHsc', '/Zi', '/std:c++17', `/Fe:${outputPath}`, sourcePath], workspacePath, env);
|
||||
assert.strictEqual(result.code, 0, `MSVC compilation failed. stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMacOS) {
|
||||
const result = await runProcess('clang++', ['-std=c++17', '-g', sourcePath, '-o', outputPath], workspacePath);
|
||||
assert.strictEqual(result.code, 0, `clang++ compilation failed. stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLinux) {
|
||||
const result = await runProcess('g++', ['-std=c++17', '-g', sourcePath, '-o', outputPath], workspacePath);
|
||||
assert.strictEqual(result.code, 0, `g++ compilation failed. stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.fail(`Unsupported test platform: ${process.platform}`);
|
||||
}
|
||||
-267
@@ -1,267 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
/// <reference path="../../../../vscode.d.ts" />
|
||||
import * as assert from 'assert';
|
||||
import { suite } from 'mocha';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as util from '../../../../src/common';
|
||||
import { isMacOS, isWindows } from '../../../../src/constants';
|
||||
import { compileProgram } from './compileProgram';
|
||||
|
||||
interface TrackerState {
|
||||
setBreakpointsRequestReceived: boolean;
|
||||
stoppedEventReceived: boolean;
|
||||
exitedEventReceived: boolean;
|
||||
exitedBeforeStop: boolean;
|
||||
}
|
||||
|
||||
interface TrackerController {
|
||||
state: TrackerState;
|
||||
lastEvent: Promise<'stopped' | 'exited'>;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
async function createBreakpointAtResultWriteStatement(sourceUri: vscode.Uri): Promise<vscode.SourceBreakpoint> {
|
||||
const document = await vscode.workspace.openTextDocument(sourceUri);
|
||||
const resultWriteLine = document.getText().split(/\r?\n/).findIndex((line) => line.includes('resultFile << 37;'));
|
||||
assert.notStrictEqual(resultWriteLine, -1, 'Unable to find expected result-write statement for breakpoint placement.');
|
||||
const breakpoint = new vscode.SourceBreakpoint(new vscode.Location(sourceUri, new vscode.Position(resultWriteLine, 0)), true);
|
||||
vscode.debug.addBreakpoints([breakpoint]);
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
function createSessionTerminatedPromise(sessionName: string): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
const terminateSubscription = vscode.debug.onDidTerminateDebugSession((session) => {
|
||||
if (session.name === sessionName) {
|
||||
terminateSubscription.dispose();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createTracker(debugType: string, sessionName: string, timeoutMs: number, timeoutMessage: string): TrackerController {
|
||||
const state: TrackerState = {
|
||||
setBreakpointsRequestReceived: false,
|
||||
stoppedEventReceived: false,
|
||||
exitedEventReceived: false,
|
||||
exitedBeforeStop: false
|
||||
};
|
||||
|
||||
let trackerRegistration: vscode.Disposable | undefined;
|
||||
let timeoutHandle: NodeJS.Timeout | undefined;
|
||||
|
||||
const lastEvent = new Promise<'stopped' | 'exited'>((resolve, reject) => {
|
||||
timeoutHandle = setTimeout(() => {
|
||||
trackerRegistration?.dispose();
|
||||
trackerRegistration = undefined;
|
||||
reject(new Error(timeoutMessage));
|
||||
}, timeoutMs);
|
||||
|
||||
trackerRegistration = vscode.debug.registerDebugAdapterTrackerFactory(debugType, {
|
||||
createDebugAdapterTracker: (session: vscode.DebugSession): vscode.DebugAdapterTracker | undefined => {
|
||||
if (session.name !== sessionName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
onWillReceiveMessage: (message: any): void => {
|
||||
if (message?.type === 'request' && message?.command === 'setBreakpoints') {
|
||||
state.setBreakpointsRequestReceived = true;
|
||||
}
|
||||
},
|
||||
onDidSendMessage: (message: any): void => {
|
||||
if (message?.type !== 'event') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.event === 'stopped') {
|
||||
state.stoppedEventReceived = true;
|
||||
if (timeoutHandle) {
|
||||
clearTimeout(timeoutHandle);
|
||||
timeoutHandle = undefined;
|
||||
}
|
||||
resolve('stopped');
|
||||
}
|
||||
|
||||
if ((message.event === 'terminated' || message.event === 'exited') && !state.exitedEventReceived) {
|
||||
state.exitedEventReceived = true;
|
||||
if (!state.stoppedEventReceived) {
|
||||
state.exitedBeforeStop = true;
|
||||
}
|
||||
if (timeoutHandle) {
|
||||
clearTimeout(timeoutHandle);
|
||||
timeoutHandle = undefined;
|
||||
}
|
||||
resolve('exited');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
state,
|
||||
lastEvent,
|
||||
dispose(): void {
|
||||
if (timeoutHandle) {
|
||||
clearTimeout(timeoutHandle);
|
||||
timeoutHandle = undefined;
|
||||
}
|
||||
trackerRegistration?.dispose();
|
||||
trackerRegistration = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function waitForResultFileValue(filePath: string, timeoutMs: number): Promise<number> {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let lastContents = '';
|
||||
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
lastContents = await util.readFileText(filePath, 'utf8');
|
||||
const trimmedContents = lastContents.trim();
|
||||
if (trimmedContents.length > 0) {
|
||||
const value = Number.parseInt(trimmedContents, 10);
|
||||
if (!Number.isNaN(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
assert.fail(`Timed out waiting for numeric result in ${filePath}. Last contents: ${lastContents}`);
|
||||
}
|
||||
|
||||
suite('Run Without Debugging Test', function (): void {
|
||||
const expectedResultValue = 37;
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0] ?? assert.fail('No workspace folder available');
|
||||
const workspacePath = workspaceFolder.uri.fsPath;
|
||||
const sourceFile = path.join(workspacePath, 'debugTest.cpp');
|
||||
const sourceUri = vscode.Uri.file(sourceFile);
|
||||
const resultFilePath = path.join(workspacePath, 'runWithoutDebuggingResult.txt');
|
||||
const executableName = isWindows ? 'debugTestProgram.exe' : 'debugTestProgram';
|
||||
const executablePath = path.join(workspacePath, executableName);
|
||||
const sessionName = 'Run Without Debugging Result File';
|
||||
const debugType = isWindows ? 'cppvsdbg' : 'cppdbg';
|
||||
const miMode = isMacOS ? 'lldb' : 'gdb';
|
||||
|
||||
suiteSetup(async function (): Promise<void> {
|
||||
const extension: vscode.Extension<any> = vscode.extensions.getExtension('ms-vscode.cpptools') || assert.fail('Extension not found');
|
||||
if (!extension.isActive) {
|
||||
await extension.activate();
|
||||
}
|
||||
await compileProgram(workspacePath, sourceFile, executablePath);
|
||||
});
|
||||
|
||||
suiteTeardown(async function (): Promise<void> {
|
||||
if (isWindows) {
|
||||
await vscode.commands.executeCommand('C_Cpp.ClearVsDeveloperEnvironment');
|
||||
}
|
||||
});
|
||||
|
||||
setup(async function (): Promise<void> {
|
||||
await util.deleteFile(resultFilePath);
|
||||
});
|
||||
|
||||
test('Run Without Debugging should not break on breakpoints and write the expected result file', async () => {
|
||||
const breakpoint = await createBreakpointAtResultWriteStatement(sourceUri);
|
||||
const tracker = createTracker(debugType, sessionName, 30000, 'Timed out waiting for debugger event.');
|
||||
const debugSessionTerminated = createSessionTerminatedPromise(sessionName);
|
||||
|
||||
try {
|
||||
const started = await vscode.debug.startDebugging(
|
||||
workspaceFolder,
|
||||
{
|
||||
name: sessionName,
|
||||
type: debugType,
|
||||
request: 'launch',
|
||||
program: executablePath,
|
||||
args: [],
|
||||
cwd: workspacePath,
|
||||
externalConsole: debugType === 'cppdbg' ? false : undefined,
|
||||
console: debugType === 'cppvsdbg' ? 'internalConsole' : undefined
|
||||
},
|
||||
{ noDebug: true });
|
||||
|
||||
assert.strictEqual(started, true, 'The noDebug launch did not start successfully.');
|
||||
|
||||
const lastEvent = await tracker.lastEvent;
|
||||
await debugSessionTerminated;
|
||||
const actualResultValue = await waitForResultFileValue(resultFilePath, 10000);
|
||||
|
||||
assert.strictEqual(lastEvent, 'exited', 'No-debug launch should exit rather than stop on a breakpoint.');
|
||||
assert.strictEqual(tracker.state.setBreakpointsRequestReceived, false, 'a "no debug" session should not send setBreakpoints requests.');
|
||||
assert.strictEqual(tracker.state.stoppedEventReceived, false, 'a "no debug" session should not emit stopped events.');
|
||||
assert.strictEqual(actualResultValue, expectedResultValue, 'Unexpected result value from run without debugging launch.');
|
||||
} finally {
|
||||
tracker.dispose();
|
||||
vscode.debug.removeBreakpoints([breakpoint]);
|
||||
await util.deleteFile(resultFilePath);
|
||||
}
|
||||
});
|
||||
|
||||
test('Debug launch should bind and stop at the breakpoint', async () => {
|
||||
const breakpoint = await createBreakpointAtResultWriteStatement(sourceUri);
|
||||
const tracker = createTracker(debugType, sessionName, 30000, 'Timed out waiting for debugger event in normal debug mode.');
|
||||
const debugSessionTerminated = createSessionTerminatedPromise(sessionName);
|
||||
|
||||
let launchedSession: vscode.DebugSession | undefined;
|
||||
const startedSubscription = vscode.debug.onDidStartDebugSession((session) => {
|
||||
if (session.name === sessionName) {
|
||||
launchedSession = session;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const started = await vscode.debug.startDebugging(
|
||||
workspaceFolder,
|
||||
{
|
||||
name: sessionName,
|
||||
type: debugType,
|
||||
request: 'launch',
|
||||
program: executablePath,
|
||||
args: [],
|
||||
cwd: workspacePath,
|
||||
MIMode: debugType === 'cppdbg' ? miMode : undefined,
|
||||
externalConsole: debugType === 'cppdbg' ? false : undefined,
|
||||
console: debugType === 'cppvsdbg' ? 'internalConsole' : undefined
|
||||
},
|
||||
{ noDebug: false });
|
||||
|
||||
assert.strictEqual(started, true, 'The debug launch did not start successfully.');
|
||||
|
||||
const lastEvent = await tracker.lastEvent;
|
||||
|
||||
assert.strictEqual(lastEvent, 'stopped', 'Debug launch should stop at the breakpoint before exit.');
|
||||
assert.strictEqual(tracker.state.setBreakpointsRequestReceived, true, 'Debug mode should send setBreakpoints requests.');
|
||||
assert.strictEqual(tracker.state.stoppedEventReceived, true, 'Debug mode should emit a stopped event at the breakpoint.');
|
||||
assert.strictEqual(tracker.state.exitedBeforeStop, false, 'Program exited before stopping at breakpoint in debug mode.');
|
||||
assert.strictEqual(vscode.debug.activeDebugSession?.name, sessionName, 'Debug session should still be active at breakpoint.');
|
||||
|
||||
const stoppedSession = launchedSession ?? vscode.debug.activeDebugSession;
|
||||
assert.ok(stoppedSession, 'Unable to identify the running debug session for termination.');
|
||||
await vscode.debug.stopDebugging(stoppedSession);
|
||||
await debugSessionTerminated;
|
||||
} finally {
|
||||
startedSubscription.dispose();
|
||||
tracker.dispose();
|
||||
vscode.debug.removeBreakpoints([breakpoint]);
|
||||
await util.deleteFile(resultFilePath);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
-190
@@ -1,190 +0,0 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
/// <reference path="../../../../vscode.d.ts" />
|
||||
import * as assert from 'assert';
|
||||
import { suite } from 'mocha';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as util from '../../../../src/common';
|
||||
import { isWindows } from '../../../../src/constants';
|
||||
import { compileProgram } from './compileProgram';
|
||||
|
||||
type ConsoleMode = 'integratedTerminal' | 'externalTerminal';
|
||||
type WindowsTerminalProfile = 'Command Prompt' | 'PowerShell';
|
||||
|
||||
/**
|
||||
* Waits for the output of a program to be written to a file and returns the lines of output.
|
||||
* @param filePath The path to the file containing the program output.
|
||||
* @param timeoutMs The maximum time to wait for the output, in milliseconds.
|
||||
* @returns A promise that resolves to an array of output lines.
|
||||
* @throws An error if the output is not available within the specified timeout.
|
||||
*/
|
||||
async function waitForOutput(filePath: string, timeoutMs: number): Promise<string[]> {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let lastContents = '';
|
||||
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
lastContents = await util.readFileText(filePath, 'utf8');
|
||||
const trimmedContents = lastContents.trimEnd();
|
||||
if (trimmedContents.length > 0) {
|
||||
return trimmedContents.split(/\r?\n/);
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
assert.fail(`Timed out waiting for argument output in ${filePath}. Last contents: ${lastContents}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of any terminals whose names match the given program paths. These are the terminals that were created to run the specified programs.
|
||||
* @param programs An array of program paths whose corresponding terminals should be disposed.
|
||||
*/
|
||||
function disposeTerminals(programs: string[]): void {
|
||||
const terminalNames = new Set(programs.map(program => path.normalize(program)));
|
||||
for (const terminal of vscode.window.terminals) {
|
||||
if (terminalNames.has(terminal.name)) {
|
||||
terminal.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or clears the setting for the default Windows terminal profile.
|
||||
* @param profile The terminal profile to set as the default, or undefined to clear the setting.
|
||||
*/
|
||||
async function setWindowsDefaultTerminalProfile(profile?: WindowsTerminalProfile): Promise<void> {
|
||||
if (!isWindows) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = vscode.workspace.getConfiguration('terminal.integrated');
|
||||
await config.update('defaultProfile.windows', profile, vscode.ConfigurationTarget.Workspace);
|
||||
}
|
||||
|
||||
async function runNoDebugLaunch(workspaceFolder: vscode.WorkspaceFolder, sessionName: string, program: string, consoleMode: ConsoleMode, resultFilePath: string, args: string[]): Promise<string[]> {
|
||||
const debugType = isWindows ? 'cppvsdbg' : 'cppdbg';
|
||||
const launchConfig: vscode.DebugConfiguration = {
|
||||
name: sessionName,
|
||||
type: debugType,
|
||||
request: 'launch',
|
||||
program: program,
|
||||
args: [resultFilePath, ...args],
|
||||
cwd: workspaceFolder.uri.fsPath
|
||||
};
|
||||
|
||||
if (debugType === 'cppvsdbg') {
|
||||
launchConfig.console = consoleMode;
|
||||
} else {
|
||||
launchConfig.externalConsole = consoleMode === 'externalTerminal';
|
||||
}
|
||||
|
||||
const started = await vscode.debug.startDebugging(workspaceFolder, launchConfig, { noDebug: true });
|
||||
assert.strictEqual(started, true, `The ${consoleMode} noDebug launch did not start successfully.`);
|
||||
return waitForOutput(resultFilePath, 15000);
|
||||
}
|
||||
|
||||
suite('Run Without Debugging Terminal and Arguments Test', function (this: Mocha.Suite): void {
|
||||
this.timeout(120000);
|
||||
|
||||
const workspaceFolder = vscode.workspace.workspaceFolders?.[0] ?? assert.fail('No workspace folder available');
|
||||
const workspacePath = workspaceFolder.uri.fsPath;
|
||||
const sourceFile = path.join(workspacePath, 'argsTest.cpp');
|
||||
const resultFilePath = path.join(workspacePath, 'test_output.txt');
|
||||
const executablePath = path.join(workspacePath, isWindows ? 'argsTestProgram.exe' : 'argsTestProgram');
|
||||
const spacedExecutablePath = path.join(workspacePath, isWindows ? 'args Test Program.exe' : 'args Test Program');
|
||||
const executablePaths = [executablePath, spacedExecutablePath];
|
||||
const expectedArgs = [
|
||||
'alpha',
|
||||
'two words',
|
||||
path.join(workspacePath, 'input folder', 'three words.txt')
|
||||
];
|
||||
|
||||
suiteSetup(async function (): Promise<void> {
|
||||
const extension: vscode.Extension<any> = vscode.extensions.getExtension('ms-vscode.cpptools') || assert.fail('Extension not found');
|
||||
if (!extension.isActive) {
|
||||
await extension.activate();
|
||||
}
|
||||
|
||||
await compileProgram(workspacePath, sourceFile, executablePath);
|
||||
await compileProgram(workspacePath, sourceFile, spacedExecutablePath);
|
||||
});
|
||||
|
||||
teardown(async function (): Promise<void> {
|
||||
await util.deleteFile(resultFilePath);
|
||||
disposeTerminals(executablePaths);
|
||||
});
|
||||
|
||||
setup(async function (): Promise<void> {
|
||||
if (await util.checkFileExists(resultFilePath)) {
|
||||
await util.deleteFile(resultFilePath);
|
||||
}
|
||||
});
|
||||
|
||||
suiteTeardown(async function (): Promise<void> {
|
||||
await util.deleteFile(resultFilePath);
|
||||
disposeTerminals(executablePaths);
|
||||
|
||||
if (isWindows) {
|
||||
await vscode.commands.executeCommand('C_Cpp.ClearVsDeveloperEnvironment');
|
||||
await util.deleteFile(path.join(workspacePath, '.vscode', 'settings.json'));
|
||||
}
|
||||
});
|
||||
|
||||
const consoleCases: { label: string; consoleMode: ConsoleMode; windowsProfiles?: (WindowsTerminalProfile | undefined)[] }[] = [
|
||||
{
|
||||
label: 'integrated terminal',
|
||||
consoleMode: 'integratedTerminal',
|
||||
windowsProfiles: [undefined, 'Command Prompt', 'PowerShell']
|
||||
},
|
||||
{
|
||||
label: 'external terminal',
|
||||
consoleMode: 'externalTerminal'
|
||||
}
|
||||
];
|
||||
|
||||
const programCases = [
|
||||
{
|
||||
label: 'a program name without spaces',
|
||||
programPath: executablePath
|
||||
},
|
||||
{
|
||||
label: 'a program name with spaces',
|
||||
programPath: spacedExecutablePath
|
||||
}
|
||||
];
|
||||
|
||||
for (const consoleCase of consoleCases) {
|
||||
for (const programCase of programCases) {
|
||||
const profiles: (WindowsTerminalProfile | undefined)[] = isWindows && consoleCase.consoleMode === 'integratedTerminal' ? consoleCase.windowsProfiles ?? [undefined] : [undefined];
|
||||
|
||||
for (const profile of profiles) {
|
||||
const profileSuffix = profile ? ` with ${profile} as the default terminal` : consoleCase.consoleMode === 'integratedTerminal' ? ' with default terminal' : '';
|
||||
test(`No-debug launch via ${consoleCase.label} handles ${programCase.label}${profileSuffix}`, async () => {
|
||||
await setWindowsDefaultTerminalProfile(profile);
|
||||
|
||||
disposeTerminals(executablePaths);
|
||||
const sessionName = `Run Without Debugging Args (${consoleCase.consoleMode}, ${path.basename(programCase.programPath)}${profile ? `, ${profile}` : ''})`;
|
||||
const actualArgs = await runNoDebugLaunch(
|
||||
workspaceFolder,
|
||||
sessionName,
|
||||
programCase.programPath,
|
||||
consoleCase.consoleMode,
|
||||
resultFilePath,
|
||||
expectedArgs);
|
||||
|
||||
assert.deepStrictEqual(actualArgs, expectedArgs, `Unexpected arguments received for ${consoleCase.label} using ${programCase.label}${profileSuffix}.`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,8 +1,9 @@
|
||||
<h1 data-loc-id="walkthrough.windows.install.compiler">Install a C++ compiler on Windows</h1>
|
||||
<p data-loc-id="walkthrough.windows.text1">If you're doing C++ development for Windows, we recommend installing the Microsoft Visual C++ (MSVC) compiler.</p>
|
||||
<ol>
|
||||
<li><p data-loc-id="walkthrough.windows.text2">To install MSVC, open the VS Code terminal (CTRL + `) and paste in the following command:</p>
|
||||
<p><code>winget install Microsoft.<wbr>VisualStudio.<wbr>2022.<wbr>BuildTools --force --override "--wait --passive --add Microsoft.<wbr>VisualStudio.<wbr>Workload.<wbr>VCTools --add Microsoft.<wbr>VisualStudio.<wbr>Component.<wbr>VC.<wbr>Tools.<wbr>x86.<wbr>x64 --add Microsoft.<wbr>VisualStudio.<wbr>Component.<wbr>Windows10SDK.<wbr>19041"</code></p>
|
||||
<li><p data-loc-id="walkthrough.windows.text2">To install MSVC, open the VS Code terminal (CTRL + `) and paste in the following command:
|
||||
<pre><code style="white-space: pre-wrap;">winget install Microsoft.VisualStudio.2022.BuildTools --force --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.20348"</code></pre>
|
||||
</li>
|
||||
<blockquote>
|
||||
<p><strong data-loc-id="walkthrough.windows.note1">Note</strong>: <span data-loc-id="walkthrough.windows.note1.text">You can use the C++ toolset from Visual Studio Build Tools along with Visual Studio Code to compile, build, and verify any C++ codebase as long as you also have a valid Visual Studio license (either Community, Pro, or Enterprise) that you are actively using to develop that C++ codebase.</span></p>
|
||||
</blockquote>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<h1 data-loc-id="walkthrough.windows.install.compiler">Install a C++ compiler on Windows</h1>
|
||||
<p data-loc-id="walkthrough.windows.text1">If you're doing C++ development for Windows, we recommend installing the Microsoft Visual C++ (MSVC) compiler.</p>
|
||||
<ol>
|
||||
<li><p data-loc-id="walkthrough.windows.text2">To install MSVC, open the VS Code terminal (CTRL + `) and paste in the following command:</p>
|
||||
<p><code>winget install Microsoft.<wbr>VisualStudio.<wbr>2022.<wbr>BuildTools --force --override "--wait --passive --add Microsoft.<wbr>VisualStudio.<wbr>Workload.<wbr>VCTools --add Microsoft.<wbr>VisualStudio.<wbr>Component.<wbr>VC.<wbr>Tools.<wbr>x86.<wbr>x64 --add Microsoft.<wbr>VisualStudio.<wbr>Component.<wbr>Windows11SDK.<wbr>26100"</code></p>
|
||||
<li><p data-loc-id="walkthrough.windows.text2">To install MSVC, open the VS Code terminal (CTRL + `) and paste in the following command:
|
||||
<pre><code style="white-space: pre-wrap;">winget install Microsoft.VisualStudio.2022.BuildTools --force --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.26100"</code></pre>
|
||||
</li>
|
||||
<blockquote>
|
||||
<p><strong data-loc-id="walkthrough.windows.note1">Note</strong>: <span data-loc-id="walkthrough.windows.note1.text">You can use the C++ toolset from Visual Studio Build Tools along with Visual Studio Code to compile, build, and verify any C++ codebase as long as you also have a valid Visual Studio license (either Community, Pro, or Enterprise) that you are actively using to develop that C++ codebase.</span></p>
|
||||
</blockquote>
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
|
||||
always-auth=true
|
||||
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
|
||||
ignore-scripts=true
|
||||
always-auth=true
|
||||
+1
-3
@@ -1,4 +1,2 @@
|
||||
registry=https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/
|
||||
always-auth=true
|
||||
# Disable postinstall scripts for supply chain security. Allowlist exceptions with npm trust: https://docs.npmjs.com/cli/v11/commands/npm-trust
|
||||
ignore-scripts=true
|
||||
always-auth=true
|
||||
Reference in New Issue
Block a user